@basou/cli 0.16.0 → 0.17.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.
- package/dist/index.js +60 -11
- package/dist/index.js.map +1 -1
- package/dist/program.js +60 -11
- package/dist/program.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/error-render.ts","../src/program.ts","../src/commands/approval.ts","../src/commands/decision.ts","../src/lib/repo-root.ts","../src/lib/portfolio-config.ts","../src/commands/decisions.ts","../src/commands/exec.ts","../src/commands/handoff.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/note.ts","../src/commands/orient.ts","../src/lib/hosts-config.ts","../src/lib/provenance-actions.ts","../src/commands/project.ts","../src/commands/protocol.ts","../src/lib/durable-write.ts","../src/lib/protocols-config.ts","../src/commands/refresh.ts","../src/commands/refresh-watch.ts","../src/commands/report.ts","../src/commands/review-gaps.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","../src/index.ts"],"sourcesContent":["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 { 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 { registerNoteCommand } from \"./commands/note.js\";\nimport { registerOrientCommand } from \"./commands/orient.js\";\nimport { registerProjectCommand } from \"./commands/project.js\";\nimport { registerProtocolCommand } from \"./commands/protocol.js\";\nimport { registerRefreshCommand } from \"./commands/refresh.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerReviewGapsCommand } from \"./commands/review-gaps.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 registerNoteCommand(program);\n registerTaskCommand(program);\n registerHandoffCommand(program);\n registerDecisionsCommand(program);\n registerReportCommand(program);\n registerOrientCommand(program);\n registerReviewGapsCommand(program);\n registerProjectCommand(program);\n registerProtocolCommand(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 { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n isValidPrefixedId,\n type PrefixedId,\n prefixedUlid,\n readManifest,\n resolveRepositoryRoot,\n resolveSessionId,\n type SessionStatus,\n sanitizePath,\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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.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 decision\n .command(\"capture\")\n .description(\n \"Capture a batch of decisions from a JSON array (stdin or --file). The \" +\n \"in-loop agent extracts a session's conversational decisions -- with \" +\n \"rationale, alternatives, and rejected reasons -- and pipes them in; \" +\n \"basou writes them deterministically into one ad-hoc session.\",\n )\n .option(\"--file <path>\", \"Read the JSON array from a file instead of stdin\")\n .option(\"--dry-run\", \"Validate and preview the decisions without writing them\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .addHelpText(\"after\", CAPTURE_HELP)\n .action(async (options: DecisionCaptureOptions) => {\n await runDecisionCapture(options);\n });\n}\n\nconst CAPTURE_HELP = `\nInput format (a JSON array; one object per decision):\n [\n {\n \"title\": \"Adopt pnpm for the monorepo\",\n \"rationale\": \"Workspace protocol and a content-addressed store fit our layout.\",\n \"alternatives\": [\"npm workspaces\", \"yarn\"],\n \"rejected_reason\": \"npm hoisting caused phantom-dependency bugs\",\n \"linked_files\": [\"pnpm-workspace.yaml\"]\n }\n ]\n\nOnly \"title\" is required; every other field is optional. All decisions are\nwritten into one ad-hoc session timestamped now, so orientation surfaces them\nas the latest decisions. Run from a workspace-view directory and it resolves to\nthe planning repo, like 'basou orient' / 'basou refresh' / 'basou note'.\n\nExample (heredoc on stdin):\n basou decision capture <<'JSON'\n [{ \"title\": \"Ship the capture command\", \"rationale\": \"Close the why-capture gap\" }]\n JSON\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\nexport type DecisionCaptureOptions = {\n /** Read the JSON array from this file instead of stdin. */\n file?: string;\n /** Validate + preview without writing anything. */\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type DecisionCaptureContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n /**\n * Defaults to reading process.stdin to EOF. Injectable for tests so they do\n * not depend on a real stdin stream. Ignored when `--file` is given.\n */\n readInput?: () => Promise<string>;\n};\n\n/** One decision in the capture input: a title plus the optional rich fields. */\ntype CaptureDecisionInput = { title: string } & RichDecisionFields;\n\n/**\n * Programmatic entry for `basou decision capture`. Owns process exit state.\n * Tests targeting the success path or the thrown error should prefer\n * {@link doRunDecisionCapture}.\n */\nexport async function runDecisionCapture(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext = {},\n): Promise<void> {\n try {\n await doRunDecisionCapture(options, ctx);\n } catch (error: unknown) {\n // The ad-hoc path writes the decision events before finalizing\n // session.yaml; on a finalize failure the classifier surfaces \"do not\n // rerun\" so the agent does not re-pipe and duplicate the batch (mirrors\n // `basou decision record`).\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionCapture(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n // View-aware resolution (like orient / refresh / note) so capture works from\n // a workspace-view dir, redirecting to the planning repo where decisions.md\n // and orient live. `basou decision record` predates this and uses a plain\n // git-root resolver; aligning record is a separate, behavior-changing\n // follow-up, not in scope for the capture slice.\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"decision capture\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const raw = await readCaptureInput(options, ctx);\n const decisions = parseCaptureInput(raw);\n\n if (options.dryRun === true) {\n printCapturePreview(options, decisions);\n return;\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n // Mint the decision ids up front, in input order. prefixedUlid is monotonic,\n // so even though every event shares `occurredAt` the ids increase with input\n // order; decisions.md and orient (which sort by occurred_at then decision id)\n // therefore preserve the agent's ordering and treat the last item as latest.\n const decisionIds = decisions.map(() => prefixedUlid(\"decision\"));\n\n const manifest = await readManifest(paths);\n // Sanitize the --file path before it lands in session.yaml invocation.args:\n // an absolute path would otherwise leak the operator's machine layout into\n // persisted `.basou/` state, the same reason `working_directory` is\n // sanitized. Resolve against cwd first so a relative --file is rewritten the\n // same way readFile resolved it.\n const invocationArgs =\n options.file !== undefined\n ? [\n \"--file\",\n sanitizePath(resolve(cwd, options.file), {\n workingDirectory: repositoryRoot,\n homedir: homedir(),\n }),\n ]\n : [];\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildCaptureLabel(decisions.length),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou decision capture\",\n args: invocationArgs,\n },\n targetEventBuilders: decisions.map(\n (decision, index) =>\n (sessionId: PrefixedId<\"ses\">, eventId: PrefixedId<\"evt\">): Event =>\n buildDecisionEvent({\n eventId,\n sessionId,\n decisionId: decisionIds[index] as PrefixedId<\"decision\">,\n title: decision.title,\n occurredAt,\n rich: toRichFields(decision),\n }),\n ),\n });\n\n printCaptureResult(options, {\n sessionId: adHoc.sessionId,\n items: decisions.map((decision, index) => ({\n decisionId: decisionIds[index] as string,\n eventId: adHoc.targetEventIds[index] as string,\n input: decision,\n })),\n });\n}\n\nasync function readCaptureInput(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext,\n): Promise<string> {\n if (options.file !== undefined) {\n try {\n return await readFile(options.file, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(`Input file not found: ${options.file}`);\n }\n throw error;\n }\n }\n if (ctx.readInput !== undefined) {\n return await ctx.readInput();\n }\n // A bare invocation with no piped stdin would otherwise block forever; fail\n // fast with the same actionable hint the empty-input guard uses.\n if (process.stdin.isTTY === true) {\n throw new Error(NO_INPUT_HINT);\n }\n return await readStdinToEnd();\n}\n\nasync function readStdinToEnd(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nconst NO_INPUT_HINT = \"No input: pipe a JSON array of decisions to stdin or pass --file <path>.\";\n\nconst CAPTURE_ALLOWED_KEYS: ReadonlySet<string> = new Set([\n \"title\",\n \"rationale\",\n \"rejected_reason\",\n \"alternatives\",\n \"linked_events\",\n \"linked_files\",\n]);\n\n/**\n * Parse + validate the capture input. Errors name the offending array index and\n * field (e.g. `decision[2].title must be a non-empty string`) so the in-loop\n * agent can self-correct its extraction without guessing.\n */\nfunction parseCaptureInput(raw: string): CaptureDecisionInput[] {\n if (raw.trim().length === 0) {\n throw new Error(NO_INPUT_HINT);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error: unknown) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new Error(`Input is not valid JSON: ${detail}`);\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\"Input must be a JSON array of decision objects.\");\n }\n if (parsed.length === 0) {\n throw new Error(\"Input array must contain at least one decision.\");\n }\n return parsed.map((item, index) => validateCaptureItem(item, index));\n}\n\nfunction validateCaptureItem(item: unknown, index: number): CaptureDecisionInput {\n if (typeof item !== \"object\" || item === null || Array.isArray(item)) {\n throw new Error(`decision[${index}] must be a JSON object.`);\n }\n const obj = item as Record<string, unknown>;\n for (const key of Object.keys(obj)) {\n if (!CAPTURE_ALLOWED_KEYS.has(key)) {\n throw new Error(\n `decision[${index}]: unknown field '${key}'. Allowed: title, rationale, rejected_reason, alternatives, linked_events, linked_files.`,\n );\n }\n }\n if (typeof obj.title !== \"string\" || isBlank(obj.title)) {\n throw new Error(`decision[${index}].title must be a non-empty string.`);\n }\n const out: CaptureDecisionInput = { title: obj.title };\n if (obj.rationale !== undefined) {\n out.rationale = requireNonEmptyString(obj.rationale, index, \"rationale\");\n }\n if (obj.rejected_reason !== undefined) {\n out.rejected_reason = requireNonEmptyString(obj.rejected_reason, index, \"rejected_reason\");\n }\n if (obj.alternatives !== undefined) {\n out.alternatives = validateStringArray(obj.alternatives, index, \"alternatives\", (value, i) => {\n if (isBlank(value)) {\n throw new Error(`decision[${index}].alternatives[${i}] must not be empty.`);\n }\n });\n }\n if (obj.linked_events !== undefined) {\n out.linked_events = validateStringArray(\n obj.linked_events,\n index,\n \"linked_events\",\n (value, i) => {\n if (!isValidEventId(value)) {\n throw new Error(\n `decision[${index}].linked_events[${i}] must match evt_<ULID>, got '${value}'.`,\n );\n }\n },\n );\n }\n if (obj.linked_files !== undefined) {\n out.linked_files = validateStringArray(obj.linked_files, index, \"linked_files\", (value, i) => {\n if (isBlank(value)) {\n throw new Error(`decision[${index}].linked_files[${i}] must not be empty.`);\n }\n if (value.length > 4096) {\n throw new Error(`decision[${index}].linked_files[${i}] exceeds 4096 chars.`);\n }\n });\n }\n return out;\n}\n\nfunction requireNonEmptyString(value: unknown, index: number, field: string): string {\n if (typeof value !== \"string\" || isBlank(value)) {\n throw new Error(`decision[${index}].${field} must be a non-empty string.`);\n }\n return value;\n}\n\n// Treat whitespace-only as empty: a blank title / rationale persists into\n// decisions.md and orientation as an unreadable entry. `basou note` already\n// guards this way; `decision record` / `decision capture` now match.\nfunction isBlank(value: string): boolean {\n return value.trim().length === 0;\n}\n\nfunction validateStringArray(\n value: unknown,\n index: number,\n field: string,\n checkEach: (value: string, i: number) => void,\n): string[] {\n if (!Array.isArray(value)) {\n throw new Error(`decision[${index}].${field} must be an array of strings.`);\n }\n return value.map((entry, i) => {\n if (typeof entry !== \"string\") {\n throw new Error(`decision[${index}].${field}[${i}] must be a string.`);\n }\n checkEach(entry, i);\n return entry;\n });\n}\n\nfunction toRichFields(decision: CaptureDecisionInput): RichDecisionFields {\n const out: RichDecisionFields = {};\n if (decision.rationale !== undefined) out.rationale = decision.rationale;\n if (decision.rejected_reason !== undefined) out.rejected_reason = decision.rejected_reason;\n if (decision.alternatives !== undefined) out.alternatives = [...decision.alternatives];\n if (decision.linked_events !== undefined) out.linked_events = [...decision.linked_events];\n if (decision.linked_files !== undefined) out.linked_files = [...decision.linked_files];\n return out;\n}\n\nfunction buildCaptureLabel(count: number): string {\n return `Ad-hoc capture: ${count} decision${count === 1 ? \"\" : \"s\"}`;\n}\n\ntype CaptureResultItem = { decisionId: string; eventId: string; input: CaptureDecisionInput };\n\nfunction captureItemToPayload(item: CaptureResultItem): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n decision_id: item.decisionId,\n event_id: item.eventId,\n title: item.input.title,\n };\n if (item.input.rationale !== undefined) payload.rationale = item.input.rationale;\n if (item.input.alternatives !== undefined) payload.alternatives = item.input.alternatives;\n if (item.input.rejected_reason !== undefined)\n payload.rejected_reason = item.input.rejected_reason;\n if (item.input.linked_events !== undefined) payload.linked_events = item.input.linked_events;\n if (item.input.linked_files !== undefined) payload.linked_files = item.input.linked_files;\n return payload;\n}\n\nfunction printCapturePreview(\n options: DecisionCaptureOptions,\n decisions: CaptureDecisionInput[],\n): void {\n if (options.json === true) {\n console.log(JSON.stringify({ dry_run: true, count: decisions.length, decisions }));\n return;\n }\n console.log(\n `Would capture ${decisions.length} decision${decisions.length === 1 ? \"\" : \"s\"} (dry run; nothing written):`,\n );\n for (const decision of decisions) {\n console.log(`- ${decision.title}`);\n }\n}\n\nfunction printCaptureResult(\n options: DecisionCaptureOptions,\n result: { sessionId: string; items: CaptureResultItem[] },\n): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n mode: \"ad-hoc\",\n session_id: result.sessionId,\n session_status: \"completed\",\n count: result.items.length,\n decisions: result.items.map(captureItemToPayload),\n }),\n );\n return;\n }\n console.log(\n `Captured ${result.items.length} decision${result.items.length === 1 ? \"\" : \"s\"} in ad-hoc session ${sid}:`,\n );\n for (const item of result.items) {\n console.log(`- ${item.decisionId}: ${item.input.title}`);\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 (isBlank(raw)) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseRationale(raw: string): string {\n if (isBlank(raw)) {\n throw new InvalidArgumentError(\"Rationale must not be empty\");\n }\n return raw;\n}\n\nfunction parseRejectedReason(raw: string): string {\n if (isBlank(raw)) {\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 (isBlank(value)) {\n throw new InvalidArgumentError(\"Alternative must not be empty\");\n }\n return prev.concat(value);\n}\n\n// Validate against the canonical event-id shape (`evt_<26-char Crockford ULID>`),\n// exactly what `EventIdSchema` enforces at write time. A looser check (e.g. a\n// bare `evt_[A-Z0-9]+` regex) would accept ids like `evt_X` here only for the\n// chained-append `EventSchema.parse` to reject them later with a generic\n// \"Invalid Basou event payload\" error -- and would let `decision capture\n// --dry-run` falsely report success. Shared by `decision record` and\n// `decision capture` so both reject the same set up front.\nfunction isValidEventId(value: string): boolean {\n return isValidPrefixedId(value) && value.startsWith(\"evt_\");\n}\n\nfunction collectLinkedEvent(value: string, prev: string[]): string[] {\n if (!isValidEventId(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 (isBlank(value)) {\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 { realpath, stat } from \"node:fs/promises\";\nimport { basename, resolve } from \"node:path\";\nimport { basouPaths, readManifest, resolveBasouRepositoryRoot } from \"@basou/core\";\nimport { DEFAULT_PORTFOLIO_CONFIG_PATH, loadPortfolioConfig } from \"./portfolio-config.js\";\n\n/** A planning master that aggregates the queried repo via its `source_roots`. */\nexport type MemberMaster = { root: string; label: string };\n\n/** Override the portfolio registry path (tests). */\nexport type ResolveRootOptions = {\n /** Defaults to {@link DEFAULT_PORTFOLIO_CONFIG_PATH}. */\n portfolioConfigPath?: string;\n};\n\n/**\n * Resolve the repository root for a CLI command with two fallbacks, shared by\n * `orient` / `refresh` / `note` / `decision capture` / `project *` /\n * `review-gaps` / `session` so they behave identically:\n *\n * 1. A git-untracked workspace *view* dir that symlinks its planning repo\n * redirects to that repo (handled inside {@link resolveBasouRepositoryRoot},\n * with a note on stderr).\n * 2. A portfolio *member* repo — a git repo that holds no `.basou/` store of its\n * own because its trail aggregates into a SEPARATE planning master via that\n * master's `import.source_roots` — redirects to the master. The git resolver\n * returns a member as its own toplevel (the view fallback only fires for\n * non-git dirs), so without this it would die downstream with \"Workspace not\n * initialized\". When the resolved repo has no store, the master's declaration\n * is honored in reverse via the portfolio registry (see\n * {@link resolveMemberToMaster}).\n *\n * A genuine non-git dir reports a command-specific \"run git init\" message.\n */\nexport async function resolveBasouRootForCommand(\n cwd: string,\n commandName: string,\n opts: ResolveRootOptions = {},\n): Promise<string> {\n let root: string;\n try {\n root = 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 // The view fallback already returns a master that has a `.basou/` store, so the\n // reverse-lookup only runs for a git repo that resolved to itself with no store\n // — the exact portfolio-member case (and the genuinely-uninitialized case,\n // where no master claims it and the original \"Workspace not initialized\"\n // message is preserved). Normal repos pay nothing: the store probe short-circuits.\n if (!(await hasBasouStore(root))) {\n const master = await resolveMemberToMaster(\n root,\n opts.portfolioConfigPath ?? DEFAULT_PORTFOLIO_CONFIG_PATH,\n );\n if (master !== undefined) {\n console.error(\n `Resolved portfolio member to ${master.root} (via portfolio: ${master.label}).`,\n );\n return master.root;\n }\n }\n return root;\n}\n\n/** Whether `root` owns a `.basou/` store directory. */\nasync function hasBasouStore(root: string): Promise<boolean> {\n try {\n return (await stat(basouPaths(root).root)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Reverse the `import.source_roots` declaration: find the planning master that\n * aggregates `repoRoot`. Reads the portfolio registry (`~/.basou/portfolio.yaml`),\n * and for each registered workspace resolves its `source_roots` to absolute,\n * realpath-canonicalized paths and checks whether any equals `repoRoot`'s\n * realpath. Returns the single claiming master, throws on ambiguity (>=2 DISTINCT\n * masters claim it), and returns `undefined` when nothing claims it or the\n * registry is absent (so the caller falls back to the unchanged behavior).\n *\n * Matching is realpath-based on both sides (the master root and each resolved\n * source root) so a symlinked layout, a `~`-relative registry entry, or platform\n * path aliases all collapse to one identity. Claimants are de-duped by that same\n * canonical root, so one master registered twice under different spellings (e.g.\n * a real path and a symlink alias — `loadPortfolioConfig` only de-dupes them\n * LEXICALLY) collapses to a single claimant rather than a false ambiguity; this\n * mirrors {@link resolveBasouRepositoryRoot}'s view fallback, which de-dupes\n * linked repos by resolved root. A master never claims itself (its own `.` source\n * root resolves to its root, which can't equal a storeless member).\n *\n * A present-but-broken registry, or a present-but-unreadable master manifest, is\n * surfaced on stderr (best-effort) rather than silently dropped: a genuinely\n * absent file is the expected case for any storeless repo, but a malformed config\n * is a fixable operator error that would otherwise hide behind the downstream\n * \"Workspace not initialized\" message (whose advice — run `basou init` — would\n * wrongly create a competing store inside the member). The SessionStart hook\n * discards stderr, so these notes only reach a manual invocation.\n */\nexport async function resolveMemberToMaster(\n repoRoot: string,\n configPath: string,\n): Promise<MemberMaster | undefined> {\n let workspaces: Awaited<ReturnType<typeof loadPortfolioConfig>>;\n try {\n workspaces = await loadPortfolioConfig(configPath);\n } catch (error: unknown) {\n // A genuinely-absent registry is the common case for any storeless repo that\n // is not a portfolio member: stay silent and fall through. A present-but-\n // malformed registry is a fixable operator error worth surfacing.\n if (!(error instanceof Error) || !error.message.startsWith(\"No portfolio config at\")) {\n const detail = error instanceof Error ? error.message : String(error);\n console.error(`Ignoring ~/.basou/portfolio.yaml: ${detail}`);\n }\n return undefined;\n }\n\n const memberReal = await realpathOrNull(repoRoot);\n if (memberReal === null) return undefined;\n\n // De-dupe by canonical master root: the same master reached via two registry\n // spellings (which survive loadPortfolioConfig's lexical de-dup) must count\n // once, or it would self-trigger a false ambiguity. First spelling's label wins.\n const claimants = new Map<string, MemberMaster>();\n const seenMaster = new Set<string>();\n for (const ws of workspaces) {\n const masterReal = await realpathOrNull(ws.path);\n if (masterReal === null) continue;\n if (masterReal === memberReal) continue; // a master never claims itself\n if (seenMaster.has(masterReal)) continue; // same master, another spelling — process once\n seenMaster.add(masterReal);\n let manifest: Awaited<ReturnType<typeof readManifest>>;\n try {\n manifest = await readManifest(basouPaths(masterReal));\n } catch (error: unknown) {\n // A missing manifest = a stale/uninitialized registry entry (master moved\n // or never initialized): expected, skip quietly. A present-but-unreadable\n // manifest (corrupt YAML / schema-invalid) is a real fault in an owned\n // workspace; surface it so a claiming master is not silently lost.\n if (error instanceof Error && error.message !== \"YAML file not found\") {\n console.error(\n `Skipping portfolio workspace '${ws.label ?? basename(masterReal)}': could not read its manifest (${error.message}).`,\n );\n }\n continue;\n }\n // Absent source_roots means the master aggregates only itself (\".\") — it can\n // never claim a separate member, so the default is harmless and correct.\n const sourceRoots = manifest.import?.source_roots ?? [\".\"];\n for (const sr of sourceRoots) {\n const real = await realpathOrNull(resolve(masterReal, sr));\n if (real !== null && real === memberReal) {\n claimants.set(masterReal, { root: masterReal, label: ws.label ?? basename(masterReal) });\n break;\n }\n }\n }\n\n const matched = [...claimants.values()];\n if (matched.length === 1) return matched[0] as MemberMaster;\n if (matched.length > 1) {\n const names = matched.map((c) => c.label).join(\", \");\n throw new Error(\n `This repository is declared as a source root by ${matched.length} portfolio workspaces (${names}). Disambiguate in ~/.basou/portfolio.yaml so only one aggregates it.`,\n );\n }\n return undefined;\n}\n\nasync function realpathOrNull(p: string): Promise<string | null> {\n try {\n return await realpath(p);\n } catch {\n return null;\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 {\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 // Claude Code's per-project directory name is lossy (every non-alphanumeric\n // char -> \"-\"), so distinct project paths can collide into one directory.\n // Attribute each transcript by its OWN recorded cwd and skip any that does not\n // belong to a requested project — mirroring the Codex adapter's cwd guard —\n // so a colliding sibling project's transcripts are not imported under this one.\n // (Equality matches the Codex adapter: the recorded cwd must equal a resolved\n // source root verbatim.)\n const projectSet = new Set(projectPaths);\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 const cwd = firstTranscriptCwd(records);\n if (cwd === undefined || !projectSet.has(cwd)) return null;\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 every NON-alphanumeric character with `-`, not\n * just the path separator, so `/Users/x/projects/foo_bar` becomes\n * `-Users-x-projects-foo-bar` (note `_` -> `-`, `.` -> `-`, etc.). Encoding\n * only `/` missed any project whose path contained `_`/`.`/space — its\n * transcripts were under a `-`-encoded directory while we looked for an\n * underscore-preserving one, so the whole project was silently skipped as\n * \"no source logs\". Matching the full rule keeps those projects discoverable.\n */\nfunction encodeProjectDir(projectPath: string): string {\n return projectPath.replace(/[^a-zA-Z0-9]/g, \"-\");\n}\n\n/**\n * The cwd a Claude transcript was recorded in — the first record that carries\n * one. Used to attribute a transcript to the project it belongs to when a lossy\n * directory-name collision colocates more than one project's transcripts.\n */\nfunction firstTranscriptCwd(records: ReadonlyArray<ClaudeTranscriptRecord>): string | undefined {\n for (const record of records) {\n const cwd = record.cwd;\n if (typeof cwd === \"string\" && cwd.length > 0) return cwd;\n }\n return undefined;\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 acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n type PrefixedId,\n readManifest,\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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\n\n// The note body becomes an ad-hoc session label; truncate long bodies for the\n// label only (the full body is preserved in the note_added event). Mirrors the\n// decision-title cap so labels stay single-column in session list / handoff.\nconst LABEL_BODY_MAX = 80;\nconst LABEL_TRUNCATE_HEAD = LABEL_BODY_MAX - 3;\n\nexport type NoteOptions = {\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type NoteContext = {\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 note` onto `program`. A one-shot, free-text note that orientation\n * surfaces as the recorded next step (\"次の起点\") — the in-model way to leave a\n * resume hint that survives into the next session. By default it creates an\n * ad-hoc session to hold the `note_added` event (imported sessions are not\n * attachable), mirroring `basou decision record`; `--session` attaches to an\n * existing attachable session instead.\n */\nexport function registerNoteCommand(program: Command): void {\n program\n .command(\"note\")\n .description(\"Record a free-text note (orientation surfaces the latest as the next step)\")\n .argument(\"<body>\", \"Note text\", parseBody)\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 (body: string, options: NoteOptions) => {\n await runNote(body, options);\n });\n}\n\n/**\n * Programmatic entry for `basou note`. Owns process exit state. Tests targeting\n * the success path or the thrown error should prefer {@link doRunNote}.\n */\nexport async function runNote(\n body: string,\n options: NoteOptions,\n ctx: NoteContext = {},\n): Promise<void> {\n try {\n await doRunNote(body, options, ctx);\n } catch (error: unknown) {\n // The ad-hoc path writes the note_added event before finalizing\n // session.yaml; on a finalize failure the classifier surfaces \"do not\n // rerun\" so the operator does not append a duplicate note (mirrors\n // `basou decision record`).\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunNote(\n body: string,\n options: NoteOptions,\n ctx: NoteContext,\n): Promise<void> {\n // Defense in depth: the commander parser (parseBody) rejects an empty body,\n // but doRunNote is also a public programmatic entry, so guard here too\n // (mirrors `basou session note`). Whitespace-only is treated as empty.\n if (body.trim().length === 0) {\n throw new Error(\"Note body must not be empty\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n // View-aware resolution so `basou note` works from a workspace-view dir\n // (redirects to the planning repo), matching orient / refresh / session.\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"note\");\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\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 events.jsonl append against a concurrent\n // writer (decision record / another note / an attach-flavoured task\n // command). appendEventToExistingSession holds no lock; the caller owns the\n // 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) => buildNoteEvent({ eventId, sessionId: sesId, occurredAt, body }),\n });\n } finally {\n await sessionLock.release();\n }\n printNoteResult(options, {\n mode: \"attached\",\n sessionId,\n eventId: result.eventId,\n sessionStatus: result.sessionStatus,\n body,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildAdHocLabel(body),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou note\",\n args: [body],\n },\n targetEventBuilders: [\n (sessionId, eventId) => buildNoteEvent({ eventId, sessionId, occurredAt, body }),\n ],\n });\n printNoteResult(options, {\n mode: \"ad-hoc\",\n sessionId: adHoc.sessionId,\n eventId: adHoc.targetEventIds[0] as string,\n sessionStatus: \"completed\",\n body,\n });\n}\n\nfunction buildNoteEvent(input: {\n eventId: PrefixedId<\"evt\">;\n sessionId: PrefixedId<\"ses\">;\n occurredAt: string;\n body: string;\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: \"note_added\",\n body: input.body,\n // `basou note` is the resume-hint command; mark it so orientation surfaces\n // it as the next step and a plain `basou session note` annotation does not.\n kind: \"next_step\",\n };\n}\n\nfunction buildAdHocLabel(body: string): string {\n // Collapse whitespace so a multi-line body still produces a single-line label.\n const oneLine = body.replace(/\\s+/g, \" \").trim();\n const truncated =\n oneLine.length > LABEL_BODY_MAX ? `${oneLine.slice(0, LABEL_TRUNCATE_HEAD)}...` : oneLine;\n return `Ad-hoc note: ${truncated}`;\n}\n\nfunction parseBody(raw: string): string {\n if (raw.trim().length === 0) {\n throw new InvalidArgumentError(\"Note body must not be empty\");\n }\n return raw;\n}\n\ntype NotePrintInput = {\n mode: \"ad-hoc\" | \"attached\";\n sessionId: string;\n eventId: string;\n sessionStatus: SessionStatus;\n body: string;\n};\n\nfunction printNoteResult(options: NoteOptions, result: NotePrintInput): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n body: result.body,\n }),\n );\n return;\n }\n if (result.mode === \"ad-hoc\") {\n console.log(`Recorded note ${result.eventId} in ad-hoc session ${sid}`);\n } else {\n console.log(`Recorded note ${result.eventId} in session ${sid} (${result.sessionStatus})`);\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 type FederatedRoot,\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 { loadHostsConfig } from \"../lib/hosts-config.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 /** Override path to the hosts registry (`~/.basou/hosts.yaml`). Injectable for tests. */\n hostsConfigPath?: string;\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 // Federation (zero-network): merge other hosts' trails listed in\n // ~/.basou/hosts.yaml, each a LOCAL path the operator's own tooling (an SSHFS\n // mount / rsync over their existing SSH) keeps in sync. Best-effort and\n // non-fatal: an absent registry is silent (local-only); a malformed one warns\n // and falls back to local-only so `orient` — the default command — never\n // hard-fails on it.\n let federatedRoots: FederatedRoot[] = [];\n try {\n const hosts = await loadHostsConfig(ctx.hostsConfigPath);\n if (hosts !== null) {\n federatedRoots = hosts.map((h) => ({ paths: basouPaths(h.path), host: h.label }));\n }\n } catch (error: unknown) {\n console.error(\n `basou: ignoring ~/.basou/hosts.yaml (${error instanceof Error ? error.message : String(error)}); showing local sessions only.`,\n );\n }\n\n const result = await renderOrientation({\n paths,\n nowIso,\n staleness,\n verbose: options.verbose === true,\n federatedRoots,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n onHostUnavailable: (host, error) =>\n console.error(\n `basou: host '${host}' mirror unreadable (${error instanceof Error ? error.message : String(error)}); skipping it.`,\n ),\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 { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { readYamlFile } from \"@basou/core\";\n\n/**\n * Local registry for federated, multi-host orientation (`basou orient`). Each\n * entry points at ANOTHER host's `.basou` store as it is reachable on THIS\n * machine as a LOCAL path — an SSHFS mount, an rsync / Syncthing mirror, etc.\n * basou performs NO network I/O: the operator's own tooling (over the SSH they\n * already use) keeps these paths in sync. Like `portfolio.yaml`, this is local\n * machine config, NOT provenance/trail data — it is never committed into a\n * monitored repo, so absolute paths are required.\n *\n * Shape:\n * version: 1 # optional, reserved for future migrations\n * hosts:\n * - label: laptop # required, non-empty, distinct (the host tag)\n * path: ~/mirrors/laptop/myrepo # required, absolute (~ ok) — the repo\n * # root (the parent of its `.basou`)\n */\nexport type HostMirror = { label: string; path: string };\n\n/** Canonical location of the hosts registry. */\nexport const DEFAULT_HOSTS_CONFIG_PATH = join(homedir(), \".basou\", \"hosts.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 `~/.basou/hosts.yaml` (or an injected path for tests).\n *\n * Returns `null` when the file is ABSENT: `orient` is the default command, so a\n * missing registry must be silent (\"no federation\") — unlike the explicit\n * `--portfolio`, whose loader throws. A present-but-malformed file THROWS a\n * pathless, user-facing message so the caller can warn and fall back to\n * local-only. Each `path` is `~`-expanded, required absolute, and de-duped by\n * resolved path (first occurrence wins, keeping its label and order). Labels\n * must be distinct (orientation collapses hosts by label). An empty `hosts:`\n * list returns `[]` (benign no-op, not an error).\n */\nexport async function loadHostsConfig(\n configPath: string = DEFAULT_HOSTS_CONFIG_PATH,\n): Promise<HostMirror[] | null> {\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 return null;\n }\n if (error instanceof Error && error.message === \"Failed to parse YAML content\") {\n throw new Error(\"~/.basou/hosts.yaml is not valid YAML.\");\n }\n throw error;\n }\n\n if (!isRecord(raw) || !Array.isArray(raw.hosts)) {\n throw new Error(\"~/.basou/hosts.yaml must contain a 'hosts:' list.\");\n }\n\n const seenPaths = new Set<string>();\n const seenLabels = new Set<string>();\n const result: HostMirror[] = [];\n for (const entry of raw.hosts) {\n if (!isRecord(entry) || typeof entry.label !== \"string\" || entry.label.trim().length === 0) {\n throw new Error(\"Each host needs a non-empty string 'label'.\");\n }\n const label = entry.label.trim();\n if (typeof entry.path !== \"string\" || entry.path.trim().length === 0) {\n throw new Error(\"Each host needs a non-empty string 'path'.\");\n }\n const expanded = expandTilde(entry.path.trim());\n if (!isAbsolute(expanded)) {\n throw new Error(\"Host paths must be absolute (or start with '~').\");\n }\n const abs = resolve(expanded);\n if (seenPaths.has(abs)) continue;\n // Distinct mirrors must have distinct labels: orientation collapses hosts by\n // label (a Set), so a duplicate would make two stores indistinguishable.\n if (seenLabels.has(label)) {\n throw new Error(`Duplicate host label '${label}'; each host needs a distinct label.`);\n }\n seenPaths.add(abs);\n seenLabels.add(label);\n result.push({ label, path: abs });\n }\n\n return result;\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 {\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n readlinkSync,\n realpathSync,\n statSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport {\n type AdoptCandidate,\n type ArchivePlan,\n basouPaths,\n type ExistingViewLink,\n GENERATED_END,\n GENERATED_START,\n type GitignorePlanSummary,\n type InstructionFileFact,\n type InstructionSymlinkFact,\n type InstructionSymlinkState,\n isGitNotFound,\n type Manifest,\n type PresetPlanSummary,\n parseMarkers,\n pathBasename,\n planArchive,\n planGitignore,\n planRename,\n planRosterAdoption,\n planWorkspaceView,\n type RenamePlan,\n type RepoEntry,\n type RepoGitignoreFacts,\n type RepoGitignorePlan,\n type RepoPresetFacts,\n type RepoPresetPlan,\n type RepoSymlinkFacts,\n type RepoSymlinkPlan,\n type RepoWiringFacts,\n type RosterAdoptionPlan,\n type RosterDriftSummary,\n readManifest,\n readMarkdownFile,\n reconcileSourceRoots,\n renderWithMarkers,\n type SourceRootsReconcile,\n type SymlinkPlanSummary,\n safeSimpleGit,\n summarizePresetPlan,\n summarizeRosterDrift,\n summarizeSymlinkPlan,\n summarizeWiring,\n unknownManifestKeys,\n type ViewRepoFact,\n type WiringSummary,\n type WorkspaceViewPlan,\n writeManifest,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\n\nexport type ProjectCheckOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectCheckContext = ImportContext;\n\nexport type ProjectSyncOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectSyncContext = ImportContext & { now?: () => Date };\n\n/** Flat result of {@link doRunProjectSync}: the reconciliation plus what was done. */\nexport type ProjectSyncResult = SourceRootsReconcile & {\n /** Whether a repo roster (`repos`) was declared at all (else there is nothing to sync from). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` was set AND there was drift to reconcile). */\n applied: boolean;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectAdoptOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectAdoptContext = ImportContext & { now?: () => Date };\n\n/** Flat result of {@link doRunProjectAdopt}: the proposed roster plus what was done. */\nexport type ProjectAdoptResult = RosterAdoptionPlan & {\n /** Whether a `repos` roster was ALREADY declared (adopt is a one-time bootstrap; `--apply` refuses). */\n alreadyDeclared: boolean;\n /** Whether the manifest was written (i.e. `--apply` set, no existing roster, AND at least one repo found). */\n applied: boolean;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectWiringOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectWiringContext = ImportContext;\n\n/** Result of {@link doRunProjectWiring}: the wiring summary plus whether a roster was declared. */\nexport type ProjectWiringResult = WiringSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to inspect — run adopt first). */\n hasRoster: boolean;\n};\n\nexport type ProjectGitignoreOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectGitignoreContext = ImportContext;\n\n/** Result of {@link doRunProjectGitignore}: the plan plus whether a roster exists and whether it was applied. */\nexport type ProjectGitignoreResult = GitignorePlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether `.gitignore` files were written (i.e. `--apply` was set AND there was something to add). */\n applied: boolean;\n};\n\nexport type ProjectSymlinksOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectSymlinksContext = ImportContext;\n\n/** Result of {@link doRunProjectSymlinks}: the plan plus whether a roster exists and what `--apply` did. */\nexport type ProjectSymlinksResult = SymlinkPlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether any symlinks were actually created (true only when `--apply` created at least one link). */\n applied: boolean;\n /** Per-file failures encountered during `--apply` (collected, not thrown — kept transparent). */\n failures: { repo: string; file: string; message: string }[];\n};\n\nexport type ProjectWorkspaceOptions = {\n apply?: boolean;\n prune?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectWorkspaceContext = ImportContext;\n\n/** Result of {@link doRunProjectWorkspace}: the view plan plus whether a view is declared and what `--apply` / `--prune` did. */\nexport type ProjectWorkspaceResult = WorkspaceViewPlan & {\n /** Whether `workspace.view` is declared (else there is no view to generate — solo project / not configured). */\n hasView: boolean;\n /** Whether any view symlinks were actually created (true only when `--apply` created at least one). */\n applied: boolean;\n /** Whether any stray view symlinks were actually removed (true only when `--prune` removed at least one). */\n pruned: boolean;\n /**\n * Whether `--prune` was requested with strays to remove but withheld because one\n * or more declared repos are unreachable (an unreachable repo's link can be\n * indistinguishable from a stray, so pruning is refused until the roster resolves).\n */\n pruneWithheld: boolean;\n /** Per-link create failures encountered during `--apply` (collected, not thrown — pathless reason). */\n failures: { name: string; message: string }[];\n /** Per-link prune failures encountered during `--prune` (collected, not thrown — pathless reason). */\n pruneFailures: { name: string; message: string }[];\n};\n\nexport type ProjectPresetOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectPresetContext = ImportContext;\n\n/** Result of {@link doRunProjectPreset}: the plan plus whether a roster exists and what `--apply` did. */\nexport type ProjectPresetResult = PresetPlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether any canonical was actually written (true only when `--apply` wrote at least one). */\n applied: boolean;\n /** Per-repo write failures encountered during `--apply` (collected, not thrown — pathless reason). */\n failures: { repo: string; message: string }[];\n};\n\nexport type ProjectArchiveOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectArchiveContext = ImportContext & { now?: () => Date };\n\n/** Repo-side wiring still present for the archived repo — a manual-teardown checklist (report-only). */\nexport type ArchiveTeardown = {\n /** False when the repo could not be resolved on disk (e.g. already deleted) — wiring not inspected. */\n inspected: boolean;\n /** The workspace view still has a `<basename>` entry for this repo. */\n viewLink: boolean;\n /** Instruction files still present in the repo (AGENTS.md / CLAUDE.md / copilot). */\n instructionFiles: string[];\n /** Instruction patterns still listed in the repo's `.gitignore`. */\n gitignorePatterns: string[];\n /** The anchor's canonical (`agents/<repo>/AGENTS.md`) still exists. */\n canonical: boolean;\n};\n\n/** Result of {@link doRunProjectArchive}: the plan plus whether a roster exists, the teardown checklist, and what `--apply` did. */\nexport type ProjectArchiveResult = ArchivePlan & {\n /** Whether a `repos` roster was declared (else there is nothing to archive — run adopt first). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` set, target found, and not the anchor). */\n applied: boolean;\n /** Repo-side wiring still present (report-only; `--apply` never touches it). */\n teardown: ArchiveTeardown;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectRenameOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectRenameContext = ImportContext & { now?: () => Date };\n\n/** Repo-side wiring at the OLD basename that a basename-changing rename leaves stale — a manual checklist (report-only). */\nexport type RenameWiring = {\n /** The anchor canonical dir `agents/<oldBasename>` still exists (rename to the new basename). */\n canonicalDirOld: boolean;\n /** The workspace view still has a `<oldBasename>` entry (rename to the new basename). */\n viewLinkOld: boolean;\n};\n\n/** Result of {@link doRunProjectRename}: the plan plus whether a roster exists, the repo-side checklist, and what `--apply` did. */\nexport type ProjectRenameResult = RenamePlan & {\n /** Whether a `repos` roster was declared (else there is nothing to rename — run adopt first). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` set and the rename was actionable). */\n applied: boolean;\n /** Repo-side wiring still at the old basename (report-only; `--apply` never touches it). */\n wiring: RenameWiring;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\n/**\n * Agent instruction files inspected per repo. GEMINI.md is intentionally absent\n * (the Gemini CLI was discontinued for personal use). Each should be a gitignored\n * symlink to a canonical source, never tracked in a public repo's history.\n */\nconst INSTRUCTION_FILES = [\"AGENTS.md\", \"CLAUDE.md\", \".github/copilot-instructions.md\"] as const;\n\n/**\n * The canonical instruction file name. It lives in the anchor at\n * `agents/<repo>/AGENTS.md` and is the hub each repo's own AGENTS.md symlink\n * resolves to; CLAUDE.md and Copilot are spokes pointing back at it.\n */\nconst CANONICAL_FILE = \"AGENTS.md\";\n\n/**\n * Wire `basou project` (a read-only inspector for the project's declared repo\n * roster) and its `check` subcommand onto `program`. The roster is the single\n * source of truth for which repos make up a project; `check` compares it\n * against the capture config (`source_roots`) and surfaces drift. It writes\n * nothing and enforces nothing.\n */\nexport function registerProjectCommand(program: Command): void {\n const project = program\n .command(\"project\")\n .description(\"Inspect a project's declared repo roster (read-only)\");\n\n project\n .command(\"check\")\n .description(\n \"Compare the declared repo roster (manifest `repos`) against the capture config (`source_roots`) and surface drift (read-only, advisory)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectCheckOptions) => {\n await runProjectCheck(opts);\n });\n\n project\n .command(\"sync\")\n .description(\n \"Reconcile the capture config (`source_roots`) to cover every declared repo (manifest `repos`). Dry-run by default; pass --apply to write. Additive only — it never removes an existing source root (e.g. the workspace view)\",\n )\n .option(\n \"--apply\",\n \"Write the reconciled source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectSyncOptions) => {\n await runProjectSync(opts);\n });\n\n project\n .command(\"adopt\")\n .description(\n \"Bootstrap a repo roster (manifest `repos`) from the existing capture config (`source_roots`): classify each by realpath + `.git`, keep the git repos, exclude non-repos (the workspace view, /tmp). Dry-run by default; pass --apply to write (refuses if a roster already exists)\",\n )\n .option(\"--apply\", \"Write the bootstrapped roster to the manifest (default: dry-run preview)\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectAdoptOptions) => {\n await runProjectAdopt(opts);\n });\n\n project\n .command(\"wiring\")\n .description(\n \"Inspect each declared repo's agent instruction-file wiring (AGENTS.md, CLAUDE.md, copilot-instructions.md): present? tracked by git? Surfaces privacy risks (a public repo tracking an instruction file) and gaps (read-only, advisory)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectWiringOptions) => {\n await runProjectWiring(opts);\n });\n\n project\n .command(\"gitignore\")\n .description(\n \"Reconcile each public-facing repo's .gitignore to exclude the agent instruction files (so the gitignored symlinks never enter public history). Dry-run by default; pass --apply to write. Additive only — it never removes a line; private repos and unset-visibility repos are left untouched\",\n )\n .option(\n \"--apply\",\n \"Append the missing patterns to each repo's .gitignore (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectGitignoreOptions) => {\n await runProjectGitignore(opts);\n });\n\n project\n .command(\"symlinks\")\n .description(\n \"Generate each declared repo's agent instruction-file symlinks (AGENTS.md, CLAUDE.md, copilot-instructions.md) pointing at the project anchor's canonical (agents/<repo>/AGENTS.md). Dry-run by default; pass --apply to create. Non-destructive — it only creates missing links and never overwrites an existing file or repoints a link\",\n )\n .option(\"--apply\", \"Create the missing instruction-file symlinks (default: dry-run preview)\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectSymlinksOptions) => {\n await runProjectSymlinks(opts);\n });\n\n project\n .command(\"workspace\")\n .description(\n \"Generate the project's workspace view: a directory (manifest `workspace.view`) that aggregates every declared repo via a `<repo-basename>` symlink (the anchor included). Dry-run by default; pass --apply to create missing links. Creation is non-destructive — it never overwrites an existing entry or repoints a link. Stray repo links (a view symlink whose repo is no longer in the roster) are reported always and removed only with --prune; pruning removes ONLY a symlink whose relative target resolves to a git repository (never a real file/dir, the view's own instruction files, a broken link, or a non-repo target), and never the linked repo itself\",\n )\n .option(\"--apply\", \"Create the missing view symlinks (default: dry-run preview)\")\n .option(\n \"--prune\",\n \"Remove stray repo symlinks (links the roster no longer backs); default: dry-run preview. Independent of --apply\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectWorkspaceOptions) => {\n await runProjectWorkspace(opts);\n });\n\n project\n .command(\"preset\")\n .description(\n \"Generate the stable-preset block (source visibility, source language, published surfaces) of each declared repo's canonical instruction file (agents/<repo>/AGENTS.md) from the manifest. Dry-run by default; pass --apply to write. Non-destructive — it only writes the marker-delimited region (creating an absent canonical, updating an out-of-date one) and never touches hand-authored content or a canonical whose markers are missing/malformed\",\n )\n .option(\n \"--apply\",\n \"Write the generated preset block to each canonical (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectPresetOptions) => {\n await runProjectPreset(opts);\n });\n\n project\n .command(\"archive\")\n .argument(\"<repo>\", \"The roster repo path to archive (as declared, e.g. ../takuhon)\")\n .description(\n \"Fold a repo out of the project: remove it from the declared roster (manifest `repos`) and prune its capture entry (`source_roots`). Dry-run by default; pass --apply to write. Manifest-only and reversible (the manifest is git-tracked); it never deletes the repo, its captured history, or its on-disk wiring (view symlink / instruction symlinks / .gitignore / canonical) — those are reported as a manual teardown checklist. Archiving the anchor (`.`) is refused\",\n )\n .option(\n \"--apply\",\n \"Write the pruned roster / source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (repo: string, opts: ProjectArchiveOptions) => {\n await runProjectArchive(repo, opts);\n });\n\n project\n .command(\"rename\")\n .argument(\"<old>\", \"The current roster repo path (as declared, e.g. ../takuhon)\")\n .argument(\"<new>\", \"The new roster repo path (e.g. ../takuhon-cli)\")\n .description(\n \"Re-path a repo in the project: update its declared roster path (manifest `repos`) and its capture entry (`source_roots`). Dry-run by default; pass --apply to write. Manifest-only and reversible (the manifest is git-tracked); it does not move the repo on disk or rewire it — when the basename changes, the anchor canonical dir and view symlink that still use the old name are reported as a manual checklist (re-run `basou project symlinks` / `workspace` after). Renaming the anchor (`.`) or onto an existing entry is refused\",\n )\n .option(\n \"--apply\",\n \"Write the re-pathed roster / source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (oldPath: string, newPath: string, opts: ProjectRenameOptions) => {\n await runProjectRename(oldPath, newPath, opts);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectCheck}. */\nexport async function runProjectCheck(\n options: ProjectCheckOptions,\n ctx: ProjectCheckContext = {},\n): Promise<void> {\n try {\n await doRunProjectCheck(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * The capture roots a manifest effectively scans. An absent `import.source_roots`\n * means \"the host repository only\" (import's documented default), so it resolves\n * to `[\".\"]` here — NOT the empty set. Comparing the roster against the empty set\n * would falsely report the host `.` as a capture gap after a solo-repo adoption.\n */\nfunction effectiveSourceRoots(manifest: Manifest): string[] {\n return manifest.import?.source_roots ?? [\".\"];\n}\n\n/**\n * Header advisory lines naming the unknown top-level manifest fields the loose\n * schema preserved (empty array => no lines). Surfaced by the read-modify-write\n * commands so preservation is not silent: basou keeps a field it does not\n * recognize (a newer version's section, a future adapter, a hand-added/typo'd\n * key) rather than dropping it on write, and says so.\n */\nfunction preservedUnknownLines(fields: string[]): string[] {\n if (fields.length === 0) return [];\n return [\n `ℹ️ basou が認識しない manifest のトップレベルフィールドを ${fields.length} 件保持しています(write 時も削除しません): ${fields.join(\", \")}`,\n \"\",\n ];\n}\n\n/** Pure runner: resolves the workspace, reads the manifest, computes the drift, prints it (or JSON). */\nexport async function doRunProjectCheck(\n options: ProjectCheckOptions,\n ctx: ProjectCheckContext,\n): Promise<RosterDriftSummary> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project check\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const summary = summarizeRosterDrift({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n sourceRoots: effectiveSourceRoots(manifest),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify(summary));\n } else {\n console.log(renderProjectCheck(summary));\n }\n return summary;\n}\n\n/**\n * Render the advisory report. Leads with the capture gaps (declared repos not\n * being captured — the actionable drift), then the captured-but-undeclared\n * paths (commonly the workspace view), and states the read-only / no-enforce\n * framing so the verdict is not over-read.\n */\nexport function renderProjectCheck(summary: RosterDriftSummary): string {\n const lines: string[] = [];\n lines.push(\"# プロジェクト構成チェック(宣言 vs 捕捉)\");\n lines.push(\"\");\n\n if (summary.declaredCount === 0) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`source_roots` のみで運用中のため、宣言との照合はできません。\",\n );\n if (summary.extra.length > 0) {\n lines.push(\"\");\n lines.push(`捕捉中の source_roots (${summary.extra.length}):`);\n for (const p of summary.extra) lines.push(`- ${p}`);\n }\n return lines.join(\"\\n\");\n }\n\n if (summary.gaps.length === 0) {\n lines.push(\n `✅ 宣言された ${summary.declaredCount} repo はすべて捕捉対象(source_roots)に含まれています。`,\n );\n } else {\n lines.push(`⚠️ 宣言されているのに捕捉対象に無い repo: ${summary.gaps.length}(取りこぼし)`);\n for (const g of summary.gaps) {\n lines.push(`- ${g.path}${g.visibility ? ` [${g.visibility}]` : \"\"} — source_roots に未登録`);\n }\n }\n lines.push(\"\");\n\n if (summary.extra.length > 0) {\n lines.push(\n `## 宣言外の捕捉対象 (${summary.extra.length}) — workspace view か、宣言漏れの可能性`,\n );\n for (const p of summary.extra) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: read-only の advisory です。宣言(repos)と捕捉設定(source_roots)の差分のみを表示し、enforce はしません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectSync}. */\nexport async function runProjectSync(\n options: ProjectSyncOptions,\n ctx: ProjectSyncContext = {},\n): Promise<void> {\n try {\n await doRunProjectSync(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Reconcile `source_roots` against the declared roster. Resolves the workspace,\n * reads the manifest, computes the additive reconciliation, and — only when\n * `--apply` is set and there is drift to fix — writes the manifest back (the\n * declared repos appended to `source_roots`, `workspace.updated_at` bumped).\n * Without `--apply` it writes nothing and prints the plan.\n */\nexport async function doRunProjectSync(\n options: ProjectSyncOptions,\n ctx: ProjectSyncContext,\n): Promise<ProjectSyncResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project sync\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const hasRoster = manifest.repos !== undefined && manifest.repos.length > 0;\n const reconcile = reconcileSourceRoots({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n });\n\n const applied = options.apply === true && hasRoster && !reconcile.unchanged;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(\n paths,\n {\n ...manifest,\n import: { ...manifest.import, source_roots: reconcile.next },\n workspace: { ...manifest.workspace, updated_at: now().toISOString() },\n },\n { force: true },\n );\n }\n\n const result: ProjectSyncResult = {\n ...reconcile,\n hasRoster,\n applied,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectSync(result));\n }\n return result;\n}\n\n/**\n * Render the sync report. Leads with the actionable outcome: nothing to sync\n * (no roster), already in sync, or the source roots that will be / were added.\n * The dry-run framing makes clear that without `--apply` nothing is written.\n */\nexport function renderProjectSync(result: ProjectSyncResult): string {\n const lines: string[] = [];\n lines.push(\"# source_roots 同期(宣言ロースター → 捕捉設定)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。同期の元になる宣言が無いため、変更はありません。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.unchanged) {\n lines.push(\"✅ source_roots は宣言ロースターをすべて覆っています(同期不要)。\");\n return lines.join(\"\\n\");\n }\n\n if (result.applied) {\n lines.push(`✅ source_roots に ${result.added.length} 件追加しました:`);\n for (const p of result.added) lines.push(`- ${p}`);\n } else {\n lines.push(\n `${result.added.length} 件の repo が source_roots に未登録です。追加予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.added) lines.push(`- ${p}`);\n lines.push(\"\");\n lines.push(\"注: 既存の source_roots は保持し、不足分の追記のみ行います(削除はしません)。\");\n }\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectAdopt}. */\nexport async function runProjectAdopt(\n options: ProjectAdoptOptions,\n ctx: ProjectAdoptContext = {},\n): Promise<void> {\n try {\n await doRunProjectAdopt(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Classify a declared source-root path against disk: a git repo root (`repo`),\n * a resolved-but-non-repo directory such as the workspace view or `/tmp`\n * (`non-repo`), or a path that does not resolve (`unresolved`). Resolves the\n * path relative to the repository root, then realpath (which follows the view's\n * symlink and unifies platform aliases) before probing for `.git`.\n */\nfunction classifySourceRoot(repositoryRoot: string, declaredPath: string): AdoptCandidate {\n const absolute = resolve(repositoryRoot, declaredPath);\n let real: string;\n try {\n real = realpathSync(absolute);\n } catch {\n return { path: declaredPath, kind: \"unresolved\" };\n }\n return { path: declaredPath, kind: existsSync(join(real, \".git\")) ? \"repo\" : \"non-repo\" };\n}\n\n/**\n * Bootstrap a `repos` roster from the existing `source_roots`. Resolves the\n * workspace, reads the manifest, classifies each source root on disk, and plans\n * the roster (git repos kept, non-repos/unresolved excluded). When `--apply` is\n * set, no roster exists yet, and at least one repo was found, it writes the\n * roster (and bumps `workspace.updated_at`). Without `--apply` — or when a\n * roster already exists — it writes nothing and prints the plan.\n *\n * `source_roots` absent mirrors import's default (the host repo `.` only), so a\n * solo repo adopts a `[\".\"]` roster.\n */\nexport async function doRunProjectAdopt(\n options: ProjectAdoptOptions,\n ctx: ProjectAdoptContext,\n): Promise<ProjectAdoptResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project adopt\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const alreadyDeclared = manifest.repos !== undefined && manifest.repos.length > 0;\n const candidates = effectiveSourceRoots(manifest).map((r) =>\n classifySourceRoot(repositoryRoot, r),\n );\n const plan = planRosterAdoption(candidates);\n\n const applied = options.apply === true && !alreadyDeclared && plan.repos.length > 0;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(\n paths,\n {\n ...manifest,\n repos: plan.repos,\n workspace: { ...manifest.workspace, updated_at: now().toISOString() },\n },\n { force: true },\n );\n }\n\n const result: ProjectAdoptResult = {\n ...plan,\n alreadyDeclared,\n applied,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectAdopt(result));\n }\n return result;\n}\n\n/**\n * Render the adoption report. Leads with the actionable outcome: a roster\n * already exists (nothing to bootstrap), nothing found, or the proposed roster\n * (with the excluded paths and why). The dry-run framing makes clear that\n * without `--apply` nothing is written, and reminds the operator to set\n * visibility afterward.\n */\nexport function renderProjectAdopt(result: ProjectAdoptResult): string {\n const lines: string[] = [];\n lines.push(\"# repo ロースターの bootstrap(source_roots → repos)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (result.alreadyDeclared) {\n lines.push(\n \"ℹ️ repo ロースター(manifest の `repos`)は既に宣言済みです。adopt は一度きりの bootstrap のため何も書き込みません。以後の保守は `project check` / `project sync` を使ってください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.repos.length === 0) {\n lines.push(\"ℹ️ source_roots に git repo が見つかりませんでした(bootstrap 対象なし)。\");\n } else if (result.applied) {\n lines.push(`✅ ${result.repos.length} repo を repos ロースターに書き込みました:`);\n for (const r of result.repos) lines.push(`- ${r.path}`);\n lines.push(\"\");\n lines.push(\n \"注: visibility は未設定です。各 repo に public / private / future-public を手動で付与してください。\",\n );\n } else {\n lines.push(\n `${result.repos.length} repo を repos ロースターに宣言予定(dry-run、反映するには --apply):`,\n );\n for (const r of result.repos) lines.push(`- ${r.path}`);\n lines.push(\"\");\n lines.push(\"注: visibility は未設定で提案します。反映後に手動で付与してください。\");\n }\n\n if (result.excluded.length > 0) {\n lines.push(\"\");\n lines.push(`## 除外 (${result.excluded.length}) — git repo ではないため repos に含めません`);\n for (const e of result.excluded) {\n const reason =\n e.kind === \"non-repo\" ? \"非 repo(workspace view / tmp 等)\" : \"解決不能(パスが存在しない)\";\n lines.push(`- ${e.path} — ${reason}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectWiring}. */\nexport async function runProjectWiring(\n options: ProjectWiringOptions,\n ctx: ProjectWiringContext = {},\n): Promise<void> {\n try {\n await doRunProjectWiring(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Whether a repo-relative path is tracked by git in `repoRoot`. `git ls-files`\n * prints the path when it is tracked and nothing when it is not. Any error\n * (missing git, a corrupt repo) propagates; {@link gatherRepoWiring} decides\n * whether to surface it (a missing git executable, which is global) or degrade\n * the single repo to unreachable (a per-repo failure) — never reading the error\n * as a false \"untracked\".\n */\nasync function isTrackedByGit(repoRoot: string, relPath: string): Promise<boolean> {\n const out = await safeSimpleGit(repoRoot).raw([\"ls-files\", \"--\", relPath]);\n return out.trim().length > 0;\n}\n\n/**\n * Gather the on-disk + git facts for one declared repo. Resolves the repo path\n * (realpath) and requires a `.git`; an unresolvable or non-repo path is reported\n * as `reachable: false` rather than crashing the whole report. Presence uses\n * `lstat` so a symlink (even a broken one) still counts as present.\n */\nasync function gatherRepoWiring(\n repositoryRoot: string,\n entry: RepoEntry,\n): Promise<RepoWiringFacts> {\n const base = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, reachable: false, instructionFiles: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, reachable: false, instructionFiles: [] };\n }\n\n try {\n const instructionFiles: InstructionFileFact[] = [];\n for (const name of INSTRUCTION_FILES) {\n let present = true;\n try {\n lstatSync(join(real, name));\n } catch {\n present = false;\n }\n instructionFiles.push({ name, present, tracked: await isTrackedByGit(real, name) });\n }\n return { ...base, reachable: true, instructionFiles };\n } catch (error: unknown) {\n // A missing git executable is a global, actionable failure — surface it so\n // the whole report does not silently read every repo as \"untracked\".\n if (isGitNotFound(error)) throw error;\n // A per-repo git failure (a corrupt repo, a stale worktree pointer) degrades\n // only THIS repo to unreachable, so one bad repo cannot blank the report.\n return { ...base, reachable: false, instructionFiles: [] };\n }\n}\n\n/**\n * Inspect each declared repo's instruction-file wiring. Resolves the workspace,\n * reads the manifest, gathers per-repo facts (presence + git-tracked status),\n * and summarizes the privacy-relevant drift. Read-only — it generates nothing.\n */\nexport async function doRunProjectWiring(\n options: ProjectWiringOptions,\n ctx: ProjectWiringContext,\n): Promise<ProjectWiringResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project wiring\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const facts: RepoWiringFacts[] = [];\n for (const entry of roster) facts.push(await gatherRepoWiring(repositoryRoot, entry));\n\n const summary = summarizeWiring(facts);\n const result: ProjectWiringResult = { ...summary, hasRoster: roster.length > 0 };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectWiring(result));\n }\n return result;\n}\n\n/**\n * Render the wiring report. Leads with the actionable outcome: no roster (run\n * adopt first), the privacy risks (a public repo tracking an instruction file),\n * the unjudgeable repos (visibility unset), and the wiring gaps (missing files).\n * States the read-only framing so the verdict is not over-read.\n */\nexport function renderProjectWiring(result: ProjectWiringResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 wiring チェック(宣言ロースター × 指示書の存在/git 追跡)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.risks.length > 0) {\n lines.push(\n `⚠️ 公開系 repo で指示書が git 追跡されています: ${result.risks.length}(canonical の漏洩リスク)`,\n );\n for (const r of result.risks) {\n lines.push(\n `- ${r.repo} [${r.visibility}] — ${r.file} が tracked(gitignore された symlink である必要があります)`,\n );\n }\n } else if (result.ok) {\n lines.push(\"✅ 公開系 repo で git 追跡されている指示書はありません(privacy リスクなし)。\");\n } else {\n // No confirmed risks, but unjudgeable / unreachable repos exist below — do NOT\n // lead with a clean \"no risk\" verdict (that would be a false-clear).\n lines.push(\n \"ℹ️ 確定した privacy リスクはありませんが、判定できない/到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.unknown.length > 0) {\n lines.push(\n `## visibility 未設定 (${result.unknown.length}) — privacy 判定不可。manifest の repos に visibility を付与してください`,\n );\n for (const p of result.unknown) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.incomplete.length > 0) {\n lines.push(`## 指示書の欠落 (${result.incomplete.length}) — 後続の生成スライスで補完予定`);\n for (const i of result.incomplete) lines.push(`- ${i.repo} — ${i.missing.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: read-only の advisory です。指示書の存在と git 追跡状況のみを表示し、生成・enforce はしません(.basou のフットプリントは `basou view --check`)。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectGitignore}. */\nexport async function runProjectGitignore(\n options: ProjectGitignoreOptions,\n ctx: ProjectGitignoreContext = {},\n): Promise<void> {\n try {\n await doRunProjectGitignore(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Gather one declared repo's `.gitignore` facts. Resolves the repo path\n * (realpath) and requires a `.git`; an unresolvable / non-repo path is reported\n * as `reachable: false`. Reads the repo's `.gitignore` into trimmed-on-compare\n * lines (an empty array when there is none). Pure filesystem reads — no writes.\n */\nfunction gatherRepoGitignore(repositoryRoot: string, entry: RepoEntry): RepoGitignoreFacts {\n const base = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, reachable: false, currentLines: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, reachable: false, currentLines: [] };\n }\n return { ...base, reachable: true, currentLines: readGitignoreLines(join(real, \".gitignore\")) };\n}\n\n/** True when an error carries a string `code` (a Node errno like `ENOENT`). */\nfunction hasErrorCode(error: unknown): error is Error & { code: string } {\n return error instanceof Error && typeof (error as { code?: unknown }).code === \"string\";\n}\n\n/**\n * Read a `.gitignore` into trimmed-on-compare lines. A genuinely absent file\n * (`ENOENT`) yields `[]`; any OTHER read error is re-thrown with a pathless\n * message (so an unreadable file is never mistaken for \"no patterns\", which on\n * the apply path would clobber it down to only the generated patterns).\n */\nfunction readGitignoreLines(file: string): string[] {\n try {\n return readFileSync(file, \"utf8\").split(/\\r?\\n/);\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return [];\n throw new Error(\"Failed to read .gitignore\", { cause: error });\n }\n}\n\n/** Append the planned patterns to a repo's `.gitignore`, creating it if absent. */\nfunction applyGitignorePlan(repositoryRoot: string, plan: RepoGitignorePlan): void {\n const file = join(realpathSync(resolve(repositoryRoot, plan.path)), \".gitignore\");\n let existing = \"\";\n try {\n existing = readFileSync(file, \"utf8\");\n } catch (error: unknown) {\n if (!(hasErrorCode(error) && error.code === \"ENOENT\")) {\n // Do NOT clobber an existing-but-unreadable .gitignore with only the patterns.\n throw new Error(\"Failed to read .gitignore\", { cause: error });\n }\n }\n const sep = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n try {\n writeFileSync(file, `${existing}${sep}${plan.toAdd.join(\"\\n\")}\\n`);\n } catch (error: unknown) {\n throw new Error(\"Failed to write .gitignore\", { cause: error });\n }\n}\n\n/**\n * Reconcile each public-facing repo's `.gitignore` to exclude the agent\n * instruction files. Resolves the workspace, reads the manifest, gathers each\n * declared repo's current `.gitignore`, and plans the missing patterns. When\n * `--apply` is set and there is something to add, it appends the patterns\n * (additive — it never removes a line); otherwise it writes nothing and prints\n * the plan. Private and unset-visibility repos are left untouched.\n */\nexport async function doRunProjectGitignore(\n options: ProjectGitignoreOptions,\n ctx: ProjectGitignoreContext,\n): Promise<ProjectGitignoreResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project gitignore\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const facts = roster.map((entry) => gatherRepoGitignore(repositoryRoot, entry));\n const summary = planGitignore({ repos: facts, required: [...INSTRUCTION_FILES] });\n\n const applied = options.apply === true && summary.plans.length > 0;\n if (applied) {\n for (const plan of summary.plans) applyGitignorePlan(repositoryRoot, plan);\n }\n\n const result: ProjectGitignoreResult = { ...summary, hasRoster: roster.length > 0, applied };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectGitignore(result));\n }\n return result;\n}\n\n/**\n * Render the gitignore report. Leads with the actionable outcome: no roster (run\n * adopt first), the per-repo patterns that will be / were added, then the\n * skipped (unset visibility) and unreachable repos. A clean verdict is shown\n * only when there is genuinely nothing to do AND every repo was judgeable and\n * reachable (no false-clear).\n */\nexport function renderProjectGitignore(result: ProjectGitignoreResult): string {\n const lines: string[] = [];\n lines.push(\"# .gitignore 生成(公開系 repo の指示書を除外)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n const verb = result.applied ? \"追加しました\" : \"追加予定(dry-run、反映するには --apply)\";\n lines.push(\n `${result.applied ? \"✅ \" : \"\"}${result.plans.length} repo の .gitignore に${verb}:`,\n );\n for (const p of result.plans) lines.push(`- ${p.path} — ${p.toAdd.join(\", \")}`);\n } else if (result.ok) {\n lines.push(\"✅ 公開系 repo の .gitignore は指示書をすべて除外済みです(追加不要)。\");\n } else {\n lines.push(\n \"ℹ️ 追加が必要な公開系 repo はありませんが、判定できない/到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.unknown.length > 0) {\n lines.push(\n `## visibility 未設定 (${result.unknown.length}) — 対象外。manifest の repos に visibility を付与してください`,\n );\n for (const p of result.unknown) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 既存の .gitignore 行は保持し、不足パターンの追記のみ行います(削除はしません)。private / visibility 未設定の repo は対象外です。\",\n );\n lines.push(\n \"注: .gitignore への追記は、既に git 追跡済みのファイルを untrack しません。追跡済みの指示書は `basou project wiring` で検出し、`git rm --cached <file>` で外してください。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectSymlinks}. */\nexport async function runProjectSymlinks(\n options: ProjectSymlinksOptions,\n ctx: ProjectSymlinksContext = {},\n): Promise<void> {\n try {\n await doRunProjectSymlinks(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * The instruction files and their expected symlink targets for one repo, in the\n * hub-and-spoke topology: AGENTS.md is the hub (a relative link to the anchor's\n * canonical), while CLAUDE.md and Copilot are spokes pointing back at the repo's\n * own AGENTS.md. `repoDirReal` and `canonicalFile` are both realpath-resolved so\n * the computed relative target matches a hand-wired link byte-for-byte.\n */\nfunction expectedSymlinkTargets(\n repoDirReal: string,\n canonicalFile: string,\n): { name: string; target: string }[] {\n return [\n { name: \"AGENTS.md\", target: relative(repoDirReal, canonicalFile) },\n { name: \"CLAUDE.md\", target: CANONICAL_FILE },\n { name: \".github/copilot-instructions.md\", target: `../${CANONICAL_FILE}` },\n ];\n}\n\n/**\n * Inspect one instruction file's on-disk state against the link it should be.\n * `lstat` examines a symlink as a link (even a broken one), never following it.\n * Only a genuinely absent path (ENOENT) is `missing` (a creatable gap); any other\n * lstat error (ENOTDIR when a parent component is a regular file, EACCES) is\n * `blocked` — NOT `missing` — so a non-ENOENT error is never mistaken for a gap\n * and planned, which would crash `--apply` (e.g. `mkdirSync` over a `.github`\n * file). A symlink is `correct` when it points at `expectedTarget` and `mismatch`\n * (carrying its current target) otherwise; a real file or directory is `occupied`.\n */\nfunction inspectSymlink(\n filePath: string,\n expectedTarget: string,\n): { state: InstructionSymlinkState; actualTarget?: string } {\n let isLink: boolean;\n try {\n isLink = lstatSync(filePath).isSymbolicLink();\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return { state: \"missing\" };\n return { state: \"blocked\" };\n }\n if (!isLink) return { state: \"occupied\" };\n const actual = readlinkSync(filePath);\n return actual === expectedTarget\n ? { state: \"correct\" }\n : { state: \"mismatch\", actualTarget: actual };\n}\n\n/**\n * Gather the symlink facts for one declared repo. Resolves the repo path\n * (realpath); the entry that resolves to the manifest root IS the anchor (it\n * owns the canonical, so it is flagged `isAnchor` and never linked to itself). A\n * path that does not resolve or has no `.git` is `reachable: false`. Otherwise it\n * checks whether the anchor's canonical (`agents/<repo>/AGENTS.md`) exists and,\n * if so, inspects each instruction file's current state. Pure filesystem reads —\n * no writes.\n */\nfunction gatherRepoSymlinks(\n repositoryRoot: string,\n anchorReal: string,\n entry: RepoEntry,\n): RepoSymlinkFacts {\n const base = { path: entry.path };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };\n }\n if (real === anchorReal) {\n return { ...base, isAnchor: true, reachable: true, canonicalPresent: false, files: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };\n }\n\n const canonicalFile = join(anchorReal, \"agents\", basename(real), CANONICAL_FILE);\n if (!existsSync(canonicalFile)) {\n return { ...base, isAnchor: false, reachable: true, canonicalPresent: false, files: [] };\n }\n\n const files: InstructionSymlinkFact[] = expectedSymlinkTargets(real, canonicalFile).map(\n (spec) => {\n const { state, actualTarget } = inspectSymlink(join(real, spec.name), spec.target);\n return {\n name: spec.name,\n expectedTarget: spec.target,\n state,\n ...(actualTarget !== undefined ? { actualTarget } : {}),\n };\n },\n );\n return {\n ...base,\n isAnchor: false,\n reachable: true,\n canonicalPresent: true,\n canonicalName: basename(real),\n files,\n };\n}\n\n/**\n * Create the planned (missing) symlinks for one repo, making `.github` if needed.\n * Defensive: a per-file failure (a path made unwritable, a parent that is not a\n * directory, or a race that created the file first) is collected, not thrown — so\n * one bad path neither aborts the remaining repos nor leaves the run silent about\n * what was actually created (upholding the non-destructive contract transparently).\n */\nfunction applySymlinkPlan(\n repositoryRoot: string,\n plan: RepoSymlinkPlan,\n): { created: string[]; failed: { file: string; message: string }[] } {\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, plan.path));\n } catch (error: unknown) {\n const message = failureReason(error);\n return { created: [], failed: plan.toCreate.map((c) => ({ file: c.name, message })) };\n }\n const created: string[] = [];\n const failed: { file: string; message: string }[] = [];\n for (const { name, target } of plan.toCreate) {\n const filePath = join(real, name);\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n symlinkSync(target, filePath);\n created.push(name);\n } catch (error: unknown) {\n failed.push({ file: name, message: failureReason(error) });\n }\n }\n return { created, failed };\n}\n\n/**\n * A pathless failure reason for `--apply` errors: the errno code (EEXIST,\n * ENOTDIR, EACCES, …) when present, else a generic label. Never the raw Node\n * `error.message`, which embeds the absolute filesystem path and would leak it\n * into the report / `--json` output (the repo + repo-relative file already\n * identify the failure).\n */\nfunction failureReason(error: unknown): string {\n return hasErrorCode(error) ? error.code : \"unknown error\";\n}\n\n/**\n * Generate each declared repo's instruction-file symlinks. Resolves the\n * workspace, reads the manifest, gathers each repo's current symlink state, and\n * plans the missing links. When `--apply` is set and there is something to\n * create, it creates only the `missing` links (non-destructive — conflicts and\n * occupied paths are never touched); otherwise it writes nothing and prints the\n * plan.\n */\nexport async function doRunProjectSymlinks(\n options: ProjectSymlinksOptions,\n ctx: ProjectSymlinksContext,\n): Promise<ProjectSymlinksResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project symlinks\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const anchorReal = realpathSync(repositoryRoot);\n const facts = roster.map((entry) => gatherRepoSymlinks(repositoryRoot, anchorReal, entry));\n const summary = summarizeSymlinkPlan(facts);\n\n const wantApply = options.apply === true && summary.plans.length > 0;\n const failures: { repo: string; file: string; message: string }[] = [];\n let createdCount = 0;\n if (wantApply) {\n for (const plan of summary.plans) {\n const { created, failed } = applySymlinkPlan(repositoryRoot, plan);\n createdCount += created.length;\n for (const f of failed) failures.push({ repo: plan.path, file: f.file, message: f.message });\n }\n }\n\n const result: ProjectSymlinksResult = {\n ...summary,\n hasRoster: roster.length > 0,\n applied: createdCount > 0,\n failures,\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectSymlinks(result));\n }\n return result;\n}\n\n/**\n * Render the symlink-generation report. Leads with the actionable outcome: no\n * roster (run adopt first), the per-repo links that will be / were created, then\n * the conflicts (existing files / links pointing elsewhere — left untouched),\n * repos whose anchor canonical is absent, and unreachable repos. A clean \"all\n * wired\" verdict is shown only when there is genuinely nothing to do AND every\n * repo was judgeable and reachable (no false-clear).\n */\nexport function renderProjectSymlinks(result: ProjectSymlinksResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 symlink 生成(各 repo → anchor の canonical)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n // `--apply` was attempted when something was created OR something failed; a\n // dry-run has neither (its plan is just intentions, written nowhere).\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.plans.length} repo に指示書 symlink を作成予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.plans) {\n lines.push(`- ${p.path}`);\n for (const c of p.toCreate) lines.push(` ${c.name} -> ${c.target}`);\n }\n } else {\n // List only what was ACTUALLY created — a planned file that failed appears\n // in the failures section, never here (no false \"created\" claim).\n const header =\n result.failures.length === 0\n ? \"✅ 指示書 symlink を作成しました:\"\n : result.applied\n ? \"指示書 symlink を作成しました(一部失敗、下記参照):\"\n : \"指示書 symlink を作成できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.plans) {\n const failedFiles = new Set(\n result.failures.filter((f) => f.repo === p.path).map((f) => f.file),\n );\n const created = p.toCreate.filter((c) => !failedFiles.has(c.name));\n if (created.length === 0) continue;\n lines.push(`- ${p.path}`);\n for (const c of created) lines.push(` ${c.name} -> ${c.target}`);\n }\n }\n } else if (result.ok) {\n lines.push(\"✅ 宣言された全 repo の指示書 symlink は正しく張られています(生成不要)。\");\n } else {\n lines.push(\n \"ℹ️ 生成が必要な symlink はありませんが、競合 / 衝突 / canonical 不在 / 到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.failures.length > 0) {\n lines.push(`## 作成に失敗 (${result.failures.length}) — 一部の symlink を作成できませんでした`);\n for (const f of result.failures) lines.push(`- ${f.repo} — ${f.file}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.conflicts.length > 0) {\n lines.push(\n `## 競合 (${result.conflicts.length}) — 既存を上書きしません。手動で確認してください`,\n );\n for (const c of result.conflicts) {\n const detail =\n c.reason === \"mismatch\"\n ? `別の場所を指す symlink(現在: ${c.actualTarget ?? \"?\"})`\n : c.reason === \"occupied\"\n ? \"symlink でない実ファイル/ディレクトリ\"\n : \"検査できないパス(親が非ディレクトリ等)\";\n lines.push(`- ${c.repo} — ${c.file}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## canonical 衝突 (${result.collisions.length}) — 別 repo が同名 canonical を共有(自動配線しません)`,\n );\n for (const c of result.collisions) {\n lines.push(`- agents/${c.canonicalName}/AGENTS.md ← ${c.repos.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n if (result.missingCanonical.length > 0) {\n lines.push(\n `## canonical 不在 (${result.missingCanonical.length}) — anchor に agents/<repo>/AGENTS.md が無いため生成できません`,\n );\n for (const p of result.missingCanonical) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 既存ファイル・別の場所を指す symlink は上書きせず、不足分の作成のみ行います(GEMINI.md は廃止のため生成しません)。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectWorkspace}. */\nexport async function runProjectWorkspace(\n options: ProjectWorkspaceOptions,\n ctx: ProjectWorkspaceContext = {},\n): Promise<void> {\n try {\n await doRunProjectWorkspace(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Resolve the view directory to a realpath-stable absolute path. When the view\n * exists, realpath it; when it does not exist yet, anchor on its (existing)\n * parent's realpath + basename so the relative targets computed against the\n * realpath'd repos stay consistent. Falls back to the plain resolved path only\n * when the parent is also absent (apply's recursive mkdir will create it).\n */\nfunction resolveViewDir(repositoryRoot: string, viewPath: string): string {\n const abs = resolve(repositoryRoot, viewPath);\n try {\n return realpathSync(abs);\n } catch {\n try {\n return join(realpathSync(dirname(abs)), basename(abs));\n } catch {\n return abs;\n }\n }\n}\n\n/**\n * Gather one roster repo's place in the view. Resolves the repo (realpath); an\n * unresolvable path is `reachable: false` (cannot be aggregated). The view link\n * is named by the repo's basename and should point at the repo relative to the\n * view; its on-disk state is inspected with the same ENOENT-only rule as the\n * instruction symlinks (a non-ENOENT lstat error is `blocked`, never a creatable\n * gap). Pure filesystem reads — no writes.\n */\nfunction gatherViewRepo(repositoryRoot: string, viewDir: string, entry: RepoEntry): ViewRepoFact {\n let repoReal: string;\n try {\n repoReal = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { path: entry.path, reachable: false };\n }\n const expectedTarget = relative(viewDir, repoReal);\n // A repo that resolves to the view directory ITSELF yields an empty (self-)\n // target. It cannot be aggregated into the view, and an empty symlink target\n // would create a broken link that a later run reads back as falsely \"correct\"\n // (readlink \"\" === expectedTarget \"\") — so surface it as unreachable instead.\n if (expectedTarget === \"\" || expectedTarget === \".\") {\n return { path: entry.path, reachable: false };\n }\n const linkName = basename(repoReal);\n const { state, actualTarget } = inspectSymlink(join(viewDir, linkName), expectedTarget);\n return {\n path: entry.path,\n reachable: true,\n linkName,\n expectedTarget,\n state,\n ...(actualTarget !== undefined ? { actualTarget } : {}),\n };\n}\n\n/** Create the planned (missing) view symlinks, making the view directory if needed. */\nfunction applyViewPlan(\n viewDir: string,\n toCreate: { name: string; target: string }[],\n): { created: string[]; failed: { name: string; message: string }[] } {\n const created: string[] = [];\n const failed: { name: string; message: string }[] = [];\n for (const { name, target } of toCreate) {\n const filePath = join(viewDir, name);\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n symlinkSync(target, filePath);\n created.push(name);\n } catch (error: unknown) {\n failed.push({ name, message: failureReason(error) });\n }\n }\n return { created, failed };\n}\n\n/** Top-level instruction-file names the view may hold for itself — never treated as strays (case-insensitive). */\nconst TOP_LEVEL_INSTRUCTION_FILES_LOWER: ReadonlySet<string> = new Set(\n INSTRUCTION_FILES.filter((f) => !f.includes(\"/\")).map((f) => f.toLowerCase()),\n);\n\n/**\n * Classify one view entry by name for stray detection. Returns `null` when the\n * entry is NOT a removable stray candidate — it is not a symlink (a real file/dir\n * is never ours to remove), it vanished, or its target resolves to a CURRENT\n * roster repo (owned by the roster under whatever name — an aliased/symlinked\n * roster path, or a different-case link on a case-insensitive filesystem — so it\n * must never be pruned). Otherwise returns the link's target and `kind`: `repo`\n * (a relative target following to a git repository — a dir holding a `.git` entry,\n * matching the project family's `existsSync(<dir>/.git)` repo test, so worktrees /\n * submodules count); `absolute` (basou never writes absolute view links); `broken`\n * (a relative target that does not resolve); or `non-repo` (resolves to a file or a\n * non-repository directory). Pure filesystem reads — the single source of truth for\n * both the scan and the pre-unlink re-verification.\n */\nfunction classifyViewLink(\n viewDir: string,\n name: string,\n rosterRealpaths: ReadonlySet<string>,\n): { target: string; kind: ExistingViewLink[\"kind\"] } | null {\n const filePath = join(viewDir, name);\n let isLink: boolean;\n try {\n isLink = lstatSync(filePath).isSymbolicLink();\n } catch {\n return null; // vanished between readdir and lstat, or not inspectable\n }\n if (!isLink) return null; // a real file/dir is never ours to prune\n let target: string;\n try {\n target = readlinkSync(filePath);\n } catch {\n return null;\n }\n // A link pointing at a CURRENT roster repo (by resolved identity, not name) is\n // the repo's own link, never a stray — even under an aliased name, a case-folded\n // spelling, OR an absolute target. realpath canonicalizes all three. This\n // ownership check precedes the absolute/relative classification so an absolute\n // link to a rostered repo is treated as owned (not surfaced as a stray).\n const resolved = isAbsolute(target) ? target : resolve(viewDir, target);\n try {\n if (rosterRealpaths.has(realpathSync(resolved))) return null;\n } catch {\n // unresolvable target → not a roster repo; fall through to classify\n }\n if (isAbsolute(target)) return { target, kind: \"absolute\" }; // basou writes only relative links\n let isDir = false;\n try {\n isDir = statSync(resolved).isDirectory(); // follows the link\n } catch {\n isDir = false; // ENOENT / unreadable → broken\n }\n if (!isDir) {\n // Resolves to a file (e.g. an instruction symlink) or not at all — not a repo.\n return { target, kind: existsSync(resolved) ? \"non-repo\" : \"broken\" };\n }\n return { target, kind: existsSync(join(resolved, \".git\")) ? \"repo\" : \"non-repo\" };\n}\n\n/**\n * Scan the view directory for stray-detection candidates: its top-level SYMLINK\n * entries, classified by {@link classifyViewLink}. The view's own top-level\n * instruction-file symlinks (`AGENTS.md`/`CLAUDE.md`, matched case-insensitively)\n * and links resolving to a current roster repo are skipped. An ABSENT view\n * directory (ENOENT — nothing generated yet) yields `[]`; any other readdir error\n * (the view path is a file, or is unreadable) is surfaced, never read as \"no\n * strays\" (no false-clear). Pure reads.\n */\nexport function gatherExistingViewLinks(\n viewDir: string,\n rosterRealpaths: ReadonlySet<string>,\n): ExistingViewLink[] {\n let names: string[];\n try {\n names = readdirSync(viewDir);\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return []; // not generated yet\n // The view path exists but could not be scanned (a regular file, EACCES, …) —\n // surface it rather than silently reporting a clean, stray-free view. The\n // message is path-less (matching the file's other thrown errors); the absolute\n // path stays in `cause`, shown only under --verbose.\n throw new Error(\"workspace view を走査できません(パス/種別を確認してください)\", {\n cause: error,\n });\n }\n const links: ExistingViewLink[] = [];\n for (const name of names) {\n if (TOP_LEVEL_INSTRUCTION_FILES_LOWER.has(name.toLowerCase())) continue; // the view's own instruction file\n const c = classifyViewLink(viewDir, name, rosterRealpaths);\n if (c === null) continue;\n links.push({ name, target: c.target, kind: c.kind });\n }\n return links;\n}\n\n/**\n * Remove the planned stray view symlinks. Immediately before each `unlinkSync` it\n * RE-DERIVES the full prune predicate via {@link classifyViewLink} (still a symlink,\n * still a relative target following to a git repo the roster does not back) and\n * skips with a collected failure if anything changed since the scan — closing the\n * scan-to-unlink window for this first file-removing operation. It only ever\n * unlinks the link, never its target. Failures are collected, not thrown.\n */\nexport function pruneViewLinks(\n viewDir: string,\n toPrune: { name: string; target: string }[],\n rosterRealpaths: ReadonlySet<string>,\n): { pruned: string[]; failed: { name: string; message: string }[] } {\n const pruned: string[] = [];\n const failed: { name: string; message: string }[] = [];\n for (const { name } of toPrune) {\n const filePath = join(viewDir, name);\n const c = classifyViewLink(viewDir, name, rosterRealpaths);\n if (c === null || c.kind !== \"repo\") {\n failed.push({\n name,\n message:\n \"撤去対象が scan 時と変わりました(basou 生成の stray repo link ではなくなった/再実行してください)\",\n });\n continue;\n }\n try {\n unlinkSync(filePath);\n pruned.push(name);\n } catch (error: unknown) {\n failed.push({ name, message: failureReason(error) });\n }\n }\n return { pruned, failed };\n}\n\n/**\n * Generate the project's workspace view and reconcile its strays. Resolves the\n * workspace, reads the manifest, and — when `workspace.view` is declared — gathers\n * each roster repo's view-link state plus the view's existing symlink entries, and\n * plans the missing links to create and the stray repo links to prune. When\n * `--apply` is set it creates only the `missing` links (non-destructive — conflicts\n * and collisions are never touched). When `--prune` is set it removes only the\n * confirmed stray repo links (a symlink whose relative target follows to a git\n * repository the roster no longer backs); unrecognized strays are reported, never\n * removed, and pruning is WITHHELD entirely while any declared repo is unreachable\n * (its live link could be indistinguishable from a stray). The two writes are\n * independent opt-ins; with neither flag it writes nothing and prints the plan.\n * After the writes the verdict (`ok`) is recomputed from the residual state so a\n * fully successful run is not reported as still needing attention.\n */\nexport async function doRunProjectWorkspace(\n options: ProjectWorkspaceOptions,\n ctx: ProjectWorkspaceContext,\n): Promise<ProjectWorkspaceResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project workspace\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const viewPath = manifest.workspace.view;\n const roster = manifest.repos ?? [];\n\n let result: ProjectWorkspaceResult;\n if (viewPath === undefined) {\n result = {\n toCreate: [],\n conflicts: [],\n collisions: [],\n unreachable: [],\n toPrune: [],\n strayUnknown: [],\n correctCount: 0,\n ok: true,\n hasView: false,\n applied: false,\n pruned: false,\n pruneWithheld: false,\n failures: [],\n pruneFailures: [],\n };\n } else {\n const viewDir = resolveViewDir(repositoryRoot, viewPath);\n const facts = roster.map((entry) => gatherViewRepo(repositoryRoot, viewDir, entry));\n // Ownership inputs for stray detection, computed once and shared by the scan\n // and the pre-unlink re-verification: the basename every declared entry would\n // own (reachability-INDEPENDENT, so a transiently-unreachable repo still owns\n // its link name), and the resolved identity of every repo that DOES resolve\n // (so a link reaching a roster repo under any name/case is never a stray).\n const rosterNames = roster.map((entry) => basename(resolve(repositoryRoot, entry.path)));\n const rosterRealpaths = new Set<string>();\n for (const entry of roster) {\n try {\n rosterRealpaths.add(realpathSync(resolve(repositoryRoot, entry.path)));\n } catch {\n // unreachable repo — protected by name via rosterNames + the prune withhold\n }\n }\n const existing = gatherExistingViewLinks(viewDir, rosterRealpaths);\n const plan = planWorkspaceView(facts, existing, rosterNames);\n\n const failures: { name: string; message: string }[] = [];\n let createdCount = 0;\n if (options.apply === true && plan.toCreate.length > 0) {\n const applied = applyViewPlan(viewDir, plan.toCreate);\n createdCount = applied.created.length;\n for (const f of applied.failed) failures.push(f);\n }\n\n // Refuse to prune while any declared repo is unreachable: such a repo's live\n // link can be indistinguishable from a stray, and a false delete is the worst\n // outcome for the family's first file-removing operation. The operator resolves\n // reachability (clone/mount the repo, or `archive` it) and re-runs.\n const pruneWithheld =\n options.prune === true && plan.toPrune.length > 0 && plan.unreachable.length > 0;\n const pruneFailures: { name: string; message: string }[] = [];\n let prunedCount = 0;\n if (options.prune === true && plan.toPrune.length > 0 && plan.unreachable.length === 0) {\n const removed = pruneViewLinks(viewDir, plan.toPrune, rosterRealpaths);\n prunedCount = removed.pruned.length;\n for (const f of removed.failed) pruneFailures.push(f);\n }\n\n // The plan's `ok` was computed BEFORE the writes; recompute the residual so a\n // create/prune that fully succeeded no longer counts as outstanding work (no\n // false \"items need attention\" after a successful run).\n const createsOutstanding =\n plan.toCreate.length > 0 && !(options.apply === true && failures.length === 0);\n const prunesOutstanding =\n plan.toPrune.length > 0 &&\n !(options.prune === true && !pruneWithheld && pruneFailures.length === 0);\n const ok =\n plan.conflicts.length === 0 &&\n plan.collisions.length === 0 &&\n plan.unreachable.length === 0 &&\n plan.strayUnknown.length === 0 &&\n !createsOutstanding &&\n !prunesOutstanding;\n\n result = {\n ...plan,\n ok,\n hasView: true,\n applied: createdCount > 0,\n pruned: prunedCount > 0,\n pruneWithheld,\n failures,\n pruneFailures,\n };\n }\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectWorkspace(result));\n }\n return result;\n}\n\n/**\n * Render the workspace-view report. Leads with the actionable outcome: no view\n * declared, the links that will be / were created, the stray repo links that will\n * be / were pruned, then conflicts, basename collisions, unreachable repos, and\n * the unrecognized strays left untouched. A clean \"in sync\" verdict is shown only\n * when there is genuinely nothing to do, every repo was resolvable and unambiguous,\n * and the view carries no stray (no false-clear).\n */\nexport function renderProjectWorkspace(result: ProjectWorkspaceResult): string {\n const lines: string[] = [];\n lines.push(\"# workspace view 生成(roster repo を集約)\");\n lines.push(\"\");\n\n if (!result.hasView) {\n lines.push(\n \"ℹ️ view が未宣言です(manifest の `workspace.view`)。集約先のディレクトリを宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.toCreate.length > 0) {\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.toCreate.length} 件の repo symlink を view に作成予定(dry-run、反映するには --apply):`,\n );\n for (const c of result.toCreate) lines.push(` ${c.name} -> ${c.target}`);\n } else {\n const failed = new Set(result.failures.map((f) => f.name));\n const header =\n result.failures.length === 0\n ? \"✅ view に repo symlink を作成しました:\"\n : result.applied\n ? \"view に repo symlink を作成しました(一部失敗、下記参照):\"\n : \"view に repo symlink を作成できませんでした(下記参照):\";\n lines.push(header);\n for (const c of result.toCreate) {\n if (failed.has(c.name)) continue;\n lines.push(` ${c.name} -> ${c.target}`);\n }\n }\n } else if (result.ok) {\n lines.push(\n `✅ view は宣言された roster をすべて集約しています(${result.correctCount} links、生成不要)。`,\n );\n } else {\n lines.push(\n \"ℹ️ 作成が必要な symlink はありませんが、対応の必要な項目があります(stray / 競合 / 衝突 / 到達できない repo、下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.failures.length > 0) {\n lines.push(`## 作成に失敗 (${result.failures.length}) — 一部の symlink を作成できませんでした`);\n for (const f of result.failures) lines.push(`- ${f.name}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.toPrune.length > 0) {\n const attempted = result.pruned || result.pruneFailures.length > 0;\n if (result.pruneWithheld) {\n lines.push(\n `${result.toPrune.length} 件の stray repo symlink を撤去予定でしたが、到達できない repo があるため撤去を保留しました(到達できない repo の link と stray を区別できないため。下記の repo を解決するか archive してから再実行してください):`,\n );\n for (const p of result.toPrune) lines.push(` ${p.name} -> ${p.target}`);\n } else if (!attempted) {\n lines.push(\n `${result.toPrune.length} 件の stray repo symlink を撤去予定(dry-run、撤去するには --prune):`,\n );\n for (const p of result.toPrune) lines.push(` ${p.name} -> ${p.target}`);\n } else {\n const failed = new Set(result.pruneFailures.map((f) => f.name));\n const header =\n result.pruneFailures.length === 0\n ? \"🧹 stray repo symlink を撤去しました:\"\n : result.pruned\n ? \"stray repo symlink を撤去しました(一部失敗、下記参照):\"\n : \"stray repo symlink を撤去できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.toPrune) {\n if (failed.has(p.name)) continue;\n lines.push(` ${p.name} -> ${p.target}`);\n }\n }\n lines.push(\"\");\n }\n\n if (result.pruneFailures.length > 0) {\n lines.push(\n `## 撤去に失敗 (${result.pruneFailures.length}) — 一部の stray symlink を撤去できませんでした`,\n );\n for (const f of result.pruneFailures) lines.push(`- ${f.name}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.conflicts.length > 0) {\n lines.push(\n `## 競合 (${result.conflicts.length}) — 既存を上書きしません。手動で確認してください`,\n );\n for (const c of result.conflicts) {\n const detail =\n c.reason === \"mismatch\"\n ? `別の場所を指す symlink(現在: ${c.actualTarget ?? \"?\"})`\n : c.reason === \"occupied\"\n ? \"symlink でない実ファイル/ディレクトリ\"\n : \"検査できないパス(親が非ディレクトリ等)\";\n lines.push(`- ${c.name}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## basename 衝突 (${result.collisions.length}) — 別 repo が同じ view 名を取り合い(自動配線しません)`,\n );\n for (const c of result.collisions) lines.push(`- ${c.linkName} ← ${c.repos.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(\n `## 到達不能 (${result.unreachable.length}) — パス未解決、または view 自身に解決するため集約できません`,\n );\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.strayUnknown.length > 0) {\n lines.push(\n `## 未撤去の stray (${result.strayUnknown.length}) — basou 生成の repo link と確認できないため撤去しません。手動で確認してください`,\n );\n for (const s of result.strayUnknown) {\n const detail =\n s.reason === \"broken\"\n ? \"リンク切れ(ターゲットが解決できません)\"\n : s.reason === \"non-repo\"\n ? \"git repo でないターゲット(ファイル、または .git の無いディレクトリ)\"\n : \"絶対パスのターゲット(basou は相対リンクのみ生成します)\";\n lines.push(`- ${s.name} -> ${s.target}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 作成(--apply)は既存エントリを上書きしません。stray repo link の撤去は --prune で行います(symlink のみ削除し、参照先 repo は削除しません)。basou 生成と確認できない stray(リンク切れ / 非 repo / 絶対パス)は撤去しません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectPreset}. */\nexport async function runProjectPreset(\n options: ProjectPresetOptions,\n ctx: ProjectPresetContext = {},\n): Promise<void> {\n try {\n await doRunProjectPreset(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** The anchor's canonical file for a repo: `<anchor>/agents/<name>/AGENTS.md`. */\nfunction canonicalFileFor(anchorReal: string, canonicalName: string): string {\n return join(anchorReal, \"agents\", canonicalName, CANONICAL_FILE);\n}\n\n/** The repo-relative label for a canonical (used in marker errors — never an absolute path). */\nfunction canonicalLabelFor(canonicalName: string): string {\n return join(\"agents\", canonicalName, CANONICAL_FILE);\n}\n\n/**\n * Gather one declared repo's preset facts. Resolves the repo (realpath); the\n * entry that resolves to the manifest root IS the anchor (its own AGENTS.md is\n * hand-maintained, so it is flagged and skipped). A path that does not resolve\n * or has no `.git` is `reachable: false`. Otherwise it reads the anchor's\n * canonical (`agents/<repo>/AGENTS.md`): absent => to be created; present =>\n * parsed for its marker region so the summarizer can detect drift. A present\n * canonical that cannot be read (a non-ENOENT failure) degrades only this repo\n * (`canonicalReadable: false`) instead of crashing the whole report.\n */\nasync function gatherRepoPreset(\n repositoryRoot: string,\n anchorReal: string,\n entry: RepoEntry,\n): Promise<RepoPresetFacts> {\n const declared = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n ...(entry.language !== undefined ? { language: entry.language } : {}),\n ...(entry.publishes !== undefined ? { publishes: entry.publishes } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };\n }\n if (real === anchorReal) {\n return { ...declared, isAnchor: true, reachable: true, canonicalPresent: false };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };\n }\n\n const canonicalName = basename(real);\n let content: string | null;\n try {\n content = await readMarkdownFile(canonicalFileFor(anchorReal, canonicalName));\n } catch {\n // Present but unreadable (e.g. a directory at that path, or permission denied).\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: true,\n canonicalReadable: false,\n };\n }\n if (content === null) {\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: false,\n };\n }\n const section = parseMarkers(content);\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: true,\n canonicalReadable: true,\n markerKind: section.kind,\n ...(section.kind === \"ok\" ? { currentBlock: section.generated } : {}),\n };\n}\n\n/**\n * Write one planned canonical, always replacing ONLY the marker region via\n * {@link renderWithMarkers} so hand-authored content around it is preserved.\n *\n * Both `create` and `update` re-read the file at write time and render against\n * the CURRENT content (null => fresh). This closes the create-race: if a\n * canonical appeared between gather (which saw it absent) and the write, its\n * hand-authored content around well-formed markers is preserved, and a\n * markerless / malformed file makes {@link renderWithMarkers} throw — collected\n * by the caller as a failure — rather than being clobbered by a blind null-based\n * write. A symlinked canonical is refused: `atomicReplace` would swap the link\n * for a regular file, silently breaking deliberate wiring. The only on-disk\n * mutations are the recursive `mkdir` for a create and the marker-region write.\n */\nasync function applyPresetPlan(anchorReal: string, plan: RepoPresetPlan): Promise<void> {\n const file = canonicalFileFor(anchorReal, plan.canonicalName);\n const label = canonicalLabelFor(plan.canonicalName);\n // Refuse to replace a symlinked canonical. `lstat` examines the link itself; an\n // absent path (ENOENT) or any uninspectable path is not a symlink to guard —\n // the create branch / the write itself handles those.\n let isLink = false;\n try {\n isLink = lstatSync(file).isSymbolicLink();\n } catch {\n isLink = false;\n }\n if (isLink) throw new Error(`Canonical is a symlink in ${label}`);\n\n if (plan.action === \"create\") mkdirSync(dirname(file), { recursive: true });\n const existing = await readMarkdownFile(file);\n await writeMarkdownFile(file, renderWithMarkers(existing, plan.desiredBlock, label));\n}\n\n/**\n * A pathless failure reason for an `--apply` write error. A marker mismatch\n * thrown by {@link renderWithMarkers} (`Markers …`) or the symlink guard above\n * (`Canonical …`) carries an already-safe message (it embeds only the\n * repo-relative label); any other error is reduced to its errno code (from the\n * wrapped cause when present), never the raw message (which would leak an\n * absolute filesystem path into the report / `--json`).\n */\nfunction presetFailureReason(error: unknown): string {\n if (\n error instanceof Error &&\n (error.message.startsWith(\"Markers\") || error.message.startsWith(\"Canonical\"))\n ) {\n return error.message;\n }\n const cause = error instanceof Error ? (error as { cause?: unknown }).cause : undefined;\n if (hasErrorCode(cause)) return cause.code;\n if (hasErrorCode(error)) return error.code;\n return \"unknown error\";\n}\n\n/**\n * Generate each declared repo's canonical instruction-file preset block.\n * Resolves the workspace, reads the manifest, gathers each repo's canonical\n * state, and plans the create/update work. When `--apply` is set and there is\n * something to write, it writes only the marker-delimited region (creating an\n * absent canonical, updating an out-of-date one); a per-repo write failure is\n * collected, not thrown. Without `--apply` it writes nothing and prints the plan.\n */\nexport async function doRunProjectPreset(\n options: ProjectPresetOptions,\n ctx: ProjectPresetContext,\n): Promise<ProjectPresetResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project preset\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const anchorReal = realpathSync(repositoryRoot);\n const facts: RepoPresetFacts[] = [];\n for (const entry of roster) facts.push(await gatherRepoPreset(repositoryRoot, anchorReal, entry));\n const summary = summarizePresetPlan(facts);\n\n const failures: { repo: string; message: string }[] = [];\n let writtenCount = 0;\n if (options.apply === true && summary.plans.length > 0) {\n for (const plan of summary.plans) {\n try {\n await applyPresetPlan(anchorReal, plan);\n writtenCount += 1;\n } catch (error: unknown) {\n failures.push({ repo: plan.path, message: presetFailureReason(error) });\n }\n }\n }\n\n const result: ProjectPresetResult = {\n ...summary,\n hasRoster: roster.length > 0,\n applied: writtenCount > 0,\n failures,\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectPreset(result));\n }\n return result;\n}\n\n/** A compact one-line summary of what a plan's generated block declares. */\nfunction presetActionLabel(action: RepoPresetPlan[\"action\"]): string {\n return action === \"create\" ? \"新規作成\" : \"更新\";\n}\n\n/**\n * Render the preset-generation report. Leads with the actionable outcome: no\n * roster (run adopt first), the per-repo canonical blocks that will be / were\n * written (with the generated block shown in dry-run), then the marker conflicts\n * (canonical present but unmarked/malformed — left untouched, with the remedy),\n * unreadable canonicals, basename collisions, undeclared repos, the skipped\n * anchor, and unreachable repos. A clean \"all in sync\" verdict is shown only when\n * there is genuinely nothing to do AND every repo was judgeable (no false-clear).\n */\nexport function renderProjectPreset(result: ProjectPresetResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 A プリセット生成(宣言 → canonical の生成領域)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n // `--apply` was attempted when something was written OR something failed.\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.plans.length} repo の canonical に A プリセットを生成予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.plans) {\n lines.push(\n `- ${p.path} [${presetActionLabel(p.action)}] → ${canonicalLabelFor(p.canonicalName)}`,\n );\n for (const bl of p.desiredBlock.split(\"\\n\")) lines.push(` ${bl}`);\n }\n } else {\n const failed = new Set(result.failures.map((f) => f.repo));\n const header =\n result.failures.length === 0\n ? \"✅ canonical に A プリセットを生成しました:\"\n : result.applied\n ? \"A プリセットを生成しました(一部失敗、下記参照):\"\n : \"A プリセットを生成できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.plans) {\n if (failed.has(p.path)) continue;\n lines.push(\n `- ${p.path} [${presetActionLabel(p.action)}] → ${canonicalLabelFor(p.canonicalName)}`,\n );\n }\n }\n } else if (result.ok) {\n lines.push(\"✅ 宣言された全 repo の A プリセットは canonical と同期済みです(生成不要)。\");\n } else {\n lines.push(\n \"ℹ️ 生成が必要な repo はありませんが、マーカー競合 / 衝突 / 未宣言 / 到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.inSync.length > 0) {\n lines.push(`同期済み (${result.inSync.length}): ${result.inSync.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.failures.length > 0) {\n lines.push(\n `## 書き込みに失敗 (${result.failures.length}) — 一部の canonical を書けませんでした`,\n );\n for (const f of result.failures) lines.push(`- ${f.repo}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.markerConflicts.length > 0) {\n lines.push(\n `## マーカー競合 (${result.markerConflicts.length}) — canonical のマーカーが無い/壊れているため上書きしません`,\n );\n for (const c of result.markerConflicts) {\n const detail =\n c.reason === \"no_markers\" ? \"マーカー領域が無い\" : `マーカー不整合(${c.reason})`;\n lines.push(`- ${c.repo}: ${detail}`);\n }\n lines.push(\n ` 対処: A プリセットを入れたい位置に次の2行を追加してください — \\`${GENERATED_START}\\` と \\`${GENERATED_END}\\`(無ければ basou が新規 canonical を作ります)。`,\n );\n lines.push(\"\");\n }\n\n if (result.unreadable.length > 0) {\n lines.push(\n `## canonical 読み取り不能 (${result.unreadable.length}) — ディレクトリ/権限等で読めません`,\n );\n for (const p of result.unreadable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## canonical 衝突 (${result.collisions.length}) — 別 repo が同名 canonical を共有(自動生成しません)`,\n );\n for (const c of result.collisions) {\n lines.push(`- agents/${c.canonicalName}/AGENTS.md ← ${c.repos.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n if (result.undeclared.length > 0) {\n lines.push(\n `## 宣言なし (${result.undeclared.length}) — visibility / language / publishes が未設定のため生成しません`,\n );\n for (const p of result.undeclared) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.anchors.length > 0) {\n lines.push(\n `## anchor (${result.anchors.length}) — 自身の AGENTS.md は手で維持するためスキップ`,\n );\n for (const p of result.anchors) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: マーカー領域のみを生成し、canonical の手書き部分(マーカー外)は保持します。生成内容は manifest の宣言から導出されます。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectArchive}. */\nexport async function runProjectArchive(\n target: string,\n options: ProjectArchiveOptions,\n ctx: ProjectArchiveContext = {},\n): Promise<void> {\n try {\n await doRunProjectArchive(target, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Inspect the repo-side wiring still present for an archived repo — the manual\n * teardown checklist `--apply` does NOT touch (it only mutates the manifest).\n * Best-effort: an unresolvable repo (already deleted from disk) yields\n * `inspected: false` and empty facts, so archiving a removed repo still works.\n */\nfunction gatherArchiveTeardown(\n repositoryRoot: string,\n manifest: Manifest,\n target: string,\n): ArchiveTeardown {\n const empty: ArchiveTeardown = {\n inspected: false,\n viewLink: false,\n instructionFiles: [],\n gitignorePatterns: [],\n canonical: false,\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, target));\n } catch {\n return empty;\n }\n const anchorReal = realpathSync(repositoryRoot);\n const canonicalName = basename(real);\n\n const instructionFiles: string[] = [];\n for (const name of INSTRUCTION_FILES) {\n try {\n lstatSync(join(real, name));\n instructionFiles.push(name);\n } catch {\n // not present — nothing to tear down\n }\n }\n\n // An unreadable .gitignore (EACCES / I/O error) must NOT throw out of this\n // advisory, read-only inspection — that would block the authoritative,\n // manifest-only archive write it has no say over. Degrade to \"no patterns\".\n let ignored: Set<string>;\n try {\n ignored = new Set(readGitignoreLines(join(real, \".gitignore\")).map((l) => l.trim()));\n } catch {\n ignored = new Set();\n }\n const gitignorePatterns = INSTRUCTION_FILES.filter((p) => ignored.has(p) || ignored.has(`/${p}`));\n\n const canonical = existsSync(join(anchorReal, \"agents\", canonicalName, CANONICAL_FILE));\n\n let viewLink = false;\n const viewPath = manifest.workspace.view;\n if (viewPath !== undefined) {\n try {\n lstatSync(join(resolveViewDir(repositoryRoot, viewPath), canonicalName));\n viewLink = true;\n } catch {\n // no view entry for this repo\n }\n }\n\n return {\n inspected: true,\n viewLink,\n instructionFiles,\n gitignorePatterns: [...gitignorePatterns],\n canonical,\n };\n}\n\n/** Shallow clone of an object with one optional key removed (preserves every other own field). */\nfunction omitKey<T extends object>(obj: T, key: keyof T): T {\n const clone = { ...obj };\n delete clone[key];\n return clone;\n}\n\n/**\n * Build the manifest to write after archiving. Spreads the original so every\n * other manifest field is preserved — both KNOWN fields not handled here and any\n * unknown/future field, which `readManifest`'s loose schema now carries through\n * (at the top level and nested) and surfaces via {@link unknownManifestKeys}. It\n * bumps `updated_at`, removes the target from `repos` (dropping the key entirely when\n * the roster empties, since `repos: []` is not a valid roster), and prunes the\n * target's `source_roots` entry (dropping `source_roots` — and an emptied\n * `import` block — rather than writing an invalid empty list).\n */\nfunction buildArchivedManifest(manifest: Manifest, plan: ArchivePlan, updatedAt: string): Manifest {\n let next: Manifest = { ...manifest, workspace: { ...manifest.workspace, updated_at: updatedAt } };\n\n next = plan.reposEmptied ? omitKey(next, \"repos\") : { ...next, repos: plan.nextRepos };\n\n if (plan.nextSourceRoots !== undefined) {\n if (plan.nextSourceRoots.length === 0) {\n const prunedImport =\n manifest.import !== undefined ? omitKey(manifest.import, \"source_roots\") : {};\n next =\n Object.keys(prunedImport).length === 0\n ? omitKey(next, \"import\")\n : { ...next, import: prunedImport };\n } else {\n next = {\n ...next,\n import: { ...(manifest.import ?? {}), source_roots: plan.nextSourceRoots },\n };\n }\n }\n\n return next;\n}\n\n/**\n * Archive (fold) a repo out of the project. Resolves the workspace, reads the\n * manifest, plans the manifest mutation (roster removal + source_roots prune),\n * and inspects the repo-side wiring for the teardown checklist. When `--apply`\n * is set and the target is a real, non-anchor roster member, it writes the\n * pruned manifest (bumping `updated_at`); otherwise it writes nothing and prints\n * the plan. The repo, its captured history, and its on-disk wiring are never\n * touched.\n */\nexport async function doRunProjectArchive(\n target: string,\n options: ProjectArchiveOptions,\n ctx: ProjectArchiveContext,\n): Promise<ProjectArchiveResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project archive\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n const roster = manifest.repos ?? [];\n\n let targetIsAnchor = false;\n try {\n targetIsAnchor = realpathSync(resolve(repositoryRoot, target)) === realpathSync(repositoryRoot);\n } catch {\n targetIsAnchor = false;\n }\n\n const plan = planArchive({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n target,\n targetIsAnchor,\n });\n\n const teardown =\n plan.found && !plan.isAnchor\n ? gatherArchiveTeardown(repositoryRoot, manifest, target)\n : {\n inspected: false,\n viewLink: false,\n instructionFiles: [],\n gitignorePatterns: [],\n canonical: false,\n };\n\n const applied = options.apply === true && plan.found && !plan.isAnchor;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(paths, buildArchivedManifest(manifest, plan, now().toISOString()), {\n force: true,\n });\n }\n\n const result: ProjectArchiveResult = {\n ...plan,\n hasRoster: roster.length > 0,\n applied,\n teardown,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectArchive(result));\n }\n return result;\n}\n\n/**\n * Render the archive report. Leads with the actionable outcome: no roster (run\n * adopt first), anchor refusal, target not found (with the declared paths), or\n * the manifest mutation that will be / was applied. Then the repo-side teardown\n * checklist (what `--apply` did NOT touch), and a note when the project becomes\n * solo or closes. Dry-run framing makes clear that without `--apply` nothing is\n * written.\n */\nexport function renderProjectArchive(result: ProjectArchiveResult): string {\n const lines: string[] = [];\n lines.push(\"# repo の archive(roster から畳む)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。archive 対象がありません。\");\n return lines.join(\"\\n\");\n }\n\n if (result.isAnchor) {\n lines.push(\n `⚠️ \\`${result.target}\\` は anchor(プロジェクトの root)です。anchor は archive できません(manifest の家のため)。`,\n );\n return lines.join(\"\\n\");\n }\n\n if (!result.found) {\n lines.push(`ℹ️ \\`${result.target}\\` は roster に宣言されていません(archive 対象なし)。`);\n return lines.join(\"\\n\");\n }\n\n // Manifest mutation summary.\n if (result.applied) {\n lines.push(`✅ \\`${result.target}\\` を roster から削除しました。`);\n } else {\n lines.push(`\\`${result.target}\\` を roster から削除予定(dry-run、反映するには --apply):`);\n }\n if (result.sourceRootRemoval !== undefined) {\n lines.push(\n `- source_roots から ${result.sourceRootRemoval} を prune${result.applied ? \"しました\" : \"します\"}(以後 refresh の対象外)。`,\n );\n } else {\n lines.push(\"- source_roots に該当エントリはありません(prune 不要)。\");\n }\n if (result.reposEmptied) {\n lines.push(\n \"- これが最後のメンバーです → roster は空になり `repos` 宣言は除去されます(プロジェクトを畳む)。\",\n );\n } else if (result.becomesSolo) {\n lines.push(\n \"- 残り 1 repo(solo)になります → workspace view は不要です(view 宣言/ディレクトリの撤去を検討)。\",\n );\n }\n lines.push(\"\");\n\n // Teardown checklist (report-only).\n const t = result.teardown;\n const items: string[] = [];\n if (t.viewLink) items.push(\"workspace view の symlink エントリ\");\n if (t.instructionFiles.length > 0) items.push(`指示書(${t.instructionFiles.join(\", \")})`);\n if (t.gitignorePatterns.length > 0)\n items.push(`.gitignore の指示書パターン(${t.gitignorePatterns.join(\", \")})`);\n if (t.canonical) items.push(`anchor の canonical(agents/${basename(result.target)}/AGENTS.md)`);\n\n if (!t.inspected) {\n lines.push(\"## 手動 teardown(repo がディスク上に解決できないため未検査)\");\n lines.push(\n \"- repo は既に削除済みの可能性があります。view symlink / 指示書 symlink / .gitignore / canonical が残っていないか手動で確認してください。\",\n );\n lines.push(\"\");\n } else if (items.length > 0) {\n lines.push(\"## 手動 teardown(--apply は触れません。残っている wiring を手で撤去してください)\");\n for (const i of items) lines.push(`- ${i}`);\n lines.push(\"\");\n } else {\n lines.push(\"repo 側の wiring(view/指示書/.gitignore/canonical)は残っていません。\");\n lines.push(\"\");\n }\n\n lines.push(\n \"注: archive は manifest(.basou、git 追跡=可逆)のみを変更します。repo・捕捉履歴・on-disk の wiring は削除しません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectRename}. */\nexport async function runProjectRename(\n oldPath: string,\n newPath: string,\n options: ProjectRenameOptions,\n ctx: ProjectRenameContext = {},\n): Promise<void> {\n try {\n await doRunProjectRename(oldPath, newPath, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Inspect the anchor-side wiring still at the OLD basename after a\n * basename-changing rename — the manual checklist `--apply` does NOT touch.\n * Read-only existence checks; an uninspectable path is reported as absent.\n */\nfunction gatherRenameWiring(\n repositoryRoot: string,\n manifest: Manifest,\n oldBasename: string,\n): RenameWiring {\n // An uninspectable anchor (a TOCTOU deletion since the manifest was read) must\n // not throw out of this advisory inspection — that would block the\n // authoritative manifest write that runs after it. Degrade to \"nothing found\".\n let anchorReal: string;\n try {\n anchorReal = realpathSync(repositoryRoot);\n } catch {\n return { canonicalDirOld: false, viewLinkOld: false };\n }\n const canonicalDirOld = existsSync(join(anchorReal, \"agents\", oldBasename));\n\n let viewLinkOld = false;\n const viewPath = manifest.workspace.view;\n if (viewPath !== undefined) {\n try {\n lstatSync(join(resolveViewDir(repositoryRoot, viewPath), oldBasename));\n viewLinkOld = true;\n } catch {\n // no view entry at the old basename\n }\n }\n return { canonicalDirOld, viewLinkOld };\n}\n\n/**\n * Build the manifest to write after a rename. Spreads the original (preserving\n * every known field), bumps `updated_at`, and replaces `repos` with the\n * re-pathed roster; when the source root was captured, replaces\n * `import.source_roots` with the re-pathed list. A rename never empties either\n * list, so no key is dropped.\n */\nfunction buildRenamedManifest(manifest: Manifest, plan: RenamePlan, updatedAt: string): Manifest {\n const next: Manifest = {\n ...manifest,\n workspace: { ...manifest.workspace, updated_at: updatedAt },\n repos: plan.nextRepos,\n };\n if (plan.nextSourceRoots !== undefined) {\n return { ...next, import: { ...(manifest.import ?? {}), source_roots: plan.nextSourceRoots } };\n }\n return next;\n}\n\n/**\n * Re-path a repo in the project. Resolves the workspace, reads the manifest,\n * plans the manifest mutation (roster + source_roots path update), and inspects\n * the anchor-side wiring still at the old basename. When `--apply` is set and the\n * rename is actionable (the source is a real, non-anchor roster member, the\n * destination is free, and old != new), it writes the re-pathed manifest;\n * otherwise it writes nothing and prints the plan. The repo is never moved or\n * rewired on disk.\n */\nexport async function doRunProjectRename(\n oldPath: string,\n newPath: string,\n options: ProjectRenameOptions,\n ctx: ProjectRenameContext,\n): Promise<ProjectRenameResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project rename\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n const roster = manifest.repos ?? [];\n\n let oldIsAnchor = false;\n try {\n oldIsAnchor = realpathSync(resolve(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);\n } catch {\n oldIsAnchor = false;\n }\n\n const plan = planRename({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n oldPath,\n newPath,\n oldIsAnchor,\n });\n\n const actionable = plan.found && !plan.isAnchor && !plan.collision && !plan.noop;\n const wiring =\n actionable && plan.basenameChanged\n ? gatherRenameWiring(repositoryRoot, manifest, pathBasename(plan.oldTarget))\n : { canonicalDirOld: false, viewLinkOld: false };\n\n const applied = options.apply === true && actionable;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(paths, buildRenamedManifest(manifest, plan, now().toISOString()), {\n force: true,\n });\n }\n\n const result: ProjectRenameResult = {\n ...plan,\n hasRoster: roster.length > 0,\n applied,\n wiring,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectRename(result));\n }\n return result;\n}\n\n/**\n * Render the rename report. Leads with the actionable outcome: no roster, no-op,\n * anchor refusal, collision refusal, source not found, or the manifest mutation\n * that will be / was applied. Then the anchor-side rename checklist (when the\n * basename changed) and a note to re-run the wiring generators.\n */\nexport function renderProjectRename(result: ProjectRenameResult): string {\n const lines: string[] = [];\n lines.push(\"# repo の rename(roster のパス更新)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。rename 対象がありません。\");\n return lines.join(\"\\n\");\n }\n if (result.noop) {\n lines.push(`ℹ️ \\`${result.oldTarget}\\` と \\`${result.newTarget}\\` は同一です(変更なし)。`);\n return lines.join(\"\\n\");\n }\n if (result.isAnchor) {\n lines.push(\n `⚠️ \\`${result.oldTarget}\\` は anchor(プロジェクトの root)です。anchor は rename できません。`,\n );\n return lines.join(\"\\n\");\n }\n if (!result.found) {\n lines.push(`ℹ️ \\`${result.oldTarget}\\` は roster に宣言されていません(rename 対象なし)。`);\n return lines.join(\"\\n\");\n }\n if (result.collision) {\n lines.push(\n `⚠️ \\`${result.newTarget}\\` は既に roster に宣言されています。重複を避けるため rename しません。`,\n );\n return lines.join(\"\\n\");\n }\n\n if (result.applied) {\n lines.push(`✅ \\`${result.oldTarget}\\` を \\`${result.newTarget}\\` に rename しました。`);\n } else {\n lines.push(\n `\\`${result.oldTarget}\\` を \\`${result.newTarget}\\` に rename 予定(dry-run、反映するには --apply):`,\n );\n }\n if (result.sourceRootRenamed !== undefined) {\n lines.push(\n `- source_roots の ${result.sourceRootRenamed} を ${result.newTarget} に更新${result.applied ? \"しました\" : \"します\"}。`,\n );\n } else {\n lines.push(\"- source_roots に該当エントリはありません(更新不要)。\");\n }\n lines.push(\"\");\n\n // Anchor-side checklist (report-only) — only relevant when the basename changes.\n if (result.basenameChanged) {\n const oldName = pathBasename(result.oldTarget);\n const newName = pathBasename(result.newTarget);\n const items: string[] = [];\n if (result.wiring.canonicalDirOld)\n items.push(`anchor canonical: agents/${oldName}/ → agents/${newName}/`);\n if (result.wiring.viewLinkOld) items.push(`workspace view の symlink: ${oldName} → ${newName}`);\n if (items.length > 0) {\n lines.push(\n \"## 手動リネーム(--apply は触れません。basename が変わるため手で更新してください)\",\n );\n for (const i of items) lines.push(`- ${i}`);\n } else {\n lines.push(\n `basename が ${oldName} → ${newName} に変わりますが、anchor canonical / view symlink は見つかりませんでした。`,\n );\n }\n lines.push(\n \" 反映後は `basou project symlinks` / `basou project workspace` で指示書 symlink と view を再生成してください。\",\n );\n } else {\n lines.push(\n \"注: basename は不変です。repo を別の場所へ移動した場合は `basou project symlinks` / `basou project workspace` で相対ターゲットを再生成してください。\",\n );\n }\n lines.push(\"\");\n\n lines.push(\n \"注: rename は manifest(.basou、git 追跡=可逆)のみを変更します。repo の移動・on-disk の wiring 更新は行いません。\",\n );\n return lines.join(\"\\n\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n PROTOCOL_END,\n PROTOCOL_START,\n parseMarkers,\n readMarkdownFile,\n removeMarkerSection,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { assertNotSymlink, writeFileDurable } from \"../lib/durable-write.js\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport {\n DEFAULT_PROTOCOLS_CONFIG_PATH,\n DEFAULT_TARGET_PATH,\n loadProtocolsConfig,\n type ProtocolEntry,\n} from \"../lib/protocols-config.js\";\n\n/** Marker pair that delimits the basou-managed protocol block in the target. */\nconst PROTOCOL_MARKERS = { start: PROTOCOL_START, end: PROTOCOL_END };\n\n/** Note rendered at the top of the managed block so a reader knows not to edit it. */\nconst MANAGED_NOTE =\n \"<!-- Managed by basou: 'basou protocol sync' regenerates everything between the BASOU:PROTOCOLS markers from ~/.basou/protocols.yaml. Manual edits inside the block are overwritten; edit the source files instead. -->\";\n\nexport type ProtocolCommonOptions = {\n config?: string;\n target?: string;\n verbose?: boolean;\n};\n\nexport type ProtocolSyncOptions = ProtocolCommonOptions & { dryRun?: boolean };\n\n/**\n * Wire `basou protocol` (sync / list / unsync) onto `program`. The command\n * renders operator-declared standing protocols into a marker-delimited block\n * inside the user-global Claude Code instructions file (~/.claude/CLAUDE.md),\n * which Claude Code auto-loads every session. It only ever touches the bytes\n * between the BASOU:PROTOCOLS markers; everything else in the file is preserved.\n */\nexport function registerProtocolCommand(program: Command): void {\n const protocol = program\n .command(\"protocol\")\n .description(\"Manage the basou-managed standing-protocol block in the global CLAUDE.md\");\n\n protocol\n .command(\"sync\")\n .description(\"Render declared protocols into the global CLAUDE.md (creates/updates the block)\")\n .option(\"--config <path>\", \"Path to protocols.yaml (default ~/.basou/protocols.yaml)\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"--dry-run\", \"Print what would change without writing\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolSyncOptions) => {\n await runProtocolSync(opts);\n });\n\n protocol\n .command(\"list\")\n .description(\"List declared protocols and whether the block is installed\")\n .option(\"--config <path>\", \"Path to protocols.yaml (default ~/.basou/protocols.yaml)\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolCommonOptions) => {\n await runProtocolList(opts);\n });\n\n protocol\n .command(\"unsync\")\n .description(\"Remove the basou-managed protocol block from the global CLAUDE.md\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"--dry-run\", \"Print what would change without writing\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolSyncOptions) => {\n await runProtocolUnsync(opts);\n });\n}\n\nexport async function runProtocolSync(options: ProtocolSyncOptions): Promise<void> {\n try {\n await doRunProtocolSync(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runProtocolList(options: ProtocolCommonOptions): Promise<void> {\n try {\n await doRunProtocolList(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runProtocolUnsync(options: ProtocolSyncOptions): Promise<void> {\n try {\n await doRunProtocolUnsync(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Read each protocol source and refuse if a source body contains a marker line\n * (which would corrupt the managed block on the next parse). Returns the\n * entries paired with their file contents, in declared order.\n */\nasync function readProtocolSources(\n entries: ProtocolEntry[],\n): Promise<{ entry: ProtocolEntry; content: string }[]> {\n const out: { entry: ProtocolEntry; content: string }[] = [];\n for (const entry of entries) {\n let content: string;\n try {\n content = await readFile(entry.source, \"utf8\");\n } catch (error: unknown) {\n if (error instanceof Error && (error as { code?: string }).code === \"ENOENT\") {\n throw new Error(\n \"A protocol source file does not exist. Check the 'source' paths in ~/.basou/protocols.yaml.\",\n { cause: error },\n );\n }\n throw new Error(\"Failed to read a protocol source file.\", { cause: error });\n }\n for (const line of content.split(/\\r?\\n/)) {\n if (line === PROTOCOL_START || line === PROTOCOL_END) {\n throw new Error(\n \"A protocol source contains a BASOU:PROTOCOLS marker line, which would corrupt the managed block. Remove that line from the source.\",\n );\n }\n }\n out.push({ entry, content });\n }\n return out;\n}\n\n/** Assemble the inner block body (without the markers) from the read sources. */\nfunction buildBlock(sources: { entry: ProtocolEntry; content: string }[]): string {\n const sections = sources.map(({ entry, content }) => {\n const body = content.replace(/\\s+$/, \"\");\n return entry.title !== undefined ? `## ${entry.title}\\n\\n${body}` : body;\n });\n return `${MANAGED_NOTE}\\n\\n${sections.join(\"\\n\\n\")}\\n`;\n}\n\n/**\n * Compute the new target body. Unlike the basou-owned generated files, the\n * target is a foreign file that may already hold user content with no basou\n * block yet, so the no-markers case APPENDS rather than throwing.\n *\n * - target absent: file is just the wrapped block.\n * - existing has an `ok` block: replace it in place (preserve before/after).\n * - existing has no block: append the block to the end (preserve all content).\n * - existing has a malformed block: refuse (do not silently rewrite).\n */\nfunction buildTargetBody(existing: string | null, block: string): string {\n const wrapped = `${PROTOCOL_START}\\n${block}${PROTOCOL_END}\\n`;\n // An empty existing file is treated like an absent one, so a freshly-touched\n // CLAUDE.md does not gain spurious leading blank lines from the append path.\n if (existing === null || existing === \"\") return wrapped;\n const section = parseMarkers(existing, PROTOCOL_MARKERS);\n switch (section.kind) {\n case \"ok\":\n return `${section.before}${PROTOCOL_START}\\n${block}${PROTOCOL_END}${section.after}`;\n case \"no_markers\": {\n const sep = existing.endsWith(\"\\n\\n\") ? \"\" : existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n return `${existing}${sep}${wrapped}`;\n }\n default:\n throw new Error(\n \"The BASOU:PROTOCOLS markers in the target are malformed (a marker is missing, duplicated, or out of order). Fix or remove them, then retry.\",\n );\n }\n}\n\n/**\n * Back up the target's original content the first time basou modifies it.\n * Uses a single stable `<target>.basou-bak` and never overwrites it, so the\n * pre-basou original is preserved exactly once. No-op when a backup already\n * exists or the target does not exist.\n */\nasync function backupOnce(target: string, existing: string | null): Promise<void> {\n if (existing === null) return;\n const bak = `${target}.basou-bak`;\n const already = await readMarkdownFile(bak);\n if (already !== null) return;\n await writeFileDurable(bak, existing);\n}\n\nexport async function doRunProtocolSync(options: ProtocolSyncOptions): Promise<void> {\n const configPath = options.config ?? DEFAULT_PROTOCOLS_CONFIG_PATH;\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n const entries = await loadProtocolsConfig(configPath);\n const sources = await readProtocolSources(entries);\n const block = buildBlock(sources);\n\n await assertNotSymlink(target);\n const existing = await readMarkdownFile(target);\n const newBody = buildTargetBody(existing, block);\n\n if (newBody === existing) {\n console.log(`The basou:protocols block is already up to date (${entries.length} protocol(s)).`);\n return;\n }\n\n // Install vs update wording comes from the parsed result, not a substring\n // check, so marker text appearing in the user's prose is not mistaken for an\n // installed block.\n const hadBlock = existing !== null && parseMarkers(existing, PROTOCOL_MARKERS).kind === \"ok\";\n\n if (options.dryRun === true) {\n console.log(\n `[dry-run] Would ${hadBlock ? \"update\" : \"install\"} the basou:protocols block (${entries.length} protocol(s)).`,\n );\n for (const { entry } of sources) {\n console.log(` - ${entry.title ?? entry.source}`);\n }\n return;\n }\n\n // Optimistic concurrency: re-read and abort if the file changed since the\n // read above, so a concurrent edit is not clobbered. This narrows but does\n // not fully close the window (a writer landing between this read and the\n // rename inside writeFileDurable is still possible); hard exclusion would\n // need a lock, which is out of scope for this slice.\n const recheck = await readMarkdownFile(target);\n if (recheck !== existing) {\n throw new Error(\n \"The target changed during sync; aborting so a concurrent edit is not overwritten. Re-run 'basou protocol sync'.\",\n );\n }\n\n // Back up the original only after the CAS check passes, so an aborted run\n // never leaves a backup of a file it did not modify.\n await backupOnce(target, existing);\n await writeFileDurable(target, newBody);\n console.log(\n `${hadBlock ? \"Updated\" : \"Installed\"} the basou:protocols block in the global CLAUDE.md (${entries.length} protocol(s)).`,\n );\n}\n\nexport async function doRunProtocolList(options: ProtocolCommonOptions): Promise<void> {\n const configPath = options.config ?? DEFAULT_PROTOCOLS_CONFIG_PATH;\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n const entries = await loadProtocolsConfig(configPath);\n const existing = await readMarkdownFile(target);\n const installed = existing !== null && parseMarkers(existing, PROTOCOL_MARKERS).kind === \"ok\";\n\n console.log(`Declared protocols (${entries.length}):`);\n for (const entry of entries) {\n console.log(` - ${entry.title ?? entry.source}`);\n }\n console.log(installed ? \"Block: installed in the global CLAUDE.md.\" : \"Block: not installed.\");\n}\n\nexport async function doRunProtocolUnsync(options: ProtocolSyncOptions): Promise<void> {\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n await assertNotSymlink(target);\n const existing = await readMarkdownFile(target);\n if (existing === null) {\n console.log(\"No target file; nothing to remove.\");\n return;\n }\n\n const newBody = removeMarkerSection(existing, \"CLAUDE.md\", PROTOCOL_MARKERS);\n if (newBody === existing) {\n console.log(\"No basou:protocols block found; nothing removed.\");\n return;\n }\n\n if (options.dryRun === true) {\n console.log(\"[dry-run] Would remove the basou:protocols block from the global CLAUDE.md.\");\n return;\n }\n\n // Optimistic concurrency (see sync): re-read and abort on a concurrent edit\n // before backing up or writing, so an aborted run leaves nothing behind.\n const recheck = await readMarkdownFile(target);\n if (recheck !== existing) {\n throw new Error(\n \"The target changed during unsync; aborting so a concurrent edit is not overwritten. Re-run 'basou protocol unsync'.\",\n );\n }\n\n await backupOnce(target, existing);\n await writeFileDurable(target, newBody);\n console.log(\"Removed the basou:protocols block from the global CLAUDE.md.\");\n}\n","import { randomUUID } from \"node:crypto\";\nimport { lstat, open, rename, stat, unlink } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\n\n/**\n * Throw if `targetPath` is a symlink. Returns silently when the path is a\n * regular file or does not exist.\n *\n * Writing through a symlink would let a link at the target redirect the write\n * to an unexpected file. The protocol channel writes into a user-owned config\n * file and refuses symlinked targets by default (mirroring the `.basou/` root\n * invariant, which also rejects a symlink in its place). `lstat` does not\n * follow the link, so a symlink is detected as such.\n */\nexport async function assertNotSymlink(targetPath: string): Promise<void> {\n try {\n const st = await lstat(targetPath);\n if (st.isSymbolicLink()) {\n throw new Error(\n \"Refusing to write through a symlink. Replace the symlinked target with a regular file (or remove it) and retry.\",\n );\n }\n } catch (error: unknown) {\n if (error instanceof Error && (error as { code?: string }).code === \"ENOENT\") return;\n throw error;\n }\n}\n\n/**\n * Durably write `content` to `targetPath`, preserving the existing file's\n * permission bits and fsyncing both the file and its directory.\n *\n * In addition to a tmp + rename atomic swap, the file contents are fsynced\n * before the rename and the parent directory is fsynced after, so a crash or\n * power loss leaves either the old file or the fully-written new one (never a\n * truncated file), and the rename itself survives. The new file inherits the\n * mode of the file it replaces (default 0o644 when the target does not yet\n * exist) rather than whatever the umask would impose. Directory fsync is\n * best-effort: platforms that reject an fsync on a directory fd do not fail the\n * write (the contents are already durable via the file fsync and the atomic\n * rename).\n *\n * Intended for writing into a user-owned config file (e.g. ~/.claude/CLAUDE.md)\n * where durability and mode preservation matter. The tmp file is created with\n * the `wx` flag in the same directory so the rename cannot cross filesystems\n * and never clobbers a concurrent tmp file. The caller is responsible for\n * refusing symlinked targets (see {@link assertNotSymlink}); this helper\n * replaces the name via rename and does not follow a symlink at `targetPath`.\n */\nexport async function writeFileDurable(targetPath: string, content: string): Promise<void> {\n const dir = dirname(targetPath);\n const tmpPath = join(dir, `.${basename(targetPath)}.tmp.${randomUUID()}`);\n\n let mode = 0o644;\n try {\n mode = (await stat(targetPath)).mode & 0o777;\n } catch (error: unknown) {\n if (!(error instanceof Error && (error as { code?: string }).code === \"ENOENT\")) {\n throw error;\n }\n }\n\n let handle: Awaited<ReturnType<typeof open>> | undefined;\n try {\n handle = await open(tmpPath, \"wx\", mode);\n await handle.writeFile(content, \"utf8\");\n await handle.chmod(mode);\n await handle.sync();\n await handle.close();\n handle = undefined;\n await rename(tmpPath, targetPath);\n } catch (error: unknown) {\n if (handle) await handle.close().catch(() => undefined);\n await unlink(tmpPath).catch(() => undefined);\n throw error;\n }\n\n // Best-effort directory fsync so the rename is durable across power loss.\n try {\n const dirHandle = await open(dir, \"r\");\n try {\n await dirHandle.sync();\n } finally {\n await dirHandle.close();\n }\n } catch {\n // Some platforms reject fsync on a directory fd; the file content is\n // already durable and the rename is atomic, so do not fail the write.\n }\n}\n","import { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { readYamlFile } from \"@basou/core\";\n\n/**\n * One declared standing protocol: a markdown source file (the protocol text)\n * and an optional display title. `source` is resolved to an absolute path by\n * {@link loadProtocolsConfig}.\n */\nexport type ProtocolEntry = { source: string; title?: string };\n\n/** Canonical location of the protocols config (a user-level, machine-local file). */\nexport const DEFAULT_PROTOCOLS_CONFIG_PATH = join(homedir(), \".basou\", \"protocols.yaml\");\n\n/**\n * Locked render target for this slice: the user-global Claude Code instructions\n * file, which Claude Code auto-loads at every session start. The target is not\n * read from the config (a config-supplied path would let the writer append to\n * arbitrary files); only an explicit `--target` flag may override it, and that\n * override exists for tests.\n */\nexport const DEFAULT_TARGET_PATH = join(homedir(), \".claude\", \"CLAUDE.md\");\n\nconst ALLOWED_TOP_KEYS = new Set([\"version\", \"protocols\"]);\nconst ALLOWED_ENTRY_KEYS = new Set([\"source\", \"title\"]);\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/protocols.yaml` (or an injected path for tests),\n * returning the protocol entries with each `source` expanded to an absolute\n * path. Throws an Error with a pathless, user-facing message on a missing file,\n * invalid YAML, a malformed shape, an unknown key, an empty or duplicate\n * source, an empty title, or an empty list.\n *\n * Shape (strict; unknown keys are rejected):\n * version: 1 # optional\n * protocols:\n * - source: ~/projects/foo-planning/protocols/bar.md # required, absolute or ~\n * title: Bar Protocol # optional, non-empty\n */\nexport async function loadProtocolsConfig(\n configPath: string = DEFAULT_PROTOCOLS_CONFIG_PATH,\n): Promise<ProtocolEntry[]> {\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 protocols config at ~/.basou/protocols.yaml. Create one (a 'protocols:' list of source markdown paths) before running 'basou protocol sync'.\",\n );\n }\n if (error instanceof Error && error.message === \"Failed to parse YAML content\") {\n throw new Error(\"~/.basou/protocols.yaml is not valid YAML.\");\n }\n throw error;\n }\n\n if (!isRecord(raw) || !Array.isArray(raw.protocols)) {\n throw new Error(\"~/.basou/protocols.yaml must contain a 'protocols:' list.\");\n }\n for (const key of Object.keys(raw)) {\n if (!ALLOWED_TOP_KEYS.has(key)) {\n throw new Error(\n `~/.basou/protocols.yaml has an unknown key '${key}' (allowed: version, protocols).`,\n );\n }\n }\n\n const seen = new Set<string>();\n const result: ProtocolEntry[] = [];\n for (const entry of raw.protocols) {\n if (!isRecord(entry)) {\n throw new Error(\"Each protocol entry must be a mapping with a 'source' key.\");\n }\n for (const key of Object.keys(entry)) {\n if (!ALLOWED_ENTRY_KEYS.has(key)) {\n throw new Error(`A protocol entry has an unknown key '${key}' (allowed: source, title).`);\n }\n }\n if (typeof entry.source !== \"string\" || entry.source.trim().length === 0) {\n throw new Error(\"Each protocol entry needs a non-empty string 'source'.\");\n }\n if (\n entry.title !== undefined &&\n (typeof entry.title !== \"string\" || entry.title.trim().length === 0)\n ) {\n throw new Error(\"A protocol entry 'title' must be a non-empty string when present.\");\n }\n const expanded = expandTilde(entry.source.trim());\n if (!isAbsolute(expanded)) {\n throw new Error(\"Protocol 'source' paths must be absolute (or start with '~').\");\n }\n const abs = resolve(expanded);\n if (seen.has(abs)) {\n throw new Error(\"Duplicate protocol source (each source path may appear only once).\");\n }\n seen.add(abs);\n result.push(\n entry.title !== undefined ? { source: abs, title: entry.title.trim() } : { source: abs },\n );\n }\n\n if (result.length === 0) {\n throw new Error(\"~/.basou/protocols.yaml has no protocols.\");\n }\n return result;\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\nexport function 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 if (result.decisions.decisionCount === 0) {\n // \"regenerated (0)\" read as success while the decision provenance was in\n // fact empty. State the count plainly, and when there are captured sessions\n // but no decisions, point at the capture path. Wording is cause-neutral and\n // adapter-blind on purpose (we only know the aggregate session count here):\n // \"none auto-recorded\" is true whether codex carries no approval-question\n // signal to derive from, or a Claude Code run simply made no decisions.\n // The pointer names `basou decision capture` (the batch path the in-loop\n // agent uses to record a session's conversational decisions at once)\n // rather than the single-shot `basou decision record`.\n const hasSessions = result.handoff.status === \"generated\" && result.handoff.sessionCount > 0;\n console.log(\n hasSessions\n ? \"decisions: 0 (none auto-recorded from these sessions; capture any made with 'basou decision capture')\"\n : \"decisions: 0\",\n );\n } else {\n console.log(`decisions: regenerated (${result.decisions.decisionCount})`);\n }\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 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 {\n basouPaths,\n findReviewGaps,\n type ReviewGapsSummary,\n type ReviewGapUnit,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { InvalidArgumentError } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\n\nexport type ReviewGapsOptions = {\n repo?: string[];\n window?: number;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ReviewGapsContext = ImportContext & {\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/** Commander collector: accumulate a repeatable `--repo` into an array. */\nfunction collectRepo(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** Commander parser: `--window` is a positive integer count of hours. */\nexport function parseWindow(value: string): number {\n const hours = Number(value);\n if (!Number.isInteger(hours) || hours <= 0) {\n throw new InvalidArgumentError(\"--window must be a positive integer (hours).\");\n }\n return hours;\n}\n\n/**\n * Wire `basou review-gaps` onto `program`. A read-only, advisory check for the\n * \"external adversarial review before commit\" protocol: it surfaces units of\n * work that landed commits with NO bound cross-model (Codex) review trail. It\n * never claims a unit WAS reviewed — temporal proximity is not binding — so it\n * surfaces suspicion and leaves the final call to the operator. It writes\n * nothing and enforces nothing.\n */\nexport function registerReviewGapsCommand(program: Command): void {\n program\n .command(\"review-gaps\")\n .description(\n \"Surface units of work committed without a bound cross-model review trail (read-only, advisory)\",\n )\n .option(\n \"--repo <name>\",\n \"Restrict to a repo by name (repeatable; default: every repo with captured commits)\",\n collectRepo,\n [],\n )\n .option(\n \"--window <hours>\",\n \"Hours before a commit to look for a review (default 24)\",\n parseWindow,\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ReviewGapsOptions) => {\n await runReviewGaps(opts);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunReviewGaps}. */\nexport async function runReviewGaps(\n options: ReviewGapsOptions,\n ctx: ReviewGapsContext = {},\n): Promise<void> {\n try {\n await doRunReviewGaps(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** Pure runner: resolves the workspace, computes the summary, prints it (or JSON). */\nexport async function doRunReviewGaps(\n options: ReviewGapsOptions,\n ctx: ReviewGapsContext,\n): Promise<ReviewGapsSummary> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"review-gaps\");\n const paths = basouPaths(repositoryRoot);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const summary = await findReviewGaps({\n paths,\n nowIso,\n ...(options.repo !== undefined && options.repo.length > 0 ? { scope: options.repo } : {}),\n ...(options.window !== undefined ? { windowHours: options.window } : {}),\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(summary));\n } else {\n console.log(renderReviewGaps(summary));\n }\n return summary;\n}\n\nfunction relAge(iso: string | null, now: Date): string {\n if (iso === null) return \"(不明)\";\n const ms = now.getTime() - Date.parse(iso);\n if (!Number.isFinite(ms) || ms < 0) return \"たった今\";\n const days = Math.floor(ms / 86_400_000);\n if (days >= 1) return `${days}日前`;\n const hours = Math.floor(ms / 3_600_000);\n if (hours >= 1) return `${hours}時間前`;\n return `${Math.max(1, Math.floor(ms / 60_000))}分前`;\n}\n\nfunction unitLine(u: ReviewGapUnit, now: Date): string {\n const when = relAge(u.lastCommitAt, now);\n const head = `- ${u.repo} ${when} (${u.commitCount} commit${u.commitCount === 1 ? \"\" : \"s\"})`;\n if (u.verdict === \"near_unbound\") {\n const ids = u.reviews.map((r) => r.sessionId.slice(0, 14)).join(\", \");\n return `${head} — 近接レビューはあるが diff/変更ファイルを確認していない [${ids}]`;\n }\n return `${head} — 紐づくクロスモデルレビューなし`;\n}\n\nfunction candidateLine(u: ReviewGapUnit, now: Date): string {\n const when = relAge(u.lastCommitAt, now);\n const cite = u.reviews\n .map((r) => `${r.sessionId.slice(0, 14)}${r.examinedDiff ? \"(diff)\" : \"\"}`)\n .join(\", \");\n return `- ${u.repo} ${when} (${u.commitCount} commit${u.commitCount === 1 ? \"\" : \"s\"}) — レビュー形跡: ${cite}`;\n}\n\n/**\n * Render the advisory report. Leads with the gaps (units with no bound review),\n * then the candidates to confirm, then a per-repo tally. It deliberately states\n * the read-only / capture-bounded / no-auto-clear framing so the verdict is not\n * over-read.\n */\nexport function renderReviewGaps(summary: ReviewGapsSummary): string {\n const now = new Date(summary.generatedAt);\n const lines: string[] = [];\n const scope = summary.scope ? summary.scope.join(\", \") : \"全リポジトリ\";\n lines.push(`# レビュー証跡のギャップ (${scope})`);\n lines.push(\"\");\n\n if (summary.gaps.length === 0) {\n lines.push(\"✅ 取り込み済みの範囲では、レビュー証跡なしで着地した作業単位はありません。\");\n } else {\n lines.push(`⚠️ レビュー証跡なしで着地した作業単位: ${summary.gaps.length}`);\n for (const u of summary.gaps) lines.push(unitLine(u, now));\n }\n lines.push(\"\");\n\n if (summary.candidates.length > 0) {\n lines.push(\n `## 確認待ち (${summary.candidates.length}) — クロスモデルがレビューした形跡あり。この変更を本当に見たか確認してください`,\n );\n for (const u of summary.candidates) lines.push(candidateLine(u, now));\n lines.push(\"\");\n }\n\n if (summary.unknowns.length > 0) {\n const n = summary.unknowns.reduce((sum, u) => sum + u.commitCount, 0);\n lines.push(\n `## 導出不可 (${summary.unknowns.length} 単位 / ${n} commit) — repo か時刻を捕捉から導けず、判定を保留(clear ではありません)`,\n );\n lines.push(\"\");\n }\n\n lines.push(\"## リポジトリ別\");\n for (const r of summary.repos) {\n lines.push(\n `- ${r.repo}: ${r.units} 単位 (証跡なし ${r.omissionUnits} / 近接のみ ${r.nearUnboundUnits} / 確認待ち ${r.candidateUnits}${r.unknownUnits > 0 ? ` / 不明 ${r.unknownUnits}` : \"\"})`,\n );\n }\n lines.push(\"\");\n lines.push(\n `注: read-only の advisory です。取り込み済みの commit のみが対象(最新取込 commit: ${summary.newestCommitAt === null ? \"なし\" : relAge(summary.newestCommitAt, now)})。レビューの「実施」は自動判定せず、時間的近接だけでは合格にしません。enforce はしません。`,\n );\n return lines.join(\"\\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 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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.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\n/**\n * Resolve the repository root that owns the `.basou/` store for a session\n * subcommand, sharing the workspace-view fallback used by `orient` / `refresh`\n * (and the `project` commands): a git-untracked view dir that symlinks its\n * planning repo redirects to that repo (with a note on stderr) instead of failing\n * with \"Not a git repository\". Session commands previously resolved with the\n * git-only `resolveRepositoryRoot`, so `basou session list` died in a view; this\n * unifies them with the rest of the CLI.\n */\nasync function resolveRepositoryRootForSession(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"import\" | \"note\" | \"rechain\",\n): Promise<string> {\n return resolveBasouRootForCommand(cwd, `session ${subcmd}`);\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\">← 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'\n ? '; handoff regenerated, decisions: ' + (data.decisions ? data.decisions.decisionCount : 0)\n : '');\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","import { isVerbose, renderCliError } from \"./lib/error-render.js\";\nimport { buildProgram } from \"./program.js\";\n\n// Thin binary entry: construction lives in the side-effect-free ./program.ts\n// (so the docs generator can import `buildProgram` and introspect the command\n// surface without triggering a parse); this file owns the single argv parse.\nconst program = buildProgram();\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n // Top-level safety net: never print the Error object directly because\n // Node's util.inspect recursively expands `error.cause`, which can carry\n // absolute paths from native fs errors. Delegates to the shared pathless\n // renderer; verbose mode is gated on BASOU_DEBUG only since the failure\n // bypassed the subcommand handler that owns the `-v` flag.\n renderCliError(err, { verbose: isVerbose(undefined) });\n process.exit(1);\n});\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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":["program","id","homedir","resolve","acquireLock","assertBasouRootSafe","basouPaths","findErrorCode","prefixedUlid","readManifest","resolveRepositoryRoot","resolve","basouPaths","join","readYamlFile","root","basouPaths","resolve","program","basouPaths","assertWorkspaceInitialized","prefixedUlid","acquireLock","readManifest","resolve","homedir","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","program","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","program","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","acquireLock","homedir","readYamlFile","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","readMarkdownFile","renderWithMarkers","resolveRepositoryRoot","writeMarkdownFile","program","basouPaths","assertWorkspaceInitialized","readMarkdownFile","renderWithMarkers","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","readFile","stat","homedir","basename","join","resolve","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","readSessionYaml","resolveRepositoryRoot","SES_PREFIX","SHORT_ID_LEN","program","resolve","join","homedir","basename","basouPaths","assertWorkspaceInitialized","readManifest","payload","readSessionYaml","findErrorCode","stat","readFile","shortId","resolveRepositoryRoot","assertBasouRootSafe","basename","resolve","resolveRepositoryRoot","program","basename","resolve","resolveRepositoryRoot","acquireLock","appendEventToExistingSession","assertBasouRootSafe","basouPaths","createAdHocSessionWithEvent","findErrorCode","readManifest","resolveSessionId","InvalidArgumentError","LABEL_TRUNCATE_HEAD","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","acquireLock","appendEventToExistingSession","readManifest","createAdHocSessionWithEvent","buildAdHocLabel","InvalidArgumentError","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","renderOrientation","writeMarkdownFile","homedir","isAbsolute","join","resolve","readYamlFile","expandTilde","isRecord","readMarkdownFile","renderDecisions","renderHandoff","renderWithMarkers","writeMarkdownFile","renderHandoff","readMarkdownFile","writeMarkdownFile","renderWithMarkers","renderDecisions","program","basouPaths","assertWorkspaceInitialized","renderOrientation","writeMarkdownFile","assertBasouRootSafe","findErrorCode","basename","isAbsolute","join","relative","resolve","basouPaths","readManifest","readMarkdownFile","renderWithMarkers","writeManifest","writeMarkdownFile","program","basouPaths","readManifest","writeManifest","resolve","join","relative","basename","isAbsolute","readMarkdownFile","writeMarkdownFile","renderWithMarkers","canonical","readFile","parseMarkers","readMarkdownFile","stat","unlink","basename","dirname","join","homedir","isAbsolute","join","resolve","readYamlFile","expandTilde","isRecord","program","readFile","parseMarkers","readMarkdownFile","assertBasouRootSafe","basouPaths","findErrorCode","InvalidArgumentError","readdir","stat","homedir","join","findErrorCode","join","homedir","readdir","findErrorCode","stat","collectPath","InvalidArgumentError","resolve","program","basouPaths","assertWorkspaceInitialized","assertBasouRootSafe","findErrorCode","isAbsolute","resolve","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","writeMarkdownFile","program","basouPaths","assertWorkspaceInitialized","isAbsolute","resolve","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","basouPaths","InvalidArgumentError","InvalidArgumentError","program","basouPaths","mkdir","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","ChildProcessRunner","coreAppendChainedEvent","finalizeSessionYaml","getSnapshot","overwriteYamlFile","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","SessionSchema","sanitizeWorkingDirectory","writeYamlFile","program","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","resolveSessionId","SessionImportPayloadSchema","SessionSchema","InvalidArgumentError","SES_PREFIX","TASK_PREFIX","SHORT_ID_BASE_LEN","SHORT_ID_MAX_LEN","STATUS_VALUES","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","join","readYamlFile","SessionSchema","findErrorCode","computeUniquePrefixLen","sliceShort","maxLen","pad","isAbsolute","relative","shortTaskId","shortId","assertBasouRootSafe","readManifest","SessionImportPayloadSchema","importOptions","importSessionFromJson","readFile","InvalidArgumentError","basename","acquireLock","appendEventToExistingSession","enumerateSessionDirs","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","program","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","program","basouPaths","assertBasouRootSafe","findErrorCode","readManifest","resolveRepositoryRoot","readFile","join","assertBasouRootSafe","basouPaths","findErrorCode","loadSessionEntries","prefixedUlid","readManifest","replayEvents","resolveRepositoryRoot","resolveSessionId","resolveTaskId","InvalidArgumentError","STATUS_VALUES","program","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","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","enumerateSessionDirs","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","basename","resolve","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","InvalidArgumentError","lstat","realpath","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","program","basouPaths","assertWorkspaceInitialized","resolve","readManifest","basename","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","require","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/error-render.ts","../src/program.ts","../src/commands/approval.ts","../src/commands/decision.ts","../src/lib/repo-root.ts","../src/lib/portfolio-config.ts","../src/commands/decisions.ts","../src/commands/exec.ts","../src/commands/handoff.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/note.ts","../src/commands/orient.ts","../src/lib/hosts-config.ts","../src/lib/provenance-actions.ts","../src/commands/project.ts","../src/commands/protocol.ts","../src/lib/durable-write.ts","../src/lib/protocols-config.ts","../src/commands/refresh.ts","../src/commands/refresh-watch.ts","../src/commands/report.ts","../src/commands/review-gaps.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","../src/index.ts"],"sourcesContent":["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 { 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 { registerNoteCommand } from \"./commands/note.js\";\nimport { registerOrientCommand } from \"./commands/orient.js\";\nimport { registerProjectCommand } from \"./commands/project.js\";\nimport { registerProtocolCommand } from \"./commands/protocol.js\";\nimport { registerRefreshCommand } from \"./commands/refresh.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerReviewGapsCommand } from \"./commands/review-gaps.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 registerNoteCommand(program);\n registerTaskCommand(program);\n registerHandoffCommand(program);\n registerDecisionsCommand(program);\n registerReportCommand(program);\n registerOrientCommand(program);\n registerReviewGapsCommand(program);\n registerProjectCommand(program);\n registerProtocolCommand(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 { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport {\n acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n isValidPrefixedId,\n type PrefixedId,\n prefixedUlid,\n readManifest,\n resolveRepositoryRoot,\n resolveSessionId,\n type SessionStatus,\n sanitizePath,\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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.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 decision\n .command(\"capture\")\n .description(\n \"Capture a batch of decisions from a JSON array (stdin or --file). The \" +\n \"in-loop agent extracts a session's conversational decisions -- with \" +\n \"rationale, alternatives, and rejected reasons -- and pipes them in; \" +\n \"basou writes them deterministically into one ad-hoc session.\",\n )\n .option(\"--file <path>\", \"Read the JSON array from a file instead of stdin\")\n .option(\"--dry-run\", \"Validate and preview the decisions without writing them\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .addHelpText(\"after\", CAPTURE_HELP)\n .action(async (options: DecisionCaptureOptions) => {\n await runDecisionCapture(options);\n });\n}\n\nconst CAPTURE_HELP = `\nInput format (a JSON array; one object per decision):\n [\n {\n \"title\": \"Adopt pnpm for the monorepo\",\n \"rationale\": \"Workspace protocol and a content-addressed store fit our layout.\",\n \"alternatives\": [\"npm workspaces\", \"yarn\"],\n \"rejected_reason\": \"npm hoisting caused phantom-dependency bugs\",\n \"linked_files\": [\"pnpm-workspace.yaml\"]\n }\n ]\n\nOnly \"title\" is required; every other field is optional. All decisions are\nwritten into one ad-hoc session timestamped now, so orientation surfaces them\nas the latest decisions. Run from a workspace-view directory and it resolves to\nthe planning repo, like 'basou orient' / 'basou refresh' / 'basou note'.\n\nExample (heredoc on stdin):\n basou decision capture <<'JSON'\n [{ \"title\": \"Ship the capture command\", \"rationale\": \"Close the why-capture gap\" }]\n JSON\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\nexport type DecisionCaptureOptions = {\n /** Read the JSON array from this file instead of stdin. */\n file?: string;\n /** Validate + preview without writing anything. */\n dryRun?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type DecisionCaptureContext = {\n /** Defaults to `process.cwd()`. Injectable for tests. */\n cwd?: string;\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n /**\n * Defaults to reading process.stdin to EOF. Injectable for tests so they do\n * not depend on a real stdin stream. Ignored when `--file` is given.\n */\n readInput?: () => Promise<string>;\n};\n\n/** One decision in the capture input: a title plus the optional rich fields. */\ntype CaptureDecisionInput = { title: string } & RichDecisionFields;\n\n/**\n * Programmatic entry for `basou decision capture`. Owns process exit state.\n * Tests targeting the success path or the thrown error should prefer\n * {@link doRunDecisionCapture}.\n */\nexport async function runDecisionCapture(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext = {},\n): Promise<void> {\n try {\n await doRunDecisionCapture(options, ctx);\n } catch (error: unknown) {\n // The ad-hoc path writes the decision events before finalizing\n // session.yaml; on a finalize failure the classifier surfaces \"do not\n // rerun\" so the agent does not re-pipe and duplicate the batch (mirrors\n // `basou decision record`).\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunDecisionCapture(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext,\n): Promise<void> {\n const cwd = ctx.cwd ?? process.cwd();\n // View-aware resolution (like orient / refresh / note) so capture works from\n // a workspace-view dir, redirecting to the planning repo where decisions.md\n // and orient live. `basou decision record` predates this and uses a plain\n // git-root resolver; aligning record is a separate, behavior-changing\n // follow-up, not in scope for the capture slice.\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"decision capture\");\n const paths = basouPaths(repositoryRoot);\n await assertWorkspaceInitialized(paths.root);\n\n const raw = await readCaptureInput(options, ctx);\n const decisions = parseCaptureInput(raw);\n\n if (options.dryRun === true) {\n printCapturePreview(options, decisions);\n return;\n }\n\n const now = ctx.nowProvider !== undefined ? ctx.nowProvider() : new Date();\n const occurredAt = now.toISOString();\n // Mint the decision ids up front, in input order. prefixedUlid is monotonic,\n // so even though every event shares `occurredAt` the ids increase with input\n // order; decisions.md and orient (which sort by occurred_at then decision id)\n // therefore preserve the agent's ordering and treat the last item as latest.\n const decisionIds = decisions.map(() => prefixedUlid(\"decision\"));\n\n const manifest = await readManifest(paths);\n // Sanitize the --file path before it lands in session.yaml invocation.args:\n // an absolute path would otherwise leak the operator's machine layout into\n // persisted `.basou/` state, the same reason `working_directory` is\n // sanitized. Resolve against cwd first so a relative --file is rewritten the\n // same way readFile resolved it.\n const invocationArgs =\n options.file !== undefined\n ? [\n \"--file\",\n sanitizePath(resolve(cwd, options.file), {\n workingDirectory: repositoryRoot,\n homedir: homedir(),\n }),\n ]\n : [];\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildCaptureLabel(decisions.length),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou decision capture\",\n args: invocationArgs,\n },\n targetEventBuilders: decisions.map(\n (decision, index) =>\n (sessionId: PrefixedId<\"ses\">, eventId: PrefixedId<\"evt\">): Event =>\n buildDecisionEvent({\n eventId,\n sessionId,\n decisionId: decisionIds[index] as PrefixedId<\"decision\">,\n title: decision.title,\n occurredAt,\n rich: toRichFields(decision),\n }),\n ),\n });\n\n printCaptureResult(options, {\n sessionId: adHoc.sessionId,\n items: decisions.map((decision, index) => ({\n decisionId: decisionIds[index] as string,\n eventId: adHoc.targetEventIds[index] as string,\n input: decision,\n })),\n });\n}\n\nasync function readCaptureInput(\n options: DecisionCaptureOptions,\n ctx: DecisionCaptureContext,\n): Promise<string> {\n if (options.file !== undefined) {\n try {\n return await readFile(options.file, \"utf8\");\n } catch (error: unknown) {\n if (findErrorCode(error, \"ENOENT\")) {\n throw new Error(`Input file not found: ${options.file}`);\n }\n throw error;\n }\n }\n if (ctx.readInput !== undefined) {\n return await ctx.readInput();\n }\n // A bare invocation with no piped stdin would otherwise block forever; fail\n // fast with the same actionable hint the empty-input guard uses.\n if (process.stdin.isTTY === true) {\n throw new Error(NO_INPUT_HINT);\n }\n return await readStdinToEnd();\n}\n\nasync function readStdinToEnd(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nconst NO_INPUT_HINT = \"No input: pipe a JSON array of decisions to stdin or pass --file <path>.\";\n\nconst CAPTURE_ALLOWED_KEYS: ReadonlySet<string> = new Set([\n \"title\",\n \"rationale\",\n \"rejected_reason\",\n \"alternatives\",\n \"linked_events\",\n \"linked_files\",\n]);\n\n/**\n * Parse + validate the capture input. Errors name the offending array index and\n * field (e.g. `decision[2].title must be a non-empty string`) so the in-loop\n * agent can self-correct its extraction without guessing.\n */\nfunction parseCaptureInput(raw: string): CaptureDecisionInput[] {\n if (raw.trim().length === 0) {\n throw new Error(NO_INPUT_HINT);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error: unknown) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new Error(`Input is not valid JSON: ${detail}`);\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\"Input must be a JSON array of decision objects.\");\n }\n if (parsed.length === 0) {\n throw new Error(\"Input array must contain at least one decision.\");\n }\n return parsed.map((item, index) => validateCaptureItem(item, index));\n}\n\nfunction validateCaptureItem(item: unknown, index: number): CaptureDecisionInput {\n if (typeof item !== \"object\" || item === null || Array.isArray(item)) {\n throw new Error(`decision[${index}] must be a JSON object.`);\n }\n const obj = item as Record<string, unknown>;\n for (const key of Object.keys(obj)) {\n if (!CAPTURE_ALLOWED_KEYS.has(key)) {\n throw new Error(\n `decision[${index}]: unknown field '${key}'. Allowed: title, rationale, rejected_reason, alternatives, linked_events, linked_files.`,\n );\n }\n }\n if (typeof obj.title !== \"string\" || isBlank(obj.title)) {\n throw new Error(`decision[${index}].title must be a non-empty string.`);\n }\n const out: CaptureDecisionInput = { title: obj.title };\n if (obj.rationale !== undefined) {\n out.rationale = requireNonEmptyString(obj.rationale, index, \"rationale\");\n }\n if (obj.rejected_reason !== undefined) {\n out.rejected_reason = requireNonEmptyString(obj.rejected_reason, index, \"rejected_reason\");\n }\n if (obj.alternatives !== undefined) {\n out.alternatives = validateStringArray(obj.alternatives, index, \"alternatives\", (value, i) => {\n if (isBlank(value)) {\n throw new Error(`decision[${index}].alternatives[${i}] must not be empty.`);\n }\n });\n }\n if (obj.linked_events !== undefined) {\n out.linked_events = validateStringArray(\n obj.linked_events,\n index,\n \"linked_events\",\n (value, i) => {\n if (!isValidEventId(value)) {\n throw new Error(\n `decision[${index}].linked_events[${i}] must match evt_<ULID>, got '${value}'.`,\n );\n }\n },\n );\n }\n if (obj.linked_files !== undefined) {\n out.linked_files = validateStringArray(obj.linked_files, index, \"linked_files\", (value, i) => {\n if (isBlank(value)) {\n throw new Error(`decision[${index}].linked_files[${i}] must not be empty.`);\n }\n if (value.length > 4096) {\n throw new Error(`decision[${index}].linked_files[${i}] exceeds 4096 chars.`);\n }\n });\n }\n return out;\n}\n\nfunction requireNonEmptyString(value: unknown, index: number, field: string): string {\n if (typeof value !== \"string\" || isBlank(value)) {\n throw new Error(`decision[${index}].${field} must be a non-empty string.`);\n }\n return value;\n}\n\n// Treat whitespace-only as empty: a blank title / rationale persists into\n// decisions.md and orientation as an unreadable entry. `basou note` already\n// guards this way; `decision record` / `decision capture` now match.\nfunction isBlank(value: string): boolean {\n return value.trim().length === 0;\n}\n\nfunction validateStringArray(\n value: unknown,\n index: number,\n field: string,\n checkEach: (value: string, i: number) => void,\n): string[] {\n if (!Array.isArray(value)) {\n throw new Error(`decision[${index}].${field} must be an array of strings.`);\n }\n return value.map((entry, i) => {\n if (typeof entry !== \"string\") {\n throw new Error(`decision[${index}].${field}[${i}] must be a string.`);\n }\n checkEach(entry, i);\n return entry;\n });\n}\n\nfunction toRichFields(decision: CaptureDecisionInput): RichDecisionFields {\n const out: RichDecisionFields = {};\n if (decision.rationale !== undefined) out.rationale = decision.rationale;\n if (decision.rejected_reason !== undefined) out.rejected_reason = decision.rejected_reason;\n if (decision.alternatives !== undefined) out.alternatives = [...decision.alternatives];\n if (decision.linked_events !== undefined) out.linked_events = [...decision.linked_events];\n if (decision.linked_files !== undefined) out.linked_files = [...decision.linked_files];\n return out;\n}\n\nfunction buildCaptureLabel(count: number): string {\n return `Ad-hoc capture: ${count} decision${count === 1 ? \"\" : \"s\"}`;\n}\n\ntype CaptureResultItem = { decisionId: string; eventId: string; input: CaptureDecisionInput };\n\nfunction captureItemToPayload(item: CaptureResultItem): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n decision_id: item.decisionId,\n event_id: item.eventId,\n title: item.input.title,\n };\n if (item.input.rationale !== undefined) payload.rationale = item.input.rationale;\n if (item.input.alternatives !== undefined) payload.alternatives = item.input.alternatives;\n if (item.input.rejected_reason !== undefined)\n payload.rejected_reason = item.input.rejected_reason;\n if (item.input.linked_events !== undefined) payload.linked_events = item.input.linked_events;\n if (item.input.linked_files !== undefined) payload.linked_files = item.input.linked_files;\n return payload;\n}\n\nfunction printCapturePreview(\n options: DecisionCaptureOptions,\n decisions: CaptureDecisionInput[],\n): void {\n if (options.json === true) {\n console.log(JSON.stringify({ dry_run: true, count: decisions.length, decisions }));\n return;\n }\n console.log(\n `Would capture ${decisions.length} decision${decisions.length === 1 ? \"\" : \"s\"} (dry run; nothing written):`,\n );\n for (const decision of decisions) {\n console.log(`- ${decision.title}`);\n }\n}\n\nfunction printCaptureResult(\n options: DecisionCaptureOptions,\n result: { sessionId: string; items: CaptureResultItem[] },\n): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n mode: \"ad-hoc\",\n session_id: result.sessionId,\n session_status: \"completed\",\n count: result.items.length,\n decisions: result.items.map(captureItemToPayload),\n }),\n );\n return;\n }\n console.log(\n `Captured ${result.items.length} decision${result.items.length === 1 ? \"\" : \"s\"} in ad-hoc session ${sid}:`,\n );\n for (const item of result.items) {\n console.log(`- ${item.decisionId}: ${item.input.title}`);\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 (isBlank(raw)) {\n throw new InvalidArgumentError(\"Title must not be empty\");\n }\n return raw;\n}\n\nfunction parseRationale(raw: string): string {\n if (isBlank(raw)) {\n throw new InvalidArgumentError(\"Rationale must not be empty\");\n }\n return raw;\n}\n\nfunction parseRejectedReason(raw: string): string {\n if (isBlank(raw)) {\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 (isBlank(value)) {\n throw new InvalidArgumentError(\"Alternative must not be empty\");\n }\n return prev.concat(value);\n}\n\n// Validate against the canonical event-id shape (`evt_<26-char Crockford ULID>`),\n// exactly what `EventIdSchema` enforces at write time. A looser check (e.g. a\n// bare `evt_[A-Z0-9]+` regex) would accept ids like `evt_X` here only for the\n// chained-append `EventSchema.parse` to reject them later with a generic\n// \"Invalid Basou event payload\" error -- and would let `decision capture\n// --dry-run` falsely report success. Shared by `decision record` and\n// `decision capture` so both reject the same set up front.\nfunction isValidEventId(value: string): boolean {\n return isValidPrefixedId(value) && value.startsWith(\"evt_\");\n}\n\nfunction collectLinkedEvent(value: string, prev: string[]): string[] {\n if (!isValidEventId(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 (isBlank(value)) {\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 { realpath, stat } from \"node:fs/promises\";\nimport { basename, resolve } from \"node:path\";\nimport { basouPaths, readManifest, resolveBasouRepositoryRoot } from \"@basou/core\";\nimport { DEFAULT_PORTFOLIO_CONFIG_PATH, loadPortfolioConfig } from \"./portfolio-config.js\";\n\n/** A planning master that aggregates the queried repo via its `source_roots`. */\nexport type MemberMaster = { root: string; label: string };\n\n/** Override the portfolio registry path (tests). */\nexport type ResolveRootOptions = {\n /** Defaults to {@link DEFAULT_PORTFOLIO_CONFIG_PATH}. */\n portfolioConfigPath?: string;\n};\n\n/**\n * Resolve the repository root for a CLI command with two fallbacks, shared by\n * `orient` / `refresh` / `note` / `decision capture` / `project *` /\n * `review-gaps` / `session` so they behave identically:\n *\n * 1. A git-untracked workspace *view* dir that symlinks its planning repo\n * redirects to that repo (handled inside {@link resolveBasouRepositoryRoot},\n * with a note on stderr).\n * 2. A portfolio *member* repo — a git repo that holds no `.basou/` store of its\n * own because its trail aggregates into a SEPARATE planning master via that\n * master's `import.source_roots` — redirects to the master. The git resolver\n * returns a member as its own toplevel (the view fallback only fires for\n * non-git dirs), so without this it would die downstream with \"Workspace not\n * initialized\". When the resolved repo has no store, the master's declaration\n * is honored in reverse via the portfolio registry (see\n * {@link resolveMemberToMaster}).\n *\n * A genuine non-git dir reports a command-specific \"run git init\" message.\n */\nexport async function resolveBasouRootForCommand(\n cwd: string,\n commandName: string,\n opts: ResolveRootOptions = {},\n): Promise<string> {\n let root: string;\n try {\n root = 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 // The view fallback already returns a master that has a `.basou/` store, so the\n // reverse-lookup only runs for a git repo that resolved to itself with no store\n // — the exact portfolio-member case (and the genuinely-uninitialized case,\n // where no master claims it and the original \"Workspace not initialized\"\n // message is preserved). Normal repos pay nothing: the store probe short-circuits.\n if (!(await hasBasouStore(root))) {\n const master = await resolveMemberToMaster(\n root,\n opts.portfolioConfigPath ?? DEFAULT_PORTFOLIO_CONFIG_PATH,\n );\n if (master !== undefined) {\n console.error(\n `Resolved portfolio member to ${master.root} (via portfolio: ${master.label}).`,\n );\n return master.root;\n }\n }\n return root;\n}\n\n/** Whether `root` owns a `.basou/` store directory. */\nasync function hasBasouStore(root: string): Promise<boolean> {\n try {\n return (await stat(basouPaths(root).root)).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Reverse the `import.source_roots` declaration: find the planning master that\n * aggregates `repoRoot`. Reads the portfolio registry (`~/.basou/portfolio.yaml`),\n * and for each registered workspace resolves its `source_roots` to absolute,\n * realpath-canonicalized paths and checks whether any equals `repoRoot`'s\n * realpath. Returns the single claiming master, throws on ambiguity (>=2 DISTINCT\n * masters claim it), and returns `undefined` when nothing claims it or the\n * registry is absent (so the caller falls back to the unchanged behavior).\n *\n * Matching is realpath-based on both sides (the master root and each resolved\n * source root) so a symlinked layout, a `~`-relative registry entry, or platform\n * path aliases all collapse to one identity. Claimants are de-duped by that same\n * canonical root, so one master registered twice under different spellings (e.g.\n * a real path and a symlink alias — `loadPortfolioConfig` only de-dupes them\n * LEXICALLY) collapses to a single claimant rather than a false ambiguity; this\n * mirrors {@link resolveBasouRepositoryRoot}'s view fallback, which de-dupes\n * linked repos by resolved root. A master never claims itself (its own `.` source\n * root resolves to its root, which can't equal a storeless member).\n *\n * A present-but-broken registry, or a present-but-unreadable master manifest, is\n * surfaced on stderr (best-effort) rather than silently dropped: a genuinely\n * absent file is the expected case for any storeless repo, but a malformed config\n * is a fixable operator error that would otherwise hide behind the downstream\n * \"Workspace not initialized\" message (whose advice — run `basou init` — would\n * wrongly create a competing store inside the member). The SessionStart hook\n * discards stderr, so these notes only reach a manual invocation.\n */\nexport async function resolveMemberToMaster(\n repoRoot: string,\n configPath: string,\n): Promise<MemberMaster | undefined> {\n let workspaces: Awaited<ReturnType<typeof loadPortfolioConfig>>;\n try {\n workspaces = await loadPortfolioConfig(configPath);\n } catch (error: unknown) {\n // A genuinely-absent registry is the common case for any storeless repo that\n // is not a portfolio member: stay silent and fall through. A present-but-\n // malformed registry is a fixable operator error worth surfacing.\n if (!(error instanceof Error) || !error.message.startsWith(\"No portfolio config at\")) {\n const detail = error instanceof Error ? error.message : String(error);\n console.error(`Ignoring ~/.basou/portfolio.yaml: ${detail}`);\n }\n return undefined;\n }\n\n const memberReal = await realpathOrNull(repoRoot);\n if (memberReal === null) return undefined;\n\n // De-dupe by canonical master root: the same master reached via two registry\n // spellings (which survive loadPortfolioConfig's lexical de-dup) must count\n // once, or it would self-trigger a false ambiguity. First spelling's label wins.\n const claimants = new Map<string, MemberMaster>();\n const seenMaster = new Set<string>();\n for (const ws of workspaces) {\n const masterReal = await realpathOrNull(ws.path);\n if (masterReal === null) continue;\n if (masterReal === memberReal) continue; // a master never claims itself\n if (seenMaster.has(masterReal)) continue; // same master, another spelling — process once\n seenMaster.add(masterReal);\n let manifest: Awaited<ReturnType<typeof readManifest>>;\n try {\n manifest = await readManifest(basouPaths(masterReal));\n } catch (error: unknown) {\n // A missing manifest = a stale/uninitialized registry entry (master moved\n // or never initialized): expected, skip quietly. A present-but-unreadable\n // manifest (corrupt YAML / schema-invalid) is a real fault in an owned\n // workspace; surface it so a claiming master is not silently lost.\n if (error instanceof Error && error.message !== \"YAML file not found\") {\n console.error(\n `Skipping portfolio workspace '${ws.label ?? basename(masterReal)}': could not read its manifest (${error.message}).`,\n );\n }\n continue;\n }\n // Absent source_roots means the master aggregates only itself (\".\") — it can\n // never claim a separate member, so the default is harmless and correct.\n const sourceRoots = manifest.import?.source_roots ?? [\".\"];\n for (const sr of sourceRoots) {\n const real = await realpathOrNull(resolve(masterReal, sr));\n if (real !== null && real === memberReal) {\n claimants.set(masterReal, { root: masterReal, label: ws.label ?? basename(masterReal) });\n break;\n }\n }\n }\n\n const matched = [...claimants.values()];\n if (matched.length === 1) return matched[0] as MemberMaster;\n if (matched.length > 1) {\n const names = matched.map((c) => c.label).join(\", \");\n throw new Error(\n `This repository is declared as a source root by ${matched.length} portfolio workspaces (${names}). Disambiguate in ~/.basou/portfolio.yaml so only one aggregates it.`,\n );\n }\n return undefined;\n}\n\nasync function realpathOrNull(p: string): Promise<string | null> {\n try {\n return await realpath(p);\n } catch {\n return null;\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 {\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, dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport {\n AGENT_INFRA_DIRS,\n assertBasouRootSafe,\n type BasouPaths,\n basouPaths,\n CLAUDE_IMPORT_SOURCE,\n type ClaudeTranscriptRecord,\n CODEX_IMPORT_SOURCE,\n type CodexRolloutRecord,\n classifyFilesBySourceRoot,\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 // Claude Code's per-project directory name is lossy (every non-alphanumeric\n // char -> \"-\"), so distinct project paths can collide into one directory.\n // Attribute each transcript by its OWN recorded cwd and skip any that does not\n // belong to a requested project — mirroring the Codex adapter's cwd guard —\n // so a colliding sibling project's transcripts are not imported under this one.\n // (Equality matches the Codex adapter: the recorded cwd must equal a resolved\n // source root verbatim.)\n const projectSet = new Set(projectPaths);\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 const cwd = firstTranscriptCwd(records);\n if (cwd === undefined || !projectSet.has(cwd)) return null;\n return claudeTranscriptToImportPayload(records, {\n workspaceId: manifest.workspace.id,\n externalId,\n sourceSizeBytes: sizeBytes,\n });\n },\n };\n });\n\n await importDerivedSessions(\n paths,\n manifest,\n options,\n CLAUDE_IMPORT_SOURCE,\n candidates,\n projectPaths,\n hasDeclaredBoundary(options, manifest),\n );\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(\n paths,\n manifest,\n options,\n CODEX_IMPORT_SOURCE,\n candidates,\n projectPaths,\n hasDeclaredBoundary(options, manifest),\n );\n}\n\n/**\n * Whether the operator declared a project boundary worth checking edits\n * against: explicit `--project` flags, or a manifest `import.source_roots`\n * list. Neither ⇒ a solo project, where every edit under the repo root is\n * in-bounds and the cross-project warning would be noise.\n */\nfunction hasDeclaredBoundary(options: ImportOptions, manifest: Manifest): boolean {\n return (options.project?.length ?? 0) > 0 || (manifest.import?.source_roots?.length ?? 0) > 0;\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 projectPaths: ReadonlyArray<string>,\n boundaryDeclared: boolean,\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 // Cross-project boundary check: a session attributed to this project (by its\n // cwd) can still have edited files OUTSIDE the declared source roots. Flag\n // those so a resuming agent does not mistake another repo's work for this\n // project's. Gated to a DECLARED boundary — explicit `--project` flags or a\n // manifest `import.source_roots` list; a solo project (neither) has no\n // boundary to cross. `projectPaths` are already absolute, so they double as\n // the resolved source roots.\n const crossProjectCheck = boundaryDeclared;\n const crossProject: { externalId: string; outOfRoot: string[] }[] = [];\n const noteCrossProject = async (\n externalId: string,\n payload: SessionImportPayload,\n ): Promise<void> => {\n if (!crossProjectCheck) return;\n try {\n const scope = await classifyFilesBySourceRoot({\n files: payload.session.related_files ?? [],\n workingDirectory: payload.session.working_directory,\n sourceRoots: projectPaths,\n masterRoot: dirname(paths.root),\n extraInRoot: AGENT_INFRA_DIRS,\n });\n if (scope.outOfRoot.length > 0) crossProject.push({ externalId, outOfRoot: scope.outOfRoot });\n } catch {\n // Advisory only; a classification failure must never abort the import.\n }\n };\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 await noteCrossProject(externalId, payload);\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 await noteCrossProject(externalId, payload);\n }\n\n if (sanitizedPaths > 0) {\n console.error(`Imported sessions: ${sanitizedPaths} path(s) sanitized`);\n }\n\n if (crossProject.length > 0) {\n const PATH_SAMPLE = 5;\n for (const { externalId, outOfRoot } of crossProject) {\n const sample = outOfRoot.slice(0, PATH_SAMPLE).join(\", \");\n const more =\n outOfRoot.length > PATH_SAMPLE ? ` (... +${outOfRoot.length - PATH_SAMPLE} more)` : \"\";\n console.error(\n `basou: session ${externalId} edited ${outOfRoot.length} file(s) outside this project's source_roots: ${sample}${more} — they may belong to another project.`,\n );\n }\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 every NON-alphanumeric character with `-`, not\n * just the path separator, so `/Users/x/projects/foo_bar` becomes\n * `-Users-x-projects-foo-bar` (note `_` -> `-`, `.` -> `-`, etc.). Encoding\n * only `/` missed any project whose path contained `_`/`.`/space — its\n * transcripts were under a `-`-encoded directory while we looked for an\n * underscore-preserving one, so the whole project was silently skipped as\n * \"no source logs\". Matching the full rule keeps those projects discoverable.\n */\nfunction encodeProjectDir(projectPath: string): string {\n return projectPath.replace(/[^a-zA-Z0-9]/g, \"-\");\n}\n\n/**\n * The cwd a Claude transcript was recorded in — the first record that carries\n * one. Used to attribute a transcript to the project it belongs to when a lossy\n * directory-name collision colocates more than one project's transcripts.\n */\nfunction firstTranscriptCwd(records: ReadonlyArray<ClaudeTranscriptRecord>): string | undefined {\n for (const record of records) {\n const cwd = record.cwd;\n if (typeof cwd === \"string\" && cwd.length > 0) return cwd;\n }\n return undefined;\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 acquireLock,\n appendEventToExistingSession,\n assertBasouRootSafe,\n basouPaths,\n createAdHocSessionWithEvent,\n type Event,\n findErrorCode,\n type PrefixedId,\n readManifest,\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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\n\n// The note body becomes an ad-hoc session label; truncate long bodies for the\n// label only (the full body is preserved in the note_added event). Mirrors the\n// decision-title cap so labels stay single-column in session list / handoff.\nconst LABEL_BODY_MAX = 80;\nconst LABEL_TRUNCATE_HEAD = LABEL_BODY_MAX - 3;\n\nexport type NoteOptions = {\n session?: string;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type NoteContext = {\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 note` onto `program`. A one-shot, free-text note that orientation\n * surfaces as the recorded next step (\"次の起点\") — the in-model way to leave a\n * resume hint that survives into the next session. By default it creates an\n * ad-hoc session to hold the `note_added` event (imported sessions are not\n * attachable), mirroring `basou decision record`; `--session` attaches to an\n * existing attachable session instead.\n */\nexport function registerNoteCommand(program: Command): void {\n program\n .command(\"note\")\n .description(\"Record a free-text note (orientation surfaces the latest as the next step)\")\n .argument(\"<body>\", \"Note text\", parseBody)\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 (body: string, options: NoteOptions) => {\n await runNote(body, options);\n });\n}\n\n/**\n * Programmatic entry for `basou note`. Owns process exit state. Tests targeting\n * the success path or the thrown error should prefer {@link doRunNote}.\n */\nexport async function runNote(\n body: string,\n options: NoteOptions,\n ctx: NoteContext = {},\n): Promise<void> {\n try {\n await doRunNote(body, options, ctx);\n } catch (error: unknown) {\n // The ad-hoc path writes the note_added event before finalizing\n // session.yaml; on a finalize failure the classifier surfaces \"do not\n // rerun\" so the operator does not append a duplicate note (mirrors\n // `basou decision record`).\n renderCliError(error, {\n verbose: isVerbose(options),\n classifiers: [failedToFinalizeClassifier],\n });\n process.exitCode = 1;\n }\n}\n\nexport async function doRunNote(\n body: string,\n options: NoteOptions,\n ctx: NoteContext,\n): Promise<void> {\n // Defense in depth: the commander parser (parseBody) rejects an empty body,\n // but doRunNote is also a public programmatic entry, so guard here too\n // (mirrors `basou session note`). Whitespace-only is treated as empty.\n if (body.trim().length === 0) {\n throw new Error(\"Note body must not be empty\");\n }\n\n const cwd = ctx.cwd ?? process.cwd();\n // View-aware resolution so `basou note` works from a workspace-view dir\n // (redirects to the planning repo), matching orient / refresh / session.\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"note\");\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\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 events.jsonl append against a concurrent\n // writer (decision record / another note / an attach-flavoured task\n // command). appendEventToExistingSession holds no lock; the caller owns the\n // 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) => buildNoteEvent({ eventId, sessionId: sesId, occurredAt, body }),\n });\n } finally {\n await sessionLock.release();\n }\n printNoteResult(options, {\n mode: \"attached\",\n sessionId,\n eventId: result.eventId,\n sessionStatus: result.sessionStatus,\n body,\n });\n return;\n }\n\n const manifest = await readManifest(paths);\n const adHoc = await createAdHocSessionWithEvent({\n paths,\n manifest,\n label: buildAdHocLabel(body),\n occurredAt,\n sessionSource: \"human\",\n workingDirectory: repositoryRoot,\n invocation: {\n command: \"basou note\",\n args: [body],\n },\n targetEventBuilders: [\n (sessionId, eventId) => buildNoteEvent({ eventId, sessionId, occurredAt, body }),\n ],\n });\n printNoteResult(options, {\n mode: \"ad-hoc\",\n sessionId: adHoc.sessionId,\n eventId: adHoc.targetEventIds[0] as string,\n sessionStatus: \"completed\",\n body,\n });\n}\n\nfunction buildNoteEvent(input: {\n eventId: PrefixedId<\"evt\">;\n sessionId: PrefixedId<\"ses\">;\n occurredAt: string;\n body: string;\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: \"note_added\",\n body: input.body,\n // `basou note` is the resume-hint command; mark it so orientation surfaces\n // it as the next step and a plain `basou session note` annotation does not.\n kind: \"next_step\",\n };\n}\n\nfunction buildAdHocLabel(body: string): string {\n // Collapse whitespace so a multi-line body still produces a single-line label.\n const oneLine = body.replace(/\\s+/g, \" \").trim();\n const truncated =\n oneLine.length > LABEL_BODY_MAX ? `${oneLine.slice(0, LABEL_TRUNCATE_HEAD)}...` : oneLine;\n return `Ad-hoc note: ${truncated}`;\n}\n\nfunction parseBody(raw: string): string {\n if (raw.trim().length === 0) {\n throw new InvalidArgumentError(\"Note body must not be empty\");\n }\n return raw;\n}\n\ntype NotePrintInput = {\n mode: \"ad-hoc\" | \"attached\";\n sessionId: string;\n eventId: string;\n sessionStatus: SessionStatus;\n body: string;\n};\n\nfunction printNoteResult(options: NoteOptions, result: NotePrintInput): void {\n const sid = shortSessionId(result.sessionId);\n if (options.json === true) {\n console.log(\n JSON.stringify({\n event_id: result.eventId,\n session_id: result.sessionId,\n session_status: result.sessionStatus,\n mode: result.mode,\n body: result.body,\n }),\n );\n return;\n }\n if (result.mode === \"ad-hoc\") {\n console.log(`Recorded note ${result.eventId} in ad-hoc session ${sid}`);\n } else {\n console.log(`Recorded note ${result.eventId} in session ${sid} (${result.sessionStatus})`);\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 type FederatedRoot,\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 { loadHostsConfig } from \"../lib/hosts-config.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 /** Override path to the hosts registry (`~/.basou/hosts.yaml`). Injectable for tests. */\n hostsConfigPath?: string;\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 // Federation (zero-network): merge other hosts' trails listed in\n // ~/.basou/hosts.yaml, each a LOCAL path the operator's own tooling (an SSHFS\n // mount / rsync over their existing SSH) keeps in sync. Best-effort and\n // non-fatal: an absent registry is silent (local-only); a malformed one warns\n // and falls back to local-only so `orient` — the default command — never\n // hard-fails on it.\n let federatedRoots: FederatedRoot[] = [];\n try {\n const hosts = await loadHostsConfig(ctx.hostsConfigPath);\n if (hosts !== null) {\n federatedRoots = hosts.map((h) => ({ paths: basouPaths(h.path), host: h.label }));\n }\n } catch (error: unknown) {\n console.error(\n `basou: ignoring ~/.basou/hosts.yaml (${error instanceof Error ? error.message : String(error)}); showing local sessions only.`,\n );\n }\n\n const result = await renderOrientation({\n paths,\n nowIso,\n staleness,\n verbose: options.verbose === true,\n federatedRoots,\n onWarning: (w, sid) => printReplayWarning(w, sid),\n onSessionSkip: (sid, reason) => printSessionSkip(sid, reason),\n onTaskSkip: (taskId, reason) => printTaskSkip(taskId, reason),\n onHostUnavailable: (host, error) =>\n console.error(\n `basou: host '${host}' mirror unreadable (${error instanceof Error ? error.message : String(error)}); skipping it.`,\n ),\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 { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { readYamlFile } from \"@basou/core\";\n\n/**\n * Local registry for federated, multi-host orientation (`basou orient`). Each\n * entry points at ANOTHER host's `.basou` store as it is reachable on THIS\n * machine as a LOCAL path — an SSHFS mount, an rsync / Syncthing mirror, etc.\n * basou performs NO network I/O: the operator's own tooling (over the SSH they\n * already use) keeps these paths in sync. Like `portfolio.yaml`, this is local\n * machine config, NOT provenance/trail data — it is never committed into a\n * monitored repo, so absolute paths are required.\n *\n * Shape:\n * version: 1 # optional, reserved for future migrations\n * hosts:\n * - label: laptop # required, non-empty, distinct (the host tag)\n * path: ~/mirrors/laptop/myrepo # required, absolute (~ ok) — the repo\n * # root (the parent of its `.basou`)\n */\nexport type HostMirror = { label: string; path: string };\n\n/** Canonical location of the hosts registry. */\nexport const DEFAULT_HOSTS_CONFIG_PATH = join(homedir(), \".basou\", \"hosts.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 `~/.basou/hosts.yaml` (or an injected path for tests).\n *\n * Returns `null` when the file is ABSENT: `orient` is the default command, so a\n * missing registry must be silent (\"no federation\") — unlike the explicit\n * `--portfolio`, whose loader throws. A present-but-malformed file THROWS a\n * pathless, user-facing message so the caller can warn and fall back to\n * local-only. Each `path` is `~`-expanded, required absolute, and de-duped by\n * resolved path (first occurrence wins, keeping its label and order). Labels\n * must be distinct (orientation collapses hosts by label). An empty `hosts:`\n * list returns `[]` (benign no-op, not an error).\n */\nexport async function loadHostsConfig(\n configPath: string = DEFAULT_HOSTS_CONFIG_PATH,\n): Promise<HostMirror[] | null> {\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 return null;\n }\n if (error instanceof Error && error.message === \"Failed to parse YAML content\") {\n throw new Error(\"~/.basou/hosts.yaml is not valid YAML.\");\n }\n throw error;\n }\n\n if (!isRecord(raw) || !Array.isArray(raw.hosts)) {\n throw new Error(\"~/.basou/hosts.yaml must contain a 'hosts:' list.\");\n }\n\n const seenPaths = new Set<string>();\n const seenLabels = new Set<string>();\n const result: HostMirror[] = [];\n for (const entry of raw.hosts) {\n if (!isRecord(entry) || typeof entry.label !== \"string\" || entry.label.trim().length === 0) {\n throw new Error(\"Each host needs a non-empty string 'label'.\");\n }\n const label = entry.label.trim();\n if (typeof entry.path !== \"string\" || entry.path.trim().length === 0) {\n throw new Error(\"Each host needs a non-empty string 'path'.\");\n }\n const expanded = expandTilde(entry.path.trim());\n if (!isAbsolute(expanded)) {\n throw new Error(\"Host paths must be absolute (or start with '~').\");\n }\n const abs = resolve(expanded);\n if (seenPaths.has(abs)) continue;\n // Distinct mirrors must have distinct labels: orientation collapses hosts by\n // label (a Set), so a duplicate would make two stores indistinguishable.\n if (seenLabels.has(label)) {\n throw new Error(`Duplicate host label '${label}'; each host needs a distinct label.`);\n }\n seenPaths.add(abs);\n seenLabels.add(label);\n result.push({ label, path: abs });\n }\n\n return result;\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 {\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n readlinkSync,\n realpathSync,\n statSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport {\n type AdoptCandidate,\n type ArchivePlan,\n basouPaths,\n type ExistingViewLink,\n GENERATED_END,\n GENERATED_START,\n type GitignorePlanSummary,\n type InstructionFileFact,\n type InstructionSymlinkFact,\n type InstructionSymlinkState,\n isGitNotFound,\n type Manifest,\n type PresetPlanSummary,\n parseMarkers,\n pathBasename,\n planArchive,\n planGitignore,\n planRename,\n planRosterAdoption,\n planWorkspaceView,\n type RenamePlan,\n type RepoEntry,\n type RepoGitignoreFacts,\n type RepoGitignorePlan,\n type RepoPresetFacts,\n type RepoPresetPlan,\n type RepoSymlinkFacts,\n type RepoSymlinkPlan,\n type RepoWiringFacts,\n type RosterAdoptionPlan,\n type RosterDriftSummary,\n readManifest,\n readMarkdownFile,\n reconcileSourceRoots,\n renderWithMarkers,\n type SourceRootsReconcile,\n type SymlinkPlanSummary,\n safeSimpleGit,\n summarizePresetPlan,\n summarizeRosterDrift,\n summarizeSymlinkPlan,\n summarizeWiring,\n unknownManifestKeys,\n type ViewRepoFact,\n type WiringSummary,\n type WorkspaceViewPlan,\n writeManifest,\n writeMarkdownFile,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\n\nexport type ProjectCheckOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectCheckContext = ImportContext;\n\nexport type ProjectSyncOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectSyncContext = ImportContext & { now?: () => Date };\n\n/** Flat result of {@link doRunProjectSync}: the reconciliation plus what was done. */\nexport type ProjectSyncResult = SourceRootsReconcile & {\n /** Whether a repo roster (`repos`) was declared at all (else there is nothing to sync from). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` was set AND there was drift to reconcile). */\n applied: boolean;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectAdoptOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectAdoptContext = ImportContext & { now?: () => Date };\n\n/** Flat result of {@link doRunProjectAdopt}: the proposed roster plus what was done. */\nexport type ProjectAdoptResult = RosterAdoptionPlan & {\n /** Whether a `repos` roster was ALREADY declared (adopt is a one-time bootstrap; `--apply` refuses). */\n alreadyDeclared: boolean;\n /** Whether the manifest was written (i.e. `--apply` set, no existing roster, AND at least one repo found). */\n applied: boolean;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectWiringOptions = {\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectWiringContext = ImportContext;\n\n/** Result of {@link doRunProjectWiring}: the wiring summary plus whether a roster was declared. */\nexport type ProjectWiringResult = WiringSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to inspect — run adopt first). */\n hasRoster: boolean;\n};\n\nexport type ProjectGitignoreOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectGitignoreContext = ImportContext;\n\n/** Result of {@link doRunProjectGitignore}: the plan plus whether a roster exists and whether it was applied. */\nexport type ProjectGitignoreResult = GitignorePlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether `.gitignore` files were written (i.e. `--apply` was set AND there was something to add). */\n applied: boolean;\n};\n\nexport type ProjectSymlinksOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectSymlinksContext = ImportContext;\n\n/** Result of {@link doRunProjectSymlinks}: the plan plus whether a roster exists and what `--apply` did. */\nexport type ProjectSymlinksResult = SymlinkPlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether any symlinks were actually created (true only when `--apply` created at least one link). */\n applied: boolean;\n /** Per-file failures encountered during `--apply` (collected, not thrown — kept transparent). */\n failures: { repo: string; file: string; message: string }[];\n};\n\nexport type ProjectWorkspaceOptions = {\n apply?: boolean;\n prune?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectWorkspaceContext = ImportContext;\n\n/** Result of {@link doRunProjectWorkspace}: the view plan plus whether a view is declared and what `--apply` / `--prune` did. */\nexport type ProjectWorkspaceResult = WorkspaceViewPlan & {\n /** Whether `workspace.view` is declared (else there is no view to generate — solo project / not configured). */\n hasView: boolean;\n /** Whether any view symlinks were actually created (true only when `--apply` created at least one). */\n applied: boolean;\n /** Whether any stray view symlinks were actually removed (true only when `--prune` removed at least one). */\n pruned: boolean;\n /**\n * Whether `--prune` was requested with strays to remove but withheld because one\n * or more declared repos are unreachable (an unreachable repo's link can be\n * indistinguishable from a stray, so pruning is refused until the roster resolves).\n */\n pruneWithheld: boolean;\n /** Per-link create failures encountered during `--apply` (collected, not thrown — pathless reason). */\n failures: { name: string; message: string }[];\n /** Per-link prune failures encountered during `--prune` (collected, not thrown — pathless reason). */\n pruneFailures: { name: string; message: string }[];\n};\n\nexport type ProjectPresetOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ProjectPresetContext = ImportContext;\n\n/** Result of {@link doRunProjectPreset}: the plan plus whether a roster exists and what `--apply` did. */\nexport type ProjectPresetResult = PresetPlanSummary & {\n /** Whether a `repos` roster was declared (else there is nothing to generate — run adopt first). */\n hasRoster: boolean;\n /** Whether any canonical was actually written (true only when `--apply` wrote at least one). */\n applied: boolean;\n /** Per-repo write failures encountered during `--apply` (collected, not thrown — pathless reason). */\n failures: { repo: string; message: string }[];\n};\n\nexport type ProjectArchiveOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectArchiveContext = ImportContext & { now?: () => Date };\n\n/** Repo-side wiring still present for the archived repo — a manual-teardown checklist (report-only). */\nexport type ArchiveTeardown = {\n /** False when the repo could not be resolved on disk (e.g. already deleted) — wiring not inspected. */\n inspected: boolean;\n /** The workspace view still has a `<basename>` entry for this repo. */\n viewLink: boolean;\n /** Instruction files still present in the repo (AGENTS.md / CLAUDE.md / copilot). */\n instructionFiles: string[];\n /** Instruction patterns still listed in the repo's `.gitignore`. */\n gitignorePatterns: string[];\n /** The anchor's canonical (`agents/<repo>/AGENTS.md`) still exists. */\n canonical: boolean;\n};\n\n/** Result of {@link doRunProjectArchive}: the plan plus whether a roster exists, the teardown checklist, and what `--apply` did. */\nexport type ProjectArchiveResult = ArchivePlan & {\n /** Whether a `repos` roster was declared (else there is nothing to archive — run adopt first). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` set, target found, and not the anchor). */\n applied: boolean;\n /** Repo-side wiring still present (report-only; `--apply` never touches it). */\n teardown: ArchiveTeardown;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\nexport type ProjectRenameOptions = {\n apply?: boolean;\n json?: boolean;\n verbose?: boolean;\n};\n\n/** `now` is injectable so the `updated_at` bump on `--apply` is deterministic in tests. */\nexport type ProjectRenameContext = ImportContext & { now?: () => Date };\n\n/** Repo-side wiring at the OLD basename that a basename-changing rename leaves stale — a manual checklist (report-only). */\nexport type RenameWiring = {\n /** The anchor canonical dir `agents/<oldBasename>` still exists (rename to the new basename). */\n canonicalDirOld: boolean;\n /** The workspace view still has a `<oldBasename>` entry (rename to the new basename). */\n viewLinkOld: boolean;\n};\n\n/** Result of {@link doRunProjectRename}: the plan plus whether a roster exists, the repo-side checklist, and what `--apply` did. */\nexport type ProjectRenameResult = RenamePlan & {\n /** Whether a `repos` roster was declared (else there is nothing to rename — run adopt first). */\n hasRoster: boolean;\n /** Whether the manifest was written (i.e. `--apply` set and the rename was actionable). */\n applied: boolean;\n /** Repo-side wiring still at the old basename (report-only; `--apply` never touches it). */\n wiring: RenameWiring;\n /** Unknown top-level manifest fields the loose schema preserved (surfaced, never dropped). */\n preservedUnknownFields: string[];\n};\n\n/**\n * Agent instruction files inspected per repo. GEMINI.md is intentionally absent\n * (the Gemini CLI was discontinued for personal use). Each should be a gitignored\n * symlink to a canonical source, never tracked in a public repo's history.\n */\nconst INSTRUCTION_FILES = [\"AGENTS.md\", \"CLAUDE.md\", \".github/copilot-instructions.md\"] as const;\n\n/**\n * The canonical instruction file name. It lives in the anchor at\n * `agents/<repo>/AGENTS.md` and is the hub each repo's own AGENTS.md symlink\n * resolves to; CLAUDE.md and Copilot are spokes pointing back at it.\n */\nconst CANONICAL_FILE = \"AGENTS.md\";\n\n/**\n * Wire `basou project` (a read-only inspector for the project's declared repo\n * roster) and its `check` subcommand onto `program`. The roster is the single\n * source of truth for which repos make up a project; `check` compares it\n * against the capture config (`source_roots`) and surfaces drift. It writes\n * nothing and enforces nothing.\n */\nexport function registerProjectCommand(program: Command): void {\n const project = program\n .command(\"project\")\n .description(\"Inspect a project's declared repo roster (read-only)\");\n\n project\n .command(\"check\")\n .description(\n \"Compare the declared repo roster (manifest `repos`) against the capture config (`source_roots`) and surface drift (read-only, advisory)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectCheckOptions) => {\n await runProjectCheck(opts);\n });\n\n project\n .command(\"sync\")\n .description(\n \"Reconcile the capture config (`source_roots`) to cover every declared repo (manifest `repos`). Dry-run by default; pass --apply to write. Additive only — it never removes an existing source root (e.g. the workspace view)\",\n )\n .option(\n \"--apply\",\n \"Write the reconciled source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectSyncOptions) => {\n await runProjectSync(opts);\n });\n\n project\n .command(\"adopt\")\n .description(\n \"Bootstrap a repo roster (manifest `repos`) from the existing capture config (`source_roots`): classify each by realpath + `.git`, keep the git repos, exclude non-repos (the workspace view, /tmp). Dry-run by default; pass --apply to write (refuses if a roster already exists)\",\n )\n .option(\"--apply\", \"Write the bootstrapped roster to the manifest (default: dry-run preview)\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectAdoptOptions) => {\n await runProjectAdopt(opts);\n });\n\n project\n .command(\"wiring\")\n .description(\n \"Inspect each declared repo's agent instruction-file wiring (AGENTS.md, CLAUDE.md, copilot-instructions.md): present? tracked by git? Surfaces privacy risks (a public repo tracking an instruction file) and gaps (read-only, advisory)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectWiringOptions) => {\n await runProjectWiring(opts);\n });\n\n project\n .command(\"gitignore\")\n .description(\n \"Reconcile each public-facing repo's .gitignore to exclude the agent instruction files (so the gitignored symlinks never enter public history). Dry-run by default; pass --apply to write. Additive only — it never removes a line; private repos and unset-visibility repos are left untouched\",\n )\n .option(\n \"--apply\",\n \"Append the missing patterns to each repo's .gitignore (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectGitignoreOptions) => {\n await runProjectGitignore(opts);\n });\n\n project\n .command(\"symlinks\")\n .description(\n \"Generate each declared repo's agent instruction-file symlinks (AGENTS.md, CLAUDE.md, copilot-instructions.md) pointing at the project anchor's canonical (agents/<repo>/AGENTS.md). Dry-run by default; pass --apply to create. Non-destructive — it only creates missing links and never overwrites an existing file or repoints a link\",\n )\n .option(\"--apply\", \"Create the missing instruction-file symlinks (default: dry-run preview)\")\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectSymlinksOptions) => {\n await runProjectSymlinks(opts);\n });\n\n project\n .command(\"workspace\")\n .description(\n \"Generate the project's workspace view: a directory (manifest `workspace.view`) that aggregates every declared repo via a `<repo-basename>` symlink (the anchor included). Dry-run by default; pass --apply to create missing links. Creation is non-destructive — it never overwrites an existing entry or repoints a link. Stray repo links (a view symlink whose repo is no longer in the roster) are reported always and removed only with --prune; pruning removes ONLY a symlink whose relative target resolves to a git repository (never a real file/dir, the view's own instruction files, a broken link, or a non-repo target), and never the linked repo itself\",\n )\n .option(\"--apply\", \"Create the missing view symlinks (default: dry-run preview)\")\n .option(\n \"--prune\",\n \"Remove stray repo symlinks (links the roster no longer backs); default: dry-run preview. Independent of --apply\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectWorkspaceOptions) => {\n await runProjectWorkspace(opts);\n });\n\n project\n .command(\"preset\")\n .description(\n \"Generate the stable-preset block (source visibility, source language, published surfaces) of each declared repo's canonical instruction file (agents/<repo>/AGENTS.md) from the manifest. Dry-run by default; pass --apply to write. Non-destructive — it only writes the marker-delimited region (creating an absent canonical, updating an out-of-date one) and never touches hand-authored content or a canonical whose markers are missing/malformed\",\n )\n .option(\n \"--apply\",\n \"Write the generated preset block to each canonical (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProjectPresetOptions) => {\n await runProjectPreset(opts);\n });\n\n project\n .command(\"archive\")\n .argument(\"<repo>\", \"The roster repo path to archive (as declared, e.g. ../takuhon)\")\n .description(\n \"Fold a repo out of the project: remove it from the declared roster (manifest `repos`) and prune its capture entry (`source_roots`). Dry-run by default; pass --apply to write. Manifest-only and reversible (the manifest is git-tracked); it never deletes the repo, its captured history, or its on-disk wiring (view symlink / instruction symlinks / .gitignore / canonical) — those are reported as a manual teardown checklist. Archiving the anchor (`.`) is refused\",\n )\n .option(\n \"--apply\",\n \"Write the pruned roster / source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (repo: string, opts: ProjectArchiveOptions) => {\n await runProjectArchive(repo, opts);\n });\n\n project\n .command(\"rename\")\n .argument(\"<old>\", \"The current roster repo path (as declared, e.g. ../takuhon)\")\n .argument(\"<new>\", \"The new roster repo path (e.g. ../takuhon-cli)\")\n .description(\n \"Re-path a repo in the project: update its declared roster path (manifest `repos`) and its capture entry (`source_roots`). Dry-run by default; pass --apply to write. Manifest-only and reversible (the manifest is git-tracked); it does not move the repo on disk or rewire it — when the basename changes, the anchor canonical dir and view symlink that still use the old name are reported as a manual checklist (re-run `basou project symlinks` / `workspace` after). Renaming the anchor (`.`) or onto an existing entry is refused\",\n )\n .option(\n \"--apply\",\n \"Write the re-pathed roster / source_roots to the manifest (default: dry-run preview)\",\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (oldPath: string, newPath: string, opts: ProjectRenameOptions) => {\n await runProjectRename(oldPath, newPath, opts);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectCheck}. */\nexport async function runProjectCheck(\n options: ProjectCheckOptions,\n ctx: ProjectCheckContext = {},\n): Promise<void> {\n try {\n await doRunProjectCheck(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * The capture roots a manifest effectively scans. An absent `import.source_roots`\n * means \"the host repository only\" (import's documented default), so it resolves\n * to `[\".\"]` here — NOT the empty set. Comparing the roster against the empty set\n * would falsely report the host `.` as a capture gap after a solo-repo adoption.\n */\nfunction effectiveSourceRoots(manifest: Manifest): string[] {\n return manifest.import?.source_roots ?? [\".\"];\n}\n\n/**\n * Header advisory lines naming the unknown top-level manifest fields the loose\n * schema preserved (empty array => no lines). Surfaced by the read-modify-write\n * commands so preservation is not silent: basou keeps a field it does not\n * recognize (a newer version's section, a future adapter, a hand-added/typo'd\n * key) rather than dropping it on write, and says so.\n */\nfunction preservedUnknownLines(fields: string[]): string[] {\n if (fields.length === 0) return [];\n return [\n `ℹ️ basou が認識しない manifest のトップレベルフィールドを ${fields.length} 件保持しています(write 時も削除しません): ${fields.join(\", \")}`,\n \"\",\n ];\n}\n\n/** Pure runner: resolves the workspace, reads the manifest, computes the drift, prints it (or JSON). */\nexport async function doRunProjectCheck(\n options: ProjectCheckOptions,\n ctx: ProjectCheckContext,\n): Promise<RosterDriftSummary> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project check\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const summary = summarizeRosterDrift({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n sourceRoots: effectiveSourceRoots(manifest),\n });\n\n if (options.json === true) {\n console.log(JSON.stringify(summary));\n } else {\n console.log(renderProjectCheck(summary));\n }\n return summary;\n}\n\n/**\n * Render the advisory report. Leads with the capture gaps (declared repos not\n * being captured — the actionable drift), then the captured-but-undeclared\n * paths (commonly the workspace view), and states the read-only / no-enforce\n * framing so the verdict is not over-read.\n */\nexport function renderProjectCheck(summary: RosterDriftSummary): string {\n const lines: string[] = [];\n lines.push(\"# プロジェクト構成チェック(宣言 vs 捕捉)\");\n lines.push(\"\");\n\n if (summary.declaredCount === 0) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`source_roots` のみで運用中のため、宣言との照合はできません。\",\n );\n if (summary.extra.length > 0) {\n lines.push(\"\");\n lines.push(`捕捉中の source_roots (${summary.extra.length}):`);\n for (const p of summary.extra) lines.push(`- ${p}`);\n }\n return lines.join(\"\\n\");\n }\n\n if (summary.gaps.length === 0) {\n lines.push(\n `✅ 宣言された ${summary.declaredCount} repo はすべて捕捉対象(source_roots)に含まれています。`,\n );\n } else {\n lines.push(`⚠️ 宣言されているのに捕捉対象に無い repo: ${summary.gaps.length}(取りこぼし)`);\n for (const g of summary.gaps) {\n lines.push(`- ${g.path}${g.visibility ? ` [${g.visibility}]` : \"\"} — source_roots に未登録`);\n }\n }\n lines.push(\"\");\n\n if (summary.extra.length > 0) {\n lines.push(\n `## 宣言外の捕捉対象 (${summary.extra.length}) — workspace view か、宣言漏れの可能性`,\n );\n for (const p of summary.extra) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: read-only の advisory です。宣言(repos)と捕捉設定(source_roots)の差分のみを表示し、enforce はしません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectSync}. */\nexport async function runProjectSync(\n options: ProjectSyncOptions,\n ctx: ProjectSyncContext = {},\n): Promise<void> {\n try {\n await doRunProjectSync(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Reconcile `source_roots` against the declared roster. Resolves the workspace,\n * reads the manifest, computes the additive reconciliation, and — only when\n * `--apply` is set and there is drift to fix — writes the manifest back (the\n * declared repos appended to `source_roots`, `workspace.updated_at` bumped).\n * Without `--apply` it writes nothing and prints the plan.\n */\nexport async function doRunProjectSync(\n options: ProjectSyncOptions,\n ctx: ProjectSyncContext,\n): Promise<ProjectSyncResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project sync\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const hasRoster = manifest.repos !== undefined && manifest.repos.length > 0;\n const reconcile = reconcileSourceRoots({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n });\n\n const applied = options.apply === true && hasRoster && !reconcile.unchanged;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(\n paths,\n {\n ...manifest,\n import: { ...manifest.import, source_roots: reconcile.next },\n workspace: { ...manifest.workspace, updated_at: now().toISOString() },\n },\n { force: true },\n );\n }\n\n const result: ProjectSyncResult = {\n ...reconcile,\n hasRoster,\n applied,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectSync(result));\n }\n return result;\n}\n\n/**\n * Render the sync report. Leads with the actionable outcome: nothing to sync\n * (no roster), already in sync, or the source roots that will be / were added.\n * The dry-run framing makes clear that without `--apply` nothing is written.\n */\nexport function renderProjectSync(result: ProjectSyncResult): string {\n const lines: string[] = [];\n lines.push(\"# source_roots 同期(宣言ロースター → 捕捉設定)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。同期の元になる宣言が無いため、変更はありません。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.unchanged) {\n lines.push(\"✅ source_roots は宣言ロースターをすべて覆っています(同期不要)。\");\n return lines.join(\"\\n\");\n }\n\n if (result.applied) {\n lines.push(`✅ source_roots に ${result.added.length} 件追加しました:`);\n for (const p of result.added) lines.push(`- ${p}`);\n } else {\n lines.push(\n `${result.added.length} 件の repo が source_roots に未登録です。追加予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.added) lines.push(`- ${p}`);\n lines.push(\"\");\n lines.push(\"注: 既存の source_roots は保持し、不足分の追記のみ行います(削除はしません)。\");\n }\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectAdopt}. */\nexport async function runProjectAdopt(\n options: ProjectAdoptOptions,\n ctx: ProjectAdoptContext = {},\n): Promise<void> {\n try {\n await doRunProjectAdopt(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Classify a declared source-root path against disk: a git repo root (`repo`),\n * a resolved-but-non-repo directory such as the workspace view or `/tmp`\n * (`non-repo`), or a path that does not resolve (`unresolved`). Resolves the\n * path relative to the repository root, then realpath (which follows the view's\n * symlink and unifies platform aliases) before probing for `.git`.\n */\nfunction classifySourceRoot(repositoryRoot: string, declaredPath: string): AdoptCandidate {\n const absolute = resolve(repositoryRoot, declaredPath);\n let real: string;\n try {\n real = realpathSync(absolute);\n } catch {\n return { path: declaredPath, kind: \"unresolved\" };\n }\n return { path: declaredPath, kind: existsSync(join(real, \".git\")) ? \"repo\" : \"non-repo\" };\n}\n\n/**\n * Bootstrap a `repos` roster from the existing `source_roots`. Resolves the\n * workspace, reads the manifest, classifies each source root on disk, and plans\n * the roster (git repos kept, non-repos/unresolved excluded). When `--apply` is\n * set, no roster exists yet, and at least one repo was found, it writes the\n * roster (and bumps `workspace.updated_at`). Without `--apply` — or when a\n * roster already exists — it writes nothing and prints the plan.\n *\n * `source_roots` absent mirrors import's default (the host repo `.` only), so a\n * solo repo adopts a `[\".\"]` roster.\n */\nexport async function doRunProjectAdopt(\n options: ProjectAdoptOptions,\n ctx: ProjectAdoptContext,\n): Promise<ProjectAdoptResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project adopt\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const alreadyDeclared = manifest.repos !== undefined && manifest.repos.length > 0;\n const candidates = effectiveSourceRoots(manifest).map((r) =>\n classifySourceRoot(repositoryRoot, r),\n );\n const plan = planRosterAdoption(candidates);\n\n const applied = options.apply === true && !alreadyDeclared && plan.repos.length > 0;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(\n paths,\n {\n ...manifest,\n repos: plan.repos,\n workspace: { ...manifest.workspace, updated_at: now().toISOString() },\n },\n { force: true },\n );\n }\n\n const result: ProjectAdoptResult = {\n ...plan,\n alreadyDeclared,\n applied,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectAdopt(result));\n }\n return result;\n}\n\n/**\n * Render the adoption report. Leads with the actionable outcome: a roster\n * already exists (nothing to bootstrap), nothing found, or the proposed roster\n * (with the excluded paths and why). The dry-run framing makes clear that\n * without `--apply` nothing is written, and reminds the operator to set\n * visibility afterward.\n */\nexport function renderProjectAdopt(result: ProjectAdoptResult): string {\n const lines: string[] = [];\n lines.push(\"# repo ロースターの bootstrap(source_roots → repos)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (result.alreadyDeclared) {\n lines.push(\n \"ℹ️ repo ロースター(manifest の `repos`)は既に宣言済みです。adopt は一度きりの bootstrap のため何も書き込みません。以後の保守は `project check` / `project sync` を使ってください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.repos.length === 0) {\n lines.push(\"ℹ️ source_roots に git repo が見つかりませんでした(bootstrap 対象なし)。\");\n } else if (result.applied) {\n lines.push(`✅ ${result.repos.length} repo を repos ロースターに書き込みました:`);\n for (const r of result.repos) lines.push(`- ${r.path}`);\n lines.push(\"\");\n lines.push(\n \"注: visibility は未設定です。各 repo に public / private / future-public を手動で付与してください。\",\n );\n } else {\n lines.push(\n `${result.repos.length} repo を repos ロースターに宣言予定(dry-run、反映するには --apply):`,\n );\n for (const r of result.repos) lines.push(`- ${r.path}`);\n lines.push(\"\");\n lines.push(\"注: visibility は未設定で提案します。反映後に手動で付与してください。\");\n }\n\n if (result.excluded.length > 0) {\n lines.push(\"\");\n lines.push(`## 除外 (${result.excluded.length}) — git repo ではないため repos に含めません`);\n for (const e of result.excluded) {\n const reason =\n e.kind === \"non-repo\" ? \"非 repo(workspace view / tmp 等)\" : \"解決不能(パスが存在しない)\";\n lines.push(`- ${e.path} — ${reason}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectWiring}. */\nexport async function runProjectWiring(\n options: ProjectWiringOptions,\n ctx: ProjectWiringContext = {},\n): Promise<void> {\n try {\n await doRunProjectWiring(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Whether a repo-relative path is tracked by git in `repoRoot`. `git ls-files`\n * prints the path when it is tracked and nothing when it is not. Any error\n * (missing git, a corrupt repo) propagates; {@link gatherRepoWiring} decides\n * whether to surface it (a missing git executable, which is global) or degrade\n * the single repo to unreachable (a per-repo failure) — never reading the error\n * as a false \"untracked\".\n */\nasync function isTrackedByGit(repoRoot: string, relPath: string): Promise<boolean> {\n const out = await safeSimpleGit(repoRoot).raw([\"ls-files\", \"--\", relPath]);\n return out.trim().length > 0;\n}\n\n/**\n * Gather the on-disk + git facts for one declared repo. Resolves the repo path\n * (realpath) and requires a `.git`; an unresolvable or non-repo path is reported\n * as `reachable: false` rather than crashing the whole report. Presence uses\n * `lstat` so a symlink (even a broken one) still counts as present.\n */\nasync function gatherRepoWiring(\n repositoryRoot: string,\n entry: RepoEntry,\n): Promise<RepoWiringFacts> {\n const base = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, reachable: false, instructionFiles: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, reachable: false, instructionFiles: [] };\n }\n\n try {\n const instructionFiles: InstructionFileFact[] = [];\n for (const name of INSTRUCTION_FILES) {\n let present = true;\n try {\n lstatSync(join(real, name));\n } catch {\n present = false;\n }\n instructionFiles.push({ name, present, tracked: await isTrackedByGit(real, name) });\n }\n return { ...base, reachable: true, instructionFiles };\n } catch (error: unknown) {\n // A missing git executable is a global, actionable failure — surface it so\n // the whole report does not silently read every repo as \"untracked\".\n if (isGitNotFound(error)) throw error;\n // A per-repo git failure (a corrupt repo, a stale worktree pointer) degrades\n // only THIS repo to unreachable, so one bad repo cannot blank the report.\n return { ...base, reachable: false, instructionFiles: [] };\n }\n}\n\n/**\n * Inspect each declared repo's instruction-file wiring. Resolves the workspace,\n * reads the manifest, gathers per-repo facts (presence + git-tracked status),\n * and summarizes the privacy-relevant drift. Read-only — it generates nothing.\n */\nexport async function doRunProjectWiring(\n options: ProjectWiringOptions,\n ctx: ProjectWiringContext,\n): Promise<ProjectWiringResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project wiring\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const facts: RepoWiringFacts[] = [];\n for (const entry of roster) facts.push(await gatherRepoWiring(repositoryRoot, entry));\n\n const summary = summarizeWiring(facts);\n const result: ProjectWiringResult = { ...summary, hasRoster: roster.length > 0 };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectWiring(result));\n }\n return result;\n}\n\n/**\n * Render the wiring report. Leads with the actionable outcome: no roster (run\n * adopt first), the privacy risks (a public repo tracking an instruction file),\n * the unjudgeable repos (visibility unset), and the wiring gaps (missing files).\n * States the read-only framing so the verdict is not over-read.\n */\nexport function renderProjectWiring(result: ProjectWiringResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 wiring チェック(宣言ロースター × 指示書の存在/git 追跡)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.risks.length > 0) {\n lines.push(\n `⚠️ 公開系 repo で指示書が git 追跡されています: ${result.risks.length}(canonical の漏洩リスク)`,\n );\n for (const r of result.risks) {\n lines.push(\n `- ${r.repo} [${r.visibility}] — ${r.file} が tracked(gitignore された symlink である必要があります)`,\n );\n }\n } else if (result.ok) {\n lines.push(\"✅ 公開系 repo で git 追跡されている指示書はありません(privacy リスクなし)。\");\n } else {\n // No confirmed risks, but unjudgeable / unreachable repos exist below — do NOT\n // lead with a clean \"no risk\" verdict (that would be a false-clear).\n lines.push(\n \"ℹ️ 確定した privacy リスクはありませんが、判定できない/到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.unknown.length > 0) {\n lines.push(\n `## visibility 未設定 (${result.unknown.length}) — privacy 判定不可。manifest の repos に visibility を付与してください`,\n );\n for (const p of result.unknown) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.incomplete.length > 0) {\n lines.push(`## 指示書の欠落 (${result.incomplete.length}) — 後続の生成スライスで補完予定`);\n for (const i of result.incomplete) lines.push(`- ${i.repo} — ${i.missing.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: read-only の advisory です。指示書の存在と git 追跡状況のみを表示し、生成・enforce はしません(.basou のフットプリントは `basou view --check`)。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectGitignore}. */\nexport async function runProjectGitignore(\n options: ProjectGitignoreOptions,\n ctx: ProjectGitignoreContext = {},\n): Promise<void> {\n try {\n await doRunProjectGitignore(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Gather one declared repo's `.gitignore` facts. Resolves the repo path\n * (realpath) and requires a `.git`; an unresolvable / non-repo path is reported\n * as `reachable: false`. Reads the repo's `.gitignore` into trimmed-on-compare\n * lines (an empty array when there is none). Pure filesystem reads — no writes.\n */\nfunction gatherRepoGitignore(repositoryRoot: string, entry: RepoEntry): RepoGitignoreFacts {\n const base = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, reachable: false, currentLines: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, reachable: false, currentLines: [] };\n }\n return { ...base, reachable: true, currentLines: readGitignoreLines(join(real, \".gitignore\")) };\n}\n\n/** True when an error carries a string `code` (a Node errno like `ENOENT`). */\nfunction hasErrorCode(error: unknown): error is Error & { code: string } {\n return error instanceof Error && typeof (error as { code?: unknown }).code === \"string\";\n}\n\n/**\n * Read a `.gitignore` into trimmed-on-compare lines. A genuinely absent file\n * (`ENOENT`) yields `[]`; any OTHER read error is re-thrown with a pathless\n * message (so an unreadable file is never mistaken for \"no patterns\", which on\n * the apply path would clobber it down to only the generated patterns).\n */\nfunction readGitignoreLines(file: string): string[] {\n try {\n return readFileSync(file, \"utf8\").split(/\\r?\\n/);\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return [];\n throw new Error(\"Failed to read .gitignore\", { cause: error });\n }\n}\n\n/** Append the planned patterns to a repo's `.gitignore`, creating it if absent. */\nfunction applyGitignorePlan(repositoryRoot: string, plan: RepoGitignorePlan): void {\n const file = join(realpathSync(resolve(repositoryRoot, plan.path)), \".gitignore\");\n let existing = \"\";\n try {\n existing = readFileSync(file, \"utf8\");\n } catch (error: unknown) {\n if (!(hasErrorCode(error) && error.code === \"ENOENT\")) {\n // Do NOT clobber an existing-but-unreadable .gitignore with only the patterns.\n throw new Error(\"Failed to read .gitignore\", { cause: error });\n }\n }\n const sep = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n try {\n writeFileSync(file, `${existing}${sep}${plan.toAdd.join(\"\\n\")}\\n`);\n } catch (error: unknown) {\n throw new Error(\"Failed to write .gitignore\", { cause: error });\n }\n}\n\n/**\n * Reconcile each public-facing repo's `.gitignore` to exclude the agent\n * instruction files. Resolves the workspace, reads the manifest, gathers each\n * declared repo's current `.gitignore`, and plans the missing patterns. When\n * `--apply` is set and there is something to add, it appends the patterns\n * (additive — it never removes a line); otherwise it writes nothing and prints\n * the plan. Private and unset-visibility repos are left untouched.\n */\nexport async function doRunProjectGitignore(\n options: ProjectGitignoreOptions,\n ctx: ProjectGitignoreContext,\n): Promise<ProjectGitignoreResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project gitignore\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const facts = roster.map((entry) => gatherRepoGitignore(repositoryRoot, entry));\n const summary = planGitignore({ repos: facts, required: [...INSTRUCTION_FILES] });\n\n const applied = options.apply === true && summary.plans.length > 0;\n if (applied) {\n for (const plan of summary.plans) applyGitignorePlan(repositoryRoot, plan);\n }\n\n const result: ProjectGitignoreResult = { ...summary, hasRoster: roster.length > 0, applied };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectGitignore(result));\n }\n return result;\n}\n\n/**\n * Render the gitignore report. Leads with the actionable outcome: no roster (run\n * adopt first), the per-repo patterns that will be / were added, then the\n * skipped (unset visibility) and unreachable repos. A clean verdict is shown\n * only when there is genuinely nothing to do AND every repo was judgeable and\n * reachable (no false-clear).\n */\nexport function renderProjectGitignore(result: ProjectGitignoreResult): string {\n const lines: string[] = [];\n lines.push(\"# .gitignore 生成(公開系 repo の指示書を除外)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n const verb = result.applied ? \"追加しました\" : \"追加予定(dry-run、反映するには --apply)\";\n lines.push(\n `${result.applied ? \"✅ \" : \"\"}${result.plans.length} repo の .gitignore に${verb}:`,\n );\n for (const p of result.plans) lines.push(`- ${p.path} — ${p.toAdd.join(\", \")}`);\n } else if (result.ok) {\n lines.push(\"✅ 公開系 repo の .gitignore は指示書をすべて除外済みです(追加不要)。\");\n } else {\n lines.push(\n \"ℹ️ 追加が必要な公開系 repo はありませんが、判定できない/到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.unknown.length > 0) {\n lines.push(\n `## visibility 未設定 (${result.unknown.length}) — 対象外。manifest の repos に visibility を付与してください`,\n );\n for (const p of result.unknown) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 既存の .gitignore 行は保持し、不足パターンの追記のみ行います(削除はしません)。private / visibility 未設定の repo は対象外です。\",\n );\n lines.push(\n \"注: .gitignore への追記は、既に git 追跡済みのファイルを untrack しません。追跡済みの指示書は `basou project wiring` で検出し、`git rm --cached <file>` で外してください。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectSymlinks}. */\nexport async function runProjectSymlinks(\n options: ProjectSymlinksOptions,\n ctx: ProjectSymlinksContext = {},\n): Promise<void> {\n try {\n await doRunProjectSymlinks(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * The instruction files and their expected symlink targets for one repo, in the\n * hub-and-spoke topology: AGENTS.md is the hub (a relative link to the anchor's\n * canonical), while CLAUDE.md and Copilot are spokes pointing back at the repo's\n * own AGENTS.md. `repoDirReal` and `canonicalFile` are both realpath-resolved so\n * the computed relative target matches a hand-wired link byte-for-byte.\n */\nfunction expectedSymlinkTargets(\n repoDirReal: string,\n canonicalFile: string,\n): { name: string; target: string }[] {\n return [\n { name: \"AGENTS.md\", target: relative(repoDirReal, canonicalFile) },\n { name: \"CLAUDE.md\", target: CANONICAL_FILE },\n { name: \".github/copilot-instructions.md\", target: `../${CANONICAL_FILE}` },\n ];\n}\n\n/**\n * Inspect one instruction file's on-disk state against the link it should be.\n * `lstat` examines a symlink as a link (even a broken one), never following it.\n * Only a genuinely absent path (ENOENT) is `missing` (a creatable gap); any other\n * lstat error (ENOTDIR when a parent component is a regular file, EACCES) is\n * `blocked` — NOT `missing` — so a non-ENOENT error is never mistaken for a gap\n * and planned, which would crash `--apply` (e.g. `mkdirSync` over a `.github`\n * file). A symlink is `correct` when it points at `expectedTarget` and `mismatch`\n * (carrying its current target) otherwise; a real file or directory is `occupied`.\n */\nfunction inspectSymlink(\n filePath: string,\n expectedTarget: string,\n): { state: InstructionSymlinkState; actualTarget?: string } {\n let isLink: boolean;\n try {\n isLink = lstatSync(filePath).isSymbolicLink();\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return { state: \"missing\" };\n return { state: \"blocked\" };\n }\n if (!isLink) return { state: \"occupied\" };\n const actual = readlinkSync(filePath);\n return actual === expectedTarget\n ? { state: \"correct\" }\n : { state: \"mismatch\", actualTarget: actual };\n}\n\n/**\n * Gather the symlink facts for one declared repo. Resolves the repo path\n * (realpath); the entry that resolves to the manifest root IS the anchor (it\n * owns the canonical, so it is flagged `isAnchor` and never linked to itself). A\n * path that does not resolve or has no `.git` is `reachable: false`. Otherwise it\n * checks whether the anchor's canonical (`agents/<repo>/AGENTS.md`) exists and,\n * if so, inspects each instruction file's current state. Pure filesystem reads —\n * no writes.\n */\nfunction gatherRepoSymlinks(\n repositoryRoot: string,\n anchorReal: string,\n entry: RepoEntry,\n): RepoSymlinkFacts {\n const base = { path: entry.path };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };\n }\n if (real === anchorReal) {\n return { ...base, isAnchor: true, reachable: true, canonicalPresent: false, files: [] };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...base, isAnchor: false, reachable: false, canonicalPresent: false, files: [] };\n }\n\n const canonicalFile = join(anchorReal, \"agents\", basename(real), CANONICAL_FILE);\n if (!existsSync(canonicalFile)) {\n return { ...base, isAnchor: false, reachable: true, canonicalPresent: false, files: [] };\n }\n\n const files: InstructionSymlinkFact[] = expectedSymlinkTargets(real, canonicalFile).map(\n (spec) => {\n const { state, actualTarget } = inspectSymlink(join(real, spec.name), spec.target);\n return {\n name: spec.name,\n expectedTarget: spec.target,\n state,\n ...(actualTarget !== undefined ? { actualTarget } : {}),\n };\n },\n );\n return {\n ...base,\n isAnchor: false,\n reachable: true,\n canonicalPresent: true,\n canonicalName: basename(real),\n files,\n };\n}\n\n/**\n * Create the planned (missing) symlinks for one repo, making `.github` if needed.\n * Defensive: a per-file failure (a path made unwritable, a parent that is not a\n * directory, or a race that created the file first) is collected, not thrown — so\n * one bad path neither aborts the remaining repos nor leaves the run silent about\n * what was actually created (upholding the non-destructive contract transparently).\n */\nfunction applySymlinkPlan(\n repositoryRoot: string,\n plan: RepoSymlinkPlan,\n): { created: string[]; failed: { file: string; message: string }[] } {\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, plan.path));\n } catch (error: unknown) {\n const message = failureReason(error);\n return { created: [], failed: plan.toCreate.map((c) => ({ file: c.name, message })) };\n }\n const created: string[] = [];\n const failed: { file: string; message: string }[] = [];\n for (const { name, target } of plan.toCreate) {\n const filePath = join(real, name);\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n symlinkSync(target, filePath);\n created.push(name);\n } catch (error: unknown) {\n failed.push({ file: name, message: failureReason(error) });\n }\n }\n return { created, failed };\n}\n\n/**\n * A pathless failure reason for `--apply` errors: the errno code (EEXIST,\n * ENOTDIR, EACCES, …) when present, else a generic label. Never the raw Node\n * `error.message`, which embeds the absolute filesystem path and would leak it\n * into the report / `--json` output (the repo + repo-relative file already\n * identify the failure).\n */\nfunction failureReason(error: unknown): string {\n return hasErrorCode(error) ? error.code : \"unknown error\";\n}\n\n/**\n * Generate each declared repo's instruction-file symlinks. Resolves the\n * workspace, reads the manifest, gathers each repo's current symlink state, and\n * plans the missing links. When `--apply` is set and there is something to\n * create, it creates only the `missing` links (non-destructive — conflicts and\n * occupied paths are never touched); otherwise it writes nothing and prints the\n * plan.\n */\nexport async function doRunProjectSymlinks(\n options: ProjectSymlinksOptions,\n ctx: ProjectSymlinksContext,\n): Promise<ProjectSymlinksResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project symlinks\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const anchorReal = realpathSync(repositoryRoot);\n const facts = roster.map((entry) => gatherRepoSymlinks(repositoryRoot, anchorReal, entry));\n const summary = summarizeSymlinkPlan(facts);\n\n const wantApply = options.apply === true && summary.plans.length > 0;\n const failures: { repo: string; file: string; message: string }[] = [];\n let createdCount = 0;\n if (wantApply) {\n for (const plan of summary.plans) {\n const { created, failed } = applySymlinkPlan(repositoryRoot, plan);\n createdCount += created.length;\n for (const f of failed) failures.push({ repo: plan.path, file: f.file, message: f.message });\n }\n }\n\n const result: ProjectSymlinksResult = {\n ...summary,\n hasRoster: roster.length > 0,\n applied: createdCount > 0,\n failures,\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectSymlinks(result));\n }\n return result;\n}\n\n/**\n * Render the symlink-generation report. Leads with the actionable outcome: no\n * roster (run adopt first), the per-repo links that will be / were created, then\n * the conflicts (existing files / links pointing elsewhere — left untouched),\n * repos whose anchor canonical is absent, and unreachable repos. A clean \"all\n * wired\" verdict is shown only when there is genuinely nothing to do AND every\n * repo was judgeable and reachable (no false-clear).\n */\nexport function renderProjectSymlinks(result: ProjectSymlinksResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 symlink 生成(各 repo → anchor の canonical)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n // `--apply` was attempted when something was created OR something failed; a\n // dry-run has neither (its plan is just intentions, written nowhere).\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.plans.length} repo に指示書 symlink を作成予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.plans) {\n lines.push(`- ${p.path}`);\n for (const c of p.toCreate) lines.push(` ${c.name} -> ${c.target}`);\n }\n } else {\n // List only what was ACTUALLY created — a planned file that failed appears\n // in the failures section, never here (no false \"created\" claim).\n const header =\n result.failures.length === 0\n ? \"✅ 指示書 symlink を作成しました:\"\n : result.applied\n ? \"指示書 symlink を作成しました(一部失敗、下記参照):\"\n : \"指示書 symlink を作成できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.plans) {\n const failedFiles = new Set(\n result.failures.filter((f) => f.repo === p.path).map((f) => f.file),\n );\n const created = p.toCreate.filter((c) => !failedFiles.has(c.name));\n if (created.length === 0) continue;\n lines.push(`- ${p.path}`);\n for (const c of created) lines.push(` ${c.name} -> ${c.target}`);\n }\n }\n } else if (result.ok) {\n lines.push(\"✅ 宣言された全 repo の指示書 symlink は正しく張られています(生成不要)。\");\n } else {\n lines.push(\n \"ℹ️ 生成が必要な symlink はありませんが、競合 / 衝突 / canonical 不在 / 到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.failures.length > 0) {\n lines.push(`## 作成に失敗 (${result.failures.length}) — 一部の symlink を作成できませんでした`);\n for (const f of result.failures) lines.push(`- ${f.repo} — ${f.file}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.conflicts.length > 0) {\n lines.push(\n `## 競合 (${result.conflicts.length}) — 既存を上書きしません。手動で確認してください`,\n );\n for (const c of result.conflicts) {\n const detail =\n c.reason === \"mismatch\"\n ? `別の場所を指す symlink(現在: ${c.actualTarget ?? \"?\"})`\n : c.reason === \"occupied\"\n ? \"symlink でない実ファイル/ディレクトリ\"\n : \"検査できないパス(親が非ディレクトリ等)\";\n lines.push(`- ${c.repo} — ${c.file}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## canonical 衝突 (${result.collisions.length}) — 別 repo が同名 canonical を共有(自動配線しません)`,\n );\n for (const c of result.collisions) {\n lines.push(`- agents/${c.canonicalName}/AGENTS.md ← ${c.repos.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n if (result.missingCanonical.length > 0) {\n lines.push(\n `## canonical 不在 (${result.missingCanonical.length}) — anchor に agents/<repo>/AGENTS.md が無いため生成できません`,\n );\n for (const p of result.missingCanonical) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 既存ファイル・別の場所を指す symlink は上書きせず、不足分の作成のみ行います(GEMINI.md は廃止のため生成しません)。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectWorkspace}. */\nexport async function runProjectWorkspace(\n options: ProjectWorkspaceOptions,\n ctx: ProjectWorkspaceContext = {},\n): Promise<void> {\n try {\n await doRunProjectWorkspace(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Resolve the view directory to a realpath-stable absolute path. When the view\n * exists, realpath it; when it does not exist yet, anchor on its (existing)\n * parent's realpath + basename so the relative targets computed against the\n * realpath'd repos stay consistent. Falls back to the plain resolved path only\n * when the parent is also absent (apply's recursive mkdir will create it).\n */\nfunction resolveViewDir(repositoryRoot: string, viewPath: string): string {\n const abs = resolve(repositoryRoot, viewPath);\n try {\n return realpathSync(abs);\n } catch {\n try {\n return join(realpathSync(dirname(abs)), basename(abs));\n } catch {\n return abs;\n }\n }\n}\n\n/**\n * Gather one roster repo's place in the view. Resolves the repo (realpath); an\n * unresolvable path is `reachable: false` (cannot be aggregated). The view link\n * is named by the repo's basename and should point at the repo relative to the\n * view; its on-disk state is inspected with the same ENOENT-only rule as the\n * instruction symlinks (a non-ENOENT lstat error is `blocked`, never a creatable\n * gap). Pure filesystem reads — no writes.\n */\nfunction gatherViewRepo(repositoryRoot: string, viewDir: string, entry: RepoEntry): ViewRepoFact {\n let repoReal: string;\n try {\n repoReal = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { path: entry.path, reachable: false };\n }\n const expectedTarget = relative(viewDir, repoReal);\n // A repo that resolves to the view directory ITSELF yields an empty (self-)\n // target. It cannot be aggregated into the view, and an empty symlink target\n // would create a broken link that a later run reads back as falsely \"correct\"\n // (readlink \"\" === expectedTarget \"\") — so surface it as unreachable instead.\n if (expectedTarget === \"\" || expectedTarget === \".\") {\n return { path: entry.path, reachable: false };\n }\n const linkName = basename(repoReal);\n const { state, actualTarget } = inspectSymlink(join(viewDir, linkName), expectedTarget);\n return {\n path: entry.path,\n reachable: true,\n linkName,\n expectedTarget,\n state,\n ...(actualTarget !== undefined ? { actualTarget } : {}),\n };\n}\n\n/** Create the planned (missing) view symlinks, making the view directory if needed. */\nfunction applyViewPlan(\n viewDir: string,\n toCreate: { name: string; target: string }[],\n): { created: string[]; failed: { name: string; message: string }[] } {\n const created: string[] = [];\n const failed: { name: string; message: string }[] = [];\n for (const { name, target } of toCreate) {\n const filePath = join(viewDir, name);\n try {\n mkdirSync(dirname(filePath), { recursive: true });\n symlinkSync(target, filePath);\n created.push(name);\n } catch (error: unknown) {\n failed.push({ name, message: failureReason(error) });\n }\n }\n return { created, failed };\n}\n\n/** Top-level instruction-file names the view may hold for itself — never treated as strays (case-insensitive). */\nconst TOP_LEVEL_INSTRUCTION_FILES_LOWER: ReadonlySet<string> = new Set(\n INSTRUCTION_FILES.filter((f) => !f.includes(\"/\")).map((f) => f.toLowerCase()),\n);\n\n/**\n * Classify one view entry by name for stray detection. Returns `null` when the\n * entry is NOT a removable stray candidate — it is not a symlink (a real file/dir\n * is never ours to remove), it vanished, or its target resolves to a CURRENT\n * roster repo (owned by the roster under whatever name — an aliased/symlinked\n * roster path, or a different-case link on a case-insensitive filesystem — so it\n * must never be pruned). Otherwise returns the link's target and `kind`: `repo`\n * (a relative target following to a git repository — a dir holding a `.git` entry,\n * matching the project family's `existsSync(<dir>/.git)` repo test, so worktrees /\n * submodules count); `absolute` (basou never writes absolute view links); `broken`\n * (a relative target that does not resolve); or `non-repo` (resolves to a file or a\n * non-repository directory). Pure filesystem reads — the single source of truth for\n * both the scan and the pre-unlink re-verification.\n */\nfunction classifyViewLink(\n viewDir: string,\n name: string,\n rosterRealpaths: ReadonlySet<string>,\n): { target: string; kind: ExistingViewLink[\"kind\"] } | null {\n const filePath = join(viewDir, name);\n let isLink: boolean;\n try {\n isLink = lstatSync(filePath).isSymbolicLink();\n } catch {\n return null; // vanished between readdir and lstat, or not inspectable\n }\n if (!isLink) return null; // a real file/dir is never ours to prune\n let target: string;\n try {\n target = readlinkSync(filePath);\n } catch {\n return null;\n }\n // A link pointing at a CURRENT roster repo (by resolved identity, not name) is\n // the repo's own link, never a stray — even under an aliased name, a case-folded\n // spelling, OR an absolute target. realpath canonicalizes all three. This\n // ownership check precedes the absolute/relative classification so an absolute\n // link to a rostered repo is treated as owned (not surfaced as a stray).\n const resolved = isAbsolute(target) ? target : resolve(viewDir, target);\n try {\n if (rosterRealpaths.has(realpathSync(resolved))) return null;\n } catch {\n // unresolvable target → not a roster repo; fall through to classify\n }\n if (isAbsolute(target)) return { target, kind: \"absolute\" }; // basou writes only relative links\n let isDir = false;\n try {\n isDir = statSync(resolved).isDirectory(); // follows the link\n } catch {\n isDir = false; // ENOENT / unreadable → broken\n }\n if (!isDir) {\n // Resolves to a file (e.g. an instruction symlink) or not at all — not a repo.\n return { target, kind: existsSync(resolved) ? \"non-repo\" : \"broken\" };\n }\n return { target, kind: existsSync(join(resolved, \".git\")) ? \"repo\" : \"non-repo\" };\n}\n\n/**\n * Scan the view directory for stray-detection candidates: its top-level SYMLINK\n * entries, classified by {@link classifyViewLink}. The view's own top-level\n * instruction-file symlinks (`AGENTS.md`/`CLAUDE.md`, matched case-insensitively)\n * and links resolving to a current roster repo are skipped. An ABSENT view\n * directory (ENOENT — nothing generated yet) yields `[]`; any other readdir error\n * (the view path is a file, or is unreadable) is surfaced, never read as \"no\n * strays\" (no false-clear). Pure reads.\n */\nexport function gatherExistingViewLinks(\n viewDir: string,\n rosterRealpaths: ReadonlySet<string>,\n): ExistingViewLink[] {\n let names: string[];\n try {\n names = readdirSync(viewDir);\n } catch (error: unknown) {\n if (hasErrorCode(error) && error.code === \"ENOENT\") return []; // not generated yet\n // The view path exists but could not be scanned (a regular file, EACCES, …) —\n // surface it rather than silently reporting a clean, stray-free view. The\n // message is path-less (matching the file's other thrown errors); the absolute\n // path stays in `cause`, shown only under --verbose.\n throw new Error(\"workspace view を走査できません(パス/種別を確認してください)\", {\n cause: error,\n });\n }\n const links: ExistingViewLink[] = [];\n for (const name of names) {\n if (TOP_LEVEL_INSTRUCTION_FILES_LOWER.has(name.toLowerCase())) continue; // the view's own instruction file\n const c = classifyViewLink(viewDir, name, rosterRealpaths);\n if (c === null) continue;\n links.push({ name, target: c.target, kind: c.kind });\n }\n return links;\n}\n\n/**\n * Remove the planned stray view symlinks. Immediately before each `unlinkSync` it\n * RE-DERIVES the full prune predicate via {@link classifyViewLink} (still a symlink,\n * still a relative target following to a git repo the roster does not back) and\n * skips with a collected failure if anything changed since the scan — closing the\n * scan-to-unlink window for this first file-removing operation. It only ever\n * unlinks the link, never its target. Failures are collected, not thrown.\n */\nexport function pruneViewLinks(\n viewDir: string,\n toPrune: { name: string; target: string }[],\n rosterRealpaths: ReadonlySet<string>,\n): { pruned: string[]; failed: { name: string; message: string }[] } {\n const pruned: string[] = [];\n const failed: { name: string; message: string }[] = [];\n for (const { name } of toPrune) {\n const filePath = join(viewDir, name);\n const c = classifyViewLink(viewDir, name, rosterRealpaths);\n if (c === null || c.kind !== \"repo\") {\n failed.push({\n name,\n message:\n \"撤去対象が scan 時と変わりました(basou 生成の stray repo link ではなくなった/再実行してください)\",\n });\n continue;\n }\n try {\n unlinkSync(filePath);\n pruned.push(name);\n } catch (error: unknown) {\n failed.push({ name, message: failureReason(error) });\n }\n }\n return { pruned, failed };\n}\n\n/**\n * Generate the project's workspace view and reconcile its strays. Resolves the\n * workspace, reads the manifest, and — when `workspace.view` is declared — gathers\n * each roster repo's view-link state plus the view's existing symlink entries, and\n * plans the missing links to create and the stray repo links to prune. When\n * `--apply` is set it creates only the `missing` links (non-destructive — conflicts\n * and collisions are never touched). When `--prune` is set it removes only the\n * confirmed stray repo links (a symlink whose relative target follows to a git\n * repository the roster no longer backs); unrecognized strays are reported, never\n * removed, and pruning is WITHHELD entirely while any declared repo is unreachable\n * (its live link could be indistinguishable from a stray). The two writes are\n * independent opt-ins; with neither flag it writes nothing and prints the plan.\n * After the writes the verdict (`ok`) is recomputed from the residual state so a\n * fully successful run is not reported as still needing attention.\n */\nexport async function doRunProjectWorkspace(\n options: ProjectWorkspaceOptions,\n ctx: ProjectWorkspaceContext,\n): Promise<ProjectWorkspaceResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project workspace\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const viewPath = manifest.workspace.view;\n const roster = manifest.repos ?? [];\n\n let result: ProjectWorkspaceResult;\n if (viewPath === undefined) {\n result = {\n toCreate: [],\n conflicts: [],\n collisions: [],\n unreachable: [],\n toPrune: [],\n strayUnknown: [],\n correctCount: 0,\n ok: true,\n hasView: false,\n applied: false,\n pruned: false,\n pruneWithheld: false,\n failures: [],\n pruneFailures: [],\n };\n } else {\n const viewDir = resolveViewDir(repositoryRoot, viewPath);\n const facts = roster.map((entry) => gatherViewRepo(repositoryRoot, viewDir, entry));\n // Ownership inputs for stray detection, computed once and shared by the scan\n // and the pre-unlink re-verification: the basename every declared entry would\n // own (reachability-INDEPENDENT, so a transiently-unreachable repo still owns\n // its link name), and the resolved identity of every repo that DOES resolve\n // (so a link reaching a roster repo under any name/case is never a stray).\n const rosterNames = roster.map((entry) => basename(resolve(repositoryRoot, entry.path)));\n const rosterRealpaths = new Set<string>();\n for (const entry of roster) {\n try {\n rosterRealpaths.add(realpathSync(resolve(repositoryRoot, entry.path)));\n } catch {\n // unreachable repo — protected by name via rosterNames + the prune withhold\n }\n }\n const existing = gatherExistingViewLinks(viewDir, rosterRealpaths);\n const plan = planWorkspaceView(facts, existing, rosterNames);\n\n const failures: { name: string; message: string }[] = [];\n let createdCount = 0;\n if (options.apply === true && plan.toCreate.length > 0) {\n const applied = applyViewPlan(viewDir, plan.toCreate);\n createdCount = applied.created.length;\n for (const f of applied.failed) failures.push(f);\n }\n\n // Refuse to prune while any declared repo is unreachable: such a repo's live\n // link can be indistinguishable from a stray, and a false delete is the worst\n // outcome for the family's first file-removing operation. The operator resolves\n // reachability (clone/mount the repo, or `archive` it) and re-runs.\n const pruneWithheld =\n options.prune === true && plan.toPrune.length > 0 && plan.unreachable.length > 0;\n const pruneFailures: { name: string; message: string }[] = [];\n let prunedCount = 0;\n if (options.prune === true && plan.toPrune.length > 0 && plan.unreachable.length === 0) {\n const removed = pruneViewLinks(viewDir, plan.toPrune, rosterRealpaths);\n prunedCount = removed.pruned.length;\n for (const f of removed.failed) pruneFailures.push(f);\n }\n\n // The plan's `ok` was computed BEFORE the writes; recompute the residual so a\n // create/prune that fully succeeded no longer counts as outstanding work (no\n // false \"items need attention\" after a successful run).\n const createsOutstanding =\n plan.toCreate.length > 0 && !(options.apply === true && failures.length === 0);\n const prunesOutstanding =\n plan.toPrune.length > 0 &&\n !(options.prune === true && !pruneWithheld && pruneFailures.length === 0);\n const ok =\n plan.conflicts.length === 0 &&\n plan.collisions.length === 0 &&\n plan.unreachable.length === 0 &&\n plan.strayUnknown.length === 0 &&\n !createsOutstanding &&\n !prunesOutstanding;\n\n result = {\n ...plan,\n ok,\n hasView: true,\n applied: createdCount > 0,\n pruned: prunedCount > 0,\n pruneWithheld,\n failures,\n pruneFailures,\n };\n }\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectWorkspace(result));\n }\n return result;\n}\n\n/**\n * Render the workspace-view report. Leads with the actionable outcome: no view\n * declared, the links that will be / were created, the stray repo links that will\n * be / were pruned, then conflicts, basename collisions, unreachable repos, and\n * the unrecognized strays left untouched. A clean \"in sync\" verdict is shown only\n * when there is genuinely nothing to do, every repo was resolvable and unambiguous,\n * and the view carries no stray (no false-clear).\n */\nexport function renderProjectWorkspace(result: ProjectWorkspaceResult): string {\n const lines: string[] = [];\n lines.push(\"# workspace view 生成(roster repo を集約)\");\n lines.push(\"\");\n\n if (!result.hasView) {\n lines.push(\n \"ℹ️ view が未宣言です(manifest の `workspace.view`)。集約先のディレクトリを宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.toCreate.length > 0) {\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.toCreate.length} 件の repo symlink を view に作成予定(dry-run、反映するには --apply):`,\n );\n for (const c of result.toCreate) lines.push(` ${c.name} -> ${c.target}`);\n } else {\n const failed = new Set(result.failures.map((f) => f.name));\n const header =\n result.failures.length === 0\n ? \"✅ view に repo symlink を作成しました:\"\n : result.applied\n ? \"view に repo symlink を作成しました(一部失敗、下記参照):\"\n : \"view に repo symlink を作成できませんでした(下記参照):\";\n lines.push(header);\n for (const c of result.toCreate) {\n if (failed.has(c.name)) continue;\n lines.push(` ${c.name} -> ${c.target}`);\n }\n }\n } else if (result.ok) {\n lines.push(\n `✅ view は宣言された roster をすべて集約しています(${result.correctCount} links、生成不要)。`,\n );\n } else {\n lines.push(\n \"ℹ️ 作成が必要な symlink はありませんが、対応の必要な項目があります(stray / 競合 / 衝突 / 到達できない repo、下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.failures.length > 0) {\n lines.push(`## 作成に失敗 (${result.failures.length}) — 一部の symlink を作成できませんでした`);\n for (const f of result.failures) lines.push(`- ${f.name}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.toPrune.length > 0) {\n const attempted = result.pruned || result.pruneFailures.length > 0;\n if (result.pruneWithheld) {\n lines.push(\n `${result.toPrune.length} 件の stray repo symlink を撤去予定でしたが、到達できない repo があるため撤去を保留しました(到達できない repo の link と stray を区別できないため。下記の repo を解決するか archive してから再実行してください):`,\n );\n for (const p of result.toPrune) lines.push(` ${p.name} -> ${p.target}`);\n } else if (!attempted) {\n lines.push(\n `${result.toPrune.length} 件の stray repo symlink を撤去予定(dry-run、撤去するには --prune):`,\n );\n for (const p of result.toPrune) lines.push(` ${p.name} -> ${p.target}`);\n } else {\n const failed = new Set(result.pruneFailures.map((f) => f.name));\n const header =\n result.pruneFailures.length === 0\n ? \"🧹 stray repo symlink を撤去しました:\"\n : result.pruned\n ? \"stray repo symlink を撤去しました(一部失敗、下記参照):\"\n : \"stray repo symlink を撤去できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.toPrune) {\n if (failed.has(p.name)) continue;\n lines.push(` ${p.name} -> ${p.target}`);\n }\n }\n lines.push(\"\");\n }\n\n if (result.pruneFailures.length > 0) {\n lines.push(\n `## 撤去に失敗 (${result.pruneFailures.length}) — 一部の stray symlink を撤去できませんでした`,\n );\n for (const f of result.pruneFailures) lines.push(`- ${f.name}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.conflicts.length > 0) {\n lines.push(\n `## 競合 (${result.conflicts.length}) — 既存を上書きしません。手動で確認してください`,\n );\n for (const c of result.conflicts) {\n const detail =\n c.reason === \"mismatch\"\n ? `別の場所を指す symlink(現在: ${c.actualTarget ?? \"?\"})`\n : c.reason === \"occupied\"\n ? \"symlink でない実ファイル/ディレクトリ\"\n : \"検査できないパス(親が非ディレクトリ等)\";\n lines.push(`- ${c.name}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## basename 衝突 (${result.collisions.length}) — 別 repo が同じ view 名を取り合い(自動配線しません)`,\n );\n for (const c of result.collisions) lines.push(`- ${c.linkName} ← ${c.repos.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(\n `## 到達不能 (${result.unreachable.length}) — パス未解決、または view 自身に解決するため集約できません`,\n );\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.strayUnknown.length > 0) {\n lines.push(\n `## 未撤去の stray (${result.strayUnknown.length}) — basou 生成の repo link と確認できないため撤去しません。手動で確認してください`,\n );\n for (const s of result.strayUnknown) {\n const detail =\n s.reason === \"broken\"\n ? \"リンク切れ(ターゲットが解決できません)\"\n : s.reason === \"non-repo\"\n ? \"git repo でないターゲット(ファイル、または .git の無いディレクトリ)\"\n : \"絶対パスのターゲット(basou は相対リンクのみ生成します)\";\n lines.push(`- ${s.name} -> ${s.target}: ${detail}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\n \"注: 作成(--apply)は既存エントリを上書きしません。stray repo link の撤去は --prune で行います(symlink のみ削除し、参照先 repo は削除しません)。basou 生成と確認できない stray(リンク切れ / 非 repo / 絶対パス)は撤去しません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectPreset}. */\nexport async function runProjectPreset(\n options: ProjectPresetOptions,\n ctx: ProjectPresetContext = {},\n): Promise<void> {\n try {\n await doRunProjectPreset(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** The anchor's canonical file for a repo: `<anchor>/agents/<name>/AGENTS.md`. */\nfunction canonicalFileFor(anchorReal: string, canonicalName: string): string {\n return join(anchorReal, \"agents\", canonicalName, CANONICAL_FILE);\n}\n\n/** The repo-relative label for a canonical (used in marker errors — never an absolute path). */\nfunction canonicalLabelFor(canonicalName: string): string {\n return join(\"agents\", canonicalName, CANONICAL_FILE);\n}\n\n/**\n * Gather one declared repo's preset facts. Resolves the repo (realpath); the\n * entry that resolves to the manifest root IS the anchor (its own AGENTS.md is\n * hand-maintained, so it is flagged and skipped). A path that does not resolve\n * or has no `.git` is `reachable: false`. Otherwise it reads the anchor's\n * canonical (`agents/<repo>/AGENTS.md`): absent => to be created; present =>\n * parsed for its marker region so the summarizer can detect drift. A present\n * canonical that cannot be read (a non-ENOENT failure) degrades only this repo\n * (`canonicalReadable: false`) instead of crashing the whole report.\n */\nasync function gatherRepoPreset(\n repositoryRoot: string,\n anchorReal: string,\n entry: RepoEntry,\n): Promise<RepoPresetFacts> {\n const declared = {\n path: entry.path,\n ...(entry.visibility !== undefined ? { visibility: entry.visibility } : {}),\n ...(entry.language !== undefined ? { language: entry.language } : {}),\n ...(entry.publishes !== undefined ? { publishes: entry.publishes } : {}),\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, entry.path));\n } catch {\n return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };\n }\n if (real === anchorReal) {\n return { ...declared, isAnchor: true, reachable: true, canonicalPresent: false };\n }\n if (!existsSync(join(real, \".git\"))) {\n return { ...declared, isAnchor: false, reachable: false, canonicalPresent: false };\n }\n\n const canonicalName = basename(real);\n let content: string | null;\n try {\n content = await readMarkdownFile(canonicalFileFor(anchorReal, canonicalName));\n } catch {\n // Present but unreadable (e.g. a directory at that path, or permission denied).\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: true,\n canonicalReadable: false,\n };\n }\n if (content === null) {\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: false,\n };\n }\n const section = parseMarkers(content);\n return {\n ...declared,\n isAnchor: false,\n reachable: true,\n canonicalName,\n canonicalPresent: true,\n canonicalReadable: true,\n markerKind: section.kind,\n ...(section.kind === \"ok\" ? { currentBlock: section.generated } : {}),\n };\n}\n\n/**\n * Write one planned canonical, always replacing ONLY the marker region via\n * {@link renderWithMarkers} so hand-authored content around it is preserved.\n *\n * Both `create` and `update` re-read the file at write time and render against\n * the CURRENT content (null => fresh). This closes the create-race: if a\n * canonical appeared between gather (which saw it absent) and the write, its\n * hand-authored content around well-formed markers is preserved, and a\n * markerless / malformed file makes {@link renderWithMarkers} throw — collected\n * by the caller as a failure — rather than being clobbered by a blind null-based\n * write. A symlinked canonical is refused: `atomicReplace` would swap the link\n * for a regular file, silently breaking deliberate wiring. The only on-disk\n * mutations are the recursive `mkdir` for a create and the marker-region write.\n */\nasync function applyPresetPlan(anchorReal: string, plan: RepoPresetPlan): Promise<void> {\n const file = canonicalFileFor(anchorReal, plan.canonicalName);\n const label = canonicalLabelFor(plan.canonicalName);\n // Refuse to replace a symlinked canonical. `lstat` examines the link itself; an\n // absent path (ENOENT) or any uninspectable path is not a symlink to guard —\n // the create branch / the write itself handles those.\n let isLink = false;\n try {\n isLink = lstatSync(file).isSymbolicLink();\n } catch {\n isLink = false;\n }\n if (isLink) throw new Error(`Canonical is a symlink in ${label}`);\n\n if (plan.action === \"create\") mkdirSync(dirname(file), { recursive: true });\n const existing = await readMarkdownFile(file);\n await writeMarkdownFile(file, renderWithMarkers(existing, plan.desiredBlock, label));\n}\n\n/**\n * A pathless failure reason for an `--apply` write error. A marker mismatch\n * thrown by {@link renderWithMarkers} (`Markers …`) or the symlink guard above\n * (`Canonical …`) carries an already-safe message (it embeds only the\n * repo-relative label); any other error is reduced to its errno code (from the\n * wrapped cause when present), never the raw message (which would leak an\n * absolute filesystem path into the report / `--json`).\n */\nfunction presetFailureReason(error: unknown): string {\n if (\n error instanceof Error &&\n (error.message.startsWith(\"Markers\") || error.message.startsWith(\"Canonical\"))\n ) {\n return error.message;\n }\n const cause = error instanceof Error ? (error as { cause?: unknown }).cause : undefined;\n if (hasErrorCode(cause)) return cause.code;\n if (hasErrorCode(error)) return error.code;\n return \"unknown error\";\n}\n\n/**\n * Generate each declared repo's canonical instruction-file preset block.\n * Resolves the workspace, reads the manifest, gathers each repo's canonical\n * state, and plans the create/update work. When `--apply` is set and there is\n * something to write, it writes only the marker-delimited region (creating an\n * absent canonical, updating an out-of-date one); a per-repo write failure is\n * collected, not thrown. Without `--apply` it writes nothing and prints the plan.\n */\nexport async function doRunProjectPreset(\n options: ProjectPresetOptions,\n ctx: ProjectPresetContext,\n): Promise<ProjectPresetResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project preset\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n\n const roster = manifest.repos ?? [];\n const anchorReal = realpathSync(repositoryRoot);\n const facts: RepoPresetFacts[] = [];\n for (const entry of roster) facts.push(await gatherRepoPreset(repositoryRoot, anchorReal, entry));\n const summary = summarizePresetPlan(facts);\n\n const failures: { repo: string; message: string }[] = [];\n let writtenCount = 0;\n if (options.apply === true && summary.plans.length > 0) {\n for (const plan of summary.plans) {\n try {\n await applyPresetPlan(anchorReal, plan);\n writtenCount += 1;\n } catch (error: unknown) {\n failures.push({ repo: plan.path, message: presetFailureReason(error) });\n }\n }\n }\n\n const result: ProjectPresetResult = {\n ...summary,\n hasRoster: roster.length > 0,\n applied: writtenCount > 0,\n failures,\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectPreset(result));\n }\n return result;\n}\n\n/** A compact one-line summary of what a plan's generated block declares. */\nfunction presetActionLabel(action: RepoPresetPlan[\"action\"]): string {\n return action === \"create\" ? \"新規作成\" : \"更新\";\n}\n\n/**\n * Render the preset-generation report. Leads with the actionable outcome: no\n * roster (run adopt first), the per-repo canonical blocks that will be / were\n * written (with the generated block shown in dry-run), then the marker conflicts\n * (canonical present but unmarked/malformed — left untouched, with the remedy),\n * unreadable canonicals, basename collisions, undeclared repos, the skipped\n * anchor, and unreachable repos. A clean \"all in sync\" verdict is shown only when\n * there is genuinely nothing to do AND every repo was judgeable (no false-clear).\n */\nexport function renderProjectPreset(result: ProjectPresetResult): string {\n const lines: string[] = [];\n lines.push(\"# 指示書 A プリセット生成(宣言 → canonical の生成領域)\");\n lines.push(\"\");\n\n if (!result.hasRoster) {\n lines.push(\n \"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。`basou project adopt` で宣言してから実行してください。\",\n );\n return lines.join(\"\\n\");\n }\n\n if (result.plans.length > 0) {\n // `--apply` was attempted when something was written OR something failed.\n const attempted = result.applied || result.failures.length > 0;\n if (!attempted) {\n lines.push(\n `${result.plans.length} repo の canonical に A プリセットを生成予定(dry-run、反映するには --apply):`,\n );\n for (const p of result.plans) {\n lines.push(\n `- ${p.path} [${presetActionLabel(p.action)}] → ${canonicalLabelFor(p.canonicalName)}`,\n );\n for (const bl of p.desiredBlock.split(\"\\n\")) lines.push(` ${bl}`);\n }\n } else {\n const failed = new Set(result.failures.map((f) => f.repo));\n const header =\n result.failures.length === 0\n ? \"✅ canonical に A プリセットを生成しました:\"\n : result.applied\n ? \"A プリセットを生成しました(一部失敗、下記参照):\"\n : \"A プリセットを生成できませんでした(下記参照):\";\n lines.push(header);\n for (const p of result.plans) {\n if (failed.has(p.path)) continue;\n lines.push(\n `- ${p.path} [${presetActionLabel(p.action)}] → ${canonicalLabelFor(p.canonicalName)}`,\n );\n }\n }\n } else if (result.ok) {\n lines.push(\"✅ 宣言された全 repo の A プリセットは canonical と同期済みです(生成不要)。\");\n } else {\n lines.push(\n \"ℹ️ 生成が必要な repo はありませんが、マーカー競合 / 衝突 / 未宣言 / 到達できない repo があります(下記参照)。\",\n );\n }\n lines.push(\"\");\n\n if (result.inSync.length > 0) {\n lines.push(`同期済み (${result.inSync.length}): ${result.inSync.join(\", \")}`);\n lines.push(\"\");\n }\n\n if (result.failures.length > 0) {\n lines.push(\n `## 書き込みに失敗 (${result.failures.length}) — 一部の canonical を書けませんでした`,\n );\n for (const f of result.failures) lines.push(`- ${f.repo}: ${f.message}`);\n lines.push(\"\");\n }\n\n if (result.markerConflicts.length > 0) {\n lines.push(\n `## マーカー競合 (${result.markerConflicts.length}) — canonical のマーカーが無い/壊れているため上書きしません`,\n );\n for (const c of result.markerConflicts) {\n const detail =\n c.reason === \"no_markers\" ? \"マーカー領域が無い\" : `マーカー不整合(${c.reason})`;\n lines.push(`- ${c.repo}: ${detail}`);\n }\n lines.push(\n ` 対処: A プリセットを入れたい位置に次の2行を追加してください — \\`${GENERATED_START}\\` と \\`${GENERATED_END}\\`(無ければ basou が新規 canonical を作ります)。`,\n );\n lines.push(\"\");\n }\n\n if (result.unreadable.length > 0) {\n lines.push(\n `## canonical 読み取り不能 (${result.unreadable.length}) — ディレクトリ/権限等で読めません`,\n );\n for (const p of result.unreadable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.collisions.length > 0) {\n lines.push(\n `## canonical 衝突 (${result.collisions.length}) — 別 repo が同名 canonical を共有(自動生成しません)`,\n );\n for (const c of result.collisions) {\n lines.push(`- agents/${c.canonicalName}/AGENTS.md ← ${c.repos.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n if (result.undeclared.length > 0) {\n lines.push(\n `## 宣言なし (${result.undeclared.length}) — visibility / language / publishes が未設定のため生成しません`,\n );\n for (const p of result.undeclared) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.anchors.length > 0) {\n lines.push(\n `## anchor (${result.anchors.length}) — 自身の AGENTS.md は手で維持するためスキップ`,\n );\n for (const p of result.anchors) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n if (result.unreachable.length > 0) {\n lines.push(`## 到達不能 (${result.unreachable.length}) — パス未解決 / git repo でない`);\n for (const p of result.unreachable) lines.push(`- ${p}`);\n lines.push(\"\");\n }\n\n lines.push(\n \"注: マーカー領域のみを生成し、canonical の手書き部分(マーカー外)は保持します。生成内容は manifest の宣言から導出されます。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectArchive}. */\nexport async function runProjectArchive(\n target: string,\n options: ProjectArchiveOptions,\n ctx: ProjectArchiveContext = {},\n): Promise<void> {\n try {\n await doRunProjectArchive(target, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Inspect the repo-side wiring still present for an archived repo — the manual\n * teardown checklist `--apply` does NOT touch (it only mutates the manifest).\n * Best-effort: an unresolvable repo (already deleted from disk) yields\n * `inspected: false` and empty facts, so archiving a removed repo still works.\n */\nfunction gatherArchiveTeardown(\n repositoryRoot: string,\n manifest: Manifest,\n target: string,\n): ArchiveTeardown {\n const empty: ArchiveTeardown = {\n inspected: false,\n viewLink: false,\n instructionFiles: [],\n gitignorePatterns: [],\n canonical: false,\n };\n let real: string;\n try {\n real = realpathSync(resolve(repositoryRoot, target));\n } catch {\n return empty;\n }\n const anchorReal = realpathSync(repositoryRoot);\n const canonicalName = basename(real);\n\n const instructionFiles: string[] = [];\n for (const name of INSTRUCTION_FILES) {\n try {\n lstatSync(join(real, name));\n instructionFiles.push(name);\n } catch {\n // not present — nothing to tear down\n }\n }\n\n // An unreadable .gitignore (EACCES / I/O error) must NOT throw out of this\n // advisory, read-only inspection — that would block the authoritative,\n // manifest-only archive write it has no say over. Degrade to \"no patterns\".\n let ignored: Set<string>;\n try {\n ignored = new Set(readGitignoreLines(join(real, \".gitignore\")).map((l) => l.trim()));\n } catch {\n ignored = new Set();\n }\n const gitignorePatterns = INSTRUCTION_FILES.filter((p) => ignored.has(p) || ignored.has(`/${p}`));\n\n const canonical = existsSync(join(anchorReal, \"agents\", canonicalName, CANONICAL_FILE));\n\n let viewLink = false;\n const viewPath = manifest.workspace.view;\n if (viewPath !== undefined) {\n try {\n lstatSync(join(resolveViewDir(repositoryRoot, viewPath), canonicalName));\n viewLink = true;\n } catch {\n // no view entry for this repo\n }\n }\n\n return {\n inspected: true,\n viewLink,\n instructionFiles,\n gitignorePatterns: [...gitignorePatterns],\n canonical,\n };\n}\n\n/** Shallow clone of an object with one optional key removed (preserves every other own field). */\nfunction omitKey<T extends object>(obj: T, key: keyof T): T {\n const clone = { ...obj };\n delete clone[key];\n return clone;\n}\n\n/**\n * Build the manifest to write after archiving. Spreads the original so every\n * other manifest field is preserved — both KNOWN fields not handled here and any\n * unknown/future field, which `readManifest`'s loose schema now carries through\n * (at the top level and nested) and surfaces via {@link unknownManifestKeys}. It\n * bumps `updated_at`, removes the target from `repos` (dropping the key entirely when\n * the roster empties, since `repos: []` is not a valid roster), and prunes the\n * target's `source_roots` entry (dropping `source_roots` — and an emptied\n * `import` block — rather than writing an invalid empty list).\n */\nfunction buildArchivedManifest(manifest: Manifest, plan: ArchivePlan, updatedAt: string): Manifest {\n let next: Manifest = { ...manifest, workspace: { ...manifest.workspace, updated_at: updatedAt } };\n\n next = plan.reposEmptied ? omitKey(next, \"repos\") : { ...next, repos: plan.nextRepos };\n\n if (plan.nextSourceRoots !== undefined) {\n if (plan.nextSourceRoots.length === 0) {\n const prunedImport =\n manifest.import !== undefined ? omitKey(manifest.import, \"source_roots\") : {};\n next =\n Object.keys(prunedImport).length === 0\n ? omitKey(next, \"import\")\n : { ...next, import: prunedImport };\n } else {\n next = {\n ...next,\n import: { ...(manifest.import ?? {}), source_roots: plan.nextSourceRoots },\n };\n }\n }\n\n return next;\n}\n\n/**\n * Archive (fold) a repo out of the project. Resolves the workspace, reads the\n * manifest, plans the manifest mutation (roster removal + source_roots prune),\n * and inspects the repo-side wiring for the teardown checklist. When `--apply`\n * is set and the target is a real, non-anchor roster member, it writes the\n * pruned manifest (bumping `updated_at`); otherwise it writes nothing and prints\n * the plan. The repo, its captured history, and its on-disk wiring are never\n * touched.\n */\nexport async function doRunProjectArchive(\n target: string,\n options: ProjectArchiveOptions,\n ctx: ProjectArchiveContext,\n): Promise<ProjectArchiveResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project archive\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n const roster = manifest.repos ?? [];\n\n let targetIsAnchor = false;\n try {\n targetIsAnchor = realpathSync(resolve(repositoryRoot, target)) === realpathSync(repositoryRoot);\n } catch {\n targetIsAnchor = false;\n }\n\n const plan = planArchive({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n target,\n targetIsAnchor,\n });\n\n const teardown =\n plan.found && !plan.isAnchor\n ? gatherArchiveTeardown(repositoryRoot, manifest, target)\n : {\n inspected: false,\n viewLink: false,\n instructionFiles: [],\n gitignorePatterns: [],\n canonical: false,\n };\n\n const applied = options.apply === true && plan.found && !plan.isAnchor;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(paths, buildArchivedManifest(manifest, plan, now().toISOString()), {\n force: true,\n });\n }\n\n const result: ProjectArchiveResult = {\n ...plan,\n hasRoster: roster.length > 0,\n applied,\n teardown,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectArchive(result));\n }\n return result;\n}\n\n/**\n * Render the archive report. Leads with the actionable outcome: no roster (run\n * adopt first), anchor refusal, target not found (with the declared paths), or\n * the manifest mutation that will be / was applied. Then the repo-side teardown\n * checklist (what `--apply` did NOT touch), and a note when the project becomes\n * solo or closes. Dry-run framing makes clear that without `--apply` nothing is\n * written.\n */\nexport function renderProjectArchive(result: ProjectArchiveResult): string {\n const lines: string[] = [];\n lines.push(\"# repo の archive(roster から畳む)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。archive 対象がありません。\");\n return lines.join(\"\\n\");\n }\n\n if (result.isAnchor) {\n lines.push(\n `⚠️ \\`${result.target}\\` は anchor(プロジェクトの root)です。anchor は archive できません(manifest の家のため)。`,\n );\n return lines.join(\"\\n\");\n }\n\n if (!result.found) {\n lines.push(`ℹ️ \\`${result.target}\\` は roster に宣言されていません(archive 対象なし)。`);\n return lines.join(\"\\n\");\n }\n\n // Manifest mutation summary.\n if (result.applied) {\n lines.push(`✅ \\`${result.target}\\` を roster から削除しました。`);\n } else {\n lines.push(`\\`${result.target}\\` を roster から削除予定(dry-run、反映するには --apply):`);\n }\n if (result.sourceRootRemoval !== undefined) {\n lines.push(\n `- source_roots から ${result.sourceRootRemoval} を prune${result.applied ? \"しました\" : \"します\"}(以後 refresh の対象外)。`,\n );\n } else {\n lines.push(\"- source_roots に該当エントリはありません(prune 不要)。\");\n }\n if (result.reposEmptied) {\n lines.push(\n \"- これが最後のメンバーです → roster は空になり `repos` 宣言は除去されます(プロジェクトを畳む)。\",\n );\n } else if (result.becomesSolo) {\n lines.push(\n \"- 残り 1 repo(solo)になります → workspace view は不要です(view 宣言/ディレクトリの撤去を検討)。\",\n );\n }\n lines.push(\"\");\n\n // Teardown checklist (report-only).\n const t = result.teardown;\n const items: string[] = [];\n if (t.viewLink) items.push(\"workspace view の symlink エントリ\");\n if (t.instructionFiles.length > 0) items.push(`指示書(${t.instructionFiles.join(\", \")})`);\n if (t.gitignorePatterns.length > 0)\n items.push(`.gitignore の指示書パターン(${t.gitignorePatterns.join(\", \")})`);\n if (t.canonical) items.push(`anchor の canonical(agents/${basename(result.target)}/AGENTS.md)`);\n\n if (!t.inspected) {\n lines.push(\"## 手動 teardown(repo がディスク上に解決できないため未検査)\");\n lines.push(\n \"- repo は既に削除済みの可能性があります。view symlink / 指示書 symlink / .gitignore / canonical が残っていないか手動で確認してください。\",\n );\n lines.push(\"\");\n } else if (items.length > 0) {\n lines.push(\"## 手動 teardown(--apply は触れません。残っている wiring を手で撤去してください)\");\n for (const i of items) lines.push(`- ${i}`);\n lines.push(\"\");\n } else {\n lines.push(\"repo 側の wiring(view/指示書/.gitignore/canonical)は残っていません。\");\n lines.push(\"\");\n }\n\n lines.push(\n \"注: archive は manifest(.basou、git 追跡=可逆)のみを変更します。repo・捕捉履歴・on-disk の wiring は削除しません。\",\n );\n return lines.join(\"\\n\");\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunProjectRename}. */\nexport async function runProjectRename(\n oldPath: string,\n newPath: string,\n options: ProjectRenameOptions,\n ctx: ProjectRenameContext = {},\n): Promise<void> {\n try {\n await doRunProjectRename(oldPath, newPath, options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Inspect the anchor-side wiring still at the OLD basename after a\n * basename-changing rename — the manual checklist `--apply` does NOT touch.\n * Read-only existence checks; an uninspectable path is reported as absent.\n */\nfunction gatherRenameWiring(\n repositoryRoot: string,\n manifest: Manifest,\n oldBasename: string,\n): RenameWiring {\n // An uninspectable anchor (a TOCTOU deletion since the manifest was read) must\n // not throw out of this advisory inspection — that would block the\n // authoritative manifest write that runs after it. Degrade to \"nothing found\".\n let anchorReal: string;\n try {\n anchorReal = realpathSync(repositoryRoot);\n } catch {\n return { canonicalDirOld: false, viewLinkOld: false };\n }\n const canonicalDirOld = existsSync(join(anchorReal, \"agents\", oldBasename));\n\n let viewLinkOld = false;\n const viewPath = manifest.workspace.view;\n if (viewPath !== undefined) {\n try {\n lstatSync(join(resolveViewDir(repositoryRoot, viewPath), oldBasename));\n viewLinkOld = true;\n } catch {\n // no view entry at the old basename\n }\n }\n return { canonicalDirOld, viewLinkOld };\n}\n\n/**\n * Build the manifest to write after a rename. Spreads the original (preserving\n * every known field), bumps `updated_at`, and replaces `repos` with the\n * re-pathed roster; when the source root was captured, replaces\n * `import.source_roots` with the re-pathed list. A rename never empties either\n * list, so no key is dropped.\n */\nfunction buildRenamedManifest(manifest: Manifest, plan: RenamePlan, updatedAt: string): Manifest {\n const next: Manifest = {\n ...manifest,\n workspace: { ...manifest.workspace, updated_at: updatedAt },\n repos: plan.nextRepos,\n };\n if (plan.nextSourceRoots !== undefined) {\n return { ...next, import: { ...(manifest.import ?? {}), source_roots: plan.nextSourceRoots } };\n }\n return next;\n}\n\n/**\n * Re-path a repo in the project. Resolves the workspace, reads the manifest,\n * plans the manifest mutation (roster + source_roots path update), and inspects\n * the anchor-side wiring still at the old basename. When `--apply` is set and the\n * rename is actionable (the source is a real, non-anchor roster member, the\n * destination is free, and old != new), it writes the re-pathed manifest;\n * otherwise it writes nothing and prints the plan. The repo is never moved or\n * rewired on disk.\n */\nexport async function doRunProjectRename(\n oldPath: string,\n newPath: string,\n options: ProjectRenameOptions,\n ctx: ProjectRenameContext,\n): Promise<ProjectRenameResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"project rename\");\n const paths = basouPaths(repositoryRoot);\n const manifest = await readManifest(paths);\n const roster = manifest.repos ?? [];\n\n let oldIsAnchor = false;\n try {\n oldIsAnchor = realpathSync(resolve(repositoryRoot, oldPath)) === realpathSync(repositoryRoot);\n } catch {\n oldIsAnchor = false;\n }\n\n const plan = planRename({\n ...(manifest.repos !== undefined ? { repos: manifest.repos } : {}),\n ...(manifest.import?.source_roots !== undefined\n ? { sourceRoots: manifest.import.source_roots }\n : {}),\n oldPath,\n newPath,\n oldIsAnchor,\n });\n\n const actionable = plan.found && !plan.isAnchor && !plan.collision && !plan.noop;\n const wiring =\n actionable && plan.basenameChanged\n ? gatherRenameWiring(repositoryRoot, manifest, pathBasename(plan.oldTarget))\n : { canonicalDirOld: false, viewLinkOld: false };\n\n const applied = options.apply === true && actionable;\n if (applied) {\n const now = ctx.now ?? (() => new Date());\n await writeManifest(paths, buildRenamedManifest(manifest, plan, now().toISOString()), {\n force: true,\n });\n }\n\n const result: ProjectRenameResult = {\n ...plan,\n hasRoster: roster.length > 0,\n applied,\n wiring,\n preservedUnknownFields: unknownManifestKeys(manifest),\n };\n\n if (options.json === true) {\n console.log(JSON.stringify(result));\n } else {\n console.log(renderProjectRename(result));\n }\n return result;\n}\n\n/**\n * Render the rename report. Leads with the actionable outcome: no roster, no-op,\n * anchor refusal, collision refusal, source not found, or the manifest mutation\n * that will be / was applied. Then the anchor-side rename checklist (when the\n * basename changed) and a note to re-run the wiring generators.\n */\nexport function renderProjectRename(result: ProjectRenameResult): string {\n const lines: string[] = [];\n lines.push(\"# repo の rename(roster のパス更新)\");\n lines.push(\"\");\n lines.push(...preservedUnknownLines(result.preservedUnknownFields));\n\n if (!result.hasRoster) {\n lines.push(\"ℹ️ repo ロースターが未宣言です(manifest の `repos`)。rename 対象がありません。\");\n return lines.join(\"\\n\");\n }\n if (result.noop) {\n lines.push(`ℹ️ \\`${result.oldTarget}\\` と \\`${result.newTarget}\\` は同一です(変更なし)。`);\n return lines.join(\"\\n\");\n }\n if (result.isAnchor) {\n lines.push(\n `⚠️ \\`${result.oldTarget}\\` は anchor(プロジェクトの root)です。anchor は rename できません。`,\n );\n return lines.join(\"\\n\");\n }\n if (!result.found) {\n lines.push(`ℹ️ \\`${result.oldTarget}\\` は roster に宣言されていません(rename 対象なし)。`);\n return lines.join(\"\\n\");\n }\n if (result.collision) {\n lines.push(\n `⚠️ \\`${result.newTarget}\\` は既に roster に宣言されています。重複を避けるため rename しません。`,\n );\n return lines.join(\"\\n\");\n }\n\n if (result.applied) {\n lines.push(`✅ \\`${result.oldTarget}\\` を \\`${result.newTarget}\\` に rename しました。`);\n } else {\n lines.push(\n `\\`${result.oldTarget}\\` を \\`${result.newTarget}\\` に rename 予定(dry-run、反映するには --apply):`,\n );\n }\n if (result.sourceRootRenamed !== undefined) {\n lines.push(\n `- source_roots の ${result.sourceRootRenamed} を ${result.newTarget} に更新${result.applied ? \"しました\" : \"します\"}。`,\n );\n } else {\n lines.push(\"- source_roots に該当エントリはありません(更新不要)。\");\n }\n lines.push(\"\");\n\n // Anchor-side checklist (report-only) — only relevant when the basename changes.\n if (result.basenameChanged) {\n const oldName = pathBasename(result.oldTarget);\n const newName = pathBasename(result.newTarget);\n const items: string[] = [];\n if (result.wiring.canonicalDirOld)\n items.push(`anchor canonical: agents/${oldName}/ → agents/${newName}/`);\n if (result.wiring.viewLinkOld) items.push(`workspace view の symlink: ${oldName} → ${newName}`);\n if (items.length > 0) {\n lines.push(\n \"## 手動リネーム(--apply は触れません。basename が変わるため手で更新してください)\",\n );\n for (const i of items) lines.push(`- ${i}`);\n } else {\n lines.push(\n `basename が ${oldName} → ${newName} に変わりますが、anchor canonical / view symlink は見つかりませんでした。`,\n );\n }\n lines.push(\n \" 反映後は `basou project symlinks` / `basou project workspace` で指示書 symlink と view を再生成してください。\",\n );\n } else {\n lines.push(\n \"注: basename は不変です。repo を別の場所へ移動した場合は `basou project symlinks` / `basou project workspace` で相対ターゲットを再生成してください。\",\n );\n }\n lines.push(\"\");\n\n lines.push(\n \"注: rename は manifest(.basou、git 追跡=可逆)のみを変更します。repo の移動・on-disk の wiring 更新は行いません。\",\n );\n return lines.join(\"\\n\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n PROTOCOL_END,\n PROTOCOL_START,\n parseMarkers,\n readMarkdownFile,\n removeMarkerSection,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { assertNotSymlink, writeFileDurable } from \"../lib/durable-write.js\";\nimport { isVerbose, renderCliError } from \"../lib/error-render.js\";\nimport {\n DEFAULT_PROTOCOLS_CONFIG_PATH,\n DEFAULT_TARGET_PATH,\n loadProtocolsConfig,\n type ProtocolEntry,\n} from \"../lib/protocols-config.js\";\n\n/** Marker pair that delimits the basou-managed protocol block in the target. */\nconst PROTOCOL_MARKERS = { start: PROTOCOL_START, end: PROTOCOL_END };\n\n/** Note rendered at the top of the managed block so a reader knows not to edit it. */\nconst MANAGED_NOTE =\n \"<!-- Managed by basou: 'basou protocol sync' regenerates everything between the BASOU:PROTOCOLS markers from ~/.basou/protocols.yaml. Manual edits inside the block are overwritten; edit the source files instead. -->\";\n\nexport type ProtocolCommonOptions = {\n config?: string;\n target?: string;\n verbose?: boolean;\n};\n\nexport type ProtocolSyncOptions = ProtocolCommonOptions & { dryRun?: boolean };\n\n/**\n * Wire `basou protocol` (sync / list / unsync) onto `program`. The command\n * renders operator-declared standing protocols into a marker-delimited block\n * inside the user-global Claude Code instructions file (~/.claude/CLAUDE.md),\n * which Claude Code auto-loads every session. It only ever touches the bytes\n * between the BASOU:PROTOCOLS markers; everything else in the file is preserved.\n */\nexport function registerProtocolCommand(program: Command): void {\n const protocol = program\n .command(\"protocol\")\n .description(\"Manage the basou-managed standing-protocol block in the global CLAUDE.md\");\n\n protocol\n .command(\"sync\")\n .description(\"Render declared protocols into the global CLAUDE.md (creates/updates the block)\")\n .option(\"--config <path>\", \"Path to protocols.yaml (default ~/.basou/protocols.yaml)\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"--dry-run\", \"Print what would change without writing\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolSyncOptions) => {\n await runProtocolSync(opts);\n });\n\n protocol\n .command(\"list\")\n .description(\"List declared protocols and whether the block is installed\")\n .option(\"--config <path>\", \"Path to protocols.yaml (default ~/.basou/protocols.yaml)\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolCommonOptions) => {\n await runProtocolList(opts);\n });\n\n protocol\n .command(\"unsync\")\n .description(\"Remove the basou-managed protocol block from the global CLAUDE.md\")\n .option(\"--target <path>\", \"Override the target file (intended for tests)\")\n .option(\"--dry-run\", \"Print what would change without writing\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ProtocolSyncOptions) => {\n await runProtocolUnsync(opts);\n });\n}\n\nexport async function runProtocolSync(options: ProtocolSyncOptions): Promise<void> {\n try {\n await doRunProtocolSync(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runProtocolList(options: ProtocolCommonOptions): Promise<void> {\n try {\n await doRunProtocolList(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\nexport async function runProtocolUnsync(options: ProtocolSyncOptions): Promise<void> {\n try {\n await doRunProtocolUnsync(options);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/**\n * Read each protocol source and refuse if a source body contains a marker line\n * (which would corrupt the managed block on the next parse). Returns the\n * entries paired with their file contents, in declared order.\n */\nasync function readProtocolSources(\n entries: ProtocolEntry[],\n): Promise<{ entry: ProtocolEntry; content: string }[]> {\n const out: { entry: ProtocolEntry; content: string }[] = [];\n for (const entry of entries) {\n let content: string;\n try {\n content = await readFile(entry.source, \"utf8\");\n } catch (error: unknown) {\n if (error instanceof Error && (error as { code?: string }).code === \"ENOENT\") {\n throw new Error(\n \"A protocol source file does not exist. Check the 'source' paths in ~/.basou/protocols.yaml.\",\n { cause: error },\n );\n }\n throw new Error(\"Failed to read a protocol source file.\", { cause: error });\n }\n for (const line of content.split(/\\r?\\n/)) {\n if (line === PROTOCOL_START || line === PROTOCOL_END) {\n throw new Error(\n \"A protocol source contains a BASOU:PROTOCOLS marker line, which would corrupt the managed block. Remove that line from the source.\",\n );\n }\n }\n out.push({ entry, content });\n }\n return out;\n}\n\n/** Assemble the inner block body (without the markers) from the read sources. */\nfunction buildBlock(sources: { entry: ProtocolEntry; content: string }[]): string {\n const sections = sources.map(({ entry, content }) => {\n const body = content.replace(/\\s+$/, \"\");\n return entry.title !== undefined ? `## ${entry.title}\\n\\n${body}` : body;\n });\n return `${MANAGED_NOTE}\\n\\n${sections.join(\"\\n\\n\")}\\n`;\n}\n\n/**\n * Compute the new target body. Unlike the basou-owned generated files, the\n * target is a foreign file that may already hold user content with no basou\n * block yet, so the no-markers case APPENDS rather than throwing.\n *\n * - target absent: file is just the wrapped block.\n * - existing has an `ok` block: replace it in place (preserve before/after).\n * - existing has no block: append the block to the end (preserve all content).\n * - existing has a malformed block: refuse (do not silently rewrite).\n */\nfunction buildTargetBody(existing: string | null, block: string): string {\n const wrapped = `${PROTOCOL_START}\\n${block}${PROTOCOL_END}\\n`;\n // An empty existing file is treated like an absent one, so a freshly-touched\n // CLAUDE.md does not gain spurious leading blank lines from the append path.\n if (existing === null || existing === \"\") return wrapped;\n const section = parseMarkers(existing, PROTOCOL_MARKERS);\n switch (section.kind) {\n case \"ok\":\n return `${section.before}${PROTOCOL_START}\\n${block}${PROTOCOL_END}${section.after}`;\n case \"no_markers\": {\n const sep = existing.endsWith(\"\\n\\n\") ? \"\" : existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n return `${existing}${sep}${wrapped}`;\n }\n default:\n throw new Error(\n \"The BASOU:PROTOCOLS markers in the target are malformed (a marker is missing, duplicated, or out of order). Fix or remove them, then retry.\",\n );\n }\n}\n\n/**\n * Back up the target's original content the first time basou modifies it.\n * Uses a single stable `<target>.basou-bak` and never overwrites it, so the\n * pre-basou original is preserved exactly once. No-op when a backup already\n * exists or the target does not exist.\n */\nasync function backupOnce(target: string, existing: string | null): Promise<void> {\n if (existing === null) return;\n const bak = `${target}.basou-bak`;\n const already = await readMarkdownFile(bak);\n if (already !== null) return;\n await writeFileDurable(bak, existing);\n}\n\nexport async function doRunProtocolSync(options: ProtocolSyncOptions): Promise<void> {\n const configPath = options.config ?? DEFAULT_PROTOCOLS_CONFIG_PATH;\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n const entries = await loadProtocolsConfig(configPath);\n const sources = await readProtocolSources(entries);\n const block = buildBlock(sources);\n\n await assertNotSymlink(target);\n const existing = await readMarkdownFile(target);\n const newBody = buildTargetBody(existing, block);\n\n if (newBody === existing) {\n console.log(`The basou:protocols block is already up to date (${entries.length} protocol(s)).`);\n return;\n }\n\n // Install vs update wording comes from the parsed result, not a substring\n // check, so marker text appearing in the user's prose is not mistaken for an\n // installed block.\n const hadBlock = existing !== null && parseMarkers(existing, PROTOCOL_MARKERS).kind === \"ok\";\n\n if (options.dryRun === true) {\n console.log(\n `[dry-run] Would ${hadBlock ? \"update\" : \"install\"} the basou:protocols block (${entries.length} protocol(s)).`,\n );\n for (const { entry } of sources) {\n console.log(` - ${entry.title ?? entry.source}`);\n }\n return;\n }\n\n // Optimistic concurrency: re-read and abort if the file changed since the\n // read above, so a concurrent edit is not clobbered. This narrows but does\n // not fully close the window (a writer landing between this read and the\n // rename inside writeFileDurable is still possible); hard exclusion would\n // need a lock, which is out of scope for this slice.\n const recheck = await readMarkdownFile(target);\n if (recheck !== existing) {\n throw new Error(\n \"The target changed during sync; aborting so a concurrent edit is not overwritten. Re-run 'basou protocol sync'.\",\n );\n }\n\n // Back up the original only after the CAS check passes, so an aborted run\n // never leaves a backup of a file it did not modify.\n await backupOnce(target, existing);\n await writeFileDurable(target, newBody);\n console.log(\n `${hadBlock ? \"Updated\" : \"Installed\"} the basou:protocols block in the global CLAUDE.md (${entries.length} protocol(s)).`,\n );\n}\n\nexport async function doRunProtocolList(options: ProtocolCommonOptions): Promise<void> {\n const configPath = options.config ?? DEFAULT_PROTOCOLS_CONFIG_PATH;\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n const entries = await loadProtocolsConfig(configPath);\n const existing = await readMarkdownFile(target);\n const installed = existing !== null && parseMarkers(existing, PROTOCOL_MARKERS).kind === \"ok\";\n\n console.log(`Declared protocols (${entries.length}):`);\n for (const entry of entries) {\n console.log(` - ${entry.title ?? entry.source}`);\n }\n console.log(installed ? \"Block: installed in the global CLAUDE.md.\" : \"Block: not installed.\");\n}\n\nexport async function doRunProtocolUnsync(options: ProtocolSyncOptions): Promise<void> {\n const target = options.target ?? DEFAULT_TARGET_PATH;\n\n await assertNotSymlink(target);\n const existing = await readMarkdownFile(target);\n if (existing === null) {\n console.log(\"No target file; nothing to remove.\");\n return;\n }\n\n const newBody = removeMarkerSection(existing, \"CLAUDE.md\", PROTOCOL_MARKERS);\n if (newBody === existing) {\n console.log(\"No basou:protocols block found; nothing removed.\");\n return;\n }\n\n if (options.dryRun === true) {\n console.log(\"[dry-run] Would remove the basou:protocols block from the global CLAUDE.md.\");\n return;\n }\n\n // Optimistic concurrency (see sync): re-read and abort on a concurrent edit\n // before backing up or writing, so an aborted run leaves nothing behind.\n const recheck = await readMarkdownFile(target);\n if (recheck !== existing) {\n throw new Error(\n \"The target changed during unsync; aborting so a concurrent edit is not overwritten. Re-run 'basou protocol unsync'.\",\n );\n }\n\n await backupOnce(target, existing);\n await writeFileDurable(target, newBody);\n console.log(\"Removed the basou:protocols block from the global CLAUDE.md.\");\n}\n","import { randomUUID } from \"node:crypto\";\nimport { lstat, open, rename, stat, unlink } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\n\n/**\n * Throw if `targetPath` is a symlink. Returns silently when the path is a\n * regular file or does not exist.\n *\n * Writing through a symlink would let a link at the target redirect the write\n * to an unexpected file. The protocol channel writes into a user-owned config\n * file and refuses symlinked targets by default (mirroring the `.basou/` root\n * invariant, which also rejects a symlink in its place). `lstat` does not\n * follow the link, so a symlink is detected as such.\n */\nexport async function assertNotSymlink(targetPath: string): Promise<void> {\n try {\n const st = await lstat(targetPath);\n if (st.isSymbolicLink()) {\n throw new Error(\n \"Refusing to write through a symlink. Replace the symlinked target with a regular file (or remove it) and retry.\",\n );\n }\n } catch (error: unknown) {\n if (error instanceof Error && (error as { code?: string }).code === \"ENOENT\") return;\n throw error;\n }\n}\n\n/**\n * Durably write `content` to `targetPath`, preserving the existing file's\n * permission bits and fsyncing both the file and its directory.\n *\n * In addition to a tmp + rename atomic swap, the file contents are fsynced\n * before the rename and the parent directory is fsynced after, so a crash or\n * power loss leaves either the old file or the fully-written new one (never a\n * truncated file), and the rename itself survives. The new file inherits the\n * mode of the file it replaces (default 0o644 when the target does not yet\n * exist) rather than whatever the umask would impose. Directory fsync is\n * best-effort: platforms that reject an fsync on a directory fd do not fail the\n * write (the contents are already durable via the file fsync and the atomic\n * rename).\n *\n * Intended for writing into a user-owned config file (e.g. ~/.claude/CLAUDE.md)\n * where durability and mode preservation matter. The tmp file is created with\n * the `wx` flag in the same directory so the rename cannot cross filesystems\n * and never clobbers a concurrent tmp file. The caller is responsible for\n * refusing symlinked targets (see {@link assertNotSymlink}); this helper\n * replaces the name via rename and does not follow a symlink at `targetPath`.\n */\nexport async function writeFileDurable(targetPath: string, content: string): Promise<void> {\n const dir = dirname(targetPath);\n const tmpPath = join(dir, `.${basename(targetPath)}.tmp.${randomUUID()}`);\n\n let mode = 0o644;\n try {\n mode = (await stat(targetPath)).mode & 0o777;\n } catch (error: unknown) {\n if (!(error instanceof Error && (error as { code?: string }).code === \"ENOENT\")) {\n throw error;\n }\n }\n\n let handle: Awaited<ReturnType<typeof open>> | undefined;\n try {\n handle = await open(tmpPath, \"wx\", mode);\n await handle.writeFile(content, \"utf8\");\n await handle.chmod(mode);\n await handle.sync();\n await handle.close();\n handle = undefined;\n await rename(tmpPath, targetPath);\n } catch (error: unknown) {\n if (handle) await handle.close().catch(() => undefined);\n await unlink(tmpPath).catch(() => undefined);\n throw error;\n }\n\n // Best-effort directory fsync so the rename is durable across power loss.\n try {\n const dirHandle = await open(dir, \"r\");\n try {\n await dirHandle.sync();\n } finally {\n await dirHandle.close();\n }\n } catch {\n // Some platforms reject fsync on a directory fd; the file content is\n // already durable and the rename is atomic, so do not fail the write.\n }\n}\n","import { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { readYamlFile } from \"@basou/core\";\n\n/**\n * One declared standing protocol: a markdown source file (the protocol text)\n * and an optional display title. `source` is resolved to an absolute path by\n * {@link loadProtocolsConfig}.\n */\nexport type ProtocolEntry = { source: string; title?: string };\n\n/** Canonical location of the protocols config (a user-level, machine-local file). */\nexport const DEFAULT_PROTOCOLS_CONFIG_PATH = join(homedir(), \".basou\", \"protocols.yaml\");\n\n/**\n * Locked render target for this slice: the user-global Claude Code instructions\n * file, which Claude Code auto-loads at every session start. The target is not\n * read from the config (a config-supplied path would let the writer append to\n * arbitrary files); only an explicit `--target` flag may override it, and that\n * override exists for tests.\n */\nexport const DEFAULT_TARGET_PATH = join(homedir(), \".claude\", \"CLAUDE.md\");\n\nconst ALLOWED_TOP_KEYS = new Set([\"version\", \"protocols\"]);\nconst ALLOWED_ENTRY_KEYS = new Set([\"source\", \"title\"]);\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/protocols.yaml` (or an injected path for tests),\n * returning the protocol entries with each `source` expanded to an absolute\n * path. Throws an Error with a pathless, user-facing message on a missing file,\n * invalid YAML, a malformed shape, an unknown key, an empty or duplicate\n * source, an empty title, or an empty list.\n *\n * Shape (strict; unknown keys are rejected):\n * version: 1 # optional\n * protocols:\n * - source: ~/projects/foo-planning/protocols/bar.md # required, absolute or ~\n * title: Bar Protocol # optional, non-empty\n */\nexport async function loadProtocolsConfig(\n configPath: string = DEFAULT_PROTOCOLS_CONFIG_PATH,\n): Promise<ProtocolEntry[]> {\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 protocols config at ~/.basou/protocols.yaml. Create one (a 'protocols:' list of source markdown paths) before running 'basou protocol sync'.\",\n );\n }\n if (error instanceof Error && error.message === \"Failed to parse YAML content\") {\n throw new Error(\"~/.basou/protocols.yaml is not valid YAML.\");\n }\n throw error;\n }\n\n if (!isRecord(raw) || !Array.isArray(raw.protocols)) {\n throw new Error(\"~/.basou/protocols.yaml must contain a 'protocols:' list.\");\n }\n for (const key of Object.keys(raw)) {\n if (!ALLOWED_TOP_KEYS.has(key)) {\n throw new Error(\n `~/.basou/protocols.yaml has an unknown key '${key}' (allowed: version, protocols).`,\n );\n }\n }\n\n const seen = new Set<string>();\n const result: ProtocolEntry[] = [];\n for (const entry of raw.protocols) {\n if (!isRecord(entry)) {\n throw new Error(\"Each protocol entry must be a mapping with a 'source' key.\");\n }\n for (const key of Object.keys(entry)) {\n if (!ALLOWED_ENTRY_KEYS.has(key)) {\n throw new Error(`A protocol entry has an unknown key '${key}' (allowed: source, title).`);\n }\n }\n if (typeof entry.source !== \"string\" || entry.source.trim().length === 0) {\n throw new Error(\"Each protocol entry needs a non-empty string 'source'.\");\n }\n if (\n entry.title !== undefined &&\n (typeof entry.title !== \"string\" || entry.title.trim().length === 0)\n ) {\n throw new Error(\"A protocol entry 'title' must be a non-empty string when present.\");\n }\n const expanded = expandTilde(entry.source.trim());\n if (!isAbsolute(expanded)) {\n throw new Error(\"Protocol 'source' paths must be absolute (or start with '~').\");\n }\n const abs = resolve(expanded);\n if (seen.has(abs)) {\n throw new Error(\"Duplicate protocol source (each source path may appear only once).\");\n }\n seen.add(abs);\n result.push(\n entry.title !== undefined ? { source: abs, title: entry.title.trim() } : { source: abs },\n );\n }\n\n if (result.length === 0) {\n throw new Error(\"~/.basou/protocols.yaml has no protocols.\");\n }\n return result;\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\nexport function 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 if (result.decisions.decisionCount === 0) {\n // \"regenerated (0)\" read as success while the decision provenance was in\n // fact empty. State the count plainly, and when there are captured sessions\n // but no decisions, point at the capture path. Wording is cause-neutral and\n // adapter-blind on purpose (we only know the aggregate session count here):\n // \"none auto-recorded\" is true whether codex carries no approval-question\n // signal to derive from, or a Claude Code run simply made no decisions.\n // The pointer names `basou decision capture` (the batch path the in-loop\n // agent uses to record a session's conversational decisions at once)\n // rather than the single-shot `basou decision record`.\n const hasSessions = result.handoff.status === \"generated\" && result.handoff.sessionCount > 0;\n console.log(\n hasSessions\n ? \"decisions: 0 (none auto-recorded from these sessions; capture any made with 'basou decision capture')\"\n : \"decisions: 0\",\n );\n } else {\n console.log(`decisions: regenerated (${result.decisions.decisionCount})`);\n }\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 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 {\n basouPaths,\n findReviewGaps,\n type ReviewGapsSummary,\n type ReviewGapUnit,\n} from \"@basou/core\";\nimport type { Command } from \"commander\";\nimport { InvalidArgumentError } from \"commander\";\nimport {\n isVerbose,\n printReplayWarning,\n printSessionSkip,\n renderCliError,\n} from \"../lib/error-render.js\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.js\";\nimport type { ImportContext } from \"./import.js\";\n\nexport type ReviewGapsOptions = {\n repo?: string[];\n window?: number;\n json?: boolean;\n verbose?: boolean;\n};\n\nexport type ReviewGapsContext = ImportContext & {\n /** Defaults to `() => new Date()`. Injectable for tests. */\n nowProvider?: () => Date;\n};\n\n/** Commander collector: accumulate a repeatable `--repo` into an array. */\nfunction collectRepo(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** Commander parser: `--window` is a positive integer count of hours. */\nexport function parseWindow(value: string): number {\n const hours = Number(value);\n if (!Number.isInteger(hours) || hours <= 0) {\n throw new InvalidArgumentError(\"--window must be a positive integer (hours).\");\n }\n return hours;\n}\n\n/**\n * Wire `basou review-gaps` onto `program`. A read-only, advisory check for the\n * \"external adversarial review before commit\" protocol: it surfaces units of\n * work that landed commits with NO bound cross-model (Codex) review trail. It\n * never claims a unit WAS reviewed — temporal proximity is not binding — so it\n * surfaces suspicion and leaves the final call to the operator. It writes\n * nothing and enforces nothing.\n */\nexport function registerReviewGapsCommand(program: Command): void {\n program\n .command(\"review-gaps\")\n .description(\n \"Surface units of work committed without a bound cross-model review trail (read-only, advisory)\",\n )\n .option(\n \"--repo <name>\",\n \"Restrict to a repo by name (repeatable; default: every repo with captured commits)\",\n collectRepo,\n [],\n )\n .option(\n \"--window <hours>\",\n \"Hours before a commit to look for a review (default 24)\",\n parseWindow,\n )\n .option(\"--json\", \"Output the result as JSON\")\n .option(\"-v, --verbose\", \"Show error causes\")\n .action(async (opts: ReviewGapsOptions) => {\n await runReviewGaps(opts);\n });\n}\n\n/** Programmatic entry that owns `process.exitCode`. Tests prefer {@link doRunReviewGaps}. */\nexport async function runReviewGaps(\n options: ReviewGapsOptions,\n ctx: ReviewGapsContext = {},\n): Promise<void> {\n try {\n await doRunReviewGaps(options, ctx);\n } catch (error: unknown) {\n renderCliError(error, { verbose: isVerbose(options) });\n process.exitCode = 1;\n }\n}\n\n/** Pure runner: resolves the workspace, computes the summary, prints it (or JSON). */\nexport async function doRunReviewGaps(\n options: ReviewGapsOptions,\n ctx: ReviewGapsContext,\n): Promise<ReviewGapsSummary> {\n const cwd = ctx.cwd ?? process.cwd();\n const repositoryRoot = await resolveBasouRootForCommand(cwd, \"review-gaps\");\n const paths = basouPaths(repositoryRoot);\n\n const nowIso = (ctx.nowProvider?.() ?? new Date()).toISOString();\n const summary = await findReviewGaps({\n paths,\n nowIso,\n ...(options.repo !== undefined && options.repo.length > 0 ? { scope: options.repo } : {}),\n ...(options.window !== undefined ? { windowHours: options.window } : {}),\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(summary));\n } else {\n console.log(renderReviewGaps(summary));\n }\n return summary;\n}\n\nfunction relAge(iso: string | null, now: Date): string {\n if (iso === null) return \"(不明)\";\n const ms = now.getTime() - Date.parse(iso);\n if (!Number.isFinite(ms) || ms < 0) return \"たった今\";\n const days = Math.floor(ms / 86_400_000);\n if (days >= 1) return `${days}日前`;\n const hours = Math.floor(ms / 3_600_000);\n if (hours >= 1) return `${hours}時間前`;\n return `${Math.max(1, Math.floor(ms / 60_000))}分前`;\n}\n\nfunction unitLine(u: ReviewGapUnit, now: Date): string {\n const when = relAge(u.lastCommitAt, now);\n const head = `- ${u.repo} ${when} (${u.commitCount} commit${u.commitCount === 1 ? \"\" : \"s\"})`;\n if (u.verdict === \"near_unbound\") {\n const ids = u.reviews.map((r) => r.sessionId.slice(0, 14)).join(\", \");\n return `${head} — 近接レビューはあるが diff/変更ファイルを確認していない [${ids}]`;\n }\n return `${head} — 紐づくクロスモデルレビューなし`;\n}\n\nfunction candidateLine(u: ReviewGapUnit, now: Date): string {\n const when = relAge(u.lastCommitAt, now);\n const cite = u.reviews\n .map((r) => `${r.sessionId.slice(0, 14)}${r.examinedDiff ? \"(diff)\" : \"\"}`)\n .join(\", \");\n return `- ${u.repo} ${when} (${u.commitCount} commit${u.commitCount === 1 ? \"\" : \"s\"}) — レビュー形跡: ${cite}`;\n}\n\n/**\n * Render the advisory report. Leads with the gaps (units with no bound review),\n * then the candidates to confirm, then a per-repo tally. It deliberately states\n * the read-only / capture-bounded / no-auto-clear framing so the verdict is not\n * over-read.\n */\nexport function renderReviewGaps(summary: ReviewGapsSummary): string {\n const now = new Date(summary.generatedAt);\n const lines: string[] = [];\n const scope = summary.scope ? summary.scope.join(\", \") : \"全リポジトリ\";\n lines.push(`# レビュー証跡のギャップ (${scope})`);\n lines.push(\"\");\n\n if (summary.gaps.length === 0) {\n lines.push(\"✅ 取り込み済みの範囲では、レビュー証跡なしで着地した作業単位はありません。\");\n } else {\n lines.push(`⚠️ レビュー証跡なしで着地した作業単位: ${summary.gaps.length}`);\n for (const u of summary.gaps) lines.push(unitLine(u, now));\n }\n lines.push(\"\");\n\n if (summary.candidates.length > 0) {\n lines.push(\n `## 確認待ち (${summary.candidates.length}) — クロスモデルがレビューした形跡あり。この変更を本当に見たか確認してください`,\n );\n for (const u of summary.candidates) lines.push(candidateLine(u, now));\n lines.push(\"\");\n }\n\n if (summary.unknowns.length > 0) {\n const n = summary.unknowns.reduce((sum, u) => sum + u.commitCount, 0);\n lines.push(\n `## 導出不可 (${summary.unknowns.length} 単位 / ${n} commit) — repo か時刻を捕捉から導けず、判定を保留(clear ではありません)`,\n );\n lines.push(\"\");\n }\n\n lines.push(\"## リポジトリ別\");\n for (const r of summary.repos) {\n lines.push(\n `- ${r.repo}: ${r.units} 単位 (証跡なし ${r.omissionUnits} / 近接のみ ${r.nearUnboundUnits} / 確認待ち ${r.candidateUnits}${r.unknownUnits > 0 ? ` / 不明 ${r.unknownUnits}` : \"\"})`,\n );\n }\n lines.push(\"\");\n lines.push(\n `注: read-only の advisory です。取り込み済みの commit のみが対象(最新取込 commit: ${summary.newestCommitAt === null ? \"なし\" : relAge(summary.newestCommitAt, now)})。レビューの「実施」は自動判定せず、時間的近接だけでは合格にしません。enforce はしません。`,\n );\n return lines.join(\"\\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 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\";\nimport { resolveBasouRootForCommand } from \"../lib/repo-root.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\n/**\n * Resolve the repository root that owns the `.basou/` store for a session\n * subcommand, sharing the workspace-view fallback used by `orient` / `refresh`\n * (and the `project` commands): a git-untracked view dir that symlinks its\n * planning repo redirects to that repo (with a note on stderr) instead of failing\n * with \"Not a git repository\". Session commands previously resolved with the\n * git-only `resolveRepositoryRoot`, so `basou session list` died in a view; this\n * unifies them with the rest of the CLI.\n */\nasync function resolveRepositoryRootForSession(\n cwd: string,\n subcmd: \"list\" | \"show\" | \"import\" | \"note\" | \"rechain\",\n): Promise<string> {\n return resolveBasouRootForCommand(cwd, `session ${subcmd}`);\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\">← 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'\n ? '; handoff regenerated, decisions: ' + (data.decisions ? data.decisions.decisionCount : 0)\n : '');\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","import { isVerbose, renderCliError } from \"./lib/error-render.js\";\nimport { buildProgram } from \"./program.js\";\n\n// Thin binary entry: construction lives in the side-effect-free ./program.ts\n// (so the docs generator can import `buildProgram` and introspect the command\n// surface without triggering a parse); this file owns the single argv parse.\nconst program = buildProgram();\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n // Top-level safety net: never print the Error object directly because\n // Node's util.inspect recursively expands `error.cause`, which can carry\n // absolute paths from native fs errors. Delegates to the shared pathless\n // renderer; verbose mode is gated on BASOU_DEBUG only since the failure\n // bypassed the subcommand handler that owns the `-v` flag.\n renderCliError(err, { verbose: isVerbose(undefined) });\n process.exit(1);\n});\n"],"mappings":";;;AAAA;AAAA,EACE;AAAA,OAIK;AAMP,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,eAAe;AAOd,SAAS,eAAe,IAAoB;AACjD,MAAI,GAAG,WAAW,UAAU;AAC1B,WAAO,GAAG,MAAM,WAAW,QAAQ,WAAW,SAAS,YAAY;AACrE,SAAO,GAAG,MAAM,GAAG,YAAY;AACjC;AAKO,SAAS,YAAY,IAAoB;AAC9C,MAAI,GAAG,WAAW,WAAW;AAC3B,WAAO,GAAG,MAAM,YAAY,QAAQ,YAAY,SAAS,YAAY;AACvE,SAAO,GAAG,MAAM,GAAG,YAAY;AACjC;AAWO,SAAS,UAAU,SAAqD;AAC7E,SAAO,SAAS,YAAY,QAAQ,QAAQ,IAAI,gBAAgB;AAClE;AAMA,IAAM,wBAAwB;AAWvB,SAAS,kBAAkB,OAAkC;AAClE,MAAI,UAAmB,MAAM;AAC7B,MAAI;AACJ,WAAS,QAAQ,GAAG,QAAQ,uBAAuB,SAAS,GAAG;AAC7D,QAAI,EAAE,mBAAmB,OAAQ;AACjC,UAAM,OAAQ,QAAuC;AACrD,QAAI,OAAO,SAAS,YAAY,KAAK,SAAS,EAAG,QAAO;AACxD,sBAAkB,QAAQ,YAAY;AACtC,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAwBO,IAAM,6BAA8C;AAAA,EACzD,OAAO,CAAC,UAAU,iBAAiB;AAAA,EACnC,iBAAiB,CAAC,UAAU;AAC1B,UAAM,IAAI;AACV,UAAM,MAAM,eAAe,EAAE,SAAS;AAOtC,UAAM,SAAS,EAAE,eAAe,CAAC;AACjC,WAAO;AAAA,MACL,YAAY,MAAM,eAAe,GAAG;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAmBO,SAAS,eACd,OACA,SACM;AACN,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,YAAQ,MAAM,OAAO,KAAK,CAAC;AAC3B;AAAA,EACF;AACA,UAAQ,MAAM,MAAM,OAAO;AAC3B,aAAW,cAAc,QAAQ,eAAe,CAAC,GAAG;AAClD,QAAI,WAAW,MAAM,KAAK,GAAG;AAC3B,iBAAW,QAAQ,WAAW,gBAAgB,KAAK,EAAG,SAAQ,MAAM,IAAI;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,QAAQ,SAAS;AACnB,UAAM,QAAQ,kBAAkB,KAAK;AACrC,QAAI,UAAU,OAAW,SAAQ,MAAM,cAAc,KAAK,EAAE;AAAA,EAC9D;AACF;AAYO,SAAS,mBAAmB,SAAwB,WAAyB;AAClF,QAAM,QAAQ,eAAe,SAAS;AACtC,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,cAAQ,MAAM,6CAA6C,KAAK,eAAe;AAC/E;AAAA,IACF,KAAK;AACH,cAAQ;AAAA,QACN,2CAA2C,QAAQ,IAAI,OAAO,KAAK;AAAA,MACrE;AACA;AAAA,IACF,KAAK;AACH,cAAQ;AAAA,QACN,0CAA0C,QAAQ,IAAI,OAAO,KAAK;AAAA,MACpE;AACA;AAAA,EACJ;AACF;AASO,SAAS,iBAAiB,KAAa,QAAiC;AAC7E,QAAM,QAAQ,eAAe,GAAG;AAChC,MAAI,WAAW,2BAA2B;AACxC,YAAQ,MAAM,sCAAsC,KAAK,2BAA2B;AAAA,EACtF,OAAO;AACL,YAAQ,MAAM,WAAW,KAAK,KAAK,MAAM,EAAE;AAAA,EAC7C;AACF;AASO,SAAS,qBAAqB,KAAa,QAAiC;AACjF,QAAM,QAAQ,eAAe,GAAG;AAChC,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,cAAQ,MAAM,WAAW,KAAK,0BAA0B;AACxD;AAAA,IACF,KAAK;AACH,cAAQ,MAAM,WAAW,KAAK,0BAA0B;AACxD;AAAA,IACF,KAAK;AACH,cAAQ,MAAM,sCAAsC,KAAK,2BAA2B;AACpF;AAAA,EACJ;AACF;AAQO,SAAS,cAAc,QAAgB,QAAuC;AACnF,UAAQ,MAAM,WAAW,YAAY,MAAM,CAAC,KAAK,MAAM,EAAE;AAC3D;;;ACrOA,SAAS,qBAAqB;AAC9B,SAAS,eAAe;;;ACDxB,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB;AAAA,EAGE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,4BAA4B;AAClC,IAAM,sBAAsB;AAE5B,IAAM,gBAAgB,qBAAqB;AAyCpC,SAAS,wBAAwBA,UAAwB;AAC9D,QAAM,WAAWA,SACd,QAAQ,UAAU,EAClB,YAAY,wDAAwD;AAEvE,WACG,QAAQ,MAAM,EACd,YAAY,2DAA2D,EACvE,OAAO,UAAU,iCAAiC,EAClD;AAAA,IACC;AAAA,IACA,sCAAsC,cAAc,KAAK,IAAI,CAAC;AAAA,IAC9D;AAAA,EACF,EACC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAiC;AAC9C,UAAM,gBAAgB,OAAO;AAAA,EAC/B,CAAC;AAEH,WACG,QAAQ,WAAW,EACnB,YAAY,gDAAgD,EAC5D,OAAO,UAAU,wCAAwC,EACzD,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,IAAY,YAAiC;AAC1D,UAAM,gBAAgB,IAAI,OAAO;AAAA,EACnC,CAAC;AAEH,WACG,QAAQ,cAAc,EACtB,YAAY,4BAA4B,EACxC,OAAO,iBAAiB,wDAAwD,EAChF,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,IAAY,YAAoC;AAC7D,UAAM,mBAAmB,IAAI,OAAO;AAAA,EACtC,CAAC;AAEH,WACG,QAAQ,aAAa,EACrB,YAAY,2BAA2B,EACvC,eAAe,mBAAmB,iCAAiC,EACnE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,IAAY,YAAmC;AAC5D,UAAM,kBAAkB,IAAI,OAAO;AAAA,EACrC,CAAC;AACL;AASA,eAAsB,gBACpB,SACA,MAAuB,CAAC,GACT;AACf,MAAI;AACF,UAAM,kBAAkB,SAAS,GAAG;AAAA,EACtC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAMA,eAAsB,kBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,iCAAiC,KAAK,MAAM;AACzE,QAAM,QAAQ,WAAW,cAAc;AACvC,QAAM,2BAA2B,MAAM,IAAI;AAE3C,QAAM,MAAM,MAAM,mBAAmB,KAAK;AAI1C,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAgC,CAAC;AAIvC,QAAM,cAAc,IAAI,IAAI,IAAI,QAAQ;AACxC,aAAW,MAAM,IAAI,SAAS;AAC5B,QAAI,YAAY,IAAI,EAAE,GAAG;AACvB,cAAQ,MAAM,oCAAoC,QAAQ,EAAE,CAAC,8BAA8B;AAC3F;AAAA,IACF;AACA,UAAM,MAAM,MAAM,uBAAuB,OAAO,IAAI,WAAW,GAAG;AAClE,QAAI,QAAQ,KAAM,SAAQ,KAAK,GAAG;AAAA,EACpC;AACA,aAAW,MAAM,IAAI,UAAU;AAC7B,UAAM,MAAM,MAAM,uBAAuB,OAAO,IAAI,YAAY,GAAG;AACnE,QAAI,QAAQ,KAAM,SAAQ,KAAK,GAAG;AAAA,EACpC;AAEA,UAAQ,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,SAAS,UAAU,IAAI,KAAK,MAAM,EAAE,SAAS,UAAU,CAAC;AAE5F,QAAM,WACJ,QAAQ,WAAW,SACf,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW,QAAQ,MAAM,IAC1D;AAEN,MAAI,SAAS,WAAW,GAAG;AACzB,qBAAiB,OAAO;AACxB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,UAAU,cAAc,EAAE,YAAY,EAAE;AAAA,QACpE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,0BAAsB,QAAQ;AAAA,EAChC;AACF;AAEA,eAAe,uBACb,OACA,IACA,UACA,KACoC;AACpC,QAAM,WAAW,KAAK,MAAM,UAAU,QAAQ,GAAG,GAAG,EAAE,OAAO;AAC7D,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ;AAAA,EACnC,SAAS,OAAgB;AACvB,YAAQ,MAAM,WAAW,QAAQ,EAAE,CAAC,KAAK,kBAAkB,KAAK,CAAC,EAAE;AACnE,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,eAAe,UAAU,GAAG;AAC1C,MAAI,CAAC,MAAM,SAAS;AAClB,YAAQ,MAAM,WAAW,QAAQ,EAAE,CAAC,2BAA2B;AAC/D,WAAO;AAAA,EACT;AACA,MAAI,MAAM,KAAK,OAAO,IAAI;AAGxB,YAAQ,MAAM,WAAW,QAAQ,EAAE,CAAC,sCAAsC;AAC1E,WAAO;AAAA,EACT;AACA,QAAM,WAAW,MAAM;AACvB,SAAO,EAAE,UAAU,UAAU,aAAa,cAAc,UAAU,GAAG,EAAE;AACzE;AAIA,eAAsB,gBACpB,SACA,SACA,MAAuB,CAAC,GACT;AACf,MAAI;AACF,UAAM,kBAAkB,SAAS,SAAS,GAAG;AAAA,EAC/C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,kBACpB,SACA,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,iCAAiC,KAAK,MAAM;AACzE,QAAM,QAAQ,WAAW,cAAc;AACvC,QAAM,2BAA2B,MAAM,IAAI;AAE3C,QAAM,EAAE,GAAG,IAAI,MAAM,kBAAkB,OAAO,OAAO;AACrD,QAAM,SAAS,MAAM,aAAa,OAAO,EAAE;AAC3C,MAAI,WAAW,MAAM;AACnB,UAAM,IAAI,MAAM,uBAAuB,OAAO,EAAE;AAAA,EAClD;AAKA,QAAM,aAAa,KAAK,MAAM,UAAU,OAAO,SAAS,UAAU;AAClE,QAAM,gBAAyB,CAAC;AAChC,mBAAiB,MAAM,aAAa,YAAY;AAAA,IAC9C,WAAW,CAAC,MAAM,mBAAmB,GAAG,OAAO,SAAS,UAAU;AAAA,EACpE,CAAC,GAAG;AACF,QAAI,gBAAgB,EAAE,KAAK,GAAG,gBAAgB,IAAI;AAChD,oBAAc,KAAK,EAAE;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,cAAc,cAAc,OAAO,UAAU,GAAG;AAEtD,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH;AAAA,UACE,UAAU,EAAE,GAAG,OAAO,UAAU,cAAc,YAAY;AAAA,UAC1D,QAAQ;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,wBAAsB,OAAO,UAAU,OAAO,UAAU,eAAe,WAAW;AACpF;AAIA,eAAsB,mBACpB,SACA,SACA,MAAuB,CAAC,GACT;AACf,MAAI;AACF,UAAM,qBAAqB,SAAS,SAAS,KAAK,SAAS;AAAA,EAC7D,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,kBACpB,SACA,SACA,MAAuB,CAAC,GACT;AACf,MAAI;AACF,UAAM,qBAAqB,SAAS,SAAS,KAAK,QAAQ;AAAA,EAC5D,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAe,qBACb,SACA,SACA,KACA,UACe;AACf,MAAI,aAAa,UAAU;AACzB,UAAM,SAAU,QAAkC;AAClD,QAAI,OAAO,WAAW,GAAG;AACvB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,iCAAiC,KAAK,QAAQ;AAC3E,QAAM,QAAQ,WAAW,cAAc;AACvC,QAAM,2BAA2B,MAAM,IAAI;AAG3C,QAAM,EAAE,IAAI,SAAS,IAAI,MAAM,kBAAkB,OAAO,OAAO;AAG/D,MAAI,aAAa,YAAY;AAC3B,UAAM,IAAI,MAAM,8BAA8B,OAAO,EAAE;AAAA,EACzD;AAGA,QAAM,cAAc,KAAK,MAAM,UAAU,SAAS,GAAG,EAAE,OAAO;AAC9D,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,aAAa,WAAW;AAAA,EAC7C,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,YAAM,IAAI,MAAM,uBAAuB,OAAO,EAAE;AAAA,IAClD;AACA,UAAM,IAAI,MAAM,2BAA2B,EAAE,OAAO,MAAM,CAAC;AAAA,EAC7D;AAIA,QAAM,gBAAgB,eAAe,UAAU,UAAU;AACzD,MAAI,CAAC,cAAc,SAAS;AAC1B,UAAM,IAAI,MAAM,2BAA2B,EAAE,OAAO,cAAc,MAAM,CAAC;AAAA,EAC3E;AACA,QAAM,WAAW,cAAc;AAI/B,MAAI,SAAS,OAAO,IAAI;AACtB,UAAM,IAAI,MAAM,2BAA2B;AAAA,MACzC,OAAO,IAAI,MAAM,qCAAqC,EAAE,oBAAoB,SAAS,EAAE,EAAE;AAAA,IAC3F,CAAC;AAAA,EACH;AAIA,MAAI,SAAS,WAAW,WAAW;AACjC,UAAM,IAAI,MAAM,qDAAqD,SAAS,MAAM,EAAE;AAAA,EACxF;AAIA,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,UAAU,aAAa,KAAK;AAOlC,QAAM,cAAc,MAAM,YAAY,OAAO,WAAW,SAAS,UAAU;AAC3E,MAAI;AAKF,UAAM,aAAa,KAAK,MAAM,UAAU,SAAS,UAAU;AAC3D,qBAAiB,MAAM,aAAa,YAAY;AAAA,MAC9C,WAAW,CAAC,MAAM,mBAAmB,GAAG,SAAS,UAAU;AAAA,IAC7D,CAAC,GAAG;AACF,UACE,gBAAgB,EAAE,KAClB,GAAG,gBAAgB,SAAS,OAC3B,GAAG,SAAS,uBACX,GAAG,SAAS,uBACZ,GAAG,SAAS,qBACd;AACA,cAAM,IAAI,MAAM,iDAAiD,OAAO,EAAE;AAAA,MAC5E;AAAA,IACF;AAKA,QAAI,cAAc,UAAU,GAAG,GAAG;AAChC,YAAM,IAAI,MAAM,6BAA6B,OAAO,EAAE;AAAA,IACxD;AAUA,QAAI,gBAA+B;AACnC,QAAI;AACF,uBAAiB,MAAM,gBAAgB,OAAO,SAAS,UAAU,GAAG,QAAQ;AAAA,IAC9E,QAAQ;AACN,sBAAgB;AAAA,IAClB;AACA,UAAM,aACJ,kBAAkB,iBAClB,kBAAkB,aAClB,kBAAkB;AACpB,QAAI,kBAAkB,QAAQ,CAAC,YAAY;AACzC,YAAM,IAAI;AAAA,QACR,uEAAuE,aAAa,MAAM,OAAO;AAAA,MACnG;AAAA,IACF;AAKA,QAAI,aAAa,WAAW;AAC1B,YAAM,OAAQ,QAAmC,QAAQ;AACzD,YAAM,yBAAyB,OAAO,SAAS,YAAY;AAAA,QACzD,gBAAgB;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY,SAAS;AAAA,QACrB,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,aAAa,SAAS;AAAA,QACtB,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,YAAM,SAAU,QAAkC;AAClD,YAAM,yBAAyB,OAAO,SAAS,YAAY;AAAA,QACzD,gBAAgB;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY,SAAS;AAAA,QACrB,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,aAAa,SAAS;AAAA,QACtB,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,UAAE;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAGA,QAAM,mBACJ,aAAa,YACT;AAAA,IACE,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAO,QAAmC,QAAQ;AAAA,EACpD,IACA;AAAA,IACE,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,aAAa;AAAA,IACb,kBAAmB,QAAkC;AAAA,EACvD;AAMN,QAAM,eAAe,KAAK,MAAM,UAAU,UAAU,GAAG,EAAE,OAAO;AAChE,MAAI;AACF,UAAM,aAAa,cAAc,gBAAgB;AAAA,EACnD,SAAS,OAAgB;AACvB,UAAM,QAAQ,iBAAiB,QAAQ,MAAM,QAAQ;AACrD,QAAI,iBAAiB,SAAU,MAAqC,SAAS,UAAU;AACrF,YAAM,IAAI,MAAM,8CAA8C,EAAE,MAAM,CAAC;AAAA,IACzE;AACA,UAAM;AAAA,EACR;AAKA,MAAI;AACF,UAAM,OAAO,WAAW;AAAA,EAC1B,QAAQ;AACN,YAAQ;AAAA,MACN,+CAA+C,QAAQ,EAAE,CAAC;AAAA,IAC5D;AAAA,EACF;AAGA,QAAM,OAAO,aAAa,YAAY,aAAa;AACnD,UAAQ,IAAI,GAAG,IAAI,aAAa,QAAQ,EAAE,CAAC,EAAE;AAC/C;AAIA,eAAe,kBACb,OACA,OACqD;AACrD,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,QAAQ,WAAW,GAAG;AACxB,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AACA,QAAM,aAAa,QAAQ,WAAW,WAAW,IAAI,UAAU,GAAG,WAAW,GAAG,OAAO;AAGvF,MAAI,WAAW,UAAU,YAAY,QAAQ;AAC3C,UAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAAA,EAChD;AAEA,QAAM,cAAc,MAAM,mBAAmB,KAAK;AAIlD,QAAM,OAAO,oBAAI,IAA8B;AAC/C,aAAWC,OAAM,YAAY,SAAS;AACpC,QAAIA,IAAG,WAAW,UAAU,EAAG,MAAK,IAAIA,KAAI,SAAS;AAAA,EACvD;AACA,aAAWA,OAAM,YAAY,UAAU;AACrC,QAAI,CAACA,IAAG,WAAW,UAAU,EAAG;AAChC,QAAI,KAAK,IAAIA,GAAE,MAAM,WAAW;AAE9B,cAAQ,MAAM,oCAAoC,QAAQA,GAAE,CAAC,8BAA8B;AAAA,IAC7F;AACA,SAAK,IAAIA,KAAI,UAAU;AAAA,EACzB;AAEA,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAAA,EAChD;AACA,MAAI,KAAK,OAAO,GAAG;AACjB,UAAM,IAAI;AAAA,MACR,0BAA0B,KAAK,cAAc,KAAK,IAAI;AAAA,IACxD;AAAA,EACF;AACA,QAAM,QAAQ,KAAK,QAAQ,EAAE,KAAK,EAAE;AACpC,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAAA,EAChD;AACA,QAAM,CAAC,IAAI,QAAQ,IAAI;AACvB,SAAO,EAAE,IAAI,SAAS;AACxB;AAEA,SAAS,gBAAgB,IAAkD;AACzE,SACE,GAAG,SAAS,wBACZ,GAAG,SAAS,uBACZ,GAAG,SAAS,uBACZ,GAAG,SAAS;AAEhB;AAEA,SAAS,sBAAsB,SAAqC;AAIlE,QAAM,SAAS,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE;AAC/C,QAAM,WAAW,uBAAuB,MAAM;AAC9C,QAAM,OAAO,QAAQ,IAAI,CAAC,MAAM;AAC9B,UAAM,MAAM,WAAW,EAAE,SAAS,IAAI,QAAQ;AAC9C,UAAM,SAAS,EAAE,cAAc,GAAG,EAAE,SAAS,MAAM,eAAe,EAAE,SAAS;AAC7E,UAAM,OAAO,EAAE,SAAS;AACxB,UAAM,SAAS,EAAE,SAAS,OAAO;AACjC,UAAM,YAAY,EAAE,SAAS;AAC7B,UAAM,SAAS,SAAS,EAAE,SAAS,QAAQ,mBAAmB;AAC9D,WAAO,EAAE,KAAK,QAAQ,MAAM,QAAQ,WAAW,OAAO;AAAA,EACxD,CAAC;AAED,QAAM,SAAS;AAAA,IACb,KAAK;AAAA,MACH,KAAK,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,MACrB,WAAW;AAAA,IACb;AAAA,IACA,QAAQ;AAAA,MACN,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACxB,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,MACJ,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MACtB,OAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,MACN,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACxB,SAAS;AAAA,IACX;AAAA,IACA,WAAW;AAAA,MACT,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS;AAAA,MAC3B,aAAa;AAAA,IACf;AAAA,EACF;AAEA,UAAQ;AAAA,IACN,GAAG,IAAI,YAAY,OAAO,GAAG,CAAC,KAAK,IAAI,UAAU,OAAO,MAAM,CAAC,KAAK,IAAI,QAAQ,OAAO,IAAI,CAAC,KAAK,IAAI,UAAU,OAAO,MAAM,CAAC,KAAK,IAAI,cAAc,OAAO,SAAS,CAAC;AAAA,EACvK;AACA,aAAW,OAAO,MAAM;AACtB,YAAQ;AAAA,MACN,GAAG,IAAI,IAAI,KAAK,OAAO,GAAG,CAAC,KAAK,IAAI,IAAI,QAAQ,OAAO,MAAM,CAAC,KAAK,IAAI,IAAI,MAAM,OAAO,IAAI,CAAC,KAAK,IAAI,IAAI,QAAQ,OAAO,MAAM,CAAC,KAAK,IAAI,IAAI,WAAW,OAAO,SAAS,CAAC,KAAK,IAAI,MAAM;AAAA,IAC1L;AAAA,EACF;AACF;AAEA,SAAS,sBACP,UACA,WACA,QACA,aACM;AACN,UAAQ,IAAI,aAAa,SAAS,EAAE,cAAc,SAAS,MAAM,GAAG;AACpE,UAAQ,IAAI,mBAAmB,SAAS,UAAU,EAAE;AACpD,UAAQ,IAAI,mBAAmB,SAAS,UAAU,EAAE;AACpD,UAAQ,IAAI,mBAAmB,SAAS,UAAU,EAAE;AACpD,UAAQ,IAAI,mBAAmB,iBAAiB,SAAS,MAAM,CAAC,EAAE;AAClE,UAAQ,IAAI,mBAAmB,SAAS,MAAM,EAAE;AAChD,QAAM,eAAe,mBAAmB,SAAS,YAAY,WAAW;AACxE,UAAQ,IAAI,mBAAmB,YAAY,EAAE;AAC7C,UAAQ,IAAI,mBAAmB,SAAS,YAAY,QAAQ,EAAE;AAC9D,UAAQ,IAAI,mBAAmB,SAAS,eAAe,QAAQ,EAAE;AACjE,UAAQ,IAAI,mBAAmB,SAAS,QAAQ,QAAQ,EAAE;AAC1D,UAAQ,IAAI,qBAAqB,SAAS,oBAAoB,QAAQ,EAAE;AAExE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,mBAAmB,OAAO,MAAM,QAAQ;AACpD,aAAW,MAAM,QAAQ;AACvB,YAAQ,IAAI,KAAK,wBAAwB,EAAE,CAAC,EAAE;AAAA,EAChD;AACF;AAEA,SAAS,iBAAiB,QAA4D;AACpF,QAAM,SAAmB,CAAC;AAC1B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,QAAQ,OAAQ;AACpB,QAAI,OAAO,UAAU,SAAU;AAC/B,WAAO,KAAK,GAAG,GAAG,KAAK,SAAS,OAAO,yBAAyB,CAAC,GAAG;AACpE,QAAI,OAAO,UAAU,EAAG;AAAA,EAC1B;AACA,SAAO,OAAO,WAAW,IAAI,OAAO,OAAO,GAAG,OAAO,IAAI,KAAK,OAAO,KAAK,IAAI,CAAC;AACjF;AAEA,SAAS,mBAAmB,WAA0B,aAA8B;AAClF,MAAI,cAAc,KAAM,QAAO;AAC/B,SAAO,cAAc,GAAG,SAAS,eAAe;AAClD;AAEA,SAAS,wBAAwB,IAAmB;AAClD,QAAM,UAAU,qBAAqB,EAAE;AACvC,SAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,OAAO;AACjE;AAEA,SAAS,qBAAqB,IAAmB;AAC/C,UAAQ,GAAG,MAAM;AAAA,IACf,KAAK;AACH,aAAO,GAAG,GAAG,OAAO,IAAI,SAAS,GAAG,UAAU;AAAA,IAChD,KAAK;AACH,aAAO,GAAG,aAAa,SAAY,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC3D,KAAK;AACH,aAAO,GAAG,aAAa,SAAY,MAAM,GAAG,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG;AAAA,IAC5E,KAAK;AACH,aAAO,YAAY,GAAG,WAAW;AAAA,IACnC;AAEE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,QAAQ,IAAoB;AACnC,SAAO,WAAW,IAAI,iBAAiB;AACzC;AAMA,IAAM,oBAAoB,CAAC,SAAS,QAAQ,QAAQ,OAAO,SAAS,WAAW;AAE/E,SAAS,WAAW,IAAY,KAAqB;AACnD,aAAW,UAAU,mBAAmB;AACtC,QAAI,GAAG,WAAW,MAAM,GAAG;AACzB,aAAO,GAAG,MAAM,OAAO,QAAQ,OAAO,SAAS,GAAG;AAAA,IACpD;AAAA,EACF;AACA,SAAO,GAAG,MAAM,GAAG,GAAG;AACxB;AAEA,SAAS,uBAAuB,KAAgC;AAC9D,MAAI,IAAI,UAAU,EAAG,QAAO;AAC5B,WAAS,MAAM,mBAAmB,OAAO,kBAAkB,OAAO,GAAG;AACnE,UAAM,OAAO,oBAAI,IAAY;AAC7B,QAAI,WAAW;AACf,eAAW,MAAM,KAAK;AACpB,YAAM,MAAM,WAAW,IAAI,GAAG;AAC9B,UAAI,KAAK,IAAI,GAAG,GAAG;AACjB,mBAAW;AACX;AAAA,MACF;AACA,WAAK,IAAI,GAAG;AAAA,IACd;AACA,QAAI,CAAC,SAAU,QAAO;AAAA,EACxB;AACA,SAAO;AACT;AAEA,SAAS,IAAI,OAAe,OAAuB;AACjD,SAAO,MAAM,UAAU,QAAQ,QAAQ,QAAQ,IAAI,OAAO,QAAQ,MAAM,MAAM;AAChF;AAEA,SAAS,OAAO,QAA2B,OAAuB;AAChE,MAAI,MAAM;AACV,aAAW,KAAK,OAAQ,KAAI,EAAE,SAAS,IAAK,OAAM,EAAE;AACpD,SAAO;AACT;AAEA,SAAS,SAAS,OAAe,WAA2B;AAC1D,MAAI,MAAM,UAAU,UAAW,QAAO;AACtC,SAAO,GAAG,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC;AACzC;AAEA,eAAe,iCACb,KACA,QACiB;AACjB,MAAI;AACF,WAAO,MAAM,sBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR,2EAA2E,MAAM;AAAA,QACjF,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAe,2BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAM,oBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAI,cAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,kBAAkB,OAAwB;AACjD,MAAI,iBAAiB,OAAO;AAC1B,QAAI,MAAM,YAAY,sBAAuB,QAAO;AACpD,QAAI,MAAM,YAAY,+BAAgC,QAAO;AAC7D,WAAO,MAAM;AAAA,EACf;AACA,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,oBAAoB,KAA6B;AACxD,QAAM,SAAS,qBAAqB,UAAU,GAAG;AACjD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,4BAA4B,GAAG,mBAAmB,cAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EAC9F;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,iBAAiB,SAAoC;AAC5D,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,IAAI;AAAA,EAClB,OAAO;AACL,YAAQ,IAAI,qBAAqB;AAAA,EACnC;AACF;;;ACnyBA,SAAS,gBAAgB;AACzB,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAAC,gBAAe;AACxB;AAAA,EACE,eAAAC;AAAA,EACA;AAAA,EACA,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EAEA,iBAAAC;AAAA,EACA;AAAA,EAEA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAuB,4BAA4B;;;ACpBnD,SAAS,UAAU,YAAY;AAC/B,SAAS,UAAU,WAAAC,gBAAe;AAClC,SAAS,cAAAC,aAAY,cAAc,kCAAkC;;;ACFrE,SAAS,eAAe;AACxB,SAAS,YAAY,QAAAC,OAAM,eAAe;AAC1C,SAAS,gBAAAC,qBAAoB;AAoBtB,IAAM,gCAAgCD,MAAK,QAAQ,GAAG,UAAU,gBAAgB;AAGvF,SAAS,YAAY,GAAmB;AACtC,MAAI,MAAM,IAAK,QAAO,QAAQ;AAC9B,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOA,MAAK,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,SAAO;AACT;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AASA,eAAsB,oBACpB,aAAqB,+BACU;AAC/B,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,cAAa,UAAU;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB,SAAS,MAAM,YAAY,gCAAgC;AAC9E,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,UAAM;AAAA,EACR;AAEA,MAAI,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,QAAQ,IAAI,UAAU,GAAG;AACpD,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAA+B,CAAC;AACtC,aAAW,SAAS,IAAI,YAAY;AAClC,QAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,EAAE,WAAW,GAAG;AACxF,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC7E;AACA,QAAI,MAAM,UAAU,UAAa,OAAO,MAAM,UAAU,UAAU;AAChE,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AACA,UAAM,WAAW,YAAY,MAAM,KAAK,KAAK,CAAC;AAC9C,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,QAAQ,QAAQ;AAC5B,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,WAAO,KAAK,MAAM,UAAU,SAAY,EAAE,MAAM,KAAK,OAAO,MAAM,MAAM,IAAI,EAAE,MAAM,IAAI,CAAC;AAAA,EAC3F;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,SAAO;AACT;;;ADxDA,eAAsB,2BACpB,KACA,aACA,OAA2B,CAAC,GACX;AACjB,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,2BAA2B,KAAK;AAAA,MAC3C,YAAY,CAAC,EAAE,KAAK,MAAAC,MAAK,MACvB,QAAQ,MAAM,8BAA8BA,KAAI,SAAS,GAAG,IAAI;AAAA,IACpE,CAAC;AAAA,EACH,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR,kEAAkE,WAAW;AAAA,QAC7E,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAOA,MAAI,CAAE,MAAM,cAAc,IAAI,GAAI;AAChC,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA,KAAK,uBAAuB;AAAA,IAC9B;AACA,QAAI,WAAW,QAAW;AACxB,cAAQ;AAAA,QACN,gCAAgC,OAAO,IAAI,oBAAoB,OAAO,KAAK;AAAA,MAC7E;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAGA,eAAe,cAAc,MAAgC;AAC3D,MAAI;AACF,YAAQ,MAAM,KAAKC,YAAW,IAAI,EAAE,IAAI,GAAG,YAAY;AAAA,EACzD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA6BA,eAAsB,sBACpB,UACA,YACmC;AACnC,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,oBAAoB,UAAU;AAAA,EACnD,SAAS,OAAgB;AAIvB,QAAI,EAAE,iBAAiB,UAAU,CAAC,MAAM,QAAQ,WAAW,wBAAwB,GAAG;AACpF,YAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,cAAQ,MAAM,qCAAqC,MAAM,EAAE;AAAA,IAC7D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,eAAe,QAAQ;AAChD,MAAI,eAAe,KAAM,QAAO;AAKhC,QAAM,YAAY,oBAAI,IAA0B;AAChD,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,MAAM,YAAY;AAC3B,UAAM,aAAa,MAAM,eAAe,GAAG,IAAI;AAC/C,QAAI,eAAe,KAAM;AACzB,QAAI,eAAe,WAAY;AAC/B,QAAI,WAAW,IAAI,UAAU,EAAG;AAChC,eAAW,IAAI,UAAU;AACzB,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,aAAaA,YAAW,UAAU,CAAC;AAAA,IACtD,SAAS,OAAgB;AAKvB,UAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,gBAAQ;AAAA,UACN,iCAAiC,GAAG,SAAS,SAAS,UAAU,CAAC,mCAAmC,MAAM,OAAO;AAAA,QACnH;AAAA,MACF;AACA;AAAA,IACF;AAGA,UAAM,cAAc,SAAS,QAAQ,gBAAgB,CAAC,GAAG;AACzD,eAAW,MAAM,aAAa;AAC5B,YAAM,OAAO,MAAM,eAAeC,SAAQ,YAAY,EAAE,CAAC;AACzD,UAAI,SAAS,QAAQ,SAAS,YAAY;AACxC,kBAAU,IAAI,YAAY,EAAE,MAAM,YAAY,OAAO,GAAG,SAAS,SAAS,UAAU,EAAE,CAAC;AACvF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,GAAG,UAAU,OAAO,CAAC;AACtC,MAAI,QAAQ,WAAW,EAAG,QAAO,QAAQ,CAAC;AAC1C,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI;AACnD,UAAM,IAAI;AAAA,MACR,mDAAmD,QAAQ,MAAM,0BAA0B,KAAK;AAAA,IAClG;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,eAAe,GAAmC;AAC/D,MAAI;AACF,WAAO,MAAM,SAAS,CAAC;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADxJA,IAAM,kBAAkB;AACxB,IAAM,sBAAsB,kBAAkB;AA0BvC,SAAS,wBAAwBC,UAAwB;AAC9D,QAAM,WAAWA,SACd,QAAQ,UAAU,EAClB,YAAY,2CAA2C;AAE1D,WACG,QAAQ,QAAQ,EAChB,YAAY,kCAAkC,EAC9C,eAAe,kBAAkB,kBAAkB,UAAU,EAC7D,OAAO,sBAAsB,8BAA8B,cAAc,EACzE;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAmC;AAChD,UAAM,kBAAkB,OAAO;AAAA,EACjC,CAAC;AAEH,WACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EAIF,EACC,OAAO,iBAAiB,kDAAkD,EAC1E,OAAO,aAAa,yDAAyD,EAC7E,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,YAAY,SAAS,YAAY,EACjC,OAAO,OAAO,YAAoC;AACjD,UAAM,mBAAmB,OAAO;AAAA,EAClC,CAAC;AACL;AAEA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BrB,eAAsB,kBACpB,SACA,MAAuB,CAAC,GACT;AACf,MAAI;AACF,UAAM,oBAAoB,SAAS,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,mBAAe,OAAO;AAAA,MACpB,SAAS,UAAU,OAAO;AAAA,MAC1B,aAAa,CAAC,0BAA0B;AAAA,IAC1C,CAAC;AACD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,oBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,iCAAiC,GAAG;AACjE,QAAM,QAAQC,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,aAAaC,cAAa,UAAU;AAE1C,QAAM,OAAO,eAAe,OAAO;AAEnC,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,YAAY,MAAM,iBAAiB,OAAO,QAAQ,OAAO;AAC/D,UAAM,QAAQ;AAMd,UAAM,cAAc,MAAMC,aAAY,OAAO,WAAW,KAAK;AAC7D,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,6BAA6B;AAAA,QAC1C;AAAA,QACA,WAAW;AAAA,QACX,cAAc,CAAC,YACb,mBAAmB;AAAA,UACjB;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA,OAAO,QAAQ;AAAA,UACf;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACL,CAAC;AAAA,IACH,UAAE;AACA,YAAM,YAAY,QAAQ;AAAA,IAC5B;AACA,wBAAoB,SAAS;AAAA,MAC3B,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,eAAe,OAAO;AAAA,MACtB,OAAO,QAAQ;AAAA,MACf;AAAA,IACF,CAAC;AACD;AAAA,EACF;AAEA,QAAM,WAAW,MAAMC,cAAa,KAAK;AACzC,QAAM,QAAQ,MAAM,4BAA4B;AAAA,IAC9C;AAAA,IACA;AAAA,IACA,OAAO,gBAAgB,QAAQ,KAAK;AAAA,IACpC;AAAA,IACA,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,YAAY;AAAA,MACV,SAAS;AAAA,MACT,MAAM,CAAC,WAAW,QAAQ,KAAK;AAAA,IACjC;AAAA,IACA,qBAAqB;AAAA,MACnB,CAAC,WAAW,YACV,mBAAmB;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,QAAQ;AAAA,QACf;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACL;AAAA,EACF,CAAC;AACD,sBAAoB,SAAS;AAAA,IAC3B,MAAM;AAAA,IACN,WAAW,MAAM;AAAA,IACjB;AAAA,IACA,SAAS,MAAM,eAAe,CAAC;AAAA,IAC/B,eAAe;AAAA,IACf,OAAO,QAAQ;AAAA,IACf;AAAA,EACF,CAAC;AACH;AA+BA,eAAsB,mBACpB,SACA,MAA8B,CAAC,GAChB;AACf,MAAI;AACF,UAAM,qBAAqB,SAAS,GAAG;AAAA,EACzC,SAAS,OAAgB;AAKvB,mBAAe,OAAO;AAAA,MACpB,SAAS,UAAU,OAAO;AAAA,MAC1B,aAAa,CAAC,0BAA0B;AAAA,IAC1C,CAAC;AACD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,qBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AAMnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,kBAAkB;AAC/E,QAAM,QAAQJ,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,MAAM,MAAM,iBAAiB,SAAS,GAAG;AAC/C,QAAM,YAAY,kBAAkB,GAAG;AAEvC,MAAI,QAAQ,WAAW,MAAM;AAC3B,wBAAoB,SAAS,SAAS;AACtC;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AAKnC,QAAM,cAAc,UAAU,IAAI,MAAMC,cAAa,UAAU,CAAC;AAEhE,QAAM,WAAW,MAAME,cAAa,KAAK;AAMzC,QAAM,iBACJ,QAAQ,SAAS,SACb;AAAA,IACE;AAAA,IACA,aAAaC,SAAQ,KAAK,QAAQ,IAAI,GAAG;AAAA,MACvC,kBAAkB;AAAA,MAClB,SAASC,SAAQ;AAAA,IACnB,CAAC;AAAA,EACH,IACA,CAAC;AACP,QAAM,QAAQ,MAAM,4BAA4B;AAAA,IAC9C;AAAA,IACA;AAAA,IACA,OAAO,kBAAkB,UAAU,MAAM;AAAA,IACzC;AAAA,IACA,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,YAAY;AAAA,MACV,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,qBAAqB,UAAU;AAAA,MAC7B,CAAC,UAAU,UACT,CAAC,WAA8B,YAC7B,mBAAmB;AAAA,QACjB;AAAA,QACA;AAAA,QACA,YAAY,YAAY,KAAK;AAAA,QAC7B,OAAO,SAAS;AAAA,QAChB;AAAA,QACA,MAAM,aAAa,QAAQ;AAAA,MAC7B,CAAC;AAAA,IACP;AAAA,EACF,CAAC;AAED,qBAAmB,SAAS;AAAA,IAC1B,WAAW,MAAM;AAAA,IACjB,OAAO,UAAU,IAAI,CAAC,UAAU,WAAW;AAAA,MACzC,YAAY,YAAY,KAAK;AAAA,MAC7B,SAAS,MAAM,eAAe,KAAK;AAAA,MACnC,OAAO;AAAA,IACT,EAAE;AAAA,EACJ,CAAC;AACH;AAEA,eAAe,iBACb,SACA,KACiB;AACjB,MAAI,QAAQ,SAAS,QAAW;AAC9B,QAAI;AACF,aAAO,MAAM,SAAS,QAAQ,MAAM,MAAM;AAAA,IAC5C,SAAS,OAAgB;AACvB,UAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,cAAM,IAAI,MAAM,yBAAyB,QAAQ,IAAI,EAAE;AAAA,MACzD;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,IAAI,cAAc,QAAW;AAC/B,WAAO,MAAM,IAAI,UAAU;AAAA,EAC7B;AAGA,MAAI,QAAQ,MAAM,UAAU,MAAM;AAChC,UAAM,IAAI,MAAM,aAAa;AAAA,EAC/B;AACA,SAAO,MAAM,eAAe;AAC9B;AAEA,eAAe,iBAAkC;AAC/C,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAO;AACvC,WAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,EAChC;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,IAAM,gBAAgB;AAEtB,IAAM,uBAA4C,oBAAI,IAAI;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOD,SAAS,kBAAkB,KAAqC;AAC9D,MAAI,IAAI,KAAK,EAAE,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,aAAa;AAAA,EAC/B;AACA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,OAAgB;AACvB,UAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,UAAM,IAAI,MAAM,4BAA4B,MAAM,EAAE;AAAA,EACtD;AACA,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,SAAO,OAAO,IAAI,CAAC,MAAM,UAAU,oBAAoB,MAAM,KAAK,CAAC;AACrE;AAEA,SAAS,oBAAoB,MAAe,OAAqC;AAC/E,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpE,UAAM,IAAI,MAAM,YAAY,KAAK,0BAA0B;AAAA,EAC7D;AACA,QAAM,MAAM;AACZ,aAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,QAAI,CAAC,qBAAqB,IAAI,GAAG,GAAG;AAClC,YAAM,IAAI;AAAA,QACR,YAAY,KAAK,qBAAqB,GAAG;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,IAAI,UAAU,YAAY,QAAQ,IAAI,KAAK,GAAG;AACvD,UAAM,IAAI,MAAM,YAAY,KAAK,qCAAqC;AAAA,EACxE;AACA,QAAM,MAA4B,EAAE,OAAO,IAAI,MAAM;AACrD,MAAI,IAAI,cAAc,QAAW;AAC/B,QAAI,YAAY,sBAAsB,IAAI,WAAW,OAAO,WAAW;AAAA,EACzE;AACA,MAAI,IAAI,oBAAoB,QAAW;AACrC,QAAI,kBAAkB,sBAAsB,IAAI,iBAAiB,OAAO,iBAAiB;AAAA,EAC3F;AACA,MAAI,IAAI,iBAAiB,QAAW;AAClC,QAAI,eAAe,oBAAoB,IAAI,cAAc,OAAO,gBAAgB,CAAC,OAAO,MAAM;AAC5F,UAAI,QAAQ,KAAK,GAAG;AAClB,cAAM,IAAI,MAAM,YAAY,KAAK,kBAAkB,CAAC,sBAAsB;AAAA,MAC5E;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,IAAI,kBAAkB,QAAW;AACnC,QAAI,gBAAgB;AAAA,MAClB,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,CAAC,OAAO,MAAM;AACZ,YAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,gBAAM,IAAI;AAAA,YACR,YAAY,KAAK,mBAAmB,CAAC,iCAAiC,KAAK;AAAA,UAC7E;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,IAAI,iBAAiB,QAAW;AAClC,QAAI,eAAe,oBAAoB,IAAI,cAAc,OAAO,gBAAgB,CAAC,OAAO,MAAM;AAC5F,UAAI,QAAQ,KAAK,GAAG;AAClB,cAAM,IAAI,MAAM,YAAY,KAAK,kBAAkB,CAAC,sBAAsB;AAAA,MAC5E;AACA,UAAI,MAAM,SAAS,MAAM;AACvB,cAAM,IAAI,MAAM,YAAY,KAAK,kBAAkB,CAAC,uBAAuB;AAAA,MAC7E;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,OAAgB,OAAe,OAAuB;AACnF,MAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,GAAG;AAC/C,UAAM,IAAI,MAAM,YAAY,KAAK,KAAK,KAAK,8BAA8B;AAAA,EAC3E;AACA,SAAO;AACT;AAKA,SAAS,QAAQ,OAAwB;AACvC,SAAO,MAAM,KAAK,EAAE,WAAW;AACjC;AAEA,SAAS,oBACP,OACA,OACA,OACA,WACU;AACV,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,UAAM,IAAI,MAAM,YAAY,KAAK,KAAK,KAAK,+BAA+B;AAAA,EAC5E;AACA,SAAO,MAAM,IAAI,CAAC,OAAO,MAAM;AAC7B,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,IAAI,MAAM,YAAY,KAAK,KAAK,KAAK,IAAI,CAAC,qBAAqB;AAAA,IACvE;AACA,cAAU,OAAO,CAAC;AAClB,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,aAAa,UAAoD;AACxE,QAAM,MAA0B,CAAC;AACjC,MAAI,SAAS,cAAc,OAAW,KAAI,YAAY,SAAS;AAC/D,MAAI,SAAS,oBAAoB,OAAW,KAAI,kBAAkB,SAAS;AAC3E,MAAI,SAAS,iBAAiB,OAAW,KAAI,eAAe,CAAC,GAAG,SAAS,YAAY;AACrF,MAAI,SAAS,kBAAkB,OAAW,KAAI,gBAAgB,CAAC,GAAG,SAAS,aAAa;AACxF,MAAI,SAAS,iBAAiB,OAAW,KAAI,eAAe,CAAC,GAAG,SAAS,YAAY;AACrF,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAuB;AAChD,SAAO,mBAAmB,KAAK,YAAY,UAAU,IAAI,KAAK,GAAG;AACnE;AAIA,SAAS,qBAAqB,MAAkD;AAC9E,QAAM,UAAmC;AAAA,IACvC,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,IACf,OAAO,KAAK,MAAM;AAAA,EACpB;AACA,MAAI,KAAK,MAAM,cAAc,OAAW,SAAQ,YAAY,KAAK,MAAM;AACvE,MAAI,KAAK,MAAM,iBAAiB,OAAW,SAAQ,eAAe,KAAK,MAAM;AAC7E,MAAI,KAAK,MAAM,oBAAoB;AACjC,YAAQ,kBAAkB,KAAK,MAAM;AACvC,MAAI,KAAK,MAAM,kBAAkB,OAAW,SAAQ,gBAAgB,KAAK,MAAM;AAC/E,MAAI,KAAK,MAAM,iBAAiB,OAAW,SAAQ,eAAe,KAAK,MAAM;AAC7E,SAAO;AACT;AAEA,SAAS,oBACP,SACA,WACM;AACN,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,EAAE,SAAS,MAAM,OAAO,UAAU,QAAQ,UAAU,CAAC,CAAC;AACjF;AAAA,EACF;AACA,UAAQ;AAAA,IACN,iBAAiB,UAAU,MAAM,YAAY,UAAU,WAAW,IAAI,KAAK,GAAG;AAAA,EAChF;AACA,aAAW,YAAY,WAAW;AAChC,YAAQ,IAAI,KAAK,SAAS,KAAK,EAAE;AAAA,EACnC;AACF;AAEA,SAAS,mBACP,SACA,QACM;AACN,QAAM,MAAM,eAAe,OAAO,SAAS;AAC3C,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,MAAM;AAAA,QACN,YAAY,OAAO;AAAA,QACnB,gBAAgB;AAAA,QAChB,OAAO,OAAO,MAAM;AAAA,QACpB,WAAW,OAAO,MAAM,IAAI,oBAAoB;AAAA,MAClD,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,UAAQ;AAAA,IACN,YAAY,OAAO,MAAM,MAAM,YAAY,OAAO,MAAM,WAAW,IAAI,KAAK,GAAG,sBAAsB,GAAG;AAAA,EAC1G;AACA,aAAW,QAAQ,OAAO,OAAO;AAC/B,YAAQ,IAAI,KAAK,KAAK,UAAU,KAAK,KAAK,MAAM,KAAK,EAAE;AAAA,EACzD;AACF;AAUA,SAAS,eAAe,SAAoD;AAC1E,QAAM,MAA0B,CAAC;AACjC,MAAI,QAAQ,cAAc,OAAW,KAAI,YAAY,QAAQ;AAC7D,MAAI,QAAQ,mBAAmB,OAAW,KAAI,kBAAkB,QAAQ;AACxE,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,YAAY,SAAS,GAAG;AACvE,QAAI,eAAe,CAAC,GAAG,QAAQ,WAAW;AAAA,EAC5C;AACA,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,YAAY,SAAS,GAAG;AACvE,QAAI,gBAAgB,CAAC,GAAG,QAAQ,WAAW;AAAA,EAC7C;AACA,MAAI,QAAQ,eAAe,UAAa,QAAQ,WAAW,SAAS,GAAG;AACrE,QAAI,eAAe,CAAC,GAAG,QAAQ,UAAU;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAOlB;AACR,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,IAAI,MAAM;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,aAAa,MAAM;AAAA,IACnB,OAAO,MAAM;AAAA,IACb,GAAI,MAAM,KAAK,cAAc,SAAY,EAAE,WAAW,MAAM,KAAK,UAAU,IAAI,CAAC;AAAA,IAChF,GAAI,MAAM,KAAK,iBAAiB,SAAY,EAAE,cAAc,MAAM,KAAK,aAAa,IAAI,CAAC;AAAA,IACzF,GAAI,MAAM,KAAK,oBAAoB,SAC/B,EAAE,iBAAiB,MAAM,KAAK,gBAAgB,IAC9C,CAAC;AAAA,IACL,GAAI,MAAM,KAAK,kBAAkB,SAC7B,EAAE,eAAe,MAAM,KAAK,cAAwC,IACpE,CAAC;AAAA,IACL,GAAI,MAAM,KAAK,iBAAiB,SAAY,EAAE,cAAc,MAAM,KAAK,aAAa,IAAI,CAAC;AAAA,EAC3F;AACF;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,QAAM,YACJ,MAAM,SAAS,kBAAkB,GAAG,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ;AACjF,SAAO,oBAAoB,SAAS;AACtC;AAEA,SAAS,WAAW,KAAqB;AACvC,MAAI,QAAQ,GAAG,GAAG;AAChB,UAAM,IAAI,qBAAqB,yBAAyB;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAqB;AAC3C,MAAI,QAAQ,GAAG,GAAG;AAChB,UAAM,IAAI,qBAAqB,6BAA6B;AAAA,EAC9D;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAqB;AAChD,MAAI,QAAQ,GAAG,GAAG;AAChB,UAAM,IAAI,qBAAqB,mCAAmC;AAAA,EACpE;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAe,MAA0B;AACnE,MAAI,QAAQ,KAAK,GAAG;AAClB,UAAM,IAAI,qBAAqB,+BAA+B;AAAA,EAChE;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;AASA,SAAS,eAAe,OAAwB;AAC9C,SAAO,kBAAkB,KAAK,KAAK,MAAM,WAAW,MAAM;AAC5D;AAEA,SAAS,mBAAmB,OAAe,MAA0B;AACnE,MAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,UAAM,IAAI,qBAAqB,+CAA+C,KAAK,GAAG;AAAA,EACxF;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;AAEA,SAAS,kBAAkB,OAAe,MAA0B;AAClE,MAAI,QAAQ,KAAK,GAAG;AAClB,UAAM,IAAI,qBAAqB,oCAAoC;AAAA,EACrE;AACA,MAAI,MAAM,SAAS,MAAM;AACvB,UAAM,IAAI,qBAAqB,qCAAqC;AAAA,EACtE;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;AAYA,SAAS,oBAAoB,SAAgC,QAAkC;AAC7F,QAAM,MAAM,eAAe,OAAO,SAAS;AAC3C,MAAI,QAAQ,SAAS,MAAM;AACzB,UAAM,UAAmC;AAAA,MACvC,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,YAAY,OAAO;AAAA,MACnB,gBAAgB,OAAO;AAAA,MACvB,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,IAChB;AAIA,QAAI,OAAO,KAAK,cAAc,OAAW,SAAQ,YAAY,OAAO,KAAK;AACzE,QAAI,OAAO,KAAK,iBAAiB,OAAW,SAAQ,eAAe,OAAO,KAAK;AAC/E,QAAI,OAAO,KAAK,oBAAoB,QAAW;AAC7C,cAAQ,kBAAkB,OAAO,KAAK;AAAA,IACxC;AACA,QAAI,OAAO,KAAK,kBAAkB,OAAW,SAAQ,gBAAgB,OAAO,KAAK;AACjF,QAAI,OAAO,KAAK,iBAAiB,OAAW,SAAQ,eAAe,OAAO,KAAK;AAC/E,YAAQ,IAAI,KAAK,UAAU,OAAO,CAAC;AACnC;AAAA,EACF;AACA,QAAM,kBACJ,OAAO,KAAK,cAAc,SAAY,gBAAgB,OAAO,KAAK,SAAS,MAAM;AACnF,MAAI,OAAO,SAAS,UAAU;AAC5B,YAAQ,IAAI,YAAY,OAAO,UAAU,sBAAsB,GAAG,GAAG,eAAe,EAAE;AAAA,EACxF,OAAO;AACL,YAAQ;AAAA,MACN,YAAY,OAAO,UAAU,eAAe,GAAG,KAAK,OAAO,aAAa,IAAI,eAAe;AAAA,IAC7F;AAAA,EACF;AACF;AAEA,eAAe,iCAAiC,KAA8B;AAC5E,MAAI;AACF,WAAO,MAAMC,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,QACA,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeP,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMQ,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIF,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;AG3xBA;AAAA,EACE,uBAAAG;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EACA;AAAA,OACK;AAiBA,SAAS,yBAAyBC,UAAwB;AAC/D,QAAM,YAAYA,SACf,QAAQ,WAAW,EACnB,YAAY,yCAAyC;AAExD,YACG,QAAQ,UAAU,EAClB,YAAY,8DAA8D,EAC1E,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAmC;AAChD,UAAM,qBAAqB,IAAI;AAAA,EACjC,CAAC;AACL;AAEA,eAAsB,qBACpB,SACA,MAAwB,CAAC,GACV;AACf,MAAI;AACF,UAAM,uBAAuB,SAAS,GAAG;AAAA,EAC3C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,uBACpB,SACA,KACe;AACf,OAAK;AACL,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,kCAAkC,GAAG;AAClE,QAAM,QAAQC,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAC/D,QAAM,SAAS,MAAM,gBAAgB;AAAA,IACnC;AAAA,IACA;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,EAC9D,CAAC;AAED,QAAM,WAAW,MAAM,iBAAiB,MAAM,MAAM,SAAS;AAC7D,QAAM,YAAY,kBAAkB,UAAU,OAAO,MAAM,cAAc;AACzE,QAAM,kBAAkB,MAAM,MAAM,WAAW,SAAS;AAExD,UAAQ,IAAI,6CAA6C,OAAO,aAAa,GAAG;AAClF;AAEA,eAAe,kCAAkC,KAA8B;AAC7E,MAAI;AACF,WAAO,MAAMC,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,QACA,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeD,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAME,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;ACnGA,SAAS,aAAa;AACtB,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAErB;AAAA,EACE,eAAAC;AAAA,EACA,uBAAAC;AAAA,EAEA,cAAAC;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA,gBAAAC;AAAA,EAEA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,yBAAAC;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAwCA,SAAS,oBAAoBC,UAAwB;AAC1D,EAAAA,SACG,QAAQ,0BAA0B,EAClC,YAAY,oDAAoD,EAKhE,mBAAmB,EACnB,OAAO,wBAAwB,uDAAuD,EACtF,OAAO,iBAAiB,4CAA4C,EACpE,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAiB,MAAgB,YAAyB;AACvE,QAAI;AACF,YAAM,WAAW,MAAM,QAAQ,SAAS,MAAM,OAAO;AACrD,cAAQ,KAAK,QAAQ;AAAA,IACvB,SAAS,OAAgB;AACvB,qBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;AAEA,eAAsB,QACpB,SACA,MACA,SACA,MAAmB,CAAC,GACH;AACjB,QAAM,SAAS,IAAI,UAAU,IAAI,mBAAmB;AACpD,QAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AAGvC,QAAM,aAAa,QAAQ,YAAY,SAAY,cAAc,QAAQ,OAAO,IAAI;AAIpF,QAAM,WAAW,MAAM,6BAA6B,GAAG;AACvD,QAAM,QAAQC,YAAW,QAAQ;AAGjC,QAAMC,qBAAoB,MAAM,IAAI;AAGpC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAGzC,QAAM,YAAYC,cAAa,KAAK;AACpC,QAAM,aAAaC,MAAK,MAAM,UAAU,SAAS;AACjD,QAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAK3C,QAAM,cACJ,IAAI,gBACH,OAAO,aAAa,UAAU;AAC7B,UAAM,uBAAuB,OAAO,WAAW,KAAK;AAAA,EACtD;AAEF,QAAM,YAAY,IAAI,EAAE,YAAY;AACpC,QAAM,kBAAkBA,MAAK,YAAY,cAAc;AACvD,QAAM,UAAU,oBAAoB;AAAA,IAClC,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,SAAS,UAAU;AAAA,IAChC;AAAA,EACF,CAAC;AACD,QAAM,cAAc,iBAAiB,OAAO;AAG5C,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAID,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,EACV,CAAC;AAGD,MAAI,QAAQ,aAAa,OAAO;AAC9B,UAAM,qBAAqB,YAAY,WAAW,UAAU,KAAK,WAAW;AAAA,EAC9E;AAGA,QAAM,YAAY,IAAI,EAAE,YAAY;AACpC,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AAGD,QAAM,cAAc,MAAME,aAAY,OAAO,WAAW,SAAS;AACjE,MAAI;AACF,UAAM,kBAAkB,iBAAiB,CAAC,MAAM;AAC9C,QAAE,QAAQ,SAAS;AAAA,IACrB,CAAC;AAAA,EACH,UAAE;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAIA,QAAM,aAAa,IAAI,gBAAgB;AACvC,MAAI,iBAAwC;AAC5C,MAAI,cAAmC;AACvC,QAAM,gBAAgB,CAAC,QAAwB;AAC7C,QAAI,mBAAmB,KAAM;AAC7B,qBAAiB;AACjB,eAAW,MAAM;AAAA,EACnB;AACA,QAAM,cAAc,MAAM;AACxB,QAAI,gBAAgB,MAAM;AACxB,UAAI;AACF,oBAAY,KAAK,SAAS;AAAA,MAC5B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,MAAM,cAAc,QAAQ;AAC7C,QAAM,YAAY,MAAM,cAAc,SAAS;AAC/C,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,SAAS;AAC/B,UAAQ,GAAG,QAAQ,WAAW;AAG9B,MAAI,sBAAsB,WAAW;AAErC,MAAI;AACJ,MAAI;AACF,QAAI;AACF,eAAS,MAAM,OAAO,IAAI,SAAS,MAAM;AAAA,QACvC;AAAA,QACA,SAAS;AAAA,QACT,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,QACjD,QAAQ,WAAW;AAAA,QACnB,SAAS,CAAC,UAAU;AAClB,wBAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAAA,IACH,SAAS,YAAqB;AAI5B,YAAM,wBAAwB,OAAO,YAAY,WAAW,aAAa;AAAA,QACvE;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,IAAI,EAAE,YAAY;AAAA,QAC9B;AAAA,MACF,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF,UAAE;AACA,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,SAAS;AAChC,YAAQ,IAAI,QAAQ,WAAW;AAC/B,kBAAc;AAAA,EAChB;AAEA,QAAM,UAAU,IAAI,EAAE,YAAY;AAGlC,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIF,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,GAAI,OAAO,WAAW,OAAO,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IAC1D,GAAI,mBAAmB,OAAO,EAAE,iBAAiB,eAAe,IAAI,CAAC;AAAA,IACrE,aAAa,OAAO;AAAA,EACtB,CAAC;AAID,MAAI,QAAQ,aAAa,OAAO;AAC9B,UAAM,qBAAqB,YAAY,WAAW,UAAU,KAAK,WAAW;AAAA,EAC9E;AAEA,QAAM,cAAc,kBAAkB,QAAQ,cAAc;AAG5D,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AAGD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,GAAI,OAAO,cAAc,OAAO,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,EACrE,CAAC;AAMD,QAAM,oBAAoB,OAAO,WAAW,CAAC,MAAM;AACjD,MAAE,QAAQ,SAAS;AACnB,MAAE,QAAQ,WAAW;AACrB,MAAE,QAAQ,WAAW,YAAY,OAAO;AAAA,EAC1C,CAAC;AAED,MAAI,OAAO,cAAc,MAAM;AAC7B,WAAO,OAAO;AAAA,EAChB;AACA,SAAO,iBAAiB,kBAAkB,OAAO,MAAM;AACzD;AAEA,SAAS,kBACP,QACA,gBACwC;AACxC,MAAI,mBAAmB,YAAY,mBAAmB,UAAW,QAAO;AACxE,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,aAAa,OAAO,WAAW,WAAW;AAC5F,WAAO;AAAA,EACT;AACA,MAAI,OAAO,cAAc,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,IAAM,aAAqC;AAAA,EACzC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAAS,iBAAiB,KAAoC;AAC5D,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,MAAM,WAAW,GAAG,KAAK;AAC/B,SAAO,MAAM;AACf;AAEA,eAAe,qBACb,YACA,WACA,UACA,KACA,aACe;AAKf,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,YAAY,QAAQ;AAAA,EACvC,SAAS,OAAgB;AACvB,YAAQ,KAAK,gCAAgC,KAAK,CAAC;AACnD;AAAA,EACF;AAOA,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI,EAAE,YAAY;AAAA,IAC/B,QAAQ;AAAA,IACR,GAAG;AAAA,EACL,CAAC;AACH;AAEA,SAAS,gCAAgC,OAAwB;AAC/D,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,WAAO,yBAAyB,OAAO,KAAK,CAAC;AAAA,EAC/C;AACA,QAAM,MAAM,MAAM;AAClB,MAAI,QAAQ,wBAAwB;AAClC,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,wDAAwD;AAClE,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,4BAA4B;AACtC,WAAO;AAAA,EACT;AACA,SAAO,yBAAyB,GAAG;AACrC;AAEA,SAAS,oBAAoB,OAOjB;AACV,QAAM,UAAU,CAAC,MAAM,SAAS,GAAG,MAAM,IAAI,EAAE,KAAK,GAAG;AACvD,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,SAAS;AAAA,MACP,IAAI,MAAM;AAAA,MACV,OAAO,cAAc,OAAO,KAAK,MAAM,SAAS;AAAA,MAChD,SAAS;AAAA,MACT,cAAc,MAAM;AAAA,MACpB,QAAQ,EAAE,MAAM,YAAY,SAAS,QAAQ;AAAA,MAC7C,YAAY,MAAM;AAAA,MAClB,QAAQ;AAAA,MACR,mBAAmB,yBAAyB,MAAM,KAAK,EAAE,SAASG,SAAQ,EAAE,CAAC;AAAA,MAC7E,YAAY;AAAA,QACV,SAAS,MAAM;AAAA,QACf,MAAM,CAAC,GAAG,MAAM,IAAI;AAAA,QACpB,WAAW;AAAA,MACb;AAAA,MACA,eAAe,CAAC;AAAA,MAChB,YAAY;AAAA,IACd;AAAA,EACF;AACF;AAEA,eAAe,kBACb,UACA,SACe;AACf,QAAM,MAAM,MAAMC,cAAa,QAAQ;AACvC,QAAM,SAAS,cAAc,MAAM,GAAG;AACtC,UAAQ,MAAM;AAEd,QAAM,YAAY,cAAc,MAAM,MAAM;AAC5C,QAAM,kBAAkB,UAAU,SAAS;AAC7C;AAEA,eAAe,wBACb,OACA,YACA,WACA,aACA,KAOe;AACf,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIJ,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ;AAAA,IACR,SAAS,IAAI;AAAA,IACb,MAAM,IAAI;AAAA,IACV,KAAK,IAAI;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,GAAI,IAAI,mBAAmB,OAAO,EAAE,iBAAiB,IAAI,eAAe,IAAI,CAAC;AAAA,IAC7E,aAAa;AAAA,EACf,CAAC;AACD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AACD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,oBAAoB,OAAO,WAAW,CAAC,MAAM;AACjD,MAAE,QAAQ,SAAS;AACnB,MAAE,QAAQ,WAAW,IAAI;AACzB,MAAE,QAAQ,WAAW,YAAY;AAAA,EACnC,CAAC;AACH;AAEA,eAAe,6BAA6B,KAA8B;AACxE,MAAI;AACF,WAAO,MAAMK,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,yEAAyE;AAAA,QACvF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;;;AC5eA;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EACA,qBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,qBAAAC;AAAA,OACK;AAwBA,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,UAAUA,SAAQ,QAAQ,SAAS,EAAE,YAAY,uCAAuC;AAE9F,UACG,QAAQ,UAAU,EAClB,YAAY,yDAAyD,EACrE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAiC;AAC9C,UAAM,mBAAmB,IAAI;AAAA,EAC/B,CAAC;AACL;AAMA,eAAsB,mBACpB,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,qBAAqB,SAAS,GAAG;AAAA,EACzC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAMA,eAAsB,qBACpB,SACA,KACe;AACf,OAAK;AACL,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,GAAG;AAChE,QAAM,QAAQC,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAC/D,QAAM,SAAS,MAAM,cAAc;AAAA,IACjC;AAAA,IACA;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,IAC5D,YAAY,CAAC,QAAQ,WAAW,cAAc,QAAQ,MAAM;AAAA,EAC9D,CAAC;AAED,QAAM,WAAW,MAAMC,kBAAiB,MAAM,MAAM,OAAO;AAC3D,QAAM,YAAYC,mBAAkB,UAAU,OAAO,MAAM,YAAY;AACvE,QAAMC,mBAAkB,MAAM,MAAM,SAAS,SAAS;AAEtD,UAAQ;AAAA,IACN,0CAA0C,OAAO,YAAY,YAAY,OAAO,SAAS,gBAAgB,OAAO,aAAa,wBAAwB,OAAO,qBAAqB;AAAA,EACnL;AACF;AAEA,eAAe,gCAAgC,KAA8B;AAC3E,MAAI;AACF,WAAO,MAAMC,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,QACA,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeJ,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMK,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;ACpHA,SAAS,wBAAqC;AAC9C,SAAS,SAAS,YAAAC,WAAU,IAAI,QAAAC,aAAY;AAC5C,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAAC,WAAU,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AACjD,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA,uBAAAC;AAAA,EAEA,cAAAC;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EAEA;AAAA,EAEA,gBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EAGA;AAAA,OAEK;AAIP,IAAMC,cAAa;AACnB,IAAMC,gBAAe;AAmBrB,SAAS,YAAY,OAAe,UAA8B;AAChE,SAAO,CAAC,GAAG,UAAU,KAAK;AAC5B;AA0CO,SAAS,sBAAsBC,UAAwB;AAC5D,QAAM,YAAYA,SACf,QAAQ,QAAQ,EAChB,YAAY,0DAA0D;AAEzE,YACG,QAAQ,aAAa,EACrB,YAAY,gFAAgF,EAC5F;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC,OAAO,kBAAkB,qDAAqD,EAC9E,OAAO,SAAS,+CAA+C,EAC/D;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,aAAa,iDAAiD,EACrE,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAqC;AAClD,UAAM,oBAAoB,OAAO;AAAA,EACnC,CAAC;AAEH,YACG,QAAQ,OAAO,EACf,YAAY,iFAAiF,EAC7F;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC,OAAO,kBAAkB,iDAAiD,EAC1E,OAAO,SAAS,4CAA4C,EAC5D;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,aAAa,iDAAiD,EACrE,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAgC;AAC7C,UAAM,eAAe,OAAO;AAAA,EAC9B,CAAC;AACL;AAMA,eAAsB,oBACpB,SACA,MAAqB,CAAC,GACP;AACf,MAAI;AACF,UAAM,sBAAsB,SAAS,GAAG;AAAA,EAC1C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAMA,eAAsB,eACpB,SACA,MAAqB,CAAC,GACP;AACf,MAAI;AACF,UAAM,iBAAiB,SAAS,GAAG;AAAA,EACrC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,SAAS,mBAAmB,MAKf;AACX,QAAM,EAAE,cAAc,UAAU,UAAU,IAAI,IAAI;AAClD,MAAI;AACJ,MAAI,aAAa,SAAS,GAAG;AAC3B,eAAW,aAAa,IAAI,CAAC,MAAMC,SAAQ,KAAK,CAAC,CAAC;AAAA,EACpD,OAAO;AACL,UAAM,QAAQ,SAAS,QAAQ;AAC/B,eACE,UAAU,UAAa,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC,MAAMA,SAAQ,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ;AAAA,EAChG;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AAC9B;AAEA,eAAsB,sBACpB,SACA,KACe;AACf,iBAAe,OAAO;AACtB,QAAM,EAAE,gBAAgB,OAAO,SAAS,IAAI,MAAM,oBAAoB,GAAG;AAEzE,QAAM,eAAe,mBAAmB;AAAA,IACtC,cAAc,QAAQ,WAAW,CAAC;AAAA,IAClC;AAAA,IACA,UAAU;AAAA,IACV,KAAK,IAAI,OAAO,QAAQ,IAAI;AAAA,EAC9B,CAAC;AACD,QAAM,eAAe,IAAI,qBAAqBC,MAAKC,SAAQ,GAAG,WAAW,UAAU;AAEnF,QAAM,QAAQ,MAAM,sBAAsB,cAAc,cAAc,OAAO;AAQ7E,QAAM,aAAa,IAAI,IAAI,YAAY;AACvC,QAAM,aAAgC,MAAM,IAAI,CAAC,SAAS;AAGxD,UAAM,aAAaC,UAAS,MAAM,QAAQ;AAC1C,WAAO;AAAA,MACL;AAAA,MACA,YAAY;AAAA,MACZ,WAAW,YAAY;AACrB,cAAM,EAAE,SAAS,UAAU,IAAI,MAAM,iBAAiB,IAAI;AAC1D,cAAM,MAAM,mBAAmB,OAAO;AACtC,YAAI,QAAQ,UAAa,CAAC,WAAW,IAAI,GAAG,EAAG,QAAO;AACtD,eAAO,gCAAgC,SAAS;AAAA,UAC9C,aAAa,SAAS,UAAU;AAAA,UAChC;AAAA,UACA,iBAAiB;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,SAAS,QAAQ;AAAA,EACvC;AACF;AAEA,eAAsB,iBACpB,SACA,KACe;AACf,iBAAe,OAAO;AACtB,QAAM,EAAE,gBAAgB,OAAO,SAAS,IAAI,MAAM,oBAAoB,GAAG;AAEzE,QAAM,eAAe,mBAAmB;AAAA,IACtC,cAAc,QAAQ,WAAW,CAAC;AAAA,IAClC;AAAA,IACA,UAAU;AAAA,IACV,KAAK,IAAI,OAAO,QAAQ,IAAI;AAAA,EAC9B,CAAC;AACD,QAAM,eAAe,IAAI,oBAAoBF,MAAKC,SAAQ,GAAG,UAAU,UAAU;AAEjF,QAAM,WAAW,MAAM,sBAAsB,cAAc,cAAc,OAAO;AAChF,QAAM,aAAgC,SAAS,IAAI,CAAC,EAAE,MAAM,WAAW,OAAO;AAAA,IAC5E;AAAA,IACA,YAAY;AAAA,IACZ,WAAW,YAAY;AACrB,YAAM,EAAE,SAAS,UAAU,IAAI,MAAM,iBAAiB,IAAI;AAC1D,aAAO,4BAA4B,SAAiC;AAAA,QAClE,aAAa,SAAS,UAAU;AAAA,QAChC;AAAA,QACA,iBAAiB;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF,EAAE;AAEF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,SAAS,QAAQ;AAAA,EACvC;AACF;AAQA,SAAS,oBAAoB,SAAwB,UAA6B;AAChF,UAAQ,QAAQ,SAAS,UAAU,KAAK,MAAM,SAAS,QAAQ,cAAc,UAAU,KAAK;AAC9F;AAEA,SAAS,eAAe,SAA8B;AACpD,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,MAAM;AACzD,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,MAAM;AACzD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AACF;AAEA,eAAe,oBACb,KAC4E;AAC5E,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,+BAA+B,GAAG;AAC/D,QAAM,QAAQE,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMC,cAAa,KAAK;AACzC,SAAO,EAAE,gBAAgB,OAAO,SAAS;AAC3C;AAUA,eAAe,sBACb,OACA,UACA,SACA,YACA,YACA,cACA,kBACe;AACf,QAAM,uBAAuB,MAAM,yBAAyB,OAAO,UAAU;AAG7E,QAAM,cAAc,oBAAI,IAAY;AASpC,QAAM,oBAAoB;AAC1B,QAAM,eAA8D,CAAC;AACrE,QAAM,mBAAmB,OACvB,YACA,YACkB;AAClB,QAAI,CAAC,kBAAmB;AACxB,QAAI;AACF,YAAM,QAAQ,MAAM,0BAA0B;AAAA,QAC5C,OAAO,QAAQ,QAAQ,iBAAiB,CAAC;AAAA,QACzC,kBAAkB,QAAQ,QAAQ;AAAA,QAClC,aAAa;AAAA,QACb,YAAY,QAAQ,MAAM,IAAI;AAAA,QAC9B,aAAa;AAAA,MACf,CAAC;AACD,UAAI,MAAM,UAAU,SAAS,EAAG,cAAa,KAAK,EAAE,YAAY,WAAW,MAAM,UAAU,CAAC;AAAA,IAC9F,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,UAAiC,CAAC;AACxC,QAAM,SAAuB;AAAA,IAC3B,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,EACvB;AACA,MAAI,iBAAiB;AAIrB,QAAM,WAAW,CAAC,YAAsE;AACtF,QAAI,YAAY,KAAM,QAAO;AAC7B,UAAM,SAAS,2BAA2B,UAAU,OAAO;AAC3D,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,MAAM,0BAA0B,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,IACnE;AACA,QAAI,OAAO,KAAK,mBAAmB,SAAS;AAC1C,YAAM,IAAI,MAAM,sCAAsC,OAAO,KAAK,cAAc,EAAE;AAAA,IACpF;AACA,WAAO,OAAO;AAAA,EAChB;AAEA,aAAW,EAAE,YAAY,YAAY,UAAU,KAAK,YAAY;AAC9D,QAAI,YAAY,IAAI,UAAU,GAAG;AAC/B,aAAO;AACP;AAAA,IACF;AACA,UAAM,SAAS,qBAAqB,IAAI,UAAU,KAAK,CAAC;AAKxD,QAAI,OAAO,SAAS,KAAK,QAAQ,UAAU,MAAM;AAC/C,YAAM,QAAQ,MAAM,iBAAiB,QAAQ,YAAY,YAAY,MAAM;AAC3E,UAAI,UAAU,KAAM;AACpB,YAAMC,WAAU,SAAS,MAAM,UAAU,CAAC;AAC1C,UAAIA,aAAY,MAAM;AACpB,eAAO;AACP;AAAA,MACF;AAIA,YAAM,WAAWA,SAAQ,QAAQ,OAAO;AACxC,UACE,MAAM,oBAAoB,UAC1B,aAAa,UACb,YAAY,MAAM,iBAClB;AACA,gBAAQ;AAAA,UACN,WAAW,UAAU,oCAAoC,QAAQ,OAAO,MAAM,eAAe;AAAA,QAC/F;AACA,eAAO;AACP;AAAA,MACF;AACA,YAAM,UAAU,MAAM,qBAAqB,OAAO,UAAU,MAAM,WAAWA,UAAS;AAAA,QACpF,QAAQ,QAAQ,WAAW;AAAA,MAC7B,CAAC;AACD,UAAI,QAAQ,WAAW,WAAW;AAChC,cAAM,SACJ,QAAQ,WAAW,4BACf,4CACA,QAAQ,WAAW,uBACjB,2EACA;AACR,gBAAQ,MAAM,WAAW,UAAU,IAAI,MAAM,qBAAqB;AAKlE,eAAO;AACP;AAAA,MACF;AACA,aAAO;AACP,kBAAY,IAAI,UAAU;AAC1B,YAAM,iBAAiB,YAAYA,QAAO;AAC1C;AAAA,IACF;AAEA,UAAM,UAAU,SAAS,MAAM,UAAU,CAAC;AAC1C,QAAI,YAAY,MAAM;AACpB,aAAO;AACP;AAAA,IACF;AAKA,QAAI,OAAO,SAAS,KAAK,QAAQ,UAAU,MAAM;AAC/C,UAAI,QAAQ,WAAW,MAAM;AAC3B,mBAAW,EAAE,UAAU,KAAK,QAAQ;AAClC,gBAAM,GAAGN,MAAK,MAAM,UAAU,SAAS,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QAC5E;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM,sBAAsB,OAAO,UAAU,SAAS;AAAA,MACnE,QAAQ,QAAQ,WAAW;AAAA,IAC7B,CAAC;AACD,YAAQ,KAAK,MAAM;AACnB,gBAAY,IAAI,UAAU;AAC1B,sBACE,OAAO,mBAAmB,gBACzB,OAAO,mBAAmB,4BAA4B,IAAI;AAC7D,UAAM,iBAAiB,YAAY,OAAO;AAAA,EAC5C;AAEA,MAAI,iBAAiB,GAAG;AACtB,YAAQ,MAAM,sBAAsB,cAAc,oBAAoB;AAAA,EACxE;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,UAAM,cAAc;AACpB,eAAW,EAAE,YAAY,UAAU,KAAK,cAAc;AACpD,YAAM,SAAS,UAAU,MAAM,GAAG,WAAW,EAAE,KAAK,IAAI;AACxD,YAAM,OACJ,UAAU,SAAS,cAAc,UAAU,UAAU,SAAS,WAAW,WAAW;AACtF,cAAQ;AAAA,QACN,kBAAkB,UAAU,WAAW,UAAU,MAAM,iDAAiD,MAAM,GAAG,IAAI;AAAA,MACvH;AAAA,IACF;AAAA,EACF;AAEA,oBAAkB,SAAS,SAAS,MAAM;AAC5C;AAiCA,eAAe,iBACb,QACA,YACA,YACA,QAC6B;AAC7B,MAAI,OAAO,SAAS,GAAG;AAGrB,YAAQ;AAAA,MACN,WAAW,UAAU,QAAQ,OAAO,MAAM;AAAA,IAC5C;AACA,WAAO;AACP,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,CAAC;AACtB,MAAI,UAAU,QAAW;AACvB,WAAO;AACP,WAAO;AAAA,EACT;AACA,QAAM,cAAc,MAAM,SAAS,UAAU;AAC7C,MAAI,gBAAgB,QAAW;AAE7B,WAAO;AACP,WAAO;AAAA,EACT;AACA,MAAI,MAAM,oBAAoB,QAAW;AAGvC,WAAO;AACP,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,MAAM,iBAAiB;AACzC,WAAO;AACP,WAAO;AAAA,EACT;AACA,MAAI,cAAc,MAAM,iBAAiB;AAEvC,YAAQ;AAAA,MACN,WAAW,UAAU,mBAAmB,WAAW,MAAM,MAAM,eAAe;AAAA,IAChF;AACA,WAAO;AACP,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAYA,SAAS,iBAAiB,aAA6B;AACrD,SAAO,YAAY,QAAQ,iBAAiB,GAAG;AACjD;AAOA,SAAS,mBAAmB,SAAoE;AAC9F,aAAW,UAAU,SAAS;AAC5B,UAAM,MAAM,OAAO;AACnB,QAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,EAAG,QAAO;AAAA,EACxD;AACA,SAAO;AACT;AAoBA,eAAe,yBACb,OACA,YACqC;AACrC,QAAM,eAAe,oBAAI,IAA2B;AACpD,QAAM,MAAM,CAAC,YAAoB,UAA6B;AAC5D,UAAM,OAAO,aAAa,IAAI,UAAU;AACxC,QAAI,SAAS,OAAW,cAAa,IAAI,YAAY,CAAC,KAAK,CAAC;AAAA,QACvD,MAAK,KAAK,KAAK;AAAA,EACtB;AACA,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,qBAAqB,KAAK;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACA,aAAW,aAAa,YAAY;AAClC,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMO,iBAAgB,OAAO,SAAS;AAAA,IAClD,QAAQ;AACN;AAAA,IACF;AACA,QAAI,QAAQ,QAAQ,OAAO,SAAS,WAAY;AAChD,UAAM,kBAAkB,QAAQ,QAAQ,OAAO;AAG/C,UAAM,QACJ,oBAAoB,SAAY,EAAE,WAAW,gBAAgB,IAAI,EAAE,UAAU;AAC/E,UAAM,MAAM,QAAQ,QAAQ,OAAO;AACnC,QAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,GAAG;AAC7C,UAAI,KAAK,KAAK;AACd;AAAA,IACF;AACA,UAAM,QAAQ,QAAQ,QAAQ;AAC9B,UAAM,QAAQ,OAAO,UAAU,WAAW,MAAM,MAAM,4BAA4B,IAAI;AACtF,QAAI,QAAQ,CAAC,MAAM,OAAW,KAAI,MAAM,CAAC,GAAG,KAAK;AAAA,EACnD;AACA,SAAO;AACT;AAYA,eAAe,sBACb,cACA,cACA,SACmB;AACnB,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,UAAoB,CAAC;AAC3B,eAAW,eAAe,cAAc;AACtC,YAAM,OAAOP,MAAK,cAAc,iBAAiB,WAAW,GAAG,GAAG,QAAQ,OAAO,QAAQ;AACzF,UAAI,MAAM,WAAW,IAAI,EAAG,SAAQ,KAAK,IAAI;AAAA,IAC/C;AACA,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AACA,WAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,EAC7B;AACA,QAAM,QAAkB,CAAC;AACzB,MAAI,cAAc;AAClB,aAAW,eAAe,cAAc;AACtC,UAAM,gBAAgBA,MAAK,cAAc,iBAAiB,WAAW,CAAC;AACtE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,QAAQ,aAAa;AAAA,IACvC,SAAS,OAAgB;AACvB,UAAIQ,eAAc,OAAO,QAAQ,EAAG;AACpC,YAAM,IAAI,MAAM,8CAA8C,EAAE,OAAO,MAAM,CAAC;AAAA,IAChF;AACA,kBAAc;AACd,eAAW,QAAQ,SAAS;AAC1B,UAAI,KAAK,SAAS,QAAQ,EAAG,OAAM,KAAKR,MAAK,eAAe,IAAI,CAAC;AAAA,IACnE;AAAA,EACF;AACA,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK;AAClC;AAGA,eAAe,WAAW,MAAgC;AACxD,MAAI;AACF,UAAMS,MAAK,IAAI;AACf,WAAO;AAAA,EACT,SAAS,OAAgB;AACvB,QAAID,eAAc,OAAO,QAAQ,EAAG,QAAO;AAC3C,UAAM;AAAA,EACR;AACF;AAGA,eAAe,SAAS,MAA2C;AACjE,MAAI;AACF,YAAQ,MAAMC,MAAK,IAAI,GAAG;AAAA,EAC5B,SAAS,OAAgB;AACvB,QAAID,eAAc,OAAO,QAAQ,EAAG,QAAO;AAC3C,UAAM;AAAA,EACR;AACF;AAaA,eAAe,sBACb,cACA,cACA,SACsD;AACtD,QAAM,aAAa,IAAI,IAAI,YAAY;AACvC,QAAM,QAAQ,MAAM,iBAAiB,YAAY;AACjD,QAAM,UAAuD,CAAC;AAC9D,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,MAAM,gBAAgB,IAAI;AACvC,QAAI,SAAS,OAAW;AACxB,QAAI,CAAC,WAAW,IAAI,KAAK,GAAG,EAAG;AAC/B,QAAI,QAAQ,YAAY,UAAa,KAAK,OAAO,QAAQ,QAAS;AAClE,YAAQ,KAAK,EAAE,MAAM,YAAY,KAAK,GAAG,CAAC;AAAA,EAC5C;AACA,MAAI,QAAQ,YAAY,UAAa,QAAQ,WAAW,GAAG;AACzD,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AACT;AAGA,eAAe,iBAAiB,cAAyC;AACvE,QAAM,QAAkB,CAAC;AACzB,QAAM,OAAO,OAAO,KAAa,WAAmC;AAClE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACtD,SAAS,OAAgB;AACvB,UAAIA,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAI,QAAQ;AACV,gBAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,MAAM,CAAC;AAAA,QACxE;AACA;AAAA,MACF;AACA,YAAM,IAAI,MAAM,2CAA2C,EAAE,OAAO,MAAM,CAAC;AAAA,IAC7E;AACA,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAOR,MAAK,KAAK,MAAM,IAAI;AACjC,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,MAAM,KAAK;AAAA,MACxB,WACE,MAAM,OAAO,KACb,MAAM,KAAK,WAAW,UAAU,KAChC,MAAM,KAAK,SAAS,QAAQ,GAC5B;AACA,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,cAAc,IAAI;AAC7B,SAAO,MAAM,KAAK;AACpB;AAQA,eAAe,gBAAgB,MAAgE;AAC7F,QAAM,YAAY,MAAM,cAAc,IAAI;AAC1C,MAAI,cAAc,OAAW,QAAO;AACpC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,SAAS;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,SAAS,MAAM,KAAK,OAAO,SAAS,eAAgB,QAAO;AAChE,QAAM,UAAU,SAAS,OAAO,OAAO,IAAI,OAAO,UAAU;AAC5D,MAAI,YAAY,OAAW,QAAO;AAClC,QAAM,KAAK,QAAQ;AACnB,QAAM,MAAM,QAAQ;AACpB,MAAI,OAAO,OAAO,YAAY,GAAG,WAAW,EAAG,QAAO;AACtD,MAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,EAAG,QAAO;AACxD,SAAO,EAAE,IAAI,IAAI;AACnB;AAGA,eAAe,cAAc,MAA2C;AACtE,QAAM,SAAS,iBAAiB,MAAM,EAAE,UAAU,OAAO,CAAC;AAC1D,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,WAAW,OAAO,kBAAkB,CAAC;AACjF,MAAI;AACF,qBAAiB,QAAQ,IAAI;AAC3B,YAAM,UAAU,KAAK,KAAK;AAC1B,UAAI,QAAQ,SAAS,EAAG,QAAO;AAAA,IACjC;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,OAAG,MAAM;AACT,WAAO,QAAQ;AAAA,EACjB;AACF;AAUA,eAAe,iBACb,MACmE;AACnE,MAAI;AACJ,MAAI;AACF,aAAS,MAAMU,UAAS,IAAI;AAAA,EAC9B,SAAS,OAAgB;AACvB,QAAIF,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,wBAAwB,EAAE,OAAO,MAAM,CAAC;AAAA,IAC1D;AACA,QAAIA,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,iCAAiC,EAAE,OAAO,MAAM,CAAC;AAAA,IACnE;AACA,UAAM,IAAI,MAAM,6BAA6B,EAAE,OAAO,MAAM,CAAC;AAAA,EAC/D;AAEA,QAAM,UAAoC,CAAC;AAC3C,aAAW,QAAQ,OAAO,SAAS,MAAM,EAAE,MAAM,IAAI,GAAG;AACtD,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,EAAG;AAC1B,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,UAAI,SAAS,MAAM,GAAG;AACpB,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,EAAE,SAAS,WAAW,OAAO,OAAO;AAC7C;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,kBACP,SACA,SACA,QACM;AACN,QAAM,QAAQ,QAAQ,WAAW;AACjC,QAAM,aAAa,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,CAAC;AACnE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,UAAU,QAAQ,IAAI,CAAC,OAAO;AAAA,UAC5B,YAAY,EAAE;AAAA,UACd,aAAa,EAAE;AAAA,UACf,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE,MAAM,EAAE,iBAAiB,SAAS,QAAQ;AAAA,QACtD,EAAE;AAAA,QACF,gBAAgB,QAAQ;AAAA,QACxB,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,QAClB,mBAAmB;AAAA,QACnB,0BAA0B;AAAA,QAC1B,0BAA0B;AAAA,QAC1B,mBAAmB;AAAA,QACnB,mBAAmB;AAAA,QACnB,sBAAsB;AAAA,QACtB,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA;AAAA,EACF;AAEA,QAAM,YAAsB,CAAC;AAC7B,MAAI,kBAAkB,EAAG,WAAU,KAAK,GAAG,eAAe,kBAAkB;AAC5E,MAAI,kBAAkB,EAAG,WAAU,KAAK,GAAG,eAAe,mBAAmB;AAC7E,MAAI,gBAAgB,EAAG,WAAU,KAAK,GAAG,aAAa,0BAA0B;AAChF,MAAI,mBAAmB,EAAG,WAAU,KAAK,GAAG,gBAAgB,SAAS;AACrE,MAAI,mBAAmB,EAAG,WAAU,KAAK,GAAG,gBAAgB,aAAa;AACzE,MAAI,sBAAsB;AACxB,cAAU,KAAK,GAAG,mBAAmB,oCAAoC;AAC3E,QAAM,aAAa,UAAU,SAAS,IAAI,aAAa,UAAU,KAAK,IAAI,CAAC,KAAK;AAChF,QAAM,aACJ,WAAW,IAAI,GAAG,UAAU,YAAY,QAAQ,cAAc,GAAG,UAAU;AAE7E,MAAI,OAAO;AACT,UAAM,QAAkB,CAAC;AACzB,QAAI,QAAQ,SAAS,EAAG,OAAM,KAAK,UAAU,QAAQ,MAAM,gBAAgB,UAAU,GAAG;AACxF,QAAI,aAAa,EAAG,OAAM,KAAK,aAAa,UAAU,qBAAqB;AAC3E,UAAM,OAAO,MAAM,SAAS,IAAI,kBAAkB,MAAM,KAAK,IAAI,CAAC,KAAK;AACvE,YAAQ,IAAI,GAAG,IAAI,GAAG,UAAU,EAAE;AAClC;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,KAAK,eAAe,GAAG;AAC5C,YAAQ;AAAA,MACN,UAAU,SAAS,IACf,qCAAqC,UAAU,KAAK,IAAI,CAAC,MACzD;AAAA,IACN;AACA;AAAA,EACF;AAEA,QAAM,WAAqB,CAAC;AAC5B,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,SACJ,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,SAAY,KAAKG,SAAQ,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM;AAC7F,aAAS,KAAK,YAAY,QAAQ,MAAM,cAAc,MAAM,KAAK,UAAU,GAAG;AAAA,EAChF;AACA,MAAI,aAAa,GAAG;AAClB,aAAS;AAAA,MACP,GAAG,QAAQ,SAAS,IAAI,gBAAgB,aAAa,IAAI,UAAU;AAAA,IACrE;AAAA,EACF;AACA,UAAQ,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE;AACnD;AAEA,SAASA,SAAQ,IAAoB;AACnC,MAAI,GAAG,WAAWf,WAAU,GAAG;AAC7B,WAAO,GAAG,MAAMA,YAAW,QAAQA,YAAW,SAASC,aAAY;AAAA,EACrE;AACA,SAAO,GAAG,MAAM,GAAGA,aAAY;AACjC;AAEA,eAAe,+BAA+B,KAA8B;AAC1E,MAAI;AACF,WAAO,MAAMe,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,2EAA2E;AAAA,QACzF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeR,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMS,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIL,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;ACr/BA,SAAS,YAAAM,WAAU,UAAU,WAAAC,gBAAe;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAsBP,SAAS,aAAa,OAAe,UAA8B;AACjE,SAAO,CAAC,GAAG,UAAU,KAAK;AAC5B;AAaO,SAAS,oBAAoBC,UAAwB;AAC1D,EAAAA,SACG,QAAQ,MAAM,EACd,YAAY,iEAAiE,EAC7E,OAAO,iBAAiB,4DAA4D,EACpF,OAAO,yBAAyB,sBAAsB,EACtD,OAAO,uCAAuC,qBAAqB,EACnE;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,eAAe,gCAAgC,EACtD,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAyB;AACtC,UAAM,QAAQ,OAAO;AAAA,EACvB,CAAC;AACL;AAOA,eAAsB,QAAQ,SAAsB,MAAmB,CAAC,GAAkB;AACxF,MAAI;AACF,UAAM,UAAU,SAAS,GAAG;AAAA,EAC9B,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAQA,eAAsB,UAAU,SAAsB,KAAiC;AACrF,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,GAAG;AAC7D,QAAM,gBAAgB,QAAQ,QAAQC,UAAS,cAAc;AAI7D,MAAI;AACJ,MAAI,QAAQ,YAAY,QAAW;AACjC,oBAAgB,QAAQ,YAAY,KAAK,OAAO,QAAQ;AAAA,EAC1D,OAAO;AACL,oBAAgB,MAAM,aAAa,cAAc;AAAA,EACnD;AAKA,QAAM,eAAe,QAAQ,cAAc,CAAC,GAAG,IAAI,CAAC,MAAM;AACxD,UAAM,MAAM,SAAS,gBAAgBC,SAAQ,KAAK,CAAC,CAAC;AACpD,WAAO,QAAQ,KAAK,MAAM;AAAA,EAC5B,CAAC;AAED,QAAM,QAAQ,MAAM,qBAAqB,cAAc;AACvD,QAAM,WAAW,eAAe;AAAA,IAC9B;AAAA,IACA,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,IAChF,GAAI,QAAQ,uBAAuB,SAC/B,EAAE,oBAAoB,QAAQ,mBAAmB,IACjD,CAAC;AAAA,IACL,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACvD,GAAI,YAAY,SAAS,IAAI,EAAE,YAAY,IAAI,CAAC;AAAA,EAClD,CAAC;AAED,QAAM,cAAc,OAAO,UAAU,EAAE,OAAO,QAAQ,UAAU,KAAK,CAAC;AAMtE,MAAI;AACF,UAAM,qBAAqB,gBAAgB,EAAE,WAAW,QAAQ,cAAc,KAAK,CAAC;AAAA,EACtF,SAAS,OAAgB;AACvB,2BAAuB,OAAO,UAAU,OAAO,CAAC;AAAA,EAClD;AAEA,UAAQ,IAAI,gCAAgC,SAAS,UAAU,EAAE,EAAE;AACrE;AAQA,SAAS,uBAAuB,OAAgB,SAAwB;AACtE,QAAM,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAIzE,UAAQ;AAAA,IACN,yCAAyC,WAAW;AAAA,EACtD;AACA,MAAI,WAAW,iBAAiB,OAAO;AACrC,UAAM,QAAQ,kBAAkB,KAAK;AACrC,QAAI,UAAU,OAAW,SAAQ,MAAM,cAAc,KAAK,EAAE;AAAA,EAC9D;AACF;AAOA,eAAe,6BAA6B,KAA8B;AACxE,MAAI;AACF,WAAO,MAAMC,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,yEAAyE;AAAA,QACvF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;;;ACjLA;AAAA,EACE,eAAAC;AAAA,EACA,gCAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,+BAAAC;AAAA,EAEA,iBAAAC;AAAA,EAEA,gBAAAC;AAAA,EACA,oBAAAC;AAAA,OAEK;AACP,SAAuB,wBAAAC,6BAA4B;AAYnD,IAAM,iBAAiB;AACvB,IAAMC,uBAAsB,iBAAiB;AAuBtC,SAAS,oBAAoBC,UAAwB;AAC1D,EAAAA,SACG,QAAQ,MAAM,EACd,YAAY,4EAA4E,EACxF,SAAS,UAAU,aAAa,SAAS,EACzC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,MAAc,YAAyB;AACpD,UAAM,QAAQ,MAAM,OAAO;AAAA,EAC7B,CAAC;AACL;AAMA,eAAsB,QACpB,MACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,GAAG;AAAA,EACpC,SAAS,OAAgB;AAKvB,mBAAe,OAAO;AAAA,MACpB,SAAS,UAAU,OAAO;AAAA,MAC1B,aAAa,CAAC,0BAA0B;AAAA,IAC1C,CAAC;AACD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,UACpB,MACA,SACA,KACe;AAIf,MAAI,KAAK,KAAK,EAAE,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AAGnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,MAAM;AACnE,QAAM,QAAQC,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AAEnC,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,YAAY,MAAMC,kBAAiB,OAAO,QAAQ,OAAO;AAC/D,UAAM,QAAQ;AAKd,UAAM,cAAc,MAAMC,aAAY,OAAO,WAAW,KAAK;AAC7D,QAAI;AACJ,QAAI;AACF,eAAS,MAAMC,8BAA6B;AAAA,QAC1C;AAAA,QACA,WAAW;AAAA,QACX,cAAc,CAAC,YAAY,eAAe,EAAE,SAAS,WAAW,OAAO,YAAY,KAAK,CAAC;AAAA,MAC3F,CAAC;AAAA,IACH,UAAE;AACA,YAAM,YAAY,QAAQ;AAAA,IAC5B;AACA,oBAAgB,SAAS;AAAA,MACvB,MAAM;AAAA,MACN;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,eAAe,OAAO;AAAA,MACtB;AAAA,IACF,CAAC;AACD;AAAA,EACF;AAEA,QAAM,WAAW,MAAMC,cAAa,KAAK;AACzC,QAAM,QAAQ,MAAMC,6BAA4B;AAAA,IAC9C;AAAA,IACA;AAAA,IACA,OAAOC,iBAAgB,IAAI;AAAA,IAC3B;AAAA,IACA,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,YAAY;AAAA,MACV,SAAS;AAAA,MACT,MAAM,CAAC,IAAI;AAAA,IACb;AAAA,IACA,qBAAqB;AAAA,MACnB,CAAC,WAAW,YAAY,eAAe,EAAE,SAAS,WAAW,YAAY,KAAK,CAAC;AAAA,IACjF;AAAA,EACF,CAAC;AACD,kBAAgB,SAAS;AAAA,IACvB,MAAM;AAAA,IACN,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM,eAAe,CAAC;AAAA,IAC/B,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eAAe,OAKd;AACR,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,IAAI,MAAM;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM,MAAM;AAAA;AAAA;AAAA,IAGZ,MAAM;AAAA,EACR;AACF;AAEA,SAASA,iBAAgB,MAAsB;AAE7C,QAAM,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C,QAAM,YACJ,QAAQ,SAAS,iBAAiB,GAAG,QAAQ,MAAM,GAAGT,oBAAmB,CAAC,QAAQ;AACpF,SAAO,gBAAgB,SAAS;AAClC;AAEA,SAAS,UAAU,KAAqB;AACtC,MAAI,IAAI,KAAK,EAAE,WAAW,GAAG;AAC3B,UAAM,IAAIU,sBAAqB,6BAA6B;AAAA,EAC9D;AACA,SAAO;AACT;AAUA,SAAS,gBAAgB,SAAsB,QAA8B;AAC3E,QAAM,MAAM,eAAe,OAAO,SAAS;AAC3C,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,gBAAgB,OAAO;AAAA,QACvB,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,MACf,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,MAAI,OAAO,SAAS,UAAU;AAC5B,YAAQ,IAAI,iBAAiB,OAAO,OAAO,sBAAsB,GAAG,EAAE;AAAA,EACxE,OAAO;AACL,YAAQ,IAAI,iBAAiB,OAAO,OAAO,eAAe,GAAG,KAAK,OAAO,aAAa,GAAG;AAAA,EAC3F;AACF;AAEA,eAAeP,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMQ,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;AC7OA;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EAEA,iBAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,qBAAAC;AAAA,OACK;;;ACPP,SAAS,WAAAC,gBAAe;AACxB,SAAS,cAAAC,aAAY,QAAAC,OAAM,WAAAC,gBAAe;AAC1C,SAAS,gBAAAC,qBAAoB;AAqBtB,IAAM,4BAA4BF,MAAKF,SAAQ,GAAG,UAAU,YAAY;AAG/E,SAASK,aAAY,GAAmB;AACtC,MAAI,MAAM,IAAK,QAAOL,SAAQ;AAC9B,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOE,MAAKF,SAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,SAAO;AACT;AAEA,SAASM,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAcA,eAAsB,gBACpB,aAAqB,2BACS;AAC9B,MAAI;AACJ,MAAI;AACF,UAAM,MAAMF,cAAa,UAAU;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,aAAO;AAAA,IACT;AACA,QAAI,iBAAiB,SAAS,MAAM,YAAY,gCAAgC;AAC9E,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,UAAM;AAAA,EACR;AAEA,MAAI,CAACE,UAAS,GAAG,KAAK,CAAC,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC/C,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,QAAM,YAAY,oBAAI,IAAY;AAClC,QAAM,aAAa,oBAAI,IAAY;AACnC,QAAM,SAAuB,CAAC;AAC9B,aAAW,SAAS,IAAI,OAAO;AAC7B,QAAI,CAACA,UAAS,KAAK,KAAK,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,EAAE,WAAW,GAAG;AAC1F,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,UAAM,QAAQ,MAAM,MAAM,KAAK;AAC/B,QAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,EAAE,WAAW,GAAG;AACpE,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,UAAM,WAAWD,aAAY,MAAM,KAAK,KAAK,CAAC;AAC9C,QAAI,CAACJ,YAAW,QAAQ,GAAG;AACzB,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AACA,UAAM,MAAME,SAAQ,QAAQ;AAC5B,QAAI,UAAU,IAAI,GAAG,EAAG;AAGxB,QAAI,WAAW,IAAI,KAAK,GAAG;AACzB,YAAM,IAAI,MAAM,yBAAyB,KAAK,sCAAsC;AAAA,IACtF;AACA,cAAU,IAAI,GAAG;AACjB,eAAW,IAAI,KAAK;AACpB,WAAO,KAAK,EAAE,OAAO,MAAM,IAAI,CAAC;AAAA,EAClC;AAEA,SAAO;AACT;;;AChGA;AAAA,EAEE,oBAAAI;AAAA,EACA,mBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,EACA,qBAAAC;AAAA,EACA,qBAAAC;AAAA,OACK;AA+EP,eAAe,kBAAkB,IAA2D;AAC1F,QAAM,SAAmB,CAAC;AAC1B,QAAM,cAAc,QAAQ;AAC5B,QAAM,gBAAgB,QAAQ;AAC9B,UAAQ,OAAO,IAAI,SAAoB;AACrC,WAAO,KAAK,KAAK,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,EAClD;AAGA,UAAQ,SAAS,MAAM;AAAA,EAAC;AACxB,MAAI;AACF,UAAM,GAAG;AAAA,EACX,UAAE;AACA,YAAQ,MAAM;AACd,YAAQ,QAAQ;AAAA,EAClB;AACA,WAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,UAAM,OAAO,OAAO,CAAC;AACrB,QAAI,SAAS,OAAW;AACxB,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,UAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,oBAAoB,QAAQ;AAC/E,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,IAAI,MAAM,qCAAqC;AACvD;AAEA,SAAS,UAAU,OAAwB;AACzC,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAMA,SAAS,mBAAmB,OAAyB;AACnD,MAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,SACE,MAAM,YAAY,uDAClB,MAAM,YAAY;AAEtB;AAGA,eAAe,UAAU,SAAwB,IAAiD;AAChG,MAAI;AACF,UAAM,OAAO,MAAM,kBAAkB,EAAE;AACvC,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,eAAe,UAAU,KAAK,cAAc;AAAA,MAC5C,eAAe,UAAU,KAAK,cAAc;AAAA,MAC5C,iBAAiB,UAAU,KAAK,gBAAgB;AAAA,MAChD,iBAAiB,UAAU,KAAK,iBAAiB;AAAA,MACjD,wBAAwB,UAAU,KAAK,wBAAwB;AAAA,MAC/D,wBAAwB,UAAU,KAAK,wBAAwB;AAAA,MAC/D,qBAAqB,UAAU,KAAK,oBAAoB;AAAA,MACxD,YAAY,UAAU,KAAK,WAAW;AAAA,MACtC,QAAQ,KAAK,YAAY;AAAA,IAC3B;AAAA,EACF,SAAS,OAAgB;AACvB,QAAI,mBAAmB,KAAK,GAAG;AAC7B,aAAO,EAAE,SAAS,QAAQ,WAAW,QAAQ,kCAAkC;AAAA,IACjF;AACA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,cAAc,SAA8C;AACnE,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,IACN,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACpE,GAAI,QAAQ,UAAU,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,IAChD,GAAI,QAAQ,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,EACpD;AACF;AAGO,SAAS,iBACd,SACA,KACwB;AACxB,SAAO,UAAU,eAAe,MAAM,sBAAsB,cAAc,OAAO,GAAG,GAAG,CAAC;AAC1F;AAGO,SAAS,YACd,SACA,KACwB;AACxB,SAAO,UAAU,SAAS,MAAM,iBAAiB,cAAc,OAAO,GAAG,GAAG,CAAC;AAC/E;AAKA,eAAsB,kBACpB,OACA,QACA,WACwB;AACxB,QAAM,SAAS,MAAMC,eAAc,EAAE,OAAO,QAAQ,GAAG,UAAU,CAAC;AAClE,QAAM,WAAW,MAAMC,kBAAiB,MAAM,MAAM,OAAO;AAC3D,QAAMC;AAAA,IACJ,MAAM,MAAM;AAAA,IACZC,mBAAkB,UAAU,OAAO,MAAM,YAAY;AAAA,EACvD;AACA,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,WAAW,OAAO;AAAA,IAClB,eAAe,OAAO;AAAA,IACtB,uBAAuB,OAAO;AAAA,EAChC;AACF;AAGA,eAAsB,oBACpB,OACA,QACA,WACoC;AACpC,QAAM,SAAS,MAAMC,iBAAgB,EAAE,OAAO,QAAQ,GAAG,UAAU,CAAC;AACpE,QAAM,WAAW,MAAMH,kBAAiB,MAAM,MAAM,SAAS;AAC7D,QAAMC;AAAA,IACJ,MAAM,MAAM;AAAA,IACZC,mBAAkB,UAAU,OAAO,MAAM,cAAc;AAAA,EACzD;AACA,SAAO,EAAE,eAAe,OAAO,cAAc;AAC/C;AAOA,eAAsB,sBACpB,OACA,QACA,WAC4B;AAC5B,QAAM,SAAS,MAAM,kBAAkB,EAAE,OAAO,QAAQ,GAAG,UAAU,CAAC;AACtE,QAAMD,mBAAkB,MAAM,MAAM,aAAa,GAAG,OAAO,IAAI;AAAA,CAAI;AACnE,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,mBAAmB,OAAO;AAAA,IAC1B,uBAAuB,OAAO;AAAA,IAC9B,cAAc,OAAO;AAAA,EACvB;AACF;AAQA,eAAsB,WAAW,MAKN;AACzB,QAAM,EAAE,SAAS,KAAK,OAAO,OAAO,IAAI;AACxC,QAAM,SAAS,QAAQ,WAAW;AAElC,QAAM,aAAa,MAAM,iBAAiB,SAAS,GAAG;AACtD,QAAM,QAAQ,MAAM,YAAY,SAAS,GAAG;AAE5C,MAAI,QAAQ;AACV,UAAM,UAAU,EAAE,QAAQ,WAAoB,QAAQ,UAAU;AAChE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM,kBAAkB,OAAO,MAAM;AAC3D,QAAM,iBAAiB,MAAM,oBAAoB,OAAO,MAAM;AAS9D,QAAM,SAAS,QAAQ,YAAY,UAAa,QAAQ,QAAQ,SAAS;AACzE,QAAM,oBAAoB,MAAM;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,SACI,CAAC,IACD;AAAA,MACE,WAAW;AAAA,QACT,aAAa;AAAA,QACb,iBAAiB;AAAA,QACjB,sBAAsB,WAAW,UAAU,IAAI,WAAW,KAAK;AAAA,MACjE;AAAA,IACF;AAAA,EACN;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,EAAE,QAAQ,aAAa,GAAG,cAAc;AAAA,IACjD,WAAW,EAAE,QAAQ,aAAa,GAAG,eAAe;AAAA,IACpD,aAAa,EAAE,QAAQ,aAAa,GAAG,kBAAkB;AAAA,IACzD;AAAA,EACF;AACF;AAGA,SAAS,YAAY,SAAgC;AACnD,SAAO,QAAQ,WAAW,QAAQ,QAAQ,gBAAgB;AAC5D;AAGA,SAAS,YAAY,SAAgC;AACnD,SAAO,QAAQ,WAAW,QAAQ,QAAQ,kBAAkB,QAAQ,gBAAgB;AACtF;AAOA,SAAS,WAAW,SAAgC;AAClD,SAAO,QAAQ,WAAW,QAAQ,QAAQ,sBAAsB;AAClE;AA0BA,eAAsB,eAAe,MAIF;AACjC,MAAI;AACF,UAAM,MAAM,MAAM,WAAW;AAAA,MAC3B,SAAS,EAAE,QAAQ,KAAK;AAAA,MACxB,KAAK,KAAK;AAAA,MACV,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACf,CAAC;AACD,WAAO;AAAA,MACL,aAAa,YAAY,IAAI,UAAU,IAAI,YAAY,IAAI,KAAK;AAAA,MAChE,iBAAiB,YAAY,IAAI,UAAU,IAAI,YAAY,IAAI,KAAK;AAAA,MACpE,sBAAsB,WAAW,IAAI,UAAU,IAAI,WAAW,IAAI,KAAK;AAAA,IACzE;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AF3UO,SAAS,sBAAsBG,UAAwB;AAC5D,EAAAA,SACG,QAAQ,QAAQ,EAChB,YAAY,2EAA2E,EACvF,OAAO,eAAe,0CAA0C,EAChE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAwB;AACrC,UAAM,UAAU,IAAI;AAAA,EACtB,CAAC;AACL;AAMA,eAAsB,UAAU,SAAwB,MAAqB,CAAC,GAAkB;AAC9F,MAAI;AACF,UAAM,YAAY,SAAS,GAAG;AAAA,EAChC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAMA,eAAsB,YAAY,SAAwB,KAAmC;AAC3F,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,QAAQ;AACrE,QAAM,QAAQC,YAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAI/D,QAAM,WAA0B,EAAE,KAAK,eAAe;AACtD,MAAI,IAAI,sBAAsB,OAAW,UAAS,oBAAoB,IAAI;AAC1E,MAAI,IAAI,qBAAqB,OAAW,UAAS,mBAAmB,IAAI;AACxE,QAAM,YAAY,MAAM,eAAe,EAAE,KAAK,UAAU,OAAO,OAAO,CAAC;AAQvE,MAAI,iBAAkC,CAAC;AACvC,MAAI;AACF,UAAM,QAAQ,MAAM,gBAAgB,IAAI,eAAe;AACvD,QAAI,UAAU,MAAM;AAClB,uBAAiB,MAAM,IAAI,CAAC,OAAO,EAAE,OAAOD,YAAW,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,EAAE;AAAA,IAClF;AAAA,EACF,SAAS,OAAgB;AACvB,YAAQ;AAAA,MACN,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAChG;AAAA,EACF;AAEA,QAAM,SAAS,MAAME,mBAAkB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,QAAQ,YAAY;AAAA,IAC7B;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,IAC5D,YAAY,CAAC,QAAQ,WAAW,cAAc,QAAQ,MAAM;AAAA,IAC5D,mBAAmB,CAAC,MAAM,UACxB,QAAQ;AAAA,MACN,gBAAgB,IAAI,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACpG;AAAA,EACJ,CAAC;AAID,QAAMC,mBAAkB,MAAM,MAAM,aAAa,GAAG,OAAO,IAAI;AAAA,CAAI;AAEnE,MAAI,QAAQ,UAAU,MAAM;AAC1B,YAAQ;AAAA,MACN,8CAA8C,OAAO,YAAY,sBAAsB,OAAO,iBAAiB,wBAAwB,OAAO,qBAAqB,cAAc,OAAO,YAAY;AAAA,IACtM;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,OAAO,IAAI;AAAA,EACzB;AACF;AAEA,eAAeF,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMG,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;AGxIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAAC,WAAU,WAAAC,UAAS,cAAAC,aAAY,QAAAC,OAAM,YAAAC,WAAU,WAAAC,gBAAe;AACvE;AAAA,EAGE,cAAAC;AAAA,EAEA;AAAA,EACA;AAAA,EAKA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAYA,gBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EACA,qBAAAC;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAIA,iBAAAC;AAAA,EACA,qBAAAC;AAAA,OACK;AAsNP,IAAM,oBAAoB,CAAC,aAAa,aAAa,iCAAiC;AAOtF,IAAM,iBAAiB;AAShB,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,UAAUA,SACb,QAAQ,SAAS,EACjB,YAAY,sDAAsD;AAErE,UACG,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA8B;AAC3C,UAAM,gBAAgB,IAAI;AAAA,EAC5B,CAAC;AAEH,UACG,QAAQ,MAAM,EACd;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA6B;AAC1C,UAAM,eAAe,IAAI;AAAA,EAC3B,CAAC;AAEH,UACG,QAAQ,OAAO,EACf;AAAA,IACC;AAAA,EACF,EACC,OAAO,WAAW,0EAA0E,EAC5F,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA8B;AAC3C,UAAM,gBAAgB,IAAI;AAAA,EAC5B,CAAC;AAEH,UACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA+B;AAC5C,UAAM,iBAAiB,IAAI;AAAA,EAC7B,CAAC;AAEH,UACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAkC;AAC/C,UAAM,oBAAoB,IAAI;AAAA,EAChC,CAAC;AAEH,UACG,QAAQ,UAAU,EAClB;AAAA,IACC;AAAA,EACF,EACC,OAAO,WAAW,yEAAyE,EAC3F,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAiC;AAC9C,UAAM,mBAAmB,IAAI;AAAA,EAC/B,CAAC;AAEH,UACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EACF,EACC,OAAO,WAAW,6DAA6D,EAC/E;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAkC;AAC/C,UAAM,oBAAoB,IAAI;AAAA,EAChC,CAAC;AAEH,UACG,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA+B;AAC5C,UAAM,iBAAiB,IAAI;AAAA,EAC7B,CAAC;AAEH,UACG,QAAQ,SAAS,EACjB,SAAS,UAAU,gEAAgE,EACnF;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,MAAc,SAAgC;AAC3D,UAAM,kBAAkB,MAAM,IAAI;AAAA,EACpC,CAAC;AAEH,UACG,QAAQ,QAAQ,EAChB,SAAS,SAAS,6DAA6D,EAC/E,SAAS,SAAS,gDAAgD,EAClE;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAiB,SAAiB,SAA+B;AAC9E,UAAM,iBAAiB,SAAS,SAAS,IAAI;AAAA,EAC/C,CAAC;AACL;AAGA,eAAsB,gBACpB,SACA,MAA2B,CAAC,GACb;AACf,MAAI;AACF,UAAM,kBAAkB,SAAS,GAAG;AAAA,EACtC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAQA,SAAS,qBAAqB,UAA8B;AAC1D,SAAO,SAAS,QAAQ,gBAAgB,CAAC,GAAG;AAC9C;AASA,SAAS,sBAAsB,QAA4B;AACzD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,SAAO;AAAA,IACL,mJAA0C,OAAO,MAAM,8GAA8B,OAAO,KAAK,IAAI,CAAC;AAAA,IACtG;AAAA,EACF;AACF;AAGA,eAAsB,kBACpB,SACA,KAC6B;AAC7B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,eAAe;AAC5E,QAAM,QAAQC,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,UAAU,qBAAqB;AAAA,IACnC,GAAI,SAAS,UAAU,SAAY,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAAA,IAChE,aAAa,qBAAqB,QAAQ;AAAA,EAC5C,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,EACrC,OAAO;AACL,YAAQ,IAAI,mBAAmB,OAAO,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAQO,SAAS,mBAAmB,SAAqC;AACtE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,0GAA0B;AACrC,QAAM,KAAK,EAAE;AAEb,MAAI,QAAQ,kBAAkB,GAAG;AAC/B,UAAM;AAAA,MACJ;AAAA,IACF;AACA,QAAI,QAAQ,MAAM,SAAS,GAAG;AAC5B,YAAM,KAAK,EAAE;AACb,YAAM,KAAK,0CAAsB,QAAQ,MAAM,MAAM,IAAI;AACzD,iBAAW,KAAK,QAAQ,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AAAA,IACpD;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,QAAQ,KAAK,WAAW,GAAG;AAC7B,UAAM;AAAA,MACJ,yCAAW,QAAQ,aAAa;AAAA,IAClC;AAAA,EACF,OAAO;AACL,UAAM,KAAK,uHAA6B,QAAQ,KAAK,MAAM,kCAAS;AACpE,eAAW,KAAK,QAAQ,MAAM;AAC5B,YAAM,KAAK,KAAK,EAAE,IAAI,GAAG,EAAE,aAAa,KAAK,EAAE,UAAU,MAAM,EAAE,+CAAsB;AAAA,IACzF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,QAAQ,MAAM,SAAS,GAAG;AAC5B,UAAM;AAAA,MACJ,wDAAgB,QAAQ,MAAM,MAAM;AAAA,IACtC;AACA,eAAW,KAAK,QAAQ,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AAClD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,eACpB,SACA,MAA0B,CAAC,GACZ;AACf,MAAI;AACF,UAAM,iBAAiB,SAAS,GAAG;AAAA,EACrC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,eAAsB,iBACpB,SACA,KAC4B;AAC5B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,cAAc;AAC3E,QAAM,QAAQD,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,YAAY,SAAS,UAAU,UAAa,SAAS,MAAM,SAAS;AAC1E,QAAM,YAAY,qBAAqB;AAAA,IACrC,GAAI,SAAS,UAAU,SAAY,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAAA,IAChE,GAAI,SAAS,QAAQ,iBAAiB,SAClC,EAAE,aAAa,SAAS,OAAO,aAAa,IAC5C,CAAC;AAAA,EACP,CAAC;AAED,QAAM,UAAU,QAAQ,UAAU,QAAQ,aAAa,CAAC,UAAU;AAClE,MAAI,SAAS;AACX,UAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,UAAMC;AAAA,MACJ;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,QAAQ,EAAE,GAAG,SAAS,QAAQ,cAAc,UAAU,KAAK;AAAA,QAC3D,WAAW,EAAE,GAAG,SAAS,WAAW,YAAY,IAAI,EAAE,YAAY,EAAE;AAAA,MACtE;AAAA,MACA,EAAE,OAAO,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,SAA4B;AAAA,IAChC,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA,wBAAwB,oBAAoB,QAAQ;AAAA,EACtD;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,kBAAkB,MAAM,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAOO,SAAS,kBAAkB,QAAmC;AACnE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,yGAAmC;AAC9C,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,GAAG,sBAAsB,OAAO,sBAAsB,CAAC;AAElE,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,WAAW;AACpB,UAAM,KAAK,kKAA0C;AACrD,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM,KAAK,8BAAoB,OAAO,MAAM,MAAM,8CAAW;AAC7D,eAAW,KAAK,OAAO,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AAAA,EACnD,OAAO;AACL,UAAM;AAAA,MACJ,GAAG,OAAO,MAAM,MAAM;AAAA,IACxB;AACA,eAAW,KAAK,OAAO,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AACjD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,kMAAiD;AAAA,EAC9D;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,gBACpB,SACA,MAA2B,CAAC,GACb;AACf,MAAI;AACF,UAAM,kBAAkB,SAAS,GAAG;AAAA,EACtC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,SAAS,mBAAmB,gBAAwB,cAAsC;AACxF,QAAM,WAAWC,SAAQ,gBAAgB,YAAY;AACrD,MAAI;AACJ,MAAI;AACF,WAAO,aAAa,QAAQ;AAAA,EAC9B,QAAQ;AACN,WAAO,EAAE,MAAM,cAAc,MAAM,aAAa;AAAA,EAClD;AACA,SAAO,EAAE,MAAM,cAAc,MAAM,WAAWC,MAAK,MAAM,MAAM,CAAC,IAAI,SAAS,WAAW;AAC1F;AAaA,eAAsB,kBACpB,SACA,KAC6B;AAC7B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,eAAe;AAC5E,QAAM,QAAQJ,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,kBAAkB,SAAS,UAAU,UAAa,SAAS,MAAM,SAAS;AAChF,QAAM,aAAa,qBAAqB,QAAQ,EAAE;AAAA,IAAI,CAAC,MACrD,mBAAmB,gBAAgB,CAAC;AAAA,EACtC;AACA,QAAM,OAAO,mBAAmB,UAAU;AAE1C,QAAM,UAAU,QAAQ,UAAU,QAAQ,CAAC,mBAAmB,KAAK,MAAM,SAAS;AAClF,MAAI,SAAS;AACX,UAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,UAAMC;AAAA,MACJ;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,OAAO,KAAK;AAAA,QACZ,WAAW,EAAE,GAAG,SAAS,WAAW,YAAY,IAAI,EAAE,YAAY,EAAE;AAAA,MACtE;AAAA,MACA,EAAE,OAAO,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,SAA6B;AAAA,IACjC,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA,wBAAwB,oBAAoB,QAAQ;AAAA,EACtD;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,mBAAmB,MAAM,CAAC;AAAA,EACxC;AACA,SAAO;AACT;AASO,SAAS,mBAAmB,QAAoC;AACrE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,kFAA+C;AAC1D,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,GAAG,sBAAsB,OAAO,sBAAsB,CAAC;AAElE,MAAI,OAAO,iBAAiB;AAC1B,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,MAAM,WAAW,GAAG;AAC7B,UAAM,KAAK,wJAAyD;AAAA,EACtE,WAAW,OAAO,SAAS;AACzB,UAAM,KAAK,UAAK,OAAO,MAAM,MAAM,oGAA8B;AACjE,eAAW,KAAK,OAAO,MAAO,OAAM,KAAK,KAAK,EAAE,IAAI,EAAE;AACtD,UAAM,KAAK,EAAE;AACb,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAM;AAAA,MACJ,GAAG,OAAO,MAAM,MAAM;AAAA,IACxB;AACA,eAAW,KAAK,OAAO,MAAO,OAAM,KAAK,KAAK,EAAE,IAAI,EAAE;AACtD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,uLAA2C;AAAA,EACxD;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,oBAAU,OAAO,SAAS,MAAM,mGAAkC;AAC7E,eAAW,KAAK,OAAO,UAAU;AAC/B,YAAM,SACJ,EAAE,SAAS,aAAa,6CAAmC;AAC7D,YAAM,KAAK,KAAK,EAAE,IAAI,WAAM,MAAM,EAAE;AAAA,IACtC;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,iBACpB,SACA,MAA4B,CAAC,GACd;AACf,MAAI;AACF,UAAM,mBAAmB,SAAS,GAAG;AAAA,EACvC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAUA,eAAe,eAAe,UAAkB,SAAmC;AACjF,QAAM,MAAM,MAAM,cAAc,QAAQ,EAAE,IAAI,CAAC,YAAY,MAAM,OAAO,CAAC;AACzE,SAAO,IAAI,KAAK,EAAE,SAAS;AAC7B;AAQA,eAAe,iBACb,gBACA,OAC0B;AAC1B,QAAM,OAAO;AAAA,IACX,MAAM,MAAM;AAAA,IACZ,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,EAC3E;AACA,MAAI;AACJ,MAAI;AACF,WAAO,aAAaC,SAAQ,gBAAgB,MAAM,IAAI,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,kBAAkB,CAAC,EAAE;AAAA,EAC3D;AACA,MAAI,CAAC,WAAWC,MAAK,MAAM,MAAM,CAAC,GAAG;AACnC,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,kBAAkB,CAAC,EAAE;AAAA,EAC3D;AAEA,MAAI;AACF,UAAM,mBAA0C,CAAC;AACjD,eAAW,QAAQ,mBAAmB;AACpC,UAAI,UAAU;AACd,UAAI;AACF,kBAAUA,MAAK,MAAM,IAAI,CAAC;AAAA,MAC5B,QAAQ;AACN,kBAAU;AAAA,MACZ;AACA,uBAAiB,KAAK,EAAE,MAAM,SAAS,SAAS,MAAM,eAAe,MAAM,IAAI,EAAE,CAAC;AAAA,IACpF;AACA,WAAO,EAAE,GAAG,MAAM,WAAW,MAAM,iBAAiB;AAAA,EACtD,SAAS,OAAgB;AAGvB,QAAI,cAAc,KAAK,EAAG,OAAM;AAGhC,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,kBAAkB,CAAC,EAAE;AAAA,EAC3D;AACF;AAOA,eAAsB,mBACpB,SACA,KAC8B;AAC9B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,gBAAgB;AAC7E,QAAM,QAAQJ,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAClC,QAAM,QAA2B,CAAC;AAClC,aAAW,SAAS,OAAQ,OAAM,KAAK,MAAM,iBAAiB,gBAAgB,KAAK,CAAC;AAEpF,QAAM,UAAU,gBAAgB,KAAK;AACrC,QAAM,SAA8B,EAAE,GAAG,SAAS,WAAW,OAAO,SAAS,EAAE;AAE/E,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,oBAAoB,MAAM,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAQO,SAAS,oBAAoB,QAAqC;AACvE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,6JAA4C;AACvD,QAAM,KAAK,EAAE;AAEb,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,MAAM,SAAS,GAAG;AAC3B,UAAM;AAAA,MACJ,6HAAmC,OAAO,MAAM,MAAM;AAAA,IACxD;AACA,eAAW,KAAK,OAAO,OAAO;AAC5B,YAAM;AAAA,QACJ,KAAK,EAAE,IAAI,KAAK,EAAE,UAAU,YAAO,EAAE,IAAI;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,WAAW,OAAO,IAAI;AACpB,UAAM,KAAK,0LAAmD;AAAA,EAChE,OAAO;AAGL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM;AAAA,MACJ,qCAAsB,OAAO,QAAQ,MAAM;AAAA,IAC7C;AACA,eAAW,KAAK,OAAO,QAAS,OAAM,KAAK,KAAK,CAAC,EAAE;AACnD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM,KAAK,4CAAc,OAAO,WAAW,MAAM,+FAAoB;AACrE,eAAW,KAAK,OAAO,WAAY,OAAM,KAAK,KAAK,EAAE,IAAI,WAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,EAAE;AACrF,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,gCAAY,OAAO,YAAY,MAAM,uEAA0B;AAC1E,eAAW,KAAK,OAAO,YAAa,OAAM,KAAK,KAAK,CAAC,EAAE;AACvD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,oBACpB,SACA,MAA+B,CAAC,GACjB;AACf,MAAI;AACF,UAAM,sBAAsB,SAAS,GAAG;AAAA,EAC1C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAQA,SAAS,oBAAoB,gBAAwB,OAAsC;AACzF,QAAM,OAAO;AAAA,IACX,MAAM,MAAM;AAAA,IACZ,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,EAC3E;AACA,MAAI;AACJ,MAAI;AACF,WAAO,aAAaE,SAAQ,gBAAgB,MAAM,IAAI,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,cAAc,CAAC,EAAE;AAAA,EACvD;AACA,MAAI,CAAC,WAAWC,MAAK,MAAM,MAAM,CAAC,GAAG;AACnC,WAAO,EAAE,GAAG,MAAM,WAAW,OAAO,cAAc,CAAC,EAAE;AAAA,EACvD;AACA,SAAO,EAAE,GAAG,MAAM,WAAW,MAAM,cAAc,mBAAmBA,MAAK,MAAM,YAAY,CAAC,EAAE;AAChG;AAGA,SAAS,aAAa,OAAmD;AACvE,SAAO,iBAAiB,SAAS,OAAQ,MAA6B,SAAS;AACjF;AAQA,SAAS,mBAAmB,MAAwB;AAClD,MAAI;AACF,WAAO,aAAa,MAAM,MAAM,EAAE,MAAM,OAAO;AAAA,EACjD,SAAS,OAAgB;AACvB,QAAI,aAAa,KAAK,KAAK,MAAM,SAAS,SAAU,QAAO,CAAC;AAC5D,UAAM,IAAI,MAAM,6BAA6B,EAAE,OAAO,MAAM,CAAC;AAAA,EAC/D;AACF;AAGA,SAAS,mBAAmB,gBAAwB,MAA+B;AACjF,QAAM,OAAOA,MAAK,aAAaD,SAAQ,gBAAgB,KAAK,IAAI,CAAC,GAAG,YAAY;AAChF,MAAI,WAAW;AACf,MAAI;AACF,eAAW,aAAa,MAAM,MAAM;AAAA,EACtC,SAAS,OAAgB;AACvB,QAAI,EAAE,aAAa,KAAK,KAAK,MAAM,SAAS,WAAW;AAErD,YAAM,IAAI,MAAM,6BAA6B,EAAE,OAAO,MAAM,CAAC;AAAA,IAC/D;AAAA,EACF;AACA,QAAM,MAAM,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,IAAI,IAAI,OAAO;AACrE,MAAI;AACF,kBAAc,MAAM,GAAG,QAAQ,GAAG,GAAG,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC;AAAA,CAAI;AAAA,EACnE,SAAS,OAAgB;AACvB,UAAM,IAAI,MAAM,8BAA8B,EAAE,OAAO,MAAM,CAAC;AAAA,EAChE;AACF;AAUA,eAAsB,sBACpB,SACA,KACiC;AACjC,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,mBAAmB;AAChF,QAAM,QAAQH,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAClC,QAAM,QAAQ,OAAO,IAAI,CAAC,UAAU,oBAAoB,gBAAgB,KAAK,CAAC;AAC9E,QAAM,UAAU,cAAc,EAAE,OAAO,OAAO,UAAU,CAAC,GAAG,iBAAiB,EAAE,CAAC;AAEhF,QAAM,UAAU,QAAQ,UAAU,QAAQ,QAAQ,MAAM,SAAS;AACjE,MAAI,SAAS;AACX,eAAW,QAAQ,QAAQ,MAAO,oBAAmB,gBAAgB,IAAI;AAAA,EAC3E;AAEA,QAAM,SAAiC,EAAE,GAAG,SAAS,WAAW,OAAO,SAAS,GAAG,QAAQ;AAE3F,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,uBAAuB,MAAM,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AASO,SAAS,uBAAuB,QAAwC;AAC7E,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,+FAAmC;AAC9C,QAAM,KAAK,EAAE;AAEb,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,MAAM,SAAS,GAAG;AAC3B,UAAM,OAAO,OAAO,UAAU,yCAAW;AACzC,UAAM;AAAA,MACJ,GAAG,OAAO,UAAU,YAAO,EAAE,GAAG,OAAO,MAAM,MAAM,iCAAuB,IAAI;AAAA,IAChF;AACA,eAAW,KAAK,OAAO,MAAO,OAAM,KAAK,KAAK,EAAE,IAAI,WAAM,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,EAChF,WAAW,OAAO,IAAI;AACpB,UAAM,KAAK,uKAA+C;AAAA,EAC5D,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM;AAAA,MACJ,qCAAsB,OAAO,QAAQ,MAAM;AAAA,IAC7C;AACA,eAAW,KAAK,OAAO,QAAS,OAAM,KAAK,KAAK,CAAC,EAAE;AACnD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,gCAAY,OAAO,YAAY,MAAM,uEAA0B;AAC1E,eAAW,KAAK,OAAO,YAAa,OAAM,KAAK,KAAK,CAAC,EAAE;AACvD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,mBACpB,SACA,MAA8B,CAAC,GAChB;AACf,MAAI;AACF,UAAM,qBAAqB,SAAS,GAAG;AAAA,EACzC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,SAAS,uBACP,aACA,eACoC;AACpC,SAAO;AAAA,IACL,EAAE,MAAM,aAAa,QAAQI,UAAS,aAAa,aAAa,EAAE;AAAA,IAClE,EAAE,MAAM,aAAa,QAAQ,eAAe;AAAA,IAC5C,EAAE,MAAM,mCAAmC,QAAQ,MAAM,cAAc,GAAG;AAAA,EAC5E;AACF;AAYA,SAAS,eACP,UACA,gBAC2D;AAC3D,MAAI;AACJ,MAAI;AACF,aAAS,UAAU,QAAQ,EAAE,eAAe;AAAA,EAC9C,SAAS,OAAgB;AACvB,QAAI,aAAa,KAAK,KAAK,MAAM,SAAS,SAAU,QAAO,EAAE,OAAO,UAAU;AAC9E,WAAO,EAAE,OAAO,UAAU;AAAA,EAC5B;AACA,MAAI,CAAC,OAAQ,QAAO,EAAE,OAAO,WAAW;AACxC,QAAM,SAAS,aAAa,QAAQ;AACpC,SAAO,WAAW,iBACd,EAAE,OAAO,UAAU,IACnB,EAAE,OAAO,YAAY,cAAc,OAAO;AAChD;AAWA,SAAS,mBACP,gBACA,YACA,OACkB;AAClB,QAAM,OAAO,EAAE,MAAM,MAAM,KAAK;AAChC,MAAI;AACJ,MAAI;AACF,WAAO,aAAaF,SAAQ,gBAAgB,MAAM,IAAI,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO,EAAE,GAAG,MAAM,UAAU,OAAO,WAAW,OAAO,kBAAkB,OAAO,OAAO,CAAC,EAAE;AAAA,EAC1F;AACA,MAAI,SAAS,YAAY;AACvB,WAAO,EAAE,GAAG,MAAM,UAAU,MAAM,WAAW,MAAM,kBAAkB,OAAO,OAAO,CAAC,EAAE;AAAA,EACxF;AACA,MAAI,CAAC,WAAWC,MAAK,MAAM,MAAM,CAAC,GAAG;AACnC,WAAO,EAAE,GAAG,MAAM,UAAU,OAAO,WAAW,OAAO,kBAAkB,OAAO,OAAO,CAAC,EAAE;AAAA,EAC1F;AAEA,QAAM,gBAAgBA,MAAK,YAAY,UAAUE,UAAS,IAAI,GAAG,cAAc;AAC/E,MAAI,CAAC,WAAW,aAAa,GAAG;AAC9B,WAAO,EAAE,GAAG,MAAM,UAAU,OAAO,WAAW,MAAM,kBAAkB,OAAO,OAAO,CAAC,EAAE;AAAA,EACzF;AAEA,QAAM,QAAkC,uBAAuB,MAAM,aAAa,EAAE;AAAA,IAClF,CAAC,SAAS;AACR,YAAM,EAAE,OAAO,aAAa,IAAI,eAAeF,MAAK,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM;AACjF,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX,gBAAgB,KAAK;AAAA,QACrB;AAAA,QACA,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU;AAAA,IACV,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,eAAeE,UAAS,IAAI;AAAA,IAC5B;AAAA,EACF;AACF;AASA,SAAS,iBACP,gBACA,MACoE;AACpE,MAAI;AACJ,MAAI;AACF,WAAO,aAAaH,SAAQ,gBAAgB,KAAK,IAAI,CAAC;AAAA,EACxD,SAAS,OAAgB;AACvB,UAAM,UAAU,cAAc,KAAK;AACnC,WAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,EAAE;AAAA,EACtF;AACA,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAA8C,CAAC;AACrD,aAAW,EAAE,MAAM,OAAO,KAAK,KAAK,UAAU;AAC5C,UAAM,WAAWC,MAAK,MAAM,IAAI;AAChC,QAAI;AACF,gBAAUG,SAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,kBAAY,QAAQ,QAAQ;AAC5B,cAAQ,KAAK,IAAI;AAAA,IACnB,SAAS,OAAgB;AACvB,aAAO,KAAK,EAAE,MAAM,MAAM,SAAS,cAAc,KAAK,EAAE,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,SAAO,EAAE,SAAS,OAAO;AAC3B;AASA,SAAS,cAAc,OAAwB;AAC7C,SAAO,aAAa,KAAK,IAAI,MAAM,OAAO;AAC5C;AAUA,eAAsB,qBACpB,SACA,KACgC;AAChC,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,kBAAkB;AAC/E,QAAM,QAAQP,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAClC,QAAM,aAAa,aAAa,cAAc;AAC9C,QAAM,QAAQ,OAAO,IAAI,CAAC,UAAU,mBAAmB,gBAAgB,YAAY,KAAK,CAAC;AACzF,QAAM,UAAU,qBAAqB,KAAK;AAE1C,QAAM,YAAY,QAAQ,UAAU,QAAQ,QAAQ,MAAM,SAAS;AACnE,QAAM,WAA8D,CAAC;AACrE,MAAI,eAAe;AACnB,MAAI,WAAW;AACb,eAAW,QAAQ,QAAQ,OAAO;AAChC,YAAM,EAAE,SAAS,OAAO,IAAI,iBAAiB,gBAAgB,IAAI;AACjE,sBAAgB,QAAQ;AACxB,iBAAW,KAAK,OAAQ,UAAS,KAAK,EAAE,MAAM,KAAK,MAAM,MAAM,EAAE,MAAM,SAAS,EAAE,QAAQ,CAAC;AAAA,IAC7F;AAAA,EACF;AAEA,QAAM,SAAgC;AAAA,IACpC,GAAG;AAAA,IACH,WAAW,OAAO,SAAS;AAAA,IAC3B,SAAS,eAAe;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,sBAAsB,MAAM,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AAUO,SAAS,sBAAsB,QAAuC;AAC3E,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,uFAA+C;AAC1D,QAAM,KAAK,EAAE;AAEb,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,MAAM,SAAS,GAAG;AAG3B,UAAM,YAAY,OAAO,WAAW,OAAO,SAAS,SAAS;AAC7D,QAAI,CAAC,WAAW;AACd,YAAM;AAAA,QACJ,GAAG,OAAO,MAAM,MAAM;AAAA,MACxB;AACA,iBAAW,KAAK,OAAO,OAAO;AAC5B,cAAM,KAAK,KAAK,EAAE,IAAI,EAAE;AACxB,mBAAW,KAAK,EAAE,SAAU,OAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,MACvE;AAAA,IACF,OAAO;AAGL,YAAM,SACJ,OAAO,SAAS,WAAW,IACvB,kFACA,OAAO,UACL,mIACA;AACR,YAAM,KAAK,MAAM;AACjB,iBAAW,KAAK,OAAO,OAAO;AAC5B,cAAM,cAAc,IAAI;AAAA,UACtB,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,QACpE;AACA,cAAM,UAAU,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,IAAI,CAAC;AACjE,YAAI,QAAQ,WAAW,EAAG;AAC1B,cAAM,KAAK,KAAK,EAAE,IAAI,EAAE;AACxB,mBAAW,KAAK,QAAS,OAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,MACpE;AAAA,IACF;AAAA,EACF,WAAW,OAAO,IAAI;AACpB,UAAM,KAAK,sLAA+C;AAAA,EAC5D,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,KAAK,sCAAa,OAAO,SAAS,MAAM,wGAA6B;AAC3E,eAAW,KAAK,OAAO,SAAU,OAAM,KAAK,KAAK,EAAE,IAAI,WAAM,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AACnF,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,UAAU,SAAS,GAAG;AAC/B,UAAM;AAAA,MACJ,oBAAU,OAAO,UAAU,MAAM;AAAA,IACnC;AACA,eAAW,KAAK,OAAO,WAAW;AAChC,YAAM,SACJ,EAAE,WAAW,aACT,oEAAuB,EAAE,gBAAgB,GAAG,MAC5C,EAAE,WAAW,aACX,kGACA;AACR,YAAM,KAAK,KAAK,EAAE,IAAI,WAAM,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,IACjD;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM;AAAA,MACJ,8BAAoB,OAAO,WAAW,MAAM;AAAA,IAC9C;AACA,eAAW,KAAK,OAAO,YAAY;AACjC,YAAM,KAAK,YAAY,EAAE,aAAa,qBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,IAC5E;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,iBAAiB,SAAS,GAAG;AACtC,UAAM;AAAA,MACJ,8BAAoB,OAAO,iBAAiB,MAAM;AAAA,IACpD;AACA,eAAW,KAAK,OAAO,iBAAkB,OAAM,KAAK,KAAK,CAAC,EAAE;AAC5D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,gCAAY,OAAO,YAAY,MAAM,uEAA0B;AAC1E,eAAW,KAAK,OAAO,YAAa,OAAM,KAAK,KAAK,CAAC,EAAE;AACvD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,oBACpB,SACA,MAA+B,CAAC,GACjB;AACf,MAAI;AACF,UAAM,sBAAsB,SAAS,GAAG;AAAA,EAC1C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,SAAS,eAAe,gBAAwB,UAA0B;AACxE,QAAM,MAAME,SAAQ,gBAAgB,QAAQ;AAC5C,MAAI;AACF,WAAO,aAAa,GAAG;AAAA,EACzB,QAAQ;AACN,QAAI;AACF,aAAOC,MAAK,aAAaG,SAAQ,GAAG,CAAC,GAAGD,UAAS,GAAG,CAAC;AAAA,IACvD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAUA,SAAS,eAAe,gBAAwB,SAAiB,OAAgC;AAC/F,MAAI;AACJ,MAAI;AACF,eAAW,aAAaH,SAAQ,gBAAgB,MAAM,IAAI,CAAC;AAAA,EAC7D,QAAQ;AACN,WAAO,EAAE,MAAM,MAAM,MAAM,WAAW,MAAM;AAAA,EAC9C;AACA,QAAM,iBAAiBE,UAAS,SAAS,QAAQ;AAKjD,MAAI,mBAAmB,MAAM,mBAAmB,KAAK;AACnD,WAAO,EAAE,MAAM,MAAM,MAAM,WAAW,MAAM;AAAA,EAC9C;AACA,QAAM,WAAWC,UAAS,QAAQ;AAClC,QAAM,EAAE,OAAO,aAAa,IAAI,eAAeF,MAAK,SAAS,QAAQ,GAAG,cAAc;AACtF,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,EACvD;AACF;AAGA,SAAS,cACP,SACA,UACoE;AACpE,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAA8C,CAAC;AACrD,aAAW,EAAE,MAAM,OAAO,KAAK,UAAU;AACvC,UAAM,WAAWA,MAAK,SAAS,IAAI;AACnC,QAAI;AACF,gBAAUG,SAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,kBAAY,QAAQ,QAAQ;AAC5B,cAAQ,KAAK,IAAI;AAAA,IACnB,SAAS,OAAgB;AACvB,aAAO,KAAK,EAAE,MAAM,SAAS,cAAc,KAAK,EAAE,CAAC;AAAA,IACrD;AAAA,EACF;AACA,SAAO,EAAE,SAAS,OAAO;AAC3B;AAGA,IAAM,oCAAyD,IAAI;AAAA,EACjE,kBAAkB,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAC9E;AAgBA,SAAS,iBACP,SACA,MACA,iBAC2D;AAC3D,QAAM,WAAWH,MAAK,SAAS,IAAI;AACnC,MAAI;AACJ,MAAI;AACF,aAAS,UAAU,QAAQ,EAAE,eAAe;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACJ,MAAI;AACF,aAAS,aAAa,QAAQ;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AAMA,QAAM,WAAWI,YAAW,MAAM,IAAI,SAASL,SAAQ,SAAS,MAAM;AACtE,MAAI;AACF,QAAI,gBAAgB,IAAI,aAAa,QAAQ,CAAC,EAAG,QAAO;AAAA,EAC1D,QAAQ;AAAA,EAER;AACA,MAAIK,YAAW,MAAM,EAAG,QAAO,EAAE,QAAQ,MAAM,WAAW;AAC1D,MAAI,QAAQ;AACZ,MAAI;AACF,YAAQ,SAAS,QAAQ,EAAE,YAAY;AAAA,EACzC,QAAQ;AACN,YAAQ;AAAA,EACV;AACA,MAAI,CAAC,OAAO;AAEV,WAAO,EAAE,QAAQ,MAAM,WAAW,QAAQ,IAAI,aAAa,SAAS;AAAA,EACtE;AACA,SAAO,EAAE,QAAQ,MAAM,WAAWJ,MAAK,UAAU,MAAM,CAAC,IAAI,SAAS,WAAW;AAClF;AAWO,SAAS,wBACd,SACA,iBACoB;AACpB,MAAI;AACJ,MAAI;AACF,YAAQ,YAAY,OAAO;AAAA,EAC7B,SAAS,OAAgB;AACvB,QAAI,aAAa,KAAK,KAAK,MAAM,SAAS,SAAU,QAAO,CAAC;AAK5D,UAAM,IAAI,MAAM,oJAA2C;AAAA,MACzD,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,QAAM,QAA4B,CAAC;AACnC,aAAW,QAAQ,OAAO;AACxB,QAAI,kCAAkC,IAAI,KAAK,YAAY,CAAC,EAAG;AAC/D,UAAM,IAAI,iBAAiB,SAAS,MAAM,eAAe;AACzD,QAAI,MAAM,KAAM;AAChB,UAAM,KAAK,EAAE,MAAM,QAAQ,EAAE,QAAQ,MAAM,EAAE,KAAK,CAAC;AAAA,EACrD;AACA,SAAO;AACT;AAUO,SAAS,eACd,SACA,SACA,iBACmE;AACnE,QAAM,SAAmB,CAAC;AAC1B,QAAM,SAA8C,CAAC;AACrD,aAAW,EAAE,KAAK,KAAK,SAAS;AAC9B,UAAM,WAAWA,MAAK,SAAS,IAAI;AACnC,UAAM,IAAI,iBAAiB,SAAS,MAAM,eAAe;AACzD,QAAI,MAAM,QAAQ,EAAE,SAAS,QAAQ;AACnC,aAAO,KAAK;AAAA,QACV;AAAA,QACA,SACE;AAAA,MACJ,CAAC;AACD;AAAA,IACF;AACA,QAAI;AACF,iBAAW,QAAQ;AACnB,aAAO,KAAK,IAAI;AAAA,IAClB,SAAS,OAAgB;AACvB,aAAO,KAAK,EAAE,MAAM,SAAS,cAAc,KAAK,EAAE,CAAC;AAAA,IACrD;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAiBA,eAAsB,sBACpB,SACA,KACiC;AACjC,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,mBAAmB;AAChF,QAAM,QAAQJ,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,WAAW,SAAS,UAAU;AACpC,QAAM,SAAS,SAAS,SAAS,CAAC;AAElC,MAAI;AACJ,MAAI,aAAa,QAAW;AAC1B,aAAS;AAAA,MACP,UAAU,CAAC;AAAA,MACX,WAAW,CAAC;AAAA,MACZ,YAAY,CAAC;AAAA,MACb,aAAa,CAAC;AAAA,MACd,SAAS,CAAC;AAAA,MACV,cAAc,CAAC;AAAA,MACf,cAAc;AAAA,MACd,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,UAAU,CAAC;AAAA,MACX,eAAe,CAAC;AAAA,IAClB;AAAA,EACF,OAAO;AACL,UAAM,UAAU,eAAe,gBAAgB,QAAQ;AACvD,UAAM,QAAQ,OAAO,IAAI,CAAC,UAAU,eAAe,gBAAgB,SAAS,KAAK,CAAC;AAMlF,UAAM,cAAc,OAAO,IAAI,CAAC,UAAUK,UAASH,SAAQ,gBAAgB,MAAM,IAAI,CAAC,CAAC;AACvF,UAAM,kBAAkB,oBAAI,IAAY;AACxC,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACF,wBAAgB,IAAI,aAAaA,SAAQ,gBAAgB,MAAM,IAAI,CAAC,CAAC;AAAA,MACvE,QAAQ;AAAA,MAER;AAAA,IACF;AACA,UAAM,WAAW,wBAAwB,SAAS,eAAe;AACjE,UAAM,OAAO,kBAAkB,OAAO,UAAU,WAAW;AAE3D,UAAM,WAAgD,CAAC;AACvD,QAAI,eAAe;AACnB,QAAI,QAAQ,UAAU,QAAQ,KAAK,SAAS,SAAS,GAAG;AACtD,YAAM,UAAU,cAAc,SAAS,KAAK,QAAQ;AACpD,qBAAe,QAAQ,QAAQ;AAC/B,iBAAW,KAAK,QAAQ,OAAQ,UAAS,KAAK,CAAC;AAAA,IACjD;AAMA,UAAM,gBACJ,QAAQ,UAAU,QAAQ,KAAK,QAAQ,SAAS,KAAK,KAAK,YAAY,SAAS;AACjF,UAAM,gBAAqD,CAAC;AAC5D,QAAI,cAAc;AAClB,QAAI,QAAQ,UAAU,QAAQ,KAAK,QAAQ,SAAS,KAAK,KAAK,YAAY,WAAW,GAAG;AACtF,YAAM,UAAU,eAAe,SAAS,KAAK,SAAS,eAAe;AACrE,oBAAc,QAAQ,OAAO;AAC7B,iBAAW,KAAK,QAAQ,OAAQ,eAAc,KAAK,CAAC;AAAA,IACtD;AAKA,UAAM,qBACJ,KAAK,SAAS,SAAS,KAAK,EAAE,QAAQ,UAAU,QAAQ,SAAS,WAAW;AAC9E,UAAM,oBACJ,KAAK,QAAQ,SAAS,KACtB,EAAE,QAAQ,UAAU,QAAQ,CAAC,iBAAiB,cAAc,WAAW;AACzE,UAAM,KACJ,KAAK,UAAU,WAAW,KAC1B,KAAK,WAAW,WAAW,KAC3B,KAAK,YAAY,WAAW,KAC5B,KAAK,aAAa,WAAW,KAC7B,CAAC,sBACD,CAAC;AAEH,aAAS;AAAA,MACP,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,MACT,SAAS,eAAe;AAAA,MACxB,QAAQ,cAAc;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,uBAAuB,MAAM,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAUO,SAAS,uBAAuB,QAAwC;AAC7E,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,+DAAsC;AACjD,QAAM,KAAK,EAAE;AAEb,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,YAAY,OAAO,WAAW,OAAO,SAAS,SAAS;AAC7D,QAAI,CAAC,WAAW;AACd,YAAM;AAAA,QACJ,GAAG,OAAO,SAAS,MAAM;AAAA,MAC3B;AACA,iBAAW,KAAK,OAAO,SAAU,OAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,IAC5E,OAAO;AACL,YAAM,SAAS,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACzD,YAAM,SACJ,OAAO,SAAS,WAAW,IACvB,gFACA,OAAO,UACL,iIACA;AACR,YAAM,KAAK,MAAM;AACjB,iBAAW,KAAK,OAAO,UAAU;AAC/B,YAAI,OAAO,IAAI,EAAE,IAAI,EAAG;AACxB,cAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,MAC3C;AAAA,IACF;AAAA,EACF,WAAW,OAAO,IAAI;AACpB,UAAM;AAAA,MACJ,8HAAoC,OAAO,YAAY;AAAA,IACzD;AAAA,EACF,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,KAAK,sCAAa,OAAO,SAAS,MAAM,wGAA6B;AAC3E,eAAW,KAAK,OAAO,SAAU,OAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AACvE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM,YAAY,OAAO,UAAU,OAAO,cAAc,SAAS;AACjE,QAAI,OAAO,eAAe;AACxB,YAAM;AAAA,QACJ,GAAG,OAAO,QAAQ,MAAM;AAAA,MAC1B;AACA,iBAAW,KAAK,OAAO,QAAS,OAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,IAC3E,WAAW,CAAC,WAAW;AACrB,YAAM;AAAA,QACJ,GAAG,OAAO,QAAQ,MAAM;AAAA,MAC1B;AACA,iBAAW,KAAK,OAAO,QAAS,OAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,IAC3E,OAAO;AACL,YAAM,SAAS,IAAI,IAAI,OAAO,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAC9D,YAAM,SACJ,OAAO,cAAc,WAAW,IAC5B,6EACA,OAAO,SACL,2HACA;AACR,YAAM,KAAK,MAAM;AACjB,iBAAW,KAAK,OAAO,SAAS;AAC9B,YAAI,OAAO,IAAI,EAAE,IAAI,EAAG;AACxB,cAAM,KAAK,OAAO,EAAE,IAAI,OAAO,EAAE,MAAM,EAAE;AAAA,MAC3C;AAAA,IACF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,cAAc,SAAS,GAAG;AACnC,UAAM;AAAA,MACJ,sCAAa,OAAO,cAAc,MAAM;AAAA,IAC1C;AACA,eAAW,KAAK,OAAO,cAAe,OAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AAC5E,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,UAAU,SAAS,GAAG;AAC/B,UAAM;AAAA,MACJ,oBAAU,OAAO,UAAU,MAAM;AAAA,IACnC;AACA,eAAW,KAAK,OAAO,WAAW;AAChC,YAAM,SACJ,EAAE,WAAW,aACT,oEAAuB,EAAE,gBAAgB,GAAG,MAC5C,EAAE,WAAW,aACX,kGACA;AACR,YAAM,KAAK,KAAK,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,IACrC;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM;AAAA,MACJ,6BAAmB,OAAO,WAAW,MAAM;AAAA,IAC7C;AACA,eAAW,KAAK,OAAO,WAAY,OAAM,KAAK,KAAK,EAAE,QAAQ,WAAM,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE;AACvF,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM;AAAA,MACJ,gCAAY,OAAO,YAAY,MAAM;AAAA,IACvC;AACA,eAAW,KAAK,OAAO,YAAa,OAAM,KAAK,KAAK,CAAC,EAAE;AACvD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,aAAa,SAAS,GAAG;AAClC,UAAM;AAAA,MACJ,sCAAkB,OAAO,aAAa,MAAM;AAAA,IAC9C;AACA,eAAW,KAAK,OAAO,cAAc;AACnC,YAAM,SACJ,EAAE,WAAW,WACT,mHACA,EAAE,WAAW,aACX,4KACA;AACR,YAAM,KAAK,KAAK,EAAE,IAAI,OAAO,EAAE,MAAM,KAAK,MAAM,EAAE;AAAA,IACpD;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,iBACpB,SACA,MAA4B,CAAC,GACd;AACf,MAAI;AACF,UAAM,mBAAmB,SAAS,GAAG;AAAA,EACvC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAGA,SAAS,iBAAiB,YAAoB,eAA+B;AAC3E,SAAOC,MAAK,YAAY,UAAU,eAAe,cAAc;AACjE;AAGA,SAAS,kBAAkB,eAA+B;AACxD,SAAOA,MAAK,UAAU,eAAe,cAAc;AACrD;AAYA,eAAe,iBACb,gBACA,YACA,OAC0B;AAC1B,QAAM,WAAW;AAAA,IACf,MAAM,MAAM;AAAA,IACZ,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,IACzE,GAAI,MAAM,aAAa,SAAY,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,IACnE,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,EACxE;AACA,MAAI;AACJ,MAAI;AACF,WAAO,aAAaD,SAAQ,gBAAgB,MAAM,IAAI,CAAC;AAAA,EACzD,QAAQ;AACN,WAAO,EAAE,GAAG,UAAU,UAAU,OAAO,WAAW,OAAO,kBAAkB,MAAM;AAAA,EACnF;AACA,MAAI,SAAS,YAAY;AACvB,WAAO,EAAE,GAAG,UAAU,UAAU,MAAM,WAAW,MAAM,kBAAkB,MAAM;AAAA,EACjF;AACA,MAAI,CAAC,WAAWC,MAAK,MAAM,MAAM,CAAC,GAAG;AACnC,WAAO,EAAE,GAAG,UAAU,UAAU,OAAO,WAAW,OAAO,kBAAkB,MAAM;AAAA,EACnF;AAEA,QAAM,gBAAgBE,UAAS,IAAI;AACnC,MAAI;AACJ,MAAI;AACF,cAAU,MAAMG,kBAAiB,iBAAiB,YAAY,aAAa,CAAC;AAAA,EAC9E,QAAQ;AAEN,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,IACrB;AAAA,EACF;AACA,MAAI,YAAY,MAAM;AACpB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA,kBAAkB;AAAA,IACpB;AAAA,EACF;AACA,QAAM,UAAU,aAAa,OAAO;AACpC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,YAAY,QAAQ;AAAA,IACpB,GAAI,QAAQ,SAAS,OAAO,EAAE,cAAc,QAAQ,UAAU,IAAI,CAAC;AAAA,EACrE;AACF;AAgBA,eAAe,gBAAgB,YAAoB,MAAqC;AACtF,QAAM,OAAO,iBAAiB,YAAY,KAAK,aAAa;AAC5D,QAAM,QAAQ,kBAAkB,KAAK,aAAa;AAIlD,MAAI,SAAS;AACb,MAAI;AACF,aAAS,UAAU,IAAI,EAAE,eAAe;AAAA,EAC1C,QAAQ;AACN,aAAS;AAAA,EACX;AACA,MAAI,OAAQ,OAAM,IAAI,MAAM,6BAA6B,KAAK,EAAE;AAEhE,MAAI,KAAK,WAAW,SAAU,WAAUF,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1E,QAAM,WAAW,MAAME,kBAAiB,IAAI;AAC5C,QAAMC,mBAAkB,MAAMC,mBAAkB,UAAU,KAAK,cAAc,KAAK,CAAC;AACrF;AAUA,SAAS,oBAAoB,OAAwB;AACnD,MACE,iBAAiB,UAChB,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM,QAAQ,WAAW,WAAW,IAC5E;AACA,WAAO,MAAM;AAAA,EACf;AACA,QAAM,QAAQ,iBAAiB,QAAS,MAA8B,QAAQ;AAC9E,MAAI,aAAa,KAAK,EAAG,QAAO,MAAM;AACtC,MAAI,aAAa,KAAK,EAAG,QAAO,MAAM;AACtC,SAAO;AACT;AAUA,eAAsB,mBACpB,SACA,KAC8B;AAC9B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,gBAAgB;AAC7E,QAAM,QAAQX,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAEzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAClC,QAAM,aAAa,aAAa,cAAc;AAC9C,QAAM,QAA2B,CAAC;AAClC,aAAW,SAAS,OAAQ,OAAM,KAAK,MAAM,iBAAiB,gBAAgB,YAAY,KAAK,CAAC;AAChG,QAAM,UAAU,oBAAoB,KAAK;AAEzC,QAAM,WAAgD,CAAC;AACvD,MAAI,eAAe;AACnB,MAAI,QAAQ,UAAU,QAAQ,QAAQ,MAAM,SAAS,GAAG;AACtD,eAAW,QAAQ,QAAQ,OAAO;AAChC,UAAI;AACF,cAAM,gBAAgB,YAAY,IAAI;AACtC,wBAAgB;AAAA,MAClB,SAAS,OAAgB;AACvB,iBAAS,KAAK,EAAE,MAAM,KAAK,MAAM,SAAS,oBAAoB,KAAK,EAAE,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAA8B;AAAA,IAClC,GAAG;AAAA,IACH,WAAW,OAAO,SAAS;AAAA,IAC3B,SAAS,eAAe;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,oBAAoB,MAAM,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,QAA0C;AACnE,SAAO,WAAW,WAAW,6BAAS;AACxC;AAWO,SAAS,oBAAoB,QAAqC;AACvE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,iIAAuC;AAClD,QAAM,KAAK,EAAE;AAEb,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM;AAAA,MACJ;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,MAAM,SAAS,GAAG;AAE3B,UAAM,YAAY,OAAO,WAAW,OAAO,SAAS,SAAS;AAC7D,QAAI,CAAC,WAAW;AACd,YAAM;AAAA,QACJ,GAAG,OAAO,MAAM,MAAM;AAAA,MACxB;AACA,iBAAW,KAAK,OAAO,OAAO;AAC5B,cAAM;AAAA,UACJ,KAAK,EAAE,IAAI,KAAK,kBAAkB,EAAE,MAAM,CAAC,YAAO,kBAAkB,EAAE,aAAa,CAAC;AAAA,QACtF;AACA,mBAAW,MAAM,EAAE,aAAa,MAAM,IAAI,EAAG,OAAM,KAAK,OAAO,EAAE,EAAE;AAAA,MACrE;AAAA,IACF,OAAO;AACL,YAAM,SAAS,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACzD,YAAM,SACJ,OAAO,SAAS,WAAW,IACvB,wGACA,OAAO,UACL,wIACA;AACR,YAAM,KAAK,MAAM;AACjB,iBAAW,KAAK,OAAO,OAAO;AAC5B,YAAI,OAAO,IAAI,EAAE,IAAI,EAAG;AACxB,cAAM;AAAA,UACJ,KAAK,EAAE,IAAI,KAAK,kBAAkB,EAAE,MAAM,CAAC,YAAO,kBAAkB,EAAE,aAAa,CAAC;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,OAAO,IAAI;AACpB,UAAM,KAAK,qLAAmD;AAAA,EAChE,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,UAAM,KAAK,6BAAS,OAAO,OAAO,MAAM,MAAM,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE;AACxE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM;AAAA,MACJ,kDAAe,OAAO,SAAS,MAAM;AAAA,IACvC;AACA,eAAW,KAAK,OAAO,SAAU,OAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AACvE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,gBAAgB,SAAS,GAAG;AACrC,UAAM;AAAA,MACJ,4CAAc,OAAO,gBAAgB,MAAM;AAAA,IAC7C;AACA,eAAW,KAAK,OAAO,iBAAiB;AACtC,YAAM,SACJ,EAAE,WAAW,eAAe,2DAAc,8CAAW,EAAE,MAAM;AAC/D,YAAM,KAAK,KAAK,EAAE,IAAI,KAAK,MAAM,EAAE;AAAA,IACrC;AACA,UAAM;AAAA,MACJ,sLAA0C,eAAe,eAAU,aAAa;AAAA,IAClF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM;AAAA,MACJ,sDAAwB,OAAO,WAAW,MAAM;AAAA,IAClD;AACA,eAAW,KAAK,OAAO,WAAY,OAAM,KAAK,KAAK,CAAC,EAAE;AACtD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM;AAAA,MACJ,8BAAoB,OAAO,WAAW,MAAM;AAAA,IAC9C;AACA,eAAW,KAAK,OAAO,YAAY;AACjC,YAAM,KAAK,YAAY,EAAE,aAAa,qBAAgB,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,IAC5E;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,WAAW,SAAS,GAAG;AAChC,UAAM;AAAA,MACJ,gCAAY,OAAO,WAAW,MAAM;AAAA,IACtC;AACA,eAAW,KAAK,OAAO,WAAY,OAAM,KAAK,KAAK,CAAC,EAAE;AACtD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM;AAAA,MACJ,cAAc,OAAO,QAAQ,MAAM;AAAA,IACrC;AACA,eAAW,KAAK,OAAO,QAAS,OAAM,KAAK,KAAK,CAAC,EAAE;AACnD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,gCAAY,OAAO,YAAY,MAAM,uEAA0B;AAC1E,eAAW,KAAK,OAAO,YAAa,OAAM,KAAK,KAAK,CAAC,EAAE;AACvD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,kBACpB,QACA,SACA,MAA6B,CAAC,GACf;AACf,MAAI;AACF,UAAM,oBAAoB,QAAQ,SAAS,GAAG;AAAA,EAChD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAQA,SAAS,sBACP,gBACA,UACA,QACiB;AACjB,QAAM,QAAyB;AAAA,IAC7B,WAAW;AAAA,IACX,UAAU;AAAA,IACV,kBAAkB,CAAC;AAAA,IACnB,mBAAmB,CAAC;AAAA,IACpB,WAAW;AAAA,EACb;AACA,MAAI;AACJ,MAAI;AACF,WAAO,aAAaE,SAAQ,gBAAgB,MAAM,CAAC;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,aAAa,aAAa,cAAc;AAC9C,QAAM,gBAAgBG,UAAS,IAAI;AAEnC,QAAM,mBAA6B,CAAC;AACpC,aAAW,QAAQ,mBAAmB;AACpC,QAAI;AACF,gBAAUF,MAAK,MAAM,IAAI,CAAC;AAC1B,uBAAiB,KAAK,IAAI;AAAA,IAC5B,QAAQ;AAAA,IAER;AAAA,EACF;AAKA,MAAI;AACJ,MAAI;AACF,cAAU,IAAI,IAAI,mBAAmBA,MAAK,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAAA,EACrF,QAAQ;AACN,cAAU,oBAAI,IAAI;AAAA,EACpB;AACA,QAAM,oBAAoB,kBAAkB,OAAO,CAAC,MAAM,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC;AAEhG,QAAMQ,aAAY,WAAWR,MAAK,YAAY,UAAU,eAAe,cAAc,CAAC;AAEtF,MAAI,WAAW;AACf,QAAM,WAAW,SAAS,UAAU;AACpC,MAAI,aAAa,QAAW;AAC1B,QAAI;AACF,gBAAUA,MAAK,eAAe,gBAAgB,QAAQ,GAAG,aAAa,CAAC;AACvE,iBAAW;AAAA,IACb,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA,mBAAmB,CAAC,GAAG,iBAAiB;AAAA,IACxC,WAAAQ;AAAA,EACF;AACF;AAGA,SAAS,QAA0B,KAAQ,KAAiB;AAC1D,QAAM,QAAQ,EAAE,GAAG,IAAI;AACvB,SAAO,MAAM,GAAG;AAChB,SAAO;AACT;AAYA,SAAS,sBAAsB,UAAoB,MAAmB,WAA6B;AACjG,MAAI,OAAiB,EAAE,GAAG,UAAU,WAAW,EAAE,GAAG,SAAS,WAAW,YAAY,UAAU,EAAE;AAEhG,SAAO,KAAK,eAAe,QAAQ,MAAM,OAAO,IAAI,EAAE,GAAG,MAAM,OAAO,KAAK,UAAU;AAErF,MAAI,KAAK,oBAAoB,QAAW;AACtC,QAAI,KAAK,gBAAgB,WAAW,GAAG;AACrC,YAAM,eACJ,SAAS,WAAW,SAAY,QAAQ,SAAS,QAAQ,cAAc,IAAI,CAAC;AAC9E,aACE,OAAO,KAAK,YAAY,EAAE,WAAW,IACjC,QAAQ,MAAM,QAAQ,IACtB,EAAE,GAAG,MAAM,QAAQ,aAAa;AAAA,IACxC,OAAO;AACL,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ,EAAE,GAAI,SAAS,UAAU,CAAC,GAAI,cAAc,KAAK,gBAAgB;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAWA,eAAsB,oBACpB,QACA,SACA,KAC+B;AAC/B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,iBAAiB;AAC9E,QAAM,QAAQZ,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AACzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAElC,MAAI,iBAAiB;AACrB,MAAI;AACF,qBAAiB,aAAaE,SAAQ,gBAAgB,MAAM,CAAC,MAAM,aAAa,cAAc;AAAA,EAChG,QAAQ;AACN,qBAAiB;AAAA,EACnB;AAEA,QAAM,OAAO,YAAY;AAAA,IACvB,GAAI,SAAS,UAAU,SAAY,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAAA,IAChE,GAAI,SAAS,QAAQ,iBAAiB,SAClC,EAAE,aAAa,SAAS,OAAO,aAAa,IAC5C,CAAC;AAAA,IACL;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,WACJ,KAAK,SAAS,CAAC,KAAK,WAChB,sBAAsB,gBAAgB,UAAU,MAAM,IACtD;AAAA,IACE,WAAW;AAAA,IACX,UAAU;AAAA,IACV,kBAAkB,CAAC;AAAA,IACnB,mBAAmB,CAAC;AAAA,IACpB,WAAW;AAAA,EACb;AAEN,QAAM,UAAU,QAAQ,UAAU,QAAQ,KAAK,SAAS,CAAC,KAAK;AAC9D,MAAI,SAAS;AACX,UAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,UAAMD,eAAc,OAAO,sBAAsB,UAAU,MAAM,IAAI,EAAE,YAAY,CAAC,GAAG;AAAA,MACrF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,SAA+B;AAAA,IACnC,GAAG;AAAA,IACH,WAAW,OAAO,SAAS;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,wBAAwB,oBAAoB,QAAQ;AAAA,EACtD;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,qBAAqB,MAAM,CAAC;AAAA,EAC1C;AACA,SAAO;AACT;AAUO,SAAS,qBAAqB,QAAsC;AACzE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,wDAA+B;AAC1C,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,GAAG,sBAAsB,OAAO,sBAAsB,CAAC;AAElE,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM,KAAK,mLAA2D;AACtE,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,UAAU;AACnB,UAAM;AAAA,MACJ,kBAAQ,OAAO,MAAM;AAAA,IACvB;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,CAAC,OAAO,OAAO;AACjB,UAAM,KAAK,kBAAQ,OAAO,MAAM,uHAAuC;AACvE,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAGA,MAAI,OAAO,SAAS;AAClB,UAAM,KAAK,YAAO,OAAO,MAAM,yEAAuB;AAAA,EACxD,OAAO;AACL,UAAM,KAAK,KAAK,OAAO,MAAM,mHAA6C;AAAA,EAC5E;AACA,MAAI,OAAO,sBAAsB,QAAW;AAC1C,UAAM;AAAA,MACJ,+BAAqB,OAAO,iBAAiB,gBAAW,OAAO,UAAU,6BAAS,oBAAK;AAAA,IACzF;AAAA,EACF,OAAO;AACL,UAAM,KAAK,yHAAyC;AAAA,EACtD;AACA,MAAI,OAAO,cAAc;AACvB,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF,WAAW,OAAO,aAAa;AAC7B,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAGb,QAAM,IAAI,OAAO;AACjB,QAAM,QAAkB,CAAC;AACzB,MAAI,EAAE,SAAU,OAAM,KAAK,wDAA+B;AAC1D,MAAI,EAAE,iBAAiB,SAAS,EAAG,OAAM,KAAK,sBAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC,GAAG;AACrF,MAAI,EAAE,kBAAkB,SAAS;AAC/B,UAAM,KAAK,+DAAuB,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAAG;AACrE,MAAI,EAAE,UAAW,OAAM,KAAK,kCAA6BI,UAAS,OAAO,MAAM,CAAC,aAAa;AAE7F,MAAI,CAAC,EAAE,WAAW;AAChB,UAAM,KAAK,6IAAyC;AACpD,UAAM;AAAA,MACJ;AAAA,IACF;AACA,UAAM,KAAK,EAAE;AAAA,EACf,WAAW,MAAM,SAAS,GAAG;AAC3B,UAAM,KAAK,sLAAyD;AACpE,eAAW,KAAK,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AAC1C,UAAM,KAAK,EAAE;AAAA,EACf,OAAO;AACL,UAAM,KAAK,8HAAwD;AACnE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGA,eAAsB,iBACpB,SACA,SACA,SACA,MAA4B,CAAC,GACd;AACf,MAAI;AACF,UAAM,mBAAmB,SAAS,SAAS,SAAS,GAAG;AAAA,EACzD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAOA,SAAS,mBACP,gBACA,UACA,aACc;AAId,MAAI;AACJ,MAAI;AACF,iBAAa,aAAa,cAAc;AAAA,EAC1C,QAAQ;AACN,WAAO,EAAE,iBAAiB,OAAO,aAAa,MAAM;AAAA,EACtD;AACA,QAAM,kBAAkB,WAAWF,MAAK,YAAY,UAAU,WAAW,CAAC;AAE1E,MAAI,cAAc;AAClB,QAAM,WAAW,SAAS,UAAU;AACpC,MAAI,aAAa,QAAW;AAC1B,QAAI;AACF,gBAAUA,MAAK,eAAe,gBAAgB,QAAQ,GAAG,WAAW,CAAC;AACrE,oBAAc;AAAA,IAChB,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,EAAE,iBAAiB,YAAY;AACxC;AASA,SAAS,qBAAqB,UAAoB,MAAkB,WAA6B;AAC/F,QAAM,OAAiB;AAAA,IACrB,GAAG;AAAA,IACH,WAAW,EAAE,GAAG,SAAS,WAAW,YAAY,UAAU;AAAA,IAC1D,OAAO,KAAK;AAAA,EACd;AACA,MAAI,KAAK,oBAAoB,QAAW;AACtC,WAAO,EAAE,GAAG,MAAM,QAAQ,EAAE,GAAI,SAAS,UAAU,CAAC,GAAI,cAAc,KAAK,gBAAgB,EAAE;AAAA,EAC/F;AACA,SAAO;AACT;AAWA,eAAsB,mBACpB,SACA,SACA,SACA,KAC8B;AAC9B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,gBAAgB;AAC7E,QAAM,QAAQJ,aAAW,cAAc;AACvC,QAAM,WAAW,MAAMC,cAAa,KAAK;AACzC,QAAM,SAAS,SAAS,SAAS,CAAC;AAElC,MAAI,cAAc;AAClB,MAAI;AACF,kBAAc,aAAaE,SAAQ,gBAAgB,OAAO,CAAC,MAAM,aAAa,cAAc;AAAA,EAC9F,QAAQ;AACN,kBAAc;AAAA,EAChB;AAEA,QAAM,OAAO,WAAW;AAAA,IACtB,GAAI,SAAS,UAAU,SAAY,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAAA,IAChE,GAAI,SAAS,QAAQ,iBAAiB,SAClC,EAAE,aAAa,SAAS,OAAO,aAAa,IAC5C,CAAC;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,aAAa,KAAK,SAAS,CAAC,KAAK,YAAY,CAAC,KAAK,aAAa,CAAC,KAAK;AAC5E,QAAM,SACJ,cAAc,KAAK,kBACf,mBAAmB,gBAAgB,UAAU,aAAa,KAAK,SAAS,CAAC,IACzE,EAAE,iBAAiB,OAAO,aAAa,MAAM;AAEnD,QAAM,UAAU,QAAQ,UAAU,QAAQ;AAC1C,MAAI,SAAS;AACX,UAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,UAAMD,eAAc,OAAO,qBAAqB,UAAU,MAAM,IAAI,EAAE,YAAY,CAAC,GAAG;AAAA,MACpF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,SAA8B;AAAA,IAClC,GAAG;AAAA,IACH,WAAW,OAAO,SAAS;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,wBAAwB,oBAAoB,QAAQ;AAAA,EACtD;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,YAAQ,IAAI,oBAAoB,MAAM,CAAC;AAAA,EACzC;AACA,SAAO;AACT;AAQO,SAAS,oBAAoB,QAAqC;AACvE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,6DAA+B;AAC1C,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,GAAG,sBAAsB,OAAO,sBAAsB,CAAC;AAElE,MAAI,CAAC,OAAO,WAAW;AACrB,UAAM,KAAK,kLAA0D;AACrE,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACA,MAAI,OAAO,MAAM;AACf,UAAM,KAAK,kBAAQ,OAAO,SAAS,eAAU,OAAO,SAAS,mEAAiB;AAC9E,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACA,MAAI,OAAO,UAAU;AACnB,UAAM;AAAA,MACJ,kBAAQ,OAAO,SAAS;AAAA,IAC1B;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACA,MAAI,CAAC,OAAO,OAAO;AACjB,UAAM,KAAK,kBAAQ,OAAO,SAAS,sHAAsC;AACzE,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACA,MAAI,OAAO,WAAW;AACpB,UAAM;AAAA,MACJ,kBAAQ,OAAO,SAAS;AAAA,IAC1B;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM,KAAK,YAAO,OAAO,SAAS,eAAU,OAAO,SAAS,iDAAmB;AAAA,EACjF,OAAO;AACL,UAAM;AAAA,MACJ,KAAK,OAAO,SAAS,eAAU,OAAO,SAAS;AAAA,IACjD;AAAA,EACF;AACA,MAAI,OAAO,sBAAsB,QAAW;AAC1C,UAAM;AAAA,MACJ,yBAAoB,OAAO,iBAAiB,WAAM,OAAO,SAAS,sBAAO,OAAO,UAAU,6BAAS,oBAAK;AAAA,IAC1G;AAAA,EACF,OAAO;AACL,UAAM,KAAK,+HAAqC;AAAA,EAClD;AACA,QAAM,KAAK,EAAE;AAGb,MAAI,OAAO,iBAAiB;AAC1B,UAAM,UAAU,aAAa,OAAO,SAAS;AAC7C,UAAM,UAAU,aAAa,OAAO,SAAS;AAC7C,UAAM,QAAkB,CAAC;AACzB,QAAI,OAAO,OAAO;AAChB,YAAM,KAAK,4BAA4B,OAAO,mBAAc,OAAO,GAAG;AACxE,QAAI,OAAO,OAAO,YAAa,OAAM,KAAK,kCAA6B,OAAO,WAAM,OAAO,EAAE;AAC7F,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM;AAAA,QACJ;AAAA,MACF;AACA,iBAAW,KAAK,MAAO,OAAM,KAAK,KAAK,CAAC,EAAE;AAAA,IAC5C,OAAO;AACL,YAAM;AAAA,QACJ,mBAAc,OAAO,WAAM,OAAO;AAAA,MACpC;AAAA,IACF;AACA,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAEb,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACttFA,SAAS,YAAAW,iBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,OACK;;;ACPP,SAAS,kBAAkB;AAC3B,SAAS,OAAO,MAAM,QAAQ,QAAAC,OAAM,UAAAC,eAAc;AAClD,SAAS,YAAAC,WAAU,WAAAC,UAAS,QAAAC,aAAY;AAYxC,eAAsB,iBAAiB,YAAmC;AACxE,MAAI;AACF,UAAM,KAAK,MAAM,MAAM,UAAU;AACjC,QAAI,GAAG,eAAe,GAAG;AACvB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAU,MAA4B,SAAS,SAAU;AAC9E,UAAM;AAAA,EACR;AACF;AAuBA,eAAsB,iBAAiB,YAAoB,SAAgC;AACzF,QAAM,MAAMD,SAAQ,UAAU;AAC9B,QAAM,UAAUC,MAAK,KAAK,IAAIF,UAAS,UAAU,CAAC,QAAQ,WAAW,CAAC,EAAE;AAExE,MAAI,OAAO;AACX,MAAI;AACF,YAAQ,MAAMF,MAAK,UAAU,GAAG,OAAO;AAAA,EACzC,SAAS,OAAgB;AACvB,QAAI,EAAE,iBAAiB,SAAU,MAA4B,SAAS,WAAW;AAC/E,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,KAAK,SAAS,MAAM,IAAI;AACvC,UAAM,OAAO,UAAU,SAAS,MAAM;AACtC,UAAM,OAAO,MAAM,IAAI;AACvB,UAAM,OAAO,KAAK;AAClB,UAAM,OAAO,MAAM;AACnB,aAAS;AACT,UAAM,OAAO,SAAS,UAAU;AAAA,EAClC,SAAS,OAAgB;AACvB,QAAI,OAAQ,OAAM,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AACtD,UAAMC,QAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3C,UAAM;AAAA,EACR;AAGA,MAAI;AACF,UAAM,YAAY,MAAM,KAAK,KAAK,GAAG;AACrC,QAAI;AACF,YAAM,UAAU,KAAK;AAAA,IACvB,UAAE;AACA,YAAM,UAAU,MAAM;AAAA,IACxB;AAAA,EACF,QAAQ;AAAA,EAGR;AACF;;;ACzFA,SAAS,WAAAI,gBAAe;AACxB,SAAS,cAAAC,aAAY,QAAAC,OAAM,WAAAC,gBAAe;AAC1C,SAAS,gBAAAC,qBAAoB;AAUtB,IAAM,gCAAgCF,MAAKF,SAAQ,GAAG,UAAU,gBAAgB;AAShF,IAAM,sBAAsBE,MAAKF,SAAQ,GAAG,WAAW,WAAW;AAEzE,IAAM,mBAAmB,oBAAI,IAAI,CAAC,WAAW,WAAW,CAAC;AACzD,IAAM,qBAAqB,oBAAI,IAAI,CAAC,UAAU,OAAO,CAAC;AAGtD,SAASK,aAAY,GAAmB;AACtC,MAAI,MAAM,IAAK,QAAOL,SAAQ;AAC9B,MAAI,EAAE,WAAW,IAAI,EAAG,QAAOE,MAAKF,SAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,SAAO;AACT;AAEA,SAASM,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAeA,eAAsB,oBACpB,aAAqB,+BACK;AAC1B,MAAI;AACJ,MAAI;AACF,UAAM,MAAMF,cAAa,UAAU;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,iBAAiB,SAAS,MAAM,YAAY,gCAAgC;AAC9E,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,UAAM;AAAA,EACR;AAEA,MAAI,CAACE,UAAS,GAAG,KAAK,CAAC,MAAM,QAAQ,IAAI,SAAS,GAAG;AACnD,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AACA,aAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,QAAI,CAAC,iBAAiB,IAAI,GAAG,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,+CAA+C,GAAG;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAA0B,CAAC;AACjC,aAAW,SAAS,IAAI,WAAW;AACjC,QAAI,CAACA,UAAS,KAAK,GAAG;AACpB,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,eAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,UAAI,CAAC,mBAAmB,IAAI,GAAG,GAAG;AAChC,cAAM,IAAI,MAAM,wCAAwC,GAAG,6BAA6B;AAAA,MAC1F;AAAA,IACF;AACA,QAAI,OAAO,MAAM,WAAW,YAAY,MAAM,OAAO,KAAK,EAAE,WAAW,GAAG;AACxE,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AACA,QACE,MAAM,UAAU,WACf,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,EAAE,WAAW,IAClE;AACA,YAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AACA,UAAM,WAAWD,aAAY,MAAM,OAAO,KAAK,CAAC;AAChD,QAAI,CAACJ,YAAW,QAAQ,GAAG;AACzB,YAAM,IAAI,MAAM,+DAA+D;AAAA,IACjF;AACA,UAAM,MAAME,SAAQ,QAAQ;AAC5B,QAAI,KAAK,IAAI,GAAG,GAAG;AACjB,YAAM,IAAI,MAAM,oEAAoE;AAAA,IACtF;AACA,SAAK,IAAI,GAAG;AACZ,WAAO;AAAA,MACL,MAAM,UAAU,SAAY,EAAE,QAAQ,KAAK,OAAO,MAAM,MAAM,KAAK,EAAE,IAAI,EAAE,QAAQ,IAAI;AAAA,IACzF;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,SAAO;AACT;;;AFlGA,IAAM,mBAAmB,EAAE,OAAO,gBAAgB,KAAK,aAAa;AAGpE,IAAM,eACJ;AAiBK,SAAS,wBAAwBI,UAAwB;AAC9D,QAAM,WAAWA,SACd,QAAQ,UAAU,EAClB,YAAY,0EAA0E;AAEzF,WACG,QAAQ,MAAM,EACd,YAAY,iFAAiF,EAC7F,OAAO,mBAAmB,0DAA0D,EACpF,OAAO,mBAAmB,+CAA+C,EACzE,OAAO,aAAa,yCAAyC,EAC7D,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA8B;AAC3C,UAAM,gBAAgB,IAAI;AAAA,EAC5B,CAAC;AAEH,WACG,QAAQ,MAAM,EACd,YAAY,4DAA4D,EACxE,OAAO,mBAAmB,0DAA0D,EACpF,OAAO,mBAAmB,+CAA+C,EACzE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAgC;AAC7C,UAAM,gBAAgB,IAAI;AAAA,EAC5B,CAAC;AAEH,WACG,QAAQ,QAAQ,EAChB,YAAY,mEAAmE,EAC/E,OAAO,mBAAmB,+CAA+C,EACzE,OAAO,aAAa,yCAAyC,EAC7D,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA8B;AAC3C,UAAM,kBAAkB,IAAI;AAAA,EAC9B,CAAC;AACL;AAEA,eAAsB,gBAAgB,SAA6C;AACjF,MAAI;AACF,UAAM,kBAAkB,OAAO;AAAA,EACjC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,gBAAgB,SAA+C;AACnF,MAAI;AACF,UAAM,kBAAkB,OAAO;AAAA,EACjC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,kBAAkB,SAA6C;AACnF,MAAI;AACF,UAAM,oBAAoB,OAAO;AAAA,EACnC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAOA,eAAe,oBACb,SACsD;AACtD,QAAM,MAAmD,CAAC;AAC1D,aAAW,SAAS,SAAS;AAC3B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMC,UAAS,MAAM,QAAQ,MAAM;AAAA,IAC/C,SAAS,OAAgB;AACvB,UAAI,iBAAiB,SAAU,MAA4B,SAAS,UAAU;AAC5E,cAAM,IAAI;AAAA,UACR;AAAA,UACA,EAAE,OAAO,MAAM;AAAA,QACjB;AAAA,MACF;AACA,YAAM,IAAI,MAAM,0CAA0C,EAAE,OAAO,MAAM,CAAC;AAAA,IAC5E;AACA,eAAW,QAAQ,QAAQ,MAAM,OAAO,GAAG;AACzC,UAAI,SAAS,kBAAkB,SAAS,cAAc;AACpD,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,EAAE,OAAO,QAAQ,CAAC;AAAA,EAC7B;AACA,SAAO;AACT;AAGA,SAAS,WAAW,SAA8D;AAChF,QAAM,WAAW,QAAQ,IAAI,CAAC,EAAE,OAAO,QAAQ,MAAM;AACnD,UAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AACvC,WAAO,MAAM,UAAU,SAAY,MAAM,MAAM,KAAK;AAAA;AAAA,EAAO,IAAI,KAAK;AAAA,EACtE,CAAC;AACD,SAAO,GAAG,YAAY;AAAA;AAAA,EAAO,SAAS,KAAK,MAAM,CAAC;AAAA;AACpD;AAYA,SAAS,gBAAgB,UAAyB,OAAuB;AACvE,QAAM,UAAU,GAAG,cAAc;AAAA,EAAK,KAAK,GAAG,YAAY;AAAA;AAG1D,MAAI,aAAa,QAAQ,aAAa,GAAI,QAAO;AACjD,QAAM,UAAUC,cAAa,UAAU,gBAAgB;AACvD,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO,GAAG,QAAQ,MAAM,GAAG,cAAc;AAAA,EAAK,KAAK,GAAG,YAAY,GAAG,QAAQ,KAAK;AAAA,IACpF,KAAK,cAAc;AACjB,YAAM,MAAM,SAAS,SAAS,MAAM,IAAI,KAAK,SAAS,SAAS,IAAI,IAAI,OAAO;AAC9E,aAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,OAAO;AAAA,IACpC;AAAA,IACA;AACE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,EACJ;AACF;AAQA,eAAe,WAAW,QAAgB,UAAwC;AAChF,MAAI,aAAa,KAAM;AACvB,QAAM,MAAM,GAAG,MAAM;AACrB,QAAM,UAAU,MAAMC,kBAAiB,GAAG;AAC1C,MAAI,YAAY,KAAM;AACtB,QAAM,iBAAiB,KAAK,QAAQ;AACtC;AAEA,eAAsB,kBAAkB,SAA6C;AACnF,QAAM,aAAa,QAAQ,UAAU;AACrC,QAAM,SAAS,QAAQ,UAAU;AAEjC,QAAM,UAAU,MAAM,oBAAoB,UAAU;AACpD,QAAM,UAAU,MAAM,oBAAoB,OAAO;AACjD,QAAM,QAAQ,WAAW,OAAO;AAEhC,QAAM,iBAAiB,MAAM;AAC7B,QAAM,WAAW,MAAMA,kBAAiB,MAAM;AAC9C,QAAM,UAAU,gBAAgB,UAAU,KAAK;AAE/C,MAAI,YAAY,UAAU;AACxB,YAAQ,IAAI,oDAAoD,QAAQ,MAAM,gBAAgB;AAC9F;AAAA,EACF;AAKA,QAAM,WAAW,aAAa,QAAQD,cAAa,UAAU,gBAAgB,EAAE,SAAS;AAExF,MAAI,QAAQ,WAAW,MAAM;AAC3B,YAAQ;AAAA,MACN,mBAAmB,WAAW,WAAW,SAAS,+BAA+B,QAAQ,MAAM;AAAA,IACjG;AACA,eAAW,EAAE,MAAM,KAAK,SAAS;AAC/B,cAAQ,IAAI,OAAO,MAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAClD;AACA;AAAA,EACF;AAOA,QAAM,UAAU,MAAMC,kBAAiB,MAAM;AAC7C,MAAI,YAAY,UAAU;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAIA,QAAM,WAAW,QAAQ,QAAQ;AACjC,QAAM,iBAAiB,QAAQ,OAAO;AACtC,UAAQ;AAAA,IACN,GAAG,WAAW,YAAY,WAAW,uDAAuD,QAAQ,MAAM;AAAA,EAC5G;AACF;AAEA,eAAsB,kBAAkB,SAA+C;AACrF,QAAM,aAAa,QAAQ,UAAU;AACrC,QAAM,SAAS,QAAQ,UAAU;AAEjC,QAAM,UAAU,MAAM,oBAAoB,UAAU;AACpD,QAAM,WAAW,MAAMA,kBAAiB,MAAM;AAC9C,QAAM,YAAY,aAAa,QAAQD,cAAa,UAAU,gBAAgB,EAAE,SAAS;AAEzF,UAAQ,IAAI,uBAAuB,QAAQ,MAAM,IAAI;AACrD,aAAW,SAAS,SAAS;AAC3B,YAAQ,IAAI,OAAO,MAAM,SAAS,MAAM,MAAM,EAAE;AAAA,EAClD;AACA,UAAQ,IAAI,YAAY,8CAA8C,uBAAuB;AAC/F;AAEA,eAAsB,oBAAoB,SAA6C;AACrF,QAAM,SAAS,QAAQ,UAAU;AAEjC,QAAM,iBAAiB,MAAM;AAC7B,QAAM,WAAW,MAAMC,kBAAiB,MAAM;AAC9C,MAAI,aAAa,MAAM;AACrB,YAAQ,IAAI,oCAAoC;AAChD;AAAA,EACF;AAEA,QAAM,UAAU,oBAAoB,UAAU,aAAa,gBAAgB;AAC3E,MAAI,YAAY,UAAU;AACxB,YAAQ,IAAI,kDAAkD;AAC9D;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,MAAM;AAC3B,YAAQ,IAAI,6EAA6E;AACzF;AAAA,EACF;AAIA,QAAM,UAAU,MAAMA,kBAAiB,MAAM;AAC7C,MAAI,YAAY,UAAU;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ,QAAQ;AACjC,QAAM,iBAAiB,QAAQ,OAAO;AACtC,UAAQ,IAAI,8DAA8D;AAC5E;;;AGpSA,SAAS,uBAAAC,sBAAqB,cAAAC,cAAY,iBAAAC,sBAAqB;AAC/D,SAAuB,wBAAAC,6BAA4B;;;ACAnD,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAC9B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AACrB,SAA0B,iBAAAC,sBAAqB;AAYxC,IAAM,6BAA6B;AAEnC,IAAM,yBAAyB;AAE/B,IAAM,yBAAyB;AAY/B,SAAS,aAAa,KAA8B;AACzD,SAAO;AAAA,IACL,IAAI,oBAAoBC,MAAKC,SAAQ,GAAG,UAAU,UAAU;AAAA,IAC5D,IAAI,qBAAqBD,MAAKC,SAAQ,GAAG,WAAW,UAAU;AAAA,EAChE;AACF;AAQA,eAAsB,eAAe,OAAyC;AAC5E,QAAM,MAAqB,oBAAI,IAAI;AACnC,QAAM,OAAO,OAAO,QAA+B;AACjD,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMC,SAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IACtD,SAAS,OAAgB;AAEvB,UAAIC,eAAc,OAAO,QAAQ,KAAKA,eAAc,OAAO,SAAS,EAAG;AAEvE,YAAM,IAAI,MAAM,yCAAyC,EAAE,OAAO,MAAM,CAAC;AAAA,IAC3E;AACA,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAOH,MAAK,KAAK,MAAM,IAAI;AACjC,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,KAAK,IAAI;AAAA,MACjB,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,QAAQ,GAAG;AAC1D,YAAI;AACF,gBAAM,OAAO,MAAMI,MAAK,IAAI;AAC5B,cAAI,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,QAC1D,SAAS,OAAgB;AACvB,cAAID,eAAc,OAAO,QAAQ,EAAG;AACpC,gBAAM,IAAI,MAAM,oCAAoC,EAAE,OAAO,MAAM,CAAC;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,aAAW,QAAQ,MAAO,OAAM,KAAK,IAAI;AACzC,SAAO;AACT;AAGO,SAAS,WAAW,GAAkB,GAA2B;AACtE,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,aAAW,CAAC,MAAM,GAAG,KAAK,GAAG;AAC3B,UAAM,QAAQ,EAAE,IAAI,IAAI;AACxB,QAAI,UAAU,UAAa,MAAM,YAAY,IAAI,WAAW,MAAM,SAAS,IAAI,MAAM;AACnF,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AASA,SAAS,aAAa,SAAgC;AACpD,SAAO,QAAQ,WAAW,QACtB,QAAQ,gBAAgB,QAAQ,kBAAkB,QAAQ,gBAC1D;AACN;AAEA,SAAS,gBAAgB,SAAgC;AACvD,MAAI,QAAQ,WAAW,MAAO,QAAO,GAAG,QAAQ,OAAO;AACvD,QAAM,aAAa,QAAQ,kBAAkB,IAAI,KAAK,QAAQ,eAAe,KAAK;AAClF,SAAO,GAAG,QAAQ,OAAO,KAAK,QAAQ,aAAa,GAAG,UAAU;AAClE;AAEA,SAAS,IAAI,MAAoB;AAC/B,SAAO,KAAK,YAAY,EAAE,MAAM,IAAI,EAAE;AACxC;AAiBA,eAAe,WACb,MAC2E;AAC3E,QAAM,SAAS,MAAM,iBAAiB,KAAK,eAAe,KAAK,GAAG;AAClE,QAAM,QAAQ,MAAM,YAAY,KAAK,eAAe,KAAK,GAAG;AAC5D,SAAO,EAAE,QAAQ,OAAO,SAAS,aAAa,MAAM,IAAI,aAAa,KAAK,EAAE;AAC9E;AAGA,eAAe,WAAW,MAAkC;AAC1D,QAAM,SAAS,KAAK,IAAI,EAAE,YAAY;AACtC,QAAM,UAAU,MAAM,kBAAkB,KAAK,OAAO,MAAM;AAC1D,QAAM,oBAAoB,KAAK,OAAO,MAAM;AAC5C,SAAO,QAAQ;AACjB;AAYA,eAAsB,gBAAgB,MAAgC;AACpE,QAAM,EAAE,YAAY,KAAK,QAAQ,OAAO,IAAI,IAAI;AAChD,QAAM,QAAQ,aAAa,GAAG;AAC9B;AAAA,IACE,YAAY,MAAM,KAAK,IAAI,CAAC,UAAU,KAAK,MAAM,aAAa,GAAI,CAAC;AAAA,EAErE;AAIA,MAAI,WAAW,MAAM,eAAe,KAAK;AACzC,MAAI,eAAe;AAGnB,QAAM,UAAU,MAAM,WAAW,IAAI;AACrC,QAAM,kBAAkB,MAAM,WAAW,IAAI;AAC7C;AAAA,IACE,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,gBAAgB,gBAAgB,QAAQ,KAAK,CAAC,KAC5D,gBAAgB,QAAQ,MAAM,CAAC,eAAe,eAAe;AAAA,EACpE;AACA,MAAI,OAAO,SAAS;AAClB,QAAI,eAAe;AACnB;AAAA,EACF;AAIA,MAAI,eAAe;AACnB,SAAO,CAAC,OAAO,SAAS;AACtB,UAAM,MAAM,YAAY,MAAM;AAC9B,QAAI,OAAO,QAAS;AACpB,QAAI;AACF,YAAM,UAAU,MAAM,eAAe,KAAK;AAE1C,UAAI,WAAW,SAAS,QAAQ,KAAK,CAAC,WAAW,SAAS,YAAY,GAAG;AACvE,cAAM,EAAE,QAAQ,OAAO,QAAQ,IAAI,MAAM,WAAW,IAAI;AACxD,YAAI,UAAU,EAAG,gBAAe;AAChC,YAAI,cAAc;AAChB,gBAAM,WAAW,MAAM,WAAW,IAAI;AACtC,yBAAe;AACf;AAAA,YACE,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,gBAAgB,gBAAgB,KAAK,CAAC,KACpD,gBAAgB,MAAM,CAAC,eAAe,QAAQ;AAAA,UACrD;AAAA,QACF;AACA,uBAAe;AAAA,MACjB;AACA,iBAAW;AAAA,IACb,SAAS,OAAgB;AAGvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,4BAA4B,OAAO,EAAE;AAAA,IAC9D;AAAA,EACF;AACA,MAAI,eAAe;AACrB;;;ADnLA,SAASE,aAAY,OAAe,UAA8B;AAChE,SAAO,CAAC,GAAG,UAAU,KAAK;AAC5B;AAGO,SAAS,cAAc,OAAuB;AACnD,QAAM,UAAU,OAAO,KAAK;AAC5B,MACE,CAAC,OAAO,UAAU,OAAO,KACzB,UAAU,0BACV,UAAU,wBACV;AACA,UAAM,IAAIC;AAAA,MACR,yCAAyC,sBAAsB,QAAQ,sBAAsB;AAAA,IAC/F;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,eAAe,IAAY,QAAoC;AACtE,SAAO,IAAI,QAAc,CAACC,cAAY;AACpC,QAAI,OAAO,SAAS;AAClB,MAAAA,UAAQ;AACR;AAAA,IACF;AACA,QAAI;AACJ,UAAM,UAAU,MAAY;AAC1B,mBAAa,KAAK;AAClB,MAAAA,UAAQ;AAAA,IACV;AACA,YAAQ,WAAW,MAAM;AACvB,aAAO,oBAAoB,SAAS,OAAO;AAC3C,MAAAA,UAAQ;AAAA,IACV,GAAG,EAAE;AACL,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC1D,CAAC;AACH;AAcO,SAAS,uBAAuBC,UAAwB;AAC7D,EAAAA,SACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACAH;AAAA,IACA,CAAC;AAAA,EACH,EACC,OAAO,WAAW,yDAAyD,EAC3E,OAAO,aAAa,sDAAsD,EAC1E,OAAO,UAAU,2BAA2B,EAC5C;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA,kDAAkD,0BAA0B,SAAS,sBAAsB;AAAA,IAC3G;AAAA,EACF,EACC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAA4B;AACzC,UAAM,WAAW,OAAO;AAAA,EAC1B,CAAC;AACL;AAMA,eAAsB,WAAW,SAAyB,MAAsB,CAAC,GAAkB;AACjG,MAAI;AACF,QAAI,QAAQ,cAAc,MAAM;AAC9B,YAAM,sBAAsB,SAAS,GAAG;AAAA,IAC1C,WAAW,QAAQ,UAAU,MAAM;AACjC,YAAM,kBAAkB,SAAS,GAAG;AAAA,IACtC,OAAO;AACL,YAAM,aAAa,SAAS,GAAG;AAAA,IACjC;AAAA,EACF,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,eAAsB,sBACpB,SACA,KACe;AACf,MAAI,QAAQ,UAAU,KAAM,OAAM,IAAI,MAAM,8CAA8C;AAC1F,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,SAAS,GAAG;AAC/D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,oBAAoB,IAAI,mBAAmB;AACpE,QAAM,SAGF,CAAC;AAEL,aAAW,MAAM,YAAY;AAC3B,UAAM,QAAQ,GAAG,SAAS,GAAG;AAC7B,QAAI;AACF,YAAM,SAAS,MAAM;AAAA,QACnB,EAAE,GAAG,SAAS,WAAW,MAAM;AAAA,QAC/B,EAAE,GAAG,KAAK,KAAK,GAAG,KAAK;AAAA,MACzB;AACA,aAAO,KAAK,EAAE,OAAO,MAAM,GAAG,MAAM,QAAQ,MAAM,OAAO,CAAC;AAC1D,UAAI,QAAQ,SAAS,MAAM;AACzB,gBAAQ,IAAI;AAAA,KAAQ,KAAK,KAAK,GAAG,IAAI,GAAG;AACxC,4BAAoB,MAAM;AAAA,MAC5B;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,KAAK,EAAE,OAAO,MAAM,GAAG,MAAM,QAAQ,UAAU,OAAO,QAAQ,CAAC;AACtE,UAAI,QAAQ,SAAS,MAAM;AACzB,gBAAQ,IAAI;AAAA,KAAQ,KAAK,KAAK,GAAG,IAAI,GAAG;AACxC,gBAAQ,IAAI,aAAa,OAAO,EAAE;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,EAAE,WAAW,MAAM,YAAY,OAAO,CAAC,CAAC;AAAA,EACrE,OAAO;AACL,UAAM,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE;AAC3D,UAAM,KAAK,OAAO,SAAS;AAC3B,YAAQ;AAAA,MACN;AAAA,aAAgB,EAAE,IAAI,OAAO,MAAM,aAAa,SAAS,IAAI,KAAK,MAAM,YAAY,EAAE;AAAA,IACxF;AAAA,EACF;AACA,MAAI,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAG,SAAQ,WAAW;AACpE;AAQA,eAAsB,kBACpB,SACA,KACe;AACf,MAAI,QAAQ,WAAW,KAAM,OAAM,IAAI,MAAM,4CAA4C;AACzF,MAAI,QAAQ,SAAS,KAAM,OAAM,IAAI,MAAM,yCAAyC;AACpF,MAAI,QAAQ,UAAU,KAAM,OAAM,IAAI,MAAM,0CAA0C;AAEtF,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,SAAS;AACtE,QAAM,QAAQI,aAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,cAAc,QAAQ,YAAY,8BAA8B;AACtE,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,WAAW,MAAY,WAAW,MAAM;AAC9C,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAC9B,MAAI;AACF,UAAM,gBAAgB;AAAA;AAAA;AAAA,MAGpB,KAAK,EAAE,GAAG,KAAK,KAAK,eAAe;AAAA,MACnC;AAAA,MACA;AAAA,MACA,eACE,QAAQ,YAAY,UAAa,QAAQ,QAAQ,SAAS,IACtD,EAAE,SAAS,QAAQ,QAAQ,IAC3B,CAAC;AAAA,MACP,KAAK,MAAM,IAAI,cAAc,KAAK,oBAAI,KAAK;AAAA,MAC3C,QAAQ,WAAW;AAAA,MACnB,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,QAAQ,IAAI,IAAI;AAAA,IACjC,CAAC;AAAA,EACH,UAAE;AACA,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,QAAQ;AAAA,EACjC;AACF;AAOA,eAAe,eACb,SACA,KACwB;AACxB,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,SAAS;AACtE,QAAM,QAAQD,aAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAC/D,SAAO,WAAW;AAAA,IAChB,SAAS;AAAA,MACP,GAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,SAAS,IAC1D,EAAE,SAAS,QAAQ,QAAQ,IAC3B,CAAC;AAAA,MACL,GAAI,QAAQ,UAAU,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAAA,MAChD,GAAI,QAAQ,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,IACpD;AAAA;AAAA;AAAA,IAGA,KAAK,EAAE,GAAG,KAAK,KAAK,eAAe;AAAA,IACnC;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAOA,eAAsB,aACpB,SACA,KACwB;AACxB,QAAM,SAAS,MAAM,eAAe,SAAS,GAAG;AAChD,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,OAAO;AACL,wBAAoB,MAAM;AAAA,EAC5B;AACA,SAAO;AACT;AAEA,SAAS,eAAe,SAAgC;AACtD,MAAI,QAAQ,WAAW,WAAW;AAChC,WAAO,GAAG,QAAQ,OAAO,cAAc,QAAQ,MAAM;AAAA,EACvD;AACA,QAAM,OAAO,QAAQ,SAAS,iBAAiB;AAC/C,QAAM,QAAQ,CAAC,GAAG,QAAQ,aAAa,eAAe,GAAG,QAAQ,UAAU,SAAS;AACpF,MAAI,QAAQ,kBAAkB,EAAG,OAAM,KAAK,GAAG,QAAQ,eAAe,cAAc;AACpF,MAAI,QAAQ,gBAAgB,EAAG,OAAM,KAAK,GAAG,QAAQ,aAAa,WAAW;AAC7E,MAAI,QAAQ,yBAAyB;AACnC,UAAM,KAAK,GAAG,QAAQ,sBAAsB,mBAAmB;AACjE,MAAI,QAAQ,yBAAyB,EAAG,OAAM,KAAK,GAAG,QAAQ,sBAAsB,SAAS;AAC7F,SAAO,GAAG,QAAQ,OAAO,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC;AACxD;AAEO,SAAS,oBAAoB,QAA6B;AAC/D,UAAQ,IAAI,eAAe,OAAO,UAAU,CAAC;AAC7C,UAAQ,IAAI,eAAe,OAAO,KAAK,CAAC;AACxC,MAAI,OAAO,QAAQ,WAAW,aAAa;AACzC,YAAQ;AAAA,MACN,mCAAmC,OAAO,QAAQ,YAAY,gBAAgB,OAAO,QAAQ,aAAa;AAAA,IAC5G;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,qBAAqB,OAAO,QAAQ,MAAM,GAAG;AAAA,EAC3D;AACA,MAAI,OAAO,UAAU,WAAW,aAAa;AAC3C,QAAI,OAAO,UAAU,kBAAkB,GAAG;AAUxC,YAAM,cAAc,OAAO,QAAQ,WAAW,eAAe,OAAO,QAAQ,eAAe;AAC3F,cAAQ;AAAA,QACN,cACI,0GACA;AAAA,MACN;AAAA,IACF,OAAO;AACL,cAAQ,IAAI,2BAA2B,OAAO,UAAU,aAAa,GAAG;AAAA,IAC1E;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,uBAAuB,OAAO,UAAU,MAAM,GAAG;AAAA,EAC/D;AACA,MAAI,OAAO,YAAY,WAAW,aAAa;AAC7C,YAAQ;AAAA,MACN,wCAAwC,OAAO,YAAY,iBAAiB,wBAAwB,OAAO,YAAY,qBAAqB,cAAc,OAAO,YAAY,YAAY;AAAA,IAC3L;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,yBAAyB,OAAO,YAAY,MAAM,GAAG;AAAA,EACnE;AACF;AAEA,eAAeA,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMC,qBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,eAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;AE/VA,SAAS,cAAAC,aAAY,WAAAC,gBAAe;AACpC;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EACA,qBAAAC;AAAA,OACK;AA6BA,SAAS,sBAAsBC,UAAwB;AAC5D,QAAM,SAASA,SACZ,QAAQ,QAAQ,EAChB;AAAA,IACC;AAAA,EACF;AAEF,SACG,QAAQ,UAAU,EAClB,YAAY,yDAAyD,EACrE,OAAO,gBAAgB,uDAAuD,EAC9E,OAAO,UAAU,mDAAmD,EACpE,OAAO,kBAAkB,yCAAyC,EAClE,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAgC;AAC7C,UAAM,kBAAkB,IAAI;AAAA,EAC9B,CAAC;AACL;AAQA,eAAsB,kBACpB,SACA,MAAqB,CAAC,GACP;AACf,MAAI;AACF,UAAM,oBAAoB,SAAS,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAYA,eAAsB,oBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,+BAA+B,GAAG;AAC/D,QAAM,QAAQC,aAAW,cAAc;AACvC,QAAMC,4BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAC/D,QAAM,SAAS,MAAM,aAAa;AAAA,IAChC;AAAA,IACA;AAAA,IACA,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,IAC5D,YAAY,CAAC,QAAQ,WAAW,cAAc,QAAQ,MAAM;AAAA,EAC9D,CAAC;AAED,MAAI,QAAQ,QAAQ,QAAW;AAC7B,UAAM,UAAUC,YAAW,QAAQ,GAAG,IAAI,QAAQ,MAAMC,SAAQ,KAAK,QAAQ,GAAG;AAChF,UAAMC,mBAAkB,SAAS,OAAO,IAAI;AAC5C,UAAM,EAAE,UAAU,WAAW,MAAM,IAAI,OAAO;AAE9C,YAAQ;AAAA,MACN,mBAAmB,QAAQ,GAAG,eAAe,SAAS,KAAK,gBAAgB,UAAU,KAAK,YAAY,MAAM,KAAK;AAAA,IACnH;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,EAClD,WAAW,QAAQ,QAAQ,QAAW;AACpC,YAAQ,IAAI,OAAO,IAAI;AAAA,EACzB;AACF;AAEA,eAAe,+BAA+B,KAA8B;AAC1E,MAAI;AACF,WAAO,MAAMC,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,QACA,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeJ,4BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMK,sBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;AC/IA;AAAA,EACE,cAAAC;AAAA,EACA;AAAA,OAGK;AAEP,SAAS,wBAAAC,6BAA4B;AAuBrC,SAAS,YAAY,OAAe,UAA8B;AAChE,SAAO,CAAC,GAAG,UAAU,KAAK;AAC5B;AAGO,SAAS,YAAY,OAAuB;AACjD,QAAM,QAAQ,OAAO,KAAK;AAC1B,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,SAAS,GAAG;AAC1C,UAAM,IAAIC,sBAAqB,8CAA8C;AAAA,EAC/E;AACA,SAAO;AACT;AAUO,SAAS,0BAA0BC,UAAwB;AAChE,EAAAA,SACG,QAAQ,aAAa,EACrB;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,CAAC;AAAA,EACH,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EACC,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAA4B;AACzC,UAAM,cAAc,IAAI;AAAA,EAC1B,CAAC;AACL;AAGA,eAAsB,cACpB,SACA,MAAyB,CAAC,GACX;AACf,MAAI;AACF,UAAM,gBAAgB,SAAS,GAAG;AAAA,EACpC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAGA,eAAsB,gBACpB,SACA,KAC4B;AAC5B,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,2BAA2B,KAAK,aAAa;AAC1E,QAAM,QAAQC,aAAW,cAAc;AAEvC,QAAM,UAAU,IAAI,cAAc,KAAK,oBAAI,KAAK,GAAG,YAAY;AAC/D,QAAM,UAAU,MAAM,eAAe;AAAA,IACnC;AAAA,IACA;AAAA,IACA,GAAI,QAAQ,SAAS,UAAa,QAAQ,KAAK,SAAS,IAAI,EAAE,OAAO,QAAQ,KAAK,IAAI,CAAC;AAAA,IACvF,GAAI,QAAQ,WAAW,SAAY,EAAE,aAAa,QAAQ,OAAO,IAAI,CAAC;AAAA,IACtE,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,EAC9D,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,EACrC,OAAO;AACL,YAAQ,IAAI,iBAAiB,OAAO,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,OAAO,KAAoB,KAAmB;AACrD,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,KAAK,IAAI,QAAQ,IAAI,KAAK,MAAM,GAAG;AACzC,MAAI,CAAC,OAAO,SAAS,EAAE,KAAK,KAAK,EAAG,QAAO;AAC3C,QAAM,OAAO,KAAK,MAAM,KAAK,KAAU;AACvC,MAAI,QAAQ,EAAG,QAAO,GAAG,IAAI;AAC7B,QAAM,QAAQ,KAAK,MAAM,KAAK,IAAS;AACvC,MAAI,SAAS,EAAG,QAAO,GAAG,KAAK;AAC/B,SAAO,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,GAAM,CAAC,CAAC;AAChD;AAEA,SAAS,SAAS,GAAkB,KAAmB;AACrD,QAAM,OAAO,OAAO,EAAE,cAAc,GAAG;AACvC,QAAM,OAAO,KAAK,EAAE,IAAI,IAAI,IAAI,KAAK,EAAE,WAAW,UAAU,EAAE,gBAAgB,IAAI,KAAK,GAAG;AAC1F,MAAI,EAAE,YAAY,gBAAgB;AAChC,UAAM,MAAM,EAAE,QAAQ,IAAI,CAAC,MAAM,EAAE,UAAU,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,IAAI;AACpE,WAAO,GAAG,IAAI,mKAAsC,GAAG;AAAA,EACzD;AACA,SAAO,GAAG,IAAI;AAChB;AAEA,SAAS,cAAc,GAAkB,KAAmB;AAC1D,QAAM,OAAO,OAAO,EAAE,cAAc,GAAG;AACvC,QAAM,OAAO,EAAE,QACZ,IAAI,CAAC,MAAM,GAAG,EAAE,UAAU,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,eAAe,WAAW,EAAE,EAAE,EACzE,KAAK,IAAI;AACZ,SAAO,KAAK,EAAE,IAAI,IAAI,IAAI,KAAK,EAAE,WAAW,UAAU,EAAE,gBAAgB,IAAI,KAAK,GAAG,kDAAe,IAAI;AACzG;AAQO,SAAS,iBAAiB,SAAoC;AACnE,QAAM,MAAM,IAAI,KAAK,QAAQ,WAAW;AACxC,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAQ,QAAQ,QAAQ,QAAQ,MAAM,KAAK,IAAI,IAAI;AACzD,QAAM,KAAK,yEAAkB,KAAK,GAAG;AACrC,QAAM,KAAK,EAAE;AAEb,MAAI,QAAQ,KAAK,WAAW,GAAG;AAC7B,UAAM,KAAK,iOAAwC;AAAA,EACrD,OAAO;AACL,UAAM,KAAK,wHAAyB,QAAQ,KAAK,MAAM,EAAE;AACzD,eAAW,KAAK,QAAQ,KAAM,OAAM,KAAK,SAAS,GAAG,GAAG,CAAC;AAAA,EAC3D;AACA,QAAM,KAAK,EAAE;AAEb,MAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,UAAM;AAAA,MACJ,gCAAY,QAAQ,WAAW,MAAM;AAAA,IACvC;AACA,eAAW,KAAK,QAAQ,WAAY,OAAM,KAAK,cAAc,GAAG,GAAG,CAAC;AACpE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,UAAM,IAAI,QAAQ,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AACpE,UAAM;AAAA,MACJ,gCAAY,QAAQ,SAAS,MAAM,mBAAS,CAAC;AAAA,IAC/C;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,yCAAW;AACtB,aAAW,KAAK,QAAQ,OAAO;AAC7B,UAAM;AAAA,MACJ,KAAK,EAAE,IAAI,KAAK,EAAE,KAAK,2CAAa,EAAE,aAAa,+BAAW,EAAE,gBAAgB,+BAAW,EAAE,cAAc,GAAG,EAAE,eAAe,IAAI,mBAAS,EAAE,YAAY,KAAK,EAAE;AAAA,IACnK;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AACb,QAAM;AAAA,IACJ,8KAAgE,QAAQ,mBAAmB,OAAO,iBAAO,OAAO,QAAQ,gBAAgB,GAAG,CAAC;AAAA,EAC9I;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AC/LA,SAAS,SAAAC,cAAa;AACtB,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,cAAY;AAErB;AAAA,EACE,eAAAC;AAAA,EACA,uBAAAC;AAAA,EAEA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EACA,sBAAsBC;AAAA,EAEtB,uBAAAC;AAAA,EAEA;AAAA,EACA,eAAAC;AAAA,EACA,qBAAAC;AAAA,EAGA,gBAAAC;AAAA,EAEA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA,yBAAAC;AAAA,EAEA,iBAAAC;AAAA,EACA;AAAA,EACA,4BAAAC;AAAA,EACA,iBAAAC;AAAA,OACK;AAyDA,SAAS,mBAAmBC,UAAkB,MAAkB,CAAC,GAAS;AAC/E,QAAM,aAAaA,SAChB,QAAQ,KAAK,EACb,YAAY,0DAA0D,EAItE,wBAAwB,EACxB,OAAO,iBAAiB,4CAA4C,EACpE,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,iBAAiB,mBAAmB;AAE9C,aACG,QAAQ,uBAAuB,EAC/B,YAAY,gDAAgD,EAG5D,OAAO,iBAAiB,4CAA4C,EACpE,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,iBAAiB,mBAAmB,EAC3C,mBAAmB,EACnB,OAAO,OAAO,MAAgB,SAAqB,YAAqB;AACvE,UAAM,gBAAiB,QAAQ,QAAQ,KAAK,KAAK,CAAC;AAKlD,UAAM,aAAa,cAAc,aAAa,SAAS,QAAQ,aAAa;AAC5E,UAAM,SAAqB;AAAA,MACzB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,UAAU;AAAA,IACZ;AACA,QAAI;AACF,YAAM,WAAW,MAAM,cAAc,MAAM,QAAQ,GAAG;AACtD,cAAQ,KAAK,QAAQ;AAAA,IACvB,SAAS,OAAgB;AACvB,qBAAe,OAAO,EAAE,SAAS,UAAU,MAAM,EAAE,CAAC;AACpD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;AAEA,eAAsB,cACpB,MACA,SACA,MAAkB,CAAC,GACF;AACjB,QAAM,SAAS,IAAI,UAAU,IAAIC,oBAAmB;AACpD,QAAM,MAAM,IAAI,QAAQ,MAAM,oBAAI,KAAK;AACvC,QAAM,iBAAmC,IAAI,kBAAkB;AAC/D,QAAM,YAAuB,IAAI,WAAW;AAK5C,QAAM,EAAE,QAAQ,IAAI,MAAM,eAAe;AAEzC,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;AAGvC,QAAM,WAAW,MAAM,4BAA4B,GAAG;AACtD,QAAM,QAAQC,aAAW,QAAQ;AAGjC,QAAMC,sBAAoB,MAAM,IAAI;AAGpC,QAAM,WAAW,MAAMC,cAAa,KAAK;AAGzC,QAAM,YAAYC,cAAa,KAAK;AACpC,QAAM,aAAaC,OAAK,MAAM,UAAU,SAAS;AACjD,QAAMC,OAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAK3C,QAAM,cACJ,IAAI,gBACH,OAAO,aAAa,UAAU;AAC7B,UAAMC,wBAAuB,OAAO,WAAW,KAAK;AAAA,EACtD;AAEF,QAAM,YAAY,IAAI,EAAE,YAAY;AACpC,QAAM,kBAAkBF,OAAK,YAAY,cAAc;AACvD,QAAM,UAAUG,qBAAoB;AAAA,IAClC,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,aAAa,SAAS,UAAU;AAAA,IAChC;AAAA,EACF,CAAC;AACD,QAAMC,eAAc,iBAAiB,OAAO;AAG5C,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIL,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ,0BAA0B;AAAA,EACpC,CAAC;AAGD,MAAI,cAAkC;AACtC,MAAI,QAAQ,aAAa,OAAO;AAC9B,kBAAc,MAAMM,sBAAqB,YAAY,WAAW,UAAU,KAAK,WAAW;AAAA,EAC5F;AAGA,QAAM,YAAY,IAAI,EAAE,YAAY;AACpC,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIN,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ,0BAA0B;AAAA,IAClC,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AAGD,QAAM,cAAc,MAAMO,aAAY,OAAO,WAAW,SAAS;AACjE,MAAI;AACF,UAAMC,mBAAkB,iBAAiB,CAAC,MAAM;AAC9C,QAAE,QAAQ,SAAS;AAAA,IACrB,CAAC;AAAA,EACH,UAAE;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAIA,QAAM,aAAa,IAAI,gBAAgB;AACvC,MAAI,iBAAwC;AAC5C,MAAI,cAAmC;AACvC,QAAM,gBAAgB,CAAC,QAAwB;AAC7C,QAAI,mBAAmB,KAAM;AAC7B,qBAAiB;AACjB,eAAW,MAAM;AAAA,EACnB;AACA,QAAM,cAAc,MAAM;AACxB,QAAI,gBAAgB,MAAM;AACxB,UAAI;AACF,oBAAY,KAAK,SAAS;AAAA,MAC5B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,cAAc,QAAQ;AAC7C,QAAM,YAAY,MAAM,cAAc,SAAS;AAC/C,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,SAAS;AAC/B,UAAQ,GAAG,QAAQ,WAAW;AAC9B,MAAI,sBAAsB,WAAW;AAKrC,MAAI;AACJ,MAAI;AACF,QAAI;AACF,eAAS,MAAM,OAAO,IAAI,SAAS,MAAM;AAAA,QACvC,KAAK;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,WAAW;AAAA,QACnB,SAAS,CAAC,UAAU;AAClB,wBAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAAA,IACH,SAAS,YAAqB;AAC5B,YAAMC,yBAAwB,OAAO,YAAY,WAAW,aAAa;AAAA,QACvE;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,YAAY,IAAI,EAAE,YAAY;AAAA,QAC9B;AAAA,MACF,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF,UAAE;AACA,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,SAAS;AAChC,YAAQ,IAAI,QAAQ,WAAW;AAC/B,kBAAc;AAAA,EAChB;AAEA,QAAM,UAAU,IAAI,EAAE,YAAY;AAGlC,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIT,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,WAAW,OAAO;AAAA,IAClB,GAAI,OAAO,WAAW,OAAO,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IAC1D,GAAI,mBAAmB,OAAO,EAAE,iBAAiB,eAAe,IAAI,CAAC;AAAA,IACrE,aAAa,OAAO;AAAA,EACtB,CAAC;AAGD,MAAI,eAAmC;AACvC,MAAI,QAAQ,aAAa,OAAO;AAC9B,mBAAe,MAAMM,sBAAqB,YAAY,WAAW,UAAU,KAAK,WAAW;AAAA,EAC7F;AAKA,MAAI,OAA0B;AAC9B,MAAI,gBAAgB,QAAQ,iBAAiB,MAAM;AACjD,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,IAAI,EAAE,YAAY;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAQA,QAAM,aAAa,oBAAoB,aAAa,cAAc,IAAI;AACtE,QAAM,eAAe,qBAAqB,YAAY;AAAA,IACpD,kBAAkB;AAAA,IAClB,SAASI,SAAQ;AAAA,EACnB,CAAC,EAAE;AAEH,QAAM,cAAcC,mBAAkB,QAAQ,cAAc;AAG5D,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIX,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ,0BAA0B;AAAA,IAClC,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AAGD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ,0BAA0B;AAAA,IAClC,GAAI,OAAO,cAAc,OAAO,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;AAAA,EACrE,CAAC;AAMD,QAAMY,qBAAoB,OAAO,WAAW,CAAC,MAAM;AACjD,MAAE,QAAQ,SAAS;AACnB,MAAE,QAAQ,WAAW;AACrB,MAAE,QAAQ,WAAW,YAAY,OAAO;AACxC,MAAE,QAAQ,gBAAgB;AAAA,EAC5B,CAAC;AAED,MAAI,OAAO,cAAc,KAAM,QAAO,OAAO;AAC7C,SAAOC,kBAAiB,kBAAkB,OAAO,MAAM;AACzD;AAEA,SAASF,mBACP,QACA,gBACwC;AACxC,MAAI,mBAAmB,YAAY,mBAAmB,UAAW,QAAO;AACxE,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,aAAa,OAAO,WAAW,WAAW;AAC5F,WAAO;AAAA,EACT;AACA,MAAI,OAAO,cAAc,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,IAAMG,cAAqC;AAAA,EACzC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AACX;AAEA,SAASD,kBAAiB,KAAoC;AAC5D,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,MAAMC,YAAW,GAAG,KAAK;AAC/B,SAAO,MAAM;AACf;AAEA,eAAeR,sBACb,YACA,WACA,UACA,KACA,aAC6B;AAI7B,MAAI;AACJ,MAAI;AACF,eAAW,MAAMS,aAAY,QAAQ;AAAA,EACvC,SAAS,OAAgB;AACvB,YAAQ,KAAKC,iCAAgC,KAAK,CAAC;AACnD,WAAO;AAAA,EACT;AAKA,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIhB,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI,EAAE,YAAY;AAAA,IAC/B,QAAQ;AAAA,IACR,GAAG;AAAA,EACL,CAAC;AACD,SAAO;AACT;AAEA,eAAe,2BACb,YACA,WACA,UACA,SACA,SACA,YACA,aACA,WAC4B;AAG5B,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,UAAU,UAAU,SAAS,OAAO;AAAA,EACnD,SAAS,OAAgB;AACvB,YAAQ,KAAK,gCAAgC,KAAK,CAAC;AACnD,WAAO;AAAA,EACT;AAGA,aAAW,UAAU,KAAK,eAAe;AACvC,UAAM,YAAY,YAAY;AAAA,MAC5B,gBAAgB;AAAA,MAChB,MAAM;AAAA,MACN,IAAIA,cAAa,KAAK;AAAA,MACtB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,MAAM,OAAO;AAAA,MACb,aAAa,OAAO;AAAA,MACpB,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,oBACP,aACA,cACA,MACU;AACV,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,QAAQ,CAAC,aAAa,YAAY,GAAG;AAC9C,QAAI,SAAS,KAAM;AACnB,eAAW,KAAK,KAAK,OAAQ,KAAI,IAAI,CAAC;AACtC,eAAW,KAAK,KAAK,SAAU,KAAI,IAAI,CAAC;AACxC,eAAW,KAAK,KAAK,UAAW,KAAI,IAAI,CAAC;AAAA,EAC3C;AACA,MAAI,SAAS,MAAM;AACjB,eAAW,UAAU,KAAK,cAAe,KAAI,IAAI,OAAO,IAAI;AAAA,EAC9D;AACA,SAAO,CAAC,GAAG,GAAG,EAAE,KAAK;AACvB;AAEA,SAASgB,iCAAgC,OAAwB;AAC/D,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,WAAO,yBAAyB,OAAO,KAAK,CAAC;AAAA,EAC/C;AACA,QAAM,MAAM,MAAM;AAClB,MAAI,QAAQ,uBAAwB,QAAO;AAC3C,MAAI,QAAQ,wDAAwD;AAClE,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,2BAA4B,QAAO;AAC/C,SAAO,yBAAyB,GAAG;AACrC;AAEA,SAAS,gCAAgC,OAAwB;AAC/D,MAAI,EAAE,iBAAiB,QAAQ;AAC7B,WAAO,yBAAyB,OAAO,KAAK,CAAC;AAAA,EAC/C;AACA,QAAM,MAAM,MAAM;AAClB,MAAI,QAAQ,uBAAwB,QAAO;AAC3C,MAAI,QAAQ,wDAAwD;AAClE,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,cAAe,QAAO;AAClC,MAAI,QAAQ;AACV,WAAO;AACT,SAAO,yBAAyB,GAAG;AACrC;AAEA,SAASZ,qBAAoB,OAOjB;AACV,QAAM,UAAU,CAAC,MAAM,SAAS,GAAG,MAAM,IAAI,EAAE,KAAK,GAAG;AACvD,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,SAAS;AAAA,MACP,IAAI,MAAM;AAAA,MACV,OAAO,aAAa,OAAO,KAAK,MAAM,SAAS;AAAA,MAC/C,SAAS;AAAA,MACT,cAAc,MAAM;AAAA,MACpB,QAAQ,EAAE,GAAG,0BAA0B;AAAA,MACvC,YAAY,MAAM;AAAA,MAClB,QAAQ;AAAA,MACR,mBAAmBa,0BAAyB,MAAM,KAAK,EAAE,SAASP,SAAQ,EAAE,CAAC;AAAA,MAC7E,YAAY;AAAA,QACV,SAAS,MAAM;AAAA,QACf,MAAM,CAAC,GAAG,MAAM,IAAI;AAAA,QACpB,WAAW;AAAA,MACb;AAAA,MACA,eAAe,CAAC;AAAA,MAChB,YAAY;AAAA,IACd;AAAA,EACF;AACF;AAEA,eAAeF,mBACb,UACA,SACe;AACf,QAAM,MAAM,MAAMU,cAAa,QAAQ;AACvC,QAAM,SAASC,eAAc,MAAM,GAAG;AACtC,UAAQ,MAAM;AACd,QAAM,YAAYA,eAAc,MAAM,MAAM;AAC5C,QAAMC,mBAAkB,UAAU,SAAS;AAC7C;AAEA,eAAeX,yBACb,OACA,YACA,WACA,aACA,KAOe;AACf,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIT,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ;AAAA,IACR,SAAS,IAAI;AAAA,IACb,MAAM,IAAI;AAAA,IACV,KAAK,IAAI;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,GAAI,IAAI,mBAAmB,OAAO,EAAE,iBAAiB,IAAI,eAAe,IAAI,CAAC;AAAA,IAC7E,aAAa;AAAA,EACf,CAAC;AACD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ,0BAA0B;AAAA,IAClC,MAAM;AAAA,IACN,IAAI;AAAA,EACN,CAAC;AACD,QAAM,YAAY,YAAY;AAAA,IAC5B,gBAAgB;AAAA,IAChB,MAAM;AAAA,IACN,IAAIA,cAAa,KAAK;AAAA,IACtB,YAAY;AAAA,IACZ,aAAa,IAAI;AAAA,IACjB,QAAQ,0BAA0B;AAAA,EACpC,CAAC;AACD,QAAMY,qBAAoB,OAAO,WAAW,CAAC,MAAM;AACjD,MAAE,QAAQ,SAAS;AACnB,MAAE,QAAQ,WAAW,IAAI;AACzB,MAAE,QAAQ,WAAW,YAAY;AAAA,EACnC,CAAC;AACH;AAEA,eAAe,4BAA4B,KAA8B;AACvE,MAAI;AACF,WAAO,MAAMS,uBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,wEAAwE;AAAA,QACtF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;;;AC/mBA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,YAAAC,WAAU,cAAAC,aAAY,QAAAC,QAAM,YAAAC,iBAAgB;AACrD;AAAA,EACE,eAAAC;AAAA,EACA,gCAAAC;AAAA,EACA,uBAAAC;AAAA,EACA,cAAAC;AAAA,EAEA,wBAAAC;AAAA,EACA,iBAAAC;AAAA,EAGA,yBAAAC;AAAA,EACA;AAAA,EAEA;AAAA,EACA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EAEA,8BAAAC;AAAA,EACA,iBAAAC;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AACP,SAAuB,wBAAAC,6BAA4B;;;ACtBnD,SAAS,wBAAwB;;;ADgCjC,IAAMC,cAAa;AACnB,IAAMC,eAAc;AACpB,IAAMC,qBAAoB;AAC1B,IAAMC,oBAAmB;AAEzB,IAAMC,iBAAgB,oBAAoB;AA0DnC,SAAS,uBAAuBC,UAAwB;AAC7D,QAAM,UAAUA,SACb,QAAQ,SAAS,EACjB,YAAY,sDAAsD;AAErE,UACG,QAAQ,MAAM,EACd,YAAY,uDAAuD,EACnE,OAAO,UAAU,iCAAiC,EAClD;AAAA,IACC;AAAA,IACA,qCAAqCD,eAAc,KAAK,IAAI,CAAC;AAAA,IAC7D;AAAA,EACF,EACC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAgC;AAC7C,UAAM,eAAe,OAAO;AAAA,EAC9B,CAAC;AAEH,UACG,QAAQ,WAAW,EACnB,YAAY,6CAA6C,EACzD,OAAO,UAAU,uCAAuC,EACxD,OAAO,YAAY,kDAAkD,EACrE,OAAO,cAAc,qDAAqD,gBAAgB,EAC1F;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,IAAY,YAAgC;AACzD,UAAM,eAAe,IAAI,OAAO;AAAA,EAClC,CAAC;AAEH,UACG,QAAQ,QAAQ,EAChB,YAAY,mCAAmC,EAC/C,eAAe,qBAAqB,wCAAwC,iBAAiB,EAC7F,eAAe,iBAAiB,6BAA6B,EAC7D,OAAO,kBAAkB,8BAA8B,kBAAkB,EACzE,OAAO,oBAAoB,gCAAgC,mBAAmB,EAC9E,OAAO,aAAa,2CAA2C,EAC/D,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAkC;AAC/C,UAAM,iBAAiB,OAAO;AAAA,EAChC,CAAC;AAEH,UACG,QAAQ,mBAAmB,EAC3B,YAAY,kDAAkD,EAC9D,OAAO,iBAAiB,sBAAsB,mBAAmB,EACjE,OAAO,sBAAsB,4BAA4B,EACzD,OAAO,UAAU,2BAA2B,EAC5C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,gBAAwB,YAAgC;AACrE,UAAM,eAAe,gBAAgB,OAAO;AAAA,EAC9C,CAAC;AAEH,UACG,QAAQ,SAAS,EACjB;AAAA,IACC;AAAA,EACF,EACC,OAAO,kBAAkB,sDAAsD,EAC/E,OAAO,SAAS,wCAAwC,EACxD,OAAO,aAAa,yCAAyC,EAC7D,OAAO,UAAU,6BAA6B,EAC9C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAAmC;AAChD,UAAM,kBAAkB,OAAO;AAAA,EACjC,CAAC;AACL;AAOA,eAAsB,eACpB,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,iBAAiB,SAAS,GAAG;AAAA,EACrC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAMA,eAAsB,iBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,KAAK,MAAM;AACxE,QAAM,QAAQE,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAM3C,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,WACJ,MAAM,mBAAmB,OAAO;AAAA,IAC9B;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,QAAQ,CAAC,KAAK,WAAW,qBAAqB,KAAK,MAAM;AAAA,EAC3D,CAAC,GACD,IAAI,CAAC,WAAW;AAAA,IAChB,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA,IACf,eAAe,MAAM;AAAA,EACvB,EAAE;AAEF,MAAI,QAAQ,WAAW,GAAG;AACxB,oBAAgB,OAAO;AACvB;AAAA,EACF;AAKA,UAAQ;AAAA,IACN,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,QAAQ,QAAQ,UAAU,IAAI,KAAK,MAAM,EAAE,QAAQ,QAAQ,UAAU;AAAA,EAC9F;AAEA,QAAM,WACJ,QAAQ,WAAW,SACf,QAAQ,OAAO,CAAC,MAAM,EAAE,QAAQ,QAAQ,WAAW,QAAQ,MAAM,IACjE;AAEN,MAAI,SAAS,WAAW,GAAG;AACzB,oBAAgB,OAAO;AACvB;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH,SAAS,IAAI,CAAC,OAAO;AAAA,UACnB,GAAG,EAAE,QAAQ;AAAA,UACb,SAAS,EAAE;AAAA,UACX,gBAAgB,EAAE;AAAA,QACpB,EAAE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,OAAO;AACL,yBAAqB,QAAQ;AAAA,EAC/B;AACF;AAMA,eAAsB,eACpB,SACA,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,iBAAiB,SAAS,SAAS,GAAG;AAAA,EAC9C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,iBACpB,SACA,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,KAAK,MAAM;AACxE,QAAM,QAAQD,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,YAAY,MAAMC,kBAAiB,OAAO,OAAO;AAEvD,QAAM,aAAaC,OAAK,MAAM,UAAU,SAAS;AACjD,QAAM,kBAAkBA,OAAK,YAAY,cAAc;AACvD,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAMC,cAAa,eAAe;AAC9C,cAAUC,eAAc,MAAM,GAAG;AAAA,EACnC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,sBAAsB,OAAO,EAAE;AAAA,IACjD;AACA,UAAM,IAAI,MAAM,0BAA0B,EAAE,OAAO,MAAM,CAAC;AAAA,EAC5D;AAEA,QAAM,SAAS,MAAM,cAAc,YAAY;AAAA,IAC7C,WAAW,CAAC,MAAM,mBAAmB,GAAG,SAAS;AAAA,EACnD,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,EAAE,SAAS,QAAQ,SAAS,OAAO,GAAG,MAAM,CAAC,CAAC;AACzE;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,cAAc,KAAK,oBAAI,KAAK;AAC5C,uBAAqB,SAAS,QAAQ,SAAS,gBAAgB,GAAG;AACpE;AAEA,SAAS,aAAa,QAA+B;AACnD,MAAI,WAAW,oCAAqC,QAAO;AAC3D,MAAI,WAAW,uBAAwB,QAAO;AAC9C,SAAO;AACT;AAEA,SAAS,qBAAqB,SAAoC;AAIhE,QAAM,WAAWC,wBAAuB,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AACvE,QAAM,OAAO,QAAQ,IAAI,CAAC,MAAM;AAC9B,UAAM,MAAMC,YAAW,EAAE,WAAW,QAAQ;AAC5C,UAAM,SAAS,GAAG,EAAE,QAAQ,QAAQ,MAAM,GAAG,aAAa,EAAE,aAAa,CAAC;AAC1E,UAAM,SAAS,EAAE,QAAQ,QAAQ,OAAO;AACxC,UAAM,YAAY,EAAE,QAAQ,QAAQ;AACpC,UAAM,YAAY,EAAE,QAAQ,QAAQ,cAAc;AAClD,UAAM,cAAc,YAAY,IAAI,KAAK,SAAS,YAAY;AAC9D,UAAM,SAAS,EAAE,QAAQ,QAAQ,SAAS,MAAM;AAChD,WAAO,EAAE,KAAK,QAAQ,QAAQ,WAAW,MAAM;AAAA,EACjD,CAAC;AAED,QAAM,SAAS;AAAA,IACb,KAAKC;AAAA,MACH,KAAK,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,MACrB,WAAW;AAAA,IACb;AAAA,IACA,QAAQA;AAAA,MACN,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACxB,SAAS;AAAA,IACX;AAAA,IACA,QAAQA;AAAA,MACN,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACxB,SAAS;AAAA,IACX;AAAA,IACA,WAAWA;AAAA,MACT,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS;AAAA,MAC3B,aAAa;AAAA,IACf;AAAA,EACF;AAEA,UAAQ;AAAA,IACN,GAAGC,KAAI,YAAY,OAAO,GAAG,CAAC,KAAKA,KAAI,UAAU,OAAO,MAAM,CAAC,KAAKA,KAAI,UAAU,OAAO,MAAM,CAAC,KAAKA,KAAI,cAAc,OAAO,SAAS,CAAC;AAAA,EAC1I;AACA,aAAW,OAAO,MAAM;AACtB,YAAQ;AAAA,MACN,GAAGA,KAAI,IAAI,KAAK,OAAO,GAAG,CAAC,KAAKA,KAAI,IAAI,QAAQ,OAAO,MAAM,CAAC,KAAKA,KAAI,IAAI,QAAQ,OAAO,MAAM,CAAC,KAAKA,KAAI,IAAI,WAAW,OAAO,SAAS,CAAC,KAAK,IAAI,KAAK;AAAA,IAC1J;AAAA,EACF;AACF;AAEA,SAAS,qBACP,SACA,QACA,SACA,gBACA,KACM;AACN,QAAM,IAAI,QAAQ;AAClB,UAAQ,IAAI,YAAY,EAAE,EAAE,cAAc,EAAE,MAAM,GAAG;AACrD,UAAQ,IAAI,kBAAkB,EAAE,OAAO,IAAI,MAAM,EAAE,OAAO,OAAO,GAAG;AACpE,UAAQ,IAAI,kBAAkB,EAAE,YAAY,EAAE;AAC9C,UAAQ,IAAI,kBAAkB,EAAE,UAAU,EAAE;AAC5C,MAAI,EAAE,aAAa,QAAW;AAC5B,YAAQ,IAAI,kBAAkB,EAAE,QAAQ,EAAE;AAAA,EAC5C;AACA,UAAQ,IAAI,kBAAkB,iBAAiB,EAAE,mBAAmB,gBAAgB,OAAO,CAAC,EAAE;AAC9F,QAAM,iBAAiB,EAAE,WAAW,KAAK,SAAS,IAAI,IAAI,EAAE,WAAW,KAAK,KAAK,GAAG,CAAC,KAAK;AAC1F,UAAQ,IAAI,kBAAkB,EAAE,WAAW,OAAO,GAAG,cAAc,EAAE;AACrE,MAAI,EAAE,WAAW,cAAc,MAAM;AACnC,YAAQ,IAAI,kBAAkB,EAAE,WAAW,SAAS,EAAE;AAAA,EACxD;AACA,MAAI,EAAE,UAAU,QAAW;AACzB,YAAQ,IAAI,kBAAkB,EAAE,KAAK,EAAE;AAAA,EACzC;AACA,UAAQ,IAAI,kBAAkB,mBAAmB,EAAE,aAAa,CAAC,EAAE;AAEnE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,WAAW,OAAO,MAAM,QAAQ;AAC5C,QAAM,SAAS,YAAY,MAAM;AACjC,aAAW,CAAC,MAAM,CAAC,KAAK,QAAQ;AAC9B,YAAQ,IAAI,KAAKA,KAAI,GAAG,IAAI,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE;AAAA,EAC7C;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,kBAAkB,kBAAkB,SAAS,QAAQ,GAAG,CAAC,EAAE;AAEvE,MAAI,OAAO,WAAW,EAAG;AAEzB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,UAAU,QAAQ,WAAW,QAAQ,QAAQ,SAAS;AAC5D,QAAM,QAAQ,UAAU,SAAS,OAAO,MAAM,CAAC,IAAI;AACnD,QAAM,UAAU,UAAU,gBAAgB,QAAQ,MAAM,MAAM;AAC9D,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,OAAO;AACnB,aAAW,MAAM,OAAO;AACtB,YAAQ,IAAI,KAAK,gBAAgB,EAAE,CAAC,EAAE;AAAA,EACxC;AACF;AAOA,SAAS,kBAAkB,SAAkB,QAAiB,KAAmB;AAC/E,QAAM,IAAI,2BAA2B,QAAQ,QAAQ,IAAI,QAAQ,SAAS,QAAQ,GAAG;AACrF,QAAM,QAAkB,CAAC;AACzB,MAAI,EAAE,OAAO,SAAS,EAAG,OAAM,KAAK,GAAG,EAAE,OAAO,OAAO,eAAe,OAAO,CAAC,gBAAgB;AAC9F,QAAM,KAAK,GAAG,EAAE,YAAY,UAAU,EAAE,gBAAgB,YAAY,EAAE,aAAa,MAAM;AACzF,QAAM,cAAc,EAAE,oBAAoB,kBAAkB,UAAU;AACtE,QAAM,KAAK,UAAU,iBAAiB,EAAE,YAAY,CAAC,KAAK,WAAW,GAAG;AACxE,MAAI,EAAE,aAAa,eAAe;AAChC,UAAM,KAAK,WAAW,iBAAiB,EAAE,mBAAmB,CAAC,EAAE;AAAA,EACjE;AACA,QAAM,KAAK,QAAQ,iBAAiB,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,YAAY,EAAE,EAAE;AAChF,QAAM;AAAA,IACJ,EAAE,aAAa,cACX,WAAW,iBAAiB,EAAE,aAAa,CAAC,KAC5C;AAAA,EACN;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,iBACP,YACA,gBACA,SACQ;AACR,MAAI,QAAQ,aAAa,KAAM,QAAO;AAUtC,MAAI,CAACC,YAAW,UAAU,GAAG;AAC3B,QAAI,eAAe,IAAK,QAAO;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,eAAgB,QAAO;AAC1C,QAAM,MAAMC,UAAS,gBAAgB,UAAU;AAC/C,MAAI,IAAI,WAAW,KAAK,QAAQ,IAAK,QAAO;AAK5C,MAAI,IAAI,WAAW,IAAI,EAAG,QAAO;AACjC,SAAO,KAAK,GAAG;AACjB;AAEA,SAAS,mBAAmB,OAAkC;AAC5D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,OAAO,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AACxC,QAAM,YAAY,MAAM,SAAS;AACjC,MAAI,aAAa,EAAG,QAAO,GAAG,MAAM,MAAM,WAAW,IAAI;AACzD,SAAO,GAAG,MAAM,MAAM,WAAW,IAAI,UAAU,SAAS;AAC1D;AAEA,SAAS,YAAY,QAAmD;AACtE,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,MAAM,QAAQ;AACvB,QAAI,IAAI,GAAG,OAAO,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK,CAAC;AAAA,EAC9C;AACA,SAAO,CAAC,GAAG,IAAI,QAAQ,CAAC;AAC1B;AAEA,SAAS,gBAAgB,IAAmB;AAC1C,SAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,oBAAoB,EAAE,CAAC;AACjF;AAEA,SAAS,oBAAoB,IAAmB;AAC9C,UAAQ,GAAG,MAAM;AAAA,IACf,KAAK,oBAAoB;AACvB,YAAM,WAAW,GAAG,KAAK,SAAS,IAAI,IAAI,GAAG,KAAK,KAAK,GAAG,CAAC,KAAK;AAChE,YAAM,WAAW,GAAG,cAAc,OAAO,gBAAgB,QAAQ,GAAG,SAAS;AAC7E,aAAO,GAAG,GAAG,OAAO,GAAG,QAAQ,KAAK,QAAQ,KAAK,GAAG,WAAW;AAAA,IACjE;AAAA,IACA,KAAK;AACH,aAAO,UAAU,GAAG,MAAM,UAAU,GAAG,KAAK;AAAA,IAC9C,KAAK;AACH,aAAO,GAAG,GAAG,WAAW,IAAI,GAAG,IAAI;AAAA,IACrC,KAAK;AACH,aAAO,GAAG,GAAG,IAAI,OAAO,GAAG,EAAE;AAAA,IAC/B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,GAAG,cAAc,SAAY,aAAa,GAAG,SAAS,KAAK;AAAA,IACpE,KAAK;AACH,aAAO,GAAG,GAAG,OAAO,IAAI,SAAS,GAAG,UAAU;AAAA,IAChD,KAAK;AACH,aAAO,GAAG,aAAa,SAAY,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC3D,KAAK;AACH,aAAO,GAAG,aAAa,SAAY,MAAM,GAAG,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG;AAAA,IAC5E,KAAK;AACH,aAAO,YAAY,GAAG,WAAW;AAAA,IACnC,KAAK;AACH,aAAO,GAAG;AAAA,IACZ,KAAK;AACH,aAAO,GAAG;AAAA,IACZ,KAAK;AACH,aAAO,GAAG,GAAG,IAAI,OAAO,GAAG,EAAE;AAAA,IAC/B,KAAK,mBAAmB;AACtB,YAAM,cACJ,GAAG,+BAA+B,OAAO,yBAAyB;AACpE,aAAO,QAAQC,aAAY,GAAG,OAAO,CAAC,aAAa,GAAG,wBAAwB,MAAM,aAAa,WAAW;AAAA,IAC9G;AAAA,IACA,KAAK,0BAA0B;AAC7B,YAAM,QAAQ,GAAG,sBAAsB;AACvC,YAAM,UAAU,GAAG,wBAAwB;AAC3C,YAAM,QAAQ,GAAG,gBAAgB,SAAY,UAAU,GAAG,WAAW,KAAK;AAC1E,aAAO,QAAQA,aAAY,GAAG,OAAO,CAAC,MAAM,KAAK,OAAO,OAAO,UAAU,KAAK;AAAA,IAChF;AAAA,IACA,KAAK;AACH,aAAO,QAAQA,aAAY,GAAG,OAAO,CAAC,KAAK,GAAG,KAAK;AAAA,IACrD,KAAK;AACH,aAAO,QAAQA,aAAY,GAAG,OAAO,CAAC,KAAK,GAAG,KAAK;AAAA,IACrD,KAAK;AACH,aAAO,GAAG,KAAK,SAAS,KAAK,GAAG,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,QAAQ,GAAG;AAAA,IACjE,KAAK;AACH,aAAO,GAAG,GAAG,MAAM,KAAK,GAAG,OAAO,aAAa,GAAG,OAAO;AAAA,EAC7D;AACF;AAEA,SAASC,SAAQ,IAAoB;AACnC,SAAON,YAAW,IAAIZ,kBAAiB;AACzC;AAEA,SAASiB,aAAY,IAAoB;AACvC,MAAI,GAAG,WAAWlB,YAAW,GAAG;AAC9B,WAAO,GAAG,MAAMA,aAAY,QAAQA,aAAY,SAASC,kBAAiB;AAAA,EAC5E;AACA,SAAO,GAAG,MAAM,GAAGA,kBAAiB;AACtC;AAEA,SAASY,YAAW,IAAY,KAAqB;AACnD,MAAI,GAAG,WAAWd,WAAU,GAAG;AAC7B,WAAO,GAAG,MAAMA,YAAW,QAAQA,YAAW,SAAS,GAAG;AAAA,EAC5D;AACA,SAAO,GAAG,MAAM,GAAG,GAAG;AACxB;AAQA,SAASa,wBAAuB,YAAuC;AACrE,MAAI,WAAW,UAAU,EAAG,QAAOX;AACnC,WAAS,MAAMA,oBAAmB,OAAOC,mBAAkB,OAAO,GAAG;AACnE,UAAM,OAAO,oBAAI,IAAY;AAC7B,QAAI,WAAW;AACf,eAAW,OAAO,YAAY;AAC5B,YAAM,MAAMW,YAAW,KAAK,GAAG;AAC/B,UAAI,KAAK,IAAI,GAAG,GAAG;AACjB,mBAAW;AACX;AAAA,MACF;AACA,WAAK,IAAI,GAAG;AAAA,IACd;AACA,QAAI,CAAC,SAAU,QAAO;AAAA,EACxB;AACA,SAAOX;AACT;AAEA,SAASa,KAAI,OAAe,OAAuB;AACjD,SAAO,MAAM,UAAU,QAAQ,QAAQ,QAAQ,IAAI,OAAO,QAAQ,MAAM,MAAM;AAChF;AAEA,SAASD,QAAO,QAA2B,OAAuB;AAChE,MAAI,MAAM;AACV,aAAW,KAAK,OAAQ,KAAI,EAAE,SAAS,IAAK,OAAM,EAAE;AACpD,SAAO;AACT;AAWA,eAAe,gCACb,KACA,QACiB;AACjB,SAAO,2BAA2B,KAAK,WAAW,MAAM,EAAE;AAC5D;AAEA,eAAeR,6BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMc,sBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIT,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,OAAO,CAAC,GAAG;AAC7D,UAAM,IAAI,MAAM,mBAAmB,GAAG,EAAE;AAAA,EAC1C;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAA4B;AACtD,QAAM,SAAS,oBAAoB,UAAU,GAAG;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,2BAA2B,GAAG,mBAAmBR,eAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EAC7F;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,gBAAgB,SAAmC;AAC1D,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,IAAI;AAAA,EAClB,OAAO;AACL,YAAQ,IAAI,oBAAoB;AAAA,EAClC;AACF;AAoBA,eAAsB,iBACpB,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,mBAAmB,SAAS,GAAG;AAAA,EACvC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,mBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,KAAK,QAAQ;AAC1E,QAAM,QAAQE,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,WAAW,MAAMe,cAAa,KAAK;AAEzC,QAAM,UAAU,MAAM,cAAc,QAAQ,IAAI;AAChD,QAAM,OAAO,gBAAgB,OAAO;AAEpC,QAAM,SAASC,4BAA2B,UAAU,IAAI;AACxD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,0BAA0B,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,EACnE;AAEA,MAAI,OAAO,KAAK,mBAAmB,SAAS;AAC1C,UAAM,IAAI,MAAM,sCAAsC,OAAO,KAAK,cAAc,EAAE;AAAA,EACpF;AAEA,QAAMC,iBAAsC,EAAE,QAAQ,QAAQ,WAAW,KAAK;AAC9E,MAAI,QAAQ,UAAU,OAAW,CAAAA,eAAc,gBAAgB,QAAQ;AACvE,MAAI,QAAQ,SAAS,QAAW;AAC9B,IAAAA,eAAc,iBAAiB,MAAM,cAAc,OAAO,QAAQ,IAAI;AAAA,EACxE;AAEA,QAAM,SAAS,MAAMC,uBAAsB,OAAO,UAAU,OAAO,MAAMD,cAAa;AAQtF,QAAM,iBAAiB,OAAO;AAC9B,MAAI,eAAe,eAAe,KAAK,eAAe,2BAA2B;AAC/E,UAAM,UAAU,eAAe,4BAA4B,IAAI;AAC/D,YAAQ;AAAA,MACN,qBAAqB,eAAe,eAAe,OAAO,sCAAsC,eAAe,YAAY,wBAAwB,OAAO;AAAA,IAC5J;AAAA,EACF;AAEA,2BAAyB,SAAS,MAAM;AAC1C;AAEA,eAAe,cAAc,MAA+B;AAC1D,MAAI;AACF,WAAO,MAAME,UAAS,MAAM,MAAM;AAAA,EACpC,SAAS,OAAgB;AACvB,QAAId,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,2BAA2B,EAAE,OAAO,MAAM,CAAC;AAAA,IAC7D;AACA,QAAIA,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,+BAA+B,EAAE,OAAO,MAAM,CAAC;AAAA,IACjE;AACA,UAAM,IAAI,MAAM,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,EAClE;AACF;AAEA,SAAS,gBAAgB,MAAuB;AAC9C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,SAAS,OAAgB;AACvB,UAAM,IAAI,MAAM,+BAA+B,EAAE,OAAO,MAAM,CAAC;AAAA,EACjE;AACF;AAEA,SAAS,kBAAkB,KAAqB;AAC9C,MAAI,QAAQ,QAAQ;AAClB,UAAM,IAAIe,sBAAqB,uBAAuB,GAAG,sBAAsB;AAAA,EACjF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAqB;AAC/C,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIA,sBAAqB,yBAAyB;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,KAAqB;AAChD,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIA,sBAAqB,kBAAkB;AAAA,EACnD;AACA,SAAO;AACT;AAEA,SAAS,yBACP,SACA,QACM;AACN,QAAM,QAAQ,QAAQ,WAAW;AACjC,QAAM,MAAMP,SAAQ,OAAO,SAAS;AACpC,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,YAAY,OAAO;AAAA,QACnB,aAAa,OAAO;AAAA,QACpB,SAAS;AAAA,QACT,QAAQ,EAAE,MAAM,OAAO,iBAAiB,SAAS,QAAQ;AAAA,QACzD,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AACA;AAAA,EACF;AAEA,MAAI,OAAO;AACT,YAAQ;AAAA,MACN,yBAAyB,OAAO,UAAU,gBAAgB,GAAG;AAAA,IAC/D;AACA;AAAA,EACF;AAEA,UAAQ;AAAA,IACN,oBAAoB,GAAG,KAAK,OAAO,UAAU,iBAAiBQ,UAAS,QAAQ,IAAI,CAAC;AAAA,EACtF;AACF;AAMA,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAc/B,eAAsB,eACpB,gBACA,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,iBAAiB,gBAAgB,SAAS,GAAG;AAAA,EACrD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,iBACpB,gBACA,SACA,KACe;AACf,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,cAAc,QAAQ,aAAa;AACzC,MAAI,CAAC,WAAW,CAAC,aAAa;AAC5B,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AACA,MAAI,WAAW,aAAa;AAC1B,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAGA,MAAI,eAAe,QAAQ,aAAa,KAAK;AAC3C,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,KAAK,MAAM;AACxE,QAAM,QAAQtB,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,YAAY,MAAMC,kBAAiB,OAAO,cAAc;AAE9D,QAAM,OAAO,UAAW,QAAQ,OAAkB,MAAM,aAAa,QAAQ,QAAkB;AAC/F,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAEA,QAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,QAAM,QAAQ;AAQd,QAAM,cAAc,MAAMqB,aAAY,OAAO,WAAW,KAAK;AAC7D,MAAI;AACJ,MAAI;AACF,aAAS,MAAMC,8BAA6B;AAAA,MAC1C;AAAA,MACA,WAAW;AAAA,MACX,cAAc,CAAC,aACZ;AAAA,QACC,gBAAgB;AAAA,QAChB,IAAI;AAAA,QACJ,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACJ,CAAC;AAAA,EACH,UAAE;AACA,UAAM,YAAY,QAAQ;AAAA,EAC5B;AAEA,yBAAuB,SAAS,WAAW,OAAO,SAAS,OAAO,eAAe,IAAI;AACvF;AAEA,eAAe,aAAa,MAA+B;AACzD,MAAI;AACF,WAAO,MAAMJ,UAAS,MAAM,MAAM;AAAA,EACpC,SAAS,OAAgB;AACvB,QAAId,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,yBAAyB,EAAE,OAAO,MAAM,CAAC;AAAA,IAC3D;AACA,QAAIA,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,6BAA6B,EAAE,OAAO,MAAM,CAAC;AAAA,IAC/D;AACA,UAAM,IAAI,MAAM,8BAA8B,EAAE,OAAO,MAAM,CAAC;AAAA,EAChE;AACF;AAEA,SAAS,oBAAoB,KAAqB;AAChD,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIe,sBAAqB,0BAA0B;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,uBACP,SACA,WACA,SACA,eACA,MACM;AACN,QAAM,MAAMP,SAAQ,SAAS;AAC7B,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,aAAa,KAAK;AAAA,MACpB,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,QAAM,UACJ,KAAK,SAAS,0BAA0B,GAAG,KAAK,MAAM,GAAG,sBAAsB,CAAC,QAAQ;AAC1F,UAAQ,IAAI,yBAAyB,GAAG,KAAK,aAAa,MAAM,OAAO,EAAE;AAC3E;AAOA,eAAsB,kBACpB,SACA,MAAsB,CAAC,GACR;AACf,MAAI;AACF,UAAM,oBAAoB,SAAS,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAUA,eAAsB,oBACpB,SACA,KACe;AACf,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,MAAM;AACzD,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,MAAM;AACzD,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,gCAAgC,KAAK,SAAS;AAC3E,QAAM,QAAQd,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,aACJ,QAAQ,YAAY,SAChB,CAAC,MAAMC,kBAAiB,OAAO,QAAQ,OAAO,CAAC,IAC/C,MAAMuB,sBAAqB,KAAK;AAEtC,QAAM,SAAS,QAAQ,WAAW;AAClC,QAAM,OAAqB,CAAC;AAC5B,aAAW,aAAa,YAAY;AAClC,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,sBAAsB,OAAO,WAAW,EAAE,OAAO,CAAC;AAAA,IACpE,SAAS,OAAgB;AACvB,WAAK,KAAK;AAAA,QACR,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD,CAAC;AACD;AAAA,IACF;AACA,QAAI,QAAQ,WAAW,aAAa;AAClC,WAAK,KAAK,EAAE,YAAY,WAAW,QAAQ,aAAa,aAAa,QAAQ,WAAW,CAAC;AAAA,IAC3F,OAAO;AACL,WAAK,KAAK,EAAE,YAAY,WAAW,QAAQ,WAAW,QAAQ,QAAQ,OAAO,CAAC;AAAA,IAChF;AAAA,EACF;AAEA,QAAM,gBAAgB,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAClE,QAAM,aAAa,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;AAE5D,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,EAC3C,OAAO;AACL,eAAW,OAAO,MAAM;AACtB,cAAQ,IAAI,GAAG,IAAI,UAAU,KAAK,iBAAiB,KAAK,MAAM,CAAC,EAAE;AAAA,IACnE;AACA,UAAM,YAAY,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE;AAC/D,UAAM,UAAU,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAC3D,YAAQ;AAAA,MACN,aAAa,KAAK,MAAM,iBAAY,SAAS,IAAI,SAAS,uBAAuB,WAAW,KACvF,OAAO,aAAa,UAAU;AAAA,IACrC;AAAA,EACF;AAKA,MAAI,gBAAgB,KAAK,aAAa,GAAG;AACvC,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,SAAS,iBAAiB,KAAiB,QAAyB;AAClE,UAAQ,IAAI,QAAQ;AAAA,IAClB,KAAK;AACH,aAAO,GAAG,SAAS,kBAAkB,WAAW,KAAK,IAAI,WAAW;AAAA,IACtE,KAAK;AACH,aAAO,IAAI,WAAW,aAClB,0DACA,YAAY,IAAI,MAAM;AAAA,IAC5B,KAAK;AACH,aAAO,UAAU,IAAI,OAAO;AAAA,EAChC;AACF;;;AEphCA;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EACA,yBAAAC;AAAA,OAGK;AA6BA,SAAS,qBAAqBC,UAAwB;AAC3D,EAAAA,SACG,QAAQ,OAAO,EACf,YAAY,8EAA8E,EAC1F,OAAO,eAAe,8CAA8C,EACpE,OAAO,YAAY,qDAAqD,EACxE,OAAO,UAAU,+BAA+B,EAChD,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAA0B;AACvC,UAAM,SAAS,OAAO;AAAA,EACxB,CAAC;AACL;AAGA,eAAsB,SAAS,SAAuB,MAAoB,CAAC,GAAkB;AAC3F,MAAI;AACF,UAAM,WAAW,SAAS,GAAG;AAAA,EAC/B,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAGA,eAAsB,WAAW,SAAuB,KAAkC;AACxF,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,8BAA8B,GAAG;AAC9D,QAAM,QAAQC,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,MAAM,IAAI,cAAc,KAAK,oBAAI,KAAK;AAC5C,QAAM,SAAS,MAAM,iBAAiB;AAAA,IACpC;AAAA,IACA;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,mBAAmB,GAAG,GAAG;AAAA,IAChD,eAAe,CAAC,KAAK,WAAW,iBAAiB,KAAK,MAAM;AAAA,EAC9D,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3C;AAAA,EACF;AACA,iBAAe,QAAQ,QAAQ,aAAa,MAAM,QAAQ,UAAU,IAAI;AAC1E;AAEA,SAAS,eAAe,QAAyB,UAAmB,OAAsB;AACxF,QAAM,IAAI,OAAO;AACjB,QAAM,aACJ,OAAO,SAAS,SAAS,IACrB,KAAK,OAAO,SAAS,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,CAAC,MACpE;AACN,UAAQ,IAAI,aAAa,EAAE,YAAY,GAAG,UAAU,EAAE;AAEtD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,gCAAgC;AAC5C,QAAM,gBAAgB,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAC3E,QAAM,cACJ,EAAE,mBAAmB,gBAAgB,EAAE,eACnC,oBAAoB,aAAa,OAAO,EAAE,YAAY,eACtD,EAAE,kBACA,KACA;AACR,UAAQ,IAAI,wBAAwB,UAAU,EAAE,OAAO,MAAM,CAAC,GAAG,WAAW,EAAE;AAC9E,MAAI,EAAE,OAAO,YAAY,GAAG;AAC1B,YAAQ,IAAI,wBAAwB,UAAU,EAAE,OAAO,SAAS,CAAC,WAAW;AAAA,EAC9E;AACA,UAAQ;AAAA,IACN,wBAAwB,EAAE,YAAY,cAAc,EAAE,gBAAgB,WAAW,EAAE,aAAa;AAAA,EAClG;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,mEAAmE;AAC/E,QAAM,eAAe,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,oBAAoB,eAAe,EAAE;AAC1F,QAAM,cACJ,iBAAiB,EAAE,eACf,kBACA,iBAAiB,IACf,oDACA,oBAAoB,YAAY,OAAO,EAAE,YAAY;AAC7D,UAAQ;AAAA,IACN,sBAAsB,iBAAiB,EAAE,oBAAoB,CAAC,aAAa,WAAW,iCAAiC,OAAO,QAAQ;AAAA,EACxI;AACA,MAAI,EAAE,iBAAiB,EAAE,sBAAsB;AAC7C,YAAQ;AAAA,MACN,sBAAsB,iBAAiB,EAAE,YAAY,CAAC;AAAA,IACxD;AAAA,EACF;AACA,MAAI,EAAE,wBAAwB;AAC5B,UAAM,kBAAkB,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,aAAa,EAAE;AACpF,YAAQ;AAAA,MACN,sBAAsB,iBAAiB,EAAE,mBAAmB,CAAC,8DAA8D,eAAe,OAAO,EAAE,YAAY;AAAA,IACjK;AAAA,EACF;AACA,QAAM,WAAW,EAAE,mBAAmB,IAAI,KAAK,EAAE,gBAAgB,yBAAyB;AAC1F,UAAQ;AAAA,IACN,sBAAsB,iBAAiB,EAAE,aAAa,CAAC,mBAAmB,QAAQ;AAAA,EACpF;AACA,QAAM,YAAY,EAAE,sBAChB,KACA;AACJ,UAAQ;AAAA,IACN,sBAAsB,iBAAiB,EAAE,aAAa,CAAC,0BAA0B,SAAS;AAAA,EAC5F;AAEA,MAAI,YAAY,OAAO,SAAS,SAAS,GAAG;AAC1C,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,YAAY;AACxB,eAAW,KAAK,OAAO,UAAU;AAC/B,cAAQ,IAAI,KAAK,EAAE,UAAU,KAAK,eAAe,CAAC,CAAC,EAAE;AAAA,IACvD;AAAA,EACF;AAEA,MAAI,SAAS,OAAO,MAAM,SAAS,GAAG;AACpC,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,kCAAkC;AAC9C,eAAW,KAAK,OAAO,OAAO;AAC5B,YAAM,UACJ,EAAE,sBAAsB,IAAI,WAAW,iBAAiB,EAAE,mBAAmB,CAAC,MAAM;AACtF,cAAQ;AAAA,QACN,KAAK,EAAE,IAAI,KAAK,iBAAiB,EAAE,oBAAoB,CAAC,UAAU,OAAO,KAAK,UAAU,EAAE,OAAO,MAAM,CAAC,aAAa,EAAE,YAAY,UAAU,EAAE,gBAAgB,YAAY,EAAE,aAAa;AAAA,MAC5L;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,eAAe,GAA4B;AAClD,QAAM,MAAM,EAAE,sBAAsB,iBAAiB,EAAE,aAAa,IAAI;AACxE,QAAM,SAAS,EAAE,kBAAkB,GAAG,UAAU,EAAE,OAAO,MAAM,CAAC,aAAa;AAC7E,QAAM,UAAU,EAAE,yBACd,WAAW,iBAAiB,EAAE,mBAAmB,CAAC,KAClD;AACJ,SAAO,GAAG,EAAE,YAAY,cAAc,MAAM,YAAY,iBAAiB,EAAE,YAAY,CAAC,GAAG,OAAO,aAAa,GAAG;AACpH;AAGA,SAAS,UAAU,GAAmB;AACpC,SAAO,EAAE,eAAe,OAAO;AACjC;AAEA,eAAe,8BAA8B,KAA8B;AACzE,MAAI;AACF,WAAO,MAAMC,wBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,0EAA0E;AAAA,QACxF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeD,6BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAME,sBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;ACtMA;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EAEA,gBAAAC;AAAA,EACA,yBAAAC;AAAA,EAEA;AAAA,OACK;AAmBA,SAAS,sBAAsBC,UAAwB;AAC5D,EAAAA,SACG,QAAQ,QAAQ,EAChB,YAAY,yCAAyC,EACrD,OAAO,UAAU,uCAAuC,EACxD,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAA2B;AACxC,UAAM,UAAU,OAAO;AAAA,EACzB,CAAC;AACL;AAOA,eAAsB,UAAU,SAAwB,MAAqB,CAAC,GAAkB;AAC9F,MAAI;AACF,UAAM,YAAY,SAAS,GAAG;AAAA,EAChC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AASA,eAAsB,YAAY,SAAwB,KAAmC;AAC3F,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,+BAA+B,GAAG;AAC/D,QAAM,QAAQC,aAAW,cAAc;AAKvC,MAAI;AACF,UAAMC,sBAAoB,MAAM,IAAI;AAAA,EACtC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AAEA,MAAI;AACJ,MAAI;AACF,eAAW,MAAMC,cAAa,KAAK;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAID,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AAKA,UAAM,IAAI,MAAM,qCAAqC,EAAE,OAAO,MAAM,CAAC;AAAA,EACvE;AAEA,QAAM,WAAW,MAAM,oBAAoB,EAAE,UAAU,MAAM,CAAC;AAC9D,QAAM,YAAY,OAAO,QAAQ;AAEjC,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,EAC/C,OAAO;AACL,qBAAiB,QAAQ;AAAA,EAC3B;AACF;AAEA,SAAS,iBAAiB,GAAyB;AACjD,UAAQ,IAAI,cAAc,EAAE,UAAU,IAAI,KAAK,EAAE,UAAU,EAAE,GAAG;AAQhE,UAAQ,IAAI,kBAAkB,EAAE,UAAU,aAAa,EAAE;AACzD,UAAQ,IAAI,kBAAkB,EAAE,YAAY,EAAE;AAC9C,QAAM,KAAK,EAAE;AACb,QAAM,QAAQ,OAAO,KAAK,EAAE,EAAE;AAC9B,QAAM,UAAU,OAAO,OAAO,EAAE,EAAE,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE;AAC5D,UAAQ,IAAI,2BAA2B,OAAO,IAAI,KAAK,EAAE;AAC3D;AAOA,eAAe,+BAA+B,KAA8B;AAC1E,MAAI;AACF,WAAO,MAAME,wBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,2EAA2E;AAAA,QACzF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;;;ACvIA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,QAAAC,cAAY;AACrB;AAAA,EACE;AAAA,EACA,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EAEA,gBAAAC;AAAA,EAIA,gBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,iBAAAC;AAAA,EAMA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAuB,wBAAAC,6BAA4B;AAYnD,IAAMC,iBAAgB,iBAAiB;AAoFhC,SAAS,oBAAoBC,UAAwB;AAC1D,QAAM,OAAOA,SACV,QAAQ,MAAM,EACd,YAAY,uDAAuD;AAEtE,OACG,QAAQ,KAAK,EACb,YAAY,iDAAiD,EAC7D,eAAe,kBAAkB,cAAcC,WAAU,EACzD,OAAO,kBAAkB,+BAA+B,UAAU,EAClE;AAAA,IACC;AAAA,IACA,2BAA2BF,eAAc,KAAK,IAAI,CAAC;AAAA,IACnD;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EACC,OAAO,0BAA0B,8CAA8C,EAC/E,OAAO,wBAAwB,kCAAkC,sBAAsB,EACvF,OAAO,sBAAsB,mCAAmC,EAChE,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAA4B;AACzC,UAAM,WAAW,OAAO;AAAA,EAC1B,CAAC;AAEH,OACG,QAAQ,MAAM,EACd,YAAY,oDAAoD,EAChE;AAAA,IACC;AAAA,IACA,kCAAkCA,eAAc,KAAK,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF,EACC,OAAO,sBAAsB,iEAAiE,EAC9F,OAAO,UAAU,iCAAiC,EAClD,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,YAA6B;AAC1C,UAAM,YAAY,OAAO;AAAA,EAC3B,CAAC;AAEH,OACG,QAAQ,gBAAgB,EACxB,YAAY,4DAA4D,EACxE,OAAO,UAAU,gBAAgB,EACjC,OAAO,YAAY,iDAAiD,EACpE,OAAO,cAAc,qDAAqDG,iBAAgB,EAC1F,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,IAAY,YAA6B;AACtD,UAAM,YAAY,IAAI,OAAO;AAAA,EAC/B,CAAC;AAEH,OACG,QAAQ,+BAA+B,EACvC,YAAY,yDAAyD,EACrE,OAAO,0BAA0B,8CAA8C,EAC/E,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,aAAqB,gBAAwB,YAA+B;AACzF,UAAM,cAAc,aAAa,gBAAgB,OAAO;AAAA,EAC1D,CAAC;AAEH,OACG,QAAQ,WAAW,EACnB;AAAA,IACC;AAAA,EACF,EACC,OAAO,oBAAoB,6CAA6C,EACxE,OAAO,WAAW,kCAAkC,EACpD,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,gDAAgD,EACxE,OAAO,OAAO,YAAkC;AAC/C,UAAM,iBAAiB,OAAO;AAAA,EAChC,CAAC;AAEH,OACG,QAAQ,2BAA2B,EACnC;AAAA,IACC;AAAA,EACF,EACC,OAAO,WAAW,sCAAsC,EACxD,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,aAAqB,YAAuC;AACzE,UAAM,sBAAsB,aAAa,OAAO;AAAA,EAClD,CAAC;AAEH,OACG,QAAQ,gBAAgB,EACxB;AAAA,IACC;AAAA,EACF,EACC,OAAO,kBAAkB,iCAAiCD,WAAU,EACpE;AAAA,IACC;AAAA,IACA,uBAAuBF,eAAc,KAAK,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF,EACC,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,aAAqB,YAA6B;AAC/D,UAAM,YAAY,aAAa,OAAO;AAAA,EACxC,CAAC;AAEH,OACG,QAAQ,kBAAkB,EAC1B;AAAA,IACC;AAAA,EACF,EACC,OAAO,SAAS,iEAAiE,EACjF,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,aAAqB,YAA+B;AACjE,UAAM,cAAc,aAAa,OAAO;AAAA,EAC1C,CAAC;AAEH,OACG,QAAQ,mBAAmB,EAC3B;AAAA,IACC;AAAA,EACF,EACC,OAAO,SAAS,iEAAiE,EACjF,OAAO,UAAU,gBAAgB,EACjC,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,aAAqB,YAAgC;AAClE,UAAM,eAAe,aAAa,OAAO;AAAA,EAC3C,CAAC;AACL;AAMA,eAAsB,WAAW,SAAyB,MAAmB,CAAC,GAAkB;AAC9F,MAAI;AACF,UAAM,aAAa,SAAS,GAAG;AAAA,EACjC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,aAAa,SAAyB,KAAiC;AAC3F,MAAI,QAAQ,gBAAgB,UAAa,QAAQ,aAAa,QAAW;AACvE,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AACA,MAAI,QAAQ,aAAa,KAAK;AAC5B,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,QAAM,gBAAgB,QAAQ,UAAU;AAIxC,MAAI,QAAQ,gBAAgB,UAAa,CAAC,uBAAuB,aAAa,GAAG;AAC/E,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,KAAK;AACpE,QAAM,QAAQI,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,cACJ,QAAQ,gBAAgB,SACpB,QAAQ,cACR,QAAQ,aAAa,SACnB,MAAM,oBAAoB,QAAQ,QAAQ,IAC1C;AAER,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,SAASC,cAAa,MAAM;AAElC,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,YAAa,MAAMC,kBAAiB,OAAO,QAAQ,OAAO;AAChE,UAAMC,UAAS,MAAM,oBAAoB;AAAA,MACvC,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9D;AAAA,MACA;AAAA,MACA,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,IAClF,CAAC;AACD,uBAAmB,SAAS;AAAA,MAC1B,MAAM;AAAA,MACN,QAAQA,QAAO;AAAA,MACf,SAASA,QAAO;AAAA,MAChB,WAAWA,QAAO;AAAA,MAClB,eAAeA,QAAO;AAAA,MACtB,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9D,QAAQ;AAAA,MACR;AAAA,MACA,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,MAChF,mBAAmB,YAAY;AAAA,IACjC,CAAC;AACD;AAAA,EACF;AAEA,QAAM,WAAW,MAAMC,eAAa,KAAK;AACzC,QAAM,SAAS,MAAM,oBAAoB;AAAA,IACvC,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,QAAQ;AAAA,IACf,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EAClF,CAAC;AACD,qBAAmB,SAAS;AAAA,IAC1B,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAClB,eAAe,OAAO;AAAA,IACtB,OAAO,QAAQ;AAAA,IACf,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D,QAAQ;AAAA,IACR;AAAA,IACA,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,IAChF,mBAAmB,YAAY;AAAA,EACjC,CAAC;AACH;AAEA,SAAS,uBAAuB,QAA6B;AAC3D,SAAO,WAAW,UAAU,WAAW;AACzC;AAgBA,SAAS,mBAAmB,SAAyB,QAA4B;AAC/E,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,gBAAgB,OAAO;AAAA,QACvB,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,OAAO,OAAO,SAAS;AAAA,QACvB,QAAQ,OAAO;AAAA,QACf,aAAa,OAAO;AAAA,QACpB,cAAc,OAAO,eAAe;AAAA,QACpC,oBAAoB,OAAO;AAAA,MAC7B,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,QAAM,WAAW,eAAe,OAAO,SAAS;AAChD,QAAM,UACJ,OAAO,SAAS,WACZ,WAAW,OAAO,MAAM,sBAAsB,QAAQ,KACtD,WAAW,OAAO,MAAM,eAAe,QAAQ,KAAK,OAAO,aAAa;AAC9E,UAAQ,IAAI,OAAO;AACnB,UAAQ,IAAI,aAAa,OAAO,KAAK,EAAE;AAKvC,MAAI,OAAO,gBAAgB,QAAW;AACpC,YAAQ;AAAA,MACN,aAAa,OAAO,MAAM,iBAAiB,OAAO,UAAU,kBAAkB,OAAO,WAAW;AAAA,IAClG;AAAA,EACF,OAAO;AACL,YAAQ,IAAI,aAAa,OAAO,MAAM,EAAE;AAAA,EAC1C;AACA,UAAQ,IAAI,aAAa,OAAO,SAAS,QAAQ,EAAE;AACrD;AAMA,eAAsB,YAAY,SAA0B,MAAmB,CAAC,GAAkB;AAChG,MAAI;AACF,UAAM,cAAc,SAAS,GAAG;AAAA,EAClC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,cAAc,SAA0B,KAAiC;AAC7F,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,MAAM;AACrE,QAAM,QAAQL,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,UAAU,MAAM,gBAAgB,OAAO;AAAA,IAC3C,QAAQ,CAAC,IAAI,WAAW,cAAc,IAAI,MAAM;AAAA,EAClD,CAAC;AAKD,QAAM,kBAA2D,CAAC;AAClE,MAAI,QAAQ,oBAAoB,MAAM;AACpC,UAAM,cAAc,MAAM,yBAAyB,KAAK;AACxD,eAAW,MAAM,aAAa;AAC5B,UAAI;AACF,cAAM,EAAE,IAAI,IAAI,MAAM,gCAAgC,OAAO,EAAE;AAC/D,wBAAgB,KAAK,EAAE,KAAK,UAAU,KAAK,CAAC;AAAA,MAC9C,QAAQ;AAAA,MAGR;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,CAAC,GAAG,SAAS,GAAG,gBAAgB,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;AAClE,QAAM,gBAAgB,IAAI,IAAI,gBAAgB,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;AAE5E,QAAM,UAAU,CAAC,GAAG,QAAQ,EAAE;AAAA,IAC5B,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,KAAK,KAAK,UAAU,IAAI,KAAK,MAAM,EAAE,KAAK,KAAK,UAAU;AAAA,EAClF;AACA,QAAM,WACJ,QAAQ,WAAW,SACf,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,WAAW,QAAQ,MAAM,IAC3D;AAEN,MAAI,SAAS,WAAW,GAAG;AACzB,QAAI,QAAQ,SAAS,MAAM;AACzB,cAAQ,IAAI,IAAI;AAAA,IAClB,OAAO;AACL,cAAQ,IAAI,iBAAiB;AAAA,IAC/B;AACA;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH,SAAS,IAAI,CAAC,OAAO;AAAA,UACnB,SAAS,EAAE,KAAK,KAAK;AAAA,UACrB,OAAO,EAAE,KAAK,KAAK;AAAA,UACnB,OAAO,EAAE,KAAK,KAAK,SAAS;AAAA,UAC5B,QAAQ,EAAE,KAAK,KAAK;AAAA,UACpB,YAAY,EAAE,KAAK,KAAK;AAAA,UACxB,YAAY,EAAE,KAAK,KAAK;AAAA,UACxB,sBAAsB,EAAE,KAAK,KAAK,gBAAgB;AAAA,UAClD,UAAU,cAAc,IAAI,EAAE,KAAK,KAAK,EAAE;AAAA,QAC5C,EAAE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AACA,oBAAkB,UAAU,aAAa;AAC3C;AAEA,SAAS,kBACP,SACA,aACM;AACN,QAAM,OAAO,QAAQ,IAAI,CAAC,OAAO;AAAA,IAC/B,KAAK,YAAY,EAAE,KAAK,KAAK,EAAE;AAAA,IAC/B,QAAQ,EAAE,KAAK,KAAK;AAAA,IACpB,WAAW,EAAE,KAAK,KAAK;AAAA,IACvB,OAAO,EAAE,KAAK,KAAK,SAAS;AAAA;AAAA;AAAA,IAG5B,OAAO,YAAY,IAAI,EAAE,KAAK,KAAK,EAAE,IAAI,cAAc,EAAE,KAAK,KAAK,KAAK,KAAK,EAAE,KAAK,KAAK;AAAA,IACzF,aAAa,OAAO,EAAE,KAAK,KAAK,gBAAgB,MAAM;AAAA,EACxD,EAAE;AACF,QAAM,SAAS;AAAA,IACb,KAAKK;AAAA,MACH,KAAK,IAAI,CAAC,MAAM,EAAE,GAAG;AAAA,MACrB,WAAW;AAAA,IACb;AAAA,IACA,QAAQA;AAAA,MACN,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACxB,SAAS;AAAA,IACX;AAAA,IACA,WAAWA;AAAA,MACT,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS;AAAA,MAC3B,aAAa;AAAA,IACf;AAAA,IACA,aAAaA;AAAA,MACX,KAAK,IAAI,CAAC,MAAM,EAAE,WAAW;AAAA,MAC7B,QAAQ;AAAA,IACV;AAAA,IACA,OAAOA;AAAA,MACL,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,MACvB,QAAQ;AAAA,IACV;AAAA,EACF;AACA,UAAQ;AAAA,IACN,GAAGC,KAAI,YAAY,OAAO,GAAG,CAAC,KAAKA,KAAI,UAAU,OAAO,MAAM,CAAC,KAAKA,KAAI,cAAc,OAAO,SAAS,CAAC,KAAKA,KAAI,SAAS,OAAO,WAAW,CAAC,KAAKA,KAAI,SAAS,OAAO,KAAK,CAAC;AAAA,EAC7K;AACA,aAAW,KAAK,MAAM;AACpB,YAAQ;AAAA,MACN,GAAGA,KAAI,EAAE,KAAK,OAAO,GAAG,CAAC,KAAKA,KAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,KAAKA,KAAI,EAAE,WAAW,OAAO,SAAS,CAAC,KAAKA,KAAI,EAAE,aAAa,OAAO,WAAW,CAAC,KAAKA,KAAI,EAAE,OAAO,OAAO,KAAK,CAAC,KAAK,EAAE,KAAK;AAAA,IACzL;AAAA,EACF;AACF;AAMA,eAAsB,YACpB,SACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,cAAc,SAAS,SAAS,GAAG;AAAA,EAC3C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,cACpB,SACA,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,MAAM;AACrE,QAAM,QAAQP,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,SAAS,MAAMO,eAAc,OAAO,SAAS,EAAE,iBAAiB,KAAK,CAAC;AAC5E,QAAM,EAAE,KAAK,SAAS,IAAI,MAAM,gCAAgC,OAAO,MAAM;AAK7E,QAAM,WAAW,MAAMC,oBAAmB,OAAO,EAAE,KAAK,oBAAI,KAAK,EAAE,CAAC;AACpE,QAAM,SAAkB,CAAC;AACzB,QAAM,mBAAmB,IAAI,IAAY,IAAI,KAAK,KAAK,eAAe;AAItE,aAAW,KAAK,UAAU;AACxB,UAAM,aAAaC,OAAK,MAAM,UAAU,EAAE,SAAS;AACnD,QAAI;AACF,uBAAiB,MAAMC,cAAa,YAAY;AAAA,QAC9C,WAAW,CAAC,MAAM,mBAAmB,GAAG,EAAE,SAAS;AAAA,MACrD,CAAC,GAAG;AACF,aACG,GAAG,SAAS,kBACX,GAAG,SAAS,yBACZ,GAAG,SAAS,qBACZ,GAAG,SAAS,4BACZ,GAAG,SAAS,kBACZ,GAAG,SAAS,oBACd,GAAG,YAAY,QACf;AACA,iBAAO,KAAK,EAAE;AACd,2BAAiB,IAAI,EAAE,SAAS;AAAA,QAClC;AAAA,MACF;AAAA,IACF,SAAS,OAAgB;AAIvB,YAAM,QAAQ,eAAe,EAAE,SAAS;AACxC,YAAM,SAAS,iBAAiB,QAAQ,KAAK,MAAM,OAAO,KAAK;AAC/D,cAAQ,MAAM,2CAA2C,KAAK,GAAG,MAAM,EAAE;AAAA,IAC3E;AAAA,EACF;AACA,SAAO,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,WAAW,IAAI,KAAK,MAAM,EAAE,WAAW,CAAC;AAE3E,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK;AAAA,QACH;AAAA,UACE,MAAM,IAAI,KAAK;AAAA,UACf,MAAM,IAAI;AAAA,UACV,iBAAiB,CAAC,GAAG,gBAAgB;AAAA,UACrC;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,oBAAkB,KAAK,CAAC,GAAG,gBAAgB,GAAG,QAAQ,UAAU,SAAS,QAAQ;AACnF;AAEA,SAAS,kBACP,KACA,gBACA,QACA,gBACA,SACA,UACM;AACN,QAAM,IAAI,IAAI,KAAK;AACnB,QAAM,cAAc,WAAW,gBAAgB;AAC/C,UAAQ,IAAI,SAAS,EAAE,EAAE,GAAG,WAAW,EAAE;AACzC,UAAQ,IAAI,kBAAkB,EAAE,KAAK,EAAE;AACvC,UAAQ,IAAI,kBAAkB,EAAE,MAAM,EAAE;AACxC,UAAQ,IAAI,kBAAkB,EAAE,SAAS,QAAQ,EAAE;AACnD,UAAQ,IAAI,kBAAkB,EAAE,UAAU,EAAE;AAC5C,UAAQ,IAAI,kBAAkB,EAAE,UAAU,EAAE;AAC5C,UAAQ,IAAI,kBAAkB,EAAE,YAAY,EAAE;AAC9C,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,oBAAoB,eAAe,MAAM,IAAI;AACzD,QAAM,mBAAmB,IAAI;AAAA,IAC3B,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,QAAQ,MAAM,CAAC;AAAA,EACnE;AACA,aAAW,OAAO,gBAAgB;AAChC,UAAM,SAAS,iBAAiB,IAAI,GAAG,KAAK;AAC5C,YAAQ,IAAI,KAAK,GAAG,MAAM,MAAM,GAAG;AAAA,EACrC;AACA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,cAAc;AAC1B,MAAI,IAAI,KAAK,WAAW,GAAG;AACzB,YAAQ,IAAI,kBAAkB;AAAA,EAChC,OAAO;AACL,YAAQ,IAAI,IAAI,IAAI;AAAA,EACtB;AACA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,WAAW,OAAO,MAAM,QAAQ;AAC5C,MAAI,OAAO,WAAW,EAAG;AACzB,QAAM,UAAU,QAAQ,WAAW,QAAQ,QAAQ,SAAS;AAC5D,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,QAAQ,UAAU,SAAS,OAAO,MAAM,CAAC,IAAI;AACnD,QAAM,UAAU,UAAU,gBAAgB,QAAQ,MAAM,MAAM;AAC9D,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,OAAO;AACnB,QAAM,UAAU,UAAU,OAAO;AACjC,aAAW,MAAM,OAAO;AACtB,YAAQ,IAAI,KAAK,gBAAgB,EAAE,CAAC,EAAE;AACtC,QAAI,WAAW,GAAG,SAAS,mBAAmB;AAC5C,iBAAW,QAAQ,4BAA4B,EAAE,GAAG;AAClD,gBAAQ,IAAI,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,IAAmB;AAC1C,MAAI,GAAG,SAAS,gBAAgB;AAC9B,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,+BAA+B,GAAG,KAAK;AAAA,EAC/E;AACA,MAAI,GAAG,SAAS,uBAAuB;AACrC,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,+BAA+B,GAAG,IAAI,OAAO,GAAG,EAAE;AAAA,EAC1F;AACA,MAAI,GAAG,SAAS,mBAAmB;AACjC,UAAM,gBACH,GAAG,+BAA+B,OAAO,IAAI,KAAK,GAAG,wBAAwB;AAChF,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,+BAA+B,YAAY,cAAc,iBAAiB,IAAI,KAAK,GAAG;AAAA,EAC9H;AACA,MAAI,GAAG,SAAS,0BAA0B;AACxC,UAAM,QAAQ,GAAG,sBAAsB;AACvC,UAAM,UAAU,GAAG,wBAAwB;AAC3C,UAAM,YAAY,GAAG,gBAAgB,SAAY,WAAW,GAAG,WAAW,KAAK;AAC/E,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,gCAAgC,KAAK,OAAO,OAAO,GAAG,SAAS;AAAA,EACvG;AACA,MAAI,GAAG,SAAS,gBAAgB;AAC9B,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,+BAA+B,GAAG,KAAK;AAAA,EAC/E;AACA,MAAI,GAAG,SAAS,iBAAiB;AAC/B,WAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,+BAA+B,GAAG,KAAK;AAAA,EAC/E;AACA,SAAO,GAAG,GAAG,WAAW,KAAK,GAAG,MAAM,MAAM,GAAG,IAAI;AACrD;AAEA,SAAS,4BAA4B,IAAmC;AACtE,QAAM,QAAkB,CAAC;AACzB,MAAI,GAAG,+BAA+B,MAAM;AAC1C,UAAM,KAAK,wCAAwC,GAAG,0BAA0B,EAAE;AAAA,EACpF;AACA,MAAI,GAAG,mCAAmC,MAAM;AAC9C,UAAM,KAAK,yCAAyC,GAAG,8BAA8B,EAAE;AAAA,EACzF;AACA,MAAI,GAAG,wBAAwB,SAAS,GAAG;AACzC,UAAM,KAAK,gCAAgC;AAC3C,eAAW,OAAO,GAAG,yBAAyB;AAC5C,YAAM,KAAK,aAAa,GAAG,EAAE;AAAA,IAC/B;AAAA,EACF;AACA,SAAO;AACT;AAMA,eAAsB,cACpB,aACA,gBACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,gBAAgB,aAAa,gBAAgB,SAAS,GAAG;AAAA,EACjE,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,gBACpB,aACA,gBACA,SACA,KACe;AACf,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACA,QAAM,YAAY,0BAA0B,cAAc;AAE1D,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,QAAQ;AACvE,QAAM,QAAQX,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,SAAU,MAAMO,eAAc,OAAO,WAAW;AACtD,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AAEnC,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,YAAa,MAAML,kBAAiB,OAAO,QAAQ,OAAO;AAChE,UAAMC,UAAS,MAAM,0BAA0B;AAAA,MAC7C,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,0BAAsB,SAAS;AAAA,MAC7B,MAAM;AAAA,MACN,QAAQA,QAAO;AAAA,MACf,SAASA,QAAO;AAAA,MAChB,WAAWA,QAAO;AAAA,MAClB,eAAeA,QAAO;AAAA,MACtB,gBAAgBA,QAAO;AAAA,MACvB,WAAWA,QAAO;AAAA,IACpB,CAAC;AACD;AAAA,EACF;AAEA,QAAM,WAAW,MAAMC,eAAa,KAAK;AACzC,QAAM,SAAS,MAAM,0BAA0B;AAAA,IAC7C,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AACD,wBAAsB,SAAS;AAAA,IAC7B,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAClB,eAAe,OAAO;AAAA,IACtB,gBAAgB,OAAO;AAAA,IACvB,WAAW,OAAO;AAAA,EACpB,CAAC;AACH;AAYA,SAAS,sBAAsB,SAA4B,QAA+B;AACxF,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,gBAAgB,OAAO;AAAA,QACvB,MAAM,OAAO;AAAA,QACb,iBAAiB,OAAO;AAAA,QACxB,YAAY,OAAO;AAAA,MACrB,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,QAAM,MAAM,eAAe,OAAO,SAAS;AAC3C,UAAQ;AAAA,IACN,WAAW,OAAO,MAAM,YAAY,OAAO,cAAc,OAAO,OAAO,SAAS,gBAAgB,GAAG;AAAA,EACrG;AACF;AAMA,eAAsB,iBACpB,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,mBAAmB,SAAS,GAAG;AAAA,EACvC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,mBACpB,SACA,KACe;AACf,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,WAAW;AAC1E,QAAM,QAAQL,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMI,eAAa,KAAK;AACzC,QAAM,cAAc,IAAI,gBAAgB,MAAY,oBAAI,KAAK;AAC7D,QAAM,QAAQ,QAAQ,UAAU;AAChC,QAAM,UAAU,UAAU,OAAO;AACjC,QAAM,OAAO,QAAQ,SAAS;AAE9B,MAAI,QAAQ,SAAS,QAAW;AAC9B,UAAM,SAAU,MAAMG,eAAc,OAAO,QAAQ,IAAI;AACvD,UAAM,SAAS,MAAM,cAAc,OAAO,UAAU;AAAA,MAClD;AAAA,MACA,YAAY,YAAY,EAAE,YAAY;AAAA,MACtC,kBAAkB;AAAA,MAClB;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AACD,QAAI,MAAM;AACR,yBAAmB,EAAE,QAAQ,CAAC,OAAO,SAAS,GAAG,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAC;AAAA,IAClF,OAAO;AACL,YAAM,yBAAyB,QAAQ,OAAO,EAAE,OAAO,QAAQ,CAAC;AAAA,IAClE;AACA;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,kBAAkB,OAAO,UAAU;AAAA,IACnD,YAAY,MAAM,YAAY,EAAE,YAAY;AAAA,IAC5C,kBAAkB;AAAA,IAClB;AAAA,EACF,CAAC;AACD,MAAI,MAAM;AACR,uBAAmB;AAAA,MACjB,QAAQ,CAAC;AAAA,MACT,SAAS,IAAI;AAAA,MACb,SAAS,IAAI;AAAA,MACb,QAAQ,IAAI;AAAA,IACd,CAAC;AAAA,EACH,OAAO;AACL,0BAAsB,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,EAAE,OAAO,QAAQ,CAAC;AAAA,EAChF;AACA,MAAI,IAAI,OAAO,SAAS,GAAG;AACzB,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,SAAS,mBAAmB,OAKnB;AACP,UAAQ;AAAA,IACN,KAAK;AAAA,MACH;AAAA,QACE,SAAS,MAAM;AAAA,QACf,SAAS,MAAM;AAAA,QACf,YAAY,MAAM,QAAQ,IAAI,CAAC,OAAO;AAAA,UACpC,SAAS,EAAE;AAAA,UACX,4BAA4B,EAAE;AAAA,UAC9B,gCACE,EAAE,2BAA2B,QAAQ,EAAE,qBAAqB,OACxD,EAAE,iBAAiB,YACnB;AAAA,UACN,yBAAyB,EAAE;AAAA,UAC3B,sBAAsB,EAAE,kBAAkB,aAAa;AAAA,UACvD,UAAU,EAAE,kBAAkB,WAAW;AAAA,QAC3C,EAAE;AAAA,QACF,QAAQ,MAAM,OAAO,IAAI,CAAC,OAAO;AAAA,UAC/B,SAAS,EAAE;AAAA,UACX,aAAa,EAAE;AAAA,UACf,OAAO,EAAE;AAAA,QACX,EAAE;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,yBACb,QACA,OACA,SACe;AACf,MAAI,OAAO,OAAO;AAKhB,QAAI,eAAe;AACnB,QAAI,cAAc;AAClB,QAAI;AACF,YAAM,MAAM,MAAM,aAAa,OAAO,OAAO,MAAM;AACnD,qBAAe;AACf,oBAAc,IAAI,KAAK,KAAK,gBAAgB;AAAA,IAC9C,QAAQ;AAAA,IAGR;AACA,YAAQ;AAAA,MACN,GAAG,OAAO,MAAM,qBAAqB,YAAY,yBAAyB,WAAW;AAAA,IACvF;AACA;AAAA,EACF;AACA,MAAI,QAAQ,OAAO;AACjB,UAAM,cACJ,OAAO,qBAAqB,OACxB,gBAAgB,eAAe,OAAO,iBAAiB,SAAS,CAAC,MACjE;AACN,YAAQ,IAAI,cAAc,OAAO,MAAM,KAAK,yBAAyB,MAAM,CAAC,GAAG,WAAW,GAAG;AAC7F;AAAA,EACF;AACA,QAAM,UAAU,sBAAsB,QAAQ,QAAQ,QAAQ,OAAO;AACrE,UAAQ,IAAI,6BAA6B,OAAO,MAAM,KAAK,OAAO,EAAE;AACpE,UAAQ,IAAI,kFAAkF;AAC9F,UAAQ,IAAI,+BAA+B;AAC7C;AAEA,SAAS,sBACP,SACA,QACA,SACA,SACM;AACN,MAAI,QAAQ,WAAW,KAAK,OAAO,WAAW,GAAG;AAC/C,YAAQ,IAAI,WAAW,OAAO,kCAAkC;AAChE;AAAA,EACF;AAEA,MAAI,kBAAkB;AACtB,aAAW,KAAK,SAAS;AACvB,uBAAmB,EAAE,qBAAqB,UAAU,EAAE,2BAA2B,OAAO,IAAI;AAAA,EAC9F;AAEA,MAAI,QAAQ,OAAO;AACjB,eAAW,KAAK,SAAS;AACvB,YAAM,cACJ,EAAE,qBAAqB,OACnB,gBAAgB,eAAe,EAAE,iBAAiB,SAAS,CAAC,MAC5D;AACN,cAAQ,IAAI,cAAc,EAAE,MAAM,KAAK,yBAAyB,CAAC,CAAC,GAAG,WAAW,EAAE;AAAA,IACpF;AACA,eAAW,KAAK,QAAQ;AACtB,YAAM,QAAQ,EAAE,SAAS;AACzB,cAAQ;AAAA,QACN,uBAAuB,EAAE,MAAM,KAAK,EAAE,UAAU,YAAY,KAAK;AAAA,MACnE;AAAA,IACF;AACA,UAAM,kBAAkB,QAAQ;AAChC,UAAM,iBAAiB;AACvB,UAAM,iBAAiB,cAAc,eAAe,QAAQ,oBAAoB,IAAI,KAAK,GAAG,KAAK,cAAc,cAAc,mBAAmB,IAAI,KAAK,GAAG;AAC5J,UAAM,aACJ,OAAO,WAAW,IAAI,KAAK,KAAK,OAAO,MAAM,QAAQ,OAAO,WAAW,IAAI,KAAK,GAAG;AACrF,YAAQ,IAAI,WAAW,OAAO,WAAW,cAAc,GAAG,UAAU,GAAG;AACvE,QAAI,OAAO,SAAS,GAAG;AACrB,cAAQ,MAAM,eAAe;AAAA,IAC/B;AACA;AAAA,EACF;AAGA,aAAW,KAAK,SAAS;AACvB,UAAM,UAAU,sBAAsB,GAAG,OAAO,QAAQ,OAAO;AAC/D,YAAQ,IAAI,6BAA6B,EAAE,MAAM,KAAK,OAAO,EAAE;AAAA,EACjE;AACA,UAAQ;AAAA,IACN,WAAW,OAAO,2BAA2B,QAAQ,MAAM,QAAQ,QAAQ,WAAW,IAAI,KAAK,GAAG,KAAK,eAAe,cAAc,oBAAoB,IAAI,KAAK,GAAG;AAAA,EACtK;AACA,UAAQ,IAAI,kFAAkF;AAC9F,UAAQ,IAAI,+BAA+B;AAC7C;AAEA,SAAS,yBAAyB,GAA4B;AAC5D,QAAM,cAAc,EAAE,qBAAqB;AAC3C,QAAM,QAAkB,CAAC;AACzB,MAAI,EAAE,2BAA2B,MAAM;AACrC,UAAM,KAAK,6BAA6B;AAAA,EAC1C;AACA,MAAI,cAAc,GAAG;AACnB,UAAM,KAAK,WAAW,WAAW,wBAAwB,gBAAgB,IAAI,MAAM,KAAK,EAAE;AAAA,EAC5F;AACA,SAAO,MAAM,KAAK,KAAK;AACzB;AAEA,SAAS,sBACP,GACA,OACA,SACQ;AACR,QAAM,UAAU,UAAU,UAAU;AACpC,QAAM,QAAkB,CAAC;AACzB,MAAI,EAAE,2BAA2B,MAAM;AACrC,UAAM;AAAA,MACJ,UACI,6BAA6B,0BAA0B,EAAE,wBAAwB,SAAS,KAAK,CAAC,KAChG;AAAA,IACN;AAAA,EACF;AACA,QAAM,cAAc,EAAE,qBAAqB;AAC3C,MAAI,cAAc,GAAG;AACnB,QAAI,SAAS;AACX,YAAM,MAAM,EAAE,qBACX,IAAI,CAAC,OAAO,0BAA0B,IAAI,SAAS,KAAK,CAAC,EACzD,KAAK,IAAI;AACZ,YAAM,KAAK,GAAG,WAAW,wBAAwB,gBAAgB,IAAI,MAAM,KAAK,KAAK,GAAG,GAAG;AAAA,IAC7F,OAAO;AACL,YAAM,KAAK,GAAG,WAAW,wBAAwB,gBAAgB,IAAI,MAAM,KAAK,EAAE;AAAA,IACpF;AAAA,EACF;AACA,SAAO,MAAM,KAAK,KAAK;AACzB;AAEA,SAAS,0BAA0B,IAAY,SAAkB,OAA+B;AAC9F,MAAI,WAAW,UAAU,OAAQ,QAAO;AACxC,SAAO,OAAO,eAAe,EAAE,CAAC;AAClC;AAMA,eAAsB,sBACpB,aACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,wBAAwB,aAAa,SAAS,GAAG;AAAA,EACzD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,wBACpB,aACA,SACA,KACe;AACf,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,iBAAiB;AAChF,QAAM,QAAQR,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMI,eAAa,KAAK;AACzC,QAAM,SAAU,MAAMG,eAAc,OAAO,WAAW;AACtD,QAAM,cAAc,IAAI,gBAAgB,MAAY,oBAAI,KAAK;AAC7D,QAAM,QAAQ,QAAQ,UAAU;AAEhC,QAAM,SAAS,MAAM,0BAA0B,OAAO,UAAU;AAAA,IAC9D;AAAA,IACA,YAAY,YAAY,EAAE,YAAY;AAAA,IACtC,kBAAkB;AAAA,IAClB;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,4BAAwB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;AAClD;AAAA,EACF;AACA,0BAAwB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;AACpD;AAEA,SAAS,wBAAwB,QAA8B,OAAkC;AAC/F,UAAQ;AAAA,IACN,KAAK;AAAA,MACH;AAAA,QACE,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,SAAS,MAAM;AAAA,QACf,uBAAuB,OAAO;AAAA,QAC9B,yBAAyB,OAAO;AAAA,QAChC,aAAa,OAAO;AAAA,QACpB,oBAAoB,OAAO,gBAAgB,aAAa;AAAA,QACxD,UAAU,OAAO,gBAAgB,WAAW;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,QAA8B,OAAkC;AAC/F,MAAI,OAAO,OAAO;AAChB,YAAQ;AAAA,MACN,GAAG,OAAO,MAAM,oCAAoC,OAAO,UAAU,QAAQ,OAAO,eAAe,IAAI,MAAM,KAAK;AAAA,IACpH;AACA;AAAA,EACF;AACA,QAAM,aAAa,OAAO,oBAAoB;AAC9C,QAAM,eAAe,OAAO,sBAAsB;AAClD,QAAM,eAAyB,CAAC;AAChC,MAAI,aAAa,GAAG;AAClB,iBAAa,KAAK,IAAI,UAAU,QAAQ;AAAA,EAC1C;AACA,MAAI,eAAe,GAAG;AACpB,iBAAa,KAAK,IAAI,YAAY,UAAU;AAAA,EAC9C;AACA,QAAM,UAAU,aAAa,KAAK,IAAI;AACtC,MAAI,MAAM,QAAQ;AAChB,YAAQ,IAAI,2BAA2B,OAAO,MAAM,qBAAqB,OAAO,GAAG;AACnF,YAAQ,IAAI,+BAA+B;AAC3C;AAAA,EACF;AACA,QAAM,MACJ,OAAO,mBAAmB,OACtB,gBAAgB,eAAe,OAAO,eAAe,SAAS,CAAC,MAC/D;AACN,UAAQ;AAAA,IACN,aAAa,OAAO,MAAM,qBAAqB,OAAO,GAAG,GAAG,iBAAiB,OAAO,UAAU;AAAA,EAChG;AACF;AAMA,eAAsB,YACpB,aACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,cAAc,aAAa,SAAS,GAAG;AAAA,EAC/C,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,cACpB,aACA,SACA,KACe;AACf,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACA,MAAI,QAAQ,UAAU,UAAa,QAAQ,WAAW,QAAW;AAC/D,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,MAAM;AACrE,QAAM,QAAQR,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMI,eAAa,KAAK;AACzC,QAAM,SAAU,MAAMG,eAAc,OAAO,WAAW;AACtD,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AAEnC,QAAM,SAAS,MAAM,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D,GAAI,QAAQ,WAAW,SAAY,EAAE,WAAW,QAAQ,OAAO,IAAI,CAAC;AAAA,EACtE,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,eAAe,OAAO;AAAA,QACtB,gBAAgB,OAAO;AAAA,QACvB,iBAAiB,OAAO;AAAA,QACxB,YAAY,OAAO;AAAA,QACnB,0BAA0B,OAAO,qBAAqB,aAAa;AAAA,QACnE,wBAAwB,OAAO,qBAAqB,WAAW;AAAA,MACjE,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,MAAI,OAAO,eAAe;AACxB,UAAM,MACJ,OAAO,wBAAwB,OAC3B,gBAAgB,eAAe,OAAO,oBAAoB,SAAS,CAAC,MACpE;AACN,YAAQ;AAAA,MACN,WAAW,OAAO,MAAM,YAAY,OAAO,cAAc,OAAO,OAAO,SAAS,GAAG,GAAG;AAAA,IACxF;AAAA,EACF;AACA,MAAI,OAAO,cAAc;AACvB,YAAQ,IAAI,WAAW,OAAO,MAAM,SAAS;AAAA,EAC/C;AACA,MAAI,CAAC,OAAO,iBAAiB,CAAC,OAAO,cAAc;AAGjD,YAAQ,IAAI,kBAAkB,OAAO,MAAM,GAAG;AAAA,EAChD;AACF;AAEA,eAAsB,cACpB,aACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,gBAAgB,aAAa,SAAS,GAAG;AAAA,EACjD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,gBACpB,aACA,SACA,KACe;AACf,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,QAAQ;AACvE,QAAM,QAAQR,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMI,eAAa,KAAK;AACzC,QAAM,SAAU,MAAMG,eAAc,OAAO,WAAW;AAEtD,MAAI,QAAQ,QAAQ,MAAM;AACxB,UAAM,yBAAyB,UAAU,MAAM;AAAA,EACjD;AAEA,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,SAAS,MAAM,WAAW;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,MACnB,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,UAAQ;AAAA,IACN,WAAW,OAAO,MAAM,MAAM,OAAO,KAAK,wBAAwB,eAAe,OAAO,SAAS,CAAC;AAAA,EACpG;AACF;AAEA,eAAsB,eACpB,aACA,SACA,MAAmB,CAAC,GACL;AACf,MAAI;AACF,UAAM,iBAAiB,aAAa,SAAS,GAAG;AAAA,EAClD,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,GAAG,aAAa,iBAAiB,CAAC;AACpF,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAsB,iBACpB,aACA,SACA,KACe;AACf,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI,MAAM,kBAAkB;AAAA,EACpC;AACA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,6BAA6B,KAAK,SAAS;AACxE,QAAM,QAAQR,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAC3C,QAAM,WAAW,MAAMI,eAAa,KAAK;AACzC,QAAM,SAAU,MAAMG,eAAc,OAAO,WAAW;AAEtD,MAAI,QAAQ,QAAQ,MAAM;AACxB,UAAM,yBAAyB,WAAW,MAAM;AAAA,EAClD;AAEA,QAAM,MAAM,IAAI,gBAAgB,SAAY,IAAI,YAAY,IAAI,oBAAI,KAAK;AACzE,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ;AAAA,MACN,KAAK,UAAU;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,MACnB,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,UAAQ;AAAA,IACN,YAAY,OAAO,MAAM,MAAM,OAAO,KAAK,wBAAwB,eAAe,OAAO,SAAS,CAAC;AAAA,EACrG;AACF;AAQA,eAAe,yBACb,QACA,QACe;AACf,MAAI,QAAQ,MAAM,UAAU,MAAM;AAChC,UAAM,IAAI,MAAM,eAAe,MAAM,sDAAsD;AAAA,EAC7F;AACA,QAAM,OAAO,WAAW,WAAW,WAAW;AAC9C,UAAQ,OAAO,MAAM,GAAG,IAAI,WAAW,MAAM,YAAY;AACzD,QAAM,SAAS,MAAM,wBAAwB;AAC7C,QAAM,aAAa,OAAO,KAAK,EAAE,YAAY;AAC7C,MAAI,eAAe,OAAO,eAAe,OAAO;AAC9C,UAAM,IAAI,MAAM,GAAG,IAAI,mBAAmB;AAAA,EAC5C;AACF;AAEA,eAAe,0BAA2C;AACxD,QAAM,EAAE,iBAAAI,iBAAgB,IAAI,MAAM,OAAO,mBAAwB;AACjE,QAAM,KAAKA,iBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,SAAS,EAAE;AACjC,WAAO;AAAA,EACT,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAMA,SAASd,YAAW,KAAqB;AACvC,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIe,sBAAqB,yBAAyB;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,WAAW,KAAqB;AACvC,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIA,sBAAqB,yBAAyB;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,KAAyB;AACvD,QAAM,SAAS,iBAAiB,UAAU,GAAG;AAC7C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAIA;AAAA,MACR,uCAAuCjB,eAAc,KAAK,IAAI,CAAC;AAAA,IACjE;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAEA,IAAM,cAAc;AAEpB,SAAS,wBAAwB,KAAqB;AAKpD,MAAI,CAAC,YAAY,KAAK,GAAG,KAAK,OAAO,MAAM,KAAK,MAAM,GAAG,CAAC,GAAG;AAC3D,UAAM,IAAIiB;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,KAAyB;AACtD,QAAM,SAAS,iBAAiB,UAAU,GAAG;AAC7C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAIA;AAAA,MACR,wBAAwB,GAAG,mBAAmBjB,eAAc,KAAK,IAAI,CAAC;AAAA,IACxE;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,0BAA0B,KAAyB;AAC1D,QAAM,SAAS,iBAAiB,UAAU,GAAG;AAC7C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,wBAAwB,GAAG,mBAAmBA,eAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EAC1F;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,uBAAuB,KAAqB;AACnD,MAAI,IAAI,WAAW,GAAG;AACpB,UAAM,IAAIiB,sBAAqB,+BAA+B;AAAA,EAChE;AACA,SAAO;AACT;AAEA,SAASd,kBAAiB,KAAqB;AAC7C,QAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,OAAO,CAAC,GAAG;AAC7D,UAAM,IAAIc,sBAAqB,mBAAmB,GAAG,EAAE;AAAA,EACzD;AACA,SAAO;AACT;AAMA,eAAe,oBAAoB,MAA+B;AAChE,MAAI;AACF,WAAO,MAAMC,UAAS,MAAM,MAAM;AAAA,EACpC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,gCAAgC,EAAE,OAAO,MAAM,CAAC;AAAA,IAClE;AACA,QAAIA,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oCAAoC,EAAE,OAAO,MAAM,CAAC;AAAA,IACtE;AACA,UAAM,IAAI,MAAM,qCAAqC,EAAE,OAAO,MAAM,CAAC;AAAA,EACvE;AACF;AAEA,eAAe,6BACb,KACA,QAUiB;AACjB,MAAI;AACF,WAAO,MAAMC,wBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI;AAAA,QACR,uEAAuE,MAAM;AAAA,QAC7E,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAef,6BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMgB,sBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIF,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;AAWA,IAAM,gCAAiD;AAAA,EACrD,OAAO,CAAC,UAAU,iBAAiB;AAAA,EACnC,iBAAiB,CAAC,UAAU;AAC1B,UAAM,IAAI;AACV,UAAM,MAAM,eAAe,EAAE,SAAS;AACtC,UAAM,MAAM,YAAY,EAAE,MAAM;AAChC,UAAM,iBAAiB,uBAAuB,EAAE,OAAO,KAAK,GAAG;AAC/D,UAAM,UAAU,4BAA4B,EAAE,KAAK;AACnD,UAAM,OACJ,EAAE,UAAU,yBACR,kCACA,EAAE,UAAU,+BACV,wCACA;AACR,WAAO;AAAA,MACL,YAAY,EAAE,OAAO,eAAe,GAAG,KAAK,cAAc;AAAA,MAC1D,YAAY,OAAO,iCAAiC,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;AAEA,IAAM,mBAA+C;AAAA,EACnD;AAAA,EACA;AACF;AAEA,SAAS,uBACP,OACA,KACA,KACQ;AACR,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,qBAAqB,GAAG;AAAA,IACjC,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,2BAA2B,GAAG;AAAA,IACvC,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,GAAG;AAAA,EACtB;AACF;AAEA,SAAS,4BAA4B,OAAkD;AACrF,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAASR,KAAI,OAAe,OAAuB;AACjD,SAAO,MAAM,UAAU,QAAQ,QAAQ,QAAQ,IAAI,OAAO,QAAQ,MAAM,MAAM;AAChF;AAEA,SAASD,QAAO,QAA2B,OAAuB;AAChE,MAAI,MAAM;AACV,aAAW,KAAK,OAAQ,KAAI,EAAE,SAAS,IAAK,OAAM,EAAE;AACpD,SAAO;AACT;;;ACnnDA;AAAA,EACE,uBAAAY;AAAA,EACA,cAAAC;AAAA,EAEA,wBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,yBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,OACK;AA0BA,SAAS,sBAAsBC,UAAwB;AAC5D,EAAAA,SACG,QAAQ,QAAQ,EAChB,YAAY,2EAA2E,EACvF,OAAO,kBAAkB,qDAAqD,EAC9E,OAAO,SAAS,8DAA8D,EAC9E,OAAO,UAAU,6BAA6B,EAC9C,OAAO,iBAAiB,mBAAmB,EAC3C,OAAO,OAAO,SAAwB;AACrC,UAAM,UAAU,IAAI;AAAA,EACtB,CAAC;AACL;AAEA,eAAsB,UAAU,SAAwB,MAAqB,CAAC,GAAkB;AAC9F,MAAI;AACF,UAAM,YAAY,SAAS,GAAG;AAAA,EAChC,SAAS,OAAgB;AACvB,mBAAe,OAAO,EAAE,SAAS,UAAU,OAAO,EAAE,CAAC;AACrD,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,eAAe,YAAY,SAAwB,KAAmC;AACpF,MAAI,QAAQ,YAAY,UAAa,QAAQ,QAAQ,MAAM;AACzD,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,MAAM,IAAI,OAAO,QAAQ,IAAI;AACnC,QAAM,iBAAiB,MAAM,+BAA+B,GAAG;AAC/D,QAAM,QAAQC,aAAW,cAAc;AACvC,QAAMC,6BAA2B,MAAM,IAAI;AAE3C,QAAM,aACJ,QAAQ,YAAY,SAChB,CAAC,MAAMC,kBAAiB,OAAO,QAAQ,OAAO,CAAC,IAC/C,MAAMC,sBAAqB,KAAK;AAEtC,QAAM,OAAoB,CAAC;AAC3B,aAAW,aAAa,YAAY;AAClC,UAAM,UAAU,MAAM,kBAAkB,OAAO,SAAS;AACxD,SAAK,KAAK;AAAA,MACR,YAAY;AAAA,MACZ,QAAQ,QAAQ;AAAA,MAChB,aAAa,QAAQ;AAAA,MACrB,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,MACjE,GAAI,QAAQ,SAAS,SAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC7D,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAElE,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,EAC3C,OAAO;AACL,eAAW,OAAO,MAAM;AACtB,cAAQ,IAAI,GAAG,IAAI,UAAU,KAAK,cAAc,GAAG,CAAC,EAAE;AAAA,IACxD;AACA,UAAM,QAAQ,CAAC,WACb,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC1C,YAAQ;AAAA,MACN,aAAa,KAAK,MAAM,iBAAY,MAAM,UAAU,CAAC,cAChD,MAAM,WAAW,CAAC,eAAe,MAAM,OAAO,CAAC,WAC/C,MAAM,YAAY,CAAC,gBAAgB,MAAM,aAAa,CAAC,iBACvD,aAAa;AAAA,IACpB;AAAA,EACF;AAIA,MAAI,gBAAgB,GAAG;AACrB,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,SAAS,cAAc,KAAwB;AAC7C,UAAQ,IAAI,QAAQ;AAAA,IAClB,KAAK;AACH,aAAO,aAAa,IAAI,WAAW;AAAA,IACrC,KAAK;AACH,aAAO,IAAI,SAAS,SAChB,aAAa,IAAI,MAAM,YAAY,IAAI,IAAI,MAC3C,aAAa,IAAI,MAAM;AAAA,IAC7B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,gBAAgB,IAAI,WAAW;AAAA,IACxC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,eAAe,+BAA+B,KAA8B;AAC1E,MAAI;AACF,WAAO,MAAMC,wBAAsB,GAAG;AAAA,EACxC,SAAS,OAAgB;AACvB,QAAI,iBAAiB,SAAS,MAAM,YAAY,wBAAwB;AACtE,YAAM,IAAI,MAAM,2EAA2E;AAAA,QACzF,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAeH,6BAA2B,WAAkC;AAC1E,MAAI;AACF,UAAMI,sBAAoB,SAAS;AAAA,EACrC,SAAS,OAAgB;AACvB,QAAIC,gBAAc,OAAO,QAAQ,GAAG;AAClC,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AACF;;;ACtJA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,YAAAC,WAAU,WAAAC,iBAAe;AAClC;AAAA,EACE,uBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,yBAAAC;AAAA,OACK;AACP,SAAuB,wBAAAC,6BAA4B;;;ACVnD,SAAS,gBAAgB;AACzB,SAAS,SAAAC,QAAO,YAAAC,iBAAgB;AAChC,SAAS,cAAAC,aAAY,QAAAC,QAAM,YAAAC,WAAU,WAAAC,iBAAe;AACpD,SAAS,iBAAiB;AAC1B,SAAS,gBAAAC,sBAAoB;AAG7B,IAAM,gBAAgB,UAAU,QAAQ;AA+BxC,SAAS,UAAU,OAAoC;AACrD,SAAO,iBAAiB,QAAS,MAA4B,OAAO;AACtE;AAGA,eAAe,UAAU,GAA4B;AACnD,MAAI;AACF,WAAO,MAAML,UAAS,CAAC;AAAA,EACzB,QAAQ;AACN,WAAOI,UAAQ,CAAC;AAAA,EAClB;AACF;AAGA,SAAS,SAAS,OAAe,QAAyB;AACxD,QAAM,MAAMD,UAAS,QAAQ,KAAK;AAClC,SAAO,QAAQ,MAAO,CAAC,IAAI,WAAW,IAAI,KAAK,CAACF,YAAW,GAAG;AAChE;AAGA,SAAS,YAAY,GAAoB;AACvC,SACE,MAAM,YAAY,EAAE,WAAW,SAAS,KAAK,EAAE,SAAS,UAAU,KAAK,EAAE,SAAS,SAAS;AAE/F;AAWA,eAAe,YACb,UACwE;AACxE,MAAI,WAAW;AACf,MAAI;AACF,UAAMF,OAAMG,OAAK,UAAU,QAAQ,CAAC;AACpC,eAAW;AAAA,EACb,SAAS,OAAgB;AACvB,QAAI,UAAU,KAAK,MAAM,UAAU;AACjC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,sCAAsC,UAAU,KAAK,KAAK,eAAe;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,CAAC,MAAM,UAAU,YAAY,IAAI,CAAC;AAChF,UAAM,UAAU,OAAO,MAAM,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,YAAY,CAAC,CAAC;AAC7E,QAAI,SAAS;AACX,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI,SAAU,QAAO,EAAE,MAAM,aAAa,QAAQ,8BAA8B;AAChF,SAAO;AACT;AAcA,eAAsB,qBAAqB,YAAqD;AAC9F,QAAM,WAA4B,CAAC;AACnC,MAAI,wBAAwB;AAE5B,aAAW,MAAM,YAAY;AAC3B,UAAM,SAAS,MAAM,UAAU,GAAG,QAAQ;AAE1C,QAAI,cAAqC,CAAC;AAC1C,QAAI;AACF,YAAM,WAAW,MAAMG,eAAa,GAAG,KAAK;AAC5C,oBAAc,SAAS,QAAQ,gBAAgB,CAAC;AAAA,IAClD,SAAS,OAAgB;AACvB,UAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AAGrE,sBAAc,CAAC;AAAA,MACjB,OAAO;AAEL,iBAAS,KAAK;AAAA,UACZ,gBAAgB,GAAG;AAAA,UACnB,eAAe,GAAG;AAAA,UAClB,eAAe,GAAG;AAAA,UAClB,MAAM;AAAA,UACN,QACE;AAAA,QACJ,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,oBAAI,IAAoB;AAC1C,eAAW,QAAQ,aAAa;AAC9B,YAAM,UAAUD,UAAQ,GAAG,UAAU,IAAI;AACzC,YAAM,OAAO,MAAM,UAAU,OAAO;AACpC,UAAI,SAAS,OAAQ,WAAU,IAAI,MAAM,OAAO;AAAA,IAClD;AAEA,eAAW,CAAC,MAAM,OAAO,KAAK,WAAW;AACvC;AACA,UAAI,SAAS,QAAQ,IAAI,GAAG;AAC1B,iBAAS,KAAK;AAAA,UACZ,gBAAgB,GAAG;AAAA,UACnB,eAAe,GAAG;AAAA,UAClB,eAAe;AAAA,UACf,MAAM;AAAA,UACN,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AACA,YAAM,aAAa,MAAM,YAAY,IAAI;AACzC,UAAI,eAAe,MAAM;AACvB,iBAAS,KAAK;AAAA,UACZ,gBAAgB,GAAG;AAAA,UACnB,eAAe,GAAG;AAAA,UAClB,eAAe;AAAA,UACf,MAAM,WAAW;AAAA,UACjB,QAAQ,WAAW;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,mBAAmB,WAAW,QAAQ,sBAAsB;AACjF;AAGO,SAAS,mBAAmB,QAAgC;AACjE,MAAI,OAAO,SAAS,WAAW,GAAG;AAChC,QAAI,OAAO,0BAA0B,GAAG;AACtC,aAAO;AAAA,QACL,yBAAyB,OAAO,iBAAiB;AAAA,MACnD;AAAA,IACF;AACA,WAAO;AAAA,MACL,yBAAyB,OAAO,iBAAiB,kBAAkB,OAAO,qBAAqB;AAAA,IACjG;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,mCAA8B,OAAO,SAAS,MAAM,cAAc;AACjF,aAAW,KAAK,OAAO,UAAU;AAC/B,UAAM,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,aAAa,gBAAgB,EAAE,cAAc,OAAO,EAAE,MAAM,EAAE;AAAA,EAC9F;AACA,QAAM;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AACT;;;AC3MA,SAAS,oBAA4E;AAErF,SAAS,QAAAE,cAAY;AACrB;AAAA,EAEE,oBAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,mBAAAC;AAAA,EAEA,iBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,OACK;;;ACRA,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["program","id","homedir","resolve","acquireLock","assertBasouRootSafe","basouPaths","findErrorCode","prefixedUlid","readManifest","resolveRepositoryRoot","resolve","basouPaths","join","readYamlFile","root","basouPaths","resolve","program","basouPaths","assertWorkspaceInitialized","prefixedUlid","acquireLock","readManifest","resolve","homedir","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","program","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","program","basouPaths","assertBasouRootSafe","readManifest","prefixedUlid","join","acquireLock","homedir","readYamlFile","resolveRepositoryRoot","assertBasouRootSafe","basouPaths","findErrorCode","readMarkdownFile","renderWithMarkers","resolveRepositoryRoot","writeMarkdownFile","program","basouPaths","assertWorkspaceInitialized","readMarkdownFile","renderWithMarkers","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","readFile","stat","homedir","basename","join","resolve","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","readSessionYaml","resolveRepositoryRoot","SES_PREFIX","SHORT_ID_LEN","program","resolve","join","homedir","basename","basouPaths","assertWorkspaceInitialized","readManifest","payload","readSessionYaml","findErrorCode","stat","readFile","shortId","resolveRepositoryRoot","assertBasouRootSafe","basename","resolve","resolveRepositoryRoot","program","basename","resolve","resolveRepositoryRoot","acquireLock","appendEventToExistingSession","assertBasouRootSafe","basouPaths","createAdHocSessionWithEvent","findErrorCode","readManifest","resolveSessionId","InvalidArgumentError","LABEL_TRUNCATE_HEAD","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","acquireLock","appendEventToExistingSession","readManifest","createAdHocSessionWithEvent","buildAdHocLabel","InvalidArgumentError","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","renderOrientation","writeMarkdownFile","homedir","isAbsolute","join","resolve","readYamlFile","expandTilde","isRecord","readMarkdownFile","renderDecisions","renderHandoff","renderWithMarkers","writeMarkdownFile","renderHandoff","readMarkdownFile","writeMarkdownFile","renderWithMarkers","renderDecisions","program","basouPaths","assertWorkspaceInitialized","renderOrientation","writeMarkdownFile","assertBasouRootSafe","findErrorCode","basename","dirname","isAbsolute","join","relative","resolve","basouPaths","readManifest","readMarkdownFile","renderWithMarkers","writeManifest","writeMarkdownFile","program","basouPaths","readManifest","writeManifest","resolve","join","relative","basename","dirname","isAbsolute","readMarkdownFile","writeMarkdownFile","renderWithMarkers","canonical","readFile","parseMarkers","readMarkdownFile","stat","unlink","basename","dirname","join","homedir","isAbsolute","join","resolve","readYamlFile","expandTilde","isRecord","program","readFile","parseMarkers","readMarkdownFile","assertBasouRootSafe","basouPaths","findErrorCode","InvalidArgumentError","readdir","stat","homedir","join","findErrorCode","join","homedir","readdir","findErrorCode","stat","collectPath","InvalidArgumentError","resolve","program","basouPaths","assertWorkspaceInitialized","assertBasouRootSafe","findErrorCode","isAbsolute","resolve","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","writeMarkdownFile","program","basouPaths","assertWorkspaceInitialized","isAbsolute","resolve","writeMarkdownFile","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","basouPaths","InvalidArgumentError","InvalidArgumentError","program","basouPaths","mkdir","homedir","join","acquireLock","assertBasouRootSafe","basouPaths","ChildProcessRunner","coreAppendChainedEvent","finalizeSessionYaml","getSnapshot","overwriteYamlFile","prefixedUlid","readManifest","readYamlFile","resolveRepositoryRoot","SessionSchema","sanitizeWorkingDirectory","writeYamlFile","program","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","resolveSessionId","SessionImportPayloadSchema","SessionSchema","InvalidArgumentError","SES_PREFIX","TASK_PREFIX","SHORT_ID_BASE_LEN","SHORT_ID_MAX_LEN","STATUS_VALUES","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","join","readYamlFile","SessionSchema","findErrorCode","computeUniquePrefixLen","sliceShort","maxLen","pad","isAbsolute","relative","shortTaskId","shortId","assertBasouRootSafe","readManifest","SessionImportPayloadSchema","importOptions","importSessionFromJson","readFile","InvalidArgumentError","basename","acquireLock","appendEventToExistingSession","enumerateSessionDirs","assertBasouRootSafe","basouPaths","findErrorCode","resolveRepositoryRoot","program","basouPaths","assertWorkspaceInitialized","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","program","basouPaths","assertBasouRootSafe","findErrorCode","readManifest","resolveRepositoryRoot","readFile","join","assertBasouRootSafe","basouPaths","findErrorCode","loadSessionEntries","prefixedUlid","readManifest","replayEvents","resolveRepositoryRoot","resolveSessionId","resolveTaskId","InvalidArgumentError","STATUS_VALUES","program","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","program","basouPaths","assertWorkspaceInitialized","resolveSessionId","enumerateSessionDirs","resolveRepositoryRoot","assertBasouRootSafe","findErrorCode","basename","resolve","assertBasouRootSafe","basouPaths","findErrorCode","readManifest","resolveRepositoryRoot","InvalidArgumentError","lstat","realpath","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","program","basouPaths","assertWorkspaceInitialized","resolve","readManifest","basename","findErrorCode","resolveRepositoryRoot","assertBasouRootSafe","require","program"]}
|