@basou/cli 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/program.ts","../src/commands/approval.ts","../src/lib/error-render.ts","../src/commands/decision.ts","../src/commands/decisions.ts","../src/commands/exec.ts","../src/commands/handoff.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/refresh.ts","../src/lib/provenance-actions.ts","../src/commands/refresh-watch.ts","../src/commands/report.ts","../src/commands/run.ts","../src/commands/session.ts","../src/lib/format-duration.ts","../src/commands/stats.ts","../src/commands/status.ts","../src/commands/task.ts","../src/commands/verify.ts","../src/commands/view.ts","../src/lib/view-server.ts","../src/lib/view-ui.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { registerApprovalCommand } from \"./commands/approval.js\";\nimport { registerDecisionCommand } from \"./commands/decision.js\";\nimport { registerDecisionsCommand } from \"./commands/decisions.js\";\nimport { registerExecCommand } from \"./commands/exec.js\";\nimport { registerHandoffCommand } from \"./commands/handoff.js\";\nimport { registerImportCommand } from \"./commands/import.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerRefreshCommand } from \"./commands/refresh.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerRunCommand } from \"./commands/run.js\";\nimport { registerSessionCommand } from \"./commands/session.js\";\nimport { registerStatsCommand } from \"./commands/stats.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport { registerTaskCommand } from \"./commands/task.js\";\nimport { registerVerifyCommand } from \"./commands/verify.js\";\nimport { registerViewCommand } from \"./commands/view.js\";\n\n// Read the CLI release version directly from the sibling package.json so\n// `basou --version` cannot drift past a future package-bump (the v0.2/v0.3\n// releases both shipped with a stale \"0.1.0\" constant before the dynamic\n// read landed). The relative path is stable across the dev (src/program.ts\n// → src/../package.json) and built (dist/program.js → dist/../package.json)\n// layouts, since both files sit one directory below the package root.\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\nexport const BASOU_CLI_VERSION = pkg.version;\n\n/**\n * Build the fully-registered `basou` command tree WITHOUT parsing argv.\n *\n * This is the side-effect-free entry shared by the CLI binary (./index.ts)\n * and any introspection consumer — e.g. the docs generator that renders the\n * command reference from the published `@basou/cli`. Importing this module\n * must never parse `process.argv` or run a command action; `index.ts` owns\n * the single `parseAsync` call.\n */\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"basou\")\n .description(\"Provenance layer for AI development\")\n .version(BASOU_CLI_VERSION)\n // Required so that `basou exec` (and any other passThroughOptions\n // subcommand) can forward unknown flags to the wrapped child.\n .enablePositionalOptions();\n\n registerInitCommand(program);\n registerStatusCommand(program);\n registerStatsCommand(program);\n registerExecCommand(program);\n registerRunCommand(program);\n registerSessionCommand(program);\n registerImportCommand(program);\n registerRefreshCommand(program);\n registerVerifyCommand(program);\n registerViewCommand(program);\n registerApprovalCommand(program);\n registerDecisionCommand(program);\n registerTaskCommand(program);\n registerHandoffCommand(program);\n registerDecisionsCommand(program);\n registerReportCommand(program);\n\n return program;\n}\n","import { unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n type Approval,\n type ApprovalLocation,\n ApprovalSchema,\n type ApprovalStatus,\n ApprovalStatusSchema,\n acquireLock,\n appendChainedEventLocked,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n type Event,\n enumerateApprovals,\n findErrorCode,\n isLazyExpired,\n linkYamlFile,\n loadApproval,\n prefixedUlid,\n readSessionYaml,\n readYamlFile,\n replayEvents,\n resolveRepositoryRoot,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, printReplayWarning, renderCliError } from \"../lib/error-render.js\";\n\nconst APPR_PREFIX = \"appr_\";\nconst SHORT_ID_BASE_LEN = 6;\nconst SHORT_ID_MAX_LEN = 26; // ULID body length\nconst ACTION_KEY_DETAIL_MAX_LEN = 60;\nconst REASON_TEXT_MAX_LEN = 80;\n\nconst STATUS_VALUES = ApprovalStatusSchema.options;\n\nexport type ApprovalListOptions = {\n json?: boolean;\n status?: ApprovalStatus;\n verbose?: boolean;\n};\n\nexport type ApprovalShowOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ApprovalApproveOptions = {\n note?: string;\n verbose?: boolean;\n};\n\nexport type ApprovalRejectOptions = {\n reason: string;\n verbose?: boolean;\n};\n\nexport type ApprovalContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\ntype ApprovalListRecord = {\n approval: Approval;\n location: ApprovalLocation;\n lazyExpired: boolean;\n};\n\n/**\n * Wire `basou approval list / show / approve / reject` onto `program`.\n *\n * The `approval` group is registered up front so future subcommands\n * (`cancel`, `recover`) added in later steps slot under the same group\n * without changing the externally visible CLI surface.\n */\nexport function registerApprovalCommand(program: Command): void {\n const approval = program\n .command(\"approval\")\n .description(\"Manage Basou approval requests under .basou/approvals/\");\n\n approval\n .command(\"list\")\n .description(\"List approvals across pending and resolved (newest first)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\n \"--status <state>\",\n `Filter by approval status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseApprovalStatus,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ApprovalListOptions) => {\n await runApprovalList(options);\n });\n\n approval\n .command(\"show <id>\")\n .description(\"Show an approval's metadata and related events\")\n .option(\"--json\", \"Output the approval and events as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalShowOptions) => {\n await runApprovalShow(id, options);\n });\n\n approval\n .command(\"approve <id>\")\n .description(\"Approve a pending approval\")\n .option(\"--note <text>\", \"Optional note to attach to the approval_approved event\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalApproveOptions) => {\n await runApprovalApprove(id, options);\n });\n\n approval\n .command(\"reject <id>\")\n .description(\"Reject a pending approval\")\n .requiredOption(\"--reason <text>\", \"Reason for rejection (required)\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalRejectOptions) => {\n await runApprovalReject(id, options);\n });\n}\n\n// === list ===\n\n/**\n * Programmatic entry for `basou approval list` that owns process exit\n * state. Tests targeting only the success path or the thrown error should\n * prefer {@link doRunApprovalList}.\n */\nexport async function runApprovalList(\n options: ApprovalListOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `approval list`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunApprovalList(\n options: ApprovalListOptions,\n ctx: ApprovalContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const ids = await enumerateApprovals(paths);\n // A single `now` shared across every record so that two reads on the\n // same boundary instant cannot disagree (e.g. one record flagged expired\n // and another not when both straddle the same `expires_at`).\n const now = new Date();\n const records: ApprovalListRecord[] = [];\n\n // Resolve dedupe set: id appearing in both directories → prefer resolved\n // and surface a stderr warning about the stale pending entry.\n const resolvedSet = new Set(ids.resolved);\n for (const id of ids.pending) {\n if (resolvedSet.has(id)) {\n console.error(`Warning: stale pending entry for ${shortId(id)}; resolved version preferred`);\n continue;\n }\n const rec = await readApprovalListRecord(paths, id, \"pending\", now);\n if (rec !== null) records.push(rec);\n }\n for (const id of ids.resolved) {\n const rec = await readApprovalListRecord(paths, id, \"resolved\", now);\n if (rec !== null) records.push(rec);\n }\n\n records.sort((a, b) => Date.parse(b.approval.created_at) - Date.parse(a.approval.created_at));\n\n const filtered =\n options.status !== undefined\n ? records.filter((r) => r.approval.status === options.status)\n : records;\n\n if (filtered.length === 0) {\n printNoApprovals(options);\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((r) => ({ ...r.approval, lazy_expired: r.lazyExpired })),\n null,\n 2,\n ),\n );\n } else {\n printApprovalListText(filtered);\n }\n}\n\nasync function readApprovalListRecord(\n paths: BasouPaths,\n id: string,\n location: ApprovalLocation,\n now: Date,\n): Promise<ApprovalListRecord | null> {\n const filePath = join(paths.approvals[location], `${id}.yaml`);\n let raw: unknown;\n try {\n raw = await readYamlFile(filePath);\n } catch (error: unknown) {\n console.error(`Skipped ${shortId(id)}: ${describeReadError(error)}`);\n return null;\n }\n const parse = ApprovalSchema.safeParse(raw);\n if (!parse.success) {\n console.error(`Skipped ${shortId(id)}: invalid approval schema`);\n return null;\n }\n if (parse.data.id !== id) {\n // Surface a stderr warning rather than dropping silently so an operator\n // can spot the corrupted entry from `basou approval list`.\n console.error(`Skipped ${shortId(id)}: filename and YAML body id disagree`);\n return null;\n }\n const approval = parse.data;\n return { approval, location, lazyExpired: isLazyExpired(approval, now) };\n}\n\n// === show ===\n\nexport async function runApprovalShow(\n idInput: string,\n options: ApprovalShowOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunApprovalShow(\n idInput: string,\n options: ApprovalShowOptions,\n ctx: ApprovalContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const { id } = await resolveApprovalId(paths, idInput);\n const loaded = await loadApproval(paths, id);\n if (loaded === null) {\n throw new Error(`Approval not found: ${idInput}`);\n }\n\n // events.jsonl I/O failure throws \"Failed to read events.jsonl\" and is\n // converted to exit 1 by the wrapping try/catch — partial / malformed /\n // schema warnings stream through onWarning.\n const sessionDir = join(paths.sessions, loaded.approval.session_id);\n const relatedEvents: Event[] = [];\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, loaded.approval.session_id),\n })) {\n if (isApprovalEvent(ev) && ev.approval_id === id) {\n relatedEvents.push(ev);\n }\n }\n\n const now = new Date();\n const lazyExpired = isLazyExpired(loaded.approval, now);\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n approval: { ...loaded.approval, lazy_expired: lazyExpired },\n events: relatedEvents,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n printApprovalShowText(loaded.approval, loaded.location, relatedEvents, lazyExpired);\n}\n\n// === approve / reject ===\n\nexport async function runApprovalApprove(\n idInput: string,\n options: ApprovalApproveOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalResolve(idInput, options, ctx, \"approve\");\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runApprovalReject(\n idInput: string,\n options: ApprovalRejectOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalResolve(idInput, options, ctx, \"reject\");\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nasync function doRunApprovalResolve(\n idInput: string,\n options: ApprovalApproveOptions | ApprovalRejectOptions,\n ctx: ApprovalContext,\n decision: \"approve\" | \"reject\",\n): Promise<void> {\n if (decision === \"reject\") {\n const reason = (options as ApprovalRejectOptions).reason;\n if (reason.length === 0) {\n throw new Error(\"--reason must not be empty\");\n }\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, decision);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n // Step D-2: resolve id (search both directories).\n const { id, location } = await resolveApprovalId(paths, idInput);\n\n // Step D-3: a resolved-side hit means there is nothing left to decide.\n if (location === \"resolved\") {\n throw new Error(`Approval already resolved: ${idInput}`);\n }\n\n // Step D-4: read + parse the pending YAML.\n const pendingPath = join(paths.approvals.pending, `${id}.yaml`);\n let pendingRaw: unknown;\n try {\n pendingRaw = await readYamlFile(pendingPath);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n throw new Error(`Approval not found: ${idInput}`);\n }\n throw new Error(\"Failed to read approval\", { cause: error });\n }\n // Wrap zod's parse so a malformed pending YAML surfaces through the\n // pathless `Failed to read approval` contract instead of leaking a raw\n // ZodError through the rendered output.\n const approvalParse = ApprovalSchema.safeParse(pendingRaw);\n if (!approvalParse.success) {\n throw new Error(\"Failed to read approval\", { cause: approvalParse.error });\n }\n const approval = approvalParse.data;\n // Defensive id check (matches loadApproval): filename id and body id\n // must agree, otherwise we'd resolve one approval while emitting events\n // for another.\n if (approval.id !== id) {\n throw new Error(\"Failed to read approval\", {\n cause: new Error(`Approval id mismatch: filename id ${id} vs YAML body id ${approval.id}`),\n });\n }\n // A pending-side YAML whose status is no longer `pending` means the\n // file was corrupted (or hand-edited mid-resolution). Refuse to fire a\n // second resolution event for it.\n if (approval.status !== \"pending\") {\n throw new Error(`Approval status mismatch: pending YAML has status=${approval.status}`);\n }\n\n // Step D-6/D-7 timestamps + event id, computed up front so they are shared\n // with the resolved-side YAML (Step D-9, built after the lock is released).\n const now = new Date();\n const occurredAt = now.toISOString();\n const eventId = prefixedUlid(\"evt\");\n\n // Hold the session lock across the replay fence and the resolution append so\n // two concurrent resolvers cannot both pass the fence before either appends\n // (closing a pre-existing double-resolution race) and so the resolution line\n // chains onto the session's on-disk tail. The caller owns the critical\n // section, so the lock-assumed append primitive is used here.\n const sessionLock = await acquireLock(paths, \"session\", approval.session_id);\n try {\n // Step D-5: events.jsonl fence — if a resolution event already exists\n // for this approval, refuse to fire a second one. This guards the\n // crash-mid-orchestration window where step 8 succeeded but step 10\n // failed (events.jsonl is the source-of-truth, not the YAML mirror).\n const sessionDir = join(paths.sessions, approval.session_id);\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, approval.session_id),\n })) {\n if (\n isApprovalEvent(ev) &&\n ev.approval_id === approval.id &&\n (ev.type === \"approval_approved\" ||\n ev.type === \"approval_rejected\" ||\n ev.type === \"approval_expired\")\n ) {\n throw new Error(`Approval already resolved (per events.jsonl): ${idInput}`);\n }\n }\n\n // Step D-6: lazy expire state-fence. No event is fired here; the\n // approval_expired event is reserved for a later step that owns\n // expiry-side orchestration.\n if (isLazyExpired(approval, now)) {\n throw new Error(`Approval already expired: ${idInput}`);\n }\n\n // Step D-6b: attachable-status fence. An approval is resolved while its\n // session is still live (initialized / running / waiting_approval). Refuse\n // any other status — matching every other attach path — so a resolution\n // line is never chained onto a finalized (anchored) or imported log, which\n // `verify` would otherwise read as tampered (the at-rest anchor would no\n // longer match the extended log). Only a positively read non-attachable\n // status blocks; a missing or unreadable session.yaml falls through to the\n // pre-existing behavior.\n let sessionStatus: string | null = null;\n try {\n sessionStatus = (await readSessionYaml(paths, approval.session_id)).session.status;\n } catch {\n sessionStatus = null;\n }\n const attachable =\n sessionStatus === \"initialized\" ||\n sessionStatus === \"running\" ||\n sessionStatus === \"waiting_approval\";\n if (sessionStatus !== null && !attachable) {\n throw new Error(\n `Cannot resolve an approval for a session that is not active (status=${sessionStatus}): ${idInput}`,\n );\n }\n\n // Step D-8: append the resolution event to events.jsonl, chained onto the\n // on-disk tail. After this point the trail is committed; subsequent\n // failures must not roll back the event (the source-of-truth invariant).\n if (decision === \"approve\") {\n const note = (options as ApprovalApproveOptions).note ?? null;\n await appendChainedEventLocked(paths, approval.session_id, {\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: approval.session_id,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"approval_approved\",\n approval_id: approval.id,\n resolver: \"local-cli\",\n note,\n });\n } else {\n const reason = (options as ApprovalRejectOptions).reason;\n await appendChainedEventLocked(paths, approval.session_id, {\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: approval.session_id,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"approval_rejected\",\n approval_id: approval.id,\n resolver: \"local-cli\",\n reason,\n });\n }\n } finally {\n await sessionLock.release();\n }\n\n // Step D-9: build the resolved-side YAML body in memory.\n const resolvedApproval: Approval =\n decision === \"approve\"\n ? {\n ...approval,\n status: \"approved\",\n resolver: \"local-cli\",\n resolved_at: occurredAt,\n note: (options as ApprovalApproveOptions).note ?? null,\n }\n : {\n ...approval,\n status: \"rejected\",\n resolver: \"local-cli\",\n resolved_at: occurredAt,\n rejection_reason: (options as ApprovalRejectOptions).reason,\n };\n\n // Step D-10: create-only write. linkYamlFile fails fast with EEXIST if a\n // concurrent resolver already populated the resolved-side YAML — the\n // events.jsonl fence above should have caught it first, so reaching\n // EEXIST here implies a near-simultaneous race we surface explicitly.\n const resolvedPath = join(paths.approvals.resolved, `${id}.yaml`);\n try {\n await linkYamlFile(resolvedPath, resolvedApproval);\n } catch (error: unknown) {\n const cause = error instanceof Error ? error.cause : undefined;\n if (cause instanceof Error && (cause as Error & { code?: unknown }).code === \"EEXIST\") {\n throw new Error(\"Approval already resolved at the same time\", { cause });\n }\n throw error;\n }\n\n // Step D-11: best-effort unlink of the pending YAML. The trail and the\n // resolved-side YAML are already consistent at this point; a leftover\n // pending entry is reconciled by the next `approval list`'s dedupe.\n try {\n await unlink(pendingPath);\n } catch {\n console.error(\n `Warning: failed to unlink pending entry for ${shortId(id)}; events.jsonl is consistent`,\n );\n }\n\n // Step D-12: success message.\n const verb = decision === \"approve\" ? \"Approved\" : \"Rejected\";\n console.log(`${verb} approval ${shortId(id)}`);\n}\n\n// === helpers ===\n\nasync function resolveApprovalId(\n paths: BasouPaths,\n input: string,\n): Promise<{ id: string; location: ApprovalLocation }> {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw new Error(\"Approval id is empty\");\n }\n const normalized = trimmed.startsWith(APPR_PREFIX) ? trimmed : `${APPR_PREFIX}${trimmed}`;\n // Reject prefix-only input so a bare prefix cannot match an arbitrary\n // approval via `startsWith`.\n if (normalized.length <= APPR_PREFIX.length) {\n throw new Error(`Approval not found: ${input}`);\n }\n\n const enumeration = await enumerateApprovals(paths);\n\n // Aggregate by full id so a duplicate (same id in both pending and\n // resolved) collapses to one entry with location=resolved (preferred).\n const byId = new Map<string, ApprovalLocation>();\n for (const id of enumeration.pending) {\n if (id.startsWith(normalized)) byId.set(id, \"pending\");\n }\n for (const id of enumeration.resolved) {\n if (!id.startsWith(normalized)) continue;\n if (byId.get(id) === \"pending\") {\n // Same full id present on both sides: resolved wins, surface a warning.\n console.error(`Warning: stale pending entry for ${shortId(id)}; resolved version preferred`);\n }\n byId.set(id, \"resolved\");\n }\n\n if (byId.size === 0) {\n throw new Error(`Approval not found: ${input}`);\n }\n if (byId.size > 1) {\n throw new Error(\n `Ambiguous approval id '${input}': matched ${byId.size} approvals. Disambiguate with a longer prefix.`,\n );\n }\n const first = byId.entries().next().value;\n if (first === undefined) {\n throw new Error(`Approval not found: ${input}`);\n }\n const [id, location] = first;\n return { id, location };\n}\n\nfunction isApprovalEvent(ev: Event): ev is Event & { approval_id: string } {\n return (\n ev.type === \"approval_requested\" ||\n ev.type === \"approval_approved\" ||\n ev.type === \"approval_rejected\" ||\n ev.type === \"approval_expired\"\n );\n}\n\nfunction printApprovalListText(records: ApprovalListRecord[]): void {\n // Grow the SHORT_ID column on collision. The dedupe in doRunApprovalList\n // already collapsed duplicates by full id, so feeding only the unique\n // ids here is correct.\n const allIds = records.map((r) => r.approval.id);\n const shortLen = computeUniquePrefixLen(allIds);\n const rows = records.map((r) => {\n const sid = sliceShort(r.approval.id, shortLen);\n const status = r.lazyExpired ? `${r.approval.status} (expired)` : r.approval.status;\n const risk = r.approval.risk_level;\n const action = r.approval.action.kind;\n const createdAt = r.approval.created_at;\n const reason = truncate(r.approval.reason, REASON_TEXT_MAX_LEN);\n return { sid, status, risk, action, createdAt, reason };\n });\n\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n risk: maxLen(\n rows.map((r) => r.risk),\n \"RISK\".length,\n ),\n action: maxLen(\n rows.map((r) => r.action),\n \"ACTION\".length,\n ),\n createdAt: maxLen(\n rows.map((r) => r.createdAt),\n \"CREATED_AT\".length,\n ),\n };\n\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"RISK\", widths.risk)} ${pad(\"ACTION\", widths.action)} ${pad(\"CREATED_AT\", widths.createdAt)} REASON`,\n );\n for (const row of rows) {\n console.log(\n `${pad(row.sid, widths.sid)} ${pad(row.status, widths.status)} ${pad(row.risk, widths.risk)} ${pad(row.action, widths.action)} ${pad(row.createdAt, widths.createdAt)} ${row.reason}`,\n );\n }\n}\n\nfunction printApprovalShowText(\n approval: Approval,\n _location: ApprovalLocation,\n events: readonly Event[],\n lazyExpired: boolean,\n): void {\n console.log(`Approval: ${approval.id} (status: ${approval.status})`);\n console.log(`Session: ${approval.session_id}`);\n console.log(`Created at: ${approval.created_at}`);\n console.log(`Risk level: ${approval.risk_level}`);\n console.log(`Action: ${formatActionLine(approval.action)}`);\n console.log(`Reason: ${approval.reason}`);\n const expiresLabel = formatExpiresLabel(approval.expires_at, lazyExpired);\n console.log(`Expires at: ${expiresLabel}`);\n console.log(`Resolver: ${approval.resolver ?? \"(none)\"}`);\n console.log(`Resolved at: ${approval.resolved_at ?? \"(none)\"}`);\n console.log(`Note: ${approval.note ?? \"(none)\"}`);\n console.log(`Rejection reason: ${approval.rejection_reason ?? \"(none)\"}`);\n\n console.log(\"\");\n console.log(`Related events: ${events.length} total`);\n for (const ev of events) {\n console.log(` ${formatApprovalEventLine(ev)}`);\n }\n}\n\nfunction formatActionLine(action: { kind: string } & Record<string, unknown>): string {\n const extras: string[] = [];\n for (const [key, value] of Object.entries(action)) {\n if (key === \"kind\") continue;\n if (typeof value !== \"string\") continue;\n extras.push(`${key}=\"${truncate(value, ACTION_KEY_DETAIL_MAX_LEN)}\"`);\n if (extras.length >= 2) break;\n }\n return extras.length === 0 ? action.kind : `${action.kind} (${extras.join(\", \")})`;\n}\n\nfunction formatExpiresLabel(expiresAt: string | null, lazyExpired: boolean): string {\n if (expiresAt === null) return \"(none)\";\n return lazyExpired ? `${expiresAt} (expired)` : expiresAt;\n}\n\nfunction formatApprovalEventLine(ev: Event): string {\n const summary = approvalEventSummary(ev);\n return `${ev.occurred_at} [${ev.source}] ${ev.type} ${summary}`;\n}\n\nfunction approvalEventSummary(ev: Event): string {\n switch (ev.type) {\n case \"approval_requested\":\n return `${ev.action.kind} risk=${ev.risk_level}`;\n case \"approval_approved\":\n return ev.resolver !== undefined ? `by ${ev.resolver}` : \"(approved)\";\n case \"approval_rejected\":\n return ev.resolver !== undefined ? `by ${ev.resolver}: ${ev.reason}` : ev.reason;\n case \"approval_expired\":\n return `approval=${ev.approval_id}`;\n default:\n // Other event types are filtered out before reaching this helper.\n return \"\";\n }\n}\n\nfunction shortId(id: string): string {\n return sliceShort(id, SHORT_ID_BASE_LEN);\n}\n\n// Known Basou prefixed-id leading tokens. Strip whichever applies so that\n// a session id passed through the warning handler renders as the bare\n// ULID prefix (matching what session.ts already emits) instead of leaving\n// the `ses_` head in the truncated short id.\nconst KNOWN_ID_PREFIXES = [\"appr_\", \"ses_\", \"evt_\", \"ws_\", \"task_\", \"decision_\"] as const;\n\nfunction sliceShort(id: string, len: number): string {\n for (const prefix of KNOWN_ID_PREFIXES) {\n if (id.startsWith(prefix)) {\n return id.slice(prefix.length, prefix.length + len);\n }\n }\n return id.slice(0, len);\n}\n\nfunction computeUniquePrefixLen(ids: readonly string[]): number {\n if (ids.length <= 1) return SHORT_ID_BASE_LEN;\n for (let len = SHORT_ID_BASE_LEN; len <= SHORT_ID_MAX_LEN; len += 2) {\n const seen = new Set<string>();\n let collided = false;\n for (const id of ids) {\n const key = sliceShort(id, len);\n if (seen.has(key)) {\n collided = true;\n break;\n }\n seen.add(key);\n }\n if (!collided) return len;\n }\n return SHORT_ID_MAX_LEN;\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 3)}...`;\n}\n\nasync function resolveRepositoryRootForApproval(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"approve\" | \"reject\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou approval ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\nfunction describeReadError(error: unknown): string {\n if (error instanceof Error) {\n if (error.message === \"YAML file not found\") return \"approval YAML not found\";\n if (error.message === \"Failed to parse YAML content\") return \"invalid YAML\";\n return error.message;\n }\n return String(error);\n}\n\nfunction parseApprovalStatus(raw: string): ApprovalStatus {\n const result = ApprovalStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid approval status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction printNoApprovals(options: ApprovalListOptions): void {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No approvals found.\");\n }\n}\n","import {\n FailedToFinalizeError,\n type ReplayWarning,\n type SessionSkipReason,\n type TaskSkipReason,\n} from \"@basou/core\";\n\n// ============================================================================\n// Short-id helpers\n// ============================================================================\n\nconst SES_PREFIX = \"ses_\";\nconst TASK_PREFIX = \"task_\";\nconst SHORT_ID_LEN = 6;\n\n/**\n * Strip the `ses_` prefix and slice the first {@link SHORT_ID_LEN} chars of\n * the ULID body for human-readable session identification in CLI output.\n * IDs without the prefix are sliced from offset 0.\n */\nexport function shortSessionId(id: string): string {\n if (id.startsWith(SES_PREFIX))\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + SHORT_ID_LEN);\n return id.slice(0, SHORT_ID_LEN);\n}\n\n/**\n * Same as {@link shortSessionId} but for `task_<ULID>` ids.\n */\nexport function shortTaskId(id: string): string {\n if (id.startsWith(TASK_PREFIX))\n return id.slice(TASK_PREFIX.length, TASK_PREFIX.length + SHORT_ID_LEN);\n return id.slice(0, SHORT_ID_LEN);\n}\n\n// ============================================================================\n// Verbose mode detection\n// ============================================================================\n\n/**\n * Unified verbose-mode predicate: `options.verbose === true` OR the\n * `BASOU_DEBUG=1` environment variable. CLI surfaces use this everywhere\n * the verbose error / cause label rendering needs a yes/no answer.\n */\nexport function isVerbose(options: { verbose?: boolean } | undefined): boolean {\n return options?.verbose === true || process.env.BASOU_DEBUG === \"1\";\n}\n\n// ============================================================================\n// Cause-chain walk (pathless)\n// ============================================================================\n\nconst CAUSE_CHAIN_MAX_DEPTH = 4;\n\n/**\n * Walk the cause chain (up to {@link CAUSE_CHAIN_MAX_DEPTH} hops) and return\n * the first errno-style `code` found, falling back to the deepest\n * constructor name. The value goes into `Caused by: <label>` so verbose\n * output stays pathless even when capability layers wrap native errors.\n *\n * Returns `undefined` when `error.cause` is not itself an Error (= no chain\n * to walk).\n */\nexport function extractCauseLabel(error: Error): string | undefined {\n let current: unknown = error.cause;\n let constructorName: string | undefined;\n for (let depth = 0; depth < CAUSE_CHAIN_MAX_DEPTH; depth += 1) {\n if (!(current instanceof Error)) break;\n const code = (current as Error & { code?: unknown }).code;\n if (typeof code === \"string\" && code.length > 0) return code;\n constructorName = current.constructor.name;\n current = current.cause;\n }\n return constructorName;\n}\n\n// ============================================================================\n// Pluggable classifier interface\n// ============================================================================\n\n/**\n * Plug-in for command-specific error rendering. {@link renderCliError}\n * invokes every classifier whose {@link match} returns true and emits each\n * line returned by {@link additionalLines} after the main `error.message`\n * line. Classifiers MUST keep their lines pathless — no absolute paths, no\n * `cause.message` echo.\n */\nexport interface ErrorClassifier {\n match(error: Error): boolean;\n additionalLines(error: Error): readonly string[];\n}\n\n/**\n * Shared classifier for {@link FailedToFinalizeError}. Both `task.ts` and\n * `decision.ts` need exactly the same two warning lines — the session.yaml\n * status update failed AFTER the target event was already written, so the\n * operator must NOT retry the command.\n */\nexport const failedToFinalizeClassifier: ErrorClassifier = {\n match: (error) => error instanceof FailedToFinalizeError,\n additionalLines: (error) => {\n const e = error as FailedToFinalizeError;\n const sid = shortSessionId(e.sessionId);\n // `targetEventIds[0]` is the operator-facing anchor event (= the\n // `decision_recorded` / `task_created` / `task_reconciled` event the\n // command was meant to produce). Multi-target ad-hoc sessions (e.g.\n // `task new --status done` which adds `task_status_changed`) carry the\n // additional ids in `targetEventIds[1..]`; one anchor is enough for the\n // do-not-rerun warning.\n const anchor = e.targetEventIds[0];\n return [\n `Recorded ${anchor} in session ${sid}; do not rerun`,\n \"Warning: session.yaml status update failed; events.jsonl is consistent\",\n ];\n },\n};\n\n// ============================================================================\n// Generic CLI error renderer\n// ============================================================================\n\n/**\n * Render an unknown thrown value to stderr without leaking absolute paths.\n *\n * Always prints `error.message` first, then any classifier-emitted lines,\n * and finally — in verbose mode — a single `Caused by: <label>` line where\n * `<label>` is the first errno code found while walking `error.cause` (or\n * the deepest constructor name as a fallback). The error's `cause.message`\n * is intentionally never printed because Node's native fs errors embed\n * absolute paths there.\n *\n * Non-Error values are coerced via `String(error)` so the catch-all fallback\n * in `program.parseAsync().catch(...)` still produces something readable.\n */\nexport function renderCliError(\n error: unknown,\n options: { verbose: boolean; classifiers?: readonly ErrorClassifier[] },\n): void {\n if (!(error instanceof Error)) {\n console.error(String(error));\n return;\n }\n console.error(error.message);\n for (const classifier of options.classifiers ?? []) {\n if (classifier.match(error)) {\n for (const line of classifier.additionalLines(error)) console.error(line);\n }\n }\n if (options.verbose) {\n const label = extractCauseLabel(error);\n if (label !== undefined) console.error(`Caused by: ${label}`);\n }\n}\n\n// ============================================================================\n// Warning surface helpers\n// ============================================================================\n\n/**\n * Print a `ReplayWarning` on stderr in the canonical short form used by\n * every command that consumes the event-replay stream (= task / handoff /\n * decisions / etc.). The session id is shortened via {@link shortSessionId}\n * for readability.\n */\nexport function printReplayWarning(warning: ReplayWarning, sessionId: string): void {\n const short = shortSessionId(sessionId);\n switch (warning.kind) {\n case \"partial_trailing_line\":\n console.error(`Warning: ignored partial trailing line in ${short}/events.jsonl`);\n break;\n case \"malformed_json\":\n console.error(\n `Warning: skipped malformed JSON at line ${warning.line} in ${short}/events.jsonl`,\n );\n break;\n case \"schema_violation\":\n console.error(\n `Warning: skipped invalid event at line ${warning.line} in ${short}/events.jsonl`,\n );\n break;\n }\n}\n\n/**\n * Print a session-skip warning in the \"scan\" form used by handoff / decisions\n * generators: `events_jsonl_unreadable` is mapped to the standardised\n * suspect-check warning used elsewhere in the CLI, every other reason falls\n * through to a generic `Skipped <sid>: <reason>` form preserving the raw\n * enum value.\n */\nexport function printSessionSkip(sid: string, reason: SessionSkipReason): void {\n const short = shortSessionId(sid);\n if (reason === \"events_jsonl_unreadable\") {\n console.error(`Warning: skipped suspect check for ${short}: events.jsonl unreadable`);\n } else {\n console.error(`Skipped ${short}: ${reason}`);\n }\n}\n\n/**\n * Print a session-skip warning in the \"list\" form used by `session list`.\n * Each reason is mapped to a user-friendly English phrase rather than the\n * raw enum value. `events_jsonl_unreadable` shares the wording produced by\n * {@link printSessionSkip} so the CLI surface stays consistent across\n * subcommands.\n */\nexport function printSessionListSkip(sid: string, reason: SessionSkipReason): void {\n const short = shortSessionId(sid);\n switch (reason) {\n case \"session_yaml_missing\":\n console.error(`Skipped ${short}: session.yaml not found`);\n break;\n case \"session_yaml_invalid\":\n console.error(`Skipped ${short}: invalid session schema`);\n break;\n case \"events_jsonl_unreadable\":\n console.error(`Warning: skipped suspect check for ${short}: events.jsonl unreadable`);\n break;\n }\n}\n\n/**\n * Print a task-skip warning shared between `task list` (which sees a\n * narrowed {@link TaskSkipReason} enum) and handoff / decisions generators\n * (which may forward an arbitrary reason string). Accepts a plain `string`\n * so both shapes route through the same renderer.\n */\nexport function printTaskSkip(taskId: string, reason: TaskSkipReason | string): void {\n console.error(`Skipped ${shortTaskId(taskId)}: ${reason}`);\n}\n","import {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n type PrefixedId,\n prefixedUlid,\n readManifest,\n resolveRepositoryRoot,\n resolveSessionId,\n type SessionStatus,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n failedToFinalizeClassifier,\n isVerbose,\n renderCliError,\n shortSessionId,\n} from \"../lib/error-render.js\";\n\n// Raised from the original 40-char cap to 80 chars so a long decision\n// title (= the most common ad-hoc trigger) retains its core information\n// without being truncated. 80 chars still fits comfortably in\n// single-column session list / handoff renderings. Operator feedback\n// from real-world long-title outliers may revisit this value.\nconst LABEL_TITLE_MAX = 80;\nconst LABEL_TRUNCATE_HEAD = LABEL_TITLE_MAX - 3;\n\nexport type DecisionRecordOptions = {\n title: string;\n rationale?: string;\n rejectedReason?: string;\n alternative?: string[];\n linkedEvent?: string[];\n linkedFile?: string[];\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type DecisionContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou decision record` onto `program`. The `decision` group only\n * contains the write-side `record` subcommand in v0.1; list/show inspectors\n * are deferred to a v0.3+ follow-up.\n */\nexport function registerDecisionCommand(program: Command): void {\n const decision = program\n .command(\"decision\")\n .description(\"Record human-authored decisions as events\");\n\n decision\n .command(\"record\")\n .description(\"Record a decision_recorded event\")\n .requiredOption(\"--title <text>\", \"Decision title\", parseTitle)\n .option(\"--rationale <text>\", \"Rationale for the decision\", parseRationale)\n .option(\n \"--rejected-reason <text>\",\n \"Reason rejected alternatives were not chosen\",\n parseRejectedReason,\n )\n .option(\n \"--alternative <text>\",\n \"Alternative considered (repeatable: --alternative yup --alternative joi)\",\n collectAlternative,\n [] as string[],\n )\n .option(\n \"--linked-event <event_id>\",\n \"Related event id (repeatable). Schema only checks the prefix; existence is verified at render time.\",\n collectLinkedEvent,\n [] as string[],\n )\n .option(\n \"--linked-file <path>\",\n \"Related file path (repeatable). Path is opaque; existence is verified at render time.\",\n collectLinkedFile,\n [] as string[],\n )\n .option(\n \"--session <session_id>\",\n \"Attach to an existing session; otherwise an ad-hoc session is created\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: DecisionRecordOptions) => {\n await runDecisionRecord(options);\n });\n}\n\n/**\n * Programmatic entry for `basou decision record`. Owns process exit state.\n * Tests targeting the success path or the thrown error should prefer\n * {@link doRunDecisionRecord}.\n */\nexport async function runDecisionRecord(\n options: DecisionRecordOptions,\n ctx: DecisionContext = {},\n): Promise<void> {\n try {\n await doRunDecisionRecord(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionRecord(\n options: DecisionRecordOptions,\n ctx: DecisionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForDecision(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const decisionId = prefixedUlid(\"decision\");\n\n const rich = pickRichFields(options);\n\n if (options.session !== undefined) {\n const sessionId = await resolveSessionId(paths, options.session);\n const sesId = sessionId as PrefixedId<\"ses\">;\n // Per-session lock guards the session.yaml status read + events.jsonl\n // append window against a concurrent writer (`basou session note`,\n // another `decision record --session`, or an attach-flavoured task\n // command). `appendEventToExistingSession` itself holds no lock; the\n // caller owns the critical section.\n const sessionLock = await acquireLock(paths, \"session\", sesId);\n let result: Awaited<ReturnType<typeof appendEventToExistingSession>>;\n try {\n result = await appendEventToExistingSession({\n paths,\n sessionId: sesId,\n eventBuilder: (eventId) =>\n buildDecisionEvent({\n eventId,\n sessionId: sesId,\n decisionId,\n title: options.title,\n occurredAt,\n rich,\n }),\n });\n } finally {\n await sessionLock.release();\n }\n printDecisionResult(options, {\n mode: \"attached\",\n sessionId,\n decisionId,\n eventId: result.eventId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n rich,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildAdHocLabel(options.title),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou decision record\",\n args: [\"--title\", options.title],\n },\n targetEventBuilders: [\n (sessionId, eventId) =>\n buildDecisionEvent({\n eventId,\n sessionId,\n decisionId,\n title: options.title,\n occurredAt,\n rich,\n }),\n ],\n });\n printDecisionResult(options, {\n mode: \"ad-hoc\",\n sessionId: adHoc.sessionId,\n decisionId,\n eventId: adHoc.targetEventIds[0] as string,\n sessionStatus: \"completed\",\n title: options.title,\n rich,\n });\n}\n\ntype RichDecisionFields = {\n rationale?: string;\n rejected_reason?: string;\n alternatives?: string[];\n linked_events?: string[];\n linked_files?: string[];\n};\n\nfunction pickRichFields(options: DecisionRecordOptions): RichDecisionFields {\n const out: RichDecisionFields = {};\n if (options.rationale !== undefined) out.rationale = options.rationale;\n if (options.rejectedReason !== undefined) out.rejected_reason = options.rejectedReason;\n if (options.alternative !== undefined && options.alternative.length > 0) {\n out.alternatives = [...options.alternative];\n }\n if (options.linkedEvent !== undefined && options.linkedEvent.length > 0) {\n out.linked_events = [...options.linkedEvent];\n }\n if (options.linkedFile !== undefined && options.linkedFile.length > 0) {\n out.linked_files = [...options.linkedFile];\n }\n return out;\n}\n\nfunction buildDecisionEvent(input: {\n eventId: PrefixedId<\"evt\">;\n sessionId: PrefixedId<\"ses\">;\n decisionId: PrefixedId<\"decision\">;\n title: string;\n occurredAt: string;\n rich: RichDecisionFields;\n}): Event {\n return {\n schema_version: \"0.1.0\",\n id: input.eventId,\n session_id: input.sessionId,\n occurred_at: input.occurredAt,\n source: \"local-cli\",\n type: \"decision_recorded\",\n decision_id: input.decisionId,\n title: input.title,\n ...(input.rich.rationale !== undefined ? { rationale: input.rich.rationale } : {}),\n ...(input.rich.alternatives !== undefined ? { alternatives: input.rich.alternatives } : {}),\n ...(input.rich.rejected_reason !== undefined\n ? { rejected_reason: input.rich.rejected_reason }\n : {}),\n ...(input.rich.linked_events !== undefined\n ? { linked_events: input.rich.linked_events as Array<`evt_${string}`> }\n : {}),\n ...(input.rich.linked_files !== undefined ? { linked_files: input.rich.linked_files } : {}),\n };\n}\n\nfunction buildAdHocLabel(title: string): string {\n const truncated =\n title.length > LABEL_TITLE_MAX ? `${title.slice(0, LABEL_TRUNCATE_HEAD)}...` : title;\n return `Ad-hoc decision: ${truncated}`;\n}\n\nfunction parseTitle(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseRationale(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Rationale must not be empty\");\n }\n return raw;\n}\n\nfunction parseRejectedReason(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Rejected reason must not be empty\");\n }\n return raw;\n}\n\nfunction collectAlternative(value: string, prev: string[]): string[] {\n if (value.length === 0) {\n throw new InvalidArgumentError(\"Alternative must not be empty\");\n }\n return prev.concat(value);\n}\n\nconst EVENT_ID_RE = /^evt_[A-Z0-9]+$/;\n\nfunction collectLinkedEvent(value: string, prev: string[]): string[] {\n if (!EVENT_ID_RE.test(value)) {\n throw new InvalidArgumentError(`Linked event id must match evt_<ULID>, got '${value}'`);\n }\n return prev.concat(value);\n}\n\nfunction collectLinkedFile(value: string, prev: string[]): string[] {\n if (value.length === 0) {\n throw new InvalidArgumentError(\"Linked file path must not be empty\");\n }\n if (value.length > 4096) {\n throw new InvalidArgumentError(\"Linked file path exceeds 4096 chars\");\n }\n return prev.concat(value);\n}\n\ntype DecisionPrintInput = {\n mode: \"ad-hoc\" | \"attached\";\n sessionId: string;\n decisionId: string;\n eventId: string;\n sessionStatus: SessionStatus;\n title: string;\n rich: RichDecisionFields;\n};\n\nfunction printDecisionResult(options: DecisionRecordOptions, result: DecisionPrintInput): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n const payload: Record<string, unknown> = {\n decision_id: result.decisionId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n title: result.title,\n };\n // Rich fields are now persisted into the decision_recorded event, so\n // they appear in the JSON summary as-is (the old `rationale_saved:\n // false` indicator is gone).\n if (result.rich.rationale !== undefined) payload.rationale = result.rich.rationale;\n if (result.rich.alternatives !== undefined) payload.alternatives = result.rich.alternatives;\n if (result.rich.rejected_reason !== undefined) {\n payload.rejected_reason = result.rich.rejected_reason;\n }\n if (result.rich.linked_events !== undefined) payload.linked_events = result.rich.linked_events;\n if (result.rich.linked_files !== undefined) payload.linked_files = result.rich.linked_files;\n console.log(JSON.stringify(payload));\n return;\n }\n const rationaleSuffix =\n result.rich.rationale !== undefined ? ` (rationale: ${result.rich.rationale})` : \"\";\n if (result.mode === \"ad-hoc\") {\n console.log(`Recorded ${result.decisionId} in ad-hoc session ${sid}${rationaleSuffix}`);\n } else {\n console.log(\n `Recorded ${result.decisionId} in session ${sid} (${result.sessionStatus})${rationaleSuffix}`,\n );\n }\n}\n\nasync function resolveRepositoryRootForDecision(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou decision record'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n readMarkdownFile,\n renderDecisions,\n renderWithMarkers,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type DecisionsGenerateOptions = { verbose?: boolean };\n\nexport type DecisionsContext = {\n cwd?: string;\n nowProvider?: () => Date;\n};\n\n/** Wire `basou decisions generate` onto `program`. Mirrors `handoff` exactly. */\nexport function registerDecisionsCommand(program: Command): void {\n const decisions = program\n .command(\"decisions\")\n .description(\"Generate or inspect .basou/decisions.md\");\n\n decisions\n .command(\"generate\")\n .description(\"Regenerate .basou/decisions.md from recorded decision events\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: DecisionsGenerateOptions) => {\n await runDecisionsGenerate(opts);\n });\n}\n\nexport async function runDecisionsGenerate(\n options: DecisionsGenerateOptions,\n ctx: DecisionsContext = {},\n): Promise<void> {\n try {\n await doRunDecisionsGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionsGenerate(\n options: DecisionsGenerateOptions,\n ctx: DecisionsContext,\n): Promise<void> {\n void options;\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForDecisions(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderDecisions({\n paths,\n nowIso,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n });\n\n const existing = await readMarkdownFile(paths.files.decisions);\n const finalBody = renderWithMarkers(existing, result.body, \"decisions.md\");\n await writeMarkdownFile(paths.files.decisions, finalBody);\n\n console.log(`Generated .basou/decisions.md (decisions: ${result.decisionCount})`);\n}\n\nasync function resolveRepositoryRootForDecisions(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou decisions generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n acquireLock,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n ChildProcessRunner,\n appendChainedEvent as coreAppendChainedEvent,\n finalizeSessionYaml,\n getSnapshot,\n overwriteYamlFile,\n type PrefixedId,\n type ProcessRunner,\n parseDuration,\n prefixedUlid,\n type RunResult,\n readManifest,\n readYamlFile,\n resolveRepositoryRoot,\n type Session,\n SessionSchema,\n sanitizeWorkingDirectory,\n writeYamlFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\n// Appends one event to the session's events.jsonl. The `sessionDir` argument\n// is retained for the test-injection seam (ctx.appendEvent); the production\n// binding ignores it and chains via paths + sessionId.\ntype AppendEventFn = (sessionDir: string, event: unknown) => Promise<void>;\n\n/**\n * `basou exec` orchestration: spawn an arbitrary child as a single new\n * Basou session and record its lifecycle (session_started, optional\n * git_snapshot pre, status_changed, command_executed, optional git_snapshot\n * post, status_changed, session_ended) to `events.jsonl`.\n *\n * Output is forwarded to the parent's terminal (`capture: \"none\"`); raw\n * stdout/stderr is intentionally not stored in events.jsonl or `.basou/raw/`.\n */\nexport type ExecOptions = {\n timeout?: string;\n cwd?: string;\n // commander turns `--no-snapshot` into `snapshot: false`. The default\n // (no flag) leaves this `undefined` (treated as `true` downstream).\n snapshot?: boolean;\n verbose?: boolean;\n};\n\ntype ExecContext = {\n runner?: ProcessRunner;\n now?: () => Date;\n // events.jsonl writer override. Tests use this to verify that appendEvent\n // failures during git_snapshot propagate as exec failures (see\n // tryAppendGitSnapshot below) instead of being swallowed into a skip warning.\n appendEvent?: AppendEventFn;\n // Last-resort SIGKILL hook installation hook. Tests capture the handler\n // installed on `process.on(\"exit\", ...)` and trigger it manually to verify\n // that activeChild is killed when the parent exits abnormally.\n onExitHookInstalled?: (handler: () => void) => void;\n};\n\nexport function registerExecCommand(program: Command): void {\n program\n .command(\"exec <command> [args...]\")\n .description(\"Execute a command and record it as a Basou session\")\n // Pass through unknown options/flags after the command name to the\n // child so callers can write `basou exec npm test --watch` instead of\n // `basou exec -- npm test --watch`. basou's own options (--timeout,\n // --no-snapshot, --cwd, -v) must come before the command name.\n .passThroughOptions()\n .option(\"--timeout <duration>\", \"Kill the child after this duration (e.g. 30s, 5m, 1h)\")\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the command\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (command: string, args: string[], options: ExecOptions) => {\n try {\n const exitCode = await runExec(command, args, options);\n process.exit(exitCode);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exit(1);\n }\n });\n}\n\nexport async function runExec(\n command: string,\n args: string[],\n options: ExecOptions,\n ctx: ExecContext = {},\n): Promise<number> {\n const runner = ctx.runner ?? new ChildProcessRunner();\n const now = ctx.now ?? (() => new Date());\n const cwd = options.cwd ?? process.cwd();\n\n // 0. timeout option fail-fast: invalid timeout never creates a session.\n const timeout_ms = options.timeout !== undefined ? parseDuration(options.timeout) : undefined;\n\n // 1. Resolve repository root before touching anything; matches existing\n // init/status semantics so subdir invocations still find `.basou/`.\n const repoRoot = await resolveRepositoryRootForExec(cwd);\n const paths = basouPaths(repoRoot);\n\n // 2. Workspace safety check (caller responsibility).\n await assertBasouRootSafe(paths.root);\n\n // 3. Read manifest to bind session.workspace_id.\n const manifest = await readManifest(paths);\n\n // 4. Build a fresh session and persist its initial state.\n const sessionId = prefixedUlid(\"ses\");\n const sessionDir = join(paths.sessions, sessionId);\n await mkdir(sessionDir, { recursive: true });\n\n // Every append chains onto the on-disk tail under a short-lived session lock\n // (the self-locking wrapper); the lock is NEVER held across the child. Tests\n // inject ctx.appendEvent to force append failures.\n const appendEvent: AppendEventFn =\n ctx.appendEvent ??\n (async (_sessionDir, event) => {\n await coreAppendChainedEvent(paths, sessionId, event);\n });\n\n const startedAt = now().toISOString();\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n const session = buildInitialSession({\n id: sessionId,\n command,\n args,\n cwd,\n workspaceId: manifest.workspace.id,\n startedAt,\n });\n await writeYamlFile(sessionYamlPath, session);\n\n // 5. session_started.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_started\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: startedAt,\n source: \"terminal-recording\",\n });\n\n // 6. Optional pre-execute git_snapshot.\n if (options.snapshot !== false) {\n await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 7. status_changed: initialized -> running.\n const runningAt = now().toISOString();\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: runningAt,\n source: \"terminal-recording\",\n from: \"initialized\",\n to: \"running\",\n });\n // Lock the status write so it cannot interleave-clobber a foreign locked\n // session.yaml writer (e.g. a task attach setting task_id on this session).\n const runningLock = await acquireLock(paths, \"session\", sessionId);\n try {\n await mutateSessionYaml(sessionYamlPath, (s) => {\n s.session.status = \"running\";\n });\n } finally {\n await runningLock.release();\n }\n\n // 8. Transient signal hooks: SIGINT / SIGTERM / exit. The exit hook is\n // a synchronous last-resort SIGKILL if the parent exits abnormally.\n const controller = new AbortController();\n let signalReceived: NodeJS.Signals | null = null;\n let activeChild: ChildProcess | null = null;\n const signalHandler = (sig: NodeJS.Signals) => {\n if (signalReceived !== null) return;\n signalReceived = sig;\n controller.abort();\n };\n const exitHandler = () => {\n if (activeChild !== null) {\n try {\n activeChild.kill(\"SIGKILL\");\n } catch {\n // swallow: best-effort cleanup\n }\n }\n };\n // Bind explicit signal names so `process.emit(\"SIGINT\")` etc. produce the\n // right `received_signal` regardless of Node's listener-arg conventions.\n const onSigInt = () => signalHandler(\"SIGINT\");\n const onSigTerm = () => signalHandler(\"SIGTERM\");\n process.on(\"SIGINT\", onSigInt);\n process.on(\"SIGTERM\", onSigTerm);\n process.on(\"exit\", exitHandler);\n // Allow tests to capture the exit handler and trigger the activeChild\n // SIGKILL fallback synchronously without faking `process.emit(\"exit\")`.\n ctx.onExitHookInstalled?.(exitHandler);\n\n let result: RunResult;\n try {\n try {\n result = await runner.run(command, args, {\n cwd,\n capture: \"none\",\n ...(timeout_ms !== undefined ? { timeout_ms } : {}),\n signal: controller.signal,\n onSpawn: (child) => {\n activeChild = child;\n },\n });\n } catch (spawnError: unknown) {\n // Spawn-time error / pre-aborted / validation error: tear down the\n // session as failed before propagating so events.jsonl and session.yaml\n // are consistent even on error.\n await finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent, {\n command,\n args,\n cwd,\n occurredAt: now().toISOString(),\n signalReceived,\n });\n throw spawnError;\n }\n } finally {\n process.off(\"SIGINT\", onSigInt);\n process.off(\"SIGTERM\", onSigTerm);\n process.off(\"exit\", exitHandler);\n activeChild = null;\n }\n\n const endedAt = now().toISOString();\n\n // 9. command_executed (with parent received_signal vs child terminating signal).\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n command,\n args,\n cwd,\n exit_code: result.exit_code,\n ...(result.signal !== null ? { signal: result.signal } : {}),\n ...(signalReceived !== null ? { received_signal: signalReceived } : {}),\n duration_ms: result.duration_ms,\n });\n\n // 10. Optional post-execute git_snapshot (after command_executed so the\n // event sequence reads chronologically: pre-snapshot, run, post-snapshot).\n if (options.snapshot !== false) {\n await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n const finalStatus = decideFinalStatus(result, signalReceived);\n\n // 11. status_changed: running -> final.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n from: \"running\",\n to: finalStatus,\n });\n\n // 12. session_ended.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n ...(result.exit_code !== null ? { exit_code: result.exit_code } : {}),\n });\n\n // 13. Final session.yaml update (status / ended_at / invocation.exit_code)\n // plus the integrity head anchor, written from the on-disk tail under the\n // session lock so a foreign line appended just before finalize is\n // anchored and a later attach (now terminal) is rejected.\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = finalStatus;\n s.session.ended_at = endedAt;\n s.session.invocation.exit_code = result.exit_code;\n });\n\n if (result.exit_code !== null) {\n return result.exit_code;\n }\n return signalToExitCode(signalReceived ?? result.signal);\n}\n\nfunction decideFinalStatus(\n result: { exit_code: number | null; signal: NodeJS.Signals | null },\n signalReceived: NodeJS.Signals | null,\n): \"completed\" | \"failed\" | \"interrupted\" {\n if (signalReceived === \"SIGINT\" || signalReceived === \"SIGTERM\") return \"interrupted\";\n if (result.signal === \"SIGINT\" || result.signal === \"SIGTERM\" || result.signal === \"SIGKILL\") {\n return \"interrupted\";\n }\n if (result.exit_code === 0) return \"completed\";\n return \"failed\";\n}\n\nconst SIGNUM_MAP: Record<string, number> = {\n SIGHUP: 1,\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n};\n\nfunction signalToExitCode(sig: NodeJS.Signals | null): number {\n if (sig === null) return 1;\n const num = SIGNUM_MAP[sig] ?? 1;\n return 128 + num;\n}\n\nasync function tryAppendGitSnapshot(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n now: () => Date,\n appendEvent: AppendEventFn,\n): Promise<void> {\n // Stage 1: snapshot acquisition. Capability-level failures (no git repo,\n // git binary missing, no commits) are recoverable and downgrade to a skip\n // warning. The session continues and events.jsonl simply lacks this\n // git_snapshot entry.\n let snapshot: Awaited<ReturnType<typeof getSnapshot>>;\n try {\n snapshot = await getSnapshot(repoRoot);\n } catch (error: unknown) {\n console.warn(normalizeGitSnapshotSkipMessage(error));\n return;\n }\n // Stage 2: events.jsonl append. Schema validation / disk failures here are\n // NOT a \"snapshot capability\" miss — they would corrupt the events.jsonl\n // integrity contract (the fixed 7-event sequence when snapshot is on). We\n // intentionally do NOT swallow these; let them propagate so the exec call\n // fails loudly instead of producing a session that looks successful but\n // has missing or partial events.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"git_snapshot\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: now().toISOString(),\n source: \"git-capability\",\n ...snapshot,\n });\n}\n\nfunction normalizeGitSnapshotSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `git_snapshot skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") {\n return \"git_snapshot skipped: not in a git repository\";\n }\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"git_snapshot skipped: git executable not found\";\n }\n if (msg === \"No commits in repository\") {\n return \"git_snapshot skipped: no commits in repository\";\n }\n return `git_snapshot skipped: ${msg}`;\n}\n\nfunction buildInitialSession(input: {\n id: PrefixedId<\"ses\">;\n command: string;\n args: string[];\n cwd: string;\n workspaceId: PrefixedId<\"ws\">;\n startedAt: string;\n}): Session {\n const cmdline = [input.command, ...input.args].join(\" \");\n return {\n schema_version: \"0.1.0\",\n session: {\n id: input.id,\n label: `basou exec ${cmdline} (${input.startedAt})`,\n task_id: null,\n workspace_id: input.workspaceId,\n source: { kind: \"terminal\", version: \"0.1.0\" },\n started_at: input.startedAt,\n status: \"initialized\",\n working_directory: sanitizeWorkingDirectory(input.cwd, { homedir: homedir() }),\n invocation: {\n command: input.command,\n args: [...input.args],\n exit_code: null,\n },\n related_files: [],\n events_log: \"events.jsonl\",\n },\n };\n}\n\nasync function mutateSessionYaml(\n filePath: string,\n mutator: (session: Session) => void,\n): Promise<void> {\n const raw = await readYamlFile(filePath);\n const parsed = SessionSchema.parse(raw);\n mutator(parsed);\n // Re-validate after mutation to catch drift, then overwrite atomically.\n const validated = SessionSchema.parse(parsed);\n await overwriteYamlFile(filePath, validated);\n}\n\nasync function finalizeSessionAsFailed(\n paths: BasouPaths,\n sessionDir: string,\n sessionId: string,\n appendEvent: AppendEventFn,\n ctx: {\n command: string;\n args: string[];\n cwd: string;\n occurredAt: string;\n signalReceived: NodeJS.Signals | null;\n },\n): Promise<void> {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n command: ctx.command,\n args: ctx.args,\n cwd: ctx.cwd,\n exit_code: null,\n signal: null,\n ...(ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {}),\n duration_ms: 0,\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n from: \"running\",\n to: \"failed\",\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n });\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = \"failed\";\n s.session.ended_at = ctx.occurredAt;\n s.session.invocation.exit_code = null;\n });\n}\n\nasync function resolveRepositoryRootForExec(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou exec'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n readMarkdownFile,\n renderHandoff,\n renderWithMarkers,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n printTaskSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type HandoffGenerateOptions = { verbose?: boolean };\n\nexport type HandoffContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou handoff generate` onto `program`. The `handoff` group is\n * registered up front so future subcommands (e.g. `show`) can slot under\n * the same group without breaking the CLI surface.\n */\nexport function registerHandoffCommand(program: Command): void {\n const handoff = program.command(\"handoff\").description(\"Generate or inspect .basou/handoff.md\");\n\n handoff\n .command(\"generate\")\n .description(\"Regenerate .basou/handoff.md from current session state\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: HandoffGenerateOptions) => {\n await runHandoffGenerate(opts);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. Tests that only care\n * about the happy path or a thrown error should prefer {@link doRunHandoffGenerate}.\n */\nexport async function runHandoffGenerate(\n options: HandoffGenerateOptions,\n ctx: HandoffContext = {},\n): Promise<void> {\n try {\n await doRunHandoffGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `handoff generate`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunHandoffGenerate(\n options: HandoffGenerateOptions,\n ctx: HandoffContext,\n): Promise<void> {\n void options;\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForHandoff(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderHandoff({\n paths,\n nowIso,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n });\n\n const existing = await readMarkdownFile(paths.files.handoff);\n const finalBody = renderWithMarkers(existing, result.body, \"handoff.md\");\n await writeMarkdownFile(paths.files.handoff, finalBody);\n\n console.log(\n `Generated .basou/handoff.md (sessions: ${result.sessionCount}, tasks: ${result.taskCount}, decisions: ${result.decisionCount}, pending approvals: ${result.pendingApprovalsCount})`,\n );\n}\n\nasync function resolveRepositoryRootForHandoff(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou handoff generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { createReadStream, type Dirent } from \"node:fs\";\nimport { readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport {\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n CLAUDE_IMPORT_SOURCE,\n type ClaudeTranscriptRecord,\n CODEX_IMPORT_SOURCE,\n type CodexRolloutRecord,\n claudeTranscriptToImportPayload,\n codexRolloutToImportPayload,\n enumerateSessionDirs,\n findErrorCode,\n type ImportSessionResult,\n importSessionFromJson,\n type Manifest,\n readManifest,\n readSessionYaml,\n reimportPreservingId,\n resolveRepositoryRoot,\n type Session,\n type SessionImportPayload,\n SessionImportPayloadSchema,\n type SessionSourceKind,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nconst SES_PREFIX = \"ses_\";\nconst SHORT_ID_LEN = 6;\n\n/** Options shared by every `basou import <adapter>` subcommand. */\nexport type ImportOptions = {\n /**\n * Source project roots whose native logs to import. Repeatable on the CLI;\n * empty means \"fall back to the manifest's `import.source_roots`, then the\n * repository root\". Each entry may be absolute or relative to the cwd.\n */\n project?: string[];\n session?: string;\n all?: boolean;\n force?: boolean;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectPath(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport type ImportClaudeCodeOptions = ImportOptions;\nexport type ImportCodexOptions = ImportOptions;\n\nexport type ImportContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /**\n * Root that holds per-project Claude transcript directories. Defaults to\n * `~/.claude/projects`. Injectable for tests so no real home dir is touched.\n */\n claudeProjectsDir?: string;\n /**\n * Root that holds Codex rollout logs (`<year>/<month>/<day>/rollout-*.jsonl`).\n * Defaults to `~/.codex/sessions`. Injectable for tests.\n */\n codexSessionsDir?: string;\n};\n\n/**\n * A single source session ready to be derived and imported. The dedup key\n * (`externalId`) is known up front from discovery; `toPayload` reads and\n * transforms the source log lazily, so a session that is skipped (already\n * imported) is never read.\n */\ntype ImportCandidate = {\n externalId: string;\n /**\n * Absolute path of the source native log. The orchestrator stats this (a\n * cheap, parse-free probe) to decide whether an already-imported source\n * changed, before paying to read + derive it.\n */\n sourcePath: string;\n toPayload: () => Promise<SessionImportPayload | null>;\n};\n\n/**\n * Wire the `basou import` command group onto `program`. Each adapter\n * (`claude-code`, `codex`, ...) is a subcommand sharing the same flags, so\n * future adapters slot in without changing the visible surface.\n */\nexport function registerImportCommand(program: Command): void {\n const importCmd = program\n .command(\"import\")\n .description(\"Import provenance from an external AI tool's native logs\");\n\n importCmd\n .command(\"claude-code\")\n .description(\"Derive Basou sessions from Claude Code native transcripts (~/.claude/projects)\")\n .option(\n \"--project <path>\",\n \"Source project path whose transcripts to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--session <id>\", \"Import a single transcript by its Claude session id\")\n .option(\"--all\", \"Import every transcript found for the project\")\n .option(\n \"--force\",\n \"Re-import sessions already imported: delete and replace them instead of skipping\",\n )\n .option(\"--dry-run\", \"Validate and preview only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ImportClaudeCodeOptions) => {\n await runImportClaudeCode(options);\n });\n\n importCmd\n .command(\"codex\")\n .description(\"Derive Basou sessions from OpenAI Codex native rollout logs (~/.codex/sessions)\")\n .option(\n \"--project <path>\",\n \"Source project path whose rollouts to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--session <id>\", \"Import a single rollout by its Codex session id\")\n .option(\"--all\", \"Import every rollout found for the project\")\n .option(\n \"--force\",\n \"Re-import sessions already imported: delete and replace them instead of skipping\",\n )\n .option(\"--dry-run\", \"Validate and preview only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ImportCodexOptions) => {\n await runImportCodex(options);\n });\n}\n\n/**\n * Programmatic entry for `basou import claude-code`. Owns process exit state;\n * tests should prefer {@link doRunImportClaudeCode}.\n */\nexport async function runImportClaudeCode(\n options: ImportClaudeCodeOptions,\n ctx: ImportContext = {},\n): Promise<void> {\n try {\n await doRunImportClaudeCode(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Programmatic entry for `basou import codex`. Owns process exit state;\n * tests should prefer {@link doRunImportCodex}.\n */\nexport async function runImportCodex(\n options: ImportCodexOptions,\n ctx: ImportContext = {},\n): Promise<void> {\n try {\n await doRunImportCodex(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Resolve the absolute source roots to import from, applying precedence:\n * explicit `--project` flags first (resolved against the cwd), else the\n * manifest's `import.source_roots` (resolved against the repo root), else the\n * repository root alone. The result is de-duplicated, so a root listed twice\n * (or equal to the repo root) is scanned once.\n */\nfunction resolveSourceRoots(args: {\n projectFlags: string[];\n manifest: Manifest;\n repoRoot: string;\n cwd: string;\n}): string[] {\n const { projectFlags, manifest, repoRoot, cwd } = args;\n let resolved: string[];\n if (projectFlags.length > 0) {\n resolved = projectFlags.map((p) => resolve(cwd, p));\n } else {\n const roots = manifest.import?.source_roots;\n resolved =\n roots !== undefined && roots.length > 0 ? roots.map((r) => resolve(repoRoot, r)) : [repoRoot];\n }\n return [...new Set(resolved)];\n}\n\nexport async function doRunImportClaudeCode(\n options: ImportClaudeCodeOptions,\n ctx: ImportContext,\n): Promise<void> {\n assertSelector(options);\n const { repositoryRoot, paths, manifest } = await resolveImportTarget(ctx);\n\n const projectPaths = resolveSourceRoots({\n projectFlags: options.project ?? [],\n manifest,\n repoRoot: repositoryRoot,\n cwd: ctx.cwd ?? process.cwd(),\n });\n const projectsRoot = ctx.claudeProjectsDir ?? join(homedir(), \".claude\", \"projects\");\n\n const files = await selectTranscriptFiles(projectsRoot, projectPaths, options);\n const candidates: ImportCandidate[] = files.map((file) => {\n // The transcript filename is the Claude session id; it is both the dedup\n // key and the source external_id.\n const externalId = basename(file, \".jsonl\");\n return {\n externalId,\n sourcePath: file,\n toPayload: async () => {\n const { records, sizeBytes } = await readJsonlRecords(file);\n return claudeTranscriptToImportPayload(records, {\n workspaceId: manifest.workspace.id,\n externalId,\n sourceSizeBytes: sizeBytes,\n });\n },\n };\n });\n\n await importDerivedSessions(paths, manifest, options, CLAUDE_IMPORT_SOURCE, candidates);\n}\n\nexport async function doRunImportCodex(\n options: ImportCodexOptions,\n ctx: ImportContext,\n): Promise<void> {\n assertSelector(options);\n const { repositoryRoot, paths, manifest } = await resolveImportTarget(ctx);\n\n const projectPaths = resolveSourceRoots({\n projectFlags: options.project ?? [],\n manifest,\n repoRoot: repositoryRoot,\n cwd: ctx.cwd ?? process.cwd(),\n });\n const sessionsRoot = ctx.codexSessionsDir ?? join(homedir(), \".codex\", \"sessions\");\n\n const rollouts = await discoverCodexRollouts(sessionsRoot, projectPaths, options);\n const candidates: ImportCandidate[] = rollouts.map(({ file, externalId }) => ({\n externalId,\n sourcePath: file,\n toPayload: async () => {\n const { records, sizeBytes } = await readJsonlRecords(file);\n return codexRolloutToImportPayload(records as CodexRolloutRecord[], {\n workspaceId: manifest.workspace.id,\n externalId,\n sourceSizeBytes: sizeBytes,\n });\n },\n }));\n\n await importDerivedSessions(paths, manifest, options, CODEX_IMPORT_SOURCE, candidates);\n}\n\nfunction assertSelector(options: ImportOptions): void {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n if (options.session === undefined && options.all !== true) {\n throw new Error(\"Specify --session <id> or --all\");\n }\n}\n\nasync function resolveImportTarget(\n ctx: ImportContext,\n): Promise<{ repositoryRoot: string; paths: BasouPaths; manifest: Manifest }> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForImport(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n return { repositoryRoot, paths, manifest };\n}\n\n/**\n * The vendor-neutral import core: dedup, derive, validate, and write each\n * candidate, then report. Every `basou import <adapter>` funnels its\n * discovered candidates through here, so dedup / `--force` / `--dry-run`\n * semantics stay identical across adapters. Dedup is scoped to `sourceKind`\n * so one adapter never matches (or, under `--force`, deletes) another\n * adapter's session that happens to share an id string.\n */\nasync function importDerivedSessions(\n paths: BasouPaths,\n manifest: Manifest,\n options: ImportOptions,\n sourceKind: SessionSourceKind,\n candidates: ReadonlyArray<ImportCandidate>,\n): Promise<void> {\n const existingByExternalId = await loadExistingByExternalId(paths, sourceKind);\n // Session ids imported earlier in THIS run, so two source files that map to\n // one session id never double-import within a single invocation.\n const seenThisRun = new Set<string>();\n\n const results: ImportSessionResult[] = [];\n const counts: ImportCounts = {\n skippedNoAction: 0,\n skippedExisting: 0,\n replaced: 0,\n reimported: 0,\n skippedLegacy: 0,\n skippedDecreased: 0,\n skippedDuplicate: 0,\n };\n let sanitizedPaths = 0;\n\n // Parse + version-gate a derived payload before it touches disk. Returns null\n // when the source carried no provenance worth importing (the caller skips).\n const validate = (payload: SessionImportPayload | null): SessionImportPayload | null => {\n if (payload === null) return null;\n const parsed = SessionImportPayloadSchema.safeParse(payload);\n if (!parsed.success) {\n throw new Error(\"Invalid import payload\", { cause: parsed.error });\n }\n if (parsed.data.schema_version !== \"0.1.0\") {\n throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);\n }\n return parsed.data;\n };\n\n for (const { externalId, sourcePath, toPayload } of candidates) {\n if (seenThisRun.has(externalId)) {\n counts.skippedExisting++;\n continue;\n }\n const priors = existingByExternalId.get(externalId) ?? [];\n\n // Already imported in a prior run. Default is to skip (idempotent), but a\n // source whose native log GREW is re-imported in place, and --force\n // deletes + replaces regardless.\n if (priors.length > 0 && options.force !== true) {\n const prior = await classifyReimport(priors, sourcePath, externalId, counts);\n if (prior === null) continue; // skip recorded by classifyReimport\n const payload = validate(await toPayload());\n if (payload === null) {\n counts.skippedNoAction++;\n continue;\n }\n // Re-confirm growth against the size ACTUALLY read (the decision above used\n // a cheap pre-read stat): if the source was truncated / rotated between the\n // stat and the read, the smaller buffer must not be re-imported as a grow.\n const readSize = payload.session.source.source_size_bytes;\n if (\n prior.sourceSizeBytes !== undefined &&\n readSize !== undefined &&\n readSize <= prior.sourceSizeBytes\n ) {\n console.error(\n `Import: ${externalId} source changed during read (now ${readSize} <= ${prior.sourceSizeBytes} bytes); re-import skipped`,\n );\n counts.skippedDecreased++;\n continue;\n }\n const outcome = await reimportPreservingId(paths, manifest, prior.sessionId, payload, {\n dryRun: options.dryRun === true,\n });\n if (outcome.status === \"skipped\") {\n const detail =\n outcome.reason === \"prior_events_unreadable\"\n ? \"prior events.jsonl has unreadable lines\"\n : outcome.reason === \"prior_chain_broken\"\n ? \"prior events.jsonl failed hash-chain verification (run 'basou verify')\"\n : \"source changed in a non-append way (derived events would be dropped)\";\n console.error(`Import: ${externalId} ${detail}; re-import skipped`);\n counts.skippedNoAction++;\n continue;\n }\n counts.reimported++;\n seenThisRun.add(externalId);\n continue;\n }\n\n const payload = validate(await toPayload());\n if (payload === null) {\n counts.skippedNoAction++;\n continue;\n }\n\n // --force replace: delete the prior session(s) for this external id, but\n // only once the fresh payload is known good, so a failed re-derivation\n // never destroys the existing import. Skipped under --dry-run.\n if (priors.length > 0 && options.force === true) {\n if (options.dryRun !== true) {\n for (const { sessionId } of priors) {\n await rm(join(paths.sessions, sessionId), { recursive: true, force: true });\n }\n }\n counts.replaced++;\n }\n\n const result = await importSessionFromJson(paths, manifest, payload, {\n dryRun: options.dryRun === true,\n });\n results.push(result);\n seenThisRun.add(externalId);\n sanitizedPaths +=\n result.pathSanitizeReport.relatedFiles +\n (result.pathSanitizeReport.workingDirectoryRewritten ? 1 : 0);\n }\n\n if (sanitizedPaths > 0) {\n console.error(`Imported sessions: ${sanitizedPaths} path(s) sanitized`);\n }\n\n printImportResult(options, results, counts);\n}\n\n/** Mutable tally of every import disposition, surfaced by {@link printImportResult}. */\ntype ImportCounts = {\n skippedNoAction: number;\n /** Already imported and unchanged (or a duplicate-within-this-run). */\n skippedExisting: number;\n /** Deleted + replaced under --force. */\n replaced: number;\n /** Re-imported in place because the source grew. */\n reimported: number;\n /** Already imported but with no recorded size (pre-size-tracking import); not re-imported. */\n skippedLegacy: number;\n /** Source shrank since import (truncated / rotated); needs --force to replace. */\n skippedDecreased: number;\n /** More than one prior session for one external id (anomalous); needs --force. */\n skippedDuplicate: number;\n};\n\n/**\n * Decide whether an already-imported external id should be re-imported in place\n * because its source grew. Returns the single prior import to re-import into, or\n * `null` (recording the right skip count) when it must be left alone:\n * unchanged / shrank / legacy (no recorded size) / anomalously duplicated. The\n * size probe is a parse-free `stat`, so unchanged sources are dismissed cheaply.\n */\nasync function classifyReimport(\n priors: PriorImport[],\n sourcePath: string,\n externalId: string,\n counts: ImportCounts,\n): Promise<PriorImport | null> {\n if (priors.length > 1) {\n // Anomalous: a scoped re-import cannot pick which id to preserve, and\n // delete+recreate would orphan any linked_events. Leave it to --force.\n console.error(\n `Import: ${externalId} has ${priors.length} prior sessions; re-import skipped (use --force)`,\n );\n counts.skippedDuplicate++;\n return null;\n }\n const prior = priors[0];\n if (prior === undefined) {\n counts.skippedExisting++;\n return null;\n }\n const currentSize = await statSize(sourcePath);\n if (currentSize === undefined) {\n // Source vanished between discovery and now; nothing to re-import.\n counts.skippedExisting++;\n return null;\n }\n if (prior.sourceSizeBytes === undefined) {\n // Legacy import (no recorded size baseline): never auto-re-import; the size\n // populates on the next --force / fresh import.\n counts.skippedLegacy++;\n return null;\n }\n if (currentSize === prior.sourceSizeBytes) {\n counts.skippedExisting++; // unchanged\n return null;\n }\n if (currentSize < prior.sourceSizeBytes) {\n // Truncated / rotated: do NOT auto-replace derived provenance; --force only.\n console.error(\n `Import: ${externalId} source shrank (${currentSize} < ${prior.sourceSizeBytes} bytes); re-import skipped (use --force to replace)`,\n );\n counts.skippedDecreased++;\n return null;\n }\n return prior; // grew => re-import preserving id\n}\n\n/**\n * Encode an absolute project path into Claude Code's per-project directory\n * name. Claude Code replaces path separators with `-`, so\n * `/Users/x/projects/foo` becomes `-Users-x-projects-foo`. Best-effort for\n * the common case; paths with characters the vendor encodes differently may\n * need an explicit `--project`-derived directory in a later revision.\n */\nfunction encodeProjectDir(projectPath: string): string {\n return projectPath.replaceAll(\"/\", \"-\");\n}\n\n/**\n * Map of source external_id -> Basou session id(s) already present in the\n * workspace for the given `sourceKind`, so a re-import can skip (default) or,\n * under --force, delete and replace the existing session. Scoping to one\n * source kind keeps each adapter's id namespace separate: a Codex import must\n * never dedup against, or delete, a Claude-derived session that happens to\n * share an id string. Recognises both the structured `source.external_id`\n * (current imports) and the `claude-code import <id>` label form (sessions\n * imported before external_id existed), so existing dogfood imports are\n * matched either way. Unreadable sessions are skipped.\n */\n/**\n * A prior Basou session for an external id, with the source byte size recorded\n * at its last import (absent for legacy imports made before the field existed).\n * The size lets a re-import detect that an append-only source GREW.\n */\ntype PriorImport = { sessionId: string; sourceSizeBytes?: number };\n\nasync function loadExistingByExternalId(\n paths: BasouPaths,\n sourceKind: SessionSourceKind,\n): Promise<Map<string, PriorImport[]>> {\n const byExternalId = new Map<string, PriorImport[]>();\n const add = (externalId: string, prior: PriorImport): void => {\n const list = byExternalId.get(externalId);\n if (list === undefined) byExternalId.set(externalId, [prior]);\n else list.push(prior);\n };\n let sessionIds: string[];\n try {\n sessionIds = await enumerateSessionDirs(paths);\n } catch {\n return byExternalId;\n }\n for (const sessionId of sessionIds) {\n let session: Session;\n try {\n session = await readSessionYaml(paths, sessionId);\n } catch {\n continue;\n }\n if (session.session.source.kind !== sourceKind) continue;\n const sourceSizeBytes = session.session.source.source_size_bytes;\n // Build once; omit the size key entirely when absent (legacy import) so the\n // optional property stays absent rather than explicitly undefined.\n const prior: PriorImport =\n sourceSizeBytes !== undefined ? { sessionId, sourceSizeBytes } : { sessionId };\n const ext = session.session.source.external_id;\n if (typeof ext === \"string\" && ext.length > 0) {\n add(ext, prior);\n continue;\n }\n const label = session.session.label;\n const match = typeof label === \"string\" ? label.match(/^claude-code import (\\S+)$/) : null;\n if (match?.[1] !== undefined) add(match[1], prior);\n }\n return byExternalId;\n}\n\n/**\n * Select the Claude transcript files to import across one or more source roots.\n * Each root maps to a per-project transcript directory under `projectsRoot`.\n * With `--session`, every root is probed and only existing matches are returned\n * (an error is raised only if no root holds that transcript). With `--all`, the\n * `.jsonl` files of every root are unioned; a root whose directory is absent\n * contributes nothing. The missing-directory error is raised only when NO root\n * has a transcript directory, so refresh classifies \"nothing anywhere\" as a\n * skip rather than a failure.\n */\nasync function selectTranscriptFiles(\n projectsRoot: string,\n projectPaths: string[],\n options: ImportClaudeCodeOptions,\n): Promise<string[]> {\n if (options.session !== undefined) {\n const matches: string[] = [];\n for (const projectPath of projectPaths) {\n const file = join(projectsRoot, encodeProjectDir(projectPath), `${options.session}.jsonl`);\n if (await pathExists(file)) matches.push(file);\n }\n if (matches.length === 0) {\n throw new Error(\"Claude transcript not found for session id in project\");\n }\n return [...new Set(matches)];\n }\n const files: string[] = [];\n let anyDirFound = false;\n for (const projectPath of projectPaths) {\n const transcriptDir = join(projectsRoot, encodeProjectDir(projectPath));\n let entries: string[];\n try {\n entries = await readdir(transcriptDir);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) continue; // this root has no transcripts; try the next\n throw new Error(\"Failed to read Claude transcript directory\", { cause: error });\n }\n anyDirFound = true;\n for (const name of entries) {\n if (name.endsWith(\".jsonl\")) files.push(join(transcriptDir, name));\n }\n }\n if (!anyDirFound) {\n throw new Error(\"Claude transcript directory not found for project\");\n }\n return [...new Set(files)].sort();\n}\n\n/** Whether `file` exists (ENOENT => false; any other error propagates). */\nasync function pathExists(file: string): Promise<boolean> {\n try {\n await stat(file);\n return true;\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) return false;\n throw error;\n }\n}\n\n/** The file's byte size, or undefined if it vanished (ENOENT); other errors propagate. */\nasync function statSize(file: string): Promise<number | undefined> {\n try {\n return (await stat(file)).size;\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) return undefined;\n throw error;\n }\n}\n\n/**\n * Discover the Codex rollouts that belong to any of `projectPaths`. Codex\n * stores rollouts under date directories (not per-project like Claude), so the\n * whole tree is walked once and each rollout's `session_meta.cwd` is matched\n * against the set of requested roots. The exact-match is also the safety\n * boundary: only sessions started in a requested root are ever imported.\n * `--session` narrows to a single rollout by its Codex session id within those\n * roots; a session id that matches no rollout is an error, mirroring how the\n * Claude path fails on a missing `--session` transcript rather than reporting a\n * silent success.\n */\nasync function discoverCodexRollouts(\n sessionsRoot: string,\n projectPaths: string[],\n options: ImportCodexOptions,\n): Promise<Array<{ file: string; externalId: string }>> {\n const projectSet = new Set(projectPaths);\n const files = await findRolloutFiles(sessionsRoot);\n const matched: Array<{ file: string; externalId: string }> = [];\n for (const file of files) {\n const meta = await readRolloutMeta(file);\n if (meta === undefined) continue;\n if (!projectSet.has(meta.cwd)) continue;\n if (options.session !== undefined && meta.id !== options.session) continue;\n matched.push({ file, externalId: meta.id });\n }\n if (options.session !== undefined && matched.length === 0) {\n throw new Error(\"Codex rollout not found for session id in project\");\n }\n return matched;\n}\n\n/** Recursively collect every `rollout-*.jsonl` under the Codex sessions root. */\nasync function findRolloutFiles(sessionsRoot: string): Promise<string[]> {\n const found: string[] = [];\n const walk = async (dir: string, isRoot: boolean): Promise<void> => {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n if (isRoot) {\n throw new Error(\"Codex sessions directory not found\", { cause: error });\n }\n return; // a subdir vanished mid-walk; ignore\n }\n throw new Error(\"Failed to read Codex sessions directory\", { cause: error });\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full, false);\n } else if (\n entry.isFile() &&\n entry.name.startsWith(\"rollout-\") &&\n entry.name.endsWith(\".jsonl\")\n ) {\n found.push(full);\n }\n }\n };\n await walk(sessionsRoot, true);\n return found.sort();\n}\n\n/**\n * Read just the `session_meta` (first record) of a rollout to learn its\n * project cwd and session id, without parsing the whole — usually large — log.\n * Returns `undefined` for any file whose first record is not a usable\n * `session_meta`, so the caller can skip it.\n */\nasync function readRolloutMeta(file: string): Promise<{ id: string; cwd: string } | undefined> {\n const firstLine = await readFirstLine(file);\n if (firstLine === undefined) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(firstLine);\n } catch {\n return undefined;\n }\n if (!isObject(parsed) || parsed.type !== \"session_meta\") return undefined;\n const payload = isObject(parsed.payload) ? parsed.payload : undefined;\n if (payload === undefined) return undefined;\n const id = payload.id;\n const cwd = payload.cwd;\n if (typeof id !== \"string\" || id.length === 0) return undefined;\n if (typeof cwd !== \"string\" || cwd.length === 0) return undefined;\n return { id, cwd };\n}\n\n/** Read the first non-empty line of a file, streaming so large files are cheap. */\nasync function readFirstLine(file: string): Promise<string | undefined> {\n const stream = createReadStream(file, { encoding: \"utf8\" });\n const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });\n try {\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed.length > 0) return trimmed;\n }\n return undefined;\n } catch {\n return undefined;\n } finally {\n rl.close();\n stream.destroy();\n }\n}\n\n/**\n * Read a JSONL native log into an array of records, plus the file's exact byte\n * size. A malformed line is skipped rather than failing the whole file, so\n * partial native logs still yield best-effort provenance. The byte size is read\n * from the SAME buffer that produced the records (an immutable snapshot), so the\n * size persisted as `source.source_size_bytes` always matches the imported\n * content even if the file is being appended to concurrently.\n */\nasync function readJsonlRecords(\n file: string,\n): Promise<{ records: ClaudeTranscriptRecord[]; sizeBytes: number }> {\n let buffer: Buffer;\n try {\n buffer = await readFile(file);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Source log not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Source log path is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read source log\", { cause: error });\n }\n\n const records: ClaudeTranscriptRecord[] = [];\n for (const line of buffer.toString(\"utf8\").split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (isObject(parsed)) {\n records.push(parsed);\n }\n } catch {\n // A malformed line is skipped rather than failing the whole file.\n }\n }\n return { records, sizeBytes: buffer.length };\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction printImportResult(\n options: ImportOptions,\n results: ImportSessionResult[],\n counts: ImportCounts,\n): void {\n const isDry = options.dryRun === true;\n const eventTotal = results.reduce((sum, r) => sum + r.eventCount, 0);\n const {\n skippedNoAction,\n skippedExisting,\n replaced,\n reimported,\n skippedLegacy,\n skippedDecreased,\n skippedDuplicate,\n } = counts;\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n imported: results.map((r) => ({\n session_id: r.sessionId,\n event_count: r.eventCount,\n status: r.finalStatus,\n source: { kind: r.finalSourceKind, version: \"0.1.0\" },\n })),\n imported_count: results.length,\n replaced_count: replaced,\n reimported_count: reimported,\n skipped_no_action: skippedNoAction,\n skipped_already_imported: skippedExisting,\n skipped_legacy_untracked: skippedLegacy,\n skipped_decreased: skippedDecreased,\n skipped_duplicate: skippedDuplicate,\n event_total: eventTotal,\n dry_run: isDry,\n }),\n );\n return;\n }\n\n const skipParts: string[] = [];\n if (skippedNoAction > 0) skipParts.push(`${skippedNoAction} with no actions`);\n if (skippedExisting > 0) skipParts.push(`${skippedExisting} already imported`);\n if (skippedLegacy > 0) skipParts.push(`${skippedLegacy} legacy (untracked size)`);\n if (skippedDecreased > 0) skipParts.push(`${skippedDecreased} shrank`);\n if (skippedDuplicate > 0) skipParts.push(`${skippedDuplicate} duplicated`);\n const skipSuffix = skipParts.length > 0 ? `; skipped ${skipParts.join(\", \")}` : \"\";\n const eventsPart =\n replaced > 0 ? `${eventTotal} events, ${replaced} replaced` : `${eventTotal} events`;\n\n if (isDry) {\n const parts: string[] = [];\n if (results.length > 0) parts.push(`import ${results.length} session(s) (${eventsPart})`);\n if (reimported > 0) parts.push(`re-import ${reimported} changed session(s)`);\n const head = parts.length > 0 ? `Dry run: would ${parts.join(\", \")}` : \"Dry run: no changes\";\n console.log(`${head}${skipSuffix}`);\n return;\n }\n\n if (results.length === 0 && reimported === 0) {\n console.log(\n skipParts.length > 0\n ? `No new sessions imported (skipped ${skipParts.join(\", \")})`\n : \"No transcripts found to import\",\n );\n return;\n }\n\n const segments: string[] = [];\n if (results.length > 0) {\n const single =\n results.length === 1 && results[0] !== undefined ? ` (${shortId(results[0].sessionId)})` : \"\";\n segments.push(`Imported ${results.length} session(s)${single} (${eventsPart})`);\n }\n if (reimported > 0) {\n segments.push(\n `${results.length > 0 ? \"re-imported\" : \"Re-imported\"} ${reimported} changed session(s)`,\n );\n }\n console.log(`${segments.join(\", \")}${skipSuffix}`);\n}\n\nfunction shortId(id: string): string {\n if (id.startsWith(SES_PREFIX)) {\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + SHORT_ID_LEN);\n }\n return id.slice(0, SHORT_ID_LEN);\n}\n\nasync function resolveRepositoryRootForImport(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou import'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { basename, relative, resolve } from \"node:path\";\nimport {\n appendBasouGitignore,\n createManifest,\n ensureBasouDirectory,\n resolveRepositoryRoot,\n tryRemoteUrl,\n writeManifest,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { extractCauseLabel, isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type InitOptions = {\n name?: string;\n projectName?: string;\n projectDescription?: string;\n repoUrl?: string;\n /**\n * Import source roots (repeatable). Each may be absolute or relative to the\n * invocation cwd; persisted as a path relative to the repository root under\n * `import.source_roots`, so one `.basou/` can aggregate sibling repos.\n */\n sourceRoot?: string[];\n force?: boolean;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectValue(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport type InitContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/**\n * Register `basou init` on a commander program. The `--repo-url \"\"` (empty\n * string) form is the documented way to set `project.repository_url` to\n * `null` explicitly; omitting `--repo-url` falls back to\n * `git config --local remote.origin.url` and finally to omission.\n */\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Initialize a Basou workspace at the current Git repository root\")\n .option(\"--name <name>\", \"Workspace name (defaults to the repository directory name)\")\n .option(\"--project-name <name>\", \"Project display name\")\n .option(\"--project-description <description>\", \"Project description\")\n .option(\n \"--repo-url <url>\",\n \"Repository URL (defaults to git remote.origin.url; pass empty string for null)\",\n )\n .option(\n \"--source-root <path>\",\n \"Extra import source root, relative to the repo root (repeatable; aggregates sibling repos into this workspace)\",\n collectValue,\n [],\n )\n .option(\"-f, --force\", \"Overwrite an existing manifest\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: InitOptions) => {\n await runInit(options);\n });\n}\n\n/**\n * Programmatic entry that mutates process state (`exitCode`, stderr).\n * Exported for tests, but tests should prefer {@link doRunInit} so they are\n * not coupled to process global state.\n */\nexport async function runInit(options: InitOptions, ctx: InitContext = {}): Promise<void> {\n try {\n await doRunInit(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolves inputs, calls core APIs, prints the success line.\n * On any failure throws an Error whose `message` is pathless and whose\n * `cause` MAY contain a native fs error. Exported for tests so they can\n * assert on thrown errors without touching `process.exitCode`.\n */\nexport async function doRunInit(options: InitOptions, ctx: InitContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForInit(cwd);\n const workspaceName = options.name ?? basename(repositoryRoot);\n\n // --repo-url > git config --local remote.origin.url > omit\n // --repo-url \"\" => explicit null\n let repositoryUrl: string | null | undefined;\n if (options.repoUrl !== undefined) {\n repositoryUrl = options.repoUrl === \"\" ? null : options.repoUrl;\n } else {\n repositoryUrl = await tryRemoteUrl(repositoryRoot);\n }\n\n // Normalize each --source-root to a repo-root-relative path. A root that is\n // the repo root itself becomes \".\". Stored relative so the committed manifest\n // carries no absolute machine paths.\n const sourceRoots = (options.sourceRoot ?? []).map((p) => {\n const rel = relative(repositoryRoot, resolve(cwd, p));\n return rel === \"\" ? \".\" : rel;\n });\n\n const paths = await ensureBasouDirectory(repositoryRoot);\n const manifest = createManifest({\n workspaceName,\n ...(options.projectName !== undefined ? { projectName: options.projectName } : {}),\n ...(options.projectDescription !== undefined\n ? { projectDescription: options.projectDescription }\n : {}),\n ...(repositoryUrl !== undefined ? { repositoryUrl } : {}),\n ...(sourceRoots.length > 0 ? { sourceRoots } : {}),\n });\n\n await writeManifest(paths, manifest, { force: options.force === true });\n\n // .gitignore is best-effort: init succeeds even if this step fails.\n // The \"safe to run on an existing Git repo\" completion contract holds\n // even when manifest writes but .gitignore cannot (e.g. permission\n // denied) -- the core feature set still works.\n try {\n await appendBasouGitignore(repositoryRoot);\n } catch (error: unknown) {\n renderGitignoreWarning(error, isVerbose(options));\n }\n\n console.log(`Initialized Basou workspace: ${manifest.workspace.id}`);\n}\n\n/**\n * Render a non-fatal warning when `.gitignore` cannot be updated. Mirrors\n * the pathless contract enforced by {@link renderCliError} — never prints\n * `error.cause.message` because native fs errors embed the absolute path\n * in it.\n */\nfunction renderGitignoreWarning(error: unknown, verbose: boolean): void {\n const baseMessage = error instanceof Error ? error.message : String(error);\n // The fallback hint is intentionally `dist`-only-portable: it does not\n // reference any in-repo doc path, since the CLI is published\n // independently of `docs/`.\n console.error(\n `Warning: Could not update .gitignore (${baseMessage}). Add Basou's default .gitignore block manually.`,\n );\n if (verbose && error instanceof Error) {\n const label = extractCauseLabel(error);\n if (label !== undefined) console.error(`Caused by: ${label}`);\n }\n}\n\n/**\n * Wrap the core git capability so the CLI surfaces the command-specific\n * \"Run 'git init' first, then re-run 'basou init'.\" suffix while the\n * capability layer remains command-agnostic.\n */\nasync function resolveRepositoryRootForInit(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou init'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import { assertBasouRootSafe, basouPaths, findErrorCode, resolveRepositoryRoot } from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { type ImportOutcome, type RefreshResult, refreshAll } from \"../lib/provenance-actions.js\";\nimport type { ImportContext } from \"./import.js\";\nimport {\n DEFAULT_WATCH_INTERVAL_SEC,\n MAX_WATCH_INTERVAL_SEC,\n MIN_WATCH_INTERVAL_SEC,\n runRefreshWatch,\n} from \"./refresh-watch.js\";\n\nexport type RefreshOptions = {\n project?: string[];\n force?: boolean;\n dryRun?: boolean;\n json?: boolean;\n /** Run as a long-lived watcher: re-import when the native logs change. */\n watch?: boolean;\n /** Poll interval in seconds for `--watch` (default {@link DEFAULT_WATCH_INTERVAL_SEC}). */\n interval?: number;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectPath(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** Commander parser: `--interval` is an integer count of seconds within the supported range. */\nexport function parseInterval(value: string): number {\n const seconds = Number(value);\n if (\n !Number.isInteger(seconds) ||\n seconds < MIN_WATCH_INTERVAL_SEC ||\n seconds > MAX_WATCH_INTERVAL_SEC\n ) {\n throw new InvalidArgumentError(\n `--interval must be an integer between ${MIN_WATCH_INTERVAL_SEC} and ${MAX_WATCH_INTERVAL_SEC} (seconds).`,\n );\n }\n return seconds;\n}\n\n/** Resolve after `ms`, or early when `signal` aborts (e.g. on Ctrl-C). Leaves no listener behind. */\nfunction abortableSleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n let timer: ReturnType<typeof setTimeout>;\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve();\n };\n timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport type RefreshContext = ImportContext & {\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou refresh` onto `program`. One command that imports every adapter\n * for the project and regenerates handoff + decisions, so the dogfood loop is\n * a single invocation instead of four.\n */\nexport function registerRefreshCommand(program: Command): void {\n program\n .command(\"refresh\")\n .description(\n \"Import all adapters for the project and regenerate handoff + decisions in one step\",\n )\n .option(\n \"--project <path>\",\n \"Source project path to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--force\", \"Re-import sessions already imported instead of skipping\")\n .option(\"--dry-run\", \"Preview imports and skip writing handoff / decisions\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\n \"--watch\",\n \"Keep running: re-import + regenerate when the native logs change (Ctrl-C to stop)\",\n )\n .option(\n \"--interval <seconds>\",\n `Poll interval for --watch, in seconds (default ${DEFAULT_WATCH_INTERVAL_SEC}, min ${MIN_WATCH_INTERVAL_SEC})`,\n parseInterval,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: RefreshOptions) => {\n await runRefresh(options);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. Tests should prefer\n * {@link doRunRefresh}, which returns the structured result.\n */\nexport async function runRefresh(options: RefreshOptions, ctx: RefreshContext = {}): Promise<void> {\n try {\n if (options.watch === true) {\n await doRunRefreshWatch(options, ctx);\n } else {\n await doRunRefresh(options, ctx);\n }\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * `basou refresh --watch`: resolve + validate, then run the polling watcher\n * until SIGINT / SIGTERM. Startup failures (bad combo, no workspace, failed\n * initial refresh) propagate and exit non-zero; a steady-state cycle failure is\n * logged inside the loop and the watcher keeps running.\n */\nexport async function doRunRefreshWatch(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<void> {\n if (options.dryRun === true) throw new Error(\"--watch cannot be combined with --dry-run.\");\n if (options.json === true) throw new Error(\"--watch cannot be combined with --json.\");\n if (options.force === true) throw new Error(\"--watch cannot be combined with --force.\");\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForRefresh(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const intervalMs = (options.interval ?? DEFAULT_WATCH_INTERVAL_SEC) * 1000;\n const controller = new AbortController();\n const onSignal = (): void => controller.abort();\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n try {\n await runRefreshWatch({\n ctx,\n paths,\n intervalMs,\n importOptions:\n options.project !== undefined && options.project.length > 0\n ? { project: options.project }\n : {},\n now: () => ctx.nowProvider?.() ?? new Date(),\n signal: controller.signal,\n sleep: abortableSleep,\n log: (line) => console.log(line),\n });\n } finally {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n }\n}\n\n/**\n * Pure runner: resolves the workspace, runs the shared refresh pipeline, and\n * prints a summary (or JSON). Returns the {@link RefreshResult} so the same\n * pipeline can be exercised by tests and reused by the view server.\n */\nexport async function doRunRefresh(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<RefreshResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForRefresh(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await refreshAll({\n options: {\n ...(options.project !== undefined && options.project.length > 0\n ? { project: options.project }\n : {}),\n ...(options.force === true ? { force: true } : {}),\n ...(options.dryRun === true ? { dryRun: true } : {}),\n },\n ctx,\n paths,\n nowIso,\n });\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n printRefreshSummary(result);\n }\n return result;\n}\n\nfunction describeImport(outcome: ImportOutcome): string {\n if (outcome.status === \"skipped\") {\n return `${outcome.adapter}: skipped (${outcome.reason})`;\n }\n const verb = outcome.dryRun ? \"would import\" : \"imported\";\n const parts = [`${outcome.importedCount} session(s)`, `${outcome.eventTotal} events`];\n if (outcome.reimportedCount > 0) parts.push(`${outcome.reimportedCount} re-imported`);\n if (outcome.replacedCount > 0) parts.push(`${outcome.replacedCount} replaced`);\n if (outcome.skippedAlreadyImported > 0)\n parts.push(`${outcome.skippedAlreadyImported} already imported`);\n if (outcome.skippedLegacyUntracked > 0) parts.push(`${outcome.skippedLegacyUntracked} legacy`);\n return `${outcome.adapter}: ${verb} ${parts.join(\", \")}`;\n}\n\nfunction printRefreshSummary(result: RefreshResult): void {\n console.log(describeImport(result.claudeCode));\n console.log(describeImport(result.codex));\n if (result.handoff.status === \"generated\") {\n console.log(\n `handoff: regenerated (sessions: ${result.handoff.sessionCount}, decisions: ${result.handoff.decisionCount})`,\n );\n } else {\n console.log(`handoff: skipped (${result.handoff.reason})`);\n }\n if (result.decisions.status === \"generated\") {\n console.log(`decisions: regenerated (${result.decisions.decisionCount})`);\n } else {\n console.log(`decisions: skipped (${result.decisions.reason})`);\n }\n}\n\nasync function resolveRepositoryRootForRefresh(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou refresh'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n type BasouPaths,\n readMarkdownFile,\n renderDecisions,\n renderHandoff,\n renderWithMarkers,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport {\n doRunImportClaudeCode,\n doRunImportCodex,\n type ImportContext,\n type ImportOptions,\n} from \"../commands/import.js\";\n\n/**\n * Shared provenance actions reused by both `basou refresh` (one-shot CLI) and\n * the `basou view` server's action endpoints, so the two stay behaviourally\n * identical. These wrap the existing import commands and markdown renderers;\n * they own no process state and print nothing of their own.\n */\n\n/** Which native-log adapter an import outcome came from. */\nexport type ImportAdapter = \"claude-code\" | \"codex\";\n\n/** Result of running one adapter's import, or a note that it was skipped. */\nexport type ImportOutcome =\n | {\n adapter: ImportAdapter;\n status: \"ran\";\n importedCount: number;\n replacedCount: number;\n /** Sessions re-imported in place because their source grew. */\n reimportedCount: number;\n skippedNoAction: number;\n skippedAlreadyImported: number;\n /** Already imported but with no recorded source size (pre-size-tracking); not re-imported. */\n skippedLegacyUntracked: number;\n eventTotal: number;\n dryRun: boolean;\n }\n | { adapter: ImportAdapter; status: \"skipped\"; reason: string };\n\n/** Counts from regenerating handoff.md / decisions.md, or a skip note. */\nexport type GenerateOutcome<TExtra> =\n | ({ status: \"generated\" } & TExtra)\n | { status: \"skipped\"; reason: string };\n\nexport type HandoffCounts = {\n sessionCount: number;\n taskCount: number;\n decisionCount: number;\n pendingApprovalsCount: number;\n};\n\n/** Structured result of {@link refreshAll}. */\nexport type RefreshResult = {\n claudeCode: ImportOutcome;\n codex: ImportOutcome;\n handoff: GenerateOutcome<HandoffCounts>;\n decisions: GenerateOutcome<{ decisionCount: number }>;\n dryRun: boolean;\n};\n\nexport type RefreshActionOptions = {\n project?: string[];\n force?: boolean;\n dryRun?: boolean;\n};\n\n/**\n * Run `fn` (an import command invoked with `json: true`) while capturing its\n * console output, then return the single machine-readable JSON result line.\n * The import commands print their result as one JSON object on stdout; that\n * line is the result contract. `console` is always restored, even on throw.\n */\nasync function captureImportJson(fn: () => Promise<void>): Promise<Record<string, unknown>> {\n const stdout: string[] = [];\n const originalLog = console.log;\n const originalError = console.error;\n console.log = ((...args: unknown[]) => {\n stdout.push(args.map((a) => String(a)).join(\" \"));\n }) as typeof console.log;\n // The import path writes an informational \"N path(s) sanitized\" line to\n // stderr; swallow it so refresh / the view server stay quiet.\n console.error = (() => {}) as typeof console.error;\n try {\n await fn();\n } finally {\n console.log = originalLog;\n console.error = originalError;\n }\n for (let i = stdout.length - 1; i >= 0; i--) {\n const line = stdout[i];\n if (line === undefined) continue;\n try {\n const parsed: unknown = JSON.parse(line);\n if (parsed !== null && typeof parsed === \"object\" && \"imported_count\" in parsed) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Not the JSON result line; keep scanning earlier lines.\n }\n }\n throw new Error(\"Import produced no parseable result\");\n}\n\nfunction readCount(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/**\n * A source-log directory that does not exist for the requested project is a\n * normal \"this adapter has nothing here\" condition for refresh, not a failure.\n */\nfunction isMissingSourceDir(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.message === \"Claude transcript directory not found for project\" ||\n error.message === \"Codex sessions directory not found\"\n );\n}\n\n/** Run one adapter import as a best-effort action, classifying a missing source dir as skipped. */\nasync function runImport(adapter: ImportAdapter, fn: () => Promise<void>): Promise<ImportOutcome> {\n try {\n const json = await captureImportJson(fn);\n return {\n adapter,\n status: \"ran\",\n importedCount: readCount(json.imported_count),\n replacedCount: readCount(json.replaced_count),\n reimportedCount: readCount(json.reimported_count),\n skippedNoAction: readCount(json.skipped_no_action),\n skippedAlreadyImported: readCount(json.skipped_already_imported),\n skippedLegacyUntracked: readCount(json.skipped_legacy_untracked),\n eventTotal: readCount(json.event_total),\n dryRun: json.dry_run === true,\n };\n } catch (error: unknown) {\n if (isMissingSourceDir(error)) {\n return { adapter, status: \"skipped\", reason: \"no source logs for this project\" };\n }\n throw error;\n }\n}\n\nfunction importOptions(options: RefreshActionOptions): ImportOptions {\n return {\n all: true,\n json: true,\n ...(options.project !== undefined ? { project: options.project } : {}),\n ...(options.force === true ? { force: true } : {}),\n ...(options.dryRun === true ? { dryRun: true } : {}),\n };\n}\n\n/** Import Claude Code transcripts for the project (best-effort). */\nexport function importClaudeCode(\n options: RefreshActionOptions,\n ctx: ImportContext,\n): Promise<ImportOutcome> {\n return runImport(\"claude-code\", () => doRunImportClaudeCode(importOptions(options), ctx));\n}\n\n/** Import Codex rollouts for the project (best-effort). */\nexport function importCodex(\n options: RefreshActionOptions,\n ctx: ImportContext,\n): Promise<ImportOutcome> {\n return runImport(\"codex\", () => doRunImportCodex(importOptions(options), ctx));\n}\n\ntype RenderCallbacks = Parameters<typeof renderHandoff>[0];\n\n/** Regenerate `.basou/handoff.md` and return the renderer's counts. */\nexport async function regenerateHandoff(\n paths: BasouPaths,\n nowIso: string,\n callbacks?: Omit<RenderCallbacks, \"paths\" | \"nowIso\">,\n): Promise<HandoffCounts> {\n const result = await renderHandoff({ paths, nowIso, ...callbacks });\n const existing = await readMarkdownFile(paths.files.handoff);\n await writeMarkdownFile(\n paths.files.handoff,\n renderWithMarkers(existing, result.body, \"handoff.md\"),\n );\n return {\n sessionCount: result.sessionCount,\n taskCount: result.taskCount,\n decisionCount: result.decisionCount,\n pendingApprovalsCount: result.pendingApprovalsCount,\n };\n}\n\n/** Regenerate `.basou/decisions.md` and return the decision count. */\nexport async function regenerateDecisions(\n paths: BasouPaths,\n nowIso: string,\n callbacks?: Omit<Parameters<typeof renderDecisions>[0], \"paths\" | \"nowIso\">,\n): Promise<{ decisionCount: number }> {\n const result = await renderDecisions({ paths, nowIso, ...callbacks });\n const existing = await readMarkdownFile(paths.files.decisions);\n await writeMarkdownFile(\n paths.files.decisions,\n renderWithMarkers(existing, result.body, \"decisions.md\"),\n );\n return { decisionCount: result.decisionCount };\n}\n\n/**\n * The shared refresh pipeline: import both adapters (best-effort) for the\n * project, then regenerate handoff + decisions. Under `dryRun`, imports run in\n * preview mode and the markdown files are left untouched. The caller resolves\n * `paths` / `nowIso` and supplies the import `ctx`.\n */\nexport async function refreshAll(args: {\n options: RefreshActionOptions;\n ctx: ImportContext;\n paths: BasouPaths;\n nowIso: string;\n}): Promise<RefreshResult> {\n const { options, ctx, paths, nowIso } = args;\n const dryRun = options.dryRun === true;\n\n const claudeCode = await importClaudeCode(options, ctx);\n const codex = await importCodex(options, ctx);\n\n if (dryRun) {\n const skipped = { status: \"skipped\" as const, reason: \"dry-run\" };\n return { claudeCode, codex, handoff: skipped, decisions: skipped, dryRun };\n }\n\n const handoffCounts = await regenerateHandoff(paths, nowIso);\n const decisionCounts = await regenerateDecisions(paths, nowIso);\n return {\n claudeCode,\n codex,\n handoff: { status: \"generated\", ...handoffCounts },\n decisions: { status: \"generated\", ...decisionCounts },\n dryRun,\n };\n}\n","import type { Dirent } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BasouPaths, findErrorCode } from \"@basou/core\";\nimport {\n type ImportOutcome,\n importClaudeCode,\n importCodex,\n type RefreshActionOptions,\n regenerateDecisions,\n regenerateHandoff,\n} from \"../lib/provenance-actions.js\";\nimport type { ImportContext } from \"./import.js\";\n\n/** Default poll interval for `--watch`, in seconds. */\nexport const DEFAULT_WATCH_INTERVAL_SEC = 30;\n/** Smallest accepted `--interval`, in seconds. */\nexport const MIN_WATCH_INTERVAL_SEC = 5;\n/** Largest accepted `--interval`, in seconds (1 day; keeps the timer well within the 32-bit ms range). */\nexport const MAX_WATCH_INTERVAL_SEC = 86_400;\n\n/** A file's change signature: a refresh is triggered when this moves. */\ntype FileSig = { mtimeMs: number; size: number };\n/** Absolute `*.jsonl` path -> its {mtime, size} signature. */\nexport type SourceLogScan = Map<string, FileSig>;\n\n/**\n * The native-log stores the importers read (Codex rollouts + Claude\n * transcripts), resolved from the context or the `~` defaults. These are the\n * directories the watcher polls -- a new session is a new/grown `*.jsonl` here.\n */\nexport function watchedRoots(ctx: ImportContext): string[] {\n return [\n ctx.codexSessionsDir ?? join(homedir(), \".codex\", \"sessions\"),\n ctx.claudeProjectsDir ?? join(homedir(), \".claude\", \"projects\"),\n ];\n}\n\n/**\n * Recursively collect a `{mtime, size}` signature of every `*.jsonl` under the\n * given roots, keyed by absolute path. A missing root contributes nothing (it\n * may appear later); a file that vanishes mid-walk is skipped. No file content\n * is read, so this is cheap to run every poll.\n */\nexport async function scanSourceLogs(roots: string[]): Promise<SourceLogScan> {\n const out: SourceLogScan = new Map();\n const walk = async (dir: string): Promise<void> => {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error: unknown) {\n // Absent (ENOENT) or not a directory (ENOTDIR): nothing to scan here.\n if (findErrorCode(error, \"ENOENT\") || findErrorCode(error, \"ENOTDIR\")) return;\n // Surface other errors pathlessly (the native message carries the path).\n throw new Error(\"Failed to read a source log directory\", { cause: error });\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n try {\n const info = await stat(full);\n out.set(full, { mtimeMs: info.mtimeMs, size: info.size });\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) continue; // vanished mid-walk; skip\n throw new Error(\"Failed to stat a source log file\", { cause: error });\n }\n }\n }\n };\n for (const root of roots) await walk(root);\n return out;\n}\n\n/** Whether two scans describe the same set of files at the same size/mtime. */\nexport function scansEqual(a: SourceLogScan, b: SourceLogScan): boolean {\n if (a.size !== b.size) return false;\n for (const [path, sig] of a) {\n const other = b.get(path);\n if (other === undefined || other.mtimeMs !== sig.mtimeMs || other.size !== sig.size) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * How many sessions an import outcome changed on disk: new imports PLUS\n * in-place re-imports of grown sources PLUS --force replacements. Any\n * non-zero count must trigger a handoff / decisions regeneration, so a session\n * that was re-imported (not freshly imported) does not leave the derived\n * markdown stale.\n */\nfunction changedCount(outcome: ImportOutcome): number {\n return outcome.status === \"ran\"\n ? outcome.importedCount + outcome.reimportedCount + outcome.replacedCount\n : 0;\n}\n\nfunction describeOutcome(outcome: ImportOutcome): string {\n if (outcome.status !== \"ran\") return `${outcome.adapter} skipped`;\n const reimported = outcome.reimportedCount > 0 ? ` ~${outcome.reimportedCount}` : \"\";\n return `${outcome.adapter} +${outcome.importedCount}${reimported}`;\n}\n\nfunction hms(date: Date): string {\n return date.toISOString().slice(11, 19);\n}\n\n/** Dependencies for {@link runRefreshWatch}; timers / clock / signal are injectable for tests. */\nexport type WatchDeps = {\n ctx: ImportContext;\n paths: BasouPaths;\n intervalMs: number;\n /** Import options forwarded to each cycle (project source roots only; no force / dry-run in watch). */\n importOptions: RefreshActionOptions;\n now: () => Date;\n signal: AbortSignal;\n /** Resolves after `ms`, or early when `signal` aborts. */\n sleep: (ms: number, signal: AbortSignal) => Promise<void>;\n log: (line: string) => void;\n};\n\n/** Import both adapters for the workspace's source roots; returns the outcomes + total imported. */\nasync function runImports(\n deps: WatchDeps,\n): Promise<{ claude: ImportOutcome; codex: ImportOutcome; changed: number }> {\n const claude = await importClaudeCode(deps.importOptions, deps.ctx);\n const codex = await importCodex(deps.importOptions, deps.ctx);\n return { claude, codex, changed: changedCount(claude) + changedCount(codex) };\n}\n\n/** Regenerate handoff + decisions; returns the handoff session count. */\nasync function regenerate(deps: WatchDeps): Promise<number> {\n const nowIso = deps.now().toISOString();\n const handoff = await regenerateHandoff(deps.paths, nowIso);\n await regenerateDecisions(deps.paths, nowIso);\n return handoff.sessionCount;\n}\n\n/**\n * Poll the native-log stores and keep the workspace current. Does an initial\n * catch-up refresh, then on each interval re-imports ONLY when the logs are\n * quiescent (unchanged since the previous poll, so no session is mid-write) AND\n * have changed since the last import. Handoff / decisions regenerate only when\n * something was imported, so unrelated AI activity elsewhere never rewrites this\n * workspace's files. A failure inside a steady-state cycle is logged and the\n * loop continues; the initial refresh failing is fatal (it propagates). Returns\n * when `signal` aborts (after the in-flight cycle, never mid-write).\n */\nexport async function runRefreshWatch(deps: WatchDeps): Promise<void> {\n const { intervalMs, ctx, signal, sleep, log } = deps;\n const roots = watchedRoots(ctx);\n log(\n `watching ${roots.join(\", \")} every ${Math.round(intervalMs / 1000)}s ` +\n \"(imports on change; Ctrl-C to stop)\",\n );\n\n // Baseline BEFORE the initial import, so a session that appears during the\n // import window is not mistaken for \"already seen\" and missed forever.\n let lastScan = await scanSourceLogs(roots);\n let importedScan = lastScan;\n\n // Initial catch-up: failure here is fatal (propagates to the caller).\n const initial = await runImports(deps);\n const initialSessions = await regenerate(deps);\n log(\n `[${hms(deps.now())}] refreshed: ${describeOutcome(initial.codex)}, ` +\n `${describeOutcome(initial.claude)} (sessions: ${initialSessions})`,\n );\n if (signal.aborted) {\n log(\"watch stopped\");\n return;\n }\n\n // Set when an import succeeded but the matching regenerate has not yet (so a\n // regenerate failure cannot leave handoff / decisions stale forever).\n let pendingRegen = false;\n while (!signal.aborted) {\n await sleep(intervalMs, signal);\n if (signal.aborted) break;\n try {\n const current = await scanSourceLogs(roots);\n // Quiescent since the previous poll AND changed since the last import.\n if (scansEqual(current, lastScan) && !scansEqual(current, importedScan)) {\n const { claude, codex, changed } = await runImports(deps);\n if (changed > 0) pendingRegen = true;\n if (pendingRegen) {\n const sessions = await regenerate(deps);\n pendingRegen = false;\n log(\n `[${hms(deps.now())}] refreshed: ${describeOutcome(codex)}, ` +\n `${describeOutcome(claude)} (sessions: ${sessions})`,\n );\n }\n importedScan = current;\n }\n lastScan = current;\n } catch (error: unknown) {\n // A transient fs error must not kill a long-running watcher. Messages from\n // the scan / import / render layers are pathless by contract.\n const message = error instanceof Error ? error.message : String(error);\n log(`[${hms(deps.now())}] refresh cycle skipped: ${message}`);\n }\n }\n log(\"watch stopped\");\n}\n","import { isAbsolute, resolve } from \"node:path\";\nimport {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n renderReport,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n printTaskSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type ReportGenerateOptions = {\n out?: string;\n json?: boolean;\n title?: string;\n verbose?: boolean;\n};\n\nexport type ReportContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou report generate` onto `program`. The `report` group is\n * registered up front so future subcommands (e.g. `show`) can slot under the\n * same group without breaking the CLI surface.\n */\nexport function registerReportCommand(program: Command): void {\n const report = program\n .command(\"report\")\n .description(\n \"Generate a work report — a shareable export explaining the work in this workspace\",\n );\n\n report\n .command(\"generate\")\n .description(\"Generate a work report from the current workspace state\")\n .option(\"--out <path>\", \"Write the markdown report to a file instead of stdout\")\n .option(\"--json\", \"Emit the structured report data as JSON to stdout\")\n .option(\"--title <text>\", \"Subject line shown in the report header\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ReportGenerateOptions) => {\n await runReportGenerate(opts);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. A successful render always\n * exits 0 — integrity verdicts inside the report (`unchained` / `tampered`) are\n * informational and never fail the command (unlike `basou verify`). Only real\n * operational failures set a non-zero exit. [Codex #8]\n */\nexport async function runReportGenerate(\n options: ReportGenerateOptions,\n ctx: ReportContext = {},\n): Promise<void> {\n try {\n await doRunReportGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `report generate`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n *\n * Output contract:\n * - default → markdown body to stdout.\n * - `--json` → structured data as JSON to stdout, JSON-only (pipe-safe).\n * - `--out <path>` → write the markdown body to the file; a one-line summary\n * goes to stderr (never stdout) so `--out` composes with `--json`.\n */\nexport async function doRunReportGenerate(\n options: ReportGenerateOptions,\n ctx: ReportContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForReport(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderReport({\n paths,\n nowIso,\n ...(options.title !== undefined ? { title: options.title } : {}),\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n });\n\n if (options.out !== undefined) {\n const outPath = isAbsolute(options.out) ? options.out : resolve(cwd, options.out);\n await writeMarkdownFile(outPath, result.body);\n const { sessions, decisions, tasks } = result.data;\n // Confirmation on stderr (console.error) so stdout stays clean for `--json`.\n console.error(\n `Wrote report to ${options.out} (sessions: ${sessions.total}, decisions: ${decisions.count}, tasks: ${tasks.total})`,\n );\n }\n\n if (options.json === true) {\n console.log(JSON.stringify(result.data, null, 2));\n } else if (options.out === undefined) {\n console.log(result.body);\n }\n}\n\nasync function resolveRepositoryRootForReport(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou report generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n acquireLock,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n ChildProcessRunner,\n claudeCodeAdapterMetadata,\n appendChainedEvent as coreAppendChainedEvent,\n type DiffResult,\n finalizeSessionYaml,\n type GitSnapshot,\n getDiff,\n getSnapshot,\n overwriteYamlFile,\n type PrefixedId,\n type ProcessRunner,\n prefixedUlid,\n type RunResult,\n readManifest,\n readYamlFile,\n resolveClaudeCodeCommand,\n resolveRepositoryRoot,\n type Session,\n SessionSchema,\n sanitizeRelatedFiles,\n sanitizeWorkingDirectory,\n writeYamlFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\n// Appends one event to the session's events.jsonl. The `sessionDir` argument\n// is retained for the test-injection seam (ctx.appendEvent); the production\n// binding ignores it and chains via paths + sessionId.\ntype AppendEventFn = (sessionDir: string, event: unknown) => Promise<void>;\ntype ResolveCommandFn = typeof resolveClaudeCodeCommand;\ntype GetDiffFn = typeof getDiff;\n\n/**\n * `basou run claude-code` orchestration: spawn claude-code as a single new\n * Basou session and record its lifecycle (session_started, optional\n * git_snapshot pre, status_changed, command_executed, optional git_snapshot\n * post, file_changed × N, status_changed, session_ended) to events.jsonl.\n *\n * The child inherits the parent's stdio (`capture: \"none\"`) so that\n * claude-code's interactive TTY remains usable; raw stdout/stderr is\n * intentionally NOT captured into events.jsonl or `.basou/raw/` in v0.1.\n */\nexport type RunOptions = {\n // commander turns `--no-snapshot` into `snapshot: false`. The default\n // (no flag) leaves this `undefined` (treated as `true` downstream).\n snapshot?: boolean;\n cwd?: string;\n verbose?: boolean;\n};\n\nexport type RunContext = {\n runner?: ProcessRunner;\n now?: () => Date;\n appendEvent?: AppendEventFn;\n onExitHookInstalled?: (handler: () => void) => void;\n // Override the claude-code PATH lookup. Tests use this to skip real\n // `which` invocations and force success / failure deterministically.\n resolveCommand?: ResolveCommandFn;\n // Override the git diff capability. Tests use this to force capability\n // failure deterministically without rewriting the git fixture state.\n getDiff?: GetDiffFn;\n};\n\n/**\n * Wire the `basou run` command group into `program`. The optional `ctx` is\n * passed through to `runClaudeCode` so tests can intercept the action callback\n * (fake runner, fake clock, deterministic resolveCommand / getDiff). Production\n * callers omit it.\n *\n * Basou options (`--no-snapshot`, `--cwd`, `-v`) are defined on both the\n * `run` group and the inner `claude-code` subcommand. commander's\n * `passThroughOptions()` only forwards UNKNOWN options to args, so a\n * group-only definition would make `basou run claude-code --no-snapshot`\n * crash with \"unknown option\". Duplicating the definitions lets the option\n * be recognized regardless of position; only `--`-separated args go to the\n * child. v0.2+ adapter additions (codex / gemini) should consider\n * extracting a common-option helper rather than re-duplicating.\n */\nexport function registerRunCommand(program: Command, ctx: RunContext = {}): void {\n const runCommand = program\n .command(\"run\")\n .description(\"Run an AI coding tool through Basou as a tracked session\")\n // Required so the inner `claude-code` subcommand can pass through\n // arguments after `--` to the child without commander interpreting them\n // as run-group options.\n .enablePositionalOptions()\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the session\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\");\n\n runCommand\n .command(\"claude-code [args...]\")\n .description(\"Run Claude Code CLI as a Basou-tracked session\")\n // Same options redeclared on the subsubcommand so they are recognized\n // when placed AFTER `claude-code` as well; see the function comment.\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the session\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .passThroughOptions()\n .action(async (args: string[], options: RunOptions, command: Command) => {\n const parentOptions = (command.parent?.opts() ?? {}) as RunOptions;\n // Both layers default `snapshot` to `true` when --no-snapshot is\n // omitted, so a naive spread would let the subsubcommand's default\n // overwrite a `--no-snapshot` set on the parent. Take a logical AND\n // instead: snapshot stays on only when neither layer disables it.\n const snapshotOn = parentOptions.snapshot !== false && options.snapshot !== false;\n const merged: RunOptions = {\n ...parentOptions,\n ...options,\n snapshot: snapshotOn,\n };\n try {\n const exitCode = await runClaudeCode(args, merged, ctx);\n process.exit(exitCode);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(merged) });\n process.exit(1);\n }\n });\n}\n\nexport async function runClaudeCode(\n args: string[],\n options: RunOptions,\n ctx: RunContext = {},\n): Promise<number> {\n const runner = ctx.runner ?? new ChildProcessRunner();\n const now = ctx.now ?? (() => new Date());\n const resolveCommand: ResolveCommandFn = ctx.resolveCommand ?? resolveClaudeCodeCommand;\n const getDiffFn: GetDiffFn = ctx.getDiff ?? getDiff;\n\n // 1. Resolve the claude-code executable BEFORE any side-effect: a missing\n // CLI is a user installation issue, not something worth recording as a\n // Basou session. Failure here leaves no sessions/<id>/ entry behind.\n const { command } = await resolveCommand();\n\n const cwd = options.cwd ?? process.cwd();\n\n // 2. Resolve repository root (entry-fail when not in a git repo).\n const repoRoot = await resolveRepositoryRootForRun(cwd);\n const paths = basouPaths(repoRoot);\n\n // 3. Workspace safety check.\n await assertBasouRootSafe(paths.root);\n\n // 4. Read manifest to bind session.workspace_id.\n const manifest = await readManifest(paths);\n\n // 5. Build a fresh session and persist its initial state.\n const sessionId = prefixedUlid(\"ses\");\n const sessionDir = join(paths.sessions, sessionId);\n await mkdir(sessionDir, { recursive: true });\n\n // Every append chains onto the on-disk tail under a short-lived session lock\n // (the self-locking wrapper); the lock is NEVER held across the child. Tests\n // inject ctx.appendEvent to force append failures.\n const appendEvent: AppendEventFn =\n ctx.appendEvent ??\n (async (_sessionDir, event) => {\n await coreAppendChainedEvent(paths, sessionId, event);\n });\n\n const startedAt = now().toISOString();\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n const session = buildInitialSession({\n id: sessionId,\n command,\n args,\n cwd: repoRoot,\n workspaceId: manifest.workspace.id,\n startedAt,\n });\n await writeYamlFile(sessionYamlPath, session);\n\n // 6. session_started.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_started\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: startedAt,\n source: claudeCodeAdapterMetadata.kind,\n });\n\n // 7. Optional pre-execute git_snapshot.\n let preSnapshot: GitSnapshot | null = null;\n if (options.snapshot !== false) {\n preSnapshot = await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 8. status_changed: initialized -> running.\n const runningAt = now().toISOString();\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: runningAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"initialized\",\n to: \"running\",\n });\n // Lock the status write so it cannot interleave-clobber a foreign locked\n // session.yaml writer (e.g. a task attach setting task_id on this session).\n const runningLock = await acquireLock(paths, \"session\", sessionId);\n try {\n await mutateSessionYaml(sessionYamlPath, (s) => {\n s.session.status = \"running\";\n });\n } finally {\n await runningLock.release();\n }\n\n // 9. Transient signal hooks (SIGINT / SIGTERM / exit). The exit hook is a\n // last-resort SIGKILL if the parent dies abnormally.\n const controller = new AbortController();\n let signalReceived: NodeJS.Signals | null = null;\n let activeChild: ChildProcess | null = null;\n const signalHandler = (sig: NodeJS.Signals) => {\n if (signalReceived !== null) return;\n signalReceived = sig;\n controller.abort();\n };\n const exitHandler = () => {\n if (activeChild !== null) {\n try {\n activeChild.kill(\"SIGKILL\");\n } catch {\n // best-effort cleanup\n }\n }\n };\n const onSigInt = () => signalHandler(\"SIGINT\");\n const onSigTerm = () => signalHandler(\"SIGTERM\");\n process.on(\"SIGINT\", onSigInt);\n process.on(\"SIGTERM\", onSigTerm);\n process.on(\"exit\", exitHandler);\n ctx.onExitHookInstalled?.(exitHandler);\n\n // 10-11. runner.run() execute (capture: \"none\" inherits the parent stdio so\n // claude-code keeps a real TTY). Spawn-time errors finalize the\n // session as failed and propagate the error.\n let result: RunResult;\n try {\n try {\n result = await runner.run(command, args, {\n cwd: repoRoot,\n capture: \"none\",\n signal: controller.signal,\n onSpawn: (child) => {\n activeChild = child;\n },\n });\n } catch (spawnError: unknown) {\n await finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent, {\n command,\n args,\n cwd: repoRoot,\n occurredAt: now().toISOString(),\n signalReceived,\n });\n throw spawnError;\n }\n } finally {\n process.off(\"SIGINT\", onSigInt);\n process.off(\"SIGTERM\", onSigTerm);\n process.off(\"exit\", exitHandler);\n activeChild = null;\n }\n\n const endedAt = now().toISOString();\n\n // 12. command_executed (parent received_signal vs child terminating signal).\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n command,\n args,\n cwd: repoRoot,\n exit_code: result.exit_code,\n ...(result.signal !== null ? { signal: result.signal } : {}),\n ...(signalReceived !== null ? { received_signal: signalReceived } : {}),\n duration_ms: result.duration_ms,\n });\n\n // 13. Optional post-execute git_snapshot.\n let postSnapshot: GitSnapshot | null = null;\n if (options.snapshot !== false) {\n postSnapshot = await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 14-15. file_changed events derived from getDiff(preHead, postHead). Only\n // committed changes appear here; dirty (staged/unstaged/untracked)\n // edits are surfaced via session.yaml.related_files instead.\n let diff: DiffResult | null = null;\n if (preSnapshot !== null && postSnapshot !== null) {\n diff = await tryAppendFileChangedEvents(\n sessionDir,\n sessionId,\n repoRoot,\n preSnapshot.head,\n postSnapshot.head,\n now().toISOString(),\n appendEvent,\n getDiffFn,\n );\n }\n\n // 16. Compute related_files = pre+post snapshot ∪ diff (sorted, deduped).\n // Then sanitize so /Users/<u>/projects/foo/... is stored relative to\n // the session's working_directory; system paths outside both bases\n // stay verbatim. Git output is usually repo-relative already, but the\n // sanitizer is idempotent and cheap so we run it unconditionally\n // against the very subset of paths that ever reach session.yaml.\n const rawRelated = computeRelatedFiles(preSnapshot, postSnapshot, diff);\n const relatedFiles = sanitizeRelatedFiles(rawRelated, {\n workingDirectory: repoRoot,\n homedir: homedir(),\n }).sanitized;\n\n const finalStatus = decideFinalStatus(result, signalReceived);\n\n // 17-18. status_changed: running -> final.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"running\",\n to: finalStatus,\n });\n\n // 19. session_ended.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: claudeCodeAdapterMetadata.kind,\n ...(result.exit_code !== null ? { exit_code: result.exit_code } : {}),\n });\n\n // 20. Final session.yaml update (status / ended_at / invocation.exit_code /\n // related_files) plus the integrity head anchor, written from the on-disk\n // tail under the session lock so a foreign line appended just before\n // finalize is anchored and a later attach (now terminal) is rejected.\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = finalStatus;\n s.session.ended_at = endedAt;\n s.session.invocation.exit_code = result.exit_code;\n s.session.related_files = relatedFiles;\n });\n\n if (result.exit_code !== null) return result.exit_code;\n return signalToExitCode(signalReceived ?? result.signal);\n}\n\nfunction decideFinalStatus(\n result: { exit_code: number | null; signal: NodeJS.Signals | null },\n signalReceived: NodeJS.Signals | null,\n): \"completed\" | \"failed\" | \"interrupted\" {\n if (signalReceived === \"SIGINT\" || signalReceived === \"SIGTERM\") return \"interrupted\";\n if (result.signal === \"SIGINT\" || result.signal === \"SIGTERM\" || result.signal === \"SIGKILL\") {\n return \"interrupted\";\n }\n if (result.exit_code === 0) return \"completed\";\n return \"failed\";\n}\n\nconst SIGNUM_MAP: Record<string, number> = {\n SIGHUP: 1,\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n};\n\nfunction signalToExitCode(sig: NodeJS.Signals | null): number {\n if (sig === null) return 1;\n const num = SIGNUM_MAP[sig] ?? 1;\n return 128 + num;\n}\n\nasync function tryAppendGitSnapshot(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n now: () => Date,\n appendEvent: AppendEventFn,\n): Promise<GitSnapshot | null> {\n // Stage 1: capability acquisition. Capability-level failures (no git\n // repository, git binary missing, no commits) downgrade to a skip warning;\n // events.jsonl simply lacks this git_snapshot entry.\n let snapshot: GitSnapshot;\n try {\n snapshot = await getSnapshot(repoRoot);\n } catch (error: unknown) {\n console.warn(normalizeGitSnapshotSkipMessage(error));\n return null;\n }\n // Stage 2: events.jsonl append. Failures here would corrupt the events.jsonl\n // integrity contract; let them propagate so the run fails loudly rather\n // than producing a session that looks successful but is actually missing\n // events.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"git_snapshot\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: now().toISOString(),\n source: \"git-capability\",\n ...snapshot,\n });\n return snapshot;\n}\n\nasync function tryAppendFileChangedEvents(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n baseRef: string,\n headRef: string,\n occurredAt: string,\n appendEvent: AppendEventFn,\n getDiffFn: GetDiffFn,\n): Promise<DiffResult | null> {\n // Stage 1: capability acquisition (same skip-vs-fail split as\n // tryAppendGitSnapshot).\n let diff: DiffResult;\n try {\n diff = await getDiffFn(repoRoot, baseRef, headRef);\n } catch (error: unknown) {\n console.warn(normalizeFileChangedSkipMessage(error));\n return null;\n }\n // Stage 2: per-path appendEvent. Schema validation / disk failures here\n // are NOT a capability miss; let them propagate.\n for (const change of diff.changed_files) {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"file_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: occurredAt,\n source: \"git-capability\",\n path: change.path,\n change_type: change.status,\n ...(change.old_path !== undefined ? { old_path: change.old_path } : {}),\n });\n }\n return diff;\n}\n\nfunction computeRelatedFiles(\n preSnapshot: GitSnapshot | null,\n postSnapshot: GitSnapshot | null,\n diff: DiffResult | null,\n): string[] {\n const set = new Set<string>();\n for (const snap of [preSnapshot, postSnapshot]) {\n if (snap === null) continue;\n for (const p of snap.staged) set.add(p);\n for (const p of snap.unstaged) set.add(p);\n for (const p of snap.untracked) set.add(p);\n }\n if (diff !== null) {\n for (const change of diff.changed_files) set.add(change.path);\n }\n return [...set].sort();\n}\n\nfunction normalizeGitSnapshotSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `git_snapshot skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") return \"git_snapshot skipped: not in a git repository\";\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"git_snapshot skipped: git executable not found\";\n }\n if (msg === \"No commits in repository\") return \"git_snapshot skipped: no commits in repository\";\n return `git_snapshot skipped: ${msg}`;\n}\n\nfunction normalizeFileChangedSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `file_changed skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") return \"file_changed skipped: not in a git repository\";\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"file_changed skipped: git executable not found\";\n }\n if (msg === \"Invalid ref\") return \"file_changed skipped: invalid git ref\";\n if (msg === \"Failed to compute git diff\")\n return \"file_changed skipped: failed to compute git diff\";\n return `file_changed skipped: ${msg}`;\n}\n\nfunction buildInitialSession(input: {\n id: PrefixedId<\"ses\">;\n command: string;\n args: string[];\n cwd: string;\n workspaceId: PrefixedId<\"ws\">;\n startedAt: string;\n}): Session {\n const cmdline = [input.command, ...input.args].join(\" \");\n return {\n schema_version: \"0.1.0\",\n session: {\n id: input.id,\n label: `basou run ${cmdline} (${input.startedAt})`,\n task_id: null,\n workspace_id: input.workspaceId,\n source: { ...claudeCodeAdapterMetadata },\n started_at: input.startedAt,\n status: \"initialized\",\n working_directory: sanitizeWorkingDirectory(input.cwd, { homedir: homedir() }),\n invocation: {\n command: input.command,\n args: [...input.args],\n exit_code: null,\n },\n related_files: [],\n events_log: \"events.jsonl\",\n },\n };\n}\n\nasync function mutateSessionYaml(\n filePath: string,\n mutator: (session: Session) => void,\n): Promise<void> {\n const raw = await readYamlFile(filePath);\n const parsed = SessionSchema.parse(raw);\n mutator(parsed);\n const validated = SessionSchema.parse(parsed);\n await overwriteYamlFile(filePath, validated);\n}\n\nasync function finalizeSessionAsFailed(\n paths: BasouPaths,\n sessionDir: string,\n sessionId: string,\n appendEvent: AppendEventFn,\n ctx: {\n command: string;\n args: string[];\n cwd: string;\n occurredAt: string;\n signalReceived: NodeJS.Signals | null;\n },\n): Promise<void> {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n command: ctx.command,\n args: ctx.args,\n cwd: ctx.cwd,\n exit_code: null,\n signal: null,\n ...(ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {}),\n duration_ms: 0,\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"running\",\n to: \"failed\",\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: claudeCodeAdapterMetadata.kind,\n });\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = \"failed\";\n s.session.ended_at = ctx.occurredAt;\n s.session.invocation.exit_code = null;\n });\n}\n\nasync function resolveRepositoryRootForRun(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou run'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { basename, isAbsolute, join, relative } from \"node:path\";\nimport {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n type Event,\n enumerateSessionDirs,\n findErrorCode,\n type ImportSessionOptions,\n type ImportSessionResult,\n importSessionFromJson,\n loadSessionEntries,\n type RechainResult,\n readAllEvents,\n readManifest,\n readYamlFile,\n rechainSessionInPlace,\n resolveRepositoryRoot,\n resolveSessionId,\n resolveTaskId,\n type Session,\n SessionImportPayloadSchema,\n SessionSchema,\n type SessionStatus,\n SessionStatusSchema,\n sessionWorkStatsFromEvents,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionListSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { formatDurationMs } from \"../lib/format-duration.js\";\n\nconst SES_PREFIX = \"ses_\";\nconst TASK_PREFIX = \"task_\";\nconst SHORT_ID_BASE_LEN = 6;\nconst SHORT_ID_MAX_LEN = 26; // ULID body length\n\nconst STATUS_VALUES = SessionStatusSchema.options;\n\nexport type SessionListOptions = {\n json?: boolean;\n status?: SessionStatus;\n verbose?: boolean;\n};\n\nexport type SessionShowOptions = {\n json?: boolean;\n events?: boolean;\n last?: number;\n fullPath?: boolean;\n verbose?: boolean;\n};\n\nexport type SessionContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable so the `session show` work\n * span is deterministic in tests and for a running session. */\n nowProvider?: () => Date;\n};\n\nexport type SessionRechainOptions = {\n session?: string;\n all?: boolean;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** One row of `basou session rechain` output. */\nexport type RechainRow = {\n session_id: string;\n status: \"rechained\" | \"skipped\" | \"error\";\n /** Skip reason, present when status is \"skipped\". */\n reason?: Extract<RechainResult, { status: \"skipped\" }>[\"reason\"];\n /** Chained event count, present when status is \"rechained\". */\n event_count?: number;\n /** Fixed error message, present when status is \"error\". */\n message?: string;\n};\n\ntype SessionListRecord = {\n sessionId: string;\n session: Session;\n suspect: boolean;\n suspectReason: string | null;\n};\n\n/**\n * Wire `basou session list` and `basou session show <id>` onto `program`.\n *\n * The `session` group is registered up front so future subcommands\n * (`note`, `import`) added in later steps slot under the same group without\n * changing the externally visible CLI surface.\n */\nexport function registerSessionCommand(program: Command): void {\n const session = program\n .command(\"session\")\n .description(\"Inspect Basou sessions stored under .basou/sessions/\");\n\n session\n .command(\"list\")\n .description(\"List sessions in the current workspace (newest first)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\n \"--status <state>\",\n `Filter by session status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseSessionStatus,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionListOptions) => {\n await runSessionList(options);\n });\n\n session\n .command(\"show <id>\")\n .description(\"Show a session's metadata and recent events\")\n .option(\"--json\", \"Output the session and events as JSON\")\n .option(\"--events\", \"List all events instead of just the trailing few\")\n .option(\"--last <n>\", \"Number of trailing events to display (default: 5)\", parsePositiveInt)\n .option(\n \"--full-path\",\n \"Show working_directory as an absolute path instead of repository-relative\",\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: SessionShowOptions) => {\n await runSessionShow(id, options);\n });\n\n session\n .command(\"import\")\n .description(\"Import a session from a JSON file\")\n .requiredOption(\"--format <format>\", \"Input format (currently only 'json')\", parseImportFormat)\n .requiredOption(\"--from <path>\", \"Path to the input JSON file\")\n .option(\"--label <text>\", \"Override the session label\", parseLabelOverride)\n .option(\"--task <task_id>\", \"Override the session task_id\", parseTaskIdOverride)\n .option(\"--dry-run\", \"Validate input only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionImportOptions) => {\n await runSessionImport(options);\n });\n\n session\n .command(\"note <session_id>\")\n .description(\"Append a note_added event to an existing session\")\n .option(\"--body <text>\", \"Note body (inline)\", parseNoteBodyOption)\n .option(\"--from-file <path>\", \"Read note body from a file\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (sessionIdInput: string, options: SessionNoteOptions) => {\n await runSessionNote(sessionIdInput, options);\n });\n\n session\n .command(\"rechain\")\n .description(\n \"Add the tamper-evidence hash chain, in place, to imported sessions created before chaining existed\",\n )\n .option(\"--session <id>\", \"Rechain a single session (unique id prefix accepted)\")\n .option(\"--all\", \"Rechain every session in the workspace\")\n .option(\"--dry-run\", \"Compute the outcomes only; do not write\")\n .option(\"--json\", \"Output the outcomes as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionRechainOptions) => {\n await runSessionRechain(options);\n });\n}\n\n/**\n * Programmatic entry for `basou session list` that owns process exit state.\n * Tests targeting only the success path or the thrown error should prefer\n * {@link doRunSessionList}.\n */\nexport async function runSessionList(\n options: SessionListOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `session list`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunSessionList(\n options: SessionListOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n // Orchestration is delegated to core's `loadSessionEntries`. To preserve\n // the existing stderr surface (\"Skipped <sid>: <reason>\" and\n // \"Warning: skipped suspect check for <sid>: events.jsonl unreadable\"),\n // map onSkip / onWarning on the CLI side.\n const now = new Date();\n const records: SessionListRecord[] = (\n await loadSessionEntries(paths, {\n now,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSkip: (sid, reason) => printSessionListSkip(sid, reason),\n })\n ).map((entry) => ({\n sessionId: entry.sessionId,\n session: entry.session,\n suspect: entry.suspect,\n suspectReason: entry.suspectReason,\n }));\n\n if (records.length === 0) {\n printNoSessions(options);\n return;\n }\n\n // started_at desc using Date.parse to normalize across timezone offsets;\n // a lexicographic compare would swap two timestamps that point at the same\n // instant when their offsets differ.\n records.sort(\n (a, b) => Date.parse(b.session.session.started_at) - Date.parse(a.session.session.started_at),\n );\n\n const filtered =\n options.status !== undefined\n ? records.filter((r) => r.session.session.status === options.status)\n : records;\n\n if (filtered.length === 0) {\n printNoSessions(options);\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((r) => ({\n ...r.session.session,\n suspect: r.suspect,\n suspect_reason: r.suspectReason,\n })),\n null,\n 2,\n ),\n );\n } else {\n printSessionListText(filtered);\n }\n}\n\n/**\n * Programmatic entry for `basou session show <id>`. See {@link runSessionList}\n * for the split pattern rationale.\n */\nexport async function runSessionShow(\n idInput: string,\n options: SessionShowOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionShow(\n idInput: string,\n options: SessionShowOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionId = await resolveSessionId(paths, idInput);\n\n const sessionDir = join(paths.sessions, sessionId);\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n let session: Session;\n try {\n const raw = await readYamlFile(sessionYamlPath);\n session = SessionSchema.parse(raw);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(`Session not found: ${idInput}`);\n }\n throw new Error(\"Failed to read session\", { cause: error });\n }\n\n const events = await readAllEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, sessionId),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify({ session: session.session, events }, null, 2));\n return;\n }\n\n const now = ctx.nowProvider?.() ?? new Date();\n printSessionShowText(session, events, options, repositoryRoot, now);\n}\n\nfunction suspectLabel(reason: string | null): string {\n if (reason === \"events_say_ended_but_yaml_running\") return \" ⚠ ended (yaml stale)\";\n if (reason === \"running_no_end_event\") return \" ⚠ no end event\";\n return \"\";\n}\n\nfunction printSessionListText(records: SessionListRecord[]): void {\n // Grow the SHORT_ID column to the first length where every prefix is\n // unique. Without this an ambiguous prefix would copy-paste from the list\n // and fail `resolveSessionId` with \"Ambiguous session id\".\n const shortLen = computeUniquePrefixLen(records.map((r) => r.sessionId));\n const rows = records.map((r) => {\n const sid = sliceShort(r.sessionId, shortLen);\n const status = `${r.session.session.status}${suspectLabel(r.suspectReason)}`;\n const source = r.session.session.source.kind;\n const startedAt = r.session.session.started_at;\n const fileCount = r.session.session.related_files.length;\n const filesSuffix = fileCount > 0 ? ` (${fileCount} files)` : \"\";\n const label = (r.session.session.label ?? \"\") + filesSuffix;\n return { sid, status, source, startedAt, label };\n });\n\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n source: maxLen(\n rows.map((r) => r.source),\n \"SOURCE\".length,\n ),\n startedAt: maxLen(\n rows.map((r) => r.startedAt),\n \"STARTED_AT\".length,\n ),\n };\n\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"SOURCE\", widths.source)} ${pad(\"STARTED_AT\", widths.startedAt)} LABEL`,\n );\n for (const row of rows) {\n console.log(\n `${pad(row.sid, widths.sid)} ${pad(row.status, widths.status)} ${pad(row.source, widths.source)} ${pad(row.startedAt, widths.startedAt)} ${row.label}`,\n );\n }\n}\n\nfunction printSessionShowText(\n session: Session,\n events: Event[],\n options: SessionShowOptions,\n repositoryRoot: string,\n now: Date,\n): void {\n const s = session.session;\n console.log(`Session: ${s.id} (status: ${s.status})`);\n console.log(`Source: ${s.source.kind} (v${s.source.version})`);\n console.log(`Workspace: ${s.workspace_id}`);\n console.log(`Started at: ${s.started_at}`);\n if (s.ended_at !== undefined) {\n console.log(`Ended at: ${s.ended_at}`);\n }\n console.log(`Working dir: ${formatWorkingDir(s.working_directory, repositoryRoot, options)}`);\n const invocationArgs = s.invocation.args.length > 0 ? ` ${s.invocation.args.join(\" \")}` : \"\";\n console.log(`Invocation: ${s.invocation.command}${invocationArgs}`);\n if (s.invocation.exit_code !== null) {\n console.log(`Exit code: ${s.invocation.exit_code}`);\n }\n if (s.label !== undefined) {\n console.log(`Label: ${s.label}`);\n }\n console.log(`Related files: ${formatRelatedFiles(s.related_files)}`);\n\n console.log(\"\");\n console.log(`Events: ${events.length} total`);\n const counts = countByType(events);\n for (const [type, n] of counts) {\n console.log(` ${pad(`${type}:`, 24)} ${n}`);\n }\n\n console.log(\"\");\n console.log(`Work: ${formatSessionWork(session, events, now)}`);\n\n if (events.length === 0) return;\n\n const last = options.last ?? 5;\n const showAll = options.events === true && options.last === undefined;\n const slice = showAll ? events : events.slice(-last);\n const heading = showAll ? \"All events:\" : `Last ${slice.length} events:`;\n console.log(\"\");\n console.log(heading);\n for (const ev of slice) {\n console.log(` ${formatEventLine(ev)}`);\n }\n}\n\n/**\n * One-line work summary for `session show`: output volume + action counts +\n * time proxies, reusing the same per-session computation as `basou stats`.\n * `command n/a (import)` flags sources whose shell time is unrecorded.\n */\nfunction formatSessionWork(session: Session, events: Event[], now: Date): string {\n const w = sessionWorkStatsFromEvents(session.session.id, session.session, events, now);\n const parts: string[] = [];\n if (w.tokens.output > 0) parts.push(`${w.tokens.output.toLocaleString(\"en-US\")} output tokens`);\n parts.push(`${w.commandCount} cmd / ${w.fileChangedCount} files / ${w.decisionCount} dec`);\n const activeBasis = w.activeTimeBasis === \"engaged-turns\" ? \"turns\" : \"events\";\n parts.push(`active ${formatDurationMs(w.activeTimeMs)} (${activeBasis})`);\n if (w.availability.machineActive) {\n parts.push(`machine ${formatDurationMs(w.machineActiveTimeMs)}`);\n }\n parts.push(`span ${formatDurationMs(w.sessionSpanMs)}${w.open ? \" (open)\" : \"\"}`);\n parts.push(\n w.availability.commandTime\n ? `command ${formatDurationMs(w.commandTimeMs)}`\n : \"command n/a (import)\",\n );\n return parts.join(\", \");\n}\n\nfunction formatWorkingDir(\n workingDir: string,\n repositoryRoot: string,\n options: SessionShowOptions,\n): string {\n if (options.fullPath === true) return workingDir;\n\n // v0.3 sanitized sessions write `working_directory` as a relative form\n // (`~/projects/foo`, `src/sub`, `.`, etc.) rather than the absolute\n // path the older write paths used. path.relative against a relative\n // input would silently resolve it against process.cwd and produce\n // nonsense like `<cwd>/~/projects/foo`, so the relative form must be\n // surfaced verbatim. The one literal we collapse is `.`, which means\n // \"the session ran at the repo root\" — same semantic as an absolute\n // workingDir equal to repositoryRoot.\n if (!isAbsolute(workingDir)) {\n if (workingDir === \".\") return \"<repository_root>\";\n return workingDir;\n }\n\n if (workingDir === repositoryRoot) return \"<repository_root>\";\n const rel = relative(repositoryRoot, workingDir);\n if (rel.length === 0 || rel === \".\") return \"<repository_root>\";\n // Outside-repo working directories surface as a `../...` relative path\n // rather than the absolute path so the default-display contract holds\n // even for sessions recorded from a sibling checkout. `--full-path` is\n // the explicit opt-in for the absolute form.\n if (rel.startsWith(\"..\")) return rel;\n return `./${rel}`;\n}\n\nfunction formatRelatedFiles(files: readonly string[]): string {\n if (files.length === 0) return \"0 paths\";\n const head = files.slice(0, 3).join(\", \");\n const remaining = files.length - 3;\n if (remaining <= 0) return `${files.length} paths (${head})`;\n return `${files.length} paths (${head}, ... +${remaining} more)`;\n}\n\nfunction countByType(events: readonly Event[]): Array<[string, number]> {\n const map = new Map<string, number>();\n for (const ev of events) {\n map.set(ev.type, (map.get(ev.type) ?? 0) + 1);\n }\n return [...map.entries()];\n}\n\nfunction formatEventLine(ev: Event): string {\n return `${ev.occurred_at} [${ev.source}] ${ev.type} ${eventVariantSummary(ev)}`;\n}\n\nfunction eventVariantSummary(ev: Event): string {\n switch (ev.type) {\n case \"command_executed\": {\n const argsPart = ev.args.length > 0 ? ` ${ev.args.join(\" \")}` : \"\";\n const exitPart = ev.exit_code === null ? \"exit=signal\" : `exit=${ev.exit_code}`;\n return `${ev.command}${argsPart} (${exitPart}, ${ev.duration_ms}ms)`;\n }\n case \"git_snapshot\":\n return `branch=${ev.branch} dirty=${ev.dirty}`;\n case \"file_changed\":\n return `${ev.change_type} ${ev.path}`;\n case \"session_status_changed\":\n return `${ev.from} -> ${ev.to}`;\n case \"session_started\":\n return \"(start)\";\n case \"session_ended\":\n return ev.exit_code !== undefined ? `exit_code=${ev.exit_code}` : \"(end)\";\n case \"approval_requested\":\n return `${ev.action.kind} risk=${ev.risk_level}`;\n case \"approval_approved\":\n return ev.resolver !== undefined ? `by ${ev.resolver}` : \"(approved)\";\n case \"approval_rejected\":\n return ev.resolver !== undefined ? `by ${ev.resolver}: ${ev.reason}` : ev.reason;\n case \"approval_expired\":\n return `approval=${ev.approval_id}`;\n case \"decision_recorded\":\n return ev.title;\n case \"task_created\":\n return ev.title;\n case \"task_status_changed\":\n return `${ev.from} -> ${ev.to}`;\n case \"task_reconciled\": {\n const createdPart =\n ev.removed_created_in_session !== null ? \"1 created_in_session\" : \"0 created_in_session\";\n return `task ${shortTaskId(ev.task_id)}: cleared ${ev.removed_linked_sessions.length} linked + ${createdPart}`;\n }\n case \"task_linkage_refreshed\": {\n const added = ev.added_linked_sessions.length;\n const removed = ev.removed_linked_sessions.length;\n const final = ev.final_count !== undefined ? ` final=${ev.final_count}` : \"\";\n return `task ${shortTaskId(ev.task_id)}: +${added} / -${removed} linked${final}`;\n }\n case \"task_deleted\":\n return `task ${shortTaskId(ev.task_id)}: ${ev.title} (deleted)`;\n case \"task_archived\":\n return `task ${shortTaskId(ev.task_id)}: ${ev.title} (archived)`;\n case \"note_added\":\n return ev.body.length > 80 ? `${ev.body.slice(0, 77)}...` : ev.body;\n case \"adapter_output\":\n return `${ev.stream} \"${ev.summary}\" raw_ref=${ev.raw_ref}`;\n }\n}\n\nfunction shortId(id: string): string {\n return sliceShort(id, SHORT_ID_BASE_LEN);\n}\n\nfunction shortTaskId(id: string): string {\n if (id.startsWith(TASK_PREFIX)) {\n return id.slice(TASK_PREFIX.length, TASK_PREFIX.length + SHORT_ID_BASE_LEN);\n }\n return id.slice(0, SHORT_ID_BASE_LEN);\n}\n\nfunction sliceShort(id: string, len: number): string {\n if (id.startsWith(SES_PREFIX)) {\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + len);\n }\n return id.slice(0, len);\n}\n\n/**\n * Find the smallest length where every short_id derived from `sessionIds`\n * is unique. Starts at {@link SHORT_ID_BASE_LEN} and grows by 2 chars at a\n * time (mirroring git's automatic abbreviation behaviour). Caps at the full\n * ULID body length so a pathological collision still terminates.\n */\nfunction computeUniquePrefixLen(sessionIds: readonly string[]): number {\n if (sessionIds.length <= 1) return SHORT_ID_BASE_LEN;\n for (let len = SHORT_ID_BASE_LEN; len <= SHORT_ID_MAX_LEN; len += 2) {\n const seen = new Set<string>();\n let collided = false;\n for (const sid of sessionIds) {\n const key = sliceShort(sid, len);\n if (seen.has(key)) {\n collided = true;\n break;\n }\n seen.add(key);\n }\n if (!collided) return len;\n }\n return SHORT_ID_MAX_LEN;\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n\nasync function resolveRepositoryRootForSession(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"import\" | \"note\" | \"rechain\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou session ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\nfunction parsePositiveInt(raw: string): number {\n const n = Number.parseInt(raw, 10);\n if (!Number.isInteger(n) || n < 1 || raw.trim() !== String(n)) {\n throw new Error(`Invalid number: ${raw}`);\n }\n return n;\n}\n\nfunction parseSessionStatus(raw: string): SessionStatus {\n const result = SessionStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid session status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction printNoSessions(options: SessionListOptions): void {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No sessions found.\");\n }\n}\n\n// ----------------------------------------------------------------------------\n// session import\n// ----------------------------------------------------------------------------\n\nexport type SessionImportOptions = {\n format: \"json\";\n from: string;\n label?: string;\n task?: string;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/**\n * Programmatic entry for `basou session import`. Mirrors the wrapper /\n * pure-runner split used by list / show so tests can target either layer.\n */\nexport async function runSessionImport(\n options: SessionImportOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionImport(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionImport(\n options: SessionImportOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"import\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const manifest = await readManifest(paths);\n\n const rawBody = await readInputFile(options.from);\n const json = parseJsonStrict(rawBody);\n\n const parsed = SessionImportPayloadSchema.safeParse(json);\n if (!parsed.success) {\n throw new Error(\"Invalid import payload\", { cause: parsed.error });\n }\n\n if (parsed.data.schema_version !== \"0.1.0\") {\n throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);\n }\n\n const importOptions: ImportSessionOptions = { dryRun: options.dryRun === true };\n if (options.label !== undefined) importOptions.labelOverride = options.label;\n if (options.task !== undefined) {\n importOptions.taskIdOverride = await resolveTaskId(paths, options.task);\n }\n\n const result = await importSessionFromJson(paths, manifest, parsed.data, importOptions);\n\n // Path sanitize visibility: the importer rewrites absolute / homedir\n // prefixes inside related_files[] and working_directory so the operator-\n // private layout does not leak into local state. Surface a single-line\n // warning when anything was actually rewritten — silence on zero so the\n // happy path stays quiet. The warning fires for dry-run too so the\n // operator can preview the rewrite before committing.\n const sanitizeReport = result.pathSanitizeReport;\n if (sanitizeReport.relatedFiles > 0 || sanitizeReport.workingDirectoryRewritten) {\n const wdCount = sanitizeReport.workingDirectoryRewritten ? 1 : 0;\n console.error(\n `Imported session: ${sanitizeReport.relatedFiles + wdCount} path(s) sanitized (related_files: ${sanitizeReport.relatedFiles}, working_directory: ${wdCount})`,\n );\n }\n\n printSessionImportResult(options, result);\n}\n\nasync function readInputFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Import source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Import source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read import source\", { cause: error });\n }\n}\n\nfunction parseJsonStrict(body: string): unknown {\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new Error(\"Failed to parse import JSON\", { cause: error });\n }\n}\n\nfunction parseImportFormat(raw: string): \"json\" {\n if (raw !== \"json\") {\n throw new InvalidArgumentError(`Unsupported format: ${raw}. Valid values: json`);\n }\n return \"json\";\n}\n\nfunction parseLabelOverride(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Label must not be empty\");\n }\n return raw;\n}\n\nfunction parseTaskIdOverride(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Task id is empty\");\n }\n return raw;\n}\n\nfunction printSessionImportResult(\n options: SessionImportOptions,\n result: ImportSessionResult,\n): void {\n const isDry = options.dryRun === true;\n const sid = shortId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n session_id: result.sessionId,\n event_count: result.eventCount,\n dry_run: isDry,\n source: { kind: result.finalSourceKind, version: \"0.1.0\" },\n status: result.finalStatus,\n }),\n );\n return;\n }\n\n if (isDry) {\n console.log(\n `Dry run: would import ${result.eventCount} events into ${sid} (illustrative ID; not reserved, no files written)`,\n );\n return;\n }\n\n console.log(\n `Imported session ${sid} (${result.eventCount} events) from ${basename(options.from)}`,\n );\n}\n\n// ----------------------------------------------------------------------------\n// session note\n// ----------------------------------------------------------------------------\n\nconst NOTE_BODY_PREVIEW_LIMIT = 80;\nconst NOTE_BODY_PREVIEW_HEAD = 77;\n\nexport type SessionNoteOptions = {\n body?: string;\n fromFile?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\n/**\n * Programmatic entry for `basou session note <session_id>`. Appends a single\n * `note_added` event to an existing attachable session. `session.yaml` is\n * deliberately NOT modified.\n */\nexport async function runSessionNote(\n sessionIdInput: string,\n options: SessionNoteOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionNote(sessionIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionNote(\n sessionIdInput: string,\n options: SessionNoteOptions,\n ctx: SessionContext,\n): Promise<void> {\n const hasBody = options.body !== undefined;\n const hasFromFile = options.fromFile !== undefined;\n if (!hasBody && !hasFromFile) {\n throw new Error(\"Provide --body or --from-file\");\n }\n if (hasBody && hasFromFile) {\n throw new Error(\"--body and --from-file are mutually exclusive\");\n }\n // The stdin pipe path is not supported in v0.1. Surface a dedicated\n // pathless error before any disk I/O so the failure mode is obvious.\n if (hasFromFile && options.fromFile === \"-\") {\n throw new Error(\"--from-file - (stdin) is not supported in v0.1\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"note\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionId = await resolveSessionId(paths, sessionIdInput);\n\n const body = hasBody ? (options.body as string) : await readNoteFile(options.fromFile as string);\n if (body.length === 0) {\n throw new Error(\"Note body is empty\");\n }\n\n const occurredAt = new Date().toISOString();\n const sesId = sessionId as `ses_${string}`;\n\n // Per-session lock guards the events.jsonl append + status read window\n // against a concurrent writer (decision record / task attach / another\n // session note on the same id). The lock is the caller's responsibility:\n // appendEventToExistingSession holds no lock so we can compose larger\n // critical sections (e.g. attach-flavoured task commands) under the same\n // lock without re-entrant deadlock.\n const sessionLock = await acquireLock(paths, \"session\", sesId);\n let result: Awaited<ReturnType<typeof appendEventToExistingSession>>;\n try {\n result = await appendEventToExistingSession({\n paths,\n sessionId: sesId,\n eventBuilder: (eventId) =>\n ({\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: sesId,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"note_added\",\n body,\n }) as Event,\n });\n } finally {\n await sessionLock.release();\n }\n\n printSessionNoteResult(options, sessionId, result.eventId, result.sessionStatus, body);\n}\n\nasync function readNoteFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Note source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Note source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read note source\", { cause: error });\n }\n}\n\nfunction parseNoteBodyOption(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"--body must not be empty\");\n }\n return raw;\n}\n\nfunction printSessionNoteResult(\n options: SessionNoteOptions,\n sessionId: string,\n eventId: string,\n sessionStatus: SessionStatus,\n body: string,\n): void {\n const sid = shortId(sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n event_id: eventId,\n session_id: sessionId,\n session_status: sessionStatus,\n body_length: body.length,\n }),\n );\n return;\n }\n const preview =\n body.length > NOTE_BODY_PREVIEW_LIMIT ? `${body.slice(0, NOTE_BODY_PREVIEW_HEAD)}...` : body;\n console.log(`Added note to session ${sid} (${sessionStatus}): ${preview}`);\n}\n\n/**\n * Programmatic entry for `basou session rechain` that owns process exit\n * state. Tests should prefer {@link doRunSessionRechain} for the success\n * path.\n */\nexport async function runSessionRechain(\n options: SessionRechainOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionRechain(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Runner for `session rechain`. A WRITE command, so an explicit selector is\n * required (`--session <id>` or `--all`). Per-session outcomes are collected\n * into rows; an I/O failure on one session becomes an `error` row and the\n * sweep CONTINUES, so one unreadable directory cannot hide the rest of the\n * report. Exit is non-zero when any session was found `tampered` or errored\n * operationally; plain skips and successes exit 0.\n */\nexport async function doRunSessionRechain(\n options: SessionRechainOptions,\n ctx: SessionContext,\n): Promise<void> {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n if (options.session === undefined && options.all !== true) {\n throw new Error(\"Specify --session <id> or --all\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"rechain\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionIds =\n options.session !== undefined\n ? [await resolveSessionId(paths, options.session)]\n : await enumerateSessionDirs(paths);\n\n const dryRun = options.dryRun === true;\n const rows: RechainRow[] = [];\n for (const sessionId of sessionIds) {\n let outcome: RechainResult;\n try {\n outcome = await rechainSessionInPlace(paths, sessionId, { dryRun });\n } catch (error: unknown) {\n rows.push({\n session_id: sessionId,\n status: \"error\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n continue;\n }\n if (outcome.status === \"rechained\") {\n rows.push({ session_id: sessionId, status: \"rechained\", event_count: outcome.eventCount });\n } else {\n rows.push({ session_id: sessionId, status: \"skipped\", reason: outcome.reason });\n }\n }\n\n const tamperedCount = rows.filter((r) => r.reason === \"tampered\").length;\n const errorCount = rows.filter((r) => r.status === \"error\").length;\n\n if (options.json === true) {\n console.log(JSON.stringify(rows, null, 2));\n } else {\n for (const row of rows) {\n console.log(`${row.session_id} ${renderRechainRow(row, dryRun)}`);\n }\n const rechained = rows.filter((r) => r.status === \"rechained\").length;\n const skipped = rows.filter((r) => r.status === \"skipped\").length;\n console.log(\n `Sessions: ${rows.length} total — ${rechained} ${dryRun ? \"would be rechained\" : \"rechained\"}, ` +\n `${skipped} skipped, ${errorCount} errors`,\n );\n }\n\n // A tampered session or an operational failure must be visible in the\n // exit status; ordinary skips (already chained / live / empty) are not\n // failures.\n if (tamperedCount > 0 || errorCount > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction renderRechainRow(row: RechainRow, dryRun: boolean): string {\n switch (row.status) {\n case \"rechained\":\n return `${dryRun ? \"would rechain\" : \"rechained\"} (${row.event_count} events)`;\n case \"skipped\":\n return row.reason === \"tampered\"\n ? \"skipped (TAMPERED — inspect with 'basou verify')\"\n : `skipped (${row.reason})`;\n case \"error\":\n return `error (${row.message})`;\n }\n}\n","/**\n * Re-export the shared duration formatter from `@basou/core`. It lives in core\n * so the report renderer (also in core) and the CLI surfaces (`basou stats`,\n * `basou session show`) all format durations identically. Kept as a thin\n * re-export so existing CLI imports of `../lib/format-duration.js` stay valid.\n */\nexport { formatDurationMs } from \"@basou/core\";\n","import {\n assertBasouRootSafe,\n basouPaths,\n computeWorkStats,\n findErrorCode,\n resolveRepositoryRoot,\n type SourceWorkStats,\n type WorkStatsResult,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { formatDurationMs } from \"../lib/format-duration.js\";\n\nexport type StatsOptions = {\n json?: boolean;\n bySource?: boolean;\n byDay?: boolean;\n verbose?: boolean;\n};\n\nexport type StatsContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Register `basou stats`: an honest \"how much did the AI work\" report. It\n * leads with output VOLUME (tokens + action counts), which is the most direct\n * signal, and reports TIME measures as labeled proxies.\n */\nexport function registerStatsCommand(program: Command): void {\n program\n .command(\"stats\")\n .description(\"Report how much the AI worked (output volume + time proxies) across sessions\")\n .option(\"--by-source\", \"Break the totals down by session source kind\")\n .option(\"--by-day\", \"Break billable time and volume down by calendar day\")\n .option(\"--json\", \"Output the full stats as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: StatsOptions) => {\n await runStats(options);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunStats}. */\nexport async function runStats(options: StatsOptions, ctx: StatsContext = {}): Promise<void> {\n try {\n await doRunStats(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** Pure runner: resolve the workspace, aggregate, and print (text or JSON). */\nexport async function doRunStats(options: StatsOptions, ctx: StatsContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForStats(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const now = ctx.nowProvider?.() ?? new Date();\n const result = await computeWorkStats({\n paths,\n now,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n printStatsText(result, options.bySource === true, options.byDay === true);\n}\n\nfunction printStatsText(result: WorkStatsResult, bySource: boolean, byDay: boolean): void {\n const t = result.totals;\n const statusPart =\n result.byStatus.length > 0\n ? ` (${result.byStatus.map((s) => `${s.status} ${s.count}`).join(\", \")})`\n : \"\";\n console.log(`Sessions: ${t.sessionCount}${statusPart}`);\n\n console.log(\"\");\n console.log(\"Volume (what the AI produced):\");\n const tokenSessions = result.sessions.filter((s) => s.availability.tokens).length;\n const tokenCaveat =\n t.tokensAvailable && tokenSessions < t.sessionCount\n ? ` (token data on ${tokenSessions} of ${t.sessionCount} sessions)`\n : t.tokensAvailable\n ? \"\"\n : \" (no token data captured; re-import to backfill)\";\n console.log(` Output tokens: ${formatInt(t.tokens.output)}${tokenCaveat}`);\n if (t.tokens.reasoning > 0) {\n console.log(` Reasoning tokens: ${formatInt(t.tokens.reasoning)} (Codex)`);\n }\n console.log(\n ` Actions: ${t.commandCount} commands, ${t.fileChangedCount} files, ${t.decisionCount} decisions`,\n );\n\n console.log(\"\");\n console.log(\"Time (proxies for human harness labor; active = billing primary):\");\n const turnSessions = result.sessions.filter((s) => s.activeTimeBasis === \"engaged-turns\").length;\n const basisCaveat =\n turnSessions === t.sessionCount\n ? \"engaged turns\"\n : turnSessions === 0\n ? \"event stream; re-import to capture conversation\"\n : `engaged turns on ${turnSessions} of ${t.sessionCount} sessions, event stream on the rest`;\n console.log(\n ` Billable active: ${formatDurationMs(t.billableActiveTimeMs)} (union; ${basisCaveat}; idle gaps > 5m excluded; tz ${result.timeZone})`,\n );\n if (t.activeTimeMs !== t.billableActiveTimeMs) {\n console.log(\n ` Summed: ${formatDurationMs(t.activeTimeMs)} (per-session sum; concurrent sessions double-counted)`,\n );\n }\n if (t.machineActiveAvailable) {\n const machineSessions = result.sessions.filter((s) => s.availability.machineActive).length;\n console.log(\n ` Model working: ${formatDurationMs(t.machineActiveTimeMs)} (model compute, subset of active; Codex turn duration on ${machineSessions} of ${t.sessionCount} sessions; summed, not wall-clock-deduped)`,\n );\n }\n const openPart = t.openSessionCount > 0 ? `; ${t.openSessionCount} open counted to now` : \"\";\n console.log(\n ` Span: ${formatDurationMs(t.sessionSpanMs)} (total elapsed${openPart})`,\n );\n const cmdCaveat = t.commandTimeReliable\n ? \"\"\n : \"; some sessions (e.g. claude-code-import) report 0 shell time\";\n console.log(\n ` Command: ${formatDurationMs(t.commandTimeMs)} (real shell execution${cmdCaveat})`,\n );\n\n if (bySource && result.bySource.length > 0) {\n console.log(\"\");\n console.log(\"By source:\");\n for (const s of result.bySource) {\n console.log(` ${s.sourceKind}: ${describeSource(s)}`);\n }\n }\n\n if (byDay && result.byDay.length > 0) {\n console.log(\"\");\n console.log(\"By day (billable time x volume):\");\n for (const d of result.byDay) {\n const machine =\n d.machineActiveTimeMs > 0 ? ` (model ${formatDurationMs(d.machineActiveTimeMs)})` : \"\";\n console.log(\n ` ${d.date}: ${formatDurationMs(d.billableActiveTimeMs)} active${machine}, ${formatInt(d.tokens.output)} out tok, ${d.commandCount} cmd / ${d.fileChangedCount} files / ${d.decisionCount} dec`,\n );\n }\n }\n}\n\nfunction describeSource(s: SourceWorkStats): string {\n const cmd = s.commandTimeReliable ? formatDurationMs(s.commandTimeMs) : \"n/a\";\n const tokens = s.tokensAvailable ? `${formatInt(s.tokens.output)} out tok` : \"no tokens\";\n const machine = s.machineActiveAvailable\n ? `, model ${formatDurationMs(s.machineActiveTimeMs)}`\n : \"\";\n return `${s.sessionCount} sessions, ${tokens}, active ${formatDurationMs(s.activeTimeMs)}${machine}, command ${cmd}`;\n}\n\n/** \"1,234,567\" — thousands-separated, fixed en-US so output is deterministic. */\nfunction formatInt(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\nasync function resolveRepositoryRootForStats(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou stats'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n buildStatusSnapshot,\n findErrorCode,\n type Manifest,\n readManifest,\n resolveRepositoryRoot,\n type StatusSnapshot,\n writeStatus,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type StatusOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type StatusContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/**\n * Register `basou status` on a commander program. The command outputs a\n * human-readable summary by default, or a JSON document when `--json` is\n * given. In both modes `.basou/status.json` is rewritten as a side effect.\n */\nexport function registerStatusCommand(program: Command): void {\n program\n .command(\"status\")\n .description(\"Show the current Basou workspace status\")\n .option(\"--json\", \"Output the snapshot as JSON to stdout\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: StatusOptions) => {\n await runStatus(options);\n });\n}\n\n/**\n * Programmatic entry that mutates process state (`exitCode`, stderr).\n * Exported for tests, but tests should prefer {@link doRunStatus} when they\n * only need to assert on success behaviour or thrown errors.\n */\nexport async function runStatus(options: StatusOptions, ctx: StatusContext = {}): Promise<void> {\n try {\n await doRunStatus(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolves inputs, performs the status snapshot, writes\n * `status.json`, and prints output. On any failure throws an Error whose\n * `message` is pathless; native fs / parse errors are attached as `cause`.\n * Exported for tests so they can assert on thrown errors without touching\n * `process.exitCode`.\n */\nexport async function doRunStatus(options: StatusOptions, ctx: StatusContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForStatus(cwd);\n const paths = basouPaths(repositoryRoot);\n\n // Pre-condition: refuse to operate on a swapped/non-directory .basou root\n // before we ever touch a file. Treat ENOENT (root absent) the same way as\n // a missing manifest below — both mean \"workspace not initialized\".\n try {\n await assertBasouRootSafe(paths.root);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n\n let manifest: Manifest;\n try {\n manifest = await readManifest(paths);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n // ZodError's `message` echoes invalid input values verbatim, which can\n // include path-like strings if a user-edited manifest contains them.\n // Wrap in a fixed pathless message and surface only the cause's\n // constructor name in verbose mode via the shared renderCliError helper.\n throw new Error(\"Failed to read workspace manifest\", { cause: error });\n }\n\n const snapshot = await buildStatusSnapshot({ manifest, paths });\n await writeStatus(paths, snapshot);\n\n if (options.json === true) {\n console.log(JSON.stringify(snapshot, null, 2));\n } else {\n renderTextStatus(snapshot);\n }\n}\n\nfunction renderTextStatus(s: StatusSnapshot): void {\n console.log(`Workspace: ${s.workspace.name} (${s.workspace.id})`);\n // The label changed from \"Basou version\" to \"Spec version\" in v0.3.1\n // because the field tracks the workspace data-format spec\n // (`basou_version` literal-locked to \"0.1.0\") and was repeatedly\n // mistaken for the release version returned by `basou --version`. The\n // wire payload field name (= `workspace.basou_version`) stays the same\n // so JSON consumers are unaffected; only the human-readable label\n // moves.\n console.log(`Spec version: ${s.workspace.basou_version}`);\n console.log(`Generated at: ${s.generated_at}`);\n const dp = s.directories_present;\n const total = Object.keys(dp).length;\n const present = Object.values(dp).filter((v) => v === true).length;\n console.log(`Subdirectories present: ${present}/${total}`);\n}\n\n/**\n * Wrap the core git capability so the CLI surfaces the command-specific\n * \"Run 'git init' first, then re-run 'basou status'.\" suffix while the\n * capability layer remains command-agnostic.\n */\nasync function resolveRepositoryRootForStatus(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou status'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n archiveTask,\n assertBasouRootSafe,\n basouPaths,\n createTaskWithEvent,\n deleteTask,\n type Event,\n editTask,\n enumerateArchivedTaskIds,\n findErrorCode,\n loadSessionEntries,\n loadTaskEntries,\n type PrefixedId,\n prefixedUlid,\n type ReconcileFailure,\n type ReconcileResult,\n type RefreshLinkageResult,\n readManifest,\n readTaskFile,\n readTaskFileWithArchiveFallback,\n reconcileAllTasks,\n reconcileTask,\n refreshTaskLinkedSessions,\n replayEvents,\n resolveRepositoryRoot,\n resolveSessionId,\n resolveTaskId,\n type SessionEntry,\n type SessionStatus,\n type TaskDocument,\n type TaskReconciledEvent,\n type TaskStatus,\n TaskStatusSchema,\n TaskWriteAfterEventError,\n updateTaskStatusWithEvent,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n type ErrorClassifier,\n failedToFinalizeClassifier,\n isVerbose,\n printReplayWarning,\n printTaskSkip,\n renderCliError,\n shortSessionId,\n shortTaskId,\n} from \"../lib/error-render.js\";\n\nconst STATUS_VALUES = TaskStatusSchema.options;\n\n// ============================================================================\n// Public registration\n// ============================================================================\n\nexport type TaskNewOptions = {\n title: string;\n label?: string;\n status?: TaskStatus;\n /**\n * ISO-8601 timestamp written into `task.md.updated_at` when status is a\n * terminal value (done / cancelled). Lets the operator backdate a\n * retroactively-recorded completed task so `task.md` reflects the\n * actual completion moment while `events.jsonl` keeps recording time.\n * Rejected (exit 1) when supplied with a non-terminal status.\n */\n completedAt?: string;\n session?: string;\n description?: string;\n fromFile?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskListOptions = {\n status?: TaskStatus;\n includeArchived?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskShowOptions = {\n json?: boolean;\n events?: boolean;\n last?: number;\n verbose?: boolean;\n};\n\nexport type TaskStatusOptions = {\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskReconcileOptions = {\n task?: string;\n write?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskRefreshLinkageOptions = {\n write?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskEditOptions = {\n title?: string;\n status?: TaskStatus;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskDeleteOptions = {\n yes?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskArchiveOptions = {\n yes?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\nexport function registerTaskCommand(program: Command): void {\n const task = program\n .command(\"task\")\n .description(\"Manage Basou tasks (purpose units that span sessions)\");\n\n task\n .command(\"new\")\n .description(\"Create a new task and fire a task_created event\")\n .requiredOption(\"--title <text>\", \"Task title\", parseTitle)\n .option(\"--label <text>\", \"Optional label for the task\", parseLabel)\n .option(\n \"--status <status>\",\n `Initial status (one of: ${STATUS_VALUES.join(\", \")}; default planned). For done/cancelled the orchestrator also emits a task_status_changed event so the audit trail records the implicit transition.`,\n parseInitialTaskStatus,\n )\n .option(\n \"--completed-at <iso>\",\n \"ISO-8601 timestamp to record as the task's updated_at when --status is done or cancelled (rejected otherwise)\",\n parseIsoTimestampOption,\n )\n .option(\"--session <session_id>\", \"Attach to existing session; otherwise ad-hoc\")\n .option(\"--description <text>\", \"Task description body (inline)\", parseDescriptionOption)\n .option(\"--from-file <path>\", \"Read description body from a file\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: TaskNewOptions) => {\n await runTaskNew(options);\n });\n\n task\n .command(\"list\")\n .description(\"List tasks in the current workspace (newest first)\")\n .option(\n \"--status <status>\",\n `Filter by task status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseTaskStatusFilter,\n )\n .option(\"--include-archived\", \"Also list tasks under .basou/tasks/archive/ (hidden by default)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: TaskListOptions) => {\n await runTaskList(options);\n });\n\n task\n .command(\"show <task_id>\")\n .description(\"Show a task with its metadata, linked sessions, and events\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--events\", \"Show all related events instead of trailing few\")\n .option(\"--last <n>\", \"Number of trailing events to display (default: 5)\", parsePositiveInt)\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: TaskShowOptions) => {\n await runTaskShow(id, options);\n });\n\n task\n .command(\"status <task_id> <new_status>\")\n .description(\"Change task status and fire a task_status_changed event\")\n .option(\"--session <session_id>\", \"Attach to existing session; otherwise ad-hoc\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, newStatusInput: string, options: TaskStatusOptions) => {\n await runTaskStatus(taskIdInput, newStatusInput, options);\n });\n\n task\n .command(\"reconcile\")\n .description(\n \"Dry-run audit of task session references; use --write to repair broken refs. Forward sync (events -> task.md linked_sessions) is out of scope.\",\n )\n .option(\"--task <task_id>\", \"Limit to a single task (otherwise scan all)\")\n .option(\"--write\", \"Apply repairs (default: dry-run)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes and broken session_id values\")\n .action(async (options: TaskReconcileOptions) => {\n await runTaskReconcile(options);\n });\n\n task\n .command(\"refresh-linkage <task_id>\")\n .description(\n \"Re-derive task.md linked_sessions[] from session.yaml.task_id matches across the workspace (forward sync events -> task.md). Dry-run default; use --write to apply.\",\n )\n .option(\"--write\", \"Apply the refresh (default: dry-run)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskRefreshLinkageOptions) => {\n await runTaskRefreshLinkage(taskIdInput, options);\n });\n\n task\n .command(\"edit <task_id>\")\n .description(\n \"Update --title and/or --status on an existing task. Status changes fire a task_status_changed event; title changes update task.md only (no event).\",\n )\n .option(\"--title <text>\", \"New title (must be non-empty)\", parseTitle)\n .option(\n \"--status <status>\",\n `New status (one of: ${STATUS_VALUES.join(\", \")}); routed through STATUS_TRANSITIONS so only valid edges are accepted`,\n parseInitialTaskStatus,\n )\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskEditOptions) => {\n await runTaskEdit(taskIdInput, options);\n });\n\n task\n .command(\"delete <task_id>\")\n .description(\n \"Hard-delete a task.md file and fire a task_deleted event. Requires confirmation by default; use --yes to skip the prompt.\",\n )\n .option(\"--yes\", \"Skip the confirmation prompt (required when stdin is not a TTY)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskDeleteOptions) => {\n await runTaskDelete(taskIdInput, options);\n });\n\n task\n .command(\"archive <task_id>\")\n .description(\n \"Move task.md into .basou/tasks/archive/ and fire a task_archived event. Requires confirmation by default; use --yes to skip the prompt.\",\n )\n .option(\"--yes\", \"Skip the confirmation prompt (required when stdin is not a TTY)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskArchiveOptions) => {\n await runTaskArchive(taskIdInput, options);\n });\n}\n\n// ============================================================================\n// task new\n// ============================================================================\n\nexport async function runTaskNew(options: TaskNewOptions, ctx: TaskContext = {}): Promise<void> {\n try {\n await doRunTaskNew(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskNew(options: TaskNewOptions, ctx: TaskContext): Promise<void> {\n if (options.description !== undefined && options.fromFile !== undefined) {\n throw new Error(\"--description and --from-file are mutually exclusive\");\n }\n if (options.fromFile === \"-\") {\n throw new Error(\"--from-file - (stdin) is not supported in v0.1\");\n }\n\n const initialStatus = options.status ?? \"planned\";\n // `--completed-at` only makes sense paired with a terminal status. Catching\n // the mismatch up front avoids ambiguity about whether the override would\n // still be honored on a planned/in_progress task (= it wouldn't).\n if (options.completedAt !== undefined && !isTerminalStatusForCli(initialStatus)) {\n throw new Error(\"--completed-at requires --status done or cancelled\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"new\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const description =\n options.description !== undefined\n ? options.description\n : options.fromFile !== undefined\n ? await readDescriptionFile(options.fromFile)\n : \"\";\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const taskId = prefixedUlid(\"task\");\n\n if (options.session !== undefined) {\n const sessionId = (await resolveSessionId(paths, options.session)) as PrefixedId<\"ses\">;\n const result = await createTaskWithEvent({\n mode: \"attach\",\n paths,\n occurredAt,\n sessionId,\n taskId,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n initialStatus,\n description,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n });\n printTaskNewResult(options, {\n mode: \"attached\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n status: initialStatus,\n occurredAt,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n descriptionLength: description.length,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const result = await createTaskWithEvent({\n mode: \"ad-hoc\",\n paths,\n manifest,\n occurredAt,\n taskId,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n initialStatus,\n description,\n workingDirectory: repositoryRoot,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n });\n printTaskNewResult(options, {\n mode: \"ad-hoc\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n status: initialStatus,\n occurredAt,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n descriptionLength: description.length,\n });\n}\n\nfunction isTerminalStatusForCli(status: TaskStatus): boolean {\n return status === \"done\" || status === \"cancelled\";\n}\n\ntype TaskNewPrint = {\n mode: \"ad-hoc\" | \"attached\";\n taskId: string;\n eventId: string;\n sessionId: string;\n sessionStatus: SessionStatus;\n title: string;\n label?: string;\n status: TaskStatus;\n occurredAt: string;\n completedAt?: string;\n descriptionLength: number;\n};\n\nfunction printTaskNewResult(options: TaskNewOptions, result: TaskNewPrint): void {\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n title: result.title,\n label: result.label ?? null,\n status: result.status,\n recorded_at: result.occurredAt,\n completed_at: result.completedAt ?? null,\n description_length: result.descriptionLength,\n }),\n );\n return;\n }\n const shortSes = shortSessionId(result.sessionId);\n const created =\n result.mode === \"ad-hoc\"\n ? `Created ${result.taskId} in ad-hoc session ${shortSes}`\n : `Created ${result.taskId} in session ${shortSes} (${result.sessionStatus})`;\n console.log(created);\n console.log(` Title: ${result.title}`);\n // For terminal initial statuses surface both the recording time (= the\n // ad-hoc session timestamp = now) and the supplied completion time so the\n // operator can tell at a glance that the audit trail (events.jsonl)\n // reflects the former while task.md.updated_at reflects the latter.\n if (result.completedAt !== undefined) {\n console.log(\n ` Status: ${result.status} (recorded at ${result.occurredAt}, completed at ${result.completedAt})`,\n );\n } else {\n console.log(` Status: ${result.status}`);\n }\n console.log(` Label: ${result.label ?? \"(none)\"}`);\n}\n\n// ============================================================================\n// task list\n// ============================================================================\n\nexport async function runTaskList(options: TaskListOptions, ctx: TaskContext = {}): Promise<void> {\n try {\n await doRunTaskList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskList(options: TaskListOptions, ctx: TaskContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const entries = await loadTaskEntries(paths, {\n onSkip: (id, reason) => printTaskSkip(id, reason),\n });\n // Archive entries are read from `<paths.tasks>/archive/` directly (no\n // dedicated loader yet — call sites are rare). Marshalling them through a\n // separate scan keeps the default `task list` path fast (no extra readdir\n // when the operator does not opt in).\n const archivedEntries: { doc: TaskDocument; archived: true }[] = [];\n if (options.includeArchived === true) {\n const archivedIds = await enumerateArchivedTaskIds(paths);\n for (const id of archivedIds) {\n try {\n const { doc } = await readTaskFileWithArchiveFallback(paths, id);\n archivedEntries.push({ doc, archived: true });\n } catch {\n // Skip unreadable archive entries — keep the list output usable\n // when one file is corrupt rather than aborting the run.\n }\n }\n }\n const combined = [...entries, ...archivedEntries.map((a) => a.doc)];\n const archivedIdSet = new Set(archivedEntries.map((a) => a.doc.task.task.id));\n // loadTaskEntries returns asc by created_at; reverse for newest-first display.\n const ordered = [...combined].sort(\n (a, b) => Date.parse(b.task.task.created_at) - Date.parse(a.task.task.created_at),\n );\n const filtered =\n options.status !== undefined\n ? ordered.filter((t) => t.task.task.status === options.status)\n : ordered;\n\n if (filtered.length === 0) {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No tasks found.\");\n }\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((t) => ({\n task_id: t.task.task.id,\n title: t.task.task.title,\n label: t.task.task.label ?? null,\n status: t.task.task.status,\n created_at: t.task.task.created_at,\n updated_at: t.task.task.updated_at,\n linked_session_count: t.task.task.linked_sessions.length,\n archived: archivedIdSet.has(t.task.task.id),\n })),\n null,\n 2,\n ),\n );\n return;\n }\n printTaskListText(filtered, archivedIdSet);\n}\n\nfunction printTaskListText(\n entries: ReadonlyArray<TaskDocument>,\n archivedIds: ReadonlySet<string>,\n): void {\n const rows = entries.map((t) => ({\n sid: shortTaskId(t.task.task.id),\n status: t.task.task.status,\n createdAt: t.task.task.created_at,\n label: t.task.task.label ?? \"(none)\",\n // Mark archived entries with a leading [archived] tag so the operator\n // can distinguish them from live tasks when --include-archived is on.\n title: archivedIds.has(t.task.task.id) ? `[archived] ${t.task.task.title}` : t.task.task.title,\n linkedCount: String(t.task.task.linked_sessions.length),\n }));\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n createdAt: maxLen(\n rows.map((r) => r.createdAt),\n \"CREATED_AT\".length,\n ),\n linkedCount: maxLen(\n rows.map((r) => r.linkedCount),\n \"LINKS\".length,\n ),\n label: maxLen(\n rows.map((r) => r.label),\n \"LABEL\".length,\n ),\n };\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"CREATED_AT\", widths.createdAt)} ${pad(\"LINKS\", widths.linkedCount)} ${pad(\"LABEL\", widths.label)} TITLE`,\n );\n for (const r of rows) {\n console.log(\n `${pad(r.sid, widths.sid)} ${pad(r.status, widths.status)} ${pad(r.createdAt, widths.createdAt)} ${pad(r.linkedCount, widths.linkedCount)} ${pad(r.label, widths.label)} ${r.title}`,\n );\n }\n}\n\n// ============================================================================\n// task show\n// ============================================================================\n\nexport async function runTaskShow(\n idInput: string,\n options: TaskShowOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskShow(\n idInput: string,\n options: TaskShowOptions,\n ctx: TaskContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const taskId = await resolveTaskId(paths, idInput, { includeArchived: true });\n const { doc, archived } = await readTaskFileWithArchiveFallback(paths, taskId);\n\n // Collect events related to this task by replaying every session's\n // events.jsonl and filtering by task_id. Could be optimised via an\n // index.json cache later; v0.1 accepts the linear scan.\n const sessions = await loadSessionEntries(paths, { now: new Date() });\n const events: Event[] = [];\n const linkedSessionIds = new Set<string>(doc.task.task.linked_sessions);\n // Replay warnings (malformed JSON / schema violations / partial trailing\n // lines) and unreadable events.jsonl files must reach the operator so\n // silent gaps in the events history don't go unnoticed.\n for (const s of sessions) {\n const sessionDir = join(paths.sessions, s.sessionId);\n try {\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, s.sessionId),\n })) {\n if (\n (ev.type === \"task_created\" ||\n ev.type === \"task_status_changed\" ||\n ev.type === \"task_reconciled\" ||\n ev.type === \"task_linkage_refreshed\" ||\n ev.type === \"task_deleted\" ||\n ev.type === \"task_archived\") &&\n ev.task_id === taskId\n ) {\n events.push(ev);\n linkedSessionIds.add(s.sessionId);\n }\n }\n } catch (error: unknown) {\n // I/O failure (events.jsonl unreadable). The renderer still works on\n // task.md metadata alone, but the operator must know events from this\n // session are missing from the aggregate.\n const short = shortSessionId(s.sessionId);\n const suffix = error instanceof Error ? `: ${error.message}` : \"\";\n console.error(`Warning: events unavailable for session ${short}${suffix}`);\n }\n }\n events.sort((a, b) => Date.parse(a.occurred_at) - Date.parse(b.occurred_at));\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n task: doc.task.task,\n body: doc.body,\n linked_sessions: [...linkedSessionIds],\n archived,\n events,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n printTaskShowText(doc, [...linkedSessionIds], events, sessions, options, archived);\n}\n\nfunction printTaskShowText(\n doc: TaskDocument,\n linkedSessions: string[],\n events: ReadonlyArray<Event>,\n sessionEntries: ReadonlyArray<SessionEntry>,\n options: TaskShowOptions,\n archived: boolean,\n): void {\n const t = doc.task.task;\n const archivedTag = archived ? \" [archived]\" : \"\";\n console.log(`Task: ${t.id}${archivedTag}`);\n console.log(` Title: ${t.title}`);\n console.log(` Status: ${t.status}`);\n console.log(` Label: ${t.label ?? \"(none)\"}`);\n console.log(` Created at: ${t.created_at}`);\n console.log(` Updated at: ${t.updated_at}`);\n console.log(` Workspace: ${t.workspace_id}`);\n console.log(\"\");\n console.log(`Linked sessions (${linkedSessions.length}):`);\n const sessionStatusMap = new Map<string, string>(\n sessionEntries.map((s) => [s.sessionId, s.session.session.status]),\n );\n for (const sid of linkedSessions) {\n const status = sessionStatusMap.get(sid) ?? \"unknown\";\n console.log(` ${sid} (${status})`);\n }\n console.log(\"\");\n console.log(\"Description:\");\n if (doc.body.length === 0) {\n console.log(\"(no description)\");\n } else {\n console.log(doc.body);\n }\n console.log(\"\");\n console.log(`Events: ${events.length} total`);\n if (events.length === 0) return;\n const showAll = options.events === true && options.last === undefined;\n const last = options.last ?? 5;\n const slice = showAll ? events : events.slice(-last);\n const heading = showAll ? \"All events:\" : `Last ${slice.length} events:`;\n console.log(\"\");\n console.log(heading);\n const verbose = isVerbose(options);\n for (const ev of slice) {\n console.log(` ${formatTaskEvent(ev)}`);\n if (verbose && ev.type === \"task_reconciled\") {\n for (const line of formatTaskReconciledDetails(ev)) {\n console.log(line);\n }\n }\n }\n}\n\nfunction formatTaskEvent(ev: Event): string {\n if (ev.type === \"task_created\") {\n return `${ev.occurred_at} [${ev.source}] task_created ${ev.title}`;\n }\n if (ev.type === \"task_status_changed\") {\n return `${ev.occurred_at} [${ev.source}] task_status_changed ${ev.from} -> ${ev.to}`;\n }\n if (ev.type === \"task_reconciled\") {\n const removedCount =\n (ev.removed_created_in_session !== null ? 1 : 0) + ev.removed_linked_sessions.length;\n return `${ev.occurred_at} [${ev.source}] task_reconciled ${removedCount} broken ref${removedCount === 1 ? \"\" : \"s\"} (use -v for details)`;\n }\n if (ev.type === \"task_linkage_refreshed\") {\n const added = ev.added_linked_sessions.length;\n const removed = ev.removed_linked_sessions.length;\n const finalPart = ev.final_count !== undefined ? `, final=${ev.final_count}` : \"\";\n return `${ev.occurred_at} [${ev.source}] task_linkage_refreshed +${added} / -${removed}${finalPart}`;\n }\n if (ev.type === \"task_deleted\") {\n return `${ev.occurred_at} [${ev.source}] task_deleted ${ev.title}`;\n }\n if (ev.type === \"task_archived\") {\n return `${ev.occurred_at} [${ev.source}] task_archived ${ev.title}`;\n }\n return `${ev.occurred_at} [${ev.source}] ${ev.type}`;\n}\n\nfunction formatTaskReconciledDetails(ev: TaskReconciledEvent): string[] {\n const lines: string[] = [];\n if (ev.removed_created_in_session !== null) {\n lines.push(` removed_created_in_session: ${ev.removed_created_in_session}`);\n }\n if (ev.created_in_session_replacement !== null) {\n lines.push(` created_in_session_replacement: ${ev.created_in_session_replacement}`);\n }\n if (ev.removed_linked_sessions.length > 0) {\n lines.push(\" removed_linked_sessions:\");\n for (const sid of ev.removed_linked_sessions) {\n lines.push(` - ${sid}`);\n }\n }\n return lines;\n}\n\n// ============================================================================\n// task status\n// ============================================================================\n\nexport async function runTaskStatus(\n taskIdInput: string,\n newStatusInput: string,\n options: TaskStatusOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskStatus(taskIdInput, newStatusInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskStatus(\n taskIdInput: string,\n newStatusInput: string,\n options: TaskStatusOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const newStatus = parseTaskStatusPositional(newStatusInput);\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"status\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n\n if (options.session !== undefined) {\n const sessionId = (await resolveSessionId(paths, options.session)) as PrefixedId<\"ses\">;\n const result = await updateTaskStatusWithEvent({\n mode: \"attach\",\n paths,\n occurredAt,\n sessionId,\n taskId,\n newStatus,\n });\n printTaskStatusResult(options, {\n mode: \"attached\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n previousStatus: result.previousStatus,\n newStatus: result.newStatus,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const result = await updateTaskStatusWithEvent({\n mode: \"ad-hoc\",\n paths,\n manifest,\n occurredAt,\n taskId,\n newStatus,\n workingDirectory: repositoryRoot,\n });\n printTaskStatusResult(options, {\n mode: \"ad-hoc\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n previousStatus: result.previousStatus,\n newStatus: result.newStatus,\n });\n}\n\ntype TaskStatusPrint = {\n mode: \"ad-hoc\" | \"attached\";\n taskId: string;\n eventId: string;\n sessionId: string;\n sessionStatus: SessionStatus;\n previousStatus: TaskStatus;\n newStatus: TaskStatus;\n};\n\nfunction printTaskStatusResult(options: TaskStatusOptions, result: TaskStatusPrint): void {\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n previous_status: result.previousStatus,\n new_status: result.newStatus,\n }),\n );\n return;\n }\n const sid = shortSessionId(result.sessionId);\n console.log(\n `Updated ${result.taskId} status: ${result.previousStatus} -> ${result.newStatus} (in session ${sid})`,\n );\n}\n\n// ============================================================================\n// task reconcile\n// ============================================================================\n\nexport async function runTaskReconcile(\n options: TaskReconcileOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskReconcile(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskReconcile(\n options: TaskReconcileOptions,\n ctx: TaskContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"reconcile\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const nowProvider = ctx.nowProvider ?? ((): Date => new Date());\n const write = options.write === true;\n const verbose = isVerbose(options);\n const json = options.json === true;\n\n if (options.task !== undefined) {\n const taskId = (await resolveTaskId(paths, options.task)) as PrefixedId<\"task\">;\n const result = await reconcileTask(paths, manifest, {\n taskId,\n occurredAt: nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n scope: \"single\",\n });\n if (json) {\n printReconcileJson({ dryRun: !write, scanned: 1, results: [result], failed: [] });\n } else {\n await printReconcileSingleText(result, paths, { write, verbose });\n }\n return;\n }\n\n const all = await reconcileAllTasks(paths, manifest, {\n occurredAt: () => nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n });\n if (json) {\n printReconcileJson({\n dryRun: !write,\n scanned: all.scanned,\n results: all.results,\n failed: all.failed,\n });\n } else {\n printReconcileAllText(all.results, all.failed, all.scanned, { write, verbose });\n }\n if (all.failed.length > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction printReconcileJson(input: {\n dryRun: boolean;\n scanned: number;\n results: ReadonlyArray<ReconcileResult>;\n failed: ReadonlyArray<ReconcileFailure>;\n}): void {\n console.log(\n JSON.stringify(\n {\n dry_run: input.dryRun,\n scanned: input.scanned,\n reconciled: input.results.map((r) => ({\n task_id: r.taskId,\n removed_created_in_session: r.brokenCreatedInSession,\n created_in_session_replacement:\n r.brokenCreatedInSession !== null && r.reconcileSession !== null\n ? r.reconcileSession.sessionId\n : null,\n removed_linked_sessions: r.brokenLinkedSessions,\n reconcile_session_id: r.reconcileSession?.sessionId ?? null,\n event_id: r.reconcileSession?.eventId ?? null,\n })),\n failed: input.failed.map((f) => ({\n task_id: f.taskId,\n error_class: f.errorClass,\n phase: f.phase,\n })),\n },\n null,\n 2,\n ),\n );\n}\n\nasync function printReconcileSingleText(\n result: ReconcileResult,\n paths: ReturnType<typeof basouPaths>,\n options: { write: boolean; verbose: boolean },\n): Promise<void> {\n if (result.clean) {\n // For the --task path with no broken refs we report counts of reachable\n // references so the operator gets a positive audit confirmation rather\n // than a bare \"ok\". Re-read task.md cheaply; the core API already did\n // the integrity work so this is just for the display string.\n let createdCount = 0;\n let linkedCount = 0;\n try {\n const doc = await readTaskFile(paths, result.taskId);\n createdCount = 1;\n linkedCount = doc.task.task.linked_sessions.length;\n } catch {\n // If the file became unreadable between reconcileTask and here just\n // fall back to a less detailed message rather than crashing the run.\n }\n console.log(\n `${result.taskId}: no broken refs (${createdCount} created_in_session + ${linkedCount} linked_sessions, all reachable).`,\n );\n return;\n }\n if (options.write) {\n const sessionPart =\n result.reconcileSession !== null\n ? ` (in session ${shortSessionId(result.reconcileSession.sessionId)})`\n : \"\";\n console.log(`Reconciled ${result.taskId}: ${describeReconcileSummary(result)}${sessionPart}.`);\n return;\n }\n const summary = describeBrokenSummary(result, \"task\", options.verbose);\n console.log(`(dry-run) Would reconcile ${result.taskId}: ${summary}`);\n console.log(\"Note: events -> task.md forward sync is handled by `basou task refresh-linkage`.\");\n console.log(\"Re-run with --write to apply.\");\n}\n\nfunction printReconcileAllText(\n results: ReadonlyArray<ReconcileResult>,\n failed: ReadonlyArray<ReconcileFailure>,\n scanned: number,\n options: { write: boolean; verbose: boolean },\n): void {\n if (results.length === 0 && failed.length === 0) {\n console.log(`Scanned ${scanned} tasks, no broken refs detected.`);\n return;\n }\n\n let totalBrokenRefs = 0;\n for (const r of results) {\n totalBrokenRefs += r.brokenLinkedSessions.length + (r.brokenCreatedInSession !== null ? 1 : 0);\n }\n\n if (options.write) {\n for (const r of results) {\n const sessionPart =\n r.reconcileSession !== null\n ? ` (in session ${shortSessionId(r.reconcileSession.sessionId)})`\n : \"\";\n console.log(`Reconciled ${r.taskId}: ${describeReconcileSummary(r)}${sessionPart}`);\n }\n for (const f of failed) {\n const phase = f.phase ?? \"unknown\";\n console.error(\n `Failed to reconcile ${f.taskId}: ${f.errorClass} (phase: ${phase}); see Caused by with -v`,\n );\n }\n const reconciledCount = results.length;\n const reconciledRefs = totalBrokenRefs;\n const reconciledPart = `reconciled ${reconciledCount} task${reconciledCount === 1 ? \"\" : \"s\"} (${reconciledRefs} broken ref${reconciledRefs === 1 ? \"\" : \"s\"})`;\n const failedPart =\n failed.length === 0 ? \"\" : `, ${failed.length} task${failed.length === 1 ? \"\" : \"s\"} failed`;\n console.log(`Scanned ${scanned} tasks, ${reconciledPart}${failedPart}.`);\n if (failed.length > 0) {\n console.error(\"(exit code 1)\");\n }\n return;\n }\n\n // dry-run with broken refs\n for (const r of results) {\n const summary = describeBrokenSummary(r, \"all\", options.verbose);\n console.log(`(dry-run) Would reconcile ${r.taskId}: ${summary}`);\n }\n console.log(\n `Scanned ${scanned} tasks, would reconcile ${results.length} task${results.length === 1 ? \"\" : \"s\"} (${totalBrokenRefs} broken ref${totalBrokenRefs === 1 ? \"\" : \"s\"}).`,\n );\n console.log(\"Note: events -> task.md forward sync is handled by `basou task refresh-linkage`.\");\n console.log(\"Re-run with --write to apply.\");\n}\n\nfunction describeReconcileSummary(r: ReconcileResult): string {\n const linkedCount = r.brokenLinkedSessions.length;\n const parts: string[] = [];\n if (r.brokenCreatedInSession !== null) {\n parts.push(\"replaced created_in_session\");\n }\n if (linkedCount > 0) {\n parts.push(`removed ${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"}`);\n }\n return parts.join(\" + \");\n}\n\nfunction describeBrokenSummary(\n r: ReconcileResult,\n scope: \"all\" | \"task\",\n verbose: boolean,\n): string {\n const showIds = scope === \"task\" || verbose;\n const parts: string[] = [];\n if (r.brokenCreatedInSession !== null) {\n parts.push(\n showIds\n ? `broken created_in_session ${formatSessionIdForDisplay(r.brokenCreatedInSession, verbose, scope)}`\n : \"broken created_in_session\",\n );\n }\n const linkedCount = r.brokenLinkedSessions.length;\n if (linkedCount > 0) {\n if (showIds) {\n const ids = r.brokenLinkedSessions\n .map((id) => formatSessionIdForDisplay(id, verbose, scope))\n .join(\", \");\n parts.push(`${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"} [${ids}]`);\n } else {\n parts.push(`${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"}`);\n }\n }\n return parts.join(\" + \");\n}\n\nfunction formatSessionIdForDisplay(id: string, verbose: boolean, scope: \"all\" | \"task\"): string {\n if (verbose && scope === \"task\") return id;\n return `ses_${shortSessionId(id)}`;\n}\n\n// ============================================================================\n// task refresh-linkage\n// ============================================================================\n\nexport async function runTaskRefreshLinkage(\n taskIdInput: string,\n options: TaskRefreshLinkageOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskRefreshLinkage(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskRefreshLinkage(\n taskIdInput: string,\n options: TaskRefreshLinkageOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"refresh-linkage\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const nowProvider = ctx.nowProvider ?? ((): Date => new Date());\n const write = options.write === true;\n\n const result = await refreshTaskLinkedSessions(paths, manifest, {\n taskId,\n occurredAt: nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n });\n\n if (options.json === true) {\n printRefreshLinkageJson(result, { dryRun: !write });\n return;\n }\n printRefreshLinkageText(result, { dryRun: !write });\n}\n\nfunction printRefreshLinkageJson(result: RefreshLinkageResult, input: { dryRun: boolean }): void {\n console.log(\n JSON.stringify(\n {\n task_id: result.taskId,\n clean: result.clean,\n dry_run: input.dryRun,\n added_linked_sessions: result.addedLinkedSessions,\n removed_linked_sessions: result.removedLinkedSessions,\n final_count: result.finalCount,\n refresh_session_id: result.refreshSession?.sessionId ?? null,\n event_id: result.refreshSession?.eventId ?? null,\n },\n null,\n 2,\n ),\n );\n}\n\nfunction printRefreshLinkageText(result: RefreshLinkageResult, input: { dryRun: boolean }): void {\n if (result.clean) {\n console.log(\n `${result.taskId}: linked_sessions already fresh (${result.finalCount} entr${result.finalCount === 1 ? \"y\" : \"ies\"}).`,\n );\n return;\n }\n const addedCount = result.addedLinkedSessions.length;\n const removedCount = result.removedLinkedSessions.length;\n const summaryParts: string[] = [];\n if (addedCount > 0) {\n summaryParts.push(`+${addedCount} added`);\n }\n if (removedCount > 0) {\n summaryParts.push(`-${removedCount} removed`);\n }\n const summary = summaryParts.join(\", \");\n if (input.dryRun) {\n console.log(`(dry-run) Would refresh ${result.taskId} linked_sessions: ${summary}.`);\n console.log(\"Re-run with --write to apply.\");\n return;\n }\n const sid =\n result.refreshSession !== null\n ? ` (in session ${shortSessionId(result.refreshSession.sessionId)})`\n : \"\";\n console.log(\n `Refreshed ${result.taskId} linked_sessions: ${summary}${sid}; final count ${result.finalCount}.`,\n );\n}\n\n// ============================================================================\n// task edit / delete / archive\n// ============================================================================\n\nexport async function runTaskEdit(\n taskIdInput: string,\n options: TaskEditOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskEdit(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskEdit(\n taskIdInput: string,\n options: TaskEditOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n if (options.title === undefined && options.status === undefined) {\n throw new Error(\"Nothing to edit: provide --title or --status\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"edit\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n\n const result = await editTask({\n paths,\n taskId,\n occurredAt,\n manifest,\n workingDirectory: repositoryRoot,\n ...(options.title !== undefined ? { title: options.title } : {}),\n ...(options.status !== undefined ? { newStatus: options.status } : {}),\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title_updated: result.titleUpdated,\n status_updated: result.statusUpdated,\n previous_status: result.previousStatus,\n new_status: result.newStatus,\n status_change_session_id: result.statusChangeSession?.sessionId ?? null,\n status_change_event_id: result.statusChangeSession?.eventId ?? null,\n }),\n );\n return;\n }\n if (result.statusUpdated) {\n const sid =\n result.statusChangeSession !== null\n ? ` (in session ${shortSessionId(result.statusChangeSession.sessionId)})`\n : \"\";\n console.log(\n `Updated ${result.taskId} status: ${result.previousStatus} -> ${result.newStatus}${sid}`,\n );\n }\n if (result.titleUpdated) {\n console.log(`Updated ${result.taskId} title.`);\n }\n if (!result.statusUpdated && !result.titleUpdated) {\n // Both fields were supplied but matched the current values exactly —\n // tell the operator the task was already in the requested state.\n console.log(`No changes for ${result.taskId}.`);\n }\n}\n\nexport async function runTaskDelete(\n taskIdInput: string,\n options: TaskDeleteOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskDelete(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskDelete(\n taskIdInput: string,\n options: TaskDeleteOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"delete\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n\n if (options.yes !== true) {\n await confirmDestructiveAction(\"delete\", taskId);\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const result = await deleteTask({\n paths,\n manifest,\n taskId,\n occurredAt,\n workingDirectory: repositoryRoot,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title: result.title,\n session_id: result.sessionId,\n event_id: result.eventId,\n }),\n );\n return;\n }\n console.log(\n `Deleted ${result.taskId} (\"${result.title}\") in ad-hoc session ${shortSessionId(result.sessionId)}.`,\n );\n}\n\nexport async function runTaskArchive(\n taskIdInput: string,\n options: TaskArchiveOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskArchive(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskArchive(\n taskIdInput: string,\n options: TaskArchiveOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"archive\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n\n if (options.yes !== true) {\n await confirmDestructiveAction(\"archive\", taskId);\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const result = await archiveTask({\n paths,\n manifest,\n taskId,\n occurredAt,\n workingDirectory: repositoryRoot,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title: result.title,\n session_id: result.sessionId,\n event_id: result.eventId,\n }),\n );\n return;\n }\n console.log(\n `Archived ${result.taskId} (\"${result.title}\") in ad-hoc session ${shortSessionId(result.sessionId)}.`,\n );\n}\n\n/**\n * Read a single y/N answer from stdin when stdin is a TTY. Refuses to wait\n * for input when stdin is not a TTY (operator must pass --yes explicitly),\n * so piping `echo y | basou task delete` cannot accidentally trigger a\n * destructive action.\n */\nasync function confirmDestructiveAction(\n action: \"delete\" | \"archive\",\n taskId: string,\n): Promise<void> {\n if (process.stdin.isTTY !== true) {\n throw new Error(`Refusing to ${action} without TTY; rerun with --yes to skip confirmation.`);\n }\n const verb = action === \"delete\" ? \"Delete\" : \"Archive\";\n process.stdout.write(`${verb} task \\`${taskId}\\`? [y/N] `);\n const answer = await readSingleLineFromStdin();\n const normalized = answer.trim().toLowerCase();\n if (normalized !== \"y\" && normalized !== \"yes\") {\n throw new Error(`${verb} aborted by user.`);\n }\n}\n\nasync function readSingleLineFromStdin(): Promise<string> {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const line = await rl.question(\"\");\n return line;\n } finally {\n rl.close();\n }\n}\n\n// ============================================================================\n// option converters\n// ============================================================================\n\nfunction parseTitle(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseLabel(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Label must not be empty\");\n }\n return raw;\n}\n\nfunction parseInitialTaskStatus(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new InvalidArgumentError(\n `Initial task status must be one of: ${STATUS_VALUES.join(\", \")}`,\n );\n }\n return result.data;\n}\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/;\n\nfunction parseIsoTimestampOption(raw: string): string {\n // Mirror the IsoTimestampSchema accepted form: date + time + explicit\n // zone designator. We rely on Date.parse for content validation and the\n // regex above for shape so misformed inputs are rejected before we hand\n // the string to the orchestrator's downstream parsers.\n if (!ISO_DATE_RE.test(raw) || Number.isNaN(Date.parse(raw))) {\n throw new InvalidArgumentError(\n \"Invalid --completed-at value; expected ISO-8601 timestamp like 2026-05-10T12:34:56+09:00\",\n );\n }\n return raw;\n}\n\nfunction parseTaskStatusFilter(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new InvalidArgumentError(\n `Invalid task status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`,\n );\n }\n return result.data;\n}\n\nfunction parseTaskStatusPositional(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid task status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction parseDescriptionOption(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Description must not be empty\");\n }\n return raw;\n}\n\nfunction parsePositiveInt(raw: string): number {\n const n = Number.parseInt(raw, 10);\n if (!Number.isInteger(n) || n < 1 || raw.trim() !== String(n)) {\n throw new InvalidArgumentError(`Invalid number: ${raw}`);\n }\n return n;\n}\n\n// ============================================================================\n// IO helpers\n// ============================================================================\n\nasync function readDescriptionFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Description source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Description source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read description source\", { cause: error });\n }\n}\n\nasync function resolveRepositoryRootForTask(\n cwd: string,\n subcmd:\n | \"new\"\n | \"list\"\n | \"show\"\n | \"status\"\n | \"reconcile\"\n | \"refresh-linkage\"\n | \"edit\"\n | \"delete\"\n | \"archive\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou task ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\n/**\n * Task-specific classifier for {@link TaskWriteAfterEventError}. The\n * generic renderer ({@link renderCliError}) already prints the underlying\n * `error.message`; this classifier appends the two task-specific lines\n * that explain WHICH artefact is in unsafe state and the manual-repair\n * hint. Combined with {@link failedToFinalizeClassifier} from the shared\n * lib so both error classes are surfaced consistently across `task new`,\n * `task status`, `task reconcile`, etc.\n */\nconst taskWriteAfterEventClassifier: ErrorClassifier = {\n match: (error) => error instanceof TaskWriteAfterEventError,\n additionalLines: (error) => {\n const e = error as TaskWriteAfterEventError;\n const sid = shortSessionId(e.sessionId);\n const tid = shortTaskId(e.taskId);\n const unsafeArtefact = describeUnsafeArtefact(e.phase, tid, sid);\n const warning = describeWriteFailureWarning(e.phase);\n const hint =\n e.phase === \"reconcile-concurrent\"\n ? \"re-run `basou task reconcile`\"\n : e.phase === \"linkage-refresh-concurrent\"\n ? \"re-run `basou task refresh-linkage`\"\n : \"manual repair required; see `basou task show -v` for event payload\";\n return [\n `Recorded ${e.eventId} in session ${sid}; ${unsafeArtefact} is in unsafe state; do not rerun`,\n `Warning: ${warning}; events.jsonl is consistent; ${hint}`,\n ];\n },\n};\n\nconst TASK_CLASSIFIERS: readonly ErrorClassifier[] = [\n taskWriteAfterEventClassifier,\n failedToFinalizeClassifier,\n];\n\nfunction describeUnsafeArtefact(\n phase: TaskWriteAfterEventError[\"phase\"],\n tid: string,\n sid: string,\n): string {\n switch (phase) {\n case \"create\":\n return `task ${tid} file`;\n case \"overwrite\":\n return `task ${tid} file`;\n case \"link-session\":\n return \"session-task linkage\";\n case \"reconcile\":\n return `task ${tid} file (reconcile incomplete)`;\n case \"reconcile-finalize\":\n return `reconcile session ${sid} (finalize incomplete)`;\n case \"reconcile-concurrent\":\n return `task ${tid} file (concurrent modification detected)`;\n case \"linkage-refresh\":\n return `task ${tid} file (linkage refresh incomplete)`;\n case \"linkage-refresh-finalize\":\n return `linkage refresh session ${sid} (finalize incomplete)`;\n case \"linkage-refresh-concurrent\":\n return `task ${tid} file (concurrent modification detected)`;\n case \"delete\":\n return `task ${tid} file (delete incomplete; file still on disk)`;\n case \"archive\":\n return `task ${tid} file (archive incomplete; check tasks/ and tasks/archive/)`;\n }\n}\n\nfunction describeWriteFailureWarning(phase: TaskWriteAfterEventError[\"phase\"]): string {\n switch (phase) {\n case \"create\":\n return \"task.md creation failed\";\n case \"overwrite\":\n return \"task.md update failed\";\n case \"link-session\":\n return \"session.yaml task_id update failed\";\n case \"reconcile\":\n return \"task.md reconciliation failed\";\n case \"reconcile-finalize\":\n return \"reconcile session finalize failed (session.yaml status update)\";\n case \"reconcile-concurrent\":\n return \"task.md was modified concurrently; re-run reconcile to retry\";\n case \"linkage-refresh\":\n return \"task.md linkage refresh write failed\";\n case \"linkage-refresh-finalize\":\n return \"linkage refresh session finalize failed (session.yaml status update)\";\n case \"linkage-refresh-concurrent\":\n return \"task.md was modified concurrently; re-run refresh-linkage to retry\";\n case \"delete\":\n return \"task.md unlink failed after task_deleted event committed\";\n case \"archive\":\n return \"task.md move to archive/ failed after task_archived event committed\";\n }\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n type ChainVerdict,\n enumerateSessionDirs,\n findErrorCode,\n resolveRepositoryRoot,\n resolveSessionId,\n verifyEventsChain,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type VerifyOptions = {\n session?: string;\n all?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type VerifyContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/** One row of `basou verify` output: a session id and its chain verdict. */\nexport type VerifyRow = {\n session_id: string;\n status: ChainVerdict[\"status\"];\n event_count: number;\n reason?: ChainVerdict[\"reason\"];\n line?: number;\n};\n\n/** Wire `basou verify` onto `program`. */\nexport function registerVerifyCommand(program: Command): void {\n program\n .command(\"verify\")\n .description(\"Verify the tamper-evidence hash chain of sessions' event logs (read-only)\")\n .option(\"--session <id>\", \"Verify a single session (unique id prefix accepted)\")\n .option(\"--all\", \"Verify every session (the default when --session is omitted)\")\n .option(\"--json\", \"Output the verdicts as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: VerifyOptions) => {\n await runVerify(opts);\n });\n}\n\nexport async function runVerify(options: VerifyOptions, ctx: VerifyContext = {}): Promise<void> {\n try {\n await doRunVerify(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nasync function doRunVerify(options: VerifyOptions, ctx: VerifyContext): Promise<void> {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForVerify(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionIds =\n options.session !== undefined\n ? [await resolveSessionId(paths, options.session)]\n : await enumerateSessionDirs(paths);\n\n const rows: VerifyRow[] = [];\n for (const sessionId of sessionIds) {\n const verdict = await verifyEventsChain(paths, sessionId);\n rows.push({\n session_id: sessionId,\n status: verdict.status,\n event_count: verdict.eventCount,\n ...(verdict.reason !== undefined ? { reason: verdict.reason } : {}),\n ...(verdict.line !== undefined ? { line: verdict.line } : {}),\n });\n }\n\n const tamperedCount = rows.filter((r) => r.status === \"tampered\").length;\n\n if (options.json === true) {\n console.log(JSON.stringify(rows, null, 2));\n } else {\n for (const row of rows) {\n console.log(`${row.session_id} ${renderVerdict(row)}`);\n }\n const tally = (status: VerifyRow[\"status\"]): number =>\n rows.filter((r) => r.status === status).length;\n console.log(\n `Sessions: ${rows.length} total — ${tally(\"verified\")} verified, ` +\n `${tally(\"unchained\")} unchained, ${tally(\"empty\")} empty, ` +\n `${tally(\"incomplete\")} incomplete, ${tally(\"in_progress\")} in_progress, ` +\n `${tamperedCount} tampered`,\n );\n }\n\n // Only a real integrity break fails the command; unchained / empty /\n // incomplete / in_progress are informational states.\n if (tamperedCount > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction renderVerdict(row: VerifyRow): string {\n switch (row.status) {\n case \"verified\":\n return `verified (${row.event_count} events)`;\n case \"tampered\":\n return row.line !== undefined\n ? `TAMPERED (${row.reason} at line ${row.line})`\n : `TAMPERED (${row.reason})`;\n case \"incomplete\":\n return \"incomplete (session.yaml missing; re-import to repair)\";\n case \"in_progress\":\n return `in_progress (${row.event_count} events; live session, anchor written at finalize)`;\n case \"unchained\":\n return \"unchained (session created before event-log chaining)\";\n case \"empty\":\n return \"empty\";\n }\n}\n\nasync function resolveRepositoryRootForVerify(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou verify'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { assertBasouRootSafe, basouPaths, findErrorCode, resolveRepositoryRoot } from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { startViewServer, type ViewServerDeps, type ViewServerHandle } from \"../lib/view-server.js\";\n\nconst DEFAULT_PORT = 4319;\n\nexport type ViewOptions = {\n port?: number;\n open?: boolean;\n verbose?: boolean;\n};\n\nexport type ViewContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n /** Override the `~/.claude/projects` root used by imports. */\n claudeProjectsDir?: string;\n /** Override the `~/.codex/sessions` root used by imports. */\n codexSessionsDir?: string;\n /** Override how the browser is opened (tests pass a no-op). */\n openBrowser?: (url: string) => void;\n /** Resolves the keep-alive wait, so tests can stop the server without a signal. */\n signal?: AbortSignal;\n /** Called once the server is listening, with its handle (for tests). */\n onListening?: (handle: ViewServerHandle) => void;\n};\n\nfunction parsePort(value: string): number {\n const port = Number.parseInt(value, 10);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new InvalidArgumentError(\"Port must be an integer between 1 and 65535.\");\n }\n return port;\n}\n\n/**\n * Wire `basou view` onto `program`. Starts a localhost-only web UI for\n * browsing provenance and running imports / regeneration by clicking.\n */\nexport function registerViewCommand(program: Command): void {\n program\n .command(\"view\")\n .description(\"Open a local web UI to browse provenance and run imports (localhost only)\")\n .option(\"--port <number>\", \"Port to listen on (default 4319)\", parsePort)\n .option(\"--no-open\", \"Do not open the browser automatically\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ViewOptions) => {\n await runView(options);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunView}. */\nexport async function runView(options: ViewOptions, ctx: ViewContext = {}): Promise<void> {\n try {\n await doRunView(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolve the workspace, start the server, open the browser, and\n * keep running until SIGINT / SIGTERM (or an injected abort signal). The\n * server is always closed on the way out.\n */\nexport async function doRunView(options: ViewOptions, ctx: ViewContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForView(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const deps: ViewServerDeps = {\n paths,\n repoRoot: repositoryRoot,\n importCtx: {\n cwd: repositoryRoot,\n ...(ctx.claudeProjectsDir !== undefined ? { claudeProjectsDir: ctx.claudeProjectsDir } : {}),\n ...(ctx.codexSessionsDir !== undefined ? { codexSessionsDir: ctx.codexSessionsDir } : {}),\n },\n nowProvider: ctx.nowProvider ?? (() => new Date()),\n };\n\n const port = options.port ?? DEFAULT_PORT;\n const handle = await startListening(port, deps);\n\n // Everything past listen runs under try/finally so a throw from the browser\n // launch or the onListening callback still closes the server.\n try {\n console.log(`basou view running at ${handle.url}`);\n console.log(\n \"Localhost only, no authentication. Do not expose this port beyond your machine. Press Ctrl+C to stop.\",\n );\n\n if (options.open !== false) {\n openInBrowser(handle.url, ctx.openBrowser);\n }\n ctx.onListening?.(handle);\n\n await waitForShutdown(ctx.signal);\n } finally {\n await handle.close();\n }\n}\n\nasync function startListening(port: number, deps: ViewServerDeps): Promise<ViewServerHandle> {\n try {\n return await startViewServer({ port, deps });\n } catch (error: unknown) {\n if (findErrorCode(error, \"EADDRINUSE\")) {\n throw new Error(`Port ${port} is already in use. Pass --port <n> to choose another.`, {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nfunction openInBrowser(url: string, override?: (url: string) => void): void {\n if (override !== undefined) {\n override(url);\n return;\n }\n if (process.platform !== \"darwin\") return; // print-only elsewhere\n try {\n const child = spawn(\"open\", [url], { stdio: \"ignore\", detached: true });\n child.on(\"error\", () => {}); // browser launch is best-effort\n child.unref();\n } catch {\n // ignore: the URL is already printed\n }\n}\n\n/** Resolve once the process is asked to stop (signal) or the injected abort fires. */\nfunction waitForShutdown(signal: AbortSignal | undefined): Promise<void> {\n return new Promise((resolve) => {\n const cleanup = (): void => {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const onSignal = (): void => {\n cleanup();\n resolve();\n };\n const onAbort = (): void => {\n cleanup();\n resolve();\n };\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n if (signal !== undefined) {\n if (signal.aborted) {\n cleanup();\n resolve();\n return;\n }\n signal.addEventListener(\"abort\", onAbort);\n }\n });\n}\n\nasync function resolveRepositoryRootForView(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou view'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { join } from \"node:path\";\nimport {\n type BasouPaths,\n computeWorkStats,\n enumerateApprovals,\n findErrorCode,\n isLazyExpired,\n loadApproval,\n loadSessionEntries,\n loadTaskEntries,\n type Manifest,\n readAllEvents,\n readManifest,\n readMarkdownFile,\n readSessionYaml,\n readTaskFile,\n renderDecisions,\n renderHandoff,\n} from \"@basou/core\";\nimport type { ImportContext } from \"../commands/import.js\";\nimport {\n importClaudeCode,\n importCodex,\n type RefreshActionOptions,\n refreshAll,\n regenerateDecisions,\n regenerateHandoff,\n} from \"./provenance-actions.js\";\nimport { VIEW_HTML } from \"./view-ui.js\";\n\n/** Everything the request handlers need; resolved once when the server starts. */\nexport type ViewServerDeps = {\n paths: BasouPaths;\n repoRoot: string;\n importCtx: ImportContext;\n nowProvider: () => Date;\n};\n\n/** A running view server, with the means to stop it. */\nexport type ViewServerHandle = {\n url: string;\n port: number;\n close: () => Promise<void>;\n};\n\n/** A handler-level failure that maps to a specific HTTP status (vs a 500). */\nclass HttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nconst MAX_BODY_BYTES = 64 * 1024;\n\n/**\n * Start a localhost-only provenance viewer. Binds 127.0.0.1, serves a single\n * inline HTML page at `/` and a small JSON API under `/api/*`. Resolves once\n * listening (rejects on a bind error such as EADDRINUSE).\n */\nexport function startViewServer(opts: {\n port: number;\n host?: string;\n deps: ViewServerDeps;\n}): Promise<ViewServerHandle> {\n const { port, host = \"127.0.0.1\", deps } = opts;\n // Mutating POSTs swap process-global console (import capture); serialize them\n // so concurrent requests from a reloaded tab never interleave.\n let actionQueue: Promise<unknown> = Promise.resolve();\n const runExclusive = <T>(fn: () => Promise<T>): Promise<T> => {\n const result = actionQueue.then(fn, fn);\n actionQueue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n let boundPort = port;\n const getPort = (): number => boundPort;\n\n return new Promise((resolve, reject) => {\n const server = createServer((req, res) => {\n handleRequest(req, res, deps, getPort, runExclusive).catch((error: unknown) => {\n sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));\n });\n });\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const address = server.address();\n boundPort = isAddressInfo(address) ? address.port : port;\n server.off(\"error\", reject);\n resolve({\n url: `http://${host}:${boundPort}`,\n port: boundPort,\n close: () => closeServer(server),\n });\n });\n });\n}\n\nfunction isAddressInfo(value: string | AddressInfo | null): value is AddressInfo {\n return value !== null && typeof value === \"object\";\n}\n\nfunction closeServer(server: Server): Promise<void> {\n return new Promise((resolve) => {\n server.close(() => resolve());\n // Force-terminate any in-flight connection (e.g. a client holding a POST\n // body open) so close() resolves promptly instead of hanging shutdown.\n server.closeAllConnections();\n });\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n deps: ViewServerDeps,\n getPort: () => number,\n runExclusive: <T>(fn: () => Promise<T>) => Promise<T>,\n): Promise<void> {\n const method = req.method ?? \"GET\";\n const url = new URL(req.url ?? \"/\", \"http://localhost\");\n const pathname = url.pathname;\n\n if (!hostAllowed(req, getPort())) {\n sendError(res, 403, \"Forbidden: host not allowed\");\n return;\n }\n\n if (method === \"GET\") {\n await handleGet(res, pathname, deps);\n return;\n }\n if (method === \"POST\") {\n if (!originAllowed(req, getPort())) {\n sendError(res, 403, \"Forbidden: cross-origin request\");\n return;\n }\n const body = await readBody(req);\n await handlePost(res, pathname, body, deps, runExclusive);\n return;\n }\n sendError(res, 405, \"Method not allowed\");\n}\n\nasync function handleGet(\n res: ServerResponse,\n pathname: string,\n deps: ViewServerDeps,\n): Promise<void> {\n if (pathname === \"/\") {\n sendHtml(res, VIEW_HTML);\n return;\n }\n if (pathname === \"/api/overview\") {\n sendJson(res, 200, await overview(deps));\n return;\n }\n if (pathname === \"/api/sessions\") {\n sendJson(res, 200, await sessionsList(deps));\n return;\n }\n const sessionId = matchId(pathname, \"/api/sessions/\");\n if (sessionId !== null) {\n sendJson(res, 200, await sessionDetail(deps, sessionId));\n return;\n }\n if (pathname === \"/api/tasks\") {\n sendJson(res, 200, await tasksList(deps));\n return;\n }\n const taskId = matchId(pathname, \"/api/tasks/\");\n if (taskId !== null) {\n sendJson(res, 200, await taskDetail(deps, taskId));\n return;\n }\n if (pathname === \"/api/decisions\") {\n sendJson(res, 200, await decisionsView(deps));\n return;\n }\n if (pathname === \"/api/approvals\") {\n sendJson(res, 200, await approvalsView(deps));\n return;\n }\n if (pathname === \"/api/handoff\") {\n sendJson(res, 200, await handoffView(deps));\n return;\n }\n if (pathname === \"/api/stats\") {\n sendJson(res, 200, await computeWorkStats({ paths: deps.paths, now: deps.nowProvider() }));\n return;\n }\n sendError(res, 404, \"Not found\");\n}\n\nasync function handlePost(\n res: ServerResponse,\n pathname: string,\n body: Record<string, unknown>,\n deps: ViewServerDeps,\n runExclusive: <T>(fn: () => Promise<T>) => Promise<T>,\n): Promise<void> {\n const nowIso = deps.nowProvider().toISOString();\n const actionOptions = readActionOptions(body);\n\n if (pathname === \"/api/refresh\") {\n const result = await runExclusive(() =>\n refreshAll({ options: actionOptions, ctx: deps.importCtx, paths: deps.paths, nowIso }),\n );\n sendJson(res, 200, result);\n return;\n }\n if (pathname === \"/api/import/claude-code\") {\n sendJson(res, 200, await runExclusive(() => importClaudeCode(actionOptions, deps.importCtx)));\n return;\n }\n if (pathname === \"/api/import/codex\") {\n sendJson(res, 200, await runExclusive(() => importCodex(actionOptions, deps.importCtx)));\n return;\n }\n if (pathname === \"/api/handoff/generate\") {\n sendJson(res, 200, await runExclusive(() => regenerateHandoff(deps.paths, nowIso)));\n return;\n }\n if (pathname === \"/api/decisions/generate\") {\n sendJson(res, 200, await runExclusive(() => regenerateDecisions(deps.paths, nowIso)));\n return;\n }\n sendError(res, 404, \"Not found\");\n}\n\n// --- handlers -------------------------------------------------------------\n\nasync function overview(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n let manifest: Manifest;\n try {\n manifest = await readManifest(deps.paths);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n return { initialized: false, repoRoot: deps.repoRoot };\n }\n throw error;\n }\n const nowIso = deps.nowProvider().toISOString();\n const handoff = await renderHandoff({ paths: deps.paths, nowIso });\n const approvals = await enumerateApprovals(deps.paths);\n return {\n initialized: true,\n repoRoot: deps.repoRoot,\n workspace: {\n id: manifest.workspace.id,\n name: manifest.workspace.name,\n basouVersion: manifest.basou_version,\n },\n counts: {\n sessions: handoff.sessionCount,\n suspectSessions: handoff.suspectCount,\n tasks: handoff.taskCount,\n pendingTasks: handoff.pendingTaskCount,\n decisions: handoff.decisionCount,\n approvalsPending: approvals.pending.length,\n approvalsResolved: approvals.resolved.length,\n },\n generatedAt: nowIso,\n };\n}\n\nasync function sessionsList(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n const entries = await loadSessionEntries(deps.paths, { now: deps.nowProvider() });\n // loadSessionEntries returns oldest-first; show newest-first.\n const sessions = entries\n .map((entry) => ({\n sessionId: entry.sessionId,\n label: entry.session.session.label ?? null,\n status: entry.session.session.status,\n sourceKind: entry.session.session.source.kind,\n startedAt: entry.session.session.started_at,\n endedAt: entry.session.session.ended_at ?? null,\n suspect: entry.suspect,\n suspectReason: entry.suspectReason,\n taskId: entry.session.session.task_id ?? null,\n relatedFilesCount: entry.session.session.related_files.length,\n }))\n .reverse();\n return { sessions };\n}\n\nasync function sessionDetail(\n deps: ViewServerDeps,\n sessionId: string,\n): Promise<Record<string, unknown>> {\n let session: Awaited<ReturnType<typeof readSessionYaml>>;\n try {\n session = await readSessionYaml(deps.paths, sessionId);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n throw new HttpError(404, \"Session not found\");\n }\n throw error;\n }\n // An unreadable events.jsonl must not 500 the detail view; surface the\n // session with an empty, flagged-degraded timeline (mirrors the list path).\n try {\n const events = await readAllEvents(join(deps.paths.sessions, sessionId));\n return { session, events };\n } catch {\n return { session, events: [], degraded: true };\n }\n}\n\nasync function tasksList(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n const entries = await loadTaskEntries(deps.paths);\n return { tasks: entries.map((entry) => entry.task).reverse() };\n}\n\nasync function taskDetail(deps: ViewServerDeps, taskId: string): Promise<Record<string, unknown>> {\n try {\n const doc = await readTaskFile(deps.paths, taskId);\n return { task: doc.task, body: doc.body };\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Task file not found\") {\n throw new HttpError(404, \"Task not found\");\n }\n throw error;\n }\n}\n\nasync function decisionsView(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n // Prefer the on-disk decisions.md so hand-edited content (outside the\n // generated markers) is shown, mirroring the handoff view; fall back to a\n // fresh render when the file does not exist yet.\n const fromDisk = await readMarkdownFile(deps.paths.files.decisions);\n if (fromDisk !== null) {\n return { body: fromDisk, fromDisk: true };\n }\n const nowIso = deps.nowProvider().toISOString();\n const result = await renderDecisions({ paths: deps.paths, nowIso });\n return { body: result.body, decisionCount: result.decisionCount, fromDisk: false };\n}\n\nasync function approvalsView(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n const now = deps.nowProvider();\n const ids = await enumerateApprovals(deps.paths);\n const toViews = async (list: string[]): Promise<Array<Record<string, unknown>>> => {\n const views: Array<Record<string, unknown>> = [];\n for (const id of list) {\n const loaded = await loadApproval(deps.paths, id);\n if (loaded === null) continue;\n views.push({ id, expired: isLazyExpired(loaded.approval, now), approval: loaded.approval });\n }\n return views;\n };\n return { pending: await toViews(ids.pending), resolved: await toViews(ids.resolved) };\n}\n\nasync function handoffView(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n const fromDisk = await readMarkdownFile(deps.paths.files.handoff);\n if (fromDisk !== null) {\n return { body: fromDisk, fromDisk: true };\n }\n const nowIso = deps.nowProvider().toISOString();\n const result = await renderHandoff({ paths: deps.paths, nowIso });\n return { body: result.body, fromDisk: false };\n}\n\n// --- request helpers ------------------------------------------------------\n\nfunction readActionOptions(body: Record<string, unknown>): RefreshActionOptions {\n const options: RefreshActionOptions = {};\n // Accept `project` as a single string (the UI sends one) or an array of\n // strings (multi-root callers); normalize to a non-empty string[].\n const project = normalizeProject(body.project);\n if (project.length > 0) options.project = project;\n if (body.force === true) options.force = true;\n if (body.dryRun === true) options.dryRun = true;\n return options;\n}\n\n/** Coerce a request body `project` field into a list of non-empty path strings. */\nfunction normalizeProject(value: unknown): string[] {\n const raw = Array.isArray(value) ? value : [value];\n return raw.filter((p): p is string => typeof p === \"string\" && p.length > 0);\n}\n\nfunction hostAllowed(req: IncomingMessage, port: number): boolean {\n const host = req.headers.host;\n return host === `127.0.0.1:${port}` || host === `localhost:${port}`;\n}\n\nfunction originAllowed(req: IncomingMessage, port: number): boolean {\n const origin = req.headers.origin;\n if (origin === undefined) return true; // non-browser client (curl, tests)\n return origin === `http://127.0.0.1:${port}` || origin === `http://localhost:${port}`;\n}\n\nasync function readBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buf.length;\n if (size > MAX_BODY_BYTES) throw new HttpError(413, \"Request body too large\");\n chunks.push(buf);\n }\n const raw = Buffer.concat(chunks).toString(\"utf8\").trim();\n if (raw.length === 0) return {};\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // fall through to the shared 400 below\n }\n throw new HttpError(400, \"Invalid JSON body\");\n}\n\nfunction matchId(pathname: string, prefix: string): string | null {\n if (!pathname.startsWith(prefix)) return null;\n const encoded = pathname.slice(prefix.length);\n if (encoded.length === 0 || encoded.includes(\"/\")) return null;\n let id: string;\n try {\n id = decodeURIComponent(encoded);\n } catch {\n return null; // malformed percent-escape\n }\n // Reject anything that could escape the storage root once decoded: a path\n // separator (incl. the percent-encoded `%2f` that slips past the check\n // above) or a `.`/`..` segment. Ids are otherwise opaque to this layer.\n if (\n id.length === 0 ||\n id.includes(\"/\") ||\n id.includes(\"\\\\\") ||\n id.includes(\"\\0\") ||\n id === \".\" ||\n id === \"..\"\n ) {\n return null;\n }\n return id;\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(body);\n}\n\nfunction sendHtml(res: ServerResponse, html: string): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(html);\n}\n\nfunction sendError(res: ServerResponse, status: number, message: string): void {\n if (res.headersSent) {\n res.end();\n return;\n }\n sendJson(res, status, { error: message });\n}\n\n/**\n * A pathless, audience-safe message: the Error's own message is already\n * pathless by the codebase's convention; native fs errors are wrapped before\n * they reach here. Falls back to a generic string for non-Error throws.\n */\nfunction pathlessMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Internal error\";\n}\n","/**\n * The single-page UI for `basou view`, served verbatim at `GET /`. Kept as one\n * inline string so the CLI build needs no asset pipeline. All data is rendered\n * with createElement / textContent (never innerHTML), so session, task, and\n * command content cannot inject markup. The embedded script deliberately uses\n * no template literals (this file is itself a template literal).\n */\nexport const VIEW_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>basou view</title>\n<style>\n :root { color-scheme: light dark; }\n * { box-sizing: border-box; }\n body { margin: 0; font: 14px/1.5 system-ui, -apple-system, Segoe UI, sans-serif; }\n header { padding: 10px 16px; border-bottom: 1px solid #8884; display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }\n header h1 { font-size: 15px; margin: 0 12px 0 0; font-weight: 700; }\n header .grow { flex: 1; }\n input[type=text] { padding: 4px 8px; border: 1px solid #8886; border-radius: 6px; min-width: 280px; font: inherit; }\n button { padding: 4px 10px; border: 1px solid #8886; border-radius: 6px; background: #8881; cursor: pointer; font: inherit; }\n button.primary { background: #2563eb; color: #fff; border-color: #2563eb; }\n button:disabled { opacity: .5; cursor: default; }\n label.chk { font-size: 13px; opacity: .85; }\n #status { padding: 6px 16px; font-size: 13px; min-height: 20px; border-bottom: 1px solid #8884; white-space: pre-wrap; }\n #status.err { color: #dc2626; }\n nav { display: flex; gap: 2px; padding: 6px 12px; border-bottom: 1px solid #8884; flex-wrap: wrap; }\n nav button { border: none; border-radius: 6px; background: transparent; }\n nav button.active { background: #2563eb22; font-weight: 600; }\n main { display: grid; grid-template-columns: minmax(220px, 320px) 1fr; min-height: 60vh; }\n main.single { grid-template-columns: 1fr; }\n #list { border-right: 1px solid #8884; overflow: auto; max-height: 80vh; }\n #list .row { padding: 8px 12px; border-bottom: 1px solid #8883; cursor: pointer; }\n #list .row:hover { background: #8881; }\n #list .row.active { background: #2563eb22; }\n #list .row .meta { font-size: 12px; opacity: .7; }\n #detail { padding: 12px 16px; overflow: auto; max-height: 80vh; }\n .badge { display: inline-block; padding: 0 6px; border-radius: 6px; background: #8882; font-size: 12px; }\n .badge.warn { background: #f59e0b33; }\n pre { background: #8881; padding: 12px; border-radius: 8px; overflow: auto; white-space: pre-wrap; word-break: break-word; }\n table.kv { border-collapse: collapse; }\n table.kv td { padding: 2px 10px 2px 0; vertical-align: top; }\n table.kv td.k { opacity: .7; }\n .cards { display: flex; flex-wrap: wrap; gap: 10px; }\n .card { border: 1px solid #8884; border-radius: 8px; padding: 10px 14px; min-width: 120px; }\n .card .n { font-size: 22px; font-weight: 700; }\n .card .l { font-size: 12px; opacity: .7; }\n .tl { border-left: 2px solid #8885; margin-left: 6px; padding-left: 12px; }\n .tl .ev { margin-bottom: 8px; }\n .tl .ev .t { font-size: 12px; opacity: .65; }\n .muted { opacity: .6; }\n</style>\n</head>\n<body>\n<header>\n <h1>basou view</h1>\n <input type=\"text\" id=\"project\" placeholder=\"source root (optional override)\" />\n <button class=\"primary\" id=\"btn-refresh\">Refresh all</button>\n <button id=\"btn-import-claude\">Import claude-code</button>\n <button id=\"btn-import-codex\">Import codex</button>\n <button id=\"btn-gen-handoff\">Regenerate handoff</button>\n <button id=\"btn-gen-decisions\">Regenerate decisions</button>\n <span class=\"grow\"></span>\n <label class=\"chk\"><input type=\"checkbox\" id=\"opt-force\" /> force</label>\n <label class=\"chk\"><input type=\"checkbox\" id=\"opt-dry\" /> dry-run</label>\n</header>\n<div id=\"status\"></div>\n<nav id=\"tabs\"></nav>\n<main id=\"main\">\n <div id=\"list\"></div>\n <div id=\"detail\"></div>\n</main>\n<script>\n(function () {\n var TABS = ['overview', 'stats', 'sessions', 'tasks', 'decisions', 'approvals', 'handoff'];\n var state = { tab: 'overview', repoRoot: '' };\n\n function $(id) { return document.getElementById(id); }\n function clear(node) { while (node.firstChild) node.removeChild(node.firstChild); }\n\n function el(tag, attrs, children) {\n var node = document.createElement(tag);\n if (attrs) {\n for (var k in attrs) {\n if (!Object.prototype.hasOwnProperty.call(attrs, k)) continue;\n if (k === 'class') node.className = attrs[k];\n else if (k === 'text') node.textContent = attrs[k];\n else if (k.slice(0, 2) === 'on') node.addEventListener(k.slice(2), attrs[k]);\n else node.setAttribute(k, attrs[k]);\n }\n }\n if (children) {\n for (var i = 0; i < children.length; i++) {\n var c = children[i];\n if (c === null || c === undefined) continue;\n node.appendChild(typeof c === 'string' ? document.createTextNode(c) : c);\n }\n }\n return node;\n }\n\n function setStatus(msg, isErr) {\n var s = $('status');\n s.textContent = msg || '';\n s.className = isErr ? 'err' : '';\n }\n\n function fetchJson(path, opts) {\n return fetch(path, opts).then(function (res) {\n return res.text().then(function (text) {\n var data = null;\n try { data = text ? JSON.parse(text) : null; } catch (e) { data = null; }\n if (!res.ok) {\n var m = data && data.error ? data.error : ('HTTP ' + res.status);\n throw new Error(m);\n }\n return data;\n });\n });\n }\n\n function single(on) { $('main').className = on ? 'single' : ''; if (on) clear($('list')); }\n\n // --- action bar ---------------------------------------------------------\n\n function actionBody() {\n var body = {};\n var project = $('project').value.trim();\n if (project) body.project = project;\n if ($('opt-force').checked) body.force = true;\n if ($('opt-dry').checked) body.dryRun = true;\n return body;\n }\n\n function setBusy(busy) {\n var ids = ['btn-refresh', 'btn-import-claude', 'btn-import-codex', 'btn-gen-handoff', 'btn-gen-decisions'];\n for (var i = 0; i < ids.length; i++) $(ids[i]).disabled = busy;\n }\n\n function post(path, label) {\n setBusy(true);\n setStatus(label + '...', false);\n fetchJson(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(actionBody())\n }).then(function (data) {\n setStatus(label + ' done: ' + summarize(data), false);\n loadTab(state.tab);\n }).catch(function (err) {\n setStatus(label + ' failed: ' + err.message, true);\n }).then(function () { setBusy(false); });\n }\n\n function summarize(data) {\n if (!data) return 'ok';\n if (data.claudeCode || data.codex) {\n return 'claude-code ' + imp(data.claudeCode) + ', codex ' + imp(data.codex)\n + (data.handoff && data.handoff.status === 'generated' ? '; handoff+decisions regenerated' : '');\n }\n if (data.status === 'ran') return imp(data);\n if (data.status === 'skipped') return 'skipped (' + data.reason + ')';\n if (typeof data.sessionCount === 'number') return 'sessions ' + data.sessionCount + ', decisions ' + data.decisionCount;\n if (typeof data.decisionCount === 'number') return 'decisions ' + data.decisionCount;\n return 'ok';\n }\n function imp(o) {\n if (!o) return '-';\n if (o.status === 'skipped') return 'skipped';\n return (o.dryRun ? 'would import ' : 'imported ') + o.importedCount + ' (' + o.eventTotal + ' events)';\n }\n\n // --- tabs ---------------------------------------------------------------\n\n function buildTabs() {\n var nav = $('tabs');\n clear(nav);\n TABS.forEach(function (name) {\n nav.appendChild(el('button', {\n class: name === state.tab ? 'active' : '',\n text: name,\n onclick: function () { loadTab(name); }\n }));\n });\n }\n\n function loadTab(name) {\n state.tab = name;\n buildTabs();\n clear($('detail'));\n clear($('list'));\n if (name === 'overview') return loadOverview();\n if (name === 'stats') return loadStats();\n if (name === 'sessions') return loadSessions();\n if (name === 'tasks') return loadTasks();\n if (name === 'decisions') return loadMarkdown('/api/decisions', 'decisions');\n if (name === 'approvals') return loadApprovals();\n if (name === 'handoff') return loadMarkdown('/api/handoff', 'handoff');\n }\n\n function fail(err) { setStatus(err.message, true); }\n\n function loadOverview() {\n single(true);\n fetchJson('/api/overview').then(function (d) {\n var detail = $('detail');\n if (!d || d.initialized === false) {\n detail.appendChild(el('p', { class: 'muted', text: 'Workspace not initialized.' }));\n return;\n }\n // Leave the project field empty by default so refresh / import use the\n // manifest's import.source_roots (then the repo root) -- pre-filling the\n // repo root here would send it as an explicit --project and silently\n // override multi-root source roots. The field is an optional override.\n state.repoRoot = d.repoRoot || '';\n detail.appendChild(el('p', {}, [\n el('strong', { text: d.workspace.name }), ' ',\n el('span', { class: 'muted', text: d.workspace.id })\n ]));\n var c = d.counts;\n var cards = el('div', { class: 'cards' }, [\n card(c.sessions, 'sessions'),\n card(c.suspectSessions, 'suspect'),\n card(c.tasks, 'tasks'),\n card(c.pendingTasks, 'pending tasks'),\n card(c.decisions, 'decisions'),\n card(c.approvalsPending, 'approvals pending')\n ]);\n detail.appendChild(cards);\n detail.appendChild(el('p', { class: 'muted', text: 'repo: ' + d.repoRoot }));\n }).catch(fail);\n }\n function card(n, label) {\n return el('div', { class: 'card' }, [\n el('div', { class: 'n', text: String(n) }),\n el('div', { class: 'l', text: label })\n ]);\n }\n\n function numfmt(n) { return (n || 0).toLocaleString('en-US'); }\n function fmtDur(ms) {\n var s = Math.round((ms || 0) / 1000);\n var h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;\n if (h > 0) return h + 'h ' + (m < 10 ? '0' : '') + m + 'm';\n if (m > 0) return m + 'm ' + (sec < 10 ? '0' : '') + sec + 's';\n return sec + 's';\n }\n function kvrow(k, v) {\n return el('tr', {}, [el('td', { class: 'k', text: k }), el('td', { text: v })]);\n }\n\n function loadStats() {\n single(true);\n fetchJson('/api/stats').then(function (d) {\n var detail = $('detail');\n var t = d.totals;\n detail.appendChild(el('p', { text: 'Sessions: ' + t.sessionCount }));\n detail.appendChild(el('h3', { text: 'Volume (what the AI produced)' }));\n detail.appendChild(el('div', { class: 'cards' }, [\n card(numfmt(t.tokens.output), 'output tokens'),\n (t.tokens.reasoning > 0 ? card(numfmt(t.tokens.reasoning), 'reasoning tokens') : null),\n card(t.commandCount, 'commands'),\n card(t.fileChangedCount, 'files'),\n card(t.decisionCount, 'decisions')\n ]));\n var sessions = d.sessions || [];\n var tokenSessions = sessions.filter(function (s) { return s.availability && s.availability.tokens; }).length;\n if (!t.tokensAvailable) {\n detail.appendChild(el('p', { class: 'muted', text: 'No token data captured; re-import to backfill.' }));\n } else if (tokenSessions < t.sessionCount) {\n detail.appendChild(el('p', { class: 'muted', text: 'Token data on ' + tokenSessions + ' of ' + t.sessionCount + ' sessions; re-import to backfill the rest.' }));\n }\n var degraded = sessions.filter(function (s) { return s.eventsUnreadable; }).length;\n if (degraded > 0) {\n detail.appendChild(el('p', { class: 'muted', text: degraded + ' session(s) had unreadable event logs; their counts are incomplete.' }));\n }\n detail.appendChild(el('h3', { text: 'Time (human harness labor; active = billing primary)' }));\n var turnSessions = sessions.filter(function (s) { return s.activeTimeBasis === 'engaged-turns'; }).length;\n var basisNote = turnSessions === t.sessionCount ? 'engaged turns' : (turnSessions === 0 ? 'event stream; re-import to capture conversation' : 'engaged turns on ' + turnSessions + ' of ' + t.sessionCount + ' sessions');\n var timeRows = [kvrow('billable active', fmtDur(t.billableActiveTimeMs) + ' (union; ' + basisNote + '; idle gaps > 5m excluded; tz ' + d.timeZone + ')')];\n if (t.activeTimeMs !== t.billableActiveTimeMs) {\n timeRows.push(kvrow('summed', fmtDur(t.activeTimeMs) + ' (concurrent sessions double-counted)'));\n }\n if (t.machineActiveAvailable) {\n var machineSessions = sessions.filter(function (s) { return s.availability && s.availability.machineActive; }).length;\n timeRows.push(kvrow('model working', fmtDur(t.machineActiveTimeMs) + ' (model compute, subset of active; Codex turn duration on ' + machineSessions + ' of ' + t.sessionCount + ' sessions; not wall-clock-deduped)'));\n }\n timeRows.push(kvrow('span', fmtDur(t.sessionSpanMs) + (t.openSessionCount > 0 ? ' (' + t.openSessionCount + ' open)' : '')));\n timeRows.push(kvrow('command', fmtDur(t.commandTimeMs) + (t.commandTimeReliable ? '' : ' (some sessions report 0)')));\n detail.appendChild(el('table', { class: 'kv' }, [el('tbody', {}, timeRows)]));\n if (d.bySource && d.bySource.length) {\n detail.appendChild(el('h3', { text: 'By source' }));\n d.bySource.forEach(function (s) {\n var cmd = s.commandTimeReliable ? fmtDur(s.commandTimeMs) : 'n/a';\n var machine = s.machineActiveAvailable ? ', model ' + fmtDur(s.machineActiveTimeMs) : '';\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: s.sourceKind + ': ' + s.sessionCount + ' sessions, ' + numfmt(s.tokens.output) + ' out tok, active ' + fmtDur(s.activeTimeMs) + machine + ', command ' + cmd })\n ]));\n });\n }\n if (d.byDay && d.byDay.length) {\n detail.appendChild(el('h3', { text: 'By day (billable time x volume)' }));\n d.byDay.forEach(function (day) {\n var dayMachine = day.machineActiveTimeMs > 0 ? ' (model ' + fmtDur(day.machineActiveTimeMs) + ')' : '';\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: day.date + ': ' + fmtDur(day.billableActiveTimeMs) + ' active' + dayMachine + ', ' + numfmt(day.tokens.output) + ' out tok, ' + day.commandCount + ' cmd / ' + day.fileChangedCount + ' files / ' + day.decisionCount + ' dec' })\n ]));\n });\n }\n }).catch(fail);\n }\n\n function loadSessions() {\n single(false);\n fetchJson('/api/sessions').then(function (d) {\n var list = $('list');\n var rows = (d && d.sessions) || [];\n if (rows.length === 0) { list.appendChild(el('div', { class: 'row muted', text: 'no sessions' })); return; }\n rows.forEach(function (s) {\n var row = el('div', { class: 'row', onclick: function () { selectSession(row, s.sessionId); } }, [\n el('div', { text: s.label || s.sessionId }),\n el('div', { class: 'meta', text: s.sourceKind + ' ' + s.status + (s.suspect ? ' suspect' : '') })\n ]);\n list.appendChild(row);\n });\n }).catch(fail);\n }\n function selectSession(row, id) {\n var rows = $('list').querySelectorAll('.row');\n for (var i = 0; i < rows.length; i++) rows[i].classList.remove('active');\n row.classList.add('active');\n var detail = $('detail');\n clear(detail);\n fetchJson('/api/sessions/' + encodeURIComponent(id)).then(function (d) {\n var s = d.session.session;\n detail.appendChild(el('h3', { text: s.label || id }));\n detail.appendChild(kv([\n ['status', s.status], ['source', s.source.kind], ['started', s.started_at],\n ['ended', s.ended_at || '-'], ['workdir', s.working_directory]\n ]));\n if (d.degraded) detail.appendChild(el('p', { class: 'badge warn', text: 'events unreadable' }));\n var events = d.events || [];\n detail.appendChild(el('p', { class: 'muted', text: events.length + ' events' }));\n var tl = el('div', { class: 'tl' }, []);\n events.forEach(function (ev) {\n tl.appendChild(el('div', { class: 'ev' }, [\n el('div', { class: 't', text: ev.occurred_at + ' ' + ev.type }),\n el('div', { text: eventSummary(ev) })\n ]));\n });\n detail.appendChild(tl);\n }).catch(fail);\n }\n function eventSummary(ev) {\n if (ev.type === 'command_executed') {\n var cmd = (ev.args && ev.args.length) ? ev.args.join(' ') : ev.command;\n var ex = (ev.exit_code === null || ev.exit_code === undefined) ? '' : ' (exit ' + ev.exit_code + ')';\n return cmd + ex;\n }\n if (ev.type === 'file_changed') return ev.path + ' [' + ev.change_type + ']';\n if (ev.type === 'decision_recorded') return ev.title || '';\n return '';\n }\n\n function loadTasks() {\n single(false);\n fetchJson('/api/tasks').then(function (d) {\n var list = $('list');\n var rows = (d && d.tasks) || [];\n if (rows.length === 0) { list.appendChild(el('div', { class: 'row muted', text: 'no tasks' })); return; }\n rows.forEach(function (t) {\n var row = el('div', { class: 'row', onclick: function () { selectTask(row, t.id); } }, [\n el('div', { text: t.title || t.label || t.id }),\n el('div', { class: 'meta', text: String(t.status || '') })\n ]);\n list.appendChild(row);\n });\n }).catch(fail);\n }\n function selectTask(row, id) {\n var rows = $('list').querySelectorAll('.row');\n for (var i = 0; i < rows.length; i++) rows[i].classList.remove('active');\n row.classList.add('active');\n var detail = $('detail');\n clear(detail);\n fetchJson('/api/tasks/' + encodeURIComponent(id)).then(function (d) {\n detail.appendChild(el('h3', { text: (d.task && (d.task.title || d.task.label)) || id }));\n detail.appendChild(el('pre', { text: JSON.stringify(d.task, null, 2) }));\n if (d.body) detail.appendChild(el('pre', { text: d.body }));\n }).catch(fail);\n }\n\n function loadMarkdown(path, label) {\n single(true);\n fetchJson(path).then(function (d) {\n var detail = $('detail');\n var count = (typeof d.decisionCount === 'number') ? (' (' + d.decisionCount + ' decisions)') : '';\n detail.appendChild(el('p', { class: 'muted', text: label + count }));\n detail.appendChild(el('pre', { text: (d && d.body) || '(empty)' }));\n }).catch(fail);\n }\n\n function loadApprovals() {\n single(true);\n fetchJson('/api/approvals').then(function (d) {\n var detail = $('detail');\n var groups = [['pending', d.pending || []], ['resolved', d.resolved || []]];\n groups.forEach(function (g) {\n detail.appendChild(el('h3', { text: g[0] + ' (' + g[1].length + ')' }));\n if (g[1].length === 0) { detail.appendChild(el('p', { class: 'muted', text: 'none' })); return; }\n g[1].forEach(function (a) {\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: a.id + ' ' }),\n el('span', { class: a.expired ? 'badge warn' : 'badge', text: a.expired ? 'expired' : (a.approval && a.approval.status) || '' })\n ]));\n });\n });\n }).catch(fail);\n }\n\n function kv(pairs) {\n var tbody = el('tbody', {}, pairs.map(function (p) {\n return el('tr', {}, [el('td', { class: 'k', text: p[0] }), el('td', { text: String(p[1]) })]);\n }));\n return el('table', { class: 'kv' }, [tbody]);\n }\n\n // --- wire up ------------------------------------------------------------\n\n $('btn-refresh').addEventListener('click', function () { post('/api/refresh', 'Refresh all'); });\n $('btn-import-claude').addEventListener('click', function () { post('/api/import/claude-code', 'Import claude-code'); });\n $('btn-import-codex').addEventListener('click', function () { post('/api/import/codex', 'Import codex'); });\n $('btn-gen-handoff').addEventListener('click', function () { post('/api/handoff/generate', 'Regenerate handoff'); });\n $('btn-gen-decisions').addEventListener('click', function () { post('/api/decisions/generate', 'Regenerate decisions'); });\n\n buildTabs();\n loadTab('overview');\n})();\n</script>\n</body>\n</html>`;\n"],"mappings":"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AC;AAAA,OACK;;;ACbA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["id","acquireLock","assertBasouRootSafe","basouPaths","findErrorCode","prefixedUlid","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","prefixedUlid","acquireLock","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","join","acquireLock","assertBasouRootSafe","basouPaths","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","acquireLock","readYamlFile","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","readMarkdownFile","renderWithMarkers","resolveRepositoryRoot","writeMarkdownFile","basouPaths","assertWorkspaceInitialized","readMarkdownFile","renderWithMarkers","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","homedir","join","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","readSessionYaml","resolveRepositoryRoot","SES_PREFIX","SHORT_ID_LEN","join","homedir","basouPaths","assertWorkspaceInitialized","readManifest","payload","readSessionYaml","findErrorCode","shortId","resolveRepositoryRoot","assertBasouRootSafe","basename","resolve","resolveRepositoryRoot","basename","resolve","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","InvalidArgumentError","readMarkdownFile","renderDecisions","renderHandoff","renderWithMarkers","writeMarkdownFile","renderHandoff","readMarkdownFile","writeMarkdownFile","renderWithMarkers","renderDecisions","readdir","stat","homedir","join","findErrorCode","join","homedir","readdir","findErrorCode","stat","collectPath","InvalidArgumentError","resolve","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","resolve","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","writeMarkdownFile","basouPaths","assertWorkspaceInitialized","resolve","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","mkdir","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","ChildProcessRunner","coreAppendChainedEvent","finalizeSessionYaml","getSnapshot","overwriteYamlFile","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","SessionSchema","sanitizeWorkingDirectory","writeYamlFile","ChildProcessRunner","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","mkdir","coreAppendChainedEvent","buildInitialSession","writeYamlFile","tryAppendGitSnapshot","acquireLock","mutateSessionYaml","finalizeSessionAsFailed","homedir","decideFinalStatus","finalizeSessionYaml","signalToExitCode","SIGNUM_MAP","getSnapshot","normalizeGitSnapshotSkipMessage","sanitizeWorkingDirectory","readYamlFile","SessionSchema","overwriteYamlFile","resolveRepositoryRoot","readFile","basename","isAbsolute","join","relative","acquireLock","appendEventToExistingSession","assertBasouRootSafe","basouPaths","enumerateSessionDirs","findErrorCode","importSessionFromJson","readManifest","readYamlFile","resolveRepositoryRoot","resolveSessionId","SessionImportPayloadSchema","SessionSchema","InvalidArgumentError","SES_PREFIX","TASK_PREFIX","SHORT_ID_BASE_LEN","SHORT_ID_MAX_LEN","STATUS_VALUES","basouPaths","assertWorkspaceInitialized","resolveSessionId","join","readYamlFile","SessionSchema","findErrorCode","computeUniquePrefixLen","sliceShort","maxLen","pad","isAbsolute","relative","shortTaskId","shortId","resolveRepositoryRoot","assertBasouRootSafe","readManifest","SessionImportPayloadSchema","importOptions","importSessionFromJson","readFile","InvalidArgumentError","basename","acquireLock","appendEventToExistingSession","enumerateSessionDirs","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","basouPaths","assertBasouRootSafe","findErrorCode","readManifest","resolveRepositoryRoot","readFile","join","assertBasouRootSafe","basouPaths","findErrorCode","loadSessionEntries","prefixedUlid","readManifest","replayEvents","resolveRepositoryRoot","resolveSessionId","resolveTaskId","InvalidArgumentError","STATUS_VALUES","parseTitle","parsePositiveInt","basouPaths","assertWorkspaceInitialized","prefixedUlid","resolveSessionId","result","readManifest","maxLen","pad","resolveTaskId","loadSessionEntries","join","replayEvents","createInterface","InvalidArgumentError","readFile","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","assertBasouRootSafe","basouPaths","enumerateSessionDirs","findErrorCode","resolveRepositoryRoot","resolveSessionId","basouPaths","assertWorkspaceInitialized","resolveSessionId","enumerateSessionDirs","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","InvalidArgumentError","join","computeWorkStats","enumerateApprovals","findErrorCode","isLazyExpired","loadApproval","loadSessionEntries","loadTaskEntries","readAllEvents","readManifest","readMarkdownFile","readSessionYaml","readTaskFile","renderDecisions","renderHandoff","resolve","computeWorkStats","readManifest","findErrorCode","renderHandoff","enumerateApprovals","loadSessionEntries","readSessionYaml","readAllEvents","join","loadTaskEntries","readTaskFile","readMarkdownFile","renderDecisions","loadApproval","isLazyExpired","InvalidArgumentError","basouPaths","assertWorkspaceInitialized","findErrorCode","resolve","resolveRepositoryRoot","assertBasouRootSafe","require"]}
1
+ {"version":3,"sources":["../src/program.ts","../src/commands/approval.ts","../src/lib/error-render.ts","../src/commands/decision.ts","../src/commands/decisions.ts","../src/commands/exec.ts","../src/commands/handoff.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/orient.ts","../src/lib/provenance-actions.ts","../src/lib/repo-root.ts","../src/commands/refresh.ts","../src/lib/portfolio-config.ts","../src/commands/refresh-watch.ts","../src/commands/report.ts","../src/commands/run.ts","../src/commands/session.ts","../src/lib/format-duration.ts","../src/commands/stats.ts","../src/commands/status.ts","../src/commands/task.ts","../src/commands/verify.ts","../src/commands/view.ts","../src/lib/portfolio-safety.ts","../src/lib/view-server.ts","../src/lib/view-ui.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { registerApprovalCommand } from \"./commands/approval.js\";\nimport { registerDecisionCommand } from \"./commands/decision.js\";\nimport { registerDecisionsCommand } from \"./commands/decisions.js\";\nimport { registerExecCommand } from \"./commands/exec.js\";\nimport { registerHandoffCommand } from \"./commands/handoff.js\";\nimport { registerImportCommand } from \"./commands/import.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerOrientCommand } from \"./commands/orient.js\";\nimport { registerRefreshCommand } from \"./commands/refresh.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerRunCommand } from \"./commands/run.js\";\nimport { registerSessionCommand } from \"./commands/session.js\";\nimport { registerStatsCommand } from \"./commands/stats.js\";\nimport { registerStatusCommand } from \"./commands/status.js\";\nimport { registerTaskCommand } from \"./commands/task.js\";\nimport { registerVerifyCommand } from \"./commands/verify.js\";\nimport { registerViewCommand } from \"./commands/view.js\";\n\n// Read the CLI release version directly from the sibling package.json so\n// `basou --version` cannot drift past a future package-bump (the v0.2/v0.3\n// releases both shipped with a stale \"0.1.0\" constant before the dynamic\n// read landed). The relative path is stable across the dev (src/program.ts\n// → src/../package.json) and built (dist/program.js → dist/../package.json)\n// layouts, since both files sit one directory below the package root.\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\nexport const BASOU_CLI_VERSION = pkg.version;\n\n/**\n * Build the fully-registered `basou` command tree WITHOUT parsing argv.\n *\n * This is the side-effect-free entry shared by the CLI binary (./index.ts)\n * and any introspection consumer — e.g. the docs generator that renders the\n * command reference from the published `@basou/cli`. Importing this module\n * must never parse `process.argv` or run a command action; `index.ts` owns\n * the single `parseAsync` call.\n */\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"basou\")\n .description(\"Provenance layer for AI development\")\n .version(BASOU_CLI_VERSION)\n // Required so that `basou exec` (and any other passThroughOptions\n // subcommand) can forward unknown flags to the wrapped child.\n .enablePositionalOptions();\n\n registerInitCommand(program);\n registerStatusCommand(program);\n registerStatsCommand(program);\n registerExecCommand(program);\n registerRunCommand(program);\n registerSessionCommand(program);\n registerImportCommand(program);\n registerRefreshCommand(program);\n registerVerifyCommand(program);\n registerViewCommand(program);\n registerApprovalCommand(program);\n registerDecisionCommand(program);\n registerTaskCommand(program);\n registerHandoffCommand(program);\n registerDecisionsCommand(program);\n registerReportCommand(program);\n registerOrientCommand(program);\n\n return program;\n}\n","import { unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n type Approval,\n type ApprovalLocation,\n ApprovalSchema,\n type ApprovalStatus,\n ApprovalStatusSchema,\n acquireLock,\n appendChainedEventLocked,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n type Event,\n enumerateApprovals,\n findErrorCode,\n isLazyExpired,\n linkYamlFile,\n loadApproval,\n prefixedUlid,\n readSessionYaml,\n readYamlFile,\n replayEvents,\n resolveRepositoryRoot,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, printReplayWarning, renderCliError } from \"../lib/error-render.js\";\n\nconst APPR_PREFIX = \"appr_\";\nconst SHORT_ID_BASE_LEN = 6;\nconst SHORT_ID_MAX_LEN = 26; // ULID body length\nconst ACTION_KEY_DETAIL_MAX_LEN = 60;\nconst REASON_TEXT_MAX_LEN = 80;\n\nconst STATUS_VALUES = ApprovalStatusSchema.options;\n\nexport type ApprovalListOptions = {\n json?: boolean;\n status?: ApprovalStatus;\n verbose?: boolean;\n};\n\nexport type ApprovalShowOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ApprovalApproveOptions = {\n note?: string;\n verbose?: boolean;\n};\n\nexport type ApprovalRejectOptions = {\n reason: string;\n verbose?: boolean;\n};\n\nexport type ApprovalContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\ntype ApprovalListRecord = {\n approval: Approval;\n location: ApprovalLocation;\n lazyExpired: boolean;\n};\n\n/**\n * Wire `basou approval list / show / approve / reject` onto `program`.\n *\n * The `approval` group is registered up front so future subcommands\n * (`cancel`, `recover`) added in later steps slot under the same group\n * without changing the externally visible CLI surface.\n */\nexport function registerApprovalCommand(program: Command): void {\n const approval = program\n .command(\"approval\")\n .description(\"Manage Basou approval requests under .basou/approvals/\");\n\n approval\n .command(\"list\")\n .description(\"List approvals across pending and resolved (newest first)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\n \"--status <state>\",\n `Filter by approval status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseApprovalStatus,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ApprovalListOptions) => {\n await runApprovalList(options);\n });\n\n approval\n .command(\"show <id>\")\n .description(\"Show an approval's metadata and related events\")\n .option(\"--json\", \"Output the approval and events as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalShowOptions) => {\n await runApprovalShow(id, options);\n });\n\n approval\n .command(\"approve <id>\")\n .description(\"Approve a pending approval\")\n .option(\"--note <text>\", \"Optional note to attach to the approval_approved event\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalApproveOptions) => {\n await runApprovalApprove(id, options);\n });\n\n approval\n .command(\"reject <id>\")\n .description(\"Reject a pending approval\")\n .requiredOption(\"--reason <text>\", \"Reason for rejection (required)\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: ApprovalRejectOptions) => {\n await runApprovalReject(id, options);\n });\n}\n\n// === list ===\n\n/**\n * Programmatic entry for `basou approval list` that owns process exit\n * state. Tests targeting only the success path or the thrown error should\n * prefer {@link doRunApprovalList}.\n */\nexport async function runApprovalList(\n options: ApprovalListOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `approval list`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunApprovalList(\n options: ApprovalListOptions,\n ctx: ApprovalContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const ids = await enumerateApprovals(paths);\n // A single `now` shared across every record so that two reads on the\n // same boundary instant cannot disagree (e.g. one record flagged expired\n // and another not when both straddle the same `expires_at`).\n const now = new Date();\n const records: ApprovalListRecord[] = [];\n\n // Resolve dedupe set: id appearing in both directories → prefer resolved\n // and surface a stderr warning about the stale pending entry.\n const resolvedSet = new Set(ids.resolved);\n for (const id of ids.pending) {\n if (resolvedSet.has(id)) {\n console.error(`Warning: stale pending entry for ${shortId(id)}; resolved version preferred`);\n continue;\n }\n const rec = await readApprovalListRecord(paths, id, \"pending\", now);\n if (rec !== null) records.push(rec);\n }\n for (const id of ids.resolved) {\n const rec = await readApprovalListRecord(paths, id, \"resolved\", now);\n if (rec !== null) records.push(rec);\n }\n\n records.sort((a, b) => Date.parse(b.approval.created_at) - Date.parse(a.approval.created_at));\n\n const filtered =\n options.status !== undefined\n ? records.filter((r) => r.approval.status === options.status)\n : records;\n\n if (filtered.length === 0) {\n printNoApprovals(options);\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((r) => ({ ...r.approval, lazy_expired: r.lazyExpired })),\n null,\n 2,\n ),\n );\n } else {\n printApprovalListText(filtered);\n }\n}\n\nasync function readApprovalListRecord(\n paths: BasouPaths,\n id: string,\n location: ApprovalLocation,\n now: Date,\n): Promise<ApprovalListRecord | null> {\n const filePath = join(paths.approvals[location], `${id}.yaml`);\n let raw: unknown;\n try {\n raw = await readYamlFile(filePath);\n } catch (error: unknown) {\n console.error(`Skipped ${shortId(id)}: ${describeReadError(error)}`);\n return null;\n }\n const parse = ApprovalSchema.safeParse(raw);\n if (!parse.success) {\n console.error(`Skipped ${shortId(id)}: invalid approval schema`);\n return null;\n }\n if (parse.data.id !== id) {\n // Surface a stderr warning rather than dropping silently so an operator\n // can spot the corrupted entry from `basou approval list`.\n console.error(`Skipped ${shortId(id)}: filename and YAML body id disagree`);\n return null;\n }\n const approval = parse.data;\n return { approval, location, lazyExpired: isLazyExpired(approval, now) };\n}\n\n// === show ===\n\nexport async function runApprovalShow(\n idInput: string,\n options: ApprovalShowOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunApprovalShow(\n idInput: string,\n options: ApprovalShowOptions,\n ctx: ApprovalContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const { id } = await resolveApprovalId(paths, idInput);\n const loaded = await loadApproval(paths, id);\n if (loaded === null) {\n throw new Error(`Approval not found: ${idInput}`);\n }\n\n // events.jsonl I/O failure throws \"Failed to read events.jsonl\" and is\n // converted to exit 1 by the wrapping try/catch — partial / malformed /\n // schema warnings stream through onWarning.\n const sessionDir = join(paths.sessions, loaded.approval.session_id);\n const relatedEvents: Event[] = [];\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, loaded.approval.session_id),\n })) {\n if (isApprovalEvent(ev) && ev.approval_id === id) {\n relatedEvents.push(ev);\n }\n }\n\n const now = new Date();\n const lazyExpired = isLazyExpired(loaded.approval, now);\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n approval: { ...loaded.approval, lazy_expired: lazyExpired },\n events: relatedEvents,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n printApprovalShowText(loaded.approval, loaded.location, relatedEvents, lazyExpired);\n}\n\n// === approve / reject ===\n\nexport async function runApprovalApprove(\n idInput: string,\n options: ApprovalApproveOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalResolve(idInput, options, ctx, \"approve\");\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runApprovalReject(\n idInput: string,\n options: ApprovalRejectOptions,\n ctx: ApprovalContext = {},\n): Promise<void> {\n try {\n await doRunApprovalResolve(idInput, options, ctx, \"reject\");\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nasync function doRunApprovalResolve(\n idInput: string,\n options: ApprovalApproveOptions | ApprovalRejectOptions,\n ctx: ApprovalContext,\n decision: \"approve\" | \"reject\",\n): Promise<void> {\n if (decision === \"reject\") {\n const reason = (options as ApprovalRejectOptions).reason;\n if (reason.length === 0) {\n throw new Error(\"--reason must not be empty\");\n }\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForApproval(cwd, decision);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n // Step D-2: resolve id (search both directories).\n const { id, location } = await resolveApprovalId(paths, idInput);\n\n // Step D-3: a resolved-side hit means there is nothing left to decide.\n if (location === \"resolved\") {\n throw new Error(`Approval already resolved: ${idInput}`);\n }\n\n // Step D-4: read + parse the pending YAML.\n const pendingPath = join(paths.approvals.pending, `${id}.yaml`);\n let pendingRaw: unknown;\n try {\n pendingRaw = await readYamlFile(pendingPath);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n throw new Error(`Approval not found: ${idInput}`);\n }\n throw new Error(\"Failed to read approval\", { cause: error });\n }\n // Wrap zod's parse so a malformed pending YAML surfaces through the\n // pathless `Failed to read approval` contract instead of leaking a raw\n // ZodError through the rendered output.\n const approvalParse = ApprovalSchema.safeParse(pendingRaw);\n if (!approvalParse.success) {\n throw new Error(\"Failed to read approval\", { cause: approvalParse.error });\n }\n const approval = approvalParse.data;\n // Defensive id check (matches loadApproval): filename id and body id\n // must agree, otherwise we'd resolve one approval while emitting events\n // for another.\n if (approval.id !== id) {\n throw new Error(\"Failed to read approval\", {\n cause: new Error(`Approval id mismatch: filename id ${id} vs YAML body id ${approval.id}`),\n });\n }\n // A pending-side YAML whose status is no longer `pending` means the\n // file was corrupted (or hand-edited mid-resolution). Refuse to fire a\n // second resolution event for it.\n if (approval.status !== \"pending\") {\n throw new Error(`Approval status mismatch: pending YAML has status=${approval.status}`);\n }\n\n // Step D-6/D-7 timestamps + event id, computed up front so they are shared\n // with the resolved-side YAML (Step D-9, built after the lock is released).\n const now = new Date();\n const occurredAt = now.toISOString();\n const eventId = prefixedUlid(\"evt\");\n\n // Hold the session lock across the replay fence and the resolution append so\n // two concurrent resolvers cannot both pass the fence before either appends\n // (closing a pre-existing double-resolution race) and so the resolution line\n // chains onto the session's on-disk tail. The caller owns the critical\n // section, so the lock-assumed append primitive is used here.\n const sessionLock = await acquireLock(paths, \"session\", approval.session_id);\n try {\n // Step D-5: events.jsonl fence — if a resolution event already exists\n // for this approval, refuse to fire a second one. This guards the\n // crash-mid-orchestration window where step 8 succeeded but step 10\n // failed (events.jsonl is the source-of-truth, not the YAML mirror).\n const sessionDir = join(paths.sessions, approval.session_id);\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, approval.session_id),\n })) {\n if (\n isApprovalEvent(ev) &&\n ev.approval_id === approval.id &&\n (ev.type === \"approval_approved\" ||\n ev.type === \"approval_rejected\" ||\n ev.type === \"approval_expired\")\n ) {\n throw new Error(`Approval already resolved (per events.jsonl): ${idInput}`);\n }\n }\n\n // Step D-6: lazy expire state-fence. No event is fired here; the\n // approval_expired event is reserved for a later step that owns\n // expiry-side orchestration.\n if (isLazyExpired(approval, now)) {\n throw new Error(`Approval already expired: ${idInput}`);\n }\n\n // Step D-6b: attachable-status fence. An approval is resolved while its\n // session is still live (initialized / running / waiting_approval). Refuse\n // any other status — matching every other attach path — so a resolution\n // line is never chained onto a finalized (anchored) or imported log, which\n // `verify` would otherwise read as tampered (the at-rest anchor would no\n // longer match the extended log). Only a positively read non-attachable\n // status blocks; a missing or unreadable session.yaml falls through to the\n // pre-existing behavior.\n let sessionStatus: string | null = null;\n try {\n sessionStatus = (await readSessionYaml(paths, approval.session_id)).session.status;\n } catch {\n sessionStatus = null;\n }\n const attachable =\n sessionStatus === \"initialized\" ||\n sessionStatus === \"running\" ||\n sessionStatus === \"waiting_approval\";\n if (sessionStatus !== null && !attachable) {\n throw new Error(\n `Cannot resolve an approval for a session that is not active (status=${sessionStatus}): ${idInput}`,\n );\n }\n\n // Step D-8: append the resolution event to events.jsonl, chained onto the\n // on-disk tail. After this point the trail is committed; subsequent\n // failures must not roll back the event (the source-of-truth invariant).\n if (decision === \"approve\") {\n const note = (options as ApprovalApproveOptions).note ?? null;\n await appendChainedEventLocked(paths, approval.session_id, {\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: approval.session_id,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"approval_approved\",\n approval_id: approval.id,\n resolver: \"local-cli\",\n note,\n });\n } else {\n const reason = (options as ApprovalRejectOptions).reason;\n await appendChainedEventLocked(paths, approval.session_id, {\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: approval.session_id,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"approval_rejected\",\n approval_id: approval.id,\n resolver: \"local-cli\",\n reason,\n });\n }\n } finally {\n await sessionLock.release();\n }\n\n // Step D-9: build the resolved-side YAML body in memory.\n const resolvedApproval: Approval =\n decision === \"approve\"\n ? {\n ...approval,\n status: \"approved\",\n resolver: \"local-cli\",\n resolved_at: occurredAt,\n note: (options as ApprovalApproveOptions).note ?? null,\n }\n : {\n ...approval,\n status: \"rejected\",\n resolver: \"local-cli\",\n resolved_at: occurredAt,\n rejection_reason: (options as ApprovalRejectOptions).reason,\n };\n\n // Step D-10: create-only write. linkYamlFile fails fast with EEXIST if a\n // concurrent resolver already populated the resolved-side YAML — the\n // events.jsonl fence above should have caught it first, so reaching\n // EEXIST here implies a near-simultaneous race we surface explicitly.\n const resolvedPath = join(paths.approvals.resolved, `${id}.yaml`);\n try {\n await linkYamlFile(resolvedPath, resolvedApproval);\n } catch (error: unknown) {\n const cause = error instanceof Error ? error.cause : undefined;\n if (cause instanceof Error && (cause as Error & { code?: unknown }).code === \"EEXIST\") {\n throw new Error(\"Approval already resolved at the same time\", { cause });\n }\n throw error;\n }\n\n // Step D-11: best-effort unlink of the pending YAML. The trail and the\n // resolved-side YAML are already consistent at this point; a leftover\n // pending entry is reconciled by the next `approval list`'s dedupe.\n try {\n await unlink(pendingPath);\n } catch {\n console.error(\n `Warning: failed to unlink pending entry for ${shortId(id)}; events.jsonl is consistent`,\n );\n }\n\n // Step D-12: success message.\n const verb = decision === \"approve\" ? \"Approved\" : \"Rejected\";\n console.log(`${verb} approval ${shortId(id)}`);\n}\n\n// === helpers ===\n\nasync function resolveApprovalId(\n paths: BasouPaths,\n input: string,\n): Promise<{ id: string; location: ApprovalLocation }> {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw new Error(\"Approval id is empty\");\n }\n const normalized = trimmed.startsWith(APPR_PREFIX) ? trimmed : `${APPR_PREFIX}${trimmed}`;\n // Reject prefix-only input so a bare prefix cannot match an arbitrary\n // approval via `startsWith`.\n if (normalized.length <= APPR_PREFIX.length) {\n throw new Error(`Approval not found: ${input}`);\n }\n\n const enumeration = await enumerateApprovals(paths);\n\n // Aggregate by full id so a duplicate (same id in both pending and\n // resolved) collapses to one entry with location=resolved (preferred).\n const byId = new Map<string, ApprovalLocation>();\n for (const id of enumeration.pending) {\n if (id.startsWith(normalized)) byId.set(id, \"pending\");\n }\n for (const id of enumeration.resolved) {\n if (!id.startsWith(normalized)) continue;\n if (byId.get(id) === \"pending\") {\n // Same full id present on both sides: resolved wins, surface a warning.\n console.error(`Warning: stale pending entry for ${shortId(id)}; resolved version preferred`);\n }\n byId.set(id, \"resolved\");\n }\n\n if (byId.size === 0) {\n throw new Error(`Approval not found: ${input}`);\n }\n if (byId.size > 1) {\n throw new Error(\n `Ambiguous approval id '${input}': matched ${byId.size} approvals. Disambiguate with a longer prefix.`,\n );\n }\n const first = byId.entries().next().value;\n if (first === undefined) {\n throw new Error(`Approval not found: ${input}`);\n }\n const [id, location] = first;\n return { id, location };\n}\n\nfunction isApprovalEvent(ev: Event): ev is Event & { approval_id: string } {\n return (\n ev.type === \"approval_requested\" ||\n ev.type === \"approval_approved\" ||\n ev.type === \"approval_rejected\" ||\n ev.type === \"approval_expired\"\n );\n}\n\nfunction printApprovalListText(records: ApprovalListRecord[]): void {\n // Grow the SHORT_ID column on collision. The dedupe in doRunApprovalList\n // already collapsed duplicates by full id, so feeding only the unique\n // ids here is correct.\n const allIds = records.map((r) => r.approval.id);\n const shortLen = computeUniquePrefixLen(allIds);\n const rows = records.map((r) => {\n const sid = sliceShort(r.approval.id, shortLen);\n const status = r.lazyExpired ? `${r.approval.status} (expired)` : r.approval.status;\n const risk = r.approval.risk_level;\n const action = r.approval.action.kind;\n const createdAt = r.approval.created_at;\n const reason = truncate(r.approval.reason, REASON_TEXT_MAX_LEN);\n return { sid, status, risk, action, createdAt, reason };\n });\n\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n risk: maxLen(\n rows.map((r) => r.risk),\n \"RISK\".length,\n ),\n action: maxLen(\n rows.map((r) => r.action),\n \"ACTION\".length,\n ),\n createdAt: maxLen(\n rows.map((r) => r.createdAt),\n \"CREATED_AT\".length,\n ),\n };\n\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"RISK\", widths.risk)} ${pad(\"ACTION\", widths.action)} ${pad(\"CREATED_AT\", widths.createdAt)} REASON`,\n );\n for (const row of rows) {\n console.log(\n `${pad(row.sid, widths.sid)} ${pad(row.status, widths.status)} ${pad(row.risk, widths.risk)} ${pad(row.action, widths.action)} ${pad(row.createdAt, widths.createdAt)} ${row.reason}`,\n );\n }\n}\n\nfunction printApprovalShowText(\n approval: Approval,\n _location: ApprovalLocation,\n events: readonly Event[],\n lazyExpired: boolean,\n): void {\n console.log(`Approval: ${approval.id} (status: ${approval.status})`);\n console.log(`Session: ${approval.session_id}`);\n console.log(`Created at: ${approval.created_at}`);\n console.log(`Risk level: ${approval.risk_level}`);\n console.log(`Action: ${formatActionLine(approval.action)}`);\n console.log(`Reason: ${approval.reason}`);\n const expiresLabel = formatExpiresLabel(approval.expires_at, lazyExpired);\n console.log(`Expires at: ${expiresLabel}`);\n console.log(`Resolver: ${approval.resolver ?? \"(none)\"}`);\n console.log(`Resolved at: ${approval.resolved_at ?? \"(none)\"}`);\n console.log(`Note: ${approval.note ?? \"(none)\"}`);\n console.log(`Rejection reason: ${approval.rejection_reason ?? \"(none)\"}`);\n\n console.log(\"\");\n console.log(`Related events: ${events.length} total`);\n for (const ev of events) {\n console.log(` ${formatApprovalEventLine(ev)}`);\n }\n}\n\nfunction formatActionLine(action: { kind: string } & Record<string, unknown>): string {\n const extras: string[] = [];\n for (const [key, value] of Object.entries(action)) {\n if (key === \"kind\") continue;\n if (typeof value !== \"string\") continue;\n extras.push(`${key}=\"${truncate(value, ACTION_KEY_DETAIL_MAX_LEN)}\"`);\n if (extras.length >= 2) break;\n }\n return extras.length === 0 ? action.kind : `${action.kind} (${extras.join(\", \")})`;\n}\n\nfunction formatExpiresLabel(expiresAt: string | null, lazyExpired: boolean): string {\n if (expiresAt === null) return \"(none)\";\n return lazyExpired ? `${expiresAt} (expired)` : expiresAt;\n}\n\nfunction formatApprovalEventLine(ev: Event): string {\n const summary = approvalEventSummary(ev);\n return `${ev.occurred_at} [${ev.source}] ${ev.type} ${summary}`;\n}\n\nfunction approvalEventSummary(ev: Event): string {\n switch (ev.type) {\n case \"approval_requested\":\n return `${ev.action.kind} risk=${ev.risk_level}`;\n case \"approval_approved\":\n return ev.resolver !== undefined ? `by ${ev.resolver}` : \"(approved)\";\n case \"approval_rejected\":\n return ev.resolver !== undefined ? `by ${ev.resolver}: ${ev.reason}` : ev.reason;\n case \"approval_expired\":\n return `approval=${ev.approval_id}`;\n default:\n // Other event types are filtered out before reaching this helper.\n return \"\";\n }\n}\n\nfunction shortId(id: string): string {\n return sliceShort(id, SHORT_ID_BASE_LEN);\n}\n\n// Known Basou prefixed-id leading tokens. Strip whichever applies so that\n// a session id passed through the warning handler renders as the bare\n// ULID prefix (matching what session.ts already emits) instead of leaving\n// the `ses_` head in the truncated short id.\nconst KNOWN_ID_PREFIXES = [\"appr_\", \"ses_\", \"evt_\", \"ws_\", \"task_\", \"decision_\"] as const;\n\nfunction sliceShort(id: string, len: number): string {\n for (const prefix of KNOWN_ID_PREFIXES) {\n if (id.startsWith(prefix)) {\n return id.slice(prefix.length, prefix.length + len);\n }\n }\n return id.slice(0, len);\n}\n\nfunction computeUniquePrefixLen(ids: readonly string[]): number {\n if (ids.length <= 1) return SHORT_ID_BASE_LEN;\n for (let len = SHORT_ID_BASE_LEN; len <= SHORT_ID_MAX_LEN; len += 2) {\n const seen = new Set<string>();\n let collided = false;\n for (const id of ids) {\n const key = sliceShort(id, len);\n if (seen.has(key)) {\n collided = true;\n break;\n }\n seen.add(key);\n }\n if (!collided) return len;\n }\n return SHORT_ID_MAX_LEN;\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 3)}...`;\n}\n\nasync function resolveRepositoryRootForApproval(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"approve\" | \"reject\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou approval ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\nfunction describeReadError(error: unknown): string {\n if (error instanceof Error) {\n if (error.message === \"YAML file not found\") return \"approval YAML not found\";\n if (error.message === \"Failed to parse YAML content\") return \"invalid YAML\";\n return error.message;\n }\n return String(error);\n}\n\nfunction parseApprovalStatus(raw: string): ApprovalStatus {\n const result = ApprovalStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid approval status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction printNoApprovals(options: ApprovalListOptions): void {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No approvals found.\");\n }\n}\n","import {\n FailedToFinalizeError,\n type ReplayWarning,\n type SessionSkipReason,\n type TaskSkipReason,\n} from \"@basou/core\";\n\n// ============================================================================\n// Short-id helpers\n// ============================================================================\n\nconst SES_PREFIX = \"ses_\";\nconst TASK_PREFIX = \"task_\";\nconst SHORT_ID_LEN = 6;\n\n/**\n * Strip the `ses_` prefix and slice the first {@link SHORT_ID_LEN} chars of\n * the ULID body for human-readable session identification in CLI output.\n * IDs without the prefix are sliced from offset 0.\n */\nexport function shortSessionId(id: string): string {\n if (id.startsWith(SES_PREFIX))\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + SHORT_ID_LEN);\n return id.slice(0, SHORT_ID_LEN);\n}\n\n/**\n * Same as {@link shortSessionId} but for `task_<ULID>` ids.\n */\nexport function shortTaskId(id: string): string {\n if (id.startsWith(TASK_PREFIX))\n return id.slice(TASK_PREFIX.length, TASK_PREFIX.length + SHORT_ID_LEN);\n return id.slice(0, SHORT_ID_LEN);\n}\n\n// ============================================================================\n// Verbose mode detection\n// ============================================================================\n\n/**\n * Unified verbose-mode predicate: `options.verbose === true` OR the\n * `BASOU_DEBUG=1` environment variable. CLI surfaces use this everywhere\n * the verbose error / cause label rendering needs a yes/no answer.\n */\nexport function isVerbose(options: { verbose?: boolean } | undefined): boolean {\n return options?.verbose === true || process.env.BASOU_DEBUG === \"1\";\n}\n\n// ============================================================================\n// Cause-chain walk (pathless)\n// ============================================================================\n\nconst CAUSE_CHAIN_MAX_DEPTH = 4;\n\n/**\n * Walk the cause chain (up to {@link CAUSE_CHAIN_MAX_DEPTH} hops) and return\n * the first errno-style `code` found, falling back to the deepest\n * constructor name. The value goes into `Caused by: <label>` so verbose\n * output stays pathless even when capability layers wrap native errors.\n *\n * Returns `undefined` when `error.cause` is not itself an Error (= no chain\n * to walk).\n */\nexport function extractCauseLabel(error: Error): string | undefined {\n let current: unknown = error.cause;\n let constructorName: string | undefined;\n for (let depth = 0; depth < CAUSE_CHAIN_MAX_DEPTH; depth += 1) {\n if (!(current instanceof Error)) break;\n const code = (current as Error & { code?: unknown }).code;\n if (typeof code === \"string\" && code.length > 0) return code;\n constructorName = current.constructor.name;\n current = current.cause;\n }\n return constructorName;\n}\n\n// ============================================================================\n// Pluggable classifier interface\n// ============================================================================\n\n/**\n * Plug-in for command-specific error rendering. {@link renderCliError}\n * invokes every classifier whose {@link match} returns true and emits each\n * line returned by {@link additionalLines} after the main `error.message`\n * line. Classifiers MUST keep their lines pathless — no absolute paths, no\n * `cause.message` echo.\n */\nexport interface ErrorClassifier {\n match(error: Error): boolean;\n additionalLines(error: Error): readonly string[];\n}\n\n/**\n * Shared classifier for {@link FailedToFinalizeError}. Both `task.ts` and\n * `decision.ts` need exactly the same two warning lines — the session.yaml\n * status update failed AFTER the target event was already written, so the\n * operator must NOT retry the command.\n */\nexport const failedToFinalizeClassifier: ErrorClassifier = {\n match: (error) => error instanceof FailedToFinalizeError,\n additionalLines: (error) => {\n const e = error as FailedToFinalizeError;\n const sid = shortSessionId(e.sessionId);\n // `targetEventIds[0]` is the operator-facing anchor event (= the\n // `decision_recorded` / `task_created` / `task_reconciled` event the\n // command was meant to produce). Multi-target ad-hoc sessions (e.g.\n // `task new --status done` which adds `task_status_changed`) carry the\n // additional ids in `targetEventIds[1..]`; one anchor is enough for the\n // do-not-rerun warning.\n const anchor = e.targetEventIds[0];\n return [\n `Recorded ${anchor} in session ${sid}; do not rerun`,\n \"Warning: session.yaml status update failed; events.jsonl is consistent\",\n ];\n },\n};\n\n// ============================================================================\n// Generic CLI error renderer\n// ============================================================================\n\n/**\n * Render an unknown thrown value to stderr without leaking absolute paths.\n *\n * Always prints `error.message` first, then any classifier-emitted lines,\n * and finally — in verbose mode — a single `Caused by: <label>` line where\n * `<label>` is the first errno code found while walking `error.cause` (or\n * the deepest constructor name as a fallback). The error's `cause.message`\n * is intentionally never printed because Node's native fs errors embed\n * absolute paths there.\n *\n * Non-Error values are coerced via `String(error)` so the catch-all fallback\n * in `program.parseAsync().catch(...)` still produces something readable.\n */\nexport function renderCliError(\n error: unknown,\n options: { verbose: boolean; classifiers?: readonly ErrorClassifier[] },\n): void {\n if (!(error instanceof Error)) {\n console.error(String(error));\n return;\n }\n console.error(error.message);\n for (const classifier of options.classifiers ?? []) {\n if (classifier.match(error)) {\n for (const line of classifier.additionalLines(error)) console.error(line);\n }\n }\n if (options.verbose) {\n const label = extractCauseLabel(error);\n if (label !== undefined) console.error(`Caused by: ${label}`);\n }\n}\n\n// ============================================================================\n// Warning surface helpers\n// ============================================================================\n\n/**\n * Print a `ReplayWarning` on stderr in the canonical short form used by\n * every command that consumes the event-replay stream (= task / handoff /\n * decisions / etc.). The session id is shortened via {@link shortSessionId}\n * for readability.\n */\nexport function printReplayWarning(warning: ReplayWarning, sessionId: string): void {\n const short = shortSessionId(sessionId);\n switch (warning.kind) {\n case \"partial_trailing_line\":\n console.error(`Warning: ignored partial trailing line in ${short}/events.jsonl`);\n break;\n case \"malformed_json\":\n console.error(\n `Warning: skipped malformed JSON at line ${warning.line} in ${short}/events.jsonl`,\n );\n break;\n case \"schema_violation\":\n console.error(\n `Warning: skipped invalid event at line ${warning.line} in ${short}/events.jsonl`,\n );\n break;\n }\n}\n\n/**\n * Print a session-skip warning in the \"scan\" form used by handoff / decisions\n * generators: `events_jsonl_unreadable` is mapped to the standardised\n * suspect-check warning used elsewhere in the CLI, every other reason falls\n * through to a generic `Skipped <sid>: <reason>` form preserving the raw\n * enum value.\n */\nexport function printSessionSkip(sid: string, reason: SessionSkipReason): void {\n const short = shortSessionId(sid);\n if (reason === \"events_jsonl_unreadable\") {\n console.error(`Warning: skipped suspect check for ${short}: events.jsonl unreadable`);\n } else {\n console.error(`Skipped ${short}: ${reason}`);\n }\n}\n\n/**\n * Print a session-skip warning in the \"list\" form used by `session list`.\n * Each reason is mapped to a user-friendly English phrase rather than the\n * raw enum value. `events_jsonl_unreadable` shares the wording produced by\n * {@link printSessionSkip} so the CLI surface stays consistent across\n * subcommands.\n */\nexport function printSessionListSkip(sid: string, reason: SessionSkipReason): void {\n const short = shortSessionId(sid);\n switch (reason) {\n case \"session_yaml_missing\":\n console.error(`Skipped ${short}: session.yaml not found`);\n break;\n case \"session_yaml_invalid\":\n console.error(`Skipped ${short}: invalid session schema`);\n break;\n case \"events_jsonl_unreadable\":\n console.error(`Warning: skipped suspect check for ${short}: events.jsonl unreadable`);\n break;\n }\n}\n\n/**\n * Print a task-skip warning shared between `task list` (which sees a\n * narrowed {@link TaskSkipReason} enum) and handoff / decisions generators\n * (which may forward an arbitrary reason string). Accepts a plain `string`\n * so both shapes route through the same renderer.\n */\nexport function printTaskSkip(taskId: string, reason: TaskSkipReason | string): void {\n console.error(`Skipped ${shortTaskId(taskId)}: ${reason}`);\n}\n","import {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n type PrefixedId,\n prefixedUlid,\n readManifest,\n resolveRepositoryRoot,\n resolveSessionId,\n type SessionStatus,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n failedToFinalizeClassifier,\n isVerbose,\n renderCliError,\n shortSessionId,\n} from \"../lib/error-render.js\";\n\n// Raised from the original 40-char cap to 80 chars so a long decision\n// title (= the most common ad-hoc trigger) retains its core information\n// without being truncated. 80 chars still fits comfortably in\n// single-column session list / handoff renderings. Operator feedback\n// from real-world long-title outliers may revisit this value.\nconst LABEL_TITLE_MAX = 80;\nconst LABEL_TRUNCATE_HEAD = LABEL_TITLE_MAX - 3;\n\nexport type DecisionRecordOptions = {\n title: string;\n rationale?: string;\n rejectedReason?: string;\n alternative?: string[];\n linkedEvent?: string[];\n linkedFile?: string[];\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type DecisionContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou decision record` onto `program`. The `decision` group only\n * contains the write-side `record` subcommand in v0.1; list/show inspectors\n * are deferred to a v0.3+ follow-up.\n */\nexport function registerDecisionCommand(program: Command): void {\n const decision = program\n .command(\"decision\")\n .description(\"Record human-authored decisions as events\");\n\n decision\n .command(\"record\")\n .description(\"Record a decision_recorded event\")\n .requiredOption(\"--title <text>\", \"Decision title\", parseTitle)\n .option(\"--rationale <text>\", \"Rationale for the decision\", parseRationale)\n .option(\n \"--rejected-reason <text>\",\n \"Reason rejected alternatives were not chosen\",\n parseRejectedReason,\n )\n .option(\n \"--alternative <text>\",\n \"Alternative considered (repeatable: --alternative yup --alternative joi)\",\n collectAlternative,\n [] as string[],\n )\n .option(\n \"--linked-event <event_id>\",\n \"Related event id (repeatable). Schema only checks the prefix; existence is verified at render time.\",\n collectLinkedEvent,\n [] as string[],\n )\n .option(\n \"--linked-file <path>\",\n \"Related file path (repeatable). Path is opaque; existence is verified at render time.\",\n collectLinkedFile,\n [] as string[],\n )\n .option(\n \"--session <session_id>\",\n \"Attach to an existing session; otherwise an ad-hoc session is created\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: DecisionRecordOptions) => {\n await runDecisionRecord(options);\n });\n}\n\n/**\n * Programmatic entry for `basou decision record`. Owns process exit state.\n * Tests targeting the success path or the thrown error should prefer\n * {@link doRunDecisionRecord}.\n */\nexport async function runDecisionRecord(\n options: DecisionRecordOptions,\n ctx: DecisionContext = {},\n): Promise<void> {\n try {\n await doRunDecisionRecord(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionRecord(\n options: DecisionRecordOptions,\n ctx: DecisionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForDecision(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const decisionId = prefixedUlid(\"decision\");\n\n const rich = pickRichFields(options);\n\n if (options.session !== undefined) {\n const sessionId = await resolveSessionId(paths, options.session);\n const sesId = sessionId as PrefixedId<\"ses\">;\n // Per-session lock guards the session.yaml status read + events.jsonl\n // append window against a concurrent writer (`basou session note`,\n // another `decision record --session`, or an attach-flavoured task\n // command). `appendEventToExistingSession` itself holds no lock; the\n // caller owns the critical section.\n const sessionLock = await acquireLock(paths, \"session\", sesId);\n let result: Awaited<ReturnType<typeof appendEventToExistingSession>>;\n try {\n result = await appendEventToExistingSession({\n paths,\n sessionId: sesId,\n eventBuilder: (eventId) =>\n buildDecisionEvent({\n eventId,\n sessionId: sesId,\n decisionId,\n title: options.title,\n occurredAt,\n rich,\n }),\n });\n } finally {\n await sessionLock.release();\n }\n printDecisionResult(options, {\n mode: \"attached\",\n sessionId,\n decisionId,\n eventId: result.eventId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n rich,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildAdHocLabel(options.title),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou decision record\",\n args: [\"--title\", options.title],\n },\n targetEventBuilders: [\n (sessionId, eventId) =>\n buildDecisionEvent({\n eventId,\n sessionId,\n decisionId,\n title: options.title,\n occurredAt,\n rich,\n }),\n ],\n });\n printDecisionResult(options, {\n mode: \"ad-hoc\",\n sessionId: adHoc.sessionId,\n decisionId,\n eventId: adHoc.targetEventIds[0] as string,\n sessionStatus: \"completed\",\n title: options.title,\n rich,\n });\n}\n\ntype RichDecisionFields = {\n rationale?: string;\n rejected_reason?: string;\n alternatives?: string[];\n linked_events?: string[];\n linked_files?: string[];\n};\n\nfunction pickRichFields(options: DecisionRecordOptions): RichDecisionFields {\n const out: RichDecisionFields = {};\n if (options.rationale !== undefined) out.rationale = options.rationale;\n if (options.rejectedReason !== undefined) out.rejected_reason = options.rejectedReason;\n if (options.alternative !== undefined && options.alternative.length > 0) {\n out.alternatives = [...options.alternative];\n }\n if (options.linkedEvent !== undefined && options.linkedEvent.length > 0) {\n out.linked_events = [...options.linkedEvent];\n }\n if (options.linkedFile !== undefined && options.linkedFile.length > 0) {\n out.linked_files = [...options.linkedFile];\n }\n return out;\n}\n\nfunction buildDecisionEvent(input: {\n eventId: PrefixedId<\"evt\">;\n sessionId: PrefixedId<\"ses\">;\n decisionId: PrefixedId<\"decision\">;\n title: string;\n occurredAt: string;\n rich: RichDecisionFields;\n}): Event {\n return {\n schema_version: \"0.1.0\",\n id: input.eventId,\n session_id: input.sessionId,\n occurred_at: input.occurredAt,\n source: \"local-cli\",\n type: \"decision_recorded\",\n decision_id: input.decisionId,\n title: input.title,\n ...(input.rich.rationale !== undefined ? { rationale: input.rich.rationale } : {}),\n ...(input.rich.alternatives !== undefined ? { alternatives: input.rich.alternatives } : {}),\n ...(input.rich.rejected_reason !== undefined\n ? { rejected_reason: input.rich.rejected_reason }\n : {}),\n ...(input.rich.linked_events !== undefined\n ? { linked_events: input.rich.linked_events as Array<`evt_${string}`> }\n : {}),\n ...(input.rich.linked_files !== undefined ? { linked_files: input.rich.linked_files } : {}),\n };\n}\n\nfunction buildAdHocLabel(title: string): string {\n const truncated =\n title.length > LABEL_TITLE_MAX ? `${title.slice(0, LABEL_TRUNCATE_HEAD)}...` : title;\n return `Ad-hoc decision: ${truncated}`;\n}\n\nfunction parseTitle(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseRationale(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Rationale must not be empty\");\n }\n return raw;\n}\n\nfunction parseRejectedReason(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Rejected reason must not be empty\");\n }\n return raw;\n}\n\nfunction collectAlternative(value: string, prev: string[]): string[] {\n if (value.length === 0) {\n throw new InvalidArgumentError(\"Alternative must not be empty\");\n }\n return prev.concat(value);\n}\n\nconst EVENT_ID_RE = /^evt_[A-Z0-9]+$/;\n\nfunction collectLinkedEvent(value: string, prev: string[]): string[] {\n if (!EVENT_ID_RE.test(value)) {\n throw new InvalidArgumentError(`Linked event id must match evt_<ULID>, got '${value}'`);\n }\n return prev.concat(value);\n}\n\nfunction collectLinkedFile(value: string, prev: string[]): string[] {\n if (value.length === 0) {\n throw new InvalidArgumentError(\"Linked file path must not be empty\");\n }\n if (value.length > 4096) {\n throw new InvalidArgumentError(\"Linked file path exceeds 4096 chars\");\n }\n return prev.concat(value);\n}\n\ntype DecisionPrintInput = {\n mode: \"ad-hoc\" | \"attached\";\n sessionId: string;\n decisionId: string;\n eventId: string;\n sessionStatus: SessionStatus;\n title: string;\n rich: RichDecisionFields;\n};\n\nfunction printDecisionResult(options: DecisionRecordOptions, result: DecisionPrintInput): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n const payload: Record<string, unknown> = {\n decision_id: result.decisionId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n title: result.title,\n };\n // Rich fields are now persisted into the decision_recorded event, so\n // they appear in the JSON summary as-is (the old `rationale_saved:\n // false` indicator is gone).\n if (result.rich.rationale !== undefined) payload.rationale = result.rich.rationale;\n if (result.rich.alternatives !== undefined) payload.alternatives = result.rich.alternatives;\n if (result.rich.rejected_reason !== undefined) {\n payload.rejected_reason = result.rich.rejected_reason;\n }\n if (result.rich.linked_events !== undefined) payload.linked_events = result.rich.linked_events;\n if (result.rich.linked_files !== undefined) payload.linked_files = result.rich.linked_files;\n console.log(JSON.stringify(payload));\n return;\n }\n const rationaleSuffix =\n result.rich.rationale !== undefined ? ` (rationale: ${result.rich.rationale})` : \"\";\n if (result.mode === \"ad-hoc\") {\n console.log(`Recorded ${result.decisionId} in ad-hoc session ${sid}${rationaleSuffix}`);\n } else {\n console.log(\n `Recorded ${result.decisionId} in session ${sid} (${result.sessionStatus})${rationaleSuffix}`,\n );\n }\n}\n\nasync function resolveRepositoryRootForDecision(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou decision record'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n readMarkdownFile,\n renderDecisions,\n renderWithMarkers,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type DecisionsGenerateOptions = { verbose?: boolean };\n\nexport type DecisionsContext = {\n cwd?: string;\n nowProvider?: () => Date;\n};\n\n/** Wire `basou decisions generate` onto `program`. Mirrors `handoff` exactly. */\nexport function registerDecisionsCommand(program: Command): void {\n const decisions = program\n .command(\"decisions\")\n .description(\"Generate or inspect .basou/decisions.md\");\n\n decisions\n .command(\"generate\")\n .description(\"Regenerate .basou/decisions.md from recorded decision events\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: DecisionsGenerateOptions) => {\n await runDecisionsGenerate(opts);\n });\n}\n\nexport async function runDecisionsGenerate(\n options: DecisionsGenerateOptions,\n ctx: DecisionsContext = {},\n): Promise<void> {\n try {\n await doRunDecisionsGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionsGenerate(\n options: DecisionsGenerateOptions,\n ctx: DecisionsContext,\n): Promise<void> {\n void options;\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForDecisions(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderDecisions({\n paths,\n nowIso,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n });\n\n const existing = await readMarkdownFile(paths.files.decisions);\n const finalBody = renderWithMarkers(existing, result.body, \"decisions.md\");\n await writeMarkdownFile(paths.files.decisions, finalBody);\n\n console.log(`Generated .basou/decisions.md (decisions: ${result.decisionCount})`);\n}\n\nasync function resolveRepositoryRootForDecisions(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou decisions generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n acquireLock,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n ChildProcessRunner,\n appendChainedEvent as coreAppendChainedEvent,\n finalizeSessionYaml,\n getSnapshot,\n overwriteYamlFile,\n type PrefixedId,\n type ProcessRunner,\n parseDuration,\n prefixedUlid,\n type RunResult,\n readManifest,\n readYamlFile,\n resolveRepositoryRoot,\n type Session,\n SessionSchema,\n sanitizeWorkingDirectory,\n writeYamlFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\n// Appends one event to the session's events.jsonl. The `sessionDir` argument\n// is retained for the test-injection seam (ctx.appendEvent); the production\n// binding ignores it and chains via paths + sessionId.\ntype AppendEventFn = (sessionDir: string, event: unknown) => Promise<void>;\n\n/**\n * `basou exec` orchestration: spawn an arbitrary child as a single new\n * Basou session and record its lifecycle (session_started, optional\n * git_snapshot pre, status_changed, command_executed, optional git_snapshot\n * post, status_changed, session_ended) to `events.jsonl`.\n *\n * Output is forwarded to the parent's terminal (`capture: \"none\"`); raw\n * stdout/stderr is intentionally not stored in events.jsonl or `.basou/raw/`.\n */\nexport type ExecOptions = {\n timeout?: string;\n cwd?: string;\n // commander turns `--no-snapshot` into `snapshot: false`. The default\n // (no flag) leaves this `undefined` (treated as `true` downstream).\n snapshot?: boolean;\n verbose?: boolean;\n};\n\ntype ExecContext = {\n runner?: ProcessRunner;\n now?: () => Date;\n // events.jsonl writer override. Tests use this to verify that appendEvent\n // failures during git_snapshot propagate as exec failures (see\n // tryAppendGitSnapshot below) instead of being swallowed into a skip warning.\n appendEvent?: AppendEventFn;\n // Last-resort SIGKILL hook installation hook. Tests capture the handler\n // installed on `process.on(\"exit\", ...)` and trigger it manually to verify\n // that activeChild is killed when the parent exits abnormally.\n onExitHookInstalled?: (handler: () => void) => void;\n};\n\nexport function registerExecCommand(program: Command): void {\n program\n .command(\"exec <command> [args...]\")\n .description(\"Execute a command and record it as a Basou session\")\n // Pass through unknown options/flags after the command name to the\n // child so callers can write `basou exec npm test --watch` instead of\n // `basou exec -- npm test --watch`. basou's own options (--timeout,\n // --no-snapshot, --cwd, -v) must come before the command name.\n .passThroughOptions()\n .option(\"--timeout <duration>\", \"Kill the child after this duration (e.g. 30s, 5m, 1h)\")\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the command\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (command: string, args: string[], options: ExecOptions) => {\n try {\n const exitCode = await runExec(command, args, options);\n process.exit(exitCode);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exit(1);\n }\n });\n}\n\nexport async function runExec(\n command: string,\n args: string[],\n options: ExecOptions,\n ctx: ExecContext = {},\n): Promise<number> {\n const runner = ctx.runner ?? new ChildProcessRunner();\n const now = ctx.now ?? (() => new Date());\n const cwd = options.cwd ?? process.cwd();\n\n // 0. timeout option fail-fast: invalid timeout never creates a session.\n const timeout_ms = options.timeout !== undefined ? parseDuration(options.timeout) : undefined;\n\n // 1. Resolve repository root before touching anything; matches existing\n // init/status semantics so subdir invocations still find `.basou/`.\n const repoRoot = await resolveRepositoryRootForExec(cwd);\n const paths = basouPaths(repoRoot);\n\n // 2. Workspace safety check (caller responsibility).\n await assertBasouRootSafe(paths.root);\n\n // 3. Read manifest to bind session.workspace_id.\n const manifest = await readManifest(paths);\n\n // 4. Build a fresh session and persist its initial state.\n const sessionId = prefixedUlid(\"ses\");\n const sessionDir = join(paths.sessions, sessionId);\n await mkdir(sessionDir, { recursive: true });\n\n // Every append chains onto the on-disk tail under a short-lived session lock\n // (the self-locking wrapper); the lock is NEVER held across the child. Tests\n // inject ctx.appendEvent to force append failures.\n const appendEvent: AppendEventFn =\n ctx.appendEvent ??\n (async (_sessionDir, event) => {\n await coreAppendChainedEvent(paths, sessionId, event);\n });\n\n const startedAt = now().toISOString();\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n const session = buildInitialSession({\n id: sessionId,\n command,\n args,\n cwd,\n workspaceId: manifest.workspace.id,\n startedAt,\n });\n await writeYamlFile(sessionYamlPath, session);\n\n // 5. session_started.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_started\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: startedAt,\n source: \"terminal-recording\",\n });\n\n // 6. Optional pre-execute git_snapshot.\n if (options.snapshot !== false) {\n await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 7. status_changed: initialized -> running.\n const runningAt = now().toISOString();\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: runningAt,\n source: \"terminal-recording\",\n from: \"initialized\",\n to: \"running\",\n });\n // Lock the status write so it cannot interleave-clobber a foreign locked\n // session.yaml writer (e.g. a task attach setting task_id on this session).\n const runningLock = await acquireLock(paths, \"session\", sessionId);\n try {\n await mutateSessionYaml(sessionYamlPath, (s) => {\n s.session.status = \"running\";\n });\n } finally {\n await runningLock.release();\n }\n\n // 8. Transient signal hooks: SIGINT / SIGTERM / exit. The exit hook is\n // a synchronous last-resort SIGKILL if the parent exits abnormally.\n const controller = new AbortController();\n let signalReceived: NodeJS.Signals | null = null;\n let activeChild: ChildProcess | null = null;\n const signalHandler = (sig: NodeJS.Signals) => {\n if (signalReceived !== null) return;\n signalReceived = sig;\n controller.abort();\n };\n const exitHandler = () => {\n if (activeChild !== null) {\n try {\n activeChild.kill(\"SIGKILL\");\n } catch {\n // swallow: best-effort cleanup\n }\n }\n };\n // Bind explicit signal names so `process.emit(\"SIGINT\")` etc. produce the\n // right `received_signal` regardless of Node's listener-arg conventions.\n const onSigInt = () => signalHandler(\"SIGINT\");\n const onSigTerm = () => signalHandler(\"SIGTERM\");\n process.on(\"SIGINT\", onSigInt);\n process.on(\"SIGTERM\", onSigTerm);\n process.on(\"exit\", exitHandler);\n // Allow tests to capture the exit handler and trigger the activeChild\n // SIGKILL fallback synchronously without faking `process.emit(\"exit\")`.\n ctx.onExitHookInstalled?.(exitHandler);\n\n let result: RunResult;\n try {\n try {\n result = await runner.run(command, args, {\n cwd,\n capture: \"none\",\n ...(timeout_ms !== undefined ? { timeout_ms } : {}),\n signal: controller.signal,\n onSpawn: (child) => {\n activeChild = child;\n },\n });\n } catch (spawnError: unknown) {\n // Spawn-time error / pre-aborted / validation error: tear down the\n // session as failed before propagating so events.jsonl and session.yaml\n // are consistent even on error.\n await finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent, {\n command,\n args,\n cwd,\n occurredAt: now().toISOString(),\n signalReceived,\n });\n throw spawnError;\n }\n } finally {\n process.off(\"SIGINT\", onSigInt);\n process.off(\"SIGTERM\", onSigTerm);\n process.off(\"exit\", exitHandler);\n activeChild = null;\n }\n\n const endedAt = now().toISOString();\n\n // 9. command_executed (with parent received_signal vs child terminating signal).\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n command,\n args,\n cwd,\n exit_code: result.exit_code,\n ...(result.signal !== null ? { signal: result.signal } : {}),\n ...(signalReceived !== null ? { received_signal: signalReceived } : {}),\n duration_ms: result.duration_ms,\n });\n\n // 10. Optional post-execute git_snapshot (after command_executed so the\n // event sequence reads chronologically: pre-snapshot, run, post-snapshot).\n if (options.snapshot !== false) {\n await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n const finalStatus = decideFinalStatus(result, signalReceived);\n\n // 11. status_changed: running -> final.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n from: \"running\",\n to: finalStatus,\n });\n\n // 12. session_ended.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n ...(result.exit_code !== null ? { exit_code: result.exit_code } : {}),\n });\n\n // 13. Final session.yaml update (status / ended_at / invocation.exit_code)\n // plus the integrity head anchor, written from the on-disk tail under the\n // session lock so a foreign line appended just before finalize is\n // anchored and a later attach (now terminal) is rejected.\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = finalStatus;\n s.session.ended_at = endedAt;\n s.session.invocation.exit_code = result.exit_code;\n });\n\n if (result.exit_code !== null) {\n return result.exit_code;\n }\n return signalToExitCode(signalReceived ?? result.signal);\n}\n\nfunction decideFinalStatus(\n result: { exit_code: number | null; signal: NodeJS.Signals | null },\n signalReceived: NodeJS.Signals | null,\n): \"completed\" | \"failed\" | \"interrupted\" {\n if (signalReceived === \"SIGINT\" || signalReceived === \"SIGTERM\") return \"interrupted\";\n if (result.signal === \"SIGINT\" || result.signal === \"SIGTERM\" || result.signal === \"SIGKILL\") {\n return \"interrupted\";\n }\n if (result.exit_code === 0) return \"completed\";\n return \"failed\";\n}\n\nconst SIGNUM_MAP: Record<string, number> = {\n SIGHUP: 1,\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n};\n\nfunction signalToExitCode(sig: NodeJS.Signals | null): number {\n if (sig === null) return 1;\n const num = SIGNUM_MAP[sig] ?? 1;\n return 128 + num;\n}\n\nasync function tryAppendGitSnapshot(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n now: () => Date,\n appendEvent: AppendEventFn,\n): Promise<void> {\n // Stage 1: snapshot acquisition. Capability-level failures (no git repo,\n // git binary missing, no commits) are recoverable and downgrade to a skip\n // warning. The session continues and events.jsonl simply lacks this\n // git_snapshot entry.\n let snapshot: Awaited<ReturnType<typeof getSnapshot>>;\n try {\n snapshot = await getSnapshot(repoRoot);\n } catch (error: unknown) {\n console.warn(normalizeGitSnapshotSkipMessage(error));\n return;\n }\n // Stage 2: events.jsonl append. Schema validation / disk failures here are\n // NOT a \"snapshot capability\" miss — they would corrupt the events.jsonl\n // integrity contract (the fixed 7-event sequence when snapshot is on). We\n // intentionally do NOT swallow these; let them propagate so the exec call\n // fails loudly instead of producing a session that looks successful but\n // has missing or partial events.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"git_snapshot\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: now().toISOString(),\n source: \"git-capability\",\n ...snapshot,\n });\n}\n\nfunction normalizeGitSnapshotSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `git_snapshot skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") {\n return \"git_snapshot skipped: not in a git repository\";\n }\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"git_snapshot skipped: git executable not found\";\n }\n if (msg === \"No commits in repository\") {\n return \"git_snapshot skipped: no commits in repository\";\n }\n return `git_snapshot skipped: ${msg}`;\n}\n\nfunction buildInitialSession(input: {\n id: PrefixedId<\"ses\">;\n command: string;\n args: string[];\n cwd: string;\n workspaceId: PrefixedId<\"ws\">;\n startedAt: string;\n}): Session {\n const cmdline = [input.command, ...input.args].join(\" \");\n return {\n schema_version: \"0.1.0\",\n session: {\n id: input.id,\n label: `basou exec ${cmdline} (${input.startedAt})`,\n task_id: null,\n workspace_id: input.workspaceId,\n source: { kind: \"terminal\", version: \"0.1.0\" },\n started_at: input.startedAt,\n status: \"initialized\",\n working_directory: sanitizeWorkingDirectory(input.cwd, { homedir: homedir() }),\n invocation: {\n command: input.command,\n args: [...input.args],\n exit_code: null,\n },\n related_files: [],\n events_log: \"events.jsonl\",\n },\n };\n}\n\nasync function mutateSessionYaml(\n filePath: string,\n mutator: (session: Session) => void,\n): Promise<void> {\n const raw = await readYamlFile(filePath);\n const parsed = SessionSchema.parse(raw);\n mutator(parsed);\n // Re-validate after mutation to catch drift, then overwrite atomically.\n const validated = SessionSchema.parse(parsed);\n await overwriteYamlFile(filePath, validated);\n}\n\nasync function finalizeSessionAsFailed(\n paths: BasouPaths,\n sessionDir: string,\n sessionId: string,\n appendEvent: AppendEventFn,\n ctx: {\n command: string;\n args: string[];\n cwd: string;\n occurredAt: string;\n signalReceived: NodeJS.Signals | null;\n },\n): Promise<void> {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n command: ctx.command,\n args: ctx.args,\n cwd: ctx.cwd,\n exit_code: null,\n signal: null,\n ...(ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {}),\n duration_ms: 0,\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n from: \"running\",\n to: \"failed\",\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n });\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = \"failed\";\n s.session.ended_at = ctx.occurredAt;\n s.session.invocation.exit_code = null;\n });\n}\n\nasync function resolveRepositoryRootForExec(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou exec'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n readMarkdownFile,\n renderHandoff,\n renderWithMarkers,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n printTaskSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type HandoffGenerateOptions = { verbose?: boolean };\n\nexport type HandoffContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou handoff generate` onto `program`. The `handoff` group is\n * registered up front so future subcommands (e.g. `show`) can slot under\n * the same group without breaking the CLI surface.\n */\nexport function registerHandoffCommand(program: Command): void {\n const handoff = program.command(\"handoff\").description(\"Generate or inspect .basou/handoff.md\");\n\n handoff\n .command(\"generate\")\n .description(\"Regenerate .basou/handoff.md from current session state\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: HandoffGenerateOptions) => {\n await runHandoffGenerate(opts);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. Tests that only care\n * about the happy path or a thrown error should prefer {@link doRunHandoffGenerate}.\n */\nexport async function runHandoffGenerate(\n options: HandoffGenerateOptions,\n ctx: HandoffContext = {},\n): Promise<void> {\n try {\n await doRunHandoffGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `handoff generate`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunHandoffGenerate(\n options: HandoffGenerateOptions,\n ctx: HandoffContext,\n): Promise<void> {\n void options;\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForHandoff(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderHandoff({\n paths,\n nowIso,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n });\n\n const existing = await readMarkdownFile(paths.files.handoff);\n const finalBody = renderWithMarkers(existing, result.body, \"handoff.md\");\n await writeMarkdownFile(paths.files.handoff, finalBody);\n\n console.log(\n `Generated .basou/handoff.md (sessions: ${result.sessionCount}, tasks: ${result.taskCount}, decisions: ${result.decisionCount}, pending approvals: ${result.pendingApprovalsCount})`,\n );\n}\n\nasync function resolveRepositoryRootForHandoff(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou handoff generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { createReadStream, type Dirent } from \"node:fs\";\nimport { readdir, readFile, rm, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport {\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n CLAUDE_IMPORT_SOURCE,\n type ClaudeTranscriptRecord,\n CODEX_IMPORT_SOURCE,\n type CodexRolloutRecord,\n claudeTranscriptToImportPayload,\n codexRolloutToImportPayload,\n enumerateSessionDirs,\n findErrorCode,\n type ImportSessionResult,\n importSessionFromJson,\n type Manifest,\n readManifest,\n readSessionYaml,\n reimportPreservingId,\n resolveRepositoryRoot,\n type Session,\n type SessionImportPayload,\n SessionImportPayloadSchema,\n type SessionSourceKind,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nconst SES_PREFIX = \"ses_\";\nconst SHORT_ID_LEN = 6;\n\n/** Options shared by every `basou import <adapter>` subcommand. */\nexport type ImportOptions = {\n /**\n * Source project roots whose native logs to import. Repeatable on the CLI;\n * empty means \"fall back to the manifest's `import.source_roots`, then the\n * repository root\". Each entry may be absolute or relative to the cwd.\n */\n project?: string[];\n session?: string;\n all?: boolean;\n force?: boolean;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectPath(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport type ImportClaudeCodeOptions = ImportOptions;\nexport type ImportCodexOptions = ImportOptions;\n\nexport type ImportContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /**\n * Root that holds per-project Claude transcript directories. Defaults to\n * `~/.claude/projects`. Injectable for tests so no real home dir is touched.\n */\n claudeProjectsDir?: string;\n /**\n * Root that holds Codex rollout logs (`<year>/<month>/<day>/rollout-*.jsonl`).\n * Defaults to `~/.codex/sessions`. Injectable for tests.\n */\n codexSessionsDir?: string;\n};\n\n/**\n * A single source session ready to be derived and imported. The dedup key\n * (`externalId`) is known up front from discovery; `toPayload` reads and\n * transforms the source log lazily, so a session that is skipped (already\n * imported) is never read.\n */\ntype ImportCandidate = {\n externalId: string;\n /**\n * Absolute path of the source native log. The orchestrator stats this (a\n * cheap, parse-free probe) to decide whether an already-imported source\n * changed, before paying to read + derive it.\n */\n sourcePath: string;\n toPayload: () => Promise<SessionImportPayload | null>;\n};\n\n/**\n * Wire the `basou import` command group onto `program`. Each adapter\n * (`claude-code`, `codex`, ...) is a subcommand sharing the same flags, so\n * future adapters slot in without changing the visible surface.\n */\nexport function registerImportCommand(program: Command): void {\n const importCmd = program\n .command(\"import\")\n .description(\"Import provenance from an external AI tool's native logs\");\n\n importCmd\n .command(\"claude-code\")\n .description(\"Derive Basou sessions from Claude Code native transcripts (~/.claude/projects)\")\n .option(\n \"--project <path>\",\n \"Source project path whose transcripts to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--session <id>\", \"Import a single transcript by its Claude session id\")\n .option(\"--all\", \"Import every transcript found for the project\")\n .option(\n \"--force\",\n \"Re-import sessions already imported: delete and replace them instead of skipping\",\n )\n .option(\"--dry-run\", \"Validate and preview only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ImportClaudeCodeOptions) => {\n await runImportClaudeCode(options);\n });\n\n importCmd\n .command(\"codex\")\n .description(\"Derive Basou sessions from OpenAI Codex native rollout logs (~/.codex/sessions)\")\n .option(\n \"--project <path>\",\n \"Source project path whose rollouts to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--session <id>\", \"Import a single rollout by its Codex session id\")\n .option(\"--all\", \"Import every rollout found for the project\")\n .option(\n \"--force\",\n \"Re-import sessions already imported: delete and replace them instead of skipping\",\n )\n .option(\"--dry-run\", \"Validate and preview only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ImportCodexOptions) => {\n await runImportCodex(options);\n });\n}\n\n/**\n * Programmatic entry for `basou import claude-code`. Owns process exit state;\n * tests should prefer {@link doRunImportClaudeCode}.\n */\nexport async function runImportClaudeCode(\n options: ImportClaudeCodeOptions,\n ctx: ImportContext = {},\n): Promise<void> {\n try {\n await doRunImportClaudeCode(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Programmatic entry for `basou import codex`. Owns process exit state;\n * tests should prefer {@link doRunImportCodex}.\n */\nexport async function runImportCodex(\n options: ImportCodexOptions,\n ctx: ImportContext = {},\n): Promise<void> {\n try {\n await doRunImportCodex(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Resolve the absolute source roots to import from, applying precedence:\n * explicit `--project` flags first (resolved against the cwd), else the\n * manifest's `import.source_roots` (resolved against the repo root), else the\n * repository root alone. The result is de-duplicated, so a root listed twice\n * (or equal to the repo root) is scanned once.\n */\nfunction resolveSourceRoots(args: {\n projectFlags: string[];\n manifest: Manifest;\n repoRoot: string;\n cwd: string;\n}): string[] {\n const { projectFlags, manifest, repoRoot, cwd } = args;\n let resolved: string[];\n if (projectFlags.length > 0) {\n resolved = projectFlags.map((p) => resolve(cwd, p));\n } else {\n const roots = manifest.import?.source_roots;\n resolved =\n roots !== undefined && roots.length > 0 ? roots.map((r) => resolve(repoRoot, r)) : [repoRoot];\n }\n return [...new Set(resolved)];\n}\n\nexport async function doRunImportClaudeCode(\n options: ImportClaudeCodeOptions,\n ctx: ImportContext,\n): Promise<void> {\n assertSelector(options);\n const { repositoryRoot, paths, manifest } = await resolveImportTarget(ctx);\n\n const projectPaths = resolveSourceRoots({\n projectFlags: options.project ?? [],\n manifest,\n repoRoot: repositoryRoot,\n cwd: ctx.cwd ?? process.cwd(),\n });\n const projectsRoot = ctx.claudeProjectsDir ?? join(homedir(), \".claude\", \"projects\");\n\n const files = await selectTranscriptFiles(projectsRoot, projectPaths, options);\n const candidates: ImportCandidate[] = files.map((file) => {\n // The transcript filename is the Claude session id; it is both the dedup\n // key and the source external_id.\n const externalId = basename(file, \".jsonl\");\n return {\n externalId,\n sourcePath: file,\n toPayload: async () => {\n const { records, sizeBytes } = await readJsonlRecords(file);\n return claudeTranscriptToImportPayload(records, {\n workspaceId: manifest.workspace.id,\n externalId,\n sourceSizeBytes: sizeBytes,\n });\n },\n };\n });\n\n await importDerivedSessions(paths, manifest, options, CLAUDE_IMPORT_SOURCE, candidates);\n}\n\nexport async function doRunImportCodex(\n options: ImportCodexOptions,\n ctx: ImportContext,\n): Promise<void> {\n assertSelector(options);\n const { repositoryRoot, paths, manifest } = await resolveImportTarget(ctx);\n\n const projectPaths = resolveSourceRoots({\n projectFlags: options.project ?? [],\n manifest,\n repoRoot: repositoryRoot,\n cwd: ctx.cwd ?? process.cwd(),\n });\n const sessionsRoot = ctx.codexSessionsDir ?? join(homedir(), \".codex\", \"sessions\");\n\n const rollouts = await discoverCodexRollouts(sessionsRoot, projectPaths, options);\n const candidates: ImportCandidate[] = rollouts.map(({ file, externalId }) => ({\n externalId,\n sourcePath: file,\n toPayload: async () => {\n const { records, sizeBytes } = await readJsonlRecords(file);\n return codexRolloutToImportPayload(records as CodexRolloutRecord[], {\n workspaceId: manifest.workspace.id,\n externalId,\n sourceSizeBytes: sizeBytes,\n });\n },\n }));\n\n await importDerivedSessions(paths, manifest, options, CODEX_IMPORT_SOURCE, candidates);\n}\n\nfunction assertSelector(options: ImportOptions): void {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n if (options.session === undefined && options.all !== true) {\n throw new Error(\"Specify --session <id> or --all\");\n }\n}\n\nasync function resolveImportTarget(\n ctx: ImportContext,\n): Promise<{ repositoryRoot: string; paths: BasouPaths; manifest: Manifest }> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForImport(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n return { repositoryRoot, paths, manifest };\n}\n\n/**\n * The vendor-neutral import core: dedup, derive, validate, and write each\n * candidate, then report. Every `basou import <adapter>` funnels its\n * discovered candidates through here, so dedup / `--force` / `--dry-run`\n * semantics stay identical across adapters. Dedup is scoped to `sourceKind`\n * so one adapter never matches (or, under `--force`, deletes) another\n * adapter's session that happens to share an id string.\n */\nasync function importDerivedSessions(\n paths: BasouPaths,\n manifest: Manifest,\n options: ImportOptions,\n sourceKind: SessionSourceKind,\n candidates: ReadonlyArray<ImportCandidate>,\n): Promise<void> {\n const existingByExternalId = await loadExistingByExternalId(paths, sourceKind);\n // Session ids imported earlier in THIS run, so two source files that map to\n // one session id never double-import within a single invocation.\n const seenThisRun = new Set<string>();\n\n const results: ImportSessionResult[] = [];\n const counts: ImportCounts = {\n skippedNoAction: 0,\n skippedExisting: 0,\n replaced: 0,\n reimported: 0,\n skippedLegacy: 0,\n skippedDecreased: 0,\n skippedDuplicate: 0,\n skippedUnverifiable: 0,\n };\n let sanitizedPaths = 0;\n\n // Parse + version-gate a derived payload before it touches disk. Returns null\n // when the source carried no provenance worth importing (the caller skips).\n const validate = (payload: SessionImportPayload | null): SessionImportPayload | null => {\n if (payload === null) return null;\n const parsed = SessionImportPayloadSchema.safeParse(payload);\n if (!parsed.success) {\n throw new Error(\"Invalid import payload\", { cause: parsed.error });\n }\n if (parsed.data.schema_version !== \"0.1.0\") {\n throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);\n }\n return parsed.data;\n };\n\n for (const { externalId, sourcePath, toPayload } of candidates) {\n if (seenThisRun.has(externalId)) {\n counts.skippedExisting++;\n continue;\n }\n const priors = existingByExternalId.get(externalId) ?? [];\n\n // Already imported in a prior run. Default is to skip (idempotent), but a\n // source whose native log GREW is re-imported in place, and --force\n // deletes + replaces regardless.\n if (priors.length > 0 && options.force !== true) {\n const prior = await classifyReimport(priors, sourcePath, externalId, counts);\n if (prior === null) continue; // skip recorded by classifyReimport\n const payload = validate(await toPayload());\n if (payload === null) {\n counts.skippedNoAction++;\n continue;\n }\n // Re-confirm growth against the size ACTUALLY read (the decision above used\n // a cheap pre-read stat): if the source was truncated / rotated between the\n // stat and the read, the smaller buffer must not be re-imported as a grow.\n const readSize = payload.session.source.source_size_bytes;\n if (\n prior.sourceSizeBytes !== undefined &&\n readSize !== undefined &&\n readSize <= prior.sourceSizeBytes\n ) {\n console.error(\n `Import: ${externalId} source changed during read (now ${readSize} <= ${prior.sourceSizeBytes} bytes); re-import skipped`,\n );\n counts.skippedDecreased++;\n continue;\n }\n const outcome = await reimportPreservingId(paths, manifest, prior.sessionId, payload, {\n dryRun: options.dryRun === true,\n });\n if (outcome.status === \"skipped\") {\n const detail =\n outcome.reason === \"prior_events_unreadable\"\n ? \"prior events.jsonl has unreadable lines\"\n : outcome.reason === \"prior_chain_broken\"\n ? \"prior events.jsonl failed hash-chain verification (run 'basou verify')\"\n : \"source changed in a non-append way (derived events would be dropped)\";\n console.error(`Import: ${externalId} ${detail}; re-import skipped`);\n // The source GREW but a safe in-place re-import was refused: this is NOT\n // a benign no-op. Track it separately so freshness probes can flag that\n // captured state is provably behind (vs `skippedNoAction`, which is a\n // source with simply nothing to derive).\n counts.skippedUnverifiable++;\n continue;\n }\n counts.reimported++;\n seenThisRun.add(externalId);\n continue;\n }\n\n const payload = validate(await toPayload());\n if (payload === null) {\n counts.skippedNoAction++;\n continue;\n }\n\n // --force replace: delete the prior session(s) for this external id, but\n // only once the fresh payload is known good, so a failed re-derivation\n // never destroys the existing import. Skipped under --dry-run.\n if (priors.length > 0 && options.force === true) {\n if (options.dryRun !== true) {\n for (const { sessionId } of priors) {\n await rm(join(paths.sessions, sessionId), { recursive: true, force: true });\n }\n }\n counts.replaced++;\n }\n\n const result = await importSessionFromJson(paths, manifest, payload, {\n dryRun: options.dryRun === true,\n });\n results.push(result);\n seenThisRun.add(externalId);\n sanitizedPaths +=\n result.pathSanitizeReport.relatedFiles +\n (result.pathSanitizeReport.workingDirectoryRewritten ? 1 : 0);\n }\n\n if (sanitizedPaths > 0) {\n console.error(`Imported sessions: ${sanitizedPaths} path(s) sanitized`);\n }\n\n printImportResult(options, results, counts);\n}\n\n/** Mutable tally of every import disposition, surfaced by {@link printImportResult}. */\ntype ImportCounts = {\n skippedNoAction: number;\n /** Already imported and unchanged (or a duplicate-within-this-run). */\n skippedExisting: number;\n /** Deleted + replaced under --force. */\n replaced: number;\n /** Re-imported in place because the source grew. */\n reimported: number;\n /** Already imported but with no recorded size (pre-size-tracking import); not re-imported. */\n skippedLegacy: number;\n /** Source shrank since import (truncated / rotated); needs --force to replace. */\n skippedDecreased: number;\n /** More than one prior session for one external id (anomalous); needs --force. */\n skippedDuplicate: number;\n /**\n * Source grew but a safe in-place re-import was refused — a broken prior hash\n * chain, unreadable prior events, or a non-append change that would drop\n * derived ids. Captured state is provably behind; needs `basou verify` then a\n * `--force` re-import. Distinct from {@link skippedNoAction} (nothing to derive).\n */\n skippedUnverifiable: number;\n};\n\n/**\n * Decide whether an already-imported external id should be re-imported in place\n * because its source grew. Returns the single prior import to re-import into, or\n * `null` (recording the right skip count) when it must be left alone:\n * unchanged / shrank / legacy (no recorded size) / anomalously duplicated. The\n * size probe is a parse-free `stat`, so unchanged sources are dismissed cheaply.\n */\nasync function classifyReimport(\n priors: PriorImport[],\n sourcePath: string,\n externalId: string,\n counts: ImportCounts,\n): Promise<PriorImport | null> {\n if (priors.length > 1) {\n // Anomalous: a scoped re-import cannot pick which id to preserve, and\n // delete+recreate would orphan any linked_events. Leave it to --force.\n console.error(\n `Import: ${externalId} has ${priors.length} prior sessions; re-import skipped (use --force)`,\n );\n counts.skippedDuplicate++;\n return null;\n }\n const prior = priors[0];\n if (prior === undefined) {\n counts.skippedExisting++;\n return null;\n }\n const currentSize = await statSize(sourcePath);\n if (currentSize === undefined) {\n // Source vanished between discovery and now; nothing to re-import.\n counts.skippedExisting++;\n return null;\n }\n if (prior.sourceSizeBytes === undefined) {\n // Legacy import (no recorded size baseline): never auto-re-import; the size\n // populates on the next --force / fresh import.\n counts.skippedLegacy++;\n return null;\n }\n if (currentSize === prior.sourceSizeBytes) {\n counts.skippedExisting++; // unchanged\n return null;\n }\n if (currentSize < prior.sourceSizeBytes) {\n // Truncated / rotated: do NOT auto-replace derived provenance; --force only.\n console.error(\n `Import: ${externalId} source shrank (${currentSize} < ${prior.sourceSizeBytes} bytes); re-import skipped (use --force to replace)`,\n );\n counts.skippedDecreased++;\n return null;\n }\n return prior; // grew => re-import preserving id\n}\n\n/**\n * Encode an absolute project path into Claude Code's per-project directory\n * name. Claude Code replaces path separators with `-`, so\n * `/Users/x/projects/foo` becomes `-Users-x-projects-foo`. Best-effort for\n * the common case; paths with characters the vendor encodes differently may\n * need an explicit `--project`-derived directory in a later revision.\n */\nfunction encodeProjectDir(projectPath: string): string {\n return projectPath.replaceAll(\"/\", \"-\");\n}\n\n/**\n * Map of source external_id -> Basou session id(s) already present in the\n * workspace for the given `sourceKind`, so a re-import can skip (default) or,\n * under --force, delete and replace the existing session. Scoping to one\n * source kind keeps each adapter's id namespace separate: a Codex import must\n * never dedup against, or delete, a Claude-derived session that happens to\n * share an id string. Recognises both the structured `source.external_id`\n * (current imports) and the `claude-code import <id>` label form (sessions\n * imported before external_id existed), so existing dogfood imports are\n * matched either way. Unreadable sessions are skipped.\n */\n/**\n * A prior Basou session for an external id, with the source byte size recorded\n * at its last import (absent for legacy imports made before the field existed).\n * The size lets a re-import detect that an append-only source GREW.\n */\ntype PriorImport = { sessionId: string; sourceSizeBytes?: number };\n\nasync function loadExistingByExternalId(\n paths: BasouPaths,\n sourceKind: SessionSourceKind,\n): Promise<Map<string, PriorImport[]>> {\n const byExternalId = new Map<string, PriorImport[]>();\n const add = (externalId: string, prior: PriorImport): void => {\n const list = byExternalId.get(externalId);\n if (list === undefined) byExternalId.set(externalId, [prior]);\n else list.push(prior);\n };\n let sessionIds: string[];\n try {\n sessionIds = await enumerateSessionDirs(paths);\n } catch {\n return byExternalId;\n }\n for (const sessionId of sessionIds) {\n let session: Session;\n try {\n session = await readSessionYaml(paths, sessionId);\n } catch {\n continue;\n }\n if (session.session.source.kind !== sourceKind) continue;\n const sourceSizeBytes = session.session.source.source_size_bytes;\n // Build once; omit the size key entirely when absent (legacy import) so the\n // optional property stays absent rather than explicitly undefined.\n const prior: PriorImport =\n sourceSizeBytes !== undefined ? { sessionId, sourceSizeBytes } : { sessionId };\n const ext = session.session.source.external_id;\n if (typeof ext === \"string\" && ext.length > 0) {\n add(ext, prior);\n continue;\n }\n const label = session.session.label;\n const match = typeof label === \"string\" ? label.match(/^claude-code import (\\S+)$/) : null;\n if (match?.[1] !== undefined) add(match[1], prior);\n }\n return byExternalId;\n}\n\n/**\n * Select the Claude transcript files to import across one or more source roots.\n * Each root maps to a per-project transcript directory under `projectsRoot`.\n * With `--session`, every root is probed and only existing matches are returned\n * (an error is raised only if no root holds that transcript). With `--all`, the\n * `.jsonl` files of every root are unioned; a root whose directory is absent\n * contributes nothing. The missing-directory error is raised only when NO root\n * has a transcript directory, so refresh classifies \"nothing anywhere\" as a\n * skip rather than a failure.\n */\nasync function selectTranscriptFiles(\n projectsRoot: string,\n projectPaths: string[],\n options: ImportClaudeCodeOptions,\n): Promise<string[]> {\n if (options.session !== undefined) {\n const matches: string[] = [];\n for (const projectPath of projectPaths) {\n const file = join(projectsRoot, encodeProjectDir(projectPath), `${options.session}.jsonl`);\n if (await pathExists(file)) matches.push(file);\n }\n if (matches.length === 0) {\n throw new Error(\"Claude transcript not found for session id in project\");\n }\n return [...new Set(matches)];\n }\n const files: string[] = [];\n let anyDirFound = false;\n for (const projectPath of projectPaths) {\n const transcriptDir = join(projectsRoot, encodeProjectDir(projectPath));\n let entries: string[];\n try {\n entries = await readdir(transcriptDir);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) continue; // this root has no transcripts; try the next\n throw new Error(\"Failed to read Claude transcript directory\", { cause: error });\n }\n anyDirFound = true;\n for (const name of entries) {\n if (name.endsWith(\".jsonl\")) files.push(join(transcriptDir, name));\n }\n }\n if (!anyDirFound) {\n throw new Error(\"Claude transcript directory not found for project\");\n }\n return [...new Set(files)].sort();\n}\n\n/** Whether `file` exists (ENOENT => false; any other error propagates). */\nasync function pathExists(file: string): Promise<boolean> {\n try {\n await stat(file);\n return true;\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) return false;\n throw error;\n }\n}\n\n/** The file's byte size, or undefined if it vanished (ENOENT); other errors propagate. */\nasync function statSize(file: string): Promise<number | undefined> {\n try {\n return (await stat(file)).size;\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) return undefined;\n throw error;\n }\n}\n\n/**\n * Discover the Codex rollouts that belong to any of `projectPaths`. Codex\n * stores rollouts under date directories (not per-project like Claude), so the\n * whole tree is walked once and each rollout's `session_meta.cwd` is matched\n * against the set of requested roots. The exact-match is also the safety\n * boundary: only sessions started in a requested root are ever imported.\n * `--session` narrows to a single rollout by its Codex session id within those\n * roots; a session id that matches no rollout is an error, mirroring how the\n * Claude path fails on a missing `--session` transcript rather than reporting a\n * silent success.\n */\nasync function discoverCodexRollouts(\n sessionsRoot: string,\n projectPaths: string[],\n options: ImportCodexOptions,\n): Promise<Array<{ file: string; externalId: string }>> {\n const projectSet = new Set(projectPaths);\n const files = await findRolloutFiles(sessionsRoot);\n const matched: Array<{ file: string; externalId: string }> = [];\n for (const file of files) {\n const meta = await readRolloutMeta(file);\n if (meta === undefined) continue;\n if (!projectSet.has(meta.cwd)) continue;\n if (options.session !== undefined && meta.id !== options.session) continue;\n matched.push({ file, externalId: meta.id });\n }\n if (options.session !== undefined && matched.length === 0) {\n throw new Error(\"Codex rollout not found for session id in project\");\n }\n return matched;\n}\n\n/** Recursively collect every `rollout-*.jsonl` under the Codex sessions root. */\nasync function findRolloutFiles(sessionsRoot: string): Promise<string[]> {\n const found: string[] = [];\n const walk = async (dir: string, isRoot: boolean): Promise<void> => {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n if (isRoot) {\n throw new Error(\"Codex sessions directory not found\", { cause: error });\n }\n return; // a subdir vanished mid-walk; ignore\n }\n throw new Error(\"Failed to read Codex sessions directory\", { cause: error });\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full, false);\n } else if (\n entry.isFile() &&\n entry.name.startsWith(\"rollout-\") &&\n entry.name.endsWith(\".jsonl\")\n ) {\n found.push(full);\n }\n }\n };\n await walk(sessionsRoot, true);\n return found.sort();\n}\n\n/**\n * Read just the `session_meta` (first record) of a rollout to learn its\n * project cwd and session id, without parsing the whole — usually large — log.\n * Returns `undefined` for any file whose first record is not a usable\n * `session_meta`, so the caller can skip it.\n */\nasync function readRolloutMeta(file: string): Promise<{ id: string; cwd: string } | undefined> {\n const firstLine = await readFirstLine(file);\n if (firstLine === undefined) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(firstLine);\n } catch {\n return undefined;\n }\n if (!isObject(parsed) || parsed.type !== \"session_meta\") return undefined;\n const payload = isObject(parsed.payload) ? parsed.payload : undefined;\n if (payload === undefined) return undefined;\n const id = payload.id;\n const cwd = payload.cwd;\n if (typeof id !== \"string\" || id.length === 0) return undefined;\n if (typeof cwd !== \"string\" || cwd.length === 0) return undefined;\n return { id, cwd };\n}\n\n/** Read the first non-empty line of a file, streaming so large files are cheap. */\nasync function readFirstLine(file: string): Promise<string | undefined> {\n const stream = createReadStream(file, { encoding: \"utf8\" });\n const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });\n try {\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed.length > 0) return trimmed;\n }\n return undefined;\n } catch {\n return undefined;\n } finally {\n rl.close();\n stream.destroy();\n }\n}\n\n/**\n * Read a JSONL native log into an array of records, plus the file's exact byte\n * size. A malformed line is skipped rather than failing the whole file, so\n * partial native logs still yield best-effort provenance. The byte size is read\n * from the SAME buffer that produced the records (an immutable snapshot), so the\n * size persisted as `source.source_size_bytes` always matches the imported\n * content even if the file is being appended to concurrently.\n */\nasync function readJsonlRecords(\n file: string,\n): Promise<{ records: ClaudeTranscriptRecord[]; sizeBytes: number }> {\n let buffer: Buffer;\n try {\n buffer = await readFile(file);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Source log not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Source log path is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read source log\", { cause: error });\n }\n\n const records: ClaudeTranscriptRecord[] = [];\n for (const line of buffer.toString(\"utf8\").split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (isObject(parsed)) {\n records.push(parsed);\n }\n } catch {\n // A malformed line is skipped rather than failing the whole file.\n }\n }\n return { records, sizeBytes: buffer.length };\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction printImportResult(\n options: ImportOptions,\n results: ImportSessionResult[],\n counts: ImportCounts,\n): void {\n const isDry = options.dryRun === true;\n const eventTotal = results.reduce((sum, r) => sum + r.eventCount, 0);\n const {\n skippedNoAction,\n skippedExisting,\n replaced,\n reimported,\n skippedLegacy,\n skippedDecreased,\n skippedDuplicate,\n skippedUnverifiable,\n } = counts;\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n imported: results.map((r) => ({\n session_id: r.sessionId,\n event_count: r.eventCount,\n status: r.finalStatus,\n source: { kind: r.finalSourceKind, version: \"0.1.0\" },\n })),\n imported_count: results.length,\n replaced_count: replaced,\n reimported_count: reimported,\n skipped_no_action: skippedNoAction,\n skipped_already_imported: skippedExisting,\n skipped_legacy_untracked: skippedLegacy,\n skipped_decreased: skippedDecreased,\n skipped_duplicate: skippedDuplicate,\n skipped_unverifiable: skippedUnverifiable,\n event_total: eventTotal,\n dry_run: isDry,\n }),\n );\n return;\n }\n\n const skipParts: string[] = [];\n if (skippedNoAction > 0) skipParts.push(`${skippedNoAction} with no actions`);\n if (skippedExisting > 0) skipParts.push(`${skippedExisting} already imported`);\n if (skippedLegacy > 0) skipParts.push(`${skippedLegacy} legacy (untracked size)`);\n if (skippedDecreased > 0) skipParts.push(`${skippedDecreased} shrank`);\n if (skippedDuplicate > 0) skipParts.push(`${skippedDuplicate} duplicated`);\n if (skippedUnverifiable > 0)\n skipParts.push(`${skippedUnverifiable} unverifiable (run 'basou verify')`);\n const skipSuffix = skipParts.length > 0 ? `; skipped ${skipParts.join(\", \")}` : \"\";\n const eventsPart =\n replaced > 0 ? `${eventTotal} events, ${replaced} replaced` : `${eventTotal} events`;\n\n if (isDry) {\n const parts: string[] = [];\n if (results.length > 0) parts.push(`import ${results.length} session(s) (${eventsPart})`);\n if (reimported > 0) parts.push(`re-import ${reimported} changed session(s)`);\n const head = parts.length > 0 ? `Dry run: would ${parts.join(\", \")}` : \"Dry run: no changes\";\n console.log(`${head}${skipSuffix}`);\n return;\n }\n\n if (results.length === 0 && reimported === 0) {\n console.log(\n skipParts.length > 0\n ? `No new sessions imported (skipped ${skipParts.join(\", \")})`\n : \"No transcripts found to import\",\n );\n return;\n }\n\n const segments: string[] = [];\n if (results.length > 0) {\n const single =\n results.length === 1 && results[0] !== undefined ? ` (${shortId(results[0].sessionId)})` : \"\";\n segments.push(`Imported ${results.length} session(s)${single} (${eventsPart})`);\n }\n if (reimported > 0) {\n segments.push(\n `${results.length > 0 ? \"re-imported\" : \"Re-imported\"} ${reimported} changed session(s)`,\n );\n }\n console.log(`${segments.join(\", \")}${skipSuffix}`);\n}\n\nfunction shortId(id: string): string {\n if (id.startsWith(SES_PREFIX)) {\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + SHORT_ID_LEN);\n }\n return id.slice(0, SHORT_ID_LEN);\n}\n\nasync function resolveRepositoryRootForImport(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou import'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { basename, relative, resolve } from \"node:path\";\nimport {\n appendBasouGitignore,\n createManifest,\n ensureBasouDirectory,\n resolveRepositoryRoot,\n tryRemoteUrl,\n writeManifest,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { extractCauseLabel, isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type InitOptions = {\n name?: string;\n projectName?: string;\n projectDescription?: string;\n repoUrl?: string;\n /**\n * Import source roots (repeatable). Each may be absolute or relative to the\n * invocation cwd; persisted as a path relative to the repository root under\n * `import.source_roots`, so one `.basou/` can aggregate sibling repos.\n */\n sourceRoot?: string[];\n /** Write a `.basou/` full-exclude .gitignore block instead of the default ignore+commit block. */\n localOnly?: boolean;\n force?: boolean;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectValue(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport type InitContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/**\n * Register `basou init` on a commander program. The `--repo-url \"\"` (empty\n * string) form is the documented way to set `project.repository_url` to\n * `null` explicitly; omitting `--repo-url` falls back to\n * `git config --local remote.origin.url` and finally to omission.\n */\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Initialize a Basou workspace at the current Git repository root\")\n .option(\"--name <name>\", \"Workspace name (defaults to the repository directory name)\")\n .option(\"--project-name <name>\", \"Project display name\")\n .option(\"--project-description <description>\", \"Project description\")\n .option(\n \"--repo-url <url>\",\n \"Repository URL (defaults to git remote.origin.url; pass empty string for null)\",\n )\n .option(\n \"--source-root <path>\",\n \"Extra import source root, relative to the repo root (repeatable; aggregates sibling repos into this workspace)\",\n collectValue,\n [],\n )\n .option(\n \"--local-only\",\n \"Write a .basou/ full-exclude .gitignore block (keep the trail out of version control) instead of the default ignore+commit block\",\n )\n .option(\"-f, --force\", \"Overwrite an existing manifest\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: InitOptions) => {\n await runInit(options);\n });\n}\n\n/**\n * Programmatic entry that mutates process state (`exitCode`, stderr).\n * Exported for tests, but tests should prefer {@link doRunInit} so they are\n * not coupled to process global state.\n */\nexport async function runInit(options: InitOptions, ctx: InitContext = {}): Promise<void> {\n try {\n await doRunInit(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolves inputs, calls core APIs, prints the success line.\n * On any failure throws an Error whose `message` is pathless and whose\n * `cause` MAY contain a native fs error. Exported for tests so they can\n * assert on thrown errors without touching `process.exitCode`.\n */\nexport async function doRunInit(options: InitOptions, ctx: InitContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForInit(cwd);\n const workspaceName = options.name ?? basename(repositoryRoot);\n\n // --repo-url > git config --local remote.origin.url > omit\n // --repo-url \"\" => explicit null\n let repositoryUrl: string | null | undefined;\n if (options.repoUrl !== undefined) {\n repositoryUrl = options.repoUrl === \"\" ? null : options.repoUrl;\n } else {\n repositoryUrl = await tryRemoteUrl(repositoryRoot);\n }\n\n // Normalize each --source-root to a repo-root-relative path. A root that is\n // the repo root itself becomes \".\". Stored relative so the committed manifest\n // carries no absolute machine paths.\n const sourceRoots = (options.sourceRoot ?? []).map((p) => {\n const rel = relative(repositoryRoot, resolve(cwd, p));\n return rel === \"\" ? \".\" : rel;\n });\n\n const paths = await ensureBasouDirectory(repositoryRoot);\n const manifest = createManifest({\n workspaceName,\n ...(options.projectName !== undefined ? { projectName: options.projectName } : {}),\n ...(options.projectDescription !== undefined\n ? { projectDescription: options.projectDescription }\n : {}),\n ...(repositoryUrl !== undefined ? { repositoryUrl } : {}),\n ...(sourceRoots.length > 0 ? { sourceRoots } : {}),\n });\n\n await writeManifest(paths, manifest, { force: options.force === true });\n\n // .gitignore is best-effort: init succeeds even if this step fails.\n // The \"safe to run on an existing Git repo\" completion contract holds\n // even when manifest writes but .gitignore cannot (e.g. permission\n // denied) -- the core feature set still works.\n try {\n await appendBasouGitignore(repositoryRoot, { localOnly: options.localOnly === true });\n } catch (error: unknown) {\n renderGitignoreWarning(error, isVerbose(options));\n }\n\n console.log(`Initialized Basou workspace: ${manifest.workspace.id}`);\n}\n\n/**\n * Render a non-fatal warning when `.gitignore` cannot be updated. Mirrors\n * the pathless contract enforced by {@link renderCliError} — never prints\n * `error.cause.message` because native fs errors embed the absolute path\n * in it.\n */\nfunction renderGitignoreWarning(error: unknown, verbose: boolean): void {\n const baseMessage = error instanceof Error ? error.message : String(error);\n // The fallback hint is intentionally `dist`-only-portable: it does not\n // reference any in-repo doc path, since the CLI is published\n // independently of `docs/`.\n console.error(\n `Warning: Could not update .gitignore (${baseMessage}). Add Basou's default .gitignore block manually.`,\n );\n if (verbose && error instanceof Error) {\n const label = extractCauseLabel(error);\n if (label !== undefined) console.error(`Caused by: ${label}`);\n }\n}\n\n/**\n * Wrap the core git capability so the CLI surfaces the command-specific\n * \"Run 'git init' first, then re-run 'basou init'.\" suffix while the\n * capability layer remains command-agnostic.\n */\nasync function resolveRepositoryRootForInit(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou init'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n renderOrientation,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n printTaskSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { probeStaleness } from \"../lib/provenance-actions.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\n\nexport type OrientOptions = { verbose?: boolean; quiet?: boolean };\n\nexport type OrientContext = ImportContext & {\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou orient` onto `program`. A read-first \"where am I\" command: it\n * renders the current position, writes `.basou/orientation.md`, and prints the\n * body to stdout by default. It writes NO provenance — a read-only dry-run probe\n * checks for uncaptured native work so the \"これは最新か\" verdict is honest (use\n * `basou refresh` to actually re-import). `--verbose` appends raw freshness\n * telemetry under the verdict.\n */\nexport function registerOrientCommand(program: Command): void {\n program\n .command(\"orient\")\n .description(\"Show the workspace's current position (also writes .basou/orientation.md)\")\n .option(\"-q, --quiet\", \"Write the file without printing the body\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: OrientOptions) => {\n await runOrient(opts);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. Tests that only care about\n * the happy path or a thrown error should prefer {@link doRunOrient}.\n */\nexport async function runOrient(options: OrientOptions, ctx: OrientContext = {}): Promise<void> {\n try {\n await doRunOrient(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `orient`. Throws on any failure with a pathless message;\n * native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunOrient(options: OrientOptions, ctx: OrientContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"orient\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n\n // Read-only dry-run probe (writes nothing) so the freshness verdict reflects\n // whether uncaptured native work exists, not just the last-captured state.\n const probeCtx: ImportContext = { cwd: repositoryRoot };\n if (ctx.claudeProjectsDir !== undefined) probeCtx.claudeProjectsDir = ctx.claudeProjectsDir;\n if (ctx.codexSessionsDir !== undefined) probeCtx.codexSessionsDir = ctx.codexSessionsDir;\n const staleness = await probeStaleness({ ctx: probeCtx, paths, nowIso });\n\n const result = await renderOrientation({\n paths,\n nowIso,\n staleness,\n verbose: options.verbose === true,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n });\n\n // orientation.md is a transient, gitignored snapshot: overwrite the whole\n // file (no GENERATED markers — there is no hand-edited region to preserve).\n await writeMarkdownFile(paths.files.orientation, `${result.body}\\n`);\n\n if (options.quiet === true) {\n console.log(\n `Generated .basou/orientation.md (sessions: ${result.sessionCount}, in-flight tasks: ${result.inFlightTaskCount}, pending approvals: ${result.pendingApprovalsCount}, suspect: ${result.suspectCount})`,\n );\n } else {\n console.log(result.body);\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n type BasouPaths,\n readMarkdownFile,\n renderDecisions,\n renderHandoff,\n renderOrientation,\n renderWithMarkers,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport {\n doRunImportClaudeCode,\n doRunImportCodex,\n type ImportContext,\n type ImportOptions,\n} from \"../commands/import.js\";\n\n/**\n * Shared provenance actions reused by both `basou refresh` (one-shot CLI) and\n * the `basou view` server's action endpoints, so the two stay behaviourally\n * identical. These wrap the existing import commands and markdown renderers;\n * they own no process state and print nothing of their own.\n */\n\n/** Which native-log adapter an import outcome came from. */\nexport type ImportAdapter = \"claude-code\" | \"codex\";\n\n/** Result of running one adapter's import, or a note that it was skipped. */\nexport type ImportOutcome =\n | {\n adapter: ImportAdapter;\n status: \"ran\";\n importedCount: number;\n replacedCount: number;\n /** Sessions re-imported in place because their source grew. */\n reimportedCount: number;\n skippedNoAction: number;\n skippedAlreadyImported: number;\n /** Already imported but with no recorded source size (pre-size-tracking); not re-imported. */\n skippedLegacyUntracked: number;\n /** Source grew but a safe re-import was refused (broken chain / unreadable / non-append); captured state is provably behind. */\n skippedUnverifiable: number;\n eventTotal: number;\n dryRun: boolean;\n }\n | { adapter: ImportAdapter; status: \"skipped\"; reason: string };\n\n/** Counts from regenerating handoff.md / decisions.md, or a skip note. */\nexport type GenerateOutcome<TExtra> =\n | ({ status: \"generated\" } & TExtra)\n | { status: \"skipped\"; reason: string };\n\nexport type HandoffCounts = {\n sessionCount: number;\n taskCount: number;\n decisionCount: number;\n pendingApprovalsCount: number;\n};\n\nexport type OrientationCounts = {\n sessionCount: number;\n inFlightTaskCount: number;\n pendingApprovalsCount: number;\n suspectCount: number;\n};\n\n/** Structured result of {@link refreshAll}. */\nexport type RefreshResult = {\n claudeCode: ImportOutcome;\n codex: ImportOutcome;\n handoff: GenerateOutcome<HandoffCounts>;\n decisions: GenerateOutcome<{ decisionCount: number }>;\n orientation: GenerateOutcome<OrientationCounts>;\n dryRun: boolean;\n};\n\nexport type RefreshActionOptions = {\n project?: string[];\n force?: boolean;\n dryRun?: boolean;\n};\n\n/**\n * Run `fn` (an import command invoked with `json: true`) while capturing its\n * console output, then return the single machine-readable JSON result line.\n * The import commands print their result as one JSON object on stdout; that\n * line is the result contract. `console` is always restored, even on throw.\n */\nasync function captureImportJson(fn: () => Promise<void>): Promise<Record<string, unknown>> {\n const stdout: string[] = [];\n const originalLog = console.log;\n const originalError = console.error;\n console.log = ((...args: unknown[]) => {\n stdout.push(args.map((a) => String(a)).join(\" \"));\n }) as typeof console.log;\n // The import path writes an informational \"N path(s) sanitized\" line to\n // stderr; swallow it so refresh / the view server stay quiet.\n console.error = (() => {}) as typeof console.error;\n try {\n await fn();\n } finally {\n console.log = originalLog;\n console.error = originalError;\n }\n for (let i = stdout.length - 1; i >= 0; i--) {\n const line = stdout[i];\n if (line === undefined) continue;\n try {\n const parsed: unknown = JSON.parse(line);\n if (parsed !== null && typeof parsed === \"object\" && \"imported_count\" in parsed) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Not the JSON result line; keep scanning earlier lines.\n }\n }\n throw new Error(\"Import produced no parseable result\");\n}\n\nfunction readCount(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/**\n * A source-log directory that does not exist for the requested project is a\n * normal \"this adapter has nothing here\" condition for refresh, not a failure.\n */\nfunction isMissingSourceDir(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.message === \"Claude transcript directory not found for project\" ||\n error.message === \"Codex sessions directory not found\"\n );\n}\n\n/** Run one adapter import as a best-effort action, classifying a missing source dir as skipped. */\nasync function runImport(adapter: ImportAdapter, fn: () => Promise<void>): Promise<ImportOutcome> {\n try {\n const json = await captureImportJson(fn);\n return {\n adapter,\n status: \"ran\",\n importedCount: readCount(json.imported_count),\n replacedCount: readCount(json.replaced_count),\n reimportedCount: readCount(json.reimported_count),\n skippedNoAction: readCount(json.skipped_no_action),\n skippedAlreadyImported: readCount(json.skipped_already_imported),\n skippedLegacyUntracked: readCount(json.skipped_legacy_untracked),\n skippedUnverifiable: readCount(json.skipped_unverifiable),\n eventTotal: readCount(json.event_total),\n dryRun: json.dry_run === true,\n };\n } catch (error: unknown) {\n if (isMissingSourceDir(error)) {\n return { adapter, status: \"skipped\", reason: \"no source logs for this project\" };\n }\n throw error;\n }\n}\n\nfunction importOptions(options: RefreshActionOptions): ImportOptions {\n return {\n all: true,\n json: true,\n ...(options.project !== undefined ? { project: options.project } : {}),\n ...(options.force === true ? { force: true } : {}),\n ...(options.dryRun === true ? { dryRun: true } : {}),\n };\n}\n\n/** Import Claude Code transcripts for the project (best-effort). */\nexport function importClaudeCode(\n options: RefreshActionOptions,\n ctx: ImportContext,\n): Promise<ImportOutcome> {\n return runImport(\"claude-code\", () => doRunImportClaudeCode(importOptions(options), ctx));\n}\n\n/** Import Codex rollouts for the project (best-effort). */\nexport function importCodex(\n options: RefreshActionOptions,\n ctx: ImportContext,\n): Promise<ImportOutcome> {\n return runImport(\"codex\", () => doRunImportCodex(importOptions(options), ctx));\n}\n\ntype RenderCallbacks = Parameters<typeof renderHandoff>[0];\n\n/** Regenerate `.basou/handoff.md` and return the renderer's counts. */\nexport async function regenerateHandoff(\n paths: BasouPaths,\n nowIso: string,\n callbacks?: Omit<RenderCallbacks, \"paths\" | \"nowIso\">,\n): Promise<HandoffCounts> {\n const result = await renderHandoff({ paths, nowIso, ...callbacks });\n const existing = await readMarkdownFile(paths.files.handoff);\n await writeMarkdownFile(\n paths.files.handoff,\n renderWithMarkers(existing, result.body, \"handoff.md\"),\n );\n return {\n sessionCount: result.sessionCount,\n taskCount: result.taskCount,\n decisionCount: result.decisionCount,\n pendingApprovalsCount: result.pendingApprovalsCount,\n };\n}\n\n/** Regenerate `.basou/decisions.md` and return the decision count. */\nexport async function regenerateDecisions(\n paths: BasouPaths,\n nowIso: string,\n callbacks?: Omit<Parameters<typeof renderDecisions>[0], \"paths\" | \"nowIso\">,\n): Promise<{ decisionCount: number }> {\n const result = await renderDecisions({ paths, nowIso, ...callbacks });\n const existing = await readMarkdownFile(paths.files.decisions);\n await writeMarkdownFile(\n paths.files.decisions,\n renderWithMarkers(existing, result.body, \"decisions.md\"),\n );\n return { decisionCount: result.decisionCount };\n}\n\n/**\n * Regenerate `.basou/orientation.md` and return the orientation counts. Unlike\n * handoff/decisions this is a transient, gitignored snapshot, so the whole file\n * is overwritten (no GENERATED markers to preserve a hand-edited region).\n */\nexport async function regenerateOrientation(\n paths: BasouPaths,\n nowIso: string,\n callbacks?: Omit<Parameters<typeof renderOrientation>[0], \"paths\" | \"nowIso\">,\n): Promise<OrientationCounts> {\n const result = await renderOrientation({ paths, nowIso, ...callbacks });\n await writeMarkdownFile(paths.files.orientation, `${result.body}\\n`);\n return {\n sessionCount: result.sessionCount,\n inFlightTaskCount: result.inFlightTaskCount,\n pendingApprovalsCount: result.pendingApprovalsCount,\n suspectCount: result.suspectCount,\n };\n}\n\n/**\n * The shared refresh pipeline: import both adapters (best-effort) for the\n * project, then regenerate handoff + decisions. Under `dryRun`, imports run in\n * preview mode and the markdown files are left untouched. The caller resolves\n * `paths` / `nowIso` and supplies the import `ctx`.\n */\nexport async function refreshAll(args: {\n options: RefreshActionOptions;\n ctx: ImportContext;\n paths: BasouPaths;\n nowIso: string;\n}): Promise<RefreshResult> {\n const { options, ctx, paths, nowIso } = args;\n const dryRun = options.dryRun === true;\n\n const claudeCode = await importClaudeCode(options, ctx);\n const codex = await importCodex(options, ctx);\n\n if (dryRun) {\n const skipped = { status: \"skipped\" as const, reason: \"dry-run\" };\n return {\n claudeCode,\n codex,\n handoff: skipped,\n decisions: skipped,\n orientation: skipped,\n dryRun,\n };\n }\n\n const handoffCounts = await regenerateHandoff(paths, nowIso);\n const decisionCounts = await regenerateDecisions(paths, nowIso);\n // A full refresh just imported every root, so the snapshot is current — record\n // a zero staleness so the file's \"これは最新か\" verdict reads as up to date\n // instead of \"run refresh to check\". It still carries the unverifiable count\n // the import just hit: a session that grew but failed to re-import is behind\n // even right after a refresh, so the verdict must not falsely read \"current\".\n // A `--project`-scoped refresh only touched some roots, so leave staleness\n // unset (verdict: \"cannot confirm\") rather than claim the whole workspace is\n // current.\n const scoped = options.project !== undefined && options.project.length > 0;\n const orientationCounts = await regenerateOrientation(\n paths,\n nowIso,\n scoped\n ? {}\n : {\n staleness: {\n newSessions: 0,\n updatedSessions: 0,\n unverifiableSessions: wouldBlock(claudeCode) + wouldBlock(codex),\n },\n },\n );\n return {\n claudeCode,\n codex,\n handoff: { status: \"generated\", ...handoffCounts },\n decisions: { status: \"generated\", ...decisionCounts },\n orientation: { status: \"generated\", ...orientationCounts },\n dryRun,\n };\n}\n\n/** Sessions a refresh would newly import for this adapter; 0 unless it ran. */\nfunction wouldImport(outcome: ImportOutcome): number {\n return outcome.status === \"ran\" ? outcome.importedCount : 0;\n}\n\n/** Already-imported sessions a refresh would re-import (grown) or replace. */\nfunction wouldUpdate(outcome: ImportOutcome): number {\n return outcome.status === \"ran\" ? outcome.reimportedCount + outcome.replacedCount : 0;\n}\n\n/**\n * Sessions that GREW but a refresh would refuse to capture safely (broken prior\n * chain, unreadable prior events, non-append change). The capture is provably\n * behind, so a freshness verdict must NOT read as \"up to date\".\n */\nfunction wouldBlock(outcome: ImportOutcome): number {\n return outcome.status === \"ran\" ? outcome.skippedUnverifiable : 0;\n}\n\n/**\n * Counts of native sessions a real refresh would act on: new imports, updates\n * (grew / replaced), and `unverifiableSessions` — changed sources a refresh\n * could NOT safely capture, which the freshness verdict treats as \"can't\n * confirm current\" rather than a silent ✅.\n */\nexport type StalenessProbe = {\n newSessions: number;\n updatedSessions: number;\n unverifiableSessions: number;\n};\n\n/**\n * Make a stale capture measurable instead of silent: run a read-only DRY-RUN\n * refresh (reads the native logs, writes nothing) and count the sessions a real\n * `basou refresh` would add or update. Shared by the portfolio cards and the\n * single-workspace `basou orient` verdict so both judge freshness identically.\n * Returns `null` if the probe could not run (the caller renders \"can't confirm\"\n * rather than a false \"current\").\n *\n * NOTE: the import capture swaps the process-global console and is NOT\n * reentrant, so callers must never run two probes concurrently (e.g. the\n * portfolio runs them serially).\n */\nexport async function probeStaleness(args: {\n ctx: ImportContext;\n paths: BasouPaths;\n nowIso: string;\n}): Promise<StalenessProbe | null> {\n try {\n const dry = await refreshAll({\n options: { dryRun: true },\n ctx: args.ctx,\n paths: args.paths,\n nowIso: args.nowIso,\n });\n return {\n newSessions: wouldImport(dry.claudeCode) + wouldImport(dry.codex),\n updatedSessions: wouldUpdate(dry.claudeCode) + wouldUpdate(dry.codex),\n unverifiableSessions: wouldBlock(dry.claudeCode) + wouldBlock(dry.codex),\n };\n } catch {\n return null;\n }\n}\n","import { resolveBasouRepositoryRoot } from \"@basou/core\";\n\n/**\n * Resolve the repository root for a CLI command with the workspace-view\n * fallback, shared by `orient` and `refresh` so they behave identically: a\n * git-untracked view dir that symlinks its planning repo redirects to that repo\n * (with a note on stderr), and a genuine non-git dir reports a command-specific\n * \"run git init\" message.\n */\nexport async function resolveBasouRootForCommand(\n cwd: string,\n commandName: string,\n): Promise<string> {\n try {\n return await resolveBasouRepositoryRoot(cwd, {\n onRedirect: ({ via, root }) =>\n console.error(`Resolved workspace view to ${root} (via ${via}).`),\n });\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou ${commandName}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n","import { assertBasouRootSafe, basouPaths, findErrorCode } from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { loadPortfolioConfig } from \"../lib/portfolio-config.js\";\nimport { type ImportOutcome, type RefreshResult, refreshAll } from \"../lib/provenance-actions.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\nimport {\n DEFAULT_WATCH_INTERVAL_SEC,\n MAX_WATCH_INTERVAL_SEC,\n MIN_WATCH_INTERVAL_SEC,\n runRefreshWatch,\n} from \"./refresh-watch.js\";\n\nexport type RefreshOptions = {\n project?: string[];\n force?: boolean;\n dryRun?: boolean;\n json?: boolean;\n /** Refresh every workspace in `~/.basou/portfolio.yaml` instead of just the cwd's. */\n portfolio?: boolean;\n /** Run as a long-lived watcher: re-import when the native logs change. */\n watch?: boolean;\n /** Poll interval in seconds for `--watch` (default {@link DEFAULT_WATCH_INTERVAL_SEC}). */\n interval?: number;\n verbose?: boolean;\n};\n\n/** Commander collector: accumulate a repeatable option into an array. */\nfunction collectPath(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** Commander parser: `--interval` is an integer count of seconds within the supported range. */\nexport function parseInterval(value: string): number {\n const seconds = Number(value);\n if (\n !Number.isInteger(seconds) ||\n seconds < MIN_WATCH_INTERVAL_SEC ||\n seconds > MAX_WATCH_INTERVAL_SEC\n ) {\n throw new InvalidArgumentError(\n `--interval must be an integer between ${MIN_WATCH_INTERVAL_SEC} and ${MAX_WATCH_INTERVAL_SEC} (seconds).`,\n );\n }\n return seconds;\n}\n\n/** Resolve after `ms`, or early when `signal` aborts (e.g. on Ctrl-C). Leaves no listener behind. */\nfunction abortableSleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n let timer: ReturnType<typeof setTimeout>;\n const onAbort = (): void => {\n clearTimeout(timer);\n resolve();\n };\n timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport type RefreshContext = ImportContext & {\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n /** Portfolio config path for `--portfolio`; defaults to `~/.basou/portfolio.yaml`. Injectable for tests. */\n portfolioConfigPath?: string;\n};\n\n/**\n * Wire `basou refresh` onto `program`. One command that imports every adapter\n * for the project and regenerates handoff + decisions, so the dogfood loop is\n * a single invocation instead of four.\n */\nexport function registerRefreshCommand(program: Command): void {\n program\n .command(\"refresh\")\n .description(\n \"Import all adapters for the project and regenerate handoff + decisions in one step\",\n )\n .option(\n \"--project <path>\",\n \"Source project path to import (repeatable; defaults to the manifest source roots, then the repository root)\",\n collectPath,\n [],\n )\n .option(\"--force\", \"Re-import sessions already imported instead of skipping\")\n .option(\"--dry-run\", \"Preview imports and skip writing handoff / decisions\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\n \"--portfolio\",\n \"Refresh every workspace listed in ~/.basou/portfolio.yaml (each with its own source roots)\",\n )\n .option(\n \"--watch\",\n \"Keep running: re-import + regenerate when the native logs change (Ctrl-C to stop)\",\n )\n .option(\n \"--interval <seconds>\",\n `Poll interval for --watch, in seconds (default ${DEFAULT_WATCH_INTERVAL_SEC}, min ${MIN_WATCH_INTERVAL_SEC})`,\n parseInterval,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: RefreshOptions) => {\n await runRefresh(options);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. Tests should prefer\n * {@link doRunRefresh}, which returns the structured result.\n */\nexport async function runRefresh(options: RefreshOptions, ctx: RefreshContext = {}): Promise<void> {\n try {\n if (options.portfolio === true) {\n await doRunRefreshPortfolio(options, ctx);\n } else if (options.watch === true) {\n await doRunRefreshWatch(options, ctx);\n } else {\n await doRunRefresh(options, ctx);\n }\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * `basou refresh --portfolio`: refresh every workspace in\n * `~/.basou/portfolio.yaml` in one invocation, so the cross-repo orientation in\n * `basou view --portfolio` can be trusted as current without nine manual\n * refreshes. Best-effort: one workspace failing to refresh is reported and\n * skipped, the rest continue, and the process exits non-zero if any failed.\n */\nexport async function doRunRefreshPortfolio(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<void> {\n if (options.watch === true) throw new Error(\"--portfolio cannot be combined with --watch.\");\n if (options.project !== undefined && options.project.length > 0) {\n throw new Error(\n \"--portfolio refreshes each workspace with its own source roots; remove --project.\",\n );\n }\n\n const workspaces = await loadPortfolioConfig(ctx.portfolioConfigPath);\n const rollup: Array<\n | { label: string; path: string; status: \"ok\"; result: RefreshResult }\n | { label: string; path: string; status: \"failed\"; error: string }\n > = [];\n\n for (const ws of workspaces) {\n const label = ws.label ?? ws.path;\n try {\n const result = await computeRefresh(\n { ...options, portfolio: false },\n { ...ctx, cwd: ws.path },\n );\n rollup.push({ label, path: ws.path, status: \"ok\", result });\n if (options.json !== true) {\n console.log(`\\n## ${label} (${ws.path})`);\n printRefreshSummary(result);\n }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n rollup.push({ label, path: ws.path, status: \"failed\", error: message });\n if (options.json !== true) {\n console.log(`\\n## ${label} (${ws.path})`);\n console.log(` failed: ${message}`);\n }\n }\n }\n\n if (options.json === true) {\n console.log(JSON.stringify({ portfolio: true, workspaces: rollup }));\n } else {\n const failed = rollup.filter((r) => r.status === \"failed\").length;\n const ok = rollup.length - failed;\n console.log(\n `\\nportfolio: ${ok}/${rollup.length} refreshed${failed > 0 ? `, ${failed} failed` : \"\"}.`,\n );\n }\n if (rollup.some((r) => r.status === \"failed\")) process.exitCode = 1;\n}\n\n/**\n * `basou refresh --watch`: resolve + validate, then run the polling watcher\n * until SIGINT / SIGTERM. Startup failures (bad combo, no workspace, failed\n * initial refresh) propagate and exit non-zero; a steady-state cycle failure is\n * logged inside the loop and the watcher keeps running.\n */\nexport async function doRunRefreshWatch(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<void> {\n if (options.dryRun === true) throw new Error(\"--watch cannot be combined with --dry-run.\");\n if (options.json === true) throw new Error(\"--watch cannot be combined with --json.\");\n if (options.force === true) throw new Error(\"--watch cannot be combined with --force.\");\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"refresh\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const intervalMs = (options.interval ?? DEFAULT_WATCH_INTERVAL_SEC) * 1000;\n const controller = new AbortController();\n const onSignal = (): void => controller.abort();\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n try {\n await runRefreshWatch({\n // Watch from a workspace view: import from the resolved planning repo, not\n // the raw (non-git) view cwd — mirrors the redirect in computeRefresh.\n ctx: { ...ctx, cwd: repositoryRoot },\n paths,\n intervalMs,\n importOptions:\n options.project !== undefined && options.project.length > 0\n ? { project: options.project }\n : {},\n now: () => ctx.nowProvider?.() ?? new Date(),\n signal: controller.signal,\n sleep: abortableSleep,\n log: (line) => console.log(line),\n });\n } finally {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n }\n}\n\n/**\n * Resolve the workspace and run the shared refresh pipeline, returning the\n * {@link RefreshResult} without printing. Shared by {@link doRunRefresh} and the\n * per-workspace loop in {@link doRunRefreshPortfolio}.\n */\nasync function computeRefresh(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<RefreshResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"refresh\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n return refreshAll({\n options: {\n ...(options.project !== undefined && options.project.length > 0\n ? { project: options.project }\n : {}),\n ...(options.force === true ? { force: true } : {}),\n ...(options.dryRun === true ? { dryRun: true } : {}),\n },\n // Import from the resolved repo root, not the raw cwd: a workspace-view cwd\n // redirects to its planning repo, and the import must run there too.\n ctx: { ...ctx, cwd: repositoryRoot },\n paths,\n nowIso,\n });\n}\n\n/**\n * Pure runner: resolves the workspace, runs the shared refresh pipeline, and\n * prints a summary (or JSON). Returns the {@link RefreshResult} so the same\n * pipeline can be exercised by tests and reused by the view server.\n */\nexport async function doRunRefresh(\n options: RefreshOptions,\n ctx: RefreshContext,\n): Promise<RefreshResult> {\n const result = await computeRefresh(options, ctx);\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n printRefreshSummary(result);\n }\n return result;\n}\n\nfunction describeImport(outcome: ImportOutcome): string {\n if (outcome.status === \"skipped\") {\n return `${outcome.adapter}: skipped (${outcome.reason})`;\n }\n const verb = outcome.dryRun ? \"would import\" : \"imported\";\n const parts = [`${outcome.importedCount} session(s)`, `${outcome.eventTotal} events`];\n if (outcome.reimportedCount > 0) parts.push(`${outcome.reimportedCount} re-imported`);\n if (outcome.replacedCount > 0) parts.push(`${outcome.replacedCount} replaced`);\n if (outcome.skippedAlreadyImported > 0)\n parts.push(`${outcome.skippedAlreadyImported} already imported`);\n if (outcome.skippedLegacyUntracked > 0) parts.push(`${outcome.skippedLegacyUntracked} legacy`);\n return `${outcome.adapter}: ${verb} ${parts.join(\", \")}`;\n}\n\nfunction printRefreshSummary(result: RefreshResult): void {\n console.log(describeImport(result.claudeCode));\n console.log(describeImport(result.codex));\n if (result.handoff.status === \"generated\") {\n console.log(\n `handoff: regenerated (sessions: ${result.handoff.sessionCount}, decisions: ${result.handoff.decisionCount})`,\n );\n } else {\n console.log(`handoff: skipped (${result.handoff.reason})`);\n }\n if (result.decisions.status === \"generated\") {\n console.log(`decisions: regenerated (${result.decisions.decisionCount})`);\n } else {\n console.log(`decisions: skipped (${result.decisions.reason})`);\n }\n if (result.orientation.status === \"generated\") {\n console.log(\n `orientation: regenerated (in-flight: ${result.orientation.inFlightTaskCount}, pending approvals: ${result.orientation.pendingApprovalsCount}, suspect: ${result.orientation.suspectCount})`,\n );\n } else {\n console.log(`orientation: skipped (${result.orientation.reason})`);\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { readYamlFile } from \"@basou/core\";\n\n/**\n * GUI configuration for `basou view --portfolio`: the set of workspaces a single\n * owner wants to orient across in one screen. This is local GUI config, NOT\n * provenance/trail data — it is not part of the workspace schema bundle and is\n * never committed into a monitored repo. Because it is not a committed manifest,\n * absolute paths are required here (the `import.source_roots` relative-only rule\n * exists to keep committed manifests path-clean; that constraint does not apply\n * to a user-level config under $HOME).\n *\n * Shape:\n * version: 1 # optional, reserved for future migrations\n * workspaces:\n * - path: /abs/path/to/workspace-repo # required, absolute (~ allowed)\n * label: my-project # optional display label\n */\nexport type PortfolioWorkspace = { path: string; label?: string };\n\n/** Canonical location of the portfolio config. */\nexport const DEFAULT_PORTFOLIO_CONFIG_PATH = join(homedir(), \".basou\", \"portfolio.yaml\");\n\n/** Expand a leading `~` / `~/` to the user's home directory. */\nfunction expandTilde(p: string): string {\n if (p === \"~\") return homedir();\n if (p.startsWith(\"~/\")) return join(homedir(), p.slice(2));\n return p;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Read and validate `~/.basou/portfolio.yaml` (or an injected path for tests),\n * returning the workspace list with each `path` expanded and made absolute, and\n * de-duplicated by resolved path (first occurrence wins, preserving its label\n * and order). Throws an Error with a pathless, user-facing message on a missing\n * file, invalid YAML, a malformed shape, a non-absolute path, or an empty list.\n */\nexport async function loadPortfolioConfig(\n configPath: string = DEFAULT_PORTFOLIO_CONFIG_PATH,\n): Promise<PortfolioWorkspace[]> {\n let raw: unknown;\n try {\n raw = await readYamlFile(configPath);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n throw new Error(\n \"No portfolio config at ~/.basou/portfolio.yaml. Create one (a 'workspaces:' list of repo paths) or pass --workspace <path>.\",\n );\n }\n if (error instanceof Error && error.message === \"Failed to parse YAML content\") {\n throw new Error(\"~/.basou/portfolio.yaml is not valid YAML.\");\n }\n throw error;\n }\n\n if (!isRecord(raw) || !Array.isArray(raw.workspaces)) {\n throw new Error(\"~/.basou/portfolio.yaml must contain a 'workspaces:' list.\");\n }\n\n const seen = new Set<string>();\n const result: PortfolioWorkspace[] = [];\n for (const entry of raw.workspaces) {\n if (!isRecord(entry) || typeof entry.path !== \"string\" || entry.path.trim().length === 0) {\n throw new Error(\"Each portfolio workspace needs a non-empty string 'path'.\");\n }\n if (entry.label !== undefined && typeof entry.label !== \"string\") {\n throw new Error(\"A portfolio workspace 'label' must be a string when present.\");\n }\n const expanded = expandTilde(entry.path.trim());\n if (!isAbsolute(expanded)) {\n throw new Error(\n \"Portfolio workspace paths must be absolute (or start with '~'); use --workspace for relative ad-hoc paths.\",\n );\n }\n const abs = resolve(expanded);\n if (seen.has(abs)) continue;\n seen.add(abs);\n result.push(entry.label !== undefined ? { path: abs, label: entry.label } : { path: abs });\n }\n\n if (result.length === 0) {\n throw new Error(\"~/.basou/portfolio.yaml has no workspaces.\");\n }\n return result;\n}\n","import type { Dirent } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type BasouPaths, findErrorCode } from \"@basou/core\";\nimport {\n type ImportOutcome,\n importClaudeCode,\n importCodex,\n type RefreshActionOptions,\n regenerateDecisions,\n regenerateHandoff,\n} from \"../lib/provenance-actions.js\";\nimport type { ImportContext } from \"./import.js\";\n\n/** Default poll interval for `--watch`, in seconds. */\nexport const DEFAULT_WATCH_INTERVAL_SEC = 30;\n/** Smallest accepted `--interval`, in seconds. */\nexport const MIN_WATCH_INTERVAL_SEC = 5;\n/** Largest accepted `--interval`, in seconds (1 day; keeps the timer well within the 32-bit ms range). */\nexport const MAX_WATCH_INTERVAL_SEC = 86_400;\n\n/** A file's change signature: a refresh is triggered when this moves. */\ntype FileSig = { mtimeMs: number; size: number };\n/** Absolute `*.jsonl` path -> its {mtime, size} signature. */\nexport type SourceLogScan = Map<string, FileSig>;\n\n/**\n * The native-log stores the importers read (Codex rollouts + Claude\n * transcripts), resolved from the context or the `~` defaults. These are the\n * directories the watcher polls -- a new session is a new/grown `*.jsonl` here.\n */\nexport function watchedRoots(ctx: ImportContext): string[] {\n return [\n ctx.codexSessionsDir ?? join(homedir(), \".codex\", \"sessions\"),\n ctx.claudeProjectsDir ?? join(homedir(), \".claude\", \"projects\"),\n ];\n}\n\n/**\n * Recursively collect a `{mtime, size}` signature of every `*.jsonl` under the\n * given roots, keyed by absolute path. A missing root contributes nothing (it\n * may appear later); a file that vanishes mid-walk is skipped. No file content\n * is read, so this is cheap to run every poll.\n */\nexport async function scanSourceLogs(roots: string[]): Promise<SourceLogScan> {\n const out: SourceLogScan = new Map();\n const walk = async (dir: string): Promise<void> => {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error: unknown) {\n // Absent (ENOENT) or not a directory (ENOTDIR): nothing to scan here.\n if (findErrorCode(error, \"ENOENT\") || findErrorCode(error, \"ENOTDIR\")) return;\n // Surface other errors pathlessly (the native message carries the path).\n throw new Error(\"Failed to read a source log directory\", { cause: error });\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n try {\n const info = await stat(full);\n out.set(full, { mtimeMs: info.mtimeMs, size: info.size });\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) continue; // vanished mid-walk; skip\n throw new Error(\"Failed to stat a source log file\", { cause: error });\n }\n }\n }\n };\n for (const root of roots) await walk(root);\n return out;\n}\n\n/** Whether two scans describe the same set of files at the same size/mtime. */\nexport function scansEqual(a: SourceLogScan, b: SourceLogScan): boolean {\n if (a.size !== b.size) return false;\n for (const [path, sig] of a) {\n const other = b.get(path);\n if (other === undefined || other.mtimeMs !== sig.mtimeMs || other.size !== sig.size) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * How many sessions an import outcome changed on disk: new imports PLUS\n * in-place re-imports of grown sources PLUS --force replacements. Any\n * non-zero count must trigger a handoff / decisions regeneration, so a session\n * that was re-imported (not freshly imported) does not leave the derived\n * markdown stale.\n */\nfunction changedCount(outcome: ImportOutcome): number {\n return outcome.status === \"ran\"\n ? outcome.importedCount + outcome.reimportedCount + outcome.replacedCount\n : 0;\n}\n\nfunction describeOutcome(outcome: ImportOutcome): string {\n if (outcome.status !== \"ran\") return `${outcome.adapter} skipped`;\n const reimported = outcome.reimportedCount > 0 ? ` ~${outcome.reimportedCount}` : \"\";\n return `${outcome.adapter} +${outcome.importedCount}${reimported}`;\n}\n\nfunction hms(date: Date): string {\n return date.toISOString().slice(11, 19);\n}\n\n/** Dependencies for {@link runRefreshWatch}; timers / clock / signal are injectable for tests. */\nexport type WatchDeps = {\n ctx: ImportContext;\n paths: BasouPaths;\n intervalMs: number;\n /** Import options forwarded to each cycle (project source roots only; no force / dry-run in watch). */\n importOptions: RefreshActionOptions;\n now: () => Date;\n signal: AbortSignal;\n /** Resolves after `ms`, or early when `signal` aborts. */\n sleep: (ms: number, signal: AbortSignal) => Promise<void>;\n log: (line: string) => void;\n};\n\n/** Import both adapters for the workspace's source roots; returns the outcomes + total imported. */\nasync function runImports(\n deps: WatchDeps,\n): Promise<{ claude: ImportOutcome; codex: ImportOutcome; changed: number }> {\n const claude = await importClaudeCode(deps.importOptions, deps.ctx);\n const codex = await importCodex(deps.importOptions, deps.ctx);\n return { claude, codex, changed: changedCount(claude) + changedCount(codex) };\n}\n\n/** Regenerate handoff + decisions; returns the handoff session count. */\nasync function regenerate(deps: WatchDeps): Promise<number> {\n const nowIso = deps.now().toISOString();\n const handoff = await regenerateHandoff(deps.paths, nowIso);\n await regenerateDecisions(deps.paths, nowIso);\n return handoff.sessionCount;\n}\n\n/**\n * Poll the native-log stores and keep the workspace current. Does an initial\n * catch-up refresh, then on each interval re-imports ONLY when the logs are\n * quiescent (unchanged since the previous poll, so no session is mid-write) AND\n * have changed since the last import. Handoff / decisions regenerate only when\n * something was imported, so unrelated AI activity elsewhere never rewrites this\n * workspace's files. A failure inside a steady-state cycle is logged and the\n * loop continues; the initial refresh failing is fatal (it propagates). Returns\n * when `signal` aborts (after the in-flight cycle, never mid-write).\n */\nexport async function runRefreshWatch(deps: WatchDeps): Promise<void> {\n const { intervalMs, ctx, signal, sleep, log } = deps;\n const roots = watchedRoots(ctx);\n log(\n `watching ${roots.join(\", \")} every ${Math.round(intervalMs / 1000)}s ` +\n \"(imports on change; Ctrl-C to stop)\",\n );\n\n // Baseline BEFORE the initial import, so a session that appears during the\n // import window is not mistaken for \"already seen\" and missed forever.\n let lastScan = await scanSourceLogs(roots);\n let importedScan = lastScan;\n\n // Initial catch-up: failure here is fatal (propagates to the caller).\n const initial = await runImports(deps);\n const initialSessions = await regenerate(deps);\n log(\n `[${hms(deps.now())}] refreshed: ${describeOutcome(initial.codex)}, ` +\n `${describeOutcome(initial.claude)} (sessions: ${initialSessions})`,\n );\n if (signal.aborted) {\n log(\"watch stopped\");\n return;\n }\n\n // Set when an import succeeded but the matching regenerate has not yet (so a\n // regenerate failure cannot leave handoff / decisions stale forever).\n let pendingRegen = false;\n while (!signal.aborted) {\n await sleep(intervalMs, signal);\n if (signal.aborted) break;\n try {\n const current = await scanSourceLogs(roots);\n // Quiescent since the previous poll AND changed since the last import.\n if (scansEqual(current, lastScan) && !scansEqual(current, importedScan)) {\n const { claude, codex, changed } = await runImports(deps);\n if (changed > 0) pendingRegen = true;\n if (pendingRegen) {\n const sessions = await regenerate(deps);\n pendingRegen = false;\n log(\n `[${hms(deps.now())}] refreshed: ${describeOutcome(codex)}, ` +\n `${describeOutcome(claude)} (sessions: ${sessions})`,\n );\n }\n importedScan = current;\n }\n lastScan = current;\n } catch (error: unknown) {\n // A transient fs error must not kill a long-running watcher. Messages from\n // the scan / import / render layers are pathless by contract.\n const message = error instanceof Error ? error.message : String(error);\n log(`[${hms(deps.now())}] refresh cycle skipped: ${message}`);\n }\n }\n log(\"watch stopped\");\n}\n","import { isAbsolute, resolve } from \"node:path\";\nimport {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n renderReport,\n resolveRepositoryRoot,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n printTaskSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\n\nexport type ReportGenerateOptions = {\n out?: string;\n json?: boolean;\n title?: string;\n verbose?: boolean;\n};\n\nexport type ReportContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Wire `basou report generate` onto `program`. The `report` group is\n * registered up front so future subcommands (e.g. `show`) can slot under the\n * same group without breaking the CLI surface.\n */\nexport function registerReportCommand(program: Command): void {\n const report = program\n .command(\"report\")\n .description(\n \"Generate a work report — a shareable export explaining the work in this workspace\",\n );\n\n report\n .command(\"generate\")\n .description(\"Generate a work report from the current workspace state\")\n .option(\"--out <path>\", \"Write the markdown report to a file instead of stdout\")\n .option(\"--json\", \"Emit the structured report data as JSON to stdout\")\n .option(\"--title <text>\", \"Subject line shown in the report header\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ReportGenerateOptions) => {\n await runReportGenerate(opts);\n });\n}\n\n/**\n * Programmatic entry that owns `process.exitCode`. A successful render always\n * exits 0 — integrity verdicts inside the report (`unchained` / `tampered`) are\n * informational and never fail the command (unlike `basou verify`). Only real\n * operational failures set a non-zero exit. [Codex #8]\n */\nexport async function runReportGenerate(\n options: ReportGenerateOptions,\n ctx: ReportContext = {},\n): Promise<void> {\n try {\n await doRunReportGenerate(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `report generate`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n *\n * Output contract:\n * - default → markdown body to stdout.\n * - `--json` → structured data as JSON to stdout, JSON-only (pipe-safe).\n * - `--out <path>` → write the markdown body to the file; a one-line summary\n * goes to stderr (never stdout) so `--out` composes with `--json`.\n */\nexport async function doRunReportGenerate(\n options: ReportGenerateOptions,\n ctx: ReportContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForReport(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const result = await renderReport({\n paths,\n nowIso,\n ...(options.title !== undefined ? { title: options.title } : {}),\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n });\n\n if (options.out !== undefined) {\n const outPath = isAbsolute(options.out) ? options.out : resolve(cwd, options.out);\n await writeMarkdownFile(outPath, result.body);\n const { sessions, decisions, tasks } = result.data;\n // Confirmation on stderr (console.error) so stdout stays clean for `--json`.\n console.error(\n `Wrote report to ${options.out} (sessions: ${sessions.total}, decisions: ${decisions.count}, tasks: ${tasks.total})`,\n );\n }\n\n if (options.json === true) {\n console.log(JSON.stringify(result.data, null, 2));\n } else if (options.out === undefined) {\n console.log(result.body);\n }\n}\n\nasync function resolveRepositoryRootForReport(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n \"Not a git repository. Run 'git init' first, then re-run 'basou report generate'.\",\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n acquireLock,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n ChildProcessRunner,\n claudeCodeAdapterMetadata,\n appendChainedEvent as coreAppendChainedEvent,\n type DiffResult,\n finalizeSessionYaml,\n type GitSnapshot,\n getDiff,\n getSnapshot,\n overwriteYamlFile,\n type PrefixedId,\n type ProcessRunner,\n prefixedUlid,\n type RunResult,\n readManifest,\n readYamlFile,\n resolveClaudeCodeCommand,\n resolveRepositoryRoot,\n type Session,\n SessionSchema,\n sanitizeRelatedFiles,\n sanitizeWorkingDirectory,\n writeYamlFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\n// Appends one event to the session's events.jsonl. The `sessionDir` argument\n// is retained for the test-injection seam (ctx.appendEvent); the production\n// binding ignores it and chains via paths + sessionId.\ntype AppendEventFn = (sessionDir: string, event: unknown) => Promise<void>;\ntype ResolveCommandFn = typeof resolveClaudeCodeCommand;\ntype GetDiffFn = typeof getDiff;\n\n/**\n * `basou run claude-code` orchestration: spawn claude-code as a single new\n * Basou session and record its lifecycle (session_started, optional\n * git_snapshot pre, status_changed, command_executed, optional git_snapshot\n * post, file_changed × N, status_changed, session_ended) to events.jsonl.\n *\n * The child inherits the parent's stdio (`capture: \"none\"`) so that\n * claude-code's interactive TTY remains usable; raw stdout/stderr is\n * intentionally NOT captured into events.jsonl or `.basou/raw/` in v0.1.\n */\nexport type RunOptions = {\n // commander turns `--no-snapshot` into `snapshot: false`. The default\n // (no flag) leaves this `undefined` (treated as `true` downstream).\n snapshot?: boolean;\n cwd?: string;\n verbose?: boolean;\n};\n\nexport type RunContext = {\n runner?: ProcessRunner;\n now?: () => Date;\n appendEvent?: AppendEventFn;\n onExitHookInstalled?: (handler: () => void) => void;\n // Override the claude-code PATH lookup. Tests use this to skip real\n // `which` invocations and force success / failure deterministically.\n resolveCommand?: ResolveCommandFn;\n // Override the git diff capability. Tests use this to force capability\n // failure deterministically without rewriting the git fixture state.\n getDiff?: GetDiffFn;\n};\n\n/**\n * Wire the `basou run` command group into `program`. The optional `ctx` is\n * passed through to `runClaudeCode` so tests can intercept the action callback\n * (fake runner, fake clock, deterministic resolveCommand / getDiff). Production\n * callers omit it.\n *\n * Basou options (`--no-snapshot`, `--cwd`, `-v`) are defined on both the\n * `run` group and the inner `claude-code` subcommand. commander's\n * `passThroughOptions()` only forwards UNKNOWN options to args, so a\n * group-only definition would make `basou run claude-code --no-snapshot`\n * crash with \"unknown option\". Duplicating the definitions lets the option\n * be recognized regardless of position; only `--`-separated args go to the\n * child. v0.2+ adapter additions (codex / gemini) should consider\n * extracting a common-option helper rather than re-duplicating.\n */\nexport function registerRunCommand(program: Command, ctx: RunContext = {}): void {\n const runCommand = program\n .command(\"run\")\n .description(\"Run an AI coding tool through Basou as a tracked session\")\n // Required so the inner `claude-code` subcommand can pass through\n // arguments after `--` to the child without commander interpreting them\n // as run-group options.\n .enablePositionalOptions()\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the session\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\");\n\n runCommand\n .command(\"claude-code [args...]\")\n .description(\"Run Claude Code CLI as a Basou-tracked session\")\n // Same options redeclared on the subsubcommand so they are recognized\n // when placed AFTER `claude-code` as well; see the function comment.\n .option(\"--no-snapshot\", \"Skip git_snapshot before/after the session\")\n .option(\"--cwd <path>\", \"Run from a Basou root other than process.cwd()\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .passThroughOptions()\n .action(async (args: string[], options: RunOptions, command: Command) => {\n const parentOptions = (command.parent?.opts() ?? {}) as RunOptions;\n // Both layers default `snapshot` to `true` when --no-snapshot is\n // omitted, so a naive spread would let the subsubcommand's default\n // overwrite a `--no-snapshot` set on the parent. Take a logical AND\n // instead: snapshot stays on only when neither layer disables it.\n const snapshotOn = parentOptions.snapshot !== false && options.snapshot !== false;\n const merged: RunOptions = {\n ...parentOptions,\n ...options,\n snapshot: snapshotOn,\n };\n try {\n const exitCode = await runClaudeCode(args, merged, ctx);\n process.exit(exitCode);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(merged) });\n process.exit(1);\n }\n });\n}\n\nexport async function runClaudeCode(\n args: string[],\n options: RunOptions,\n ctx: RunContext = {},\n): Promise<number> {\n const runner = ctx.runner ?? new ChildProcessRunner();\n const now = ctx.now ?? (() => new Date());\n const resolveCommand: ResolveCommandFn = ctx.resolveCommand ?? resolveClaudeCodeCommand;\n const getDiffFn: GetDiffFn = ctx.getDiff ?? getDiff;\n\n // 1. Resolve the claude-code executable BEFORE any side-effect: a missing\n // CLI is a user installation issue, not something worth recording as a\n // Basou session. Failure here leaves no sessions/<id>/ entry behind.\n const { command } = await resolveCommand();\n\n const cwd = options.cwd ?? process.cwd();\n\n // 2. Resolve repository root (entry-fail when not in a git repo).\n const repoRoot = await resolveRepositoryRootForRun(cwd);\n const paths = basouPaths(repoRoot);\n\n // 3. Workspace safety check.\n await assertBasouRootSafe(paths.root);\n\n // 4. Read manifest to bind session.workspace_id.\n const manifest = await readManifest(paths);\n\n // 5. Build a fresh session and persist its initial state.\n const sessionId = prefixedUlid(\"ses\");\n const sessionDir = join(paths.sessions, sessionId);\n await mkdir(sessionDir, { recursive: true });\n\n // Every append chains onto the on-disk tail under a short-lived session lock\n // (the self-locking wrapper); the lock is NEVER held across the child. Tests\n // inject ctx.appendEvent to force append failures.\n const appendEvent: AppendEventFn =\n ctx.appendEvent ??\n (async (_sessionDir, event) => {\n await coreAppendChainedEvent(paths, sessionId, event);\n });\n\n const startedAt = now().toISOString();\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n const session = buildInitialSession({\n id: sessionId,\n command,\n args,\n cwd: repoRoot,\n workspaceId: manifest.workspace.id,\n startedAt,\n });\n await writeYamlFile(sessionYamlPath, session);\n\n // 6. session_started.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_started\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: startedAt,\n source: claudeCodeAdapterMetadata.kind,\n });\n\n // 7. Optional pre-execute git_snapshot.\n let preSnapshot: GitSnapshot | null = null;\n if (options.snapshot !== false) {\n preSnapshot = await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 8. status_changed: initialized -> running.\n const runningAt = now().toISOString();\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: runningAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"initialized\",\n to: \"running\",\n });\n // Lock the status write so it cannot interleave-clobber a foreign locked\n // session.yaml writer (e.g. a task attach setting task_id on this session).\n const runningLock = await acquireLock(paths, \"session\", sessionId);\n try {\n await mutateSessionYaml(sessionYamlPath, (s) => {\n s.session.status = \"running\";\n });\n } finally {\n await runningLock.release();\n }\n\n // 9. Transient signal hooks (SIGINT / SIGTERM / exit). The exit hook is a\n // last-resort SIGKILL if the parent dies abnormally.\n const controller = new AbortController();\n let signalReceived: NodeJS.Signals | null = null;\n let activeChild: ChildProcess | null = null;\n const signalHandler = (sig: NodeJS.Signals) => {\n if (signalReceived !== null) return;\n signalReceived = sig;\n controller.abort();\n };\n const exitHandler = () => {\n if (activeChild !== null) {\n try {\n activeChild.kill(\"SIGKILL\");\n } catch {\n // best-effort cleanup\n }\n }\n };\n const onSigInt = () => signalHandler(\"SIGINT\");\n const onSigTerm = () => signalHandler(\"SIGTERM\");\n process.on(\"SIGINT\", onSigInt);\n process.on(\"SIGTERM\", onSigTerm);\n process.on(\"exit\", exitHandler);\n ctx.onExitHookInstalled?.(exitHandler);\n\n // 10-11. runner.run() execute (capture: \"none\" inherits the parent stdio so\n // claude-code keeps a real TTY). Spawn-time errors finalize the\n // session as failed and propagate the error.\n let result: RunResult;\n try {\n try {\n result = await runner.run(command, args, {\n cwd: repoRoot,\n capture: \"none\",\n signal: controller.signal,\n onSpawn: (child) => {\n activeChild = child;\n },\n });\n } catch (spawnError: unknown) {\n await finalizeSessionAsFailed(paths, sessionDir, sessionId, appendEvent, {\n command,\n args,\n cwd: repoRoot,\n occurredAt: now().toISOString(),\n signalReceived,\n });\n throw spawnError;\n }\n } finally {\n process.off(\"SIGINT\", onSigInt);\n process.off(\"SIGTERM\", onSigTerm);\n process.off(\"exit\", exitHandler);\n activeChild = null;\n }\n\n const endedAt = now().toISOString();\n\n // 12. command_executed (parent received_signal vs child terminating signal).\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: \"terminal-recording\",\n command,\n args,\n cwd: repoRoot,\n exit_code: result.exit_code,\n ...(result.signal !== null ? { signal: result.signal } : {}),\n ...(signalReceived !== null ? { received_signal: signalReceived } : {}),\n duration_ms: result.duration_ms,\n });\n\n // 13. Optional post-execute git_snapshot.\n let postSnapshot: GitSnapshot | null = null;\n if (options.snapshot !== false) {\n postSnapshot = await tryAppendGitSnapshot(sessionDir, sessionId, repoRoot, now, appendEvent);\n }\n\n // 14-15. file_changed events derived from getDiff(preHead, postHead). Only\n // committed changes appear here; dirty (staged/unstaged/untracked)\n // edits are surfaced via session.yaml.related_files instead.\n let diff: DiffResult | null = null;\n if (preSnapshot !== null && postSnapshot !== null) {\n diff = await tryAppendFileChangedEvents(\n sessionDir,\n sessionId,\n repoRoot,\n preSnapshot.head,\n postSnapshot.head,\n now().toISOString(),\n appendEvent,\n getDiffFn,\n );\n }\n\n // 16. Compute related_files = pre+post snapshot ∪ diff (sorted, deduped).\n // Then sanitize so /Users/<u>/projects/foo/... is stored relative to\n // the session's working_directory; system paths outside both bases\n // stay verbatim. Git output is usually repo-relative already, but the\n // sanitizer is idempotent and cheap so we run it unconditionally\n // against the very subset of paths that ever reach session.yaml.\n const rawRelated = computeRelatedFiles(preSnapshot, postSnapshot, diff);\n const relatedFiles = sanitizeRelatedFiles(rawRelated, {\n workingDirectory: repoRoot,\n homedir: homedir(),\n }).sanitized;\n\n const finalStatus = decideFinalStatus(result, signalReceived);\n\n // 17-18. status_changed: running -> final.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"running\",\n to: finalStatus,\n });\n\n // 19. session_ended.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: endedAt,\n source: claudeCodeAdapterMetadata.kind,\n ...(result.exit_code !== null ? { exit_code: result.exit_code } : {}),\n });\n\n // 20. Final session.yaml update (status / ended_at / invocation.exit_code /\n // related_files) plus the integrity head anchor, written from the on-disk\n // tail under the session lock so a foreign line appended just before\n // finalize is anchored and a later attach (now terminal) is rejected.\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = finalStatus;\n s.session.ended_at = endedAt;\n s.session.invocation.exit_code = result.exit_code;\n s.session.related_files = relatedFiles;\n });\n\n if (result.exit_code !== null) return result.exit_code;\n return signalToExitCode(signalReceived ?? result.signal);\n}\n\nfunction decideFinalStatus(\n result: { exit_code: number | null; signal: NodeJS.Signals | null },\n signalReceived: NodeJS.Signals | null,\n): \"completed\" | \"failed\" | \"interrupted\" {\n if (signalReceived === \"SIGINT\" || signalReceived === \"SIGTERM\") return \"interrupted\";\n if (result.signal === \"SIGINT\" || result.signal === \"SIGTERM\" || result.signal === \"SIGKILL\") {\n return \"interrupted\";\n }\n if (result.exit_code === 0) return \"completed\";\n return \"failed\";\n}\n\nconst SIGNUM_MAP: Record<string, number> = {\n SIGHUP: 1,\n SIGINT: 2,\n SIGQUIT: 3,\n SIGKILL: 9,\n SIGTERM: 15,\n};\n\nfunction signalToExitCode(sig: NodeJS.Signals | null): number {\n if (sig === null) return 1;\n const num = SIGNUM_MAP[sig] ?? 1;\n return 128 + num;\n}\n\nasync function tryAppendGitSnapshot(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n now: () => Date,\n appendEvent: AppendEventFn,\n): Promise<GitSnapshot | null> {\n // Stage 1: capability acquisition. Capability-level failures (no git\n // repository, git binary missing, no commits) downgrade to a skip warning;\n // events.jsonl simply lacks this git_snapshot entry.\n let snapshot: GitSnapshot;\n try {\n snapshot = await getSnapshot(repoRoot);\n } catch (error: unknown) {\n console.warn(normalizeGitSnapshotSkipMessage(error));\n return null;\n }\n // Stage 2: events.jsonl append. Failures here would corrupt the events.jsonl\n // integrity contract; let them propagate so the run fails loudly rather\n // than producing a session that looks successful but is actually missing\n // events.\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"git_snapshot\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: now().toISOString(),\n source: \"git-capability\",\n ...snapshot,\n });\n return snapshot;\n}\n\nasync function tryAppendFileChangedEvents(\n sessionDir: string,\n sessionId: string,\n repoRoot: string,\n baseRef: string,\n headRef: string,\n occurredAt: string,\n appendEvent: AppendEventFn,\n getDiffFn: GetDiffFn,\n): Promise<DiffResult | null> {\n // Stage 1: capability acquisition (same skip-vs-fail split as\n // tryAppendGitSnapshot).\n let diff: DiffResult;\n try {\n diff = await getDiffFn(repoRoot, baseRef, headRef);\n } catch (error: unknown) {\n console.warn(normalizeFileChangedSkipMessage(error));\n return null;\n }\n // Stage 2: per-path appendEvent. Schema validation / disk failures here\n // are NOT a capability miss; let them propagate.\n for (const change of diff.changed_files) {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"file_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: occurredAt,\n source: \"git-capability\",\n path: change.path,\n change_type: change.status,\n ...(change.old_path !== undefined ? { old_path: change.old_path } : {}),\n });\n }\n return diff;\n}\n\nfunction computeRelatedFiles(\n preSnapshot: GitSnapshot | null,\n postSnapshot: GitSnapshot | null,\n diff: DiffResult | null,\n): string[] {\n const set = new Set<string>();\n for (const snap of [preSnapshot, postSnapshot]) {\n if (snap === null) continue;\n for (const p of snap.staged) set.add(p);\n for (const p of snap.unstaged) set.add(p);\n for (const p of snap.untracked) set.add(p);\n }\n if (diff !== null) {\n for (const change of diff.changed_files) set.add(change.path);\n }\n return [...set].sort();\n}\n\nfunction normalizeGitSnapshotSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `git_snapshot skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") return \"git_snapshot skipped: not in a git repository\";\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"git_snapshot skipped: git executable not found\";\n }\n if (msg === \"No commits in repository\") return \"git_snapshot skipped: no commits in repository\";\n return `git_snapshot skipped: ${msg}`;\n}\n\nfunction normalizeFileChangedSkipMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return `file_changed skipped: ${String(error)}`;\n }\n const msg = error.message;\n if (msg === \"Not a git repository\") return \"file_changed skipped: not in a git repository\";\n if (msg === \"Git executable not found in PATH. Install git first.\") {\n return \"file_changed skipped: git executable not found\";\n }\n if (msg === \"Invalid ref\") return \"file_changed skipped: invalid git ref\";\n if (msg === \"Failed to compute git diff\")\n return \"file_changed skipped: failed to compute git diff\";\n return `file_changed skipped: ${msg}`;\n}\n\nfunction buildInitialSession(input: {\n id: PrefixedId<\"ses\">;\n command: string;\n args: string[];\n cwd: string;\n workspaceId: PrefixedId<\"ws\">;\n startedAt: string;\n}): Session {\n const cmdline = [input.command, ...input.args].join(\" \");\n return {\n schema_version: \"0.1.0\",\n session: {\n id: input.id,\n label: `basou run ${cmdline} (${input.startedAt})`,\n task_id: null,\n workspace_id: input.workspaceId,\n source: { ...claudeCodeAdapterMetadata },\n started_at: input.startedAt,\n status: \"initialized\",\n working_directory: sanitizeWorkingDirectory(input.cwd, { homedir: homedir() }),\n invocation: {\n command: input.command,\n args: [...input.args],\n exit_code: null,\n },\n related_files: [],\n events_log: \"events.jsonl\",\n },\n };\n}\n\nasync function mutateSessionYaml(\n filePath: string,\n mutator: (session: Session) => void,\n): Promise<void> {\n const raw = await readYamlFile(filePath);\n const parsed = SessionSchema.parse(raw);\n mutator(parsed);\n const validated = SessionSchema.parse(parsed);\n await overwriteYamlFile(filePath, validated);\n}\n\nasync function finalizeSessionAsFailed(\n paths: BasouPaths,\n sessionDir: string,\n sessionId: string,\n appendEvent: AppendEventFn,\n ctx: {\n command: string;\n args: string[];\n cwd: string;\n occurredAt: string;\n signalReceived: NodeJS.Signals | null;\n },\n): Promise<void> {\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"command_executed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: \"terminal-recording\",\n command: ctx.command,\n args: ctx.args,\n cwd: ctx.cwd,\n exit_code: null,\n signal: null,\n ...(ctx.signalReceived !== null ? { received_signal: ctx.signalReceived } : {}),\n duration_ms: 0,\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_status_changed\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: claudeCodeAdapterMetadata.kind,\n from: \"running\",\n to: \"failed\",\n });\n await appendEvent(sessionDir, {\n schema_version: \"0.1.0\",\n type: \"session_ended\",\n id: prefixedUlid(\"evt\"),\n session_id: sessionId,\n occurred_at: ctx.occurredAt,\n source: claudeCodeAdapterMetadata.kind,\n });\n await finalizeSessionYaml(paths, sessionId, (s) => {\n s.session.status = \"failed\";\n s.session.ended_at = ctx.occurredAt;\n s.session.invocation.exit_code = null;\n });\n}\n\nasync function resolveRepositoryRootForRun(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou run'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { basename, isAbsolute, join, relative } from \"node:path\";\nimport {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n type Event,\n enumerateSessionDirs,\n findErrorCode,\n type ImportSessionOptions,\n type ImportSessionResult,\n importSessionFromJson,\n loadSessionEntries,\n type RechainResult,\n readAllEvents,\n readManifest,\n readYamlFile,\n rechainSessionInPlace,\n resolveRepositoryRoot,\n resolveSessionId,\n resolveTaskId,\n type Session,\n SessionImportPayloadSchema,\n SessionSchema,\n type SessionStatus,\n SessionStatusSchema,\n sessionWorkStatsFromEvents,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionListSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { formatDurationMs } from \"../lib/format-duration.js\";\n\nconst SES_PREFIX = \"ses_\";\nconst TASK_PREFIX = \"task_\";\nconst SHORT_ID_BASE_LEN = 6;\nconst SHORT_ID_MAX_LEN = 26; // ULID body length\n\nconst STATUS_VALUES = SessionStatusSchema.options;\n\nexport type SessionListOptions = {\n json?: boolean;\n status?: SessionStatus;\n verbose?: boolean;\n};\n\nexport type SessionShowOptions = {\n json?: boolean;\n events?: boolean;\n last?: number;\n fullPath?: boolean;\n verbose?: boolean;\n};\n\nexport type SessionContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable so the `session show` work\n * span is deterministic in tests and for a running session. */\n nowProvider?: () => Date;\n};\n\nexport type SessionRechainOptions = {\n session?: string;\n all?: boolean;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** One row of `basou session rechain` output. */\nexport type RechainRow = {\n session_id: string;\n status: \"rechained\" | \"skipped\" | \"error\";\n /** Skip reason, present when status is \"skipped\". */\n reason?: Extract<RechainResult, { status: \"skipped\" }>[\"reason\"];\n /** Chained event count, present when status is \"rechained\". */\n event_count?: number;\n /** Fixed error message, present when status is \"error\". */\n message?: string;\n};\n\ntype SessionListRecord = {\n sessionId: string;\n session: Session;\n suspect: boolean;\n suspectReason: string | null;\n};\n\n/**\n * Wire `basou session list` and `basou session show <id>` onto `program`.\n *\n * The `session` group is registered up front so future subcommands\n * (`note`, `import`) added in later steps slot under the same group without\n * changing the externally visible CLI surface.\n */\nexport function registerSessionCommand(program: Command): void {\n const session = program\n .command(\"session\")\n .description(\"Inspect Basou sessions stored under .basou/sessions/\");\n\n session\n .command(\"list\")\n .description(\"List sessions in the current workspace (newest first)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\n \"--status <state>\",\n `Filter by session status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseSessionStatus,\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionListOptions) => {\n await runSessionList(options);\n });\n\n session\n .command(\"show <id>\")\n .description(\"Show a session's metadata and recent events\")\n .option(\"--json\", \"Output the session and events as JSON\")\n .option(\"--events\", \"List all events instead of just the trailing few\")\n .option(\"--last <n>\", \"Number of trailing events to display (default: 5)\", parsePositiveInt)\n .option(\n \"--full-path\",\n \"Show working_directory as an absolute path instead of repository-relative\",\n )\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: SessionShowOptions) => {\n await runSessionShow(id, options);\n });\n\n session\n .command(\"import\")\n .description(\"Import a session from a JSON file\")\n .requiredOption(\"--format <format>\", \"Input format (currently only 'json')\", parseImportFormat)\n .requiredOption(\"--from <path>\", \"Path to the input JSON file\")\n .option(\"--label <text>\", \"Override the session label\", parseLabelOverride)\n .option(\"--task <task_id>\", \"Override the session task_id\", parseTaskIdOverride)\n .option(\"--dry-run\", \"Validate input only; do not write to disk\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionImportOptions) => {\n await runSessionImport(options);\n });\n\n session\n .command(\"note <session_id>\")\n .description(\"Append a note_added event to an existing session\")\n .option(\"--body <text>\", \"Note body (inline)\", parseNoteBodyOption)\n .option(\"--from-file <path>\", \"Read note body from a file\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (sessionIdInput: string, options: SessionNoteOptions) => {\n await runSessionNote(sessionIdInput, options);\n });\n\n session\n .command(\"rechain\")\n .description(\n \"Add the tamper-evidence hash chain, in place, to imported sessions created before chaining existed\",\n )\n .option(\"--session <id>\", \"Rechain a single session (unique id prefix accepted)\")\n .option(\"--all\", \"Rechain every session in the workspace\")\n .option(\"--dry-run\", \"Compute the outcomes only; do not write\")\n .option(\"--json\", \"Output the outcomes as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: SessionRechainOptions) => {\n await runSessionRechain(options);\n });\n}\n\n/**\n * Programmatic entry for `basou session list` that owns process exit state.\n * Tests targeting only the success path or the thrown error should prefer\n * {@link doRunSessionList}.\n */\nexport async function runSessionList(\n options: SessionListOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner for `session list`. Throws on any failure with a pathless\n * message; native errors are attached as `cause` for verbose surfacing.\n */\nexport async function doRunSessionList(\n options: SessionListOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n // Orchestration is delegated to core's `loadSessionEntries`. To preserve\n // the existing stderr surface (\"Skipped <sid>: <reason>\" and\n // \"Warning: skipped suspect check for <sid>: events.jsonl unreadable\"),\n // map onSkip / onWarning on the CLI side.\n const now = new Date();\n const records: SessionListRecord[] = (\n await loadSessionEntries(paths, {\n now,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSkip: (sid, reason) => printSessionListSkip(sid, reason),\n })\n ).map((entry) => ({\n sessionId: entry.sessionId,\n session: entry.session,\n suspect: entry.suspect,\n suspectReason: entry.suspectReason,\n }));\n\n if (records.length === 0) {\n printNoSessions(options);\n return;\n }\n\n // started_at desc using Date.parse to normalize across timezone offsets;\n // a lexicographic compare would swap two timestamps that point at the same\n // instant when their offsets differ.\n records.sort(\n (a, b) => Date.parse(b.session.session.started_at) - Date.parse(a.session.session.started_at),\n );\n\n const filtered =\n options.status !== undefined\n ? records.filter((r) => r.session.session.status === options.status)\n : records;\n\n if (filtered.length === 0) {\n printNoSessions(options);\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((r) => ({\n ...r.session.session,\n suspect: r.suspect,\n suspect_reason: r.suspectReason,\n })),\n null,\n 2,\n ),\n );\n } else {\n printSessionListText(filtered);\n }\n}\n\n/**\n * Programmatic entry for `basou session show <id>`. See {@link runSessionList}\n * for the split pattern rationale.\n */\nexport async function runSessionShow(\n idInput: string,\n options: SessionShowOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionShow(\n idInput: string,\n options: SessionShowOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionId = await resolveSessionId(paths, idInput);\n\n const sessionDir = join(paths.sessions, sessionId);\n const sessionYamlPath = join(sessionDir, \"session.yaml\");\n let session: Session;\n try {\n const raw = await readYamlFile(sessionYamlPath);\n session = SessionSchema.parse(raw);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(`Session not found: ${idInput}`);\n }\n throw new Error(\"Failed to read session\", { cause: error });\n }\n\n const events = await readAllEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, sessionId),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify({ session: session.session, events }, null, 2));\n return;\n }\n\n const now = ctx.nowProvider?.() ?? new Date();\n printSessionShowText(session, events, options, repositoryRoot, now);\n}\n\nfunction suspectLabel(reason: string | null): string {\n if (reason === \"events_say_ended_but_yaml_running\") return \" ⚠ ended (yaml stale)\";\n if (reason === \"running_no_end_event\") return \" ⚠ no end event\";\n return \"\";\n}\n\nfunction printSessionListText(records: SessionListRecord[]): void {\n // Grow the SHORT_ID column to the first length where every prefix is\n // unique. Without this an ambiguous prefix would copy-paste from the list\n // and fail `resolveSessionId` with \"Ambiguous session id\".\n const shortLen = computeUniquePrefixLen(records.map((r) => r.sessionId));\n const rows = records.map((r) => {\n const sid = sliceShort(r.sessionId, shortLen);\n const status = `${r.session.session.status}${suspectLabel(r.suspectReason)}`;\n const source = r.session.session.source.kind;\n const startedAt = r.session.session.started_at;\n const fileCount = r.session.session.related_files.length;\n const filesSuffix = fileCount > 0 ? ` (${fileCount} files)` : \"\";\n const label = (r.session.session.label ?? \"\") + filesSuffix;\n return { sid, status, source, startedAt, label };\n });\n\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n source: maxLen(\n rows.map((r) => r.source),\n \"SOURCE\".length,\n ),\n startedAt: maxLen(\n rows.map((r) => r.startedAt),\n \"STARTED_AT\".length,\n ),\n };\n\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"SOURCE\", widths.source)} ${pad(\"STARTED_AT\", widths.startedAt)} LABEL`,\n );\n for (const row of rows) {\n console.log(\n `${pad(row.sid, widths.sid)} ${pad(row.status, widths.status)} ${pad(row.source, widths.source)} ${pad(row.startedAt, widths.startedAt)} ${row.label}`,\n );\n }\n}\n\nfunction printSessionShowText(\n session: Session,\n events: Event[],\n options: SessionShowOptions,\n repositoryRoot: string,\n now: Date,\n): void {\n const s = session.session;\n console.log(`Session: ${s.id} (status: ${s.status})`);\n console.log(`Source: ${s.source.kind} (v${s.source.version})`);\n console.log(`Workspace: ${s.workspace_id}`);\n console.log(`Started at: ${s.started_at}`);\n if (s.ended_at !== undefined) {\n console.log(`Ended at: ${s.ended_at}`);\n }\n console.log(`Working dir: ${formatWorkingDir(s.working_directory, repositoryRoot, options)}`);\n const invocationArgs = s.invocation.args.length > 0 ? ` ${s.invocation.args.join(\" \")}` : \"\";\n console.log(`Invocation: ${s.invocation.command}${invocationArgs}`);\n if (s.invocation.exit_code !== null) {\n console.log(`Exit code: ${s.invocation.exit_code}`);\n }\n if (s.label !== undefined) {\n console.log(`Label: ${s.label}`);\n }\n console.log(`Related files: ${formatRelatedFiles(s.related_files)}`);\n\n console.log(\"\");\n console.log(`Events: ${events.length} total`);\n const counts = countByType(events);\n for (const [type, n] of counts) {\n console.log(` ${pad(`${type}:`, 24)} ${n}`);\n }\n\n console.log(\"\");\n console.log(`Work: ${formatSessionWork(session, events, now)}`);\n\n if (events.length === 0) return;\n\n const last = options.last ?? 5;\n const showAll = options.events === true && options.last === undefined;\n const slice = showAll ? events : events.slice(-last);\n const heading = showAll ? \"All events:\" : `Last ${slice.length} events:`;\n console.log(\"\");\n console.log(heading);\n for (const ev of slice) {\n console.log(` ${formatEventLine(ev)}`);\n }\n}\n\n/**\n * One-line work summary for `session show`: output volume + action counts +\n * time proxies, reusing the same per-session computation as `basou stats`.\n * `command n/a (import)` flags sources whose shell time is unrecorded.\n */\nfunction formatSessionWork(session: Session, events: Event[], now: Date): string {\n const w = sessionWorkStatsFromEvents(session.session.id, session.session, events, now);\n const parts: string[] = [];\n if (w.tokens.output > 0) parts.push(`${w.tokens.output.toLocaleString(\"en-US\")} output tokens`);\n parts.push(`${w.commandCount} cmd / ${w.fileChangedCount} files / ${w.decisionCount} dec`);\n const activeBasis = w.activeTimeBasis === \"engaged-turns\" ? \"turns\" : \"events\";\n parts.push(`active ${formatDurationMs(w.activeTimeMs)} (${activeBasis})`);\n if (w.availability.machineActive) {\n parts.push(`machine ${formatDurationMs(w.machineActiveTimeMs)}`);\n }\n parts.push(`span ${formatDurationMs(w.sessionSpanMs)}${w.open ? \" (open)\" : \"\"}`);\n parts.push(\n w.availability.commandTime\n ? `command ${formatDurationMs(w.commandTimeMs)}`\n : \"command n/a (import)\",\n );\n return parts.join(\", \");\n}\n\nfunction formatWorkingDir(\n workingDir: string,\n repositoryRoot: string,\n options: SessionShowOptions,\n): string {\n if (options.fullPath === true) return workingDir;\n\n // v0.3 sanitized sessions write `working_directory` as a relative form\n // (`~/projects/foo`, `src/sub`, `.`, etc.) rather than the absolute\n // path the older write paths used. path.relative against a relative\n // input would silently resolve it against process.cwd and produce\n // nonsense like `<cwd>/~/projects/foo`, so the relative form must be\n // surfaced verbatim. The one literal we collapse is `.`, which means\n // \"the session ran at the repo root\" — same semantic as an absolute\n // workingDir equal to repositoryRoot.\n if (!isAbsolute(workingDir)) {\n if (workingDir === \".\") return \"<repository_root>\";\n return workingDir;\n }\n\n if (workingDir === repositoryRoot) return \"<repository_root>\";\n const rel = relative(repositoryRoot, workingDir);\n if (rel.length === 0 || rel === \".\") return \"<repository_root>\";\n // Outside-repo working directories surface as a `../...` relative path\n // rather than the absolute path so the default-display contract holds\n // even for sessions recorded from a sibling checkout. `--full-path` is\n // the explicit opt-in for the absolute form.\n if (rel.startsWith(\"..\")) return rel;\n return `./${rel}`;\n}\n\nfunction formatRelatedFiles(files: readonly string[]): string {\n if (files.length === 0) return \"0 paths\";\n const head = files.slice(0, 3).join(\", \");\n const remaining = files.length - 3;\n if (remaining <= 0) return `${files.length} paths (${head})`;\n return `${files.length} paths (${head}, ... +${remaining} more)`;\n}\n\nfunction countByType(events: readonly Event[]): Array<[string, number]> {\n const map = new Map<string, number>();\n for (const ev of events) {\n map.set(ev.type, (map.get(ev.type) ?? 0) + 1);\n }\n return [...map.entries()];\n}\n\nfunction formatEventLine(ev: Event): string {\n return `${ev.occurred_at} [${ev.source}] ${ev.type} ${eventVariantSummary(ev)}`;\n}\n\nfunction eventVariantSummary(ev: Event): string {\n switch (ev.type) {\n case \"command_executed\": {\n const argsPart = ev.args.length > 0 ? ` ${ev.args.join(\" \")}` : \"\";\n const exitPart = ev.exit_code === null ? \"exit=signal\" : `exit=${ev.exit_code}`;\n return `${ev.command}${argsPart} (${exitPart}, ${ev.duration_ms}ms)`;\n }\n case \"git_snapshot\":\n return `branch=${ev.branch} dirty=${ev.dirty}`;\n case \"file_changed\":\n return `${ev.change_type} ${ev.path}`;\n case \"session_status_changed\":\n return `${ev.from} -> ${ev.to}`;\n case \"session_started\":\n return \"(start)\";\n case \"session_ended\":\n return ev.exit_code !== undefined ? `exit_code=${ev.exit_code}` : \"(end)\";\n case \"approval_requested\":\n return `${ev.action.kind} risk=${ev.risk_level}`;\n case \"approval_approved\":\n return ev.resolver !== undefined ? `by ${ev.resolver}` : \"(approved)\";\n case \"approval_rejected\":\n return ev.resolver !== undefined ? `by ${ev.resolver}: ${ev.reason}` : ev.reason;\n case \"approval_expired\":\n return `approval=${ev.approval_id}`;\n case \"decision_recorded\":\n return ev.title;\n case \"task_created\":\n return ev.title;\n case \"task_status_changed\":\n return `${ev.from} -> ${ev.to}`;\n case \"task_reconciled\": {\n const createdPart =\n ev.removed_created_in_session !== null ? \"1 created_in_session\" : \"0 created_in_session\";\n return `task ${shortTaskId(ev.task_id)}: cleared ${ev.removed_linked_sessions.length} linked + ${createdPart}`;\n }\n case \"task_linkage_refreshed\": {\n const added = ev.added_linked_sessions.length;\n const removed = ev.removed_linked_sessions.length;\n const final = ev.final_count !== undefined ? ` final=${ev.final_count}` : \"\";\n return `task ${shortTaskId(ev.task_id)}: +${added} / -${removed} linked${final}`;\n }\n case \"task_deleted\":\n return `task ${shortTaskId(ev.task_id)}: ${ev.title} (deleted)`;\n case \"task_archived\":\n return `task ${shortTaskId(ev.task_id)}: ${ev.title} (archived)`;\n case \"note_added\":\n return ev.body.length > 80 ? `${ev.body.slice(0, 77)}...` : ev.body;\n case \"adapter_output\":\n return `${ev.stream} \"${ev.summary}\" raw_ref=${ev.raw_ref}`;\n }\n}\n\nfunction shortId(id: string): string {\n return sliceShort(id, SHORT_ID_BASE_LEN);\n}\n\nfunction shortTaskId(id: string): string {\n if (id.startsWith(TASK_PREFIX)) {\n return id.slice(TASK_PREFIX.length, TASK_PREFIX.length + SHORT_ID_BASE_LEN);\n }\n return id.slice(0, SHORT_ID_BASE_LEN);\n}\n\nfunction sliceShort(id: string, len: number): string {\n if (id.startsWith(SES_PREFIX)) {\n return id.slice(SES_PREFIX.length, SES_PREFIX.length + len);\n }\n return id.slice(0, len);\n}\n\n/**\n * Find the smallest length where every short_id derived from `sessionIds`\n * is unique. Starts at {@link SHORT_ID_BASE_LEN} and grows by 2 chars at a\n * time (mirroring git's automatic abbreviation behaviour). Caps at the full\n * ULID body length so a pathological collision still terminates.\n */\nfunction computeUniquePrefixLen(sessionIds: readonly string[]): number {\n if (sessionIds.length <= 1) return SHORT_ID_BASE_LEN;\n for (let len = SHORT_ID_BASE_LEN; len <= SHORT_ID_MAX_LEN; len += 2) {\n const seen = new Set<string>();\n let collided = false;\n for (const sid of sessionIds) {\n const key = sliceShort(sid, len);\n if (seen.has(key)) {\n collided = true;\n break;\n }\n seen.add(key);\n }\n if (!collided) return len;\n }\n return SHORT_ID_MAX_LEN;\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n\nasync function resolveRepositoryRootForSession(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"import\" | \"note\" | \"rechain\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou session ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\nfunction parsePositiveInt(raw: string): number {\n const n = Number.parseInt(raw, 10);\n if (!Number.isInteger(n) || n < 1 || raw.trim() !== String(n)) {\n throw new Error(`Invalid number: ${raw}`);\n }\n return n;\n}\n\nfunction parseSessionStatus(raw: string): SessionStatus {\n const result = SessionStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid session status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction printNoSessions(options: SessionListOptions): void {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No sessions found.\");\n }\n}\n\n// ----------------------------------------------------------------------------\n// session import\n// ----------------------------------------------------------------------------\n\nexport type SessionImportOptions = {\n format: \"json\";\n from: string;\n label?: string;\n task?: string;\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/**\n * Programmatic entry for `basou session import`. Mirrors the wrapper /\n * pure-runner split used by list / show so tests can target either layer.\n */\nexport async function runSessionImport(\n options: SessionImportOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionImport(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionImport(\n options: SessionImportOptions,\n ctx: SessionContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"import\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const manifest = await readManifest(paths);\n\n const rawBody = await readInputFile(options.from);\n const json = parseJsonStrict(rawBody);\n\n const parsed = SessionImportPayloadSchema.safeParse(json);\n if (!parsed.success) {\n throw new Error(\"Invalid import payload\", { cause: parsed.error });\n }\n\n if (parsed.data.schema_version !== \"0.1.0\") {\n throw new Error(`Unsupported import schema_version: ${parsed.data.schema_version}`);\n }\n\n const importOptions: ImportSessionOptions = { dryRun: options.dryRun === true };\n if (options.label !== undefined) importOptions.labelOverride = options.label;\n if (options.task !== undefined) {\n importOptions.taskIdOverride = await resolveTaskId(paths, options.task);\n }\n\n const result = await importSessionFromJson(paths, manifest, parsed.data, importOptions);\n\n // Path sanitize visibility: the importer rewrites absolute / homedir\n // prefixes inside related_files[] and working_directory so the operator-\n // private layout does not leak into local state. Surface a single-line\n // warning when anything was actually rewritten — silence on zero so the\n // happy path stays quiet. The warning fires for dry-run too so the\n // operator can preview the rewrite before committing.\n const sanitizeReport = result.pathSanitizeReport;\n if (sanitizeReport.relatedFiles > 0 || sanitizeReport.workingDirectoryRewritten) {\n const wdCount = sanitizeReport.workingDirectoryRewritten ? 1 : 0;\n console.error(\n `Imported session: ${sanitizeReport.relatedFiles + wdCount} path(s) sanitized (related_files: ${sanitizeReport.relatedFiles}, working_directory: ${wdCount})`,\n );\n }\n\n printSessionImportResult(options, result);\n}\n\nasync function readInputFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Import source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Import source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read import source\", { cause: error });\n }\n}\n\nfunction parseJsonStrict(body: string): unknown {\n try {\n return JSON.parse(body);\n } catch (error: unknown) {\n throw new Error(\"Failed to parse import JSON\", { cause: error });\n }\n}\n\nfunction parseImportFormat(raw: string): \"json\" {\n if (raw !== \"json\") {\n throw new InvalidArgumentError(`Unsupported format: ${raw}. Valid values: json`);\n }\n return \"json\";\n}\n\nfunction parseLabelOverride(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Label must not be empty\");\n }\n return raw;\n}\n\nfunction parseTaskIdOverride(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Task id is empty\");\n }\n return raw;\n}\n\nfunction printSessionImportResult(\n options: SessionImportOptions,\n result: ImportSessionResult,\n): void {\n const isDry = options.dryRun === true;\n const sid = shortId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n session_id: result.sessionId,\n event_count: result.eventCount,\n dry_run: isDry,\n source: { kind: result.finalSourceKind, version: \"0.1.0\" },\n status: result.finalStatus,\n }),\n );\n return;\n }\n\n if (isDry) {\n console.log(\n `Dry run: would import ${result.eventCount} events into ${sid} (illustrative ID; not reserved, no files written)`,\n );\n return;\n }\n\n console.log(\n `Imported session ${sid} (${result.eventCount} events) from ${basename(options.from)}`,\n );\n}\n\n// ----------------------------------------------------------------------------\n// session note\n// ----------------------------------------------------------------------------\n\nconst NOTE_BODY_PREVIEW_LIMIT = 80;\nconst NOTE_BODY_PREVIEW_HEAD = 77;\n\nexport type SessionNoteOptions = {\n body?: string;\n fromFile?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\n/**\n * Programmatic entry for `basou session note <session_id>`. Appends a single\n * `note_added` event to an existing attachable session. `session.yaml` is\n * deliberately NOT modified.\n */\nexport async function runSessionNote(\n sessionIdInput: string,\n options: SessionNoteOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionNote(sessionIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunSessionNote(\n sessionIdInput: string,\n options: SessionNoteOptions,\n ctx: SessionContext,\n): Promise<void> {\n const hasBody = options.body !== undefined;\n const hasFromFile = options.fromFile !== undefined;\n if (!hasBody && !hasFromFile) {\n throw new Error(\"Provide --body or --from-file\");\n }\n if (hasBody && hasFromFile) {\n throw new Error(\"--body and --from-file are mutually exclusive\");\n }\n // The stdin pipe path is not supported in v0.1. Surface a dedicated\n // pathless error before any disk I/O so the failure mode is obvious.\n if (hasFromFile && options.fromFile === \"-\") {\n throw new Error(\"--from-file - (stdin) is not supported in v0.1\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"note\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionId = await resolveSessionId(paths, sessionIdInput);\n\n const body = hasBody ? (options.body as string) : await readNoteFile(options.fromFile as string);\n if (body.length === 0) {\n throw new Error(\"Note body is empty\");\n }\n\n const occurredAt = new Date().toISOString();\n const sesId = sessionId as `ses_${string}`;\n\n // Per-session lock guards the events.jsonl append + status read window\n // against a concurrent writer (decision record / task attach / another\n // session note on the same id). The lock is the caller's responsibility:\n // appendEventToExistingSession holds no lock so we can compose larger\n // critical sections (e.g. attach-flavoured task commands) under the same\n // lock without re-entrant deadlock.\n const sessionLock = await acquireLock(paths, \"session\", sesId);\n let result: Awaited<ReturnType<typeof appendEventToExistingSession>>;\n try {\n result = await appendEventToExistingSession({\n paths,\n sessionId: sesId,\n eventBuilder: (eventId) =>\n ({\n schema_version: \"0.1.0\",\n id: eventId,\n session_id: sesId,\n occurred_at: occurredAt,\n source: \"local-cli\",\n type: \"note_added\",\n body,\n }) as Event,\n });\n } finally {\n await sessionLock.release();\n }\n\n printSessionNoteResult(options, sessionId, result.eventId, result.sessionStatus, body);\n}\n\nasync function readNoteFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Note source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Note source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read note source\", { cause: error });\n }\n}\n\nfunction parseNoteBodyOption(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"--body must not be empty\");\n }\n return raw;\n}\n\nfunction printSessionNoteResult(\n options: SessionNoteOptions,\n sessionId: string,\n eventId: string,\n sessionStatus: SessionStatus,\n body: string,\n): void {\n const sid = shortId(sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n event_id: eventId,\n session_id: sessionId,\n session_status: sessionStatus,\n body_length: body.length,\n }),\n );\n return;\n }\n const preview =\n body.length > NOTE_BODY_PREVIEW_LIMIT ? `${body.slice(0, NOTE_BODY_PREVIEW_HEAD)}...` : body;\n console.log(`Added note to session ${sid} (${sessionStatus}): ${preview}`);\n}\n\n/**\n * Programmatic entry for `basou session rechain` that owns process exit\n * state. Tests should prefer {@link doRunSessionRechain} for the success\n * path.\n */\nexport async function runSessionRechain(\n options: SessionRechainOptions,\n ctx: SessionContext = {},\n): Promise<void> {\n try {\n await doRunSessionRechain(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Runner for `session rechain`. A WRITE command, so an explicit selector is\n * required (`--session <id>` or `--all`). Per-session outcomes are collected\n * into rows; an I/O failure on one session becomes an `error` row and the\n * sweep CONTINUES, so one unreadable directory cannot hide the rest of the\n * report. Exit is non-zero when any session was found `tampered` or errored\n * operationally; plain skips and successes exit 0.\n */\nexport async function doRunSessionRechain(\n options: SessionRechainOptions,\n ctx: SessionContext,\n): Promise<void> {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n if (options.session === undefined && options.all !== true) {\n throw new Error(\"Specify --session <id> or --all\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForSession(cwd, \"rechain\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionIds =\n options.session !== undefined\n ? [await resolveSessionId(paths, options.session)]\n : await enumerateSessionDirs(paths);\n\n const dryRun = options.dryRun === true;\n const rows: RechainRow[] = [];\n for (const sessionId of sessionIds) {\n let outcome: RechainResult;\n try {\n outcome = await rechainSessionInPlace(paths, sessionId, { dryRun });\n } catch (error: unknown) {\n rows.push({\n session_id: sessionId,\n status: \"error\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n continue;\n }\n if (outcome.status === \"rechained\") {\n rows.push({ session_id: sessionId, status: \"rechained\", event_count: outcome.eventCount });\n } else {\n rows.push({ session_id: sessionId, status: \"skipped\", reason: outcome.reason });\n }\n }\n\n const tamperedCount = rows.filter((r) => r.reason === \"tampered\").length;\n const errorCount = rows.filter((r) => r.status === \"error\").length;\n\n if (options.json === true) {\n console.log(JSON.stringify(rows, null, 2));\n } else {\n for (const row of rows) {\n console.log(`${row.session_id} ${renderRechainRow(row, dryRun)}`);\n }\n const rechained = rows.filter((r) => r.status === \"rechained\").length;\n const skipped = rows.filter((r) => r.status === \"skipped\").length;\n console.log(\n `Sessions: ${rows.length} total — ${rechained} ${dryRun ? \"would be rechained\" : \"rechained\"}, ` +\n `${skipped} skipped, ${errorCount} errors`,\n );\n }\n\n // A tampered session or an operational failure must be visible in the\n // exit status; ordinary skips (already chained / live / empty) are not\n // failures.\n if (tamperedCount > 0 || errorCount > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction renderRechainRow(row: RechainRow, dryRun: boolean): string {\n switch (row.status) {\n case \"rechained\":\n return `${dryRun ? \"would rechain\" : \"rechained\"} (${row.event_count} events)`;\n case \"skipped\":\n return row.reason === \"tampered\"\n ? \"skipped (TAMPERED — inspect with 'basou verify')\"\n : `skipped (${row.reason})`;\n case \"error\":\n return `error (${row.message})`;\n }\n}\n","/**\n * Re-export the shared duration formatter from `@basou/core`. It lives in core\n * so the report renderer (also in core) and the CLI surfaces (`basou stats`,\n * `basou session show`) all format durations identically. Kept as a thin\n * re-export so existing CLI imports of `../lib/format-duration.js` stay valid.\n */\nexport { formatDurationMs } from \"@basou/core\";\n","import {\n assertBasouRootSafe,\n basouPaths,\n computeWorkStats,\n findErrorCode,\n resolveRepositoryRoot,\n type SourceWorkStats,\n type WorkStatsResult,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { formatDurationMs } from \"../lib/format-duration.js\";\n\nexport type StatsOptions = {\n json?: boolean;\n bySource?: boolean;\n byDay?: boolean;\n verbose?: boolean;\n};\n\nexport type StatsContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/**\n * Register `basou stats`: an honest \"how much did the AI work\" report. It\n * leads with output VOLUME (tokens + action counts), which is the most direct\n * signal, and reports TIME measures as labeled proxies.\n */\nexport function registerStatsCommand(program: Command): void {\n program\n .command(\"stats\")\n .description(\"Report how much the AI worked (output volume + time proxies) across sessions\")\n .option(\"--by-source\", \"Break the totals down by session source kind\")\n .option(\"--by-day\", \"Break billable time and volume down by calendar day\")\n .option(\"--json\", \"Output the full stats as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: StatsOptions) => {\n await runStats(options);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunStats}. */\nexport async function runStats(options: StatsOptions, ctx: StatsContext = {}): Promise<void> {\n try {\n await doRunStats(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** Pure runner: resolve the workspace, aggregate, and print (text or JSON). */\nexport async function doRunStats(options: StatsOptions, ctx: StatsContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForStats(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const now = ctx.nowProvider?.() ?? new Date();\n const result = await computeWorkStats({\n paths,\n now,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n printStatsText(result, options.bySource === true, options.byDay === true);\n}\n\nfunction printStatsText(result: WorkStatsResult, bySource: boolean, byDay: boolean): void {\n const t = result.totals;\n const statusPart =\n result.byStatus.length > 0\n ? ` (${result.byStatus.map((s) => `${s.status} ${s.count}`).join(\", \")})`\n : \"\";\n console.log(`Sessions: ${t.sessionCount}${statusPart}`);\n\n console.log(\"\");\n console.log(\"Volume (what the AI produced):\");\n const tokenSessions = result.sessions.filter((s) => s.availability.tokens).length;\n const tokenCaveat =\n t.tokensAvailable && tokenSessions < t.sessionCount\n ? ` (token data on ${tokenSessions} of ${t.sessionCount} sessions)`\n : t.tokensAvailable\n ? \"\"\n : \" (no token data captured; re-import to backfill)\";\n console.log(` Output tokens: ${formatInt(t.tokens.output)}${tokenCaveat}`);\n if (t.tokens.reasoning > 0) {\n console.log(` Reasoning tokens: ${formatInt(t.tokens.reasoning)} (Codex)`);\n }\n console.log(\n ` Actions: ${t.commandCount} commands, ${t.fileChangedCount} files, ${t.decisionCount} decisions`,\n );\n\n console.log(\"\");\n console.log(\"Time (proxies for human harness labor; active = billing primary):\");\n const turnSessions = result.sessions.filter((s) => s.activeTimeBasis === \"engaged-turns\").length;\n const basisCaveat =\n turnSessions === t.sessionCount\n ? \"engaged turns\"\n : turnSessions === 0\n ? \"event stream; re-import to capture conversation\"\n : `engaged turns on ${turnSessions} of ${t.sessionCount} sessions, event stream on the rest`;\n console.log(\n ` Billable active: ${formatDurationMs(t.billableActiveTimeMs)} (union; ${basisCaveat}; idle gaps > 5m excluded; tz ${result.timeZone})`,\n );\n if (t.activeTimeMs !== t.billableActiveTimeMs) {\n console.log(\n ` Summed: ${formatDurationMs(t.activeTimeMs)} (per-session sum; concurrent sessions double-counted)`,\n );\n }\n if (t.machineActiveAvailable) {\n const machineSessions = result.sessions.filter((s) => s.availability.machineActive).length;\n console.log(\n ` Model working: ${formatDurationMs(t.machineActiveTimeMs)} (model compute, subset of active; Codex turn duration on ${machineSessions} of ${t.sessionCount} sessions; summed, not wall-clock-deduped)`,\n );\n }\n const openPart = t.openSessionCount > 0 ? `; ${t.openSessionCount} open counted to now` : \"\";\n console.log(\n ` Span: ${formatDurationMs(t.sessionSpanMs)} (total elapsed${openPart})`,\n );\n const cmdCaveat = t.commandTimeReliable\n ? \"\"\n : \"; some sessions (e.g. claude-code-import) report 0 shell time\";\n console.log(\n ` Command: ${formatDurationMs(t.commandTimeMs)} (real shell execution${cmdCaveat})`,\n );\n\n if (bySource && result.bySource.length > 0) {\n console.log(\"\");\n console.log(\"By source:\");\n for (const s of result.bySource) {\n console.log(` ${s.sourceKind}: ${describeSource(s)}`);\n }\n }\n\n if (byDay && result.byDay.length > 0) {\n console.log(\"\");\n console.log(\"By day (billable time x volume):\");\n for (const d of result.byDay) {\n const machine =\n d.machineActiveTimeMs > 0 ? ` (model ${formatDurationMs(d.machineActiveTimeMs)})` : \"\";\n console.log(\n ` ${d.date}: ${formatDurationMs(d.billableActiveTimeMs)} active${machine}, ${formatInt(d.tokens.output)} out tok, ${d.commandCount} cmd / ${d.fileChangedCount} files / ${d.decisionCount} dec`,\n );\n }\n }\n}\n\nfunction describeSource(s: SourceWorkStats): string {\n const cmd = s.commandTimeReliable ? formatDurationMs(s.commandTimeMs) : \"n/a\";\n const tokens = s.tokensAvailable ? `${formatInt(s.tokens.output)} out tok` : \"no tokens\";\n const machine = s.machineActiveAvailable\n ? `, model ${formatDurationMs(s.machineActiveTimeMs)}`\n : \"\";\n return `${s.sessionCount} sessions, ${tokens}, active ${formatDurationMs(s.activeTimeMs)}${machine}, command ${cmd}`;\n}\n\n/** \"1,234,567\" — thousands-separated, fixed en-US so output is deterministic. */\nfunction formatInt(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\nasync function resolveRepositoryRootForStats(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou stats'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n buildStatusSnapshot,\n findErrorCode,\n type Manifest,\n readManifest,\n resolveRepositoryRoot,\n type StatusSnapshot,\n writeStatus,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type StatusOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type StatusContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/**\n * Register `basou status` on a commander program. The command outputs a\n * human-readable summary by default, or a JSON document when `--json` is\n * given. In both modes `.basou/status.json` is rewritten as a side effect.\n */\nexport function registerStatusCommand(program: Command): void {\n program\n .command(\"status\")\n .description(\"Show the current Basou workspace status\")\n .option(\"--json\", \"Output the snapshot as JSON to stdout\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: StatusOptions) => {\n await runStatus(options);\n });\n}\n\n/**\n * Programmatic entry that mutates process state (`exitCode`, stderr).\n * Exported for tests, but tests should prefer {@link doRunStatus} when they\n * only need to assert on success behaviour or thrown errors.\n */\nexport async function runStatus(options: StatusOptions, ctx: StatusContext = {}): Promise<void> {\n try {\n await doRunStatus(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolves inputs, performs the status snapshot, writes\n * `status.json`, and prints output. On any failure throws an Error whose\n * `message` is pathless; native fs / parse errors are attached as `cause`.\n * Exported for tests so they can assert on thrown errors without touching\n * `process.exitCode`.\n */\nexport async function doRunStatus(options: StatusOptions, ctx: StatusContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForStatus(cwd);\n const paths = basouPaths(repositoryRoot);\n\n // Pre-condition: refuse to operate on a swapped/non-directory .basou root\n // before we ever touch a file. Treat ENOENT (root absent) the same way as\n // a missing manifest below — both mean \"workspace not initialized\".\n try {\n await assertBasouRootSafe(paths.root);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n\n let manifest: Manifest;\n try {\n manifest = await readManifest(paths);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n // ZodError's `message` echoes invalid input values verbatim, which can\n // include path-like strings if a user-edited manifest contains them.\n // Wrap in a fixed pathless message and surface only the cause's\n // constructor name in verbose mode via the shared renderCliError helper.\n throw new Error(\"Failed to read workspace manifest\", { cause: error });\n }\n\n const snapshot = await buildStatusSnapshot({ manifest, paths });\n await writeStatus(paths, snapshot);\n\n if (options.json === true) {\n console.log(JSON.stringify(snapshot, null, 2));\n } else {\n renderTextStatus(snapshot);\n }\n}\n\nfunction renderTextStatus(s: StatusSnapshot): void {\n console.log(`Workspace: ${s.workspace.name} (${s.workspace.id})`);\n // The label changed from \"Basou version\" to \"Spec version\" in v0.3.1\n // because the field tracks the workspace data-format spec\n // (`basou_version` literal-locked to \"0.1.0\") and was repeatedly\n // mistaken for the release version returned by `basou --version`. The\n // wire payload field name (= `workspace.basou_version`) stays the same\n // so JSON consumers are unaffected; only the human-readable label\n // moves.\n console.log(`Spec version: ${s.workspace.basou_version}`);\n console.log(`Generated at: ${s.generated_at}`);\n const dp = s.directories_present;\n const total = Object.keys(dp).length;\n const present = Object.values(dp).filter((v) => v === true).length;\n console.log(`Subdirectories present: ${present}/${total}`);\n}\n\n/**\n * Wrap the core git capability so the CLI surfaces the command-specific\n * \"Run 'git init' first, then re-run 'basou status'.\" suffix while the\n * capability layer remains command-agnostic.\n */\nasync function resolveRepositoryRootForStatus(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou status'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n archiveTask,\n assertBasouRootSafe,\n basouPaths,\n createTaskWithEvent,\n deleteTask,\n type Event,\n editTask,\n enumerateArchivedTaskIds,\n findErrorCode,\n loadSessionEntries,\n loadTaskEntries,\n type PrefixedId,\n prefixedUlid,\n type ReconcileFailure,\n type ReconcileResult,\n type RefreshLinkageResult,\n readManifest,\n readTaskFile,\n readTaskFileWithArchiveFallback,\n reconcileAllTasks,\n reconcileTask,\n refreshTaskLinkedSessions,\n replayEvents,\n resolveRepositoryRoot,\n resolveSessionId,\n resolveTaskId,\n type SessionEntry,\n type SessionStatus,\n type TaskDocument,\n type TaskReconciledEvent,\n type TaskStatus,\n TaskStatusSchema,\n TaskWriteAfterEventError,\n updateTaskStatusWithEvent,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport {\n type ErrorClassifier,\n failedToFinalizeClassifier,\n isVerbose,\n printReplayWarning,\n printTaskSkip,\n renderCliError,\n shortSessionId,\n shortTaskId,\n} from \"../lib/error-render.js\";\n\nconst STATUS_VALUES = TaskStatusSchema.options;\n\n// ============================================================================\n// Public registration\n// ============================================================================\n\nexport type TaskNewOptions = {\n title: string;\n label?: string;\n status?: TaskStatus;\n /**\n * ISO-8601 timestamp written into `task.md.updated_at` when status is a\n * terminal value (done / cancelled). Lets the operator backdate a\n * retroactively-recorded completed task so `task.md` reflects the\n * actual completion moment while `events.jsonl` keeps recording time.\n * Rejected (exit 1) when supplied with a non-terminal status.\n */\n completedAt?: string;\n session?: string;\n description?: string;\n fromFile?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskListOptions = {\n status?: TaskStatus;\n includeArchived?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskShowOptions = {\n json?: boolean;\n events?: boolean;\n last?: number;\n verbose?: boolean;\n};\n\nexport type TaskStatusOptions = {\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskReconcileOptions = {\n task?: string;\n write?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskRefreshLinkageOptions = {\n write?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskEditOptions = {\n title?: string;\n status?: TaskStatus;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskDeleteOptions = {\n yes?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskArchiveOptions = {\n yes?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type TaskContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\nexport function registerTaskCommand(program: Command): void {\n const task = program\n .command(\"task\")\n .description(\"Manage Basou tasks (purpose units that span sessions)\");\n\n task\n .command(\"new\")\n .description(\"Create a new task and fire a task_created event\")\n .requiredOption(\"--title <text>\", \"Task title\", parseTitle)\n .option(\"--label <text>\", \"Optional label for the task\", parseLabel)\n .option(\n \"--status <status>\",\n `Initial status (one of: ${STATUS_VALUES.join(\", \")}; default planned). For done/cancelled the orchestrator also emits a task_status_changed event so the audit trail records the implicit transition.`,\n parseInitialTaskStatus,\n )\n .option(\n \"--completed-at <iso>\",\n \"ISO-8601 timestamp to record as the task's updated_at when --status is done or cancelled (rejected otherwise)\",\n parseIsoTimestampOption,\n )\n .option(\"--session <session_id>\", \"Attach to existing session; otherwise ad-hoc\")\n .option(\"--description <text>\", \"Task description body (inline)\", parseDescriptionOption)\n .option(\"--from-file <path>\", \"Read description body from a file\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: TaskNewOptions) => {\n await runTaskNew(options);\n });\n\n task\n .command(\"list\")\n .description(\"List tasks in the current workspace (newest first)\")\n .option(\n \"--status <status>\",\n `Filter by task status (one of: ${STATUS_VALUES.join(\", \")})`,\n parseTaskStatusFilter,\n )\n .option(\"--include-archived\", \"Also list tasks under .basou/tasks/archive/ (hidden by default)\")\n .option(\"--json\", \"Output the list as a JSON array\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: TaskListOptions) => {\n await runTaskList(options);\n });\n\n task\n .command(\"show <task_id>\")\n .description(\"Show a task with its metadata, linked sessions, and events\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--events\", \"Show all related events instead of trailing few\")\n .option(\"--last <n>\", \"Number of trailing events to display (default: 5)\", parsePositiveInt)\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (id: string, options: TaskShowOptions) => {\n await runTaskShow(id, options);\n });\n\n task\n .command(\"status <task_id> <new_status>\")\n .description(\"Change task status and fire a task_status_changed event\")\n .option(\"--session <session_id>\", \"Attach to existing session; otherwise ad-hoc\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, newStatusInput: string, options: TaskStatusOptions) => {\n await runTaskStatus(taskIdInput, newStatusInput, options);\n });\n\n task\n .command(\"reconcile\")\n .description(\n \"Dry-run audit of task session references; use --write to repair broken refs. Forward sync (events -> task.md linked_sessions) is out of scope.\",\n )\n .option(\"--task <task_id>\", \"Limit to a single task (otherwise scan all)\")\n .option(\"--write\", \"Apply repairs (default: dry-run)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes and broken session_id values\")\n .action(async (options: TaskReconcileOptions) => {\n await runTaskReconcile(options);\n });\n\n task\n .command(\"refresh-linkage <task_id>\")\n .description(\n \"Re-derive task.md linked_sessions[] from session.yaml.task_id matches across the workspace (forward sync events -> task.md). Dry-run default; use --write to apply.\",\n )\n .option(\"--write\", \"Apply the refresh (default: dry-run)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskRefreshLinkageOptions) => {\n await runTaskRefreshLinkage(taskIdInput, options);\n });\n\n task\n .command(\"edit <task_id>\")\n .description(\n \"Update --title and/or --status on an existing task. Status changes fire a task_status_changed event; title changes update task.md only (no event).\",\n )\n .option(\"--title <text>\", \"New title (must be non-empty)\", parseTitle)\n .option(\n \"--status <status>\",\n `New status (one of: ${STATUS_VALUES.join(\", \")}); routed through STATUS_TRANSITIONS so only valid edges are accepted`,\n parseInitialTaskStatus,\n )\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskEditOptions) => {\n await runTaskEdit(taskIdInput, options);\n });\n\n task\n .command(\"delete <task_id>\")\n .description(\n \"Hard-delete a task.md file and fire a task_deleted event. Requires confirmation by default; use --yes to skip the prompt.\",\n )\n .option(\"--yes\", \"Skip the confirmation prompt (required when stdin is not a TTY)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskDeleteOptions) => {\n await runTaskDelete(taskIdInput, options);\n });\n\n task\n .command(\"archive <task_id>\")\n .description(\n \"Move task.md into .basou/tasks/archive/ and fire a task_archived event. Requires confirmation by default; use --yes to skip the prompt.\",\n )\n .option(\"--yes\", \"Skip the confirmation prompt (required when stdin is not a TTY)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (taskIdInput: string, options: TaskArchiveOptions) => {\n await runTaskArchive(taskIdInput, options);\n });\n}\n\n// ============================================================================\n// task new\n// ============================================================================\n\nexport async function runTaskNew(options: TaskNewOptions, ctx: TaskContext = {}): Promise<void> {\n try {\n await doRunTaskNew(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskNew(options: TaskNewOptions, ctx: TaskContext): Promise<void> {\n if (options.description !== undefined && options.fromFile !== undefined) {\n throw new Error(\"--description and --from-file are mutually exclusive\");\n }\n if (options.fromFile === \"-\") {\n throw new Error(\"--from-file - (stdin) is not supported in v0.1\");\n }\n\n const initialStatus = options.status ?? \"planned\";\n // `--completed-at` only makes sense paired with a terminal status. Catching\n // the mismatch up front avoids ambiguity about whether the override would\n // still be honored on a planned/in_progress task (= it wouldn't).\n if (options.completedAt !== undefined && !isTerminalStatusForCli(initialStatus)) {\n throw new Error(\"--completed-at requires --status done or cancelled\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"new\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const description =\n options.description !== undefined\n ? options.description\n : options.fromFile !== undefined\n ? await readDescriptionFile(options.fromFile)\n : \"\";\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const taskId = prefixedUlid(\"task\");\n\n if (options.session !== undefined) {\n const sessionId = (await resolveSessionId(paths, options.session)) as PrefixedId<\"ses\">;\n const result = await createTaskWithEvent({\n mode: \"attach\",\n paths,\n occurredAt,\n sessionId,\n taskId,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n initialStatus,\n description,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n });\n printTaskNewResult(options, {\n mode: \"attached\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n status: initialStatus,\n occurredAt,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n descriptionLength: description.length,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const result = await createTaskWithEvent({\n mode: \"ad-hoc\",\n paths,\n manifest,\n occurredAt,\n taskId,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n initialStatus,\n description,\n workingDirectory: repositoryRoot,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n });\n printTaskNewResult(options, {\n mode: \"ad-hoc\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n title: options.title,\n ...(options.label !== undefined ? { label: options.label } : {}),\n status: initialStatus,\n occurredAt,\n ...(options.completedAt !== undefined ? { completedAt: options.completedAt } : {}),\n descriptionLength: description.length,\n });\n}\n\nfunction isTerminalStatusForCli(status: TaskStatus): boolean {\n return status === \"done\" || status === \"cancelled\";\n}\n\ntype TaskNewPrint = {\n mode: \"ad-hoc\" | \"attached\";\n taskId: string;\n eventId: string;\n sessionId: string;\n sessionStatus: SessionStatus;\n title: string;\n label?: string;\n status: TaskStatus;\n occurredAt: string;\n completedAt?: string;\n descriptionLength: number;\n};\n\nfunction printTaskNewResult(options: TaskNewOptions, result: TaskNewPrint): void {\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n title: result.title,\n label: result.label ?? null,\n status: result.status,\n recorded_at: result.occurredAt,\n completed_at: result.completedAt ?? null,\n description_length: result.descriptionLength,\n }),\n );\n return;\n }\n const shortSes = shortSessionId(result.sessionId);\n const created =\n result.mode === \"ad-hoc\"\n ? `Created ${result.taskId} in ad-hoc session ${shortSes}`\n : `Created ${result.taskId} in session ${shortSes} (${result.sessionStatus})`;\n console.log(created);\n console.log(` Title: ${result.title}`);\n // For terminal initial statuses surface both the recording time (= the\n // ad-hoc session timestamp = now) and the supplied completion time so the\n // operator can tell at a glance that the audit trail (events.jsonl)\n // reflects the former while task.md.updated_at reflects the latter.\n if (result.completedAt !== undefined) {\n console.log(\n ` Status: ${result.status} (recorded at ${result.occurredAt}, completed at ${result.completedAt})`,\n );\n } else {\n console.log(` Status: ${result.status}`);\n }\n console.log(` Label: ${result.label ?? \"(none)\"}`);\n}\n\n// ============================================================================\n// task list\n// ============================================================================\n\nexport async function runTaskList(options: TaskListOptions, ctx: TaskContext = {}): Promise<void> {\n try {\n await doRunTaskList(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskList(options: TaskListOptions, ctx: TaskContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"list\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const entries = await loadTaskEntries(paths, {\n onSkip: (id, reason) => printTaskSkip(id, reason),\n });\n // Archive entries are read from `<paths.tasks>/archive/` directly (no\n // dedicated loader yet — call sites are rare). Marshalling them through a\n // separate scan keeps the default `task list` path fast (no extra readdir\n // when the operator does not opt in).\n const archivedEntries: { doc: TaskDocument; archived: true }[] = [];\n if (options.includeArchived === true) {\n const archivedIds = await enumerateArchivedTaskIds(paths);\n for (const id of archivedIds) {\n try {\n const { doc } = await readTaskFileWithArchiveFallback(paths, id);\n archivedEntries.push({ doc, archived: true });\n } catch {\n // Skip unreadable archive entries — keep the list output usable\n // when one file is corrupt rather than aborting the run.\n }\n }\n }\n const combined = [...entries, ...archivedEntries.map((a) => a.doc)];\n const archivedIdSet = new Set(archivedEntries.map((a) => a.doc.task.task.id));\n // loadTaskEntries returns asc by created_at; reverse for newest-first display.\n const ordered = [...combined].sort(\n (a, b) => Date.parse(b.task.task.created_at) - Date.parse(a.task.task.created_at),\n );\n const filtered =\n options.status !== undefined\n ? ordered.filter((t) => t.task.task.status === options.status)\n : ordered;\n\n if (filtered.length === 0) {\n if (options.json === true) {\n console.log(\"[]\");\n } else {\n console.log(\"No tasks found.\");\n }\n return;\n }\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n filtered.map((t) => ({\n task_id: t.task.task.id,\n title: t.task.task.title,\n label: t.task.task.label ?? null,\n status: t.task.task.status,\n created_at: t.task.task.created_at,\n updated_at: t.task.task.updated_at,\n linked_session_count: t.task.task.linked_sessions.length,\n archived: archivedIdSet.has(t.task.task.id),\n })),\n null,\n 2,\n ),\n );\n return;\n }\n printTaskListText(filtered, archivedIdSet);\n}\n\nfunction printTaskListText(\n entries: ReadonlyArray<TaskDocument>,\n archivedIds: ReadonlySet<string>,\n): void {\n const rows = entries.map((t) => ({\n sid: shortTaskId(t.task.task.id),\n status: t.task.task.status,\n createdAt: t.task.task.created_at,\n label: t.task.task.label ?? \"(none)\",\n // Mark archived entries with a leading [archived] tag so the operator\n // can distinguish them from live tasks when --include-archived is on.\n title: archivedIds.has(t.task.task.id) ? `[archived] ${t.task.task.title}` : t.task.task.title,\n linkedCount: String(t.task.task.linked_sessions.length),\n }));\n const widths = {\n sid: maxLen(\n rows.map((r) => r.sid),\n \"SHORT_ID\".length,\n ),\n status: maxLen(\n rows.map((r) => r.status),\n \"STATUS\".length,\n ),\n createdAt: maxLen(\n rows.map((r) => r.createdAt),\n \"CREATED_AT\".length,\n ),\n linkedCount: maxLen(\n rows.map((r) => r.linkedCount),\n \"LINKS\".length,\n ),\n label: maxLen(\n rows.map((r) => r.label),\n \"LABEL\".length,\n ),\n };\n console.log(\n `${pad(\"SHORT_ID\", widths.sid)} ${pad(\"STATUS\", widths.status)} ${pad(\"CREATED_AT\", widths.createdAt)} ${pad(\"LINKS\", widths.linkedCount)} ${pad(\"LABEL\", widths.label)} TITLE`,\n );\n for (const r of rows) {\n console.log(\n `${pad(r.sid, widths.sid)} ${pad(r.status, widths.status)} ${pad(r.createdAt, widths.createdAt)} ${pad(r.linkedCount, widths.linkedCount)} ${pad(r.label, widths.label)} ${r.title}`,\n );\n }\n}\n\n// ============================================================================\n// task show\n// ============================================================================\n\nexport async function runTaskShow(\n idInput: string,\n options: TaskShowOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskShow(idInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskShow(\n idInput: string,\n options: TaskShowOptions,\n ctx: TaskContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"show\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const taskId = await resolveTaskId(paths, idInput, { includeArchived: true });\n const { doc, archived } = await readTaskFileWithArchiveFallback(paths, taskId);\n\n // Collect events related to this task by replaying every session's\n // events.jsonl and filtering by task_id. Could be optimised via an\n // index.json cache later; v0.1 accepts the linear scan.\n const sessions = await loadSessionEntries(paths, { now: new Date() });\n const events: Event[] = [];\n const linkedSessionIds = new Set<string>(doc.task.task.linked_sessions);\n // Replay warnings (malformed JSON / schema violations / partial trailing\n // lines) and unreadable events.jsonl files must reach the operator so\n // silent gaps in the events history don't go unnoticed.\n for (const s of sessions) {\n const sessionDir = join(paths.sessions, s.sessionId);\n try {\n for await (const ev of replayEvents(sessionDir, {\n onWarning: (w) => printReplayWarning(w, s.sessionId),\n })) {\n if (\n (ev.type === \"task_created\" ||\n ev.type === \"task_status_changed\" ||\n ev.type === \"task_reconciled\" ||\n ev.type === \"task_linkage_refreshed\" ||\n ev.type === \"task_deleted\" ||\n ev.type === \"task_archived\") &&\n ev.task_id === taskId\n ) {\n events.push(ev);\n linkedSessionIds.add(s.sessionId);\n }\n }\n } catch (error: unknown) {\n // I/O failure (events.jsonl unreadable). The renderer still works on\n // task.md metadata alone, but the operator must know events from this\n // session are missing from the aggregate.\n const short = shortSessionId(s.sessionId);\n const suffix = error instanceof Error ? `: ${error.message}` : \"\";\n console.error(`Warning: events unavailable for session ${short}${suffix}`);\n }\n }\n events.sort((a, b) => Date.parse(a.occurred_at) - Date.parse(b.occurred_at));\n\n if (options.json === true) {\n console.log(\n JSON.stringify(\n {\n task: doc.task.task,\n body: doc.body,\n linked_sessions: [...linkedSessionIds],\n archived,\n events,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n printTaskShowText(doc, [...linkedSessionIds], events, sessions, options, archived);\n}\n\nfunction printTaskShowText(\n doc: TaskDocument,\n linkedSessions: string[],\n events: ReadonlyArray<Event>,\n sessionEntries: ReadonlyArray<SessionEntry>,\n options: TaskShowOptions,\n archived: boolean,\n): void {\n const t = doc.task.task;\n const archivedTag = archived ? \" [archived]\" : \"\";\n console.log(`Task: ${t.id}${archivedTag}`);\n console.log(` Title: ${t.title}`);\n console.log(` Status: ${t.status}`);\n console.log(` Label: ${t.label ?? \"(none)\"}`);\n console.log(` Created at: ${t.created_at}`);\n console.log(` Updated at: ${t.updated_at}`);\n console.log(` Workspace: ${t.workspace_id}`);\n console.log(\"\");\n console.log(`Linked sessions (${linkedSessions.length}):`);\n const sessionStatusMap = new Map<string, string>(\n sessionEntries.map((s) => [s.sessionId, s.session.session.status]),\n );\n for (const sid of linkedSessions) {\n const status = sessionStatusMap.get(sid) ?? \"unknown\";\n console.log(` ${sid} (${status})`);\n }\n console.log(\"\");\n console.log(\"Description:\");\n if (doc.body.length === 0) {\n console.log(\"(no description)\");\n } else {\n console.log(doc.body);\n }\n console.log(\"\");\n console.log(`Events: ${events.length} total`);\n if (events.length === 0) return;\n const showAll = options.events === true && options.last === undefined;\n const last = options.last ?? 5;\n const slice = showAll ? events : events.slice(-last);\n const heading = showAll ? \"All events:\" : `Last ${slice.length} events:`;\n console.log(\"\");\n console.log(heading);\n const verbose = isVerbose(options);\n for (const ev of slice) {\n console.log(` ${formatTaskEvent(ev)}`);\n if (verbose && ev.type === \"task_reconciled\") {\n for (const line of formatTaskReconciledDetails(ev)) {\n console.log(line);\n }\n }\n }\n}\n\nfunction formatTaskEvent(ev: Event): string {\n if (ev.type === \"task_created\") {\n return `${ev.occurred_at} [${ev.source}] task_created ${ev.title}`;\n }\n if (ev.type === \"task_status_changed\") {\n return `${ev.occurred_at} [${ev.source}] task_status_changed ${ev.from} -> ${ev.to}`;\n }\n if (ev.type === \"task_reconciled\") {\n const removedCount =\n (ev.removed_created_in_session !== null ? 1 : 0) + ev.removed_linked_sessions.length;\n return `${ev.occurred_at} [${ev.source}] task_reconciled ${removedCount} broken ref${removedCount === 1 ? \"\" : \"s\"} (use -v for details)`;\n }\n if (ev.type === \"task_linkage_refreshed\") {\n const added = ev.added_linked_sessions.length;\n const removed = ev.removed_linked_sessions.length;\n const finalPart = ev.final_count !== undefined ? `, final=${ev.final_count}` : \"\";\n return `${ev.occurred_at} [${ev.source}] task_linkage_refreshed +${added} / -${removed}${finalPart}`;\n }\n if (ev.type === \"task_deleted\") {\n return `${ev.occurred_at} [${ev.source}] task_deleted ${ev.title}`;\n }\n if (ev.type === \"task_archived\") {\n return `${ev.occurred_at} [${ev.source}] task_archived ${ev.title}`;\n }\n return `${ev.occurred_at} [${ev.source}] ${ev.type}`;\n}\n\nfunction formatTaskReconciledDetails(ev: TaskReconciledEvent): string[] {\n const lines: string[] = [];\n if (ev.removed_created_in_session !== null) {\n lines.push(` removed_created_in_session: ${ev.removed_created_in_session}`);\n }\n if (ev.created_in_session_replacement !== null) {\n lines.push(` created_in_session_replacement: ${ev.created_in_session_replacement}`);\n }\n if (ev.removed_linked_sessions.length > 0) {\n lines.push(\" removed_linked_sessions:\");\n for (const sid of ev.removed_linked_sessions) {\n lines.push(` - ${sid}`);\n }\n }\n return lines;\n}\n\n// ============================================================================\n// task status\n// ============================================================================\n\nexport async function runTaskStatus(\n taskIdInput: string,\n newStatusInput: string,\n options: TaskStatusOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskStatus(taskIdInput, newStatusInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskStatus(\n taskIdInput: string,\n newStatusInput: string,\n options: TaskStatusOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const newStatus = parseTaskStatusPositional(newStatusInput);\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"status\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n\n if (options.session !== undefined) {\n const sessionId = (await resolveSessionId(paths, options.session)) as PrefixedId<\"ses\">;\n const result = await updateTaskStatusWithEvent({\n mode: \"attach\",\n paths,\n occurredAt,\n sessionId,\n taskId,\n newStatus,\n });\n printTaskStatusResult(options, {\n mode: \"attached\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n previousStatus: result.previousStatus,\n newStatus: result.newStatus,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const result = await updateTaskStatusWithEvent({\n mode: \"ad-hoc\",\n paths,\n manifest,\n occurredAt,\n taskId,\n newStatus,\n workingDirectory: repositoryRoot,\n });\n printTaskStatusResult(options, {\n mode: \"ad-hoc\",\n taskId: result.taskId,\n eventId: result.eventId,\n sessionId: result.sessionId,\n sessionStatus: result.sessionStatus,\n previousStatus: result.previousStatus,\n newStatus: result.newStatus,\n });\n}\n\ntype TaskStatusPrint = {\n mode: \"ad-hoc\" | \"attached\";\n taskId: string;\n eventId: string;\n sessionId: string;\n sessionStatus: SessionStatus;\n previousStatus: TaskStatus;\n newStatus: TaskStatus;\n};\n\nfunction printTaskStatusResult(options: TaskStatusOptions, result: TaskStatusPrint): void {\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n previous_status: result.previousStatus,\n new_status: result.newStatus,\n }),\n );\n return;\n }\n const sid = shortSessionId(result.sessionId);\n console.log(\n `Updated ${result.taskId} status: ${result.previousStatus} -> ${result.newStatus} (in session ${sid})`,\n );\n}\n\n// ============================================================================\n// task reconcile\n// ============================================================================\n\nexport async function runTaskReconcile(\n options: TaskReconcileOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskReconcile(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskReconcile(\n options: TaskReconcileOptions,\n ctx: TaskContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"reconcile\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const nowProvider = ctx.nowProvider ?? ((): Date => new Date());\n const write = options.write === true;\n const verbose = isVerbose(options);\n const json = options.json === true;\n\n if (options.task !== undefined) {\n const taskId = (await resolveTaskId(paths, options.task)) as PrefixedId<\"task\">;\n const result = await reconcileTask(paths, manifest, {\n taskId,\n occurredAt: nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n scope: \"single\",\n });\n if (json) {\n printReconcileJson({ dryRun: !write, scanned: 1, results: [result], failed: [] });\n } else {\n await printReconcileSingleText(result, paths, { write, verbose });\n }\n return;\n }\n\n const all = await reconcileAllTasks(paths, manifest, {\n occurredAt: () => nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n });\n if (json) {\n printReconcileJson({\n dryRun: !write,\n scanned: all.scanned,\n results: all.results,\n failed: all.failed,\n });\n } else {\n printReconcileAllText(all.results, all.failed, all.scanned, { write, verbose });\n }\n if (all.failed.length > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction printReconcileJson(input: {\n dryRun: boolean;\n scanned: number;\n results: ReadonlyArray<ReconcileResult>;\n failed: ReadonlyArray<ReconcileFailure>;\n}): void {\n console.log(\n JSON.stringify(\n {\n dry_run: input.dryRun,\n scanned: input.scanned,\n reconciled: input.results.map((r) => ({\n task_id: r.taskId,\n removed_created_in_session: r.brokenCreatedInSession,\n created_in_session_replacement:\n r.brokenCreatedInSession !== null && r.reconcileSession !== null\n ? r.reconcileSession.sessionId\n : null,\n removed_linked_sessions: r.brokenLinkedSessions,\n reconcile_session_id: r.reconcileSession?.sessionId ?? null,\n event_id: r.reconcileSession?.eventId ?? null,\n })),\n failed: input.failed.map((f) => ({\n task_id: f.taskId,\n error_class: f.errorClass,\n phase: f.phase,\n })),\n },\n null,\n 2,\n ),\n );\n}\n\nasync function printReconcileSingleText(\n result: ReconcileResult,\n paths: ReturnType<typeof basouPaths>,\n options: { write: boolean; verbose: boolean },\n): Promise<void> {\n if (result.clean) {\n // For the --task path with no broken refs we report counts of reachable\n // references so the operator gets a positive audit confirmation rather\n // than a bare \"ok\". Re-read task.md cheaply; the core API already did\n // the integrity work so this is just for the display string.\n let createdCount = 0;\n let linkedCount = 0;\n try {\n const doc = await readTaskFile(paths, result.taskId);\n createdCount = 1;\n linkedCount = doc.task.task.linked_sessions.length;\n } catch {\n // If the file became unreadable between reconcileTask and here just\n // fall back to a less detailed message rather than crashing the run.\n }\n console.log(\n `${result.taskId}: no broken refs (${createdCount} created_in_session + ${linkedCount} linked_sessions, all reachable).`,\n );\n return;\n }\n if (options.write) {\n const sessionPart =\n result.reconcileSession !== null\n ? ` (in session ${shortSessionId(result.reconcileSession.sessionId)})`\n : \"\";\n console.log(`Reconciled ${result.taskId}: ${describeReconcileSummary(result)}${sessionPart}.`);\n return;\n }\n const summary = describeBrokenSummary(result, \"task\", options.verbose);\n console.log(`(dry-run) Would reconcile ${result.taskId}: ${summary}`);\n console.log(\"Note: events -> task.md forward sync is handled by `basou task refresh-linkage`.\");\n console.log(\"Re-run with --write to apply.\");\n}\n\nfunction printReconcileAllText(\n results: ReadonlyArray<ReconcileResult>,\n failed: ReadonlyArray<ReconcileFailure>,\n scanned: number,\n options: { write: boolean; verbose: boolean },\n): void {\n if (results.length === 0 && failed.length === 0) {\n console.log(`Scanned ${scanned} tasks, no broken refs detected.`);\n return;\n }\n\n let totalBrokenRefs = 0;\n for (const r of results) {\n totalBrokenRefs += r.brokenLinkedSessions.length + (r.brokenCreatedInSession !== null ? 1 : 0);\n }\n\n if (options.write) {\n for (const r of results) {\n const sessionPart =\n r.reconcileSession !== null\n ? ` (in session ${shortSessionId(r.reconcileSession.sessionId)})`\n : \"\";\n console.log(`Reconciled ${r.taskId}: ${describeReconcileSummary(r)}${sessionPart}`);\n }\n for (const f of failed) {\n const phase = f.phase ?? \"unknown\";\n console.error(\n `Failed to reconcile ${f.taskId}: ${f.errorClass} (phase: ${phase}); see Caused by with -v`,\n );\n }\n const reconciledCount = results.length;\n const reconciledRefs = totalBrokenRefs;\n const reconciledPart = `reconciled ${reconciledCount} task${reconciledCount === 1 ? \"\" : \"s\"} (${reconciledRefs} broken ref${reconciledRefs === 1 ? \"\" : \"s\"})`;\n const failedPart =\n failed.length === 0 ? \"\" : `, ${failed.length} task${failed.length === 1 ? \"\" : \"s\"} failed`;\n console.log(`Scanned ${scanned} tasks, ${reconciledPart}${failedPart}.`);\n if (failed.length > 0) {\n console.error(\"(exit code 1)\");\n }\n return;\n }\n\n // dry-run with broken refs\n for (const r of results) {\n const summary = describeBrokenSummary(r, \"all\", options.verbose);\n console.log(`(dry-run) Would reconcile ${r.taskId}: ${summary}`);\n }\n console.log(\n `Scanned ${scanned} tasks, would reconcile ${results.length} task${results.length === 1 ? \"\" : \"s\"} (${totalBrokenRefs} broken ref${totalBrokenRefs === 1 ? \"\" : \"s\"}).`,\n );\n console.log(\"Note: events -> task.md forward sync is handled by `basou task refresh-linkage`.\");\n console.log(\"Re-run with --write to apply.\");\n}\n\nfunction describeReconcileSummary(r: ReconcileResult): string {\n const linkedCount = r.brokenLinkedSessions.length;\n const parts: string[] = [];\n if (r.brokenCreatedInSession !== null) {\n parts.push(\"replaced created_in_session\");\n }\n if (linkedCount > 0) {\n parts.push(`removed ${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"}`);\n }\n return parts.join(\" + \");\n}\n\nfunction describeBrokenSummary(\n r: ReconcileResult,\n scope: \"all\" | \"task\",\n verbose: boolean,\n): string {\n const showIds = scope === \"task\" || verbose;\n const parts: string[] = [];\n if (r.brokenCreatedInSession !== null) {\n parts.push(\n showIds\n ? `broken created_in_session ${formatSessionIdForDisplay(r.brokenCreatedInSession, verbose, scope)}`\n : \"broken created_in_session\",\n );\n }\n const linkedCount = r.brokenLinkedSessions.length;\n if (linkedCount > 0) {\n if (showIds) {\n const ids = r.brokenLinkedSessions\n .map((id) => formatSessionIdForDisplay(id, verbose, scope))\n .join(\", \");\n parts.push(`${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"} [${ids}]`);\n } else {\n parts.push(`${linkedCount} linked_sessions entr${linkedCount === 1 ? \"y\" : \"ies\"}`);\n }\n }\n return parts.join(\" + \");\n}\n\nfunction formatSessionIdForDisplay(id: string, verbose: boolean, scope: \"all\" | \"task\"): string {\n if (verbose && scope === \"task\") return id;\n return `ses_${shortSessionId(id)}`;\n}\n\n// ============================================================================\n// task refresh-linkage\n// ============================================================================\n\nexport async function runTaskRefreshLinkage(\n taskIdInput: string,\n options: TaskRefreshLinkageOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskRefreshLinkage(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskRefreshLinkage(\n taskIdInput: string,\n options: TaskRefreshLinkageOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"refresh-linkage\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const nowProvider = ctx.nowProvider ?? ((): Date => new Date());\n const write = options.write === true;\n\n const result = await refreshTaskLinkedSessions(paths, manifest, {\n taskId,\n occurredAt: nowProvider().toISOString(),\n workingDirectory: repositoryRoot,\n write,\n });\n\n if (options.json === true) {\n printRefreshLinkageJson(result, { dryRun: !write });\n return;\n }\n printRefreshLinkageText(result, { dryRun: !write });\n}\n\nfunction printRefreshLinkageJson(result: RefreshLinkageResult, input: { dryRun: boolean }): void {\n console.log(\n JSON.stringify(\n {\n task_id: result.taskId,\n clean: result.clean,\n dry_run: input.dryRun,\n added_linked_sessions: result.addedLinkedSessions,\n removed_linked_sessions: result.removedLinkedSessions,\n final_count: result.finalCount,\n refresh_session_id: result.refreshSession?.sessionId ?? null,\n event_id: result.refreshSession?.eventId ?? null,\n },\n null,\n 2,\n ),\n );\n}\n\nfunction printRefreshLinkageText(result: RefreshLinkageResult, input: { dryRun: boolean }): void {\n if (result.clean) {\n console.log(\n `${result.taskId}: linked_sessions already fresh (${result.finalCount} entr${result.finalCount === 1 ? \"y\" : \"ies\"}).`,\n );\n return;\n }\n const addedCount = result.addedLinkedSessions.length;\n const removedCount = result.removedLinkedSessions.length;\n const summaryParts: string[] = [];\n if (addedCount > 0) {\n summaryParts.push(`+${addedCount} added`);\n }\n if (removedCount > 0) {\n summaryParts.push(`-${removedCount} removed`);\n }\n const summary = summaryParts.join(\", \");\n if (input.dryRun) {\n console.log(`(dry-run) Would refresh ${result.taskId} linked_sessions: ${summary}.`);\n console.log(\"Re-run with --write to apply.\");\n return;\n }\n const sid =\n result.refreshSession !== null\n ? ` (in session ${shortSessionId(result.refreshSession.sessionId)})`\n : \"\";\n console.log(\n `Refreshed ${result.taskId} linked_sessions: ${summary}${sid}; final count ${result.finalCount}.`,\n );\n}\n\n// ============================================================================\n// task edit / delete / archive\n// ============================================================================\n\nexport async function runTaskEdit(\n taskIdInput: string,\n options: TaskEditOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskEdit(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskEdit(\n taskIdInput: string,\n options: TaskEditOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n if (options.title === undefined && options.status === undefined) {\n throw new Error(\"Nothing to edit: provide --title or --status\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"edit\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n\n const result = await editTask({\n paths,\n taskId,\n occurredAt,\n manifest,\n workingDirectory: repositoryRoot,\n ...(options.title !== undefined ? { title: options.title } : {}),\n ...(options.status !== undefined ? { newStatus: options.status } : {}),\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title_updated: result.titleUpdated,\n status_updated: result.statusUpdated,\n previous_status: result.previousStatus,\n new_status: result.newStatus,\n status_change_session_id: result.statusChangeSession?.sessionId ?? null,\n status_change_event_id: result.statusChangeSession?.eventId ?? null,\n }),\n );\n return;\n }\n if (result.statusUpdated) {\n const sid =\n result.statusChangeSession !== null\n ? ` (in session ${shortSessionId(result.statusChangeSession.sessionId)})`\n : \"\";\n console.log(\n `Updated ${result.taskId} status: ${result.previousStatus} -> ${result.newStatus}${sid}`,\n );\n }\n if (result.titleUpdated) {\n console.log(`Updated ${result.taskId} title.`);\n }\n if (!result.statusUpdated && !result.titleUpdated) {\n // Both fields were supplied but matched the current values exactly —\n // tell the operator the task was already in the requested state.\n console.log(`No changes for ${result.taskId}.`);\n }\n}\n\nexport async function runTaskDelete(\n taskIdInput: string,\n options: TaskDeleteOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskDelete(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskDelete(\n taskIdInput: string,\n options: TaskDeleteOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"delete\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n\n if (options.yes !== true) {\n await confirmDestructiveAction(\"delete\", taskId);\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const result = await deleteTask({\n paths,\n manifest,\n taskId,\n occurredAt,\n workingDirectory: repositoryRoot,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title: result.title,\n session_id: result.sessionId,\n event_id: result.eventId,\n }),\n );\n return;\n }\n console.log(\n `Deleted ${result.taskId} (\"${result.title}\") in ad-hoc session ${shortSessionId(result.sessionId)}.`,\n );\n}\n\nexport async function runTaskArchive(\n taskIdInput: string,\n options: TaskArchiveOptions,\n ctx: TaskContext = {},\n): Promise<void> {\n try {\n await doRunTaskArchive(taskIdInput, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options), classifiers: TASK_CLASSIFIERS });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunTaskArchive(\n taskIdInput: string,\n options: TaskArchiveOptions,\n ctx: TaskContext,\n): Promise<void> {\n if (taskIdInput.trim().length === 0) {\n throw new Error(\"Task id is empty\");\n }\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForTask(cwd, \"archive\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const manifest = await readManifest(paths);\n const taskId = (await resolveTaskId(paths, taskIdInput)) as PrefixedId<\"task\">;\n\n if (options.yes !== true) {\n await confirmDestructiveAction(\"archive\", taskId);\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n const result = await archiveTask({\n paths,\n manifest,\n taskId,\n occurredAt,\n workingDirectory: repositoryRoot,\n });\n\n if (options.json === true) {\n console.log(\n JSON.stringify({\n task_id: result.taskId,\n title: result.title,\n session_id: result.sessionId,\n event_id: result.eventId,\n }),\n );\n return;\n }\n console.log(\n `Archived ${result.taskId} (\"${result.title}\") in ad-hoc session ${shortSessionId(result.sessionId)}.`,\n );\n}\n\n/**\n * Read a single y/N answer from stdin when stdin is a TTY. Refuses to wait\n * for input when stdin is not a TTY (operator must pass --yes explicitly),\n * so piping `echo y | basou task delete` cannot accidentally trigger a\n * destructive action.\n */\nasync function confirmDestructiveAction(\n action: \"delete\" | \"archive\",\n taskId: string,\n): Promise<void> {\n if (process.stdin.isTTY !== true) {\n throw new Error(`Refusing to ${action} without TTY; rerun with --yes to skip confirmation.`);\n }\n const verb = action === \"delete\" ? \"Delete\" : \"Archive\";\n process.stdout.write(`${verb} task \\`${taskId}\\`? [y/N] `);\n const answer = await readSingleLineFromStdin();\n const normalized = answer.trim().toLowerCase();\n if (normalized !== \"y\" && normalized !== \"yes\") {\n throw new Error(`${verb} aborted by user.`);\n }\n}\n\nasync function readSingleLineFromStdin(): Promise<string> {\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const line = await rl.question(\"\");\n return line;\n } finally {\n rl.close();\n }\n}\n\n// ============================================================================\n// option converters\n// ============================================================================\n\nfunction parseTitle(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseLabel(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Label must not be empty\");\n }\n return raw;\n}\n\nfunction parseInitialTaskStatus(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new InvalidArgumentError(\n `Initial task status must be one of: ${STATUS_VALUES.join(\", \")}`,\n );\n }\n return result.data;\n}\n\nconst ISO_DATE_RE = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/;\n\nfunction parseIsoTimestampOption(raw: string): string {\n // Mirror the IsoTimestampSchema accepted form: date + time + explicit\n // zone designator. We rely on Date.parse for content validation and the\n // regex above for shape so misformed inputs are rejected before we hand\n // the string to the orchestrator's downstream parsers.\n if (!ISO_DATE_RE.test(raw) || Number.isNaN(Date.parse(raw))) {\n throw new InvalidArgumentError(\n \"Invalid --completed-at value; expected ISO-8601 timestamp like 2026-05-10T12:34:56+09:00\",\n );\n }\n return raw;\n}\n\nfunction parseTaskStatusFilter(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new InvalidArgumentError(\n `Invalid task status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`,\n );\n }\n return result.data;\n}\n\nfunction parseTaskStatusPositional(raw: string): TaskStatus {\n const result = TaskStatusSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid task status: ${raw}. Valid values: ${STATUS_VALUES.join(\", \")}`);\n }\n return result.data;\n}\n\nfunction parseDescriptionOption(raw: string): string {\n if (raw.length === 0) {\n throw new InvalidArgumentError(\"Description must not be empty\");\n }\n return raw;\n}\n\nfunction parsePositiveInt(raw: string): number {\n const n = Number.parseInt(raw, 10);\n if (!Number.isInteger(n) || n < 1 || raw.trim() !== String(n)) {\n throw new InvalidArgumentError(`Invalid number: ${raw}`);\n }\n return n;\n}\n\n// ============================================================================\n// IO helpers\n// ============================================================================\n\nasync function readDescriptionFile(path: string): Promise<string> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Description source not found\", { cause: error });\n }\n if (findErrorCode(error, \"EISDIR\")) {\n throw new Error(\"Description source is not a file\", { cause: error });\n }\n throw new Error(\"Failed to read description source\", { cause: error });\n }\n}\n\nasync function resolveRepositoryRootForTask(\n cwd: string,\n subcmd:\n | \"new\"\n | \"list\"\n | \"show\"\n | \"status\"\n | \"reconcile\"\n | \"refresh-linkage\"\n | \"edit\"\n | \"delete\"\n | \"archive\",\n): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\n `Not a git repository. Run 'git init' first, then re-run 'basou task ${subcmd}'.`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n\n/**\n * Task-specific classifier for {@link TaskWriteAfterEventError}. The\n * generic renderer ({@link renderCliError}) already prints the underlying\n * `error.message`; this classifier appends the two task-specific lines\n * that explain WHICH artefact is in unsafe state and the manual-repair\n * hint. Combined with {@link failedToFinalizeClassifier} from the shared\n * lib so both error classes are surfaced consistently across `task new`,\n * `task status`, `task reconcile`, etc.\n */\nconst taskWriteAfterEventClassifier: ErrorClassifier = {\n match: (error) => error instanceof TaskWriteAfterEventError,\n additionalLines: (error) => {\n const e = error as TaskWriteAfterEventError;\n const sid = shortSessionId(e.sessionId);\n const tid = shortTaskId(e.taskId);\n const unsafeArtefact = describeUnsafeArtefact(e.phase, tid, sid);\n const warning = describeWriteFailureWarning(e.phase);\n const hint =\n e.phase === \"reconcile-concurrent\"\n ? \"re-run `basou task reconcile`\"\n : e.phase === \"linkage-refresh-concurrent\"\n ? \"re-run `basou task refresh-linkage`\"\n : \"manual repair required; see `basou task show -v` for event payload\";\n return [\n `Recorded ${e.eventId} in session ${sid}; ${unsafeArtefact} is in unsafe state; do not rerun`,\n `Warning: ${warning}; events.jsonl is consistent; ${hint}`,\n ];\n },\n};\n\nconst TASK_CLASSIFIERS: readonly ErrorClassifier[] = [\n taskWriteAfterEventClassifier,\n failedToFinalizeClassifier,\n];\n\nfunction describeUnsafeArtefact(\n phase: TaskWriteAfterEventError[\"phase\"],\n tid: string,\n sid: string,\n): string {\n switch (phase) {\n case \"create\":\n return `task ${tid} file`;\n case \"overwrite\":\n return `task ${tid} file`;\n case \"link-session\":\n return \"session-task linkage\";\n case \"reconcile\":\n return `task ${tid} file (reconcile incomplete)`;\n case \"reconcile-finalize\":\n return `reconcile session ${sid} (finalize incomplete)`;\n case \"reconcile-concurrent\":\n return `task ${tid} file (concurrent modification detected)`;\n case \"linkage-refresh\":\n return `task ${tid} file (linkage refresh incomplete)`;\n case \"linkage-refresh-finalize\":\n return `linkage refresh session ${sid} (finalize incomplete)`;\n case \"linkage-refresh-concurrent\":\n return `task ${tid} file (concurrent modification detected)`;\n case \"delete\":\n return `task ${tid} file (delete incomplete; file still on disk)`;\n case \"archive\":\n return `task ${tid} file (archive incomplete; check tasks/ and tasks/archive/)`;\n }\n}\n\nfunction describeWriteFailureWarning(phase: TaskWriteAfterEventError[\"phase\"]): string {\n switch (phase) {\n case \"create\":\n return \"task.md creation failed\";\n case \"overwrite\":\n return \"task.md update failed\";\n case \"link-session\":\n return \"session.yaml task_id update failed\";\n case \"reconcile\":\n return \"task.md reconciliation failed\";\n case \"reconcile-finalize\":\n return \"reconcile session finalize failed (session.yaml status update)\";\n case \"reconcile-concurrent\":\n return \"task.md was modified concurrently; re-run reconcile to retry\";\n case \"linkage-refresh\":\n return \"task.md linkage refresh write failed\";\n case \"linkage-refresh-finalize\":\n return \"linkage refresh session finalize failed (session.yaml status update)\";\n case \"linkage-refresh-concurrent\":\n return \"task.md was modified concurrently; re-run refresh-linkage to retry\";\n case \"delete\":\n return \"task.md unlink failed after task_deleted event committed\";\n case \"archive\":\n return \"task.md move to archive/ failed after task_archived event committed\";\n }\n}\n\nfunction pad(value: string, width: number): string {\n return value.length >= width ? value : value + \" \".repeat(width - value.length);\n}\n\nfunction maxLen(values: readonly string[], floor: number): number {\n let max = floor;\n for (const v of values) if (v.length > max) max = v.length;\n return max;\n}\n","import {\n assertBasouRootSafe,\n basouPaths,\n type ChainVerdict,\n enumerateSessionDirs,\n findErrorCode,\n resolveRepositoryRoot,\n resolveSessionId,\n verifyEventsChain,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\n\nexport type VerifyOptions = {\n session?: string;\n all?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type VerifyContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n};\n\n/** One row of `basou verify` output: a session id and its chain verdict. */\nexport type VerifyRow = {\n session_id: string;\n status: ChainVerdict[\"status\"];\n event_count: number;\n reason?: ChainVerdict[\"reason\"];\n line?: number;\n};\n\n/** Wire `basou verify` onto `program`. */\nexport function registerVerifyCommand(program: Command): void {\n program\n .command(\"verify\")\n .description(\"Verify the tamper-evidence hash chain of sessions' event logs (read-only)\")\n .option(\"--session <id>\", \"Verify a single session (unique id prefix accepted)\")\n .option(\"--all\", \"Verify every session (the default when --session is omitted)\")\n .option(\"--json\", \"Output the verdicts as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: VerifyOptions) => {\n await runVerify(opts);\n });\n}\n\nexport async function runVerify(options: VerifyOptions, ctx: VerifyContext = {}): Promise<void> {\n try {\n await doRunVerify(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nasync function doRunVerify(options: VerifyOptions, ctx: VerifyContext): Promise<void> {\n if (options.session !== undefined && options.all === true) {\n throw new Error(\"Specify either --session <id> or --all, not both\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveRepositoryRootForVerify(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const sessionIds =\n options.session !== undefined\n ? [await resolveSessionId(paths, options.session)]\n : await enumerateSessionDirs(paths);\n\n const rows: VerifyRow[] = [];\n for (const sessionId of sessionIds) {\n const verdict = await verifyEventsChain(paths, sessionId);\n rows.push({\n session_id: sessionId,\n status: verdict.status,\n event_count: verdict.eventCount,\n ...(verdict.reason !== undefined ? { reason: verdict.reason } : {}),\n ...(verdict.line !== undefined ? { line: verdict.line } : {}),\n });\n }\n\n const tamperedCount = rows.filter((r) => r.status === \"tampered\").length;\n\n if (options.json === true) {\n console.log(JSON.stringify(rows, null, 2));\n } else {\n for (const row of rows) {\n console.log(`${row.session_id} ${renderVerdict(row)}`);\n }\n const tally = (status: VerifyRow[\"status\"]): number =>\n rows.filter((r) => r.status === status).length;\n console.log(\n `Sessions: ${rows.length} total — ${tally(\"verified\")} verified, ` +\n `${tally(\"unchained\")} unchained, ${tally(\"empty\")} empty, ` +\n `${tally(\"incomplete\")} incomplete, ${tally(\"in_progress\")} in_progress, ` +\n `${tamperedCount} tampered`,\n );\n }\n\n // Only a real integrity break fails the command; unchained / empty /\n // incomplete / in_progress are informational states.\n if (tamperedCount > 0) {\n process.exitCode = 1;\n }\n}\n\nfunction renderVerdict(row: VerifyRow): string {\n switch (row.status) {\n case \"verified\":\n return `verified (${row.event_count} events)`;\n case \"tampered\":\n return row.line !== undefined\n ? `TAMPERED (${row.reason} at line ${row.line})`\n : `TAMPERED (${row.reason})`;\n case \"incomplete\":\n return \"incomplete (session.yaml missing; re-import to repair)\";\n case \"in_progress\":\n return `in_progress (${row.event_count} events; live session, anchor written at finalize)`;\n case \"unchained\":\n return \"unchained (session created before event-log chaining)\";\n case \"empty\":\n return \"empty\";\n }\n}\n\nasync function resolveRepositoryRootForVerify(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou verify'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { basename, resolve } from \"node:path\";\nimport {\n assertBasouRootSafe,\n basouPaths,\n findErrorCode,\n readManifest,\n resolveRepositoryRoot,\n} from \"@basou/core\";\nimport { type Command, InvalidArgumentError } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { loadPortfolioConfig, type PortfolioWorkspace } from \"../lib/portfolio-config.js\";\nimport { checkPortfolioSafety, formatSafetyReport } from \"../lib/portfolio-safety.js\";\nimport {\n startViewServer,\n type ViewServerDeps,\n type ViewServerHandle,\n type WorkspaceEntry,\n} from \"../lib/view-server.js\";\nimport type { ImportContext } from \"./import.js\";\n\nconst DEFAULT_PORT = 4319;\n\nexport type ViewOptions = {\n port?: number;\n open?: boolean;\n verbose?: boolean;\n /** Read `~/.basou/portfolio.yaml` and serve every listed workspace. */\n portfolio?: boolean;\n /** Ad-hoc workspace paths (repeatable); resolved against the cwd. Implies portfolio mode. */\n workspace?: string[];\n /** Run the portfolio safety preflight and exit (no server). */\n check?: boolean;\n /** Skip the portfolio safety preflight on start (not recommended). */\n skipSafetyCheck?: boolean;\n};\n\nexport type ViewContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n /** Override the `~/.claude/projects` root used by imports. */\n claudeProjectsDir?: string;\n /** Override the `~/.codex/sessions` root used by imports. */\n codexSessionsDir?: string;\n /** Override how the browser is opened (tests pass a no-op). */\n openBrowser?: (url: string) => void;\n /** Resolves the keep-alive wait, so tests can stop the server without a signal. */\n signal?: AbortSignal;\n /** Called once the server is listening, with its handle (for tests). */\n onListening?: (handle: ViewServerHandle) => void;\n /** Override the portfolio config path (tests). */\n portfolioConfigPath?: string;\n};\n\nfunction parsePort(value: string): number {\n const port = Number.parseInt(value, 10);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new InvalidArgumentError(\"Port must be an integer between 1 and 65535.\");\n }\n return port;\n}\n\n/**\n * Commander collector: accumulate a repeatable option into an array. Commander\n * passes `undefined` as `previous` on the first occurrence (no option default),\n * so default it to `[]` rather than spreading `undefined`.\n */\nfunction collectPath(value: string, previous: string[] = []): string[] {\n return [...previous, value];\n}\n\n/**\n * Wire `basou view` onto `program`. Starts a localhost-only web UI for\n * browsing provenance and running imports / regeneration by clicking. With\n * `--portfolio` / `--workspace` it serves several workspaces side by side.\n */\nexport function registerViewCommand(program: Command): void {\n program\n .command(\"view\")\n .description(\"Open a local web UI to browse provenance and run imports (localhost only)\")\n .option(\"--port <number>\", \"Port to listen on (default 4319)\", parsePort)\n .option(\"--no-open\", \"Do not open the browser automatically\")\n .option(\n \"--portfolio\",\n \"Serve every workspace listed in ~/.basou/portfolio.yaml (cross-repo orientation)\",\n )\n .option(\n \"--workspace <path>\",\n \"Workspace repo path to include (repeatable; implies portfolio mode; resolved against the cwd)\",\n collectPath,\n )\n .option(\"--check\", \"Run the portfolio safety preflight and exit (no server)\")\n .option(\"--skip-safety-check\", \"Skip the portfolio safety preflight on start (not recommended)\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (options: ViewOptions) => {\n await runView(options);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunView}. */\nexport async function runView(options: ViewOptions, ctx: ViewContext = {}): Promise<void> {\n try {\n await doRunView(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Pure runner: resolve the workspace(s), start the server, open the browser, and\n * keep running until SIGINT / SIGTERM (or an injected abort signal). The\n * server is always closed on the way out.\n */\nexport async function doRunView(options: ViewOptions, ctx: ViewContext): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n const workspaceFlags = options.workspace ?? [];\n const isPortfolio = workspaceFlags.length > 0 || options.portfolio === true;\n\n const deps = isPortfolio\n ? await buildPortfolioDeps(workspaceFlags, ctx, cwd)\n : await buildSingleDeps(ctx, cwd);\n\n // --check: run the read-only safety preflight and exit (no server).\n if (options.check === true) {\n const result = await checkPortfolioSafety(deps.workspaces);\n for (const line of formatSafetyReport(result)) console.log(line);\n if (result.findings.length > 0) process.exitCode = 1;\n return;\n }\n\n // Portfolio start auto-gates on the preflight. A footprint / overlap means a\n // monitored repo has (or would get) a `.basou/` — an irreversible write risk —\n // so the server is NOT started. An `unverifiable` item (e.g. an unreadable\n // manifest) cannot cause a write through the read-only view, so it is warned\n // about but does not block; `basou view --check` flags it strictly.\n // `--skip-safety-check` overrides the abort entirely.\n if (deps.mode === \"portfolio\" && options.skipSafetyCheck !== true) {\n const result = await checkPortfolioSafety(deps.workspaces);\n const blocking = result.findings.filter((f) => f.kind === \"footprint\" || f.kind === \"overlap\");\n if (blocking.length > 0) {\n for (const line of formatSafetyReport(result)) console.error(line);\n throw new Error(\n \"Portfolio safety preflight failed (see findings above). Fix the monitored repos, or re-run with --skip-safety-check to override.\",\n );\n }\n if (result.findings.length > 0) {\n console.error(\n `Portfolio safety: ${result.findings.length} unverifiable item(s) — the read-only view will still open; run 'basou view --check' for detail.`,\n );\n }\n }\n\n const port = options.port ?? DEFAULT_PORT;\n const handle = await startListening(port, deps);\n\n // Everything past listen runs under try/finally so a throw from the browser\n // launch or the onListening callback still closes the server.\n try {\n console.log(`basou view running at ${handle.url}`);\n if (deps.mode === \"portfolio\") {\n console.log(`Portfolio mode: ${deps.workspaces.length} workspace(s).`);\n }\n console.log(\n \"Localhost only, no authentication. Do not expose this port beyond your machine. Press Ctrl+C to stop.\",\n );\n\n if (options.open !== false) {\n openInBrowser(handle.url, ctx.openBrowser);\n }\n ctx.onListening?.(handle);\n\n await waitForShutdown(ctx.signal);\n } finally {\n await handle.close();\n }\n}\n\n/** Single-workspace mode: resolve the cwd's repo (git required) and serve it alone. */\nasync function buildSingleDeps(ctx: ViewContext, cwd: string): Promise<ViewServerDeps> {\n const repositoryRoot = await resolveRepositoryRootForView(cwd);\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n const entry = await buildWorkspaceEntry(repositoryRoot, ctx);\n return { workspaces: [entry], mode: \"single\", nowProvider: nowProviderOf(ctx) };\n}\n\n/**\n * Portfolio mode: serve several workspaces. Sources are the explicit\n * `--workspace` flags (resolved against the cwd) or, absent those,\n * `~/.basou/portfolio.yaml`. No git check and no \"initialized\" assertion — a\n * missing / uninitialized path becomes a degraded card rather than an error.\n */\nasync function buildPortfolioDeps(\n workspaceFlags: string[],\n ctx: ViewContext,\n cwd: string,\n): Promise<ViewServerDeps> {\n const specs: PortfolioWorkspace[] =\n workspaceFlags.length > 0\n ? workspaceFlags.map((p) => ({ path: resolve(cwd, p) }))\n : await loadPortfolioConfig(ctx.portfolioConfigPath);\n\n const entries: WorkspaceEntry[] = [];\n const seenPath = new Set<string>();\n const seenKey = new Set<string>();\n for (const spec of specs) {\n const repoRoot = resolve(spec.path);\n if (seenPath.has(repoRoot)) continue;\n seenPath.add(repoRoot);\n const entry = await buildWorkspaceEntry(repoRoot, ctx, spec.label);\n let key = entry.key;\n for (let n = 1; seenKey.has(key); n++) key = `${entry.key}-${n}`;\n seenKey.add(key);\n entries.push({ ...entry, key });\n }\n if (entries.length === 0) throw new Error(\"No workspaces to show.\");\n return { workspaces: entries, mode: \"portfolio\", nowProvider: nowProviderOf(ctx) };\n}\n\n/**\n * Build one workspace entry from a repo root. Reads the manifest best-effort for\n * a stable key (workspace id) and label; an unreadable manifest yields a\n * degraded entry keyed by a path hash (never the path itself, to stay pathless).\n */\nasync function buildWorkspaceEntry(\n repoRoot: string,\n ctx: ViewContext,\n labelOverride?: string,\n): Promise<WorkspaceEntry> {\n const paths = basouPaths(repoRoot);\n const importCtx: ImportContext = {\n cwd: repoRoot,\n ...(ctx.claudeProjectsDir !== undefined ? { claudeProjectsDir: ctx.claudeProjectsDir } : {}),\n ...(ctx.codexSessionsDir !== undefined ? { codexSessionsDir: ctx.codexSessionsDir } : {}),\n };\n try {\n const manifest = await readManifest(paths);\n return {\n key: manifest.workspace.id,\n label: labelOverride ?? manifest.workspace.name,\n paths,\n repoRoot,\n importCtx,\n initialized: true,\n };\n } catch (error: unknown) {\n // \"YAML file not found\" (ENOENT) = never initialized; anything else (parse /\n // permission error) = present but unreadable, surfaced so the card can say so.\n const notFound = error instanceof Error && error.message === \"YAML file not found\";\n return {\n key: `ws-${createHash(\"sha1\").update(repoRoot).digest(\"hex\").slice(0, 12)}`,\n label: labelOverride ?? basename(repoRoot),\n paths,\n repoRoot,\n importCtx,\n initialized: false,\n ...(notFound ? {} : { manifestError: \"manifest unreadable or invalid\" }),\n };\n }\n}\n\nfunction nowProviderOf(ctx: ViewContext): () => Date {\n return ctx.nowProvider ?? (() => new Date());\n}\n\nasync function startListening(port: number, deps: ViewServerDeps): Promise<ViewServerHandle> {\n try {\n return await startViewServer({ port, deps });\n } catch (error: unknown) {\n if (findErrorCode(error, \"EADDRINUSE\")) {\n throw new Error(`Port ${port} is already in use. Pass --port <n> to choose another.`, {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nfunction openInBrowser(url: string, override?: (url: string) => void): void {\n if (override !== undefined) {\n override(url);\n return;\n }\n if (process.platform !== \"darwin\") return; // print-only elsewhere\n try {\n const child = spawn(\"open\", [url], { stdio: \"ignore\", detached: true });\n child.on(\"error\", () => {}); // browser launch is best-effort\n child.unref();\n } catch {\n // ignore: the URL is already printed\n }\n}\n\n/** Resolve once the process is asked to stop (signal) or the injected abort fires. */\nfunction waitForShutdown(signal: AbortSignal | undefined): Promise<void> {\n return new Promise((resolve) => {\n const cleanup = (): void => {\n process.off(\"SIGINT\", onSignal);\n process.off(\"SIGTERM\", onSignal);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const onSignal = (): void => {\n cleanup();\n resolve();\n };\n const onAbort = (): void => {\n cleanup();\n resolve();\n };\n process.on(\"SIGINT\", onSignal);\n process.on(\"SIGTERM\", onSignal);\n if (signal !== undefined) {\n if (signal.aborted) {\n cleanup();\n resolve();\n return;\n }\n signal.addEventListener(\"abort\", onAbort);\n }\n });\n}\n\nasync function resolveRepositoryRootForView(cwd: string): Promise<string> {\n try {\n return await resolveRepositoryRoot(cwd);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Not a git repository\") {\n throw new Error(\"Not a git repository. Run 'git init' first, then re-run 'basou view'.\", {\n cause: error,\n });\n }\n throw error;\n }\n}\n\nasync function assertWorkspaceInitialized(basouRoot: string): Promise<void> {\n try {\n await assertBasouRootSafe(basouRoot);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(\"Workspace not initialized. Run 'basou init' first.\");\n }\n throw error;\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { lstat, realpath } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { readManifest } from \"@basou/core\";\nimport type { WorkspaceEntry } from \"./view-server.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * A reason a monitored repo (a workspace's `import.source_roots` other than the\n * workspace itself) is — or could become — touched by basou. Portfolio capture\n * is import-based and never writes to a monitored repo, so the only way one gets\n * a `.basou/` is a misconfiguration (a workspace pointed at it, or a stray\n * `basou init` / `run` / `exec` inside it). This preflight makes that mechanical\n * to catch before the irreversible mistake (a committed / pushed footprint).\n *\n * The check is FAIL-CLOSED: anything it cannot verify (an unreadable directory,\n * an unparseable manifest) is reported as `unverifiable` rather than assumed\n * safe.\n */\nexport type SafetyFinding = {\n workspaceLabel: string;\n workspaceRoot: string;\n /** The configured (resolved) path of the monitored repo. Shown to the owner locally so they can fix it. */\n monitoredRepo: string;\n kind: \"footprint\" | \"overlap\" | \"unverifiable\";\n detail: string;\n};\n\nexport type SafetyResult = {\n findings: SafetyFinding[];\n workspacesChecked: number;\n monitoredReposChecked: number;\n};\n\ntype ErrnoLike = { code?: string };\n\nfunction errorCode(error: unknown): string | undefined {\n return error instanceof Error ? (error as Error & ErrnoLike).code : undefined;\n}\n\n/** Canonicalize via realpath so symlinked spellings compare by real identity; fall back to a lexical resolve. */\nasync function canonical(p: string): Promise<string> {\n try {\n return await realpath(p);\n } catch {\n return resolve(p);\n }\n}\n\n/** True when `child` is `parent` itself or nested inside it (both expected canonical). */\nfunction isInside(child: string, parent: string): boolean {\n const rel = relative(parent, child);\n return rel === \"\" || (!rel.startsWith(\"..\") && !isAbsolute(rel));\n}\n\n/** A tracked path (relative to the repo) that is, or is under, a `.basou/` dir anywhere in the tree. */\nfunction isBasouPath(p: string): boolean {\n return (\n p === \".basou\" || p.startsWith(\".basou/\") || p.includes(\"/.basou/\") || p.endsWith(\"/.basou\")\n );\n}\n\n/**\n * Inspect a monitored repo for a basou footprint. Returns a finding kind or null\n * when clean. Detection is two-pronged and FAIL-CLOSED:\n * - filesystem: a top-level `.basou` entry (the common stray-init / run / exec\n * location, which lands at the repo root). A non-ENOENT stat error (e.g.\n * EACCES, ELOOP) is reported as `unverifiable`, never assumed clean.\n * - git: ANY tracked path under a `.basou/` directory, at the root OR nested\n * (a submodule / nested repo) — this is the irreversible, pushable case.\n */\nasync function inspectRepo(\n repoPath: string,\n): Promise<{ kind: \"footprint\" | \"unverifiable\"; detail: string } | null> {\n let hasEntry = false;\n try {\n await lstat(join(repoPath, \".basou\"));\n hasEntry = true;\n } catch (error: unknown) {\n if (errorCode(error) !== \"ENOENT\") {\n return {\n kind: \"unverifiable\",\n detail: `could not check for a .basou here (${errorCode(error) ?? \"unknown error\"}) — treat as unsafe`,\n };\n }\n }\n\n try {\n const { stdout } = await execFileAsync(\"git\", [\"-C\", repoPath, \"ls-files\", \"-z\"]);\n const tracked = stdout.split(\"\\0\").some((f) => f.length > 0 && isBasouPath(f));\n if (tracked) {\n return {\n kind: \"footprint\",\n detail: \"a .basou/ entry is tracked by git here and would be pushed\",\n };\n }\n } catch {\n // Not a git repo (or git unavailable): the filesystem check stands alone.\n }\n\n if (hasEntry) return { kind: \"footprint\", detail: \"a .basou/ entry exists here\" };\n return null;\n}\n\n/**\n * Verify that no monitored repo (a workspace's source roots, excluding the\n * workspace itself) carries a basou footprint, and that no workspace's `.basou/`\n * would land inside a monitored repo. Read-only: it stats `.basou` and runs\n * `git ls-files` against monitored repos but writes nothing. Returns the\n * findings (empty = safe).\n *\n * Known limitation (documented in the spec): if the owner lists a precious repo\n * DIRECTLY as a workspace, its own root is exempt (a workspace's `.basou/` is\n * by design), so the tool cannot tell \"this workspace IS a precious repo\" from\n * \"this is a dedicated aggregator\". Workspaces must be dedicated planning repos.\n */\nexport async function checkPortfolioSafety(workspaces: WorkspaceEntry[]): Promise<SafetyResult> {\n const findings: SafetyFinding[] = [];\n let monitoredReposChecked = 0;\n\n for (const ws of workspaces) {\n const wsReal = await canonical(ws.repoRoot);\n\n let sourceRoots: ReadonlyArray<string> = [];\n try {\n const manifest = await readManifest(ws.paths);\n sourceRoots = manifest.import?.source_roots ?? [];\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n // Truly uninitialized: no source roots, and it only ever writes to its\n // own (separate) root. Genuinely nothing to protect.\n sourceRoots = [];\n } else {\n // Present but unreadable/invalid: we cannot tell what it monitors. Fail closed.\n findings.push({\n workspaceLabel: ws.label,\n workspaceRoot: ws.repoRoot,\n monitoredRepo: ws.repoRoot,\n kind: \"unverifiable\",\n detail:\n \"the workspace manifest is present but unreadable — cannot determine which repos it monitors; treat as unsafe\",\n });\n continue;\n }\n }\n\n // Map canonical monitored path -> the configured (resolved) path for display.\n const monitored = new Map<string, string>();\n for (const root of sourceRoots) {\n const display = resolve(ws.repoRoot, root);\n const real = await canonical(display);\n if (real !== wsReal) monitored.set(real, display); // `.` (the workspace itself) is exempt\n }\n\n for (const [real, display] of monitored) {\n monitoredReposChecked++;\n if (isInside(wsReal, real)) {\n findings.push({\n workspaceLabel: ws.label,\n workspaceRoot: ws.repoRoot,\n monitoredRepo: display,\n kind: \"overlap\",\n detail: \"the workspace (where .basou/ is written) is inside this monitored repo\",\n });\n }\n const inspection = await inspectRepo(real);\n if (inspection !== null) {\n findings.push({\n workspaceLabel: ws.label,\n workspaceRoot: ws.repoRoot,\n monitoredRepo: display,\n kind: inspection.kind,\n detail: inspection.detail,\n });\n }\n }\n }\n\n return { findings, workspacesChecked: workspaces.length, monitoredReposChecked };\n}\n\n/** Human-readable preflight report lines (also used by `--check`). */\nexport function formatSafetyReport(result: SafetyResult): string[] {\n if (result.findings.length === 0) {\n if (result.monitoredReposChecked === 0) {\n return [\n `Portfolio safety: OK. ${result.workspacesChecked} workspace(s) checked — no monitored repos configured (portfolio safety applies when a workspace imports from sibling repos via source_roots).`,\n ];\n }\n return [\n `Portfolio safety: OK. ${result.workspacesChecked} workspace(s), ${result.monitoredReposChecked} monitored repo(s) checked — no .basou footprint, no overlap.`,\n ];\n }\n const lines = [`Portfolio safety: DANGER — ${result.findings.length} finding(s):`];\n for (const f of result.findings) {\n lines.push(` [${f.kind}] ${f.monitoredRepo} (workspace \"${f.workspaceLabel}\"): ${f.detail}`);\n }\n lines.push(\n \"A monitored repo must have no basou footprint. Use a separate workspace repo whose source_roots point at the monitored repo as a sibling; never 'basou init' / 'run' / 'exec' inside a monitored repo.\",\n );\n return lines;\n}\n","import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { join } from \"node:path\";\nimport {\n type BasouPaths,\n computeWorkStats,\n enumerateApprovals,\n findErrorCode,\n isLazyExpired,\n loadApproval,\n loadSessionEntries,\n loadTaskEntries,\n type Manifest,\n readAllEvents,\n readManifest,\n readMarkdownFile,\n readSessionYaml,\n readTaskFile,\n renderDecisions,\n renderHandoff,\n summarizeOrientation,\n} from \"@basou/core\";\nimport type { ImportContext } from \"../commands/import.js\";\nimport {\n importClaudeCode,\n importCodex,\n probeStaleness,\n type RefreshActionOptions,\n refreshAll,\n regenerateDecisions,\n regenerateHandoff,\n} from \"./provenance-actions.js\";\nimport { VIEW_HTML } from \"./view-ui.js\";\n\n/**\n * One workspace the server can serve. In single mode there is exactly one; in\n * portfolio mode there are several, each its own `.basou/` (a separate repo).\n * `key` is a stable, URL-safe identifier used in `/api/ws/:key/*` routes — it is\n * only ever an equality lookup against this registry, never joined into a path.\n */\nexport type WorkspaceEntry = {\n key: string;\n label: string;\n paths: BasouPaths;\n repoRoot: string;\n importCtx: ImportContext;\n /** False when the path has no readable `.basou/manifest` (shown as a degraded card). */\n initialized: boolean;\n /**\n * Set when the manifest is present but unreadable/invalid (parse / permission\n * error) rather than simply absent — lets a degraded card distinguish\n * \"unreadable\" from \"never initialized\". Pathless.\n */\n manifestError?: string;\n};\n\n/** Everything the request handlers need; resolved once when the server starts. */\nexport type ViewServerDeps = {\n /** At least one entry. Flat `/api/*` routes always target `workspaces[0]`. */\n workspaces: WorkspaceEntry[];\n /** How the server was started; drives the UI landing (single detail vs portfolio cards). */\n mode: \"single\" | \"portfolio\";\n nowProvider: () => Date;\n};\n\n/** A running view server, with the means to stop it. */\nexport type ViewServerHandle = {\n url: string;\n port: number;\n close: () => Promise<void>;\n};\n\n/** A handler-level failure that maps to a specific HTTP status (vs a 500). */\nclass HttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nconst MAX_BODY_BYTES = 64 * 1024;\nconst API_PREFIX = \"/api/\";\nconst WS_PREFIX = \"/api/ws/\";\n\n/**\n * Start a localhost-only provenance viewer. Binds 127.0.0.1, serves a single\n * inline HTML page at `/` and a small JSON API under `/api/*`. Resolves once\n * listening (rejects on a bind error such as EADDRINUSE).\n */\nexport function startViewServer(opts: {\n port: number;\n host?: string;\n deps: ViewServerDeps;\n}): Promise<ViewServerHandle> {\n const { port, host = \"127.0.0.1\", deps } = opts;\n // Mutating POSTs swap process-global console (import capture); serialize them\n // ACROSS all workspaces so concurrent requests never interleave their capture.\n let actionQueue: Promise<unknown> = Promise.resolve();\n const runExclusive = <T>(fn: () => Promise<T>): Promise<T> => {\n const result = actionQueue.then(fn, fn);\n actionQueue = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n };\n\n let boundPort = port;\n const getPort = (): number => boundPort;\n\n return new Promise((resolve, reject) => {\n const server = createServer((req, res) => {\n handleRequest(req, res, deps, getPort, runExclusive).catch((error: unknown) => {\n sendError(res, error instanceof HttpError ? error.status : 500, pathlessMessage(error));\n });\n });\n server.on(\"error\", reject);\n server.listen(port, host, () => {\n const address = server.address();\n boundPort = isAddressInfo(address) ? address.port : port;\n server.off(\"error\", reject);\n resolve({\n url: `http://${host}:${boundPort}`,\n port: boundPort,\n close: () => closeServer(server),\n });\n });\n });\n}\n\nfunction isAddressInfo(value: string | AddressInfo | null): value is AddressInfo {\n return value !== null && typeof value === \"object\";\n}\n\nfunction closeServer(server: Server): Promise<void> {\n return new Promise((resolve) => {\n server.close(() => resolve());\n // Force-terminate any in-flight connection (e.g. a client holding a POST\n // body open) so close() resolves promptly instead of hanging shutdown.\n server.closeAllConnections();\n });\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n deps: ViewServerDeps,\n getPort: () => number,\n runExclusive: <T>(fn: () => Promise<T>) => Promise<T>,\n): Promise<void> {\n const method = req.method ?? \"GET\";\n const url = new URL(req.url ?? \"/\", \"http://localhost\");\n const pathname = url.pathname;\n\n if (!hostAllowed(req, getPort())) {\n sendError(res, 403, \"Forbidden: host not allowed\");\n return;\n }\n\n if (method === \"GET\") {\n await handleGet(res, pathname, deps);\n return;\n }\n if (method === \"POST\") {\n if (!originAllowed(req, getPort())) {\n sendError(res, 403, \"Forbidden: cross-origin request\");\n return;\n }\n const body = await readBody(req);\n await handlePost(res, pathname, body, deps, runExclusive);\n return;\n }\n sendError(res, 405, \"Method not allowed\");\n}\n\nasync function handleGet(\n res: ServerResponse,\n pathname: string,\n deps: ViewServerDeps,\n): Promise<void> {\n if (pathname === \"/\") {\n sendHtml(res, VIEW_HTML);\n return;\n }\n if (pathname === \"/api/portfolio\") {\n sendJson(res, 200, await portfolio(deps));\n return;\n }\n const scoped = matchWsRoute(pathname);\n if (scoped !== null) {\n const ws = findWorkspace(deps, scoped.key);\n if (ws === null) {\n sendError(res, 404, \"Unknown workspace\");\n return;\n }\n if (!(await handleWorkspaceGet(res, scoped.sub, ws, deps.nowProvider))) {\n sendError(res, 404, \"Not found\");\n }\n return;\n }\n if (pathname.startsWith(API_PREFIX)) {\n const sub = pathname.slice(API_PREFIX.length);\n if (!(await handleWorkspaceGet(res, sub, primaryWorkspace(deps), deps.nowProvider))) {\n sendError(res, 404, \"Not found\");\n }\n return;\n }\n sendError(res, 404, \"Not found\");\n}\n\nasync function handlePost(\n res: ServerResponse,\n pathname: string,\n body: Record<string, unknown>,\n deps: ViewServerDeps,\n runExclusive: <T>(fn: () => Promise<T>) => Promise<T>,\n): Promise<void> {\n const scoped = matchWsRoute(pathname);\n if (scoped !== null) {\n const ws = findWorkspace(deps, scoped.key);\n if (ws === null) {\n sendError(res, 404, \"Unknown workspace\");\n return;\n }\n if (!(await handleWorkspacePost(res, scoped.sub, ws, body, deps, runExclusive))) {\n sendError(res, 404, \"Not found\");\n }\n return;\n }\n if (pathname.startsWith(API_PREFIX)) {\n const sub = pathname.slice(API_PREFIX.length);\n if (!(await handleWorkspacePost(res, sub, primaryWorkspace(deps), body, deps, runExclusive))) {\n sendError(res, 404, \"Not found\");\n }\n return;\n }\n sendError(res, 404, \"Not found\");\n}\n\n/** GET routes scoped to one workspace. Returns false if `sub` matched nothing. */\nasync function handleWorkspaceGet(\n res: ServerResponse,\n sub: string,\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<boolean> {\n if (sub === \"overview\") {\n sendJson(res, 200, await overview(ws, nowProvider));\n return true;\n }\n if (sub === \"sessions\") {\n sendJson(res, 200, await sessionsList(ws, nowProvider));\n return true;\n }\n const sessionId = matchId(sub, \"sessions/\");\n if (sessionId !== null) {\n sendJson(res, 200, await sessionDetail(ws, sessionId));\n return true;\n }\n if (sub === \"tasks\") {\n sendJson(res, 200, await tasksList(ws));\n return true;\n }\n const taskId = matchId(sub, \"tasks/\");\n if (taskId !== null) {\n sendJson(res, 200, await taskDetail(ws, taskId));\n return true;\n }\n if (sub === \"decisions\") {\n sendJson(res, 200, await decisionsView(ws, nowProvider));\n return true;\n }\n if (sub === \"approvals\") {\n sendJson(res, 200, await approvalsView(ws, nowProvider));\n return true;\n }\n if (sub === \"handoff\") {\n sendJson(res, 200, await handoffView(ws, nowProvider));\n return true;\n }\n if (sub === \"stats\") {\n sendJson(res, 200, await computeWorkStats({ paths: ws.paths, now: nowProvider() }));\n return true;\n }\n return false;\n}\n\n/** POST routes scoped to one workspace. Returns false if `sub` matched nothing. */\nasync function handleWorkspacePost(\n res: ServerResponse,\n sub: string,\n ws: WorkspaceEntry,\n body: Record<string, unknown>,\n deps: ViewServerDeps,\n runExclusive: <T>(fn: () => Promise<T>) => Promise<T>,\n): Promise<boolean> {\n const nowIso = deps.nowProvider().toISOString();\n const actionOptions = readActionOptions(body);\n\n if (sub === \"refresh\") {\n const result = await runExclusive(() =>\n refreshAll({ options: actionOptions, ctx: ws.importCtx, paths: ws.paths, nowIso }),\n );\n sendJson(res, 200, result);\n return true;\n }\n if (sub === \"import/claude-code\") {\n sendJson(res, 200, await runExclusive(() => importClaudeCode(actionOptions, ws.importCtx)));\n return true;\n }\n if (sub === \"import/codex\") {\n sendJson(res, 200, await runExclusive(() => importCodex(actionOptions, ws.importCtx)));\n return true;\n }\n if (sub === \"handoff/generate\") {\n sendJson(res, 200, await runExclusive(() => regenerateHandoff(ws.paths, nowIso)));\n return true;\n }\n if (sub === \"decisions/generate\") {\n sendJson(res, 200, await runExclusive(() => regenerateDecisions(ws.paths, nowIso)));\n return true;\n }\n return false;\n}\n\n// --- workspace registry helpers -------------------------------------------\n\nfunction primaryWorkspace(deps: ViewServerDeps): WorkspaceEntry {\n const first = deps.workspaces[0];\n if (first === undefined) throw new HttpError(500, \"No workspace configured\");\n return first;\n}\n\nfunction findWorkspace(deps: ViewServerDeps, key: string): WorkspaceEntry | null {\n return deps.workspaces.find((w) => w.key === key) ?? null;\n}\n\n/** Parse `/api/ws/<key>/<sub...>`. `key` is decoded and used only for equality lookup. */\nfunction matchWsRoute(pathname: string): { key: string; sub: string } | null {\n if (!pathname.startsWith(WS_PREFIX)) return null;\n const rest = pathname.slice(WS_PREFIX.length);\n const slash = rest.indexOf(\"/\");\n if (slash <= 0) return null;\n const sub = rest.slice(slash + 1);\n if (sub.length === 0) return null;\n let key: string;\n try {\n key = decodeURIComponent(rest.slice(0, slash));\n } catch {\n return null;\n }\n if (key.length === 0 || key.includes(\"/\") || key.includes(\"\\0\")) return null;\n return { key, sub };\n}\n\n// --- handlers -------------------------------------------------------------\n\n/**\n * Aggregate the per-workspace \"current position\" for the portfolio landing.\n * Read-only: it runs NO import, so a stale capture is shown as stale (run a\n * refresh to re-import). Each card carries STRUCTURED FACTS only (latest\n * session/decision, in-flight count, pending-approval risk, suspect count,\n * capture freshness) — never work-stats or per-agent productivity metrics. One\n * workspace failing to read degrades only its own card, not the whole response.\n */\nasync function portfolio(deps: ViewServerDeps): Promise<Record<string, unknown>> {\n const nowIso = deps.nowProvider().toISOString();\n const workspaces = await Promise.all(deps.workspaces.map((ws) => portfolioCard(ws, nowIso)));\n // Each staleness probe runs a dry-run import, which swaps the process-global\n // console to capture output (see captureImportJson). That swap is NOT\n // reentrant, so the probes must run ONE AT A TIME — running them inside the\n // parallel map above let them clobber each other's capture and most failed.\n // The summaries above are pure reads and stay parallel; only this loop serializes.\n for (let i = 0; i < deps.workspaces.length; i++) {\n const card = workspaces[i];\n const ws = deps.workspaces[i];\n if (\n ws !== undefined &&\n card !== undefined &&\n card.initialized === true &&\n card.error === undefined\n ) {\n card.staleness = await captureStaleness(ws, nowIso);\n }\n }\n return { mode: deps.mode, generatedAt: nowIso, workspaces };\n}\n\nasync function portfolioCard(ws: WorkspaceEntry, nowIso: string): Promise<Record<string, unknown>> {\n const base = { key: ws.key, label: ws.label, repoRoot: ws.repoRoot };\n if (!ws.initialized) {\n return ws.manifestError !== undefined\n ? { ...base, initialized: false, error: ws.manifestError }\n : { ...base, initialized: false };\n }\n try {\n const s = await summarizeOrientation({ paths: ws.paths, nowIso });\n return {\n ...base,\n initialized: true,\n sessionCount: s.sessionCount,\n suspectCount: s.suspects.length,\n inFlightCount: s.inFlightTasks.length,\n pendingApprovals: s.pendingApprovals.map((a) => ({\n risk: a.risk,\n kind: a.kind,\n expired: a.expired,\n })),\n latestDecision: s.latestDecision !== null ? { title: s.latestDecision.title } : null,\n latestSession:\n s.latestSession !== null\n ? { label: s.latestSession.label, status: s.latestSession.status }\n : null,\n freshness: { newestStartedAt: s.freshness.newestStartedAt, bySource: s.freshness.bySource },\n };\n } catch (error: unknown) {\n return { ...base, initialized: true, error: pathlessMessage(error) };\n }\n}\n\n/**\n * Make a stale capture visible instead of silent: a non-zero count becomes a\n * \"run refresh\" badge so the operator can tell a genuinely idle workspace from\n * one merely behind on imports. Delegates to the shared {@link probeStaleness}\n * (a read-only dry-run; the portfolio's read-only guarantee holds) and maps its\n * `null` (probe failed) to `{ checked: false }` so a card still renders.\n */\nasync function captureStaleness(\n ws: WorkspaceEntry,\n nowIso: string,\n): Promise<Record<string, unknown>> {\n const probe = await probeStaleness({ ctx: ws.importCtx, paths: ws.paths, nowIso });\n return probe === null ? { checked: false } : { checked: true, ...probe };\n}\n\nasync function overview(\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<Record<string, unknown>> {\n let manifest: Manifest;\n try {\n manifest = await readManifest(ws.paths);\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n return { initialized: false, repoRoot: ws.repoRoot };\n }\n throw error;\n }\n const nowIso = nowProvider().toISOString();\n const handoff = await renderHandoff({ paths: ws.paths, nowIso });\n const approvals = await enumerateApprovals(ws.paths);\n return {\n initialized: true,\n repoRoot: ws.repoRoot,\n workspace: {\n id: manifest.workspace.id,\n name: manifest.workspace.name,\n basouVersion: manifest.basou_version,\n },\n counts: {\n sessions: handoff.sessionCount,\n suspectSessions: handoff.suspectCount,\n tasks: handoff.taskCount,\n pendingTasks: handoff.pendingTaskCount,\n decisions: handoff.decisionCount,\n approvalsPending: approvals.pending.length,\n approvalsResolved: approvals.resolved.length,\n },\n generatedAt: nowIso,\n };\n}\n\nasync function sessionsList(\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<Record<string, unknown>> {\n const entries = await loadSessionEntries(ws.paths, { now: nowProvider() });\n // loadSessionEntries returns oldest-first; show newest-first.\n const sessions = entries\n .map((entry) => ({\n sessionId: entry.sessionId,\n label: entry.session.session.label ?? null,\n status: entry.session.session.status,\n sourceKind: entry.session.session.source.kind,\n startedAt: entry.session.session.started_at,\n endedAt: entry.session.session.ended_at ?? null,\n suspect: entry.suspect,\n suspectReason: entry.suspectReason,\n taskId: entry.session.session.task_id ?? null,\n relatedFilesCount: entry.session.session.related_files.length,\n }))\n .reverse();\n return { sessions };\n}\n\nasync function sessionDetail(\n ws: WorkspaceEntry,\n sessionId: string,\n): Promise<Record<string, unknown>> {\n let session: Awaited<ReturnType<typeof readSessionYaml>>;\n try {\n session = await readSessionYaml(ws.paths, sessionId);\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"YAML file not found\") {\n throw new HttpError(404, \"Session not found\");\n }\n throw error;\n }\n // An unreadable events.jsonl must not 500 the detail view; surface the\n // session with an empty, flagged-degraded timeline (mirrors the list path).\n try {\n const events = await readAllEvents(join(ws.paths.sessions, sessionId));\n return { session, events };\n } catch {\n return { session, events: [], degraded: true };\n }\n}\n\nasync function tasksList(ws: WorkspaceEntry): Promise<Record<string, unknown>> {\n const entries = await loadTaskEntries(ws.paths);\n return { tasks: entries.map((entry) => entry.task).reverse() };\n}\n\nasync function taskDetail(ws: WorkspaceEntry, taskId: string): Promise<Record<string, unknown>> {\n try {\n const doc = await readTaskFile(ws.paths, taskId);\n return { task: doc.task, body: doc.body };\n } catch (error: unknown) {\n if (error instanceof Error && error.message === \"Task file not found\") {\n throw new HttpError(404, \"Task not found\");\n }\n throw error;\n }\n}\n\nasync function decisionsView(\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<Record<string, unknown>> {\n // Prefer the on-disk decisions.md so hand-edited content (outside the\n // generated markers) is shown, mirroring the handoff view; fall back to a\n // fresh render when the file does not exist yet.\n const fromDisk = await readMarkdownFile(ws.paths.files.decisions);\n if (fromDisk !== null) {\n return { body: fromDisk, fromDisk: true };\n }\n const nowIso = nowProvider().toISOString();\n const result = await renderDecisions({ paths: ws.paths, nowIso });\n return { body: result.body, decisionCount: result.decisionCount, fromDisk: false };\n}\n\nasync function approvalsView(\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<Record<string, unknown>> {\n const now = nowProvider();\n const ids = await enumerateApprovals(ws.paths);\n const toViews = async (list: string[]): Promise<Array<Record<string, unknown>>> => {\n const views: Array<Record<string, unknown>> = [];\n for (const id of list) {\n const loaded = await loadApproval(ws.paths, id);\n if (loaded === null) continue;\n views.push({ id, expired: isLazyExpired(loaded.approval, now), approval: loaded.approval });\n }\n return views;\n };\n return { pending: await toViews(ids.pending), resolved: await toViews(ids.resolved) };\n}\n\nasync function handoffView(\n ws: WorkspaceEntry,\n nowProvider: () => Date,\n): Promise<Record<string, unknown>> {\n const fromDisk = await readMarkdownFile(ws.paths.files.handoff);\n if (fromDisk !== null) {\n return { body: fromDisk, fromDisk: true };\n }\n const nowIso = nowProvider().toISOString();\n const result = await renderHandoff({ paths: ws.paths, nowIso });\n return { body: result.body, fromDisk: false };\n}\n\n// --- request helpers ------------------------------------------------------\n\nfunction readActionOptions(body: Record<string, unknown>): RefreshActionOptions {\n const options: RefreshActionOptions = {};\n // Accept `project` as a single string (the UI sends one) or an array of\n // strings (multi-root callers); normalize to a non-empty string[].\n const project = normalizeProject(body.project);\n if (project.length > 0) options.project = project;\n if (body.force === true) options.force = true;\n if (body.dryRun === true) options.dryRun = true;\n return options;\n}\n\n/** Coerce a request body `project` field into a list of non-empty path strings. */\nfunction normalizeProject(value: unknown): string[] {\n const raw = Array.isArray(value) ? value : [value];\n return raw.filter((p): p is string => typeof p === \"string\" && p.length > 0);\n}\n\nfunction hostAllowed(req: IncomingMessage, port: number): boolean {\n const host = req.headers.host;\n return host === `127.0.0.1:${port}` || host === `localhost:${port}`;\n}\n\nfunction originAllowed(req: IncomingMessage, port: number): boolean {\n const origin = req.headers.origin;\n if (origin === undefined) return true; // non-browser client (curl, tests)\n return origin === `http://127.0.0.1:${port}` || origin === `http://localhost:${port}`;\n}\n\nasync function readBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n size += buf.length;\n if (size > MAX_BODY_BYTES) throw new HttpError(413, \"Request body too large\");\n chunks.push(buf);\n }\n const raw = Buffer.concat(chunks).toString(\"utf8\").trim();\n if (raw.length === 0) return {};\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // fall through to the shared 400 below\n }\n throw new HttpError(400, \"Invalid JSON body\");\n}\n\nfunction matchId(pathname: string, prefix: string): string | null {\n if (!pathname.startsWith(prefix)) return null;\n const encoded = pathname.slice(prefix.length);\n if (encoded.length === 0 || encoded.includes(\"/\")) return null;\n let id: string;\n try {\n id = decodeURIComponent(encoded);\n } catch {\n return null; // malformed percent-escape\n }\n // Reject anything that could escape the storage root once decoded: a path\n // separator (incl. the percent-encoded `%2f` that slips past the check\n // above) or a `.`/`..` segment. Ids are otherwise opaque to this layer.\n if (\n id.length === 0 ||\n id.includes(\"/\") ||\n id.includes(\"\\\\\") ||\n id.includes(\"\\0\") ||\n id === \".\" ||\n id === \"..\"\n ) {\n return null;\n }\n return id;\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(body);\n}\n\nfunction sendHtml(res: ServerResponse, html: string): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(html);\n}\n\nfunction sendError(res: ServerResponse, status: number, message: string): void {\n if (res.headersSent) {\n res.end();\n return;\n }\n sendJson(res, status, { error: message });\n}\n\n/**\n * A pathless, audience-safe message: the Error's own message is already\n * pathless by the codebase's convention; native fs errors are wrapped before\n * they reach here. Falls back to a generic string for non-Error throws.\n */\nfunction pathlessMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Internal error\";\n}\n","/**\n * The single-page UI for `basou view`, served verbatim at `GET /`. Kept as one\n * inline string so the CLI build needs no asset pipeline. All data is rendered\n * with createElement / textContent (never innerHTML), so session, task, and\n * command content cannot inject markup. The embedded script deliberately uses\n * no template literals (this file is itself a template literal).\n *\n * Two modes, distinguished by the `mode` field of `GET /api/portfolio`:\n * - single: one workspace; the tabbed detail view drives `/api/*` directly.\n * - portfolio: a landing of per-workspace cards; clicking one drills into the\n * same tabbed view scoped to `/api/ws/<key>/*`. All per-workspace fetches go\n * through `state.base`, so the single-mode code path is unchanged.\n */\nexport const VIEW_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>basou view</title>\n<style>\n :root { color-scheme: light dark; }\n * { box-sizing: border-box; }\n body { margin: 0; font: 14px/1.5 system-ui, -apple-system, Segoe UI, sans-serif; }\n header { padding: 10px 16px; border-bottom: 1px solid #8884; display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; }\n header h1 { font-size: 15px; margin: 0 12px 0 0; font-weight: 700; }\n header .grow { flex: 1; }\n input[type=text] { padding: 4px 8px; border: 1px solid #8886; border-radius: 6px; min-width: 280px; font: inherit; }\n button { padding: 4px 10px; border: 1px solid #8886; border-radius: 6px; background: #8881; cursor: pointer; font: inherit; }\n button.primary { background: #2563eb; color: #fff; border-color: #2563eb; }\n button:disabled { opacity: .5; cursor: default; }\n label.chk { font-size: 13px; opacity: .85; }\n /* On the portfolio landing there is no selected workspace, so the per-workspace action bar is hidden. */\n body.landing #project, body.landing label.chk,\n body.landing #btn-refresh, body.landing #btn-import-claude, body.landing #btn-import-codex,\n body.landing #btn-gen-handoff, body.landing #btn-gen-decisions { display: none; }\n #status { padding: 6px 16px; font-size: 13px; min-height: 20px; border-bottom: 1px solid #8884; white-space: pre-wrap; }\n #status.err { color: #dc2626; }\n .err { color: #dc2626; }\n nav { display: flex; gap: 2px; padding: 6px 12px; border-bottom: 1px solid #8884; flex-wrap: wrap; }\n nav button { border: none; border-radius: 6px; background: transparent; }\n nav button.active { background: #2563eb22; font-weight: 600; }\n main { display: grid; grid-template-columns: minmax(220px, 320px) 1fr; min-height: 60vh; }\n main.single { grid-template-columns: 1fr; }\n #list { border-right: 1px solid #8884; overflow: auto; max-height: 80vh; }\n #list .row { padding: 8px 12px; border-bottom: 1px solid #8883; cursor: pointer; }\n #list .row:hover { background: #8881; }\n #list .row.active { background: #2563eb22; }\n #list .row .meta { font-size: 12px; opacity: .7; }\n #detail { padding: 12px 16px; overflow: auto; max-height: 80vh; }\n .badge { display: inline-block; padding: 0 6px; border-radius: 6px; background: #8882; font-size: 12px; }\n .badge.warn { background: #f59e0b33; }\n .badge.danger { background: #ef444433; }\n .badge.ok { background: #22c55e33; }\n pre { background: #8881; padding: 12px; border-radius: 8px; overflow: auto; white-space: pre-wrap; word-break: break-word; }\n table.kv { border-collapse: collapse; }\n table.kv td { padding: 2px 10px 2px 0; vertical-align: top; }\n table.kv td.k { opacity: .7; }\n .cards { display: flex; flex-wrap: wrap; gap: 10px; }\n .card { border: 1px solid #8884; border-radius: 8px; padding: 10px 14px; min-width: 120px; }\n .card .n { font-size: 22px; font-weight: 700; }\n .card .l { font-size: 12px; opacity: .7; }\n .pcard { min-width: 240px; max-width: 340px; }\n .pcard.open { cursor: pointer; }\n .pcard.open:hover { background: #8881; }\n .pcard .l { font-size: 14px; font-weight: 700; opacity: 1; margin-bottom: 4px; }\n .pcard .f { font-size: 13px; }\n .tl { border-left: 2px solid #8885; margin-left: 6px; padding-left: 12px; }\n .tl .ev { margin-bottom: 8px; }\n .tl .ev .t { font-size: 12px; opacity: .65; }\n .muted { opacity: .6; }\n</style>\n</head>\n<body>\n<header>\n <h1>basou view</h1>\n <button id=\"btn-back\" style=\"display:none\">&larr; portfolio</button>\n <input type=\"text\" id=\"project\" placeholder=\"source root (optional override)\" />\n <button class=\"primary\" id=\"btn-refresh\">Refresh all</button>\n <button id=\"btn-import-claude\">Import claude-code</button>\n <button id=\"btn-import-codex\">Import codex</button>\n <button id=\"btn-gen-handoff\">Regenerate handoff</button>\n <button id=\"btn-gen-decisions\">Regenerate decisions</button>\n <span class=\"grow\"></span>\n <label class=\"chk\"><input type=\"checkbox\" id=\"opt-force\" /> force</label>\n <label class=\"chk\"><input type=\"checkbox\" id=\"opt-dry\" /> dry-run</label>\n</header>\n<div id=\"status\"></div>\n<nav id=\"tabs\"></nav>\n<main id=\"main\">\n <div id=\"list\"></div>\n <div id=\"detail\"></div>\n</main>\n<script>\n(function () {\n var TABS = ['overview', 'stats', 'sessions', 'tasks', 'decisions', 'approvals', 'handoff'];\n // base is the API prefix for the active workspace: '/api' in single mode,\n // '/api/ws/<key>' once a portfolio card is opened.\n // canAct gates the mutating action bar: true only when a concrete workspace\n // is active (single mode, or a portfolio card opened). It is the real safety\n // guard — body.landing also hides the buttons, but that is cosmetic.\n var state = { tab: 'overview', repoRoot: '', base: '/api', mode: 'single', wsKey: null, canAct: false };\n\n function $(id) { return document.getElementById(id); }\n function clear(node) { while (node.firstChild) node.removeChild(node.firstChild); }\n\n function el(tag, attrs, children) {\n var node = document.createElement(tag);\n if (attrs) {\n for (var k in attrs) {\n if (!Object.prototype.hasOwnProperty.call(attrs, k)) continue;\n if (k === 'class') node.className = attrs[k];\n else if (k === 'text') node.textContent = attrs[k];\n else if (k.slice(0, 2) === 'on') node.addEventListener(k.slice(2), attrs[k]);\n else node.setAttribute(k, attrs[k]);\n }\n }\n if (children) {\n for (var i = 0; i < children.length; i++) {\n var c = children[i];\n if (c === null || c === undefined) continue;\n node.appendChild(typeof c === 'string' ? document.createTextNode(c) : c);\n }\n }\n return node;\n }\n\n function setStatus(msg, isErr) {\n var s = $('status');\n s.textContent = msg || '';\n s.className = isErr ? 'err' : '';\n }\n\n function fetchJson(path, opts) {\n return fetch(path, opts).then(function (res) {\n return res.text().then(function (text) {\n var data = null;\n try { data = text ? JSON.parse(text) : null; } catch (e) { data = null; }\n if (!res.ok) {\n var m = data && data.error ? data.error : ('HTTP ' + res.status);\n throw new Error(m);\n }\n return data;\n });\n });\n }\n\n function single(on) { $('main').className = on ? 'single' : ''; if (on) clear($('list')); }\n\n // --- action bar ---------------------------------------------------------\n\n function actionBody() {\n var body = {};\n var project = $('project').value.trim();\n if (project) body.project = project;\n if ($('opt-force').checked) body.force = true;\n if ($('opt-dry').checked) body.dryRun = true;\n return body;\n }\n\n function setBusy(busy) {\n var ids = ['btn-refresh', 'btn-import-claude', 'btn-import-codex', 'btn-gen-handoff', 'btn-gen-decisions'];\n for (var i = 0; i < ids.length; i++) $(ids[i]).disabled = busy;\n }\n\n // Enable the action bar only when a workspace is active; disabled buttons\n // cannot post to a stale/wrong workspace even if a CSS regression un-hides them.\n function updateActionBar() {\n var ids = ['btn-refresh', 'btn-import-claude', 'btn-import-codex', 'btn-gen-handoff', 'btn-gen-decisions'];\n for (var i = 0; i < ids.length; i++) $(ids[i]).disabled = !state.canAct;\n }\n\n function post(path, label) {\n if (!state.canAct) { setStatus('Open a workspace first.', true); return; }\n setBusy(true);\n setStatus(label + '...', false);\n fetchJson(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(actionBody())\n }).then(function (data) {\n setStatus(label + ' done: ' + summarize(data), false);\n loadTab(state.tab);\n }).catch(function (err) {\n setStatus(label + ' failed: ' + err.message, true);\n }).then(function () { setBusy(false); });\n }\n\n function summarize(data) {\n if (!data) return 'ok';\n if (data.claudeCode || data.codex) {\n return 'claude-code ' + imp(data.claudeCode) + ', codex ' + imp(data.codex)\n + (data.handoff && data.handoff.status === 'generated' ? '; handoff+decisions regenerated' : '');\n }\n if (data.status === 'ran') return imp(data);\n if (data.status === 'skipped') return 'skipped (' + data.reason + ')';\n if (typeof data.sessionCount === 'number') return 'sessions ' + data.sessionCount + ', decisions ' + data.decisionCount;\n if (typeof data.decisionCount === 'number') return 'decisions ' + data.decisionCount;\n return 'ok';\n }\n function imp(o) {\n if (!o) return '-';\n if (o.status === 'skipped') return 'skipped';\n return (o.dryRun ? 'would import ' : 'imported ') + o.importedCount + ' (' + o.eventTotal + ' events)';\n }\n\n // --- portfolio landing --------------------------------------------------\n\n function boot() {\n fetchJson('/api/portfolio').then(function (d) {\n if (d && d.mode === 'portfolio') { state.mode = 'portfolio'; showLanding(d); }\n else { enterSingle(); }\n }).catch(function () {\n // First-load bootstrap failure: the single-workspace view is the safe default.\n enterSingle();\n });\n }\n\n // Re-render the portfolio landing (the back button). Unlike boot(), a fetch\n // failure here keeps the inert landing and shows an error rather than silently\n // dropping into single mode pointed at the first workspace.\n function backToPortfolio() {\n enterLandingChrome();\n fetchJson('/api/portfolio').then(function (d) {\n if (d && d.workspaces) renderCards(d);\n else portfolioError('Portfolio unavailable.');\n }).catch(function (err) { portfolioError('Could not load portfolio: ' + err.message); });\n }\n\n function enterSingle() {\n state.mode = 'single';\n state.base = '/api';\n state.wsKey = null;\n state.canAct = true;\n document.body.classList.remove('landing');\n $('btn-back').style.display = 'none';\n updateActionBar();\n buildTabs();\n loadTab('overview');\n }\n\n // Landing chrome: no workspace is active, so actions are disabled (and hidden\n // by body.landing). The disable is the safety guard; the hide is cosmetic.\n function enterLandingChrome() {\n state.wsKey = null;\n state.canAct = false;\n document.body.classList.add('landing');\n $('btn-back').style.display = 'none';\n setStatus('', false);\n clear($('tabs'));\n updateActionBar();\n single(true);\n }\n\n function showLanding(d) { enterLandingChrome(); renderCards(d); }\n\n function renderCards(d) {\n var detail = $('detail');\n clear(detail);\n var ws = d.workspaces || [];\n detail.appendChild(el('p', { class: 'muted', text: 'Portfolio — ' + ws.length + ' workspace(s). Click a card to open it.' }));\n var cards = el('div', { class: 'cards' }, []);\n ws.forEach(function (w) { cards.appendChild(portfolioCard(w, d.generatedAt)); });\n detail.appendChild(cards);\n }\n\n function portfolioError(msg) {\n var detail = $('detail');\n clear(detail);\n detail.appendChild(el('p', { class: 'err', text: msg }));\n detail.appendChild(el('button', { text: 'Retry', onclick: backToPortfolio }));\n }\n\n function highestRisk(approvals) {\n var order = ['critical', 'high', 'medium', 'low'];\n for (var i = 0; i < order.length; i++) {\n for (var j = 0; j < approvals.length; j++) {\n if (approvals[j].risk === order[i]) return order[i];\n }\n }\n return approvals.length ? approvals[0].risk : '';\n }\n\n // Human-readable age of an ISO timestamp relative to the portfolio's\n // generatedAt (\"now\"), so a stale capture reads as \"3d ago\" not a raw ISO.\n function relAge(iso, nowIso) {\n if (!iso) return '(none)';\n var ms = Date.parse(nowIso) - Date.parse(iso);\n if (!isFinite(ms)) return iso;\n if (ms < 60000) return 'just now';\n var m = Math.floor(ms / 60000); if (m < 60) return m + 'm ago';\n var h = Math.floor(m / 60); if (h < 48) return h + 'h ago';\n return Math.floor(h / 24) + 'd ago';\n }\n\n // A \"run refresh\" badge when a dry-run found uncaptured/changed native sessions,\n // an \"up to date\" badge when the capture is current, and nothing loud when the\n // staleness probe could not run (degrades to a quiet note).\n function stalenessBadge(st) {\n if (!st) return null;\n if (!st.checked) return el('span', { class: 'badge', text: 'freshness unknown' });\n if (st.unverifiableSessions > 0)\n return el('span', { class: 'badge danger', text: '⚠ ' + st.unverifiableSessions + ' unverifiable — run verify' });\n if (st.newSessions > 0)\n return el('span', { class: 'badge danger', text: '⚠ ' + st.newSessions + ' uncaptured — run refresh' });\n if (st.updatedSessions > 0)\n return el('span', { class: 'badge warn', text: st.updatedSessions + ' updated — run refresh' });\n return el('span', { class: 'badge ok', text: 'up to date' });\n }\n\n function portfolioCard(w, generatedAt) {\n if (!w.initialized) {\n return el('div', { class: 'card pcard muted' }, [\n el('div', { class: 'l', text: w.label }),\n el('div', { class: 'f', text: w.error ? ('unreadable: ' + w.error) : 'not initialized' })\n ]);\n }\n if (w.error) {\n return el('div', { class: 'card pcard' }, [\n el('div', { class: 'l', text: w.label }),\n el('div', { class: 'f' }, [el('span', { class: 'badge warn', text: 'unreadable: ' + w.error })])\n ]);\n }\n var pend = w.pendingApprovals || [];\n var pendText = 'pending ' + pend.length + (pend.length ? ' (' + highestRisk(pend) + ')' : '');\n var now = w.latestSession ? ((w.latestSession.label || '(session)') + ' [' + w.latestSession.status + ']') : '(no live sessions)';\n var dec = w.latestDecision ? w.latestDecision.title : '(no decisions yet)';\n var newest = (w.freshness && w.freshness.newestStartedAt) ? w.freshness.newestStartedAt : null;\n var badge = stalenessBadge(w.staleness);\n return el('div', { class: 'card pcard open', onclick: function () { openWorkspace(w.key, w.label); } }, [\n el('div', { class: 'l' }, [\n el('span', { text: w.label }),\n badge ? el('span', { text: ' ' }) : null,\n badge\n ]),\n el('div', { class: 'f', text: 'now: ' + now }),\n el('div', { class: 'f', text: 'latest: ' + dec }),\n el('div', { class: 'f', text: 'in-flight ' + w.inFlightCount + ' | ' + pendText + ' | suspect ' + w.suspectCount }),\n el('div', { class: 'f muted', text: 'sessions ' + w.sessionCount + ' | newest ' + relAge(newest, generatedAt) })\n ]);\n }\n\n function openWorkspace(key, label) {\n state.mode = 'portfolio';\n state.wsKey = key;\n state.base = '/api/ws/' + encodeURIComponent(key);\n state.canAct = true;\n document.body.classList.remove('landing');\n $('btn-back').style.display = '';\n updateActionBar();\n setStatus('workspace: ' + label, false);\n buildTabs();\n loadTab('overview');\n }\n\n // --- tabs ---------------------------------------------------------------\n\n function buildTabs() {\n var nav = $('tabs');\n clear(nav);\n TABS.forEach(function (name) {\n nav.appendChild(el('button', {\n class: name === state.tab ? 'active' : '',\n text: name,\n onclick: function () { loadTab(name); }\n }));\n });\n }\n\n function loadTab(name) {\n state.tab = name;\n buildTabs();\n clear($('detail'));\n clear($('list'));\n if (name === 'overview') return loadOverview();\n if (name === 'stats') return loadStats();\n if (name === 'sessions') return loadSessions();\n if (name === 'tasks') return loadTasks();\n if (name === 'decisions') return loadMarkdown(state.base + '/decisions', 'decisions');\n if (name === 'approvals') return loadApprovals();\n if (name === 'handoff') return loadMarkdown(state.base + '/handoff', 'handoff');\n }\n\n function fail(err) { setStatus(err.message, true); }\n\n function loadOverview() {\n single(true);\n fetchJson(state.base + '/overview').then(function (d) {\n var detail = $('detail');\n if (!d || d.initialized === false) {\n detail.appendChild(el('p', { class: 'muted', text: 'Workspace not initialized.' }));\n return;\n }\n // Leave the project field empty by default so refresh / import use the\n // manifest's import.source_roots (then the repo root) -- pre-filling the\n // repo root here would send it as an explicit --project and silently\n // override multi-root source roots. The field is an optional override.\n state.repoRoot = d.repoRoot || '';\n detail.appendChild(el('p', {}, [\n el('strong', { text: d.workspace.name }), ' ',\n el('span', { class: 'muted', text: d.workspace.id })\n ]));\n var c = d.counts;\n var cards = el('div', { class: 'cards' }, [\n card(c.sessions, 'sessions'),\n card(c.suspectSessions, 'suspect'),\n card(c.tasks, 'tasks'),\n card(c.pendingTasks, 'pending tasks'),\n card(c.decisions, 'decisions'),\n card(c.approvalsPending, 'approvals pending')\n ]);\n detail.appendChild(cards);\n detail.appendChild(el('p', { class: 'muted', text: 'repo: ' + d.repoRoot }));\n }).catch(fail);\n }\n function card(n, label) {\n return el('div', { class: 'card' }, [\n el('div', { class: 'n', text: String(n) }),\n el('div', { class: 'l', text: label })\n ]);\n }\n\n function numfmt(n) { return (n || 0).toLocaleString('en-US'); }\n function fmtDur(ms) {\n var s = Math.round((ms || 0) / 1000);\n var h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;\n if (h > 0) return h + 'h ' + (m < 10 ? '0' : '') + m + 'm';\n if (m > 0) return m + 'm ' + (sec < 10 ? '0' : '') + sec + 's';\n return sec + 's';\n }\n function kvrow(k, v) {\n return el('tr', {}, [el('td', { class: 'k', text: k }), el('td', { text: v })]);\n }\n\n function loadStats() {\n single(true);\n fetchJson(state.base + '/stats').then(function (d) {\n var detail = $('detail');\n var t = d.totals;\n detail.appendChild(el('p', { text: 'Sessions: ' + t.sessionCount }));\n detail.appendChild(el('h3', { text: 'Volume (what the AI produced)' }));\n detail.appendChild(el('div', { class: 'cards' }, [\n card(numfmt(t.tokens.output), 'output tokens'),\n (t.tokens.reasoning > 0 ? card(numfmt(t.tokens.reasoning), 'reasoning tokens') : null),\n card(t.commandCount, 'commands'),\n card(t.fileChangedCount, 'files'),\n card(t.decisionCount, 'decisions')\n ]));\n var sessions = d.sessions || [];\n var tokenSessions = sessions.filter(function (s) { return s.availability && s.availability.tokens; }).length;\n if (!t.tokensAvailable) {\n detail.appendChild(el('p', { class: 'muted', text: 'No token data captured; re-import to backfill.' }));\n } else if (tokenSessions < t.sessionCount) {\n detail.appendChild(el('p', { class: 'muted', text: 'Token data on ' + tokenSessions + ' of ' + t.sessionCount + ' sessions; re-import to backfill the rest.' }));\n }\n var degraded = sessions.filter(function (s) { return s.eventsUnreadable; }).length;\n if (degraded > 0) {\n detail.appendChild(el('p', { class: 'muted', text: degraded + ' session(s) had unreadable event logs; their counts are incomplete.' }));\n }\n detail.appendChild(el('h3', { text: 'Time (human harness labor; active = billing primary)' }));\n var turnSessions = sessions.filter(function (s) { return s.activeTimeBasis === 'engaged-turns'; }).length;\n var basisNote = turnSessions === t.sessionCount ? 'engaged turns' : (turnSessions === 0 ? 'event stream; re-import to capture conversation' : 'engaged turns on ' + turnSessions + ' of ' + t.sessionCount + ' sessions');\n var timeRows = [kvrow('billable active', fmtDur(t.billableActiveTimeMs) + ' (union; ' + basisNote + '; idle gaps > 5m excluded; tz ' + d.timeZone + ')')];\n if (t.activeTimeMs !== t.billableActiveTimeMs) {\n timeRows.push(kvrow('summed', fmtDur(t.activeTimeMs) + ' (concurrent sessions double-counted)'));\n }\n if (t.machineActiveAvailable) {\n var machineSessions = sessions.filter(function (s) { return s.availability && s.availability.machineActive; }).length;\n timeRows.push(kvrow('model working', fmtDur(t.machineActiveTimeMs) + ' (model compute, subset of active; Codex turn duration on ' + machineSessions + ' of ' + t.sessionCount + ' sessions; not wall-clock-deduped)'));\n }\n timeRows.push(kvrow('span', fmtDur(t.sessionSpanMs) + (t.openSessionCount > 0 ? ' (' + t.openSessionCount + ' open)' : '')));\n timeRows.push(kvrow('command', fmtDur(t.commandTimeMs) + (t.commandTimeReliable ? '' : ' (some sessions report 0)')));\n detail.appendChild(el('table', { class: 'kv' }, [el('tbody', {}, timeRows)]));\n if (d.bySource && d.bySource.length) {\n detail.appendChild(el('h3', { text: 'By source' }));\n d.bySource.forEach(function (s) {\n var cmd = s.commandTimeReliable ? fmtDur(s.commandTimeMs) : 'n/a';\n var machine = s.machineActiveAvailable ? ', model ' + fmtDur(s.machineActiveTimeMs) : '';\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: s.sourceKind + ': ' + s.sessionCount + ' sessions, ' + numfmt(s.tokens.output) + ' out tok, active ' + fmtDur(s.activeTimeMs) + machine + ', command ' + cmd })\n ]));\n });\n }\n if (d.byDay && d.byDay.length) {\n detail.appendChild(el('h3', { text: 'By day (billable time x volume)' }));\n d.byDay.forEach(function (day) {\n var dayMachine = day.machineActiveTimeMs > 0 ? ' (model ' + fmtDur(day.machineActiveTimeMs) + ')' : '';\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: day.date + ': ' + fmtDur(day.billableActiveTimeMs) + ' active' + dayMachine + ', ' + numfmt(day.tokens.output) + ' out tok, ' + day.commandCount + ' cmd / ' + day.fileChangedCount + ' files / ' + day.decisionCount + ' dec' })\n ]));\n });\n }\n }).catch(fail);\n }\n\n function loadSessions() {\n single(false);\n fetchJson(state.base + '/sessions').then(function (d) {\n var list = $('list');\n var rows = (d && d.sessions) || [];\n if (rows.length === 0) { list.appendChild(el('div', { class: 'row muted', text: 'no sessions' })); return; }\n rows.forEach(function (s) {\n var row = el('div', { class: 'row', onclick: function () { selectSession(row, s.sessionId); } }, [\n el('div', { text: s.label || s.sessionId }),\n el('div', { class: 'meta', text: s.sourceKind + ' ' + s.status + (s.suspect ? ' suspect' : '') })\n ]);\n list.appendChild(row);\n });\n }).catch(fail);\n }\n function selectSession(row, id) {\n var rows = $('list').querySelectorAll('.row');\n for (var i = 0; i < rows.length; i++) rows[i].classList.remove('active');\n row.classList.add('active');\n var detail = $('detail');\n clear(detail);\n fetchJson(state.base + '/sessions/' + encodeURIComponent(id)).then(function (d) {\n var s = d.session.session;\n detail.appendChild(el('h3', { text: s.label || id }));\n detail.appendChild(kv([\n ['status', s.status], ['source', s.source.kind], ['started', s.started_at],\n ['ended', s.ended_at || '-'], ['workdir', s.working_directory]\n ]));\n if (d.degraded) detail.appendChild(el('p', { class: 'badge warn', text: 'events unreadable' }));\n var events = d.events || [];\n detail.appendChild(el('p', { class: 'muted', text: events.length + ' events' }));\n var tl = el('div', { class: 'tl' }, []);\n events.forEach(function (ev) {\n tl.appendChild(el('div', { class: 'ev' }, [\n el('div', { class: 't', text: ev.occurred_at + ' ' + ev.type }),\n el('div', { text: eventSummary(ev) })\n ]));\n });\n detail.appendChild(tl);\n }).catch(fail);\n }\n function eventSummary(ev) {\n if (ev.type === 'command_executed') {\n var cmd = (ev.args && ev.args.length) ? ev.args.join(' ') : ev.command;\n var ex = (ev.exit_code === null || ev.exit_code === undefined) ? '' : ' (exit ' + ev.exit_code + ')';\n return cmd + ex;\n }\n if (ev.type === 'file_changed') return ev.path + ' [' + ev.change_type + ']';\n if (ev.type === 'decision_recorded') return ev.title || '';\n return '';\n }\n\n function loadTasks() {\n single(false);\n fetchJson(state.base + '/tasks').then(function (d) {\n var list = $('list');\n var rows = (d && d.tasks) || [];\n if (rows.length === 0) { list.appendChild(el('div', { class: 'row muted', text: 'no tasks' })); return; }\n rows.forEach(function (t) {\n var row = el('div', { class: 'row', onclick: function () { selectTask(row, t.id); } }, [\n el('div', { text: t.title || t.label || t.id }),\n el('div', { class: 'meta', text: String(t.status || '') })\n ]);\n list.appendChild(row);\n });\n }).catch(fail);\n }\n function selectTask(row, id) {\n var rows = $('list').querySelectorAll('.row');\n for (var i = 0; i < rows.length; i++) rows[i].classList.remove('active');\n row.classList.add('active');\n var detail = $('detail');\n clear(detail);\n fetchJson(state.base + '/tasks/' + encodeURIComponent(id)).then(function (d) {\n detail.appendChild(el('h3', { text: (d.task && (d.task.title || d.task.label)) || id }));\n detail.appendChild(el('pre', { text: JSON.stringify(d.task, null, 2) }));\n if (d.body) detail.appendChild(el('pre', { text: d.body }));\n }).catch(fail);\n }\n\n function loadMarkdown(path, label) {\n single(true);\n fetchJson(path).then(function (d) {\n var detail = $('detail');\n var count = (typeof d.decisionCount === 'number') ? (' (' + d.decisionCount + ' decisions)') : '';\n detail.appendChild(el('p', { class: 'muted', text: label + count }));\n detail.appendChild(el('pre', { text: (d && d.body) || '(empty)' }));\n }).catch(fail);\n }\n\n function loadApprovals() {\n single(true);\n fetchJson(state.base + '/approvals').then(function (d) {\n var detail = $('detail');\n var groups = [['pending', d.pending || []], ['resolved', d.resolved || []]];\n groups.forEach(function (g) {\n detail.appendChild(el('h3', { text: g[0] + ' (' + g[1].length + ')' }));\n if (g[1].length === 0) { detail.appendChild(el('p', { class: 'muted', text: 'none' })); return; }\n g[1].forEach(function (a) {\n detail.appendChild(el('div', { class: 'row' }, [\n el('span', { text: a.id + ' ' }),\n el('span', { class: a.expired ? 'badge warn' : 'badge', text: a.expired ? 'expired' : (a.approval && a.approval.status) || '' })\n ]));\n });\n });\n }).catch(fail);\n }\n\n function kv(pairs) {\n var tbody = el('tbody', {}, pairs.map(function (p) {\n return el('tr', {}, [el('td', { class: 'k', text: p[0] }), el('td', { text: String(p[1]) })]);\n }));\n return el('table', { class: 'kv' }, [tbody]);\n }\n\n // --- wire up ------------------------------------------------------------\n\n $('btn-back').addEventListener('click', function () { backToPortfolio(); });\n $('btn-refresh').addEventListener('click', function () { post(state.base + '/refresh', 'Refresh all'); });\n $('btn-import-claude').addEventListener('click', function () { post(state.base + '/import/claude-code', 'Import claude-code'); });\n $('btn-import-codex').addEventListener('click', function () { post(state.base + '/import/codex', 'Import codex'); });\n $('btn-gen-handoff').addEventListener('click', function () { post(state.base + '/handoff/generate', 'Regenerate handoff'); });\n $('btn-gen-decisions').addEventListener('click', function () { post(state.base + '/decisions/generate', 'Regenerate decisions'); });\n\n boot();\n})();\n</script>\n</body>\n</html>`;\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["id","acquireLock","assertBasouRootSafe","basouPaths","findErrorCode","prefixedUlid","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","prefixedUlid","acquireLock","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","join","acquireLock","assertBasouRootSafe","basouPaths","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","acquireLock","readYamlFile","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","readMarkdownFile","renderWithMarkers","resolveRepositoryRoot","writeMarkdownFile","basouPaths","assertWorkspaceInitialized","readMarkdownFile","renderWithMarkers","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","homedir","join","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","readSessionYaml","resolveRepositoryRoot","SES_PREFIX","SHORT_ID_LEN","join","homedir","basouPaths","assertWorkspaceInitialized","readManifest","payload","readSessionYaml","findErrorCode","shortId","resolveRepositoryRoot","assertBasouRootSafe","basename","resolve","resolveRepositoryRoot","basename","resolve","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","renderOrientation","writeMarkdownFile","readMarkdownFile","renderDecisions","renderHandoff","renderWithMarkers","writeMarkdownFile","renderHandoff","readMarkdownFile","writeMarkdownFile","renderWithMarkers","renderDecisions","basouPaths","assertWorkspaceInitialized","renderOrientation","writeMarkdownFile","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","InvalidArgumentError","homedir","join","resolve","readYamlFile","readdir","stat","homedir","join","findErrorCode","join","homedir","readdir","findErrorCode","stat","collectPath","InvalidArgumentError","resolve","basouPaths","assertWorkspaceInitialized","assertBasouRootSafe","findErrorCode","isAbsolute","resolve","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","writeMarkdownFile","basouPaths","assertWorkspaceInitialized","isAbsolute","resolve","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","mkdir","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","ChildProcessRunner","coreAppendChainedEvent","finalizeSessionYaml","getSnapshot","overwriteYamlFile","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","SessionSchema","sanitizeWorkingDirectory","writeYamlFile","ChildProcessRunner","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","mkdir","coreAppendChainedEvent","buildInitialSession","writeYamlFile","tryAppendGitSnapshot","acquireLock","mutateSessionYaml","finalizeSessionAsFailed","homedir","decideFinalStatus","finalizeSessionYaml","signalToExitCode","SIGNUM_MAP","getSnapshot","normalizeGitSnapshotSkipMessage","sanitizeWorkingDirectory","readYamlFile","SessionSchema","overwriteYamlFile","resolveRepositoryRoot","readFile","basename","isAbsolute","join","relative","acquireLock","appendEventToExistingSession","assertBasouRootSafe","basouPaths","enumerateSessionDirs","findErrorCode","importSessionFromJson","readManifest","readYamlFile","resolveRepositoryRoot","resolveSessionId","SessionImportPayloadSchema","SessionSchema","InvalidArgumentError","SES_PREFIX","TASK_PREFIX","SHORT_ID_BASE_LEN","SHORT_ID_MAX_LEN","STATUS_VALUES","basouPaths","assertWorkspaceInitialized","resolveSessionId","join","readYamlFile","SessionSchema","findErrorCode","computeUniquePrefixLen","sliceShort","maxLen","pad","isAbsolute","relative","shortTaskId","shortId","resolveRepositoryRoot","assertBasouRootSafe","readManifest","SessionImportPayloadSchema","importOptions","importSessionFromJson","readFile","InvalidArgumentError","basename","acquireLock","appendEventToExistingSession","enumerateSessionDirs","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","basouPaths","assertBasouRootSafe","findErrorCode","readManifest","resolveRepositoryRoot","readFile","join","assertBasouRootSafe","basouPaths","findErrorCode","loadSessionEntries","prefixedUlid","readManifest","replayEvents","resolveRepositoryRoot","resolveSessionId","resolveTaskId","InvalidArgumentError","STATUS_VALUES","parseTitle","parsePositiveInt","basouPaths","assertWorkspaceInitialized","prefixedUlid","resolveSessionId","result","readManifest","maxLen","pad","resolveTaskId","loadSessionEntries","join","replayEvents","createInterface","InvalidArgumentError","readFile","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","assertBasouRootSafe","basouPaths","enumerateSessionDirs","findErrorCode","resolveRepositoryRoot","resolveSessionId","basouPaths","assertWorkspaceInitialized","resolveSessionId","enumerateSessionDirs","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","basename","resolve","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","InvalidArgumentError","isAbsolute","join","relative","resolve","readManifest","join","computeWorkStats","enumerateApprovals","findErrorCode","isLazyExpired","loadApproval","loadSessionEntries","loadTaskEntries","readAllEvents","readManifest","readMarkdownFile","readSessionYaml","readTaskFile","renderDecisions","renderHandoff","resolve","computeWorkStats","readManifest","findErrorCode","renderHandoff","enumerateApprovals","loadSessionEntries","readSessionYaml","readAllEvents","join","loadTaskEntries","readTaskFile","readMarkdownFile","renderDecisions","loadApproval","isLazyExpired","InvalidArgumentError","collectPath","basouPaths","assertWorkspaceInitialized","resolve","readManifest","basename","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","require"]}