create-op-node 0.15.0 → 0.15.2
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/README.md +5 -4
- package/dist/cli.js +59 -19
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/constants.ts","../src/lib/cloudflare.ts","../src/lib/tfc.ts","../src/lib/exec.ts","../src/lib/keychain.ts","../src/lib/prompts.ts","../src/lib/github.ts","../src/lib/secrets.ts","../src/lib/polling.ts","../src/commands/init.ts","../src/lib/homebrew.ts","../src/lib/macos.ts","../src/lib/launchagent.ts","../src/lib/op-compose-script.ts","../src/lib/op-compose-install.ts","../src/lib/docker.ts","../src/lib/cosign.ts","../src/lib/ollama.ts","../src/lib/env-file.ts","../src/lib/noderepo.ts","../src/lib/assert.ts","../src/commands/bootstrap.ts","../src/commands/reset.ts","../src/lib/http.ts","../src/lib/tls.ts","../src/commands/verify.ts","../src/lib/region-schema.json","../src/lib/region.ts","../src/commands/region.ts","../src/lib/cli-args.ts","../src/cli.ts"],"names":["result","password","p","p2","pc","fresh","v","mkdir","writeFile","chmod","text","join","dirname","rename","access","homedir","Command","Option","resolveRegion","rm","save","REGION_RE","fileExists","p4","readFile","connect","resolve","DEFAULT_DEPS","tls","p5","phaseIcon","p6","first"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Shared invariants reused across libs + commands. Each constant has exactly\n * one definition so a format change can't drift between callers (which\n * happened during review: the pgsodium-key shape was hand-rolled in three\n * places).\n */\n\n/** A pgsodium master key is 32 bytes of CSPRNG output, encoded as 64\n * lowercase hex characters. Match it everywhere with this regex so an\n * uppercase-hex or wrong-length value gets a consistent reason. */\nexport const PGSODIUM_KEY_RE = /^[a-f0-9]{64}$/;\n\n/** Allowed character set for a Cloudflare Tunnel token before we\n * interpolate it into a launchd plist string. JWT-style tokens\n * (header.payload.signature) use base64-url — letters, digits, `-`,\n * `_`, `.`, `=`. We deliberately reject anything outside that set so\n * a crafted token can't inject XML attributes or break the plist\n * string content.\n *\n * Stricter than SAFE_LAUNCHCTL_VALUE_RE on purpose: Cloudflare Tunnel\n * tokens are guaranteed base64url by the issuer, so allowing `+` or `/`\n * here would silently accept malformed tokens that would later fail at\n * cloudflared startup with a less actionable error. Kept separate from\n * SAFE_LAUNCHCTL_VALUE_RE for that reason. */\nexport const TUNNEL_TOKEN_RE = /^[A-Za-z0-9_\\-.=]+$/;\n\n/** Operator-friendly path safety check used before interpolating a path\n * into a launchd `sh -c` command. Any shell metacharacter would let an\n * attacker-supplied path execute arbitrary code at every login. The set\n * permits everything macOS allows in a normal path (letters, digits,\n * `/`, `-`, `_`, `.`, space) — and rejects `;`, `$`, backticks, quotes,\n * newlines, etc. */\nexport const SAFE_PATH_RE = /^[A-Za-z0-9_\\-./ ]+$/;\n\n/** Character set allowed for any value we interpolate into the launchd\n * `sh -c` body as a `launchctl setenv VAR \"<value>\"` argument. Permits\n * every character that base64 (`+`, `/`, `=`), base64url (`-`, `_`), and\n * JWT (`.`) produce, plus alphanumerics — covers JWT_SECRET and the signed\n * Supabase tokens (which use JWT shape `xxx.yyy.zzz`). Rejects shell\n * metacharacters (`;`, `$`, backticks, quotes, spaces, newlines) that\n * would let a tampered value inject commands into the login session.\n *\n * POSTGRES_PASSWORD and DASHBOARD_PASSWORD use the stricter\n * URL_SAFE_PASSWORD_RE — they land in postgres:// URIs where `+`/`/`/`=`\n * cause parser ambiguity. */\nexport const SAFE_LAUNCHCTL_VALUE_RE = /^[A-Za-z0-9+/=._-]+$/;\n\n/** Subset of SAFE_LAUNCHCTL_VALUE_RE for values that ALSO land in URI\n * components (postgres:// connection strings, basic-auth headers).\n * base64url alphabet — no `+`, no `/`, no `=`. */\nexport const URL_SAFE_PASSWORD_RE = /^[A-Za-z0-9_-]+$/;\n\n/** Same shape as TUNNEL_TOKEN_RE but documented separately because the\n * SUPABASE_URL value also lands in the plist and we want to allow `://`\n * and `:` for the port. Letters, digits, `-`, `_`, `.`, `:`, `/`. */\nexport const SAFE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;\n\n/** The well-known placeholder the opuspopuli-node template ships as the\n * compose-level default for `GATEWAY_HMAC_SECRET` (and, JSON-wrapped, for\n * `API_KEYS`). Every checkout of the template carries this identical string,\n * so it MUST never be the live value on a node exposed via the Cloudflare\n * Tunnel (`public` profile). bootstrap generates a real per-node value and\n * refuses to activate the public profile if this default is still in force.\n *\n * Kept as a single constant so the generator, the guard, and the tests all\n * compare against the exact same literal. */\nexport const WELL_KNOWN_GATEWAY_HMAC_SECRET =\n // eslint-disable-next-line sonarjs/hardcoded-secret-signatures, sonarjs/no-hardcoded-passwords -- this is the PUBLIC well-known template default we are guarding AGAINST, not a live credential\n 'local-only-hmac-secret-rotate-before-tunnel-exposure';\n\n/** Default network timeout used by `verify`'s probes (TLS handshake, HTTP\n * GET /health, GraphQL POST). One number so tls.ts and http.ts don't drift. */\nexport const VERIFY_NETWORK_TIMEOUT_MS = 10_000;\n\n/** Per-request timeout for the Terraform Cloud + Cloudflare API helpers\n * (`tfc.ts`, `cloudflare.ts`). Deliberately separate from the `verify`\n * probe timeout: these are control-plane API calls, and the overall\n * apply-wait budget is governed by `polling.ts`, so each individual\n * request just needs a sane cap to fail fast on a stalled connection\n * instead of hanging `init` indefinitely. */\nexport const API_REQUEST_TIMEOUT_MS = 15_000;\n\n/** First N chars of a probe response body that get echoed back to the\n * operator for diagnostics. Capped low because the wizard renders this\n * inline; for the real body, use `curl -v` and friends. */\nexport const BODY_PREVIEW_MAX = 200;\n","/**\n * Cloudflare API helpers used by `create-op-node init`.\n *\n * The probe replicates what we built interactively on 2026-06-16: hit each of\n * the 5 endpoints we need so we know the token has every scope before going any\n * further. Failing early here saves a ~60-second Terraform plan that would fail\n * with a less useful error.\n *\n * Account-owned tokens (`cfat_…`) cannot use `/user/tokens/verify`. We hit\n * `/accounts/{id}/tokens/verify` for validity and the 5 resource endpoints for\n * scope coverage.\n */\n\nimport { API_REQUEST_TIMEOUT_MS } from './constants.js';\n\nconst CF_API = 'https://api.cloudflare.com/client/v4';\n\ninterface ProbeInput {\n token: string;\n accountId: string;\n zoneId: string;\n}\n\nexport interface ProbeResult {\n ok: boolean;\n issues: string[];\n}\n\n/**\n * GET a Cloudflare API path as JSON, with a hard per-request timeout.\n *\n * Native `fetch` has no default timeout, so a stalled connection would hang\n * `init` indefinitely (`probeCloudflareToken` makes 6 sequential calls). We\n * wrap the call in an `AbortController` and, on any throw (timeout / DNS blip\n * / TLS reset / proxy error), return `{ status: 0, body: null }`. Callers\n * treat a non-200 status as a soft failure, so a `0` degrades to a\n * network-error message instead of rejecting out of the wizard.\n */\nasync function get(\n token: string,\n path: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<{ status: number; body: unknown }> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(`${CF_API}${path}`, {\n headers: { Authorization: `Bearer ${token}` },\n signal: ctrl.signal,\n });\n let body: unknown = null;\n try {\n body = await res.json();\n } catch {\n /* non-JSON body — leave as null */\n }\n return { status: res.status, body };\n } catch {\n // Timeout (AbortError) or any network-layer throw. status 0 = \"never got\n // a response\" — see the docstring above.\n return { status: 0, body: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction shortError(body: unknown): string {\n if (\n typeof body === 'object' &&\n body !== null &&\n 'errors' in body &&\n Array.isArray((body as { errors: unknown[] }).errors)\n ) {\n const errs = (body as { errors: Array<{ message?: string; code?: number }> }).errors;\n return errs\n .map((e) => {\n const prefix = e.code ? `CF ${e.code}: ` : '';\n return `${prefix}${e.message ?? 'unknown'}`;\n })\n .join('; ');\n }\n return 'no error message returned';\n}\n\ninterface ScopeCheck {\n name: string;\n path: string;\n /** Endpoints that 404 when the underlying feature isn't enabled but the scope\n * IS present (e.g. R2 before \"Enable R2\"). We treat those as passes with a\n * note rather than failures. */\n treat404AsPass?: boolean;\n}\n\nexport async function probeCloudflareToken(input: ProbeInput): Promise<ProbeResult> {\n const issues: string[] = [];\n\n // ---- Validity probe (Account-owned token endpoint) ----\n const verify = await get(input.token, `/accounts/${input.accountId}/tokens/verify`);\n if (verify.status === 0) {\n issues.push(\n \"Couldn't reach Cloudflare (network error or timeout). Check your connection and retry.\",\n );\n return { ok: false, issues };\n }\n if (verify.status !== 200) {\n issues.push(\n `Token verify failed (HTTP ${verify.status}): ${shortError(verify.body)}`,\n );\n return { ok: false, issues };\n }\n\n // ---- Scope probes ----\n const checks: ScopeCheck[] = [\n { name: 'Zone : Zone : Read', path: `/zones/${input.zoneId}` },\n { name: 'Zone : DNS : Edit', path: `/zones/${input.zoneId}/dns_records?per_page=1` },\n { name: 'Account : Cloudflare Tunnel : Edit', path: `/accounts/${input.accountId}/cfd_tunnel` },\n { name: 'Account : Workers R2 Storage : Edit', path: `/accounts/${input.accountId}/r2/buckets` },\n { name: 'Account : Cloudflare Pages : Edit', path: `/accounts/${input.accountId}/pages/projects` },\n ];\n\n for (const check of checks) {\n const res = await get(input.token, check.path);\n if (res.status === 200) continue;\n if (res.status === 404 && check.treat404AsPass) continue;\n if (res.status === 0) {\n issues.push(`Couldn't reach Cloudflare while checking ${check.name} (network error or timeout).`);\n } else if (res.status === 401 || res.status === 403) {\n issues.push(`Missing scope: ${check.name}`);\n } else if (\n res.status === 400 &&\n typeof res.body === 'object' &&\n res.body !== null &&\n 'errors' in res.body &&\n Array.isArray((res.body as { errors: Array<{ code?: number }> }).errors) &&\n (res.body as { errors: Array<{ code?: number }> }).errors.some((e) => e.code === 10042)\n ) {\n // R2 not enabled yet — actionable, not a scope problem.\n issues.push(\n `R2 not enabled on this account. ` +\n `Enable it once in Cloudflare dashboard → R2 → Get started, then re-run.`,\n );\n } else {\n issues.push(`${check.name} probe returned HTTP ${res.status}: ${shortError(res.body)}`);\n }\n }\n\n return { ok: issues.length === 0, issues };\n}\n\n/* ------------------------------------------------------------------ *\n * Tunnel-status probe (used by `verify`, not `init`) *\n * ------------------------------------------------------------------ */\n\nexport interface TunnelStatusInput {\n token: string;\n accountId: string;\n tunnelId: string;\n /** Injectable for tests. */\n fetchImpl?: typeof fetch;\n}\n\nexport interface TunnelStatusOk {\n ok: true;\n /** Active connector connections registered with Cloudflare's edge. Zero on\n * a freshly-created tunnel that hasn't been started, > 0 on a healthy one. */\n connections: number;\n /** Cloudflare's own status field — `healthy`, `degraded`, `inactive`, etc. */\n status: string;\n}\n\nexport interface TunnelStatusFailed {\n ok: false;\n reason: string;\n}\n\nexport type TunnelStatusResult = TunnelStatusOk | TunnelStatusFailed;\n\ninterface CfTunnelEnvelope {\n result?: {\n status?: string;\n connections?: Array<unknown>;\n };\n}\n\n/**\n * Look up a single tunnel's current edge-side status. The CF API endpoint\n * returns `connections: []` until at least one cloudflared connector\n * registers — useful as a verify signal that the Studio's cloudflared is\n * actually online.\n */\nexport async function tunnelStatus(input: TunnelStatusInput): Promise<TunnelStatusResult> {\n const fetchImpl = input.fetchImpl ?? fetch;\n try {\n const res = await get(\n input.token,\n `/accounts/${input.accountId}/cfd_tunnel/${input.tunnelId}`,\n fetchImpl,\n );\n if (res.status === 0) {\n return { ok: false, reason: \"couldn't reach Cloudflare (network error or timeout)\" };\n }\n if (res.status !== 200) {\n return {\n ok: false,\n reason: `tunnel lookup failed (HTTP ${res.status}): ${shortError(res.body)}`,\n };\n }\n const env = res.body as CfTunnelEnvelope;\n const status = env.result?.status ?? '<no status>';\n const connections = env.result?.connections?.length ?? 0;\n return { ok: true, connections, status };\n } catch (err) {\n return { ok: false, reason: `tunnel lookup threw: ${(err as Error).message}` };\n }\n}\n","/**\n * Terraform Cloud (HCP Terraform) API helpers used by `create-op-node init`.\n *\n * We hit a tiny subset of the TFC v2 API directly via native `fetch` — no\n * client library. Three needs:\n *\n * 1. Verify the operator's TFC token is valid and has access to the org\n * they typed.\n * 2. Resolve a workspace by tag set so we can poll its state for outputs.\n * 3. Fetch the Tunnel token output after `terraform apply` completes.\n *\n * The TFC API responds with JSON:API-shaped documents; helpers below narrow\n * each call to the minimal shape we actually consume.\n */\n\nimport { API_REQUEST_TIMEOUT_MS } from './constants.js';\n\nconst TFC_API = 'https://app.terraform.io/api/v2';\n\n/** TFC organization slug rules: alphanumerics, underscores, hyphens; the API\n * doesn't formally publish a max but slugs over 40 chars are rejected in\n * practice. We validate before any URL interpolation to neutralise typos\n * that would otherwise hit unintended endpoints (e.g. `?` or `/` in the\n * slug bouncing us into a different route). */\nconst ORG_SLUG_RE = /^[A-Za-z0-9_-]{1,40}$/;\n\nexport function isValidTfcOrgSlug(slug: string): boolean {\n return ORG_SLUG_RE.test(slug);\n}\n\ninterface TfcAuth {\n token: string;\n organization: string;\n}\n\ntype Headers = Record<string, string>;\n\nfunction authHeaders(token: string): Headers {\n return {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/vnd.api+json',\n };\n}\n\n/**\n * GET a TFC API path as JSON, with a hard per-request timeout.\n *\n * A stalled or half-open connection (native `fetch` has no default timeout)\n * would otherwise hang `init` — including the ~10-minute apply-wait in\n * `polling.ts` — forever. We wrap the call in an `AbortController` and, on\n * any throw (timeout / DNS blip / TLS reset / proxy error), return\n * `{ status: 0, body: null }`. Every caller already treats a non-200 status\n * as a soft failure, so a `0` degrades to `null` / a network-error message\n * instead of rejecting out of the poll loop and crashing the wizard.\n */\nasync function getJson(\n token: string,\n path: string,\n): Promise<{ status: number; body: unknown }> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);\n try {\n const res = await fetch(`${TFC_API}${path}`, {\n headers: authHeaders(token),\n signal: ctrl.signal,\n });\n let body: unknown = null;\n try {\n body = await res.json();\n } catch {\n /* non-JSON body — leave as null */\n }\n return { status: res.status, body };\n } catch {\n // Timeout (AbortError) or any network-layer throw. status 0 = \"never got\n // a response\" — see the docstring above.\n return { status: 0, body: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport interface TfcProbeResult {\n ok: boolean;\n /** TFC user's display name when the token belongs to a user (`null` when it's a team / org token). */\n userName?: string;\n issues: string[];\n}\n\n/**\n * Sanity-check the token + organization at the same time:\n *\n * - GET /account/details — confirms the token itself is valid.\n * - GET /organizations/{org} — confirms the org exists AND that the token\n * has the membership/permissions to see it.\n *\n * Both must pass before we let the wizard proceed; a token that's valid but\n * scoped to a different org would silently fail at the workspace step.\n */\nexport async function probeTfcToken(input: TfcAuth): Promise<TfcProbeResult> {\n const issues: string[] = [];\n\n if (!isValidTfcOrgSlug(input.organization)) {\n issues.push(\n `Organization \"${input.organization}\" isn't a valid TFC slug (letters, digits, hyphens, underscores; up to 40 chars).`,\n );\n return { ok: false, issues };\n }\n\n const account = await getJson(input.token, '/account/details');\n if (account.status === 0) {\n issues.push(\n \"Couldn't reach Terraform Cloud (network error or timeout). Check your connection and retry.\",\n );\n return { ok: false, issues };\n }\n if (account.status !== 200) {\n issues.push(\n `TFC token invalid (HTTP ${account.status}). Regenerate at https://app.terraform.io/app/settings/tokens.`,\n );\n return { ok: false, issues };\n }\n const userName = extractUserName(account.body);\n\n const org = await getJson(\n input.token,\n `/organizations/${encodeURIComponent(input.organization)}`,\n );\n if (org.status === 0) {\n issues.push(\n \"Couldn't reach Terraform Cloud while checking the organization (network error or timeout).\",\n );\n } else if (org.status === 404) {\n issues.push(\n `TFC organization \"${input.organization}\" not found, or this token lacks access. Check the org slug at https://app.terraform.io.`,\n );\n } else if (org.status === 401 || org.status === 403) {\n issues.push(\n `TFC token doesn't have permission to access org \"${input.organization}\".`,\n );\n } else if (org.status !== 200) {\n issues.push(`TFC org probe returned HTTP ${org.status}.`);\n }\n\n return {\n ok: issues.length === 0,\n issues,\n ...(userName ? { userName } : {}),\n };\n}\n\nfunction extractUserName(body: unknown): string | undefined {\n if (\n typeof body === 'object' &&\n body !== null &&\n 'data' in body &&\n typeof (body as { data: unknown }).data === 'object'\n ) {\n const data = (body as { data: { attributes?: { username?: string } } }).data;\n return data.attributes?.username;\n }\n return undefined;\n}\n\nexport interface FindWorkspaceInput extends TfcAuth {\n /** Tag set the workspace must carry. For our use case: `['opuspopuli', 'cloudflare']`. */\n tags: string[];\n /** Optional name to disambiguate when multiple workspaces share the tag set. */\n name?: string;\n}\n\nexport interface TfcWorkspace {\n id: string;\n name: string;\n /** Latest run id, used to poll for apply completion. */\n currentRunId: string | null;\n}\n\n/**\n * Find the workspace this region's Terraform code will run in.\n *\n * TFC's filter syntax for tags is `filter[tagged]=tag1,tag2`. We ask for all\n * matches and let the caller pick by `name` when there's ambiguity (one TFC\n * org can host many workspaces with the same tag set).\n */\nexport async function findWorkspace(input: FindWorkspaceInput): Promise<TfcWorkspace | null> {\n if (!isValidTfcOrgSlug(input.organization)) return null;\n const tagFilter = encodeURIComponent(input.tags.join(','));\n const res = await getJson(\n input.token,\n `/organizations/${encodeURIComponent(input.organization)}/workspaces?filter[tagged]=${tagFilter}&page[size]=100`,\n );\n if (res.status !== 200) return null;\n\n const items = extractWorkspaceList(res.body);\n if (items.length === 0) return null;\n\n const match = input.name ? items.find((w) => w.name === input.name) : items[0];\n return match ?? null;\n}\n\ninterface RawWorkspace {\n id: string;\n attributes?: { name?: string };\n relationships?: { 'current-run'?: { data?: { id?: string } | null } };\n}\n\nfunction extractWorkspaceList(body: unknown): TfcWorkspace[] {\n if (\n typeof body !== 'object' ||\n body === null ||\n !('data' in body) ||\n !Array.isArray((body as { data: unknown }).data)\n ) {\n return [];\n }\n const data = (body as { data: RawWorkspace[] }).data;\n return data.map((w) => ({\n id: w.id,\n name: w.attributes?.name ?? '',\n currentRunId: w.relationships?.['current-run']?.data?.id ?? null,\n }));\n}\n\nexport interface TfcRunStatus {\n id: string;\n status: string;\n /** `true` once the run reached a terminal state (applied / errored / canceled / discarded). */\n finished: boolean;\n /** `true` only when the run finished successfully (`applied`). */\n succeeded: boolean;\n}\n\nconst TERMINAL_STATUSES = new Set([\n 'applied',\n 'errored',\n 'canceled',\n 'discarded',\n 'policy_soft_failed',\n 'force_canceled',\n]);\n\n/**\n * Look up a single TFC run by id. Used while we're waiting for the first\n * `terraform apply` to finish.\n */\nexport async function getRunStatus(\n auth: TfcAuth,\n runId: string,\n): Promise<TfcRunStatus | null> {\n // runId comes from a previous TFC response — trusted shape — but\n // encodeURIComponent is cheap defense if it's ever sourced from elsewhere.\n const res = await getJson(auth.token, `/runs/${encodeURIComponent(runId)}`);\n if (res.status !== 200) return null;\n\n const body = res.body as {\n data?: { id?: string; attributes?: { status?: string } };\n };\n const id = body.data?.id;\n const status = body.data?.attributes?.status;\n if (!id || !status) return null;\n\n return {\n id,\n status,\n finished: TERMINAL_STATUSES.has(status),\n succeeded: status === 'applied',\n };\n}\n\n/**\n * Discriminated result of pulling a named output. The three cases must stay\n * distinct so the poll loop can tell a recoverable transient apart from a\n * genuine absence (#59):\n *\n * - `value` — the output is present and usable.\n * - `absent` — the request succeeded (HTTP 200) but the named output isn't\n * in the state, or its value isn't a string (e.g. the operator\n * changed the type). Permanent — retrying won't help.\n * - `error` — the HTTP call failed (`getJson` degraded a timeout/blip to\n * `status: 0`, or a non-200 such as a 404/425 while the state\n * version is still settling). Retryable.\n */\nexport type OutputResult =\n | { kind: 'value'; value: string }\n | { kind: 'absent' }\n | { kind: 'error' };\n\n/**\n * Pull a named output value from a workspace's current state version.\n *\n * Caller should poll the matching run for `applied` status first; an\n * in-flight workspace returns a 404 / 425 here, which surfaces as `error`\n * (retryable) rather than `absent` — a network blip on the final fetch must\n * not be misreported as a missing output. See {@link OutputResult}.\n */\nexport async function fetchOutput(\n auth: TfcAuth,\n workspaceId: string,\n outputName: string,\n): Promise<OutputResult> {\n const res = await getJson(\n auth.token,\n `/workspaces/${encodeURIComponent(workspaceId)}/current-state-version-outputs`,\n );\n // status 0 (timeout/network) or any non-200: could be transient (the state\n // version may still be settling right after apply), so let the caller retry.\n if (res.status !== 200) return { kind: 'error' };\n\n const body = res.body as {\n data?: Array<{ attributes?: { name?: string; value?: unknown; sensitive?: boolean } }>;\n };\n const match = body.data?.find((o) => o.attributes?.name === outputName);\n if (!match) return { kind: 'absent' };\n\n const value = match.attributes?.value;\n return typeof value === 'string' ? { kind: 'value', value } : { kind: 'absent' };\n}\n","/**\n * Shared `execa` wrapper for the few CLIs the wizard shells out to (`op`, `gh`).\n *\n * Two patterns this exists to share:\n *\n * 1. `reject: false` is opt-out on every call, since we want to inspect the\n * exit code rather than have a thrown error fan out across the wizard.\n * 2. **ENOENT doesn't suppress** under `reject: false` — that's a spawn\n * error, not a child-process exit. Callers that don't catch it crash.\n * `safeExeca` traps `ENOENT` / `ENOTDIR` and returns `null` so callers\n * can branch on \"binary not installed at all\" cleanly.\n *\n * The shape kept narrow on purpose — adds nothing execa doesn't, just makes\n * the failure modes uniform across call sites.\n */\n\nimport { execa, ExecaError } from 'execa';\n\nexport interface SafeExecaResult {\n /** Exit code from the child. `undefined` when the child was killed by a\n * signal — we pass it through honestly so callers can distinguish\n * signal-killed from clean zero. */\n exitCode: number | undefined;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Run a command; return `null` when the binary isn't on PATH at all, an\n * object with exit code + output otherwise. Never throws on a missing\n * binary, never throws on a non-zero exit.\n */\nexport async function safeExeca(\n cmd: string,\n args: string[],\n options?: {\n input?: string;\n /** Working directory for the child. Defaults to the parent's cwd. */\n cwd?: string;\n /** Extra env vars merged into the child's env (execa's default\n * extendEnv: true means these add to process.env rather than\n * replace). Used by bootstrap's compose subprocess calls so the\n * Keychain-loaded secrets reach docker compose without first\n * being written to a plaintext .env file on disk. */\n env?: NodeJS.ProcessEnv;\n },\n): Promise<SafeExecaResult | null> {\n try {\n const result = await execa(cmd, args, { reject: false, ...options });\n return {\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n };\n } catch (err) {\n const e = err as ExecaError & NodeJS.ErrnoException;\n if (e.code === 'ENOENT' || e.code === 'ENOTDIR') return null;\n throw err;\n }\n}\n","/**\n * macOS Keychain wrapper around the built-in `security` CLI.\n *\n * Replaces the 1Password integration as of v0.3.0: secrets live in the\n * operator's login keychain (FileVault-encrypted at rest, locked with\n * the user session). Generic-password items only — we don't need\n * internet-password semantics.\n *\n * **Cross-device caveat:** the `security` CLI cannot create iCloud-\n * Keychain-synchronizable items (no `kSecAttrSynchronizable` flag is\n * exposed). Items written here stay on the machine they were written\n * on. `init` writes on the laptop; `bootstrap` reads on the Studio.\n * On a Studio miss, bootstrap falls back to prompting the operator to\n * paste the value and persists it locally for re-runs.\n *\n * **Argv exposure caveat:** `security add-generic-password -w <value>`\n * passes the secret via argv. It's briefly visible to anyone running\n * `ps -E` while the child is alive. Same risk model as the\n * `op item create notesPlain=<value>` pattern we previously accepted.\n * If a future `security` release adds a stdin form, swap to it here.\n */\n\nimport { safeExeca } from './exec.js';\n\n/** Reverse-DNS prefix for all Opus Populi entries in Keychain Access. */\nconst SERVICE_PREFIX = 'org.opuspopuli';\n\nexport type SecretAccount =\n | 'pgsodium-root-key'\n | 'tunnel-token'\n | 'postgres-password'\n | 'jwt-secret'\n | 'supabase-anon-key'\n | 'supabase-service-role-key'\n | 'dashboard-password'\n | 'prompts-db-password'\n | 'prompt-service-api-key'\n | 'prompt-service-admin-api-key'\n | 'gateway-hmac-secret'\n | 'grafana-admin-password';\n\nexport interface SecretCoordinates {\n /** Region label, used to scope the service identifier. */\n region: string;\n /** Which secret within the region. */\n account: SecretAccount;\n}\n\nfunction serviceFor(region: string): string {\n return `${SERVICE_PREFIX}.${region}`;\n}\n\nconst FRIENDLY: Record<SecretAccount, string> = {\n 'pgsodium-root-key': 'pgsodium root key',\n 'tunnel-token': 'Cloudflare Tunnel token',\n 'postgres-password': 'Postgres password',\n 'jwt-secret': 'JWT signing secret',\n 'supabase-anon-key': 'Supabase anon key',\n 'supabase-service-role-key': 'Supabase service role key',\n 'dashboard-password': 'Supabase Studio dashboard password',\n 'prompts-db-password': 'prompt-service Postgres password',\n 'prompt-service-api-key': 'prompt-service HMAC API key',\n 'prompt-service-admin-api-key': 'prompt-service admin API key',\n 'gateway-hmac-secret': 'API Gateway HMAC secret',\n 'grafana-admin-password': 'Grafana admin password',\n};\n\nfunction labelFor(coords: SecretCoordinates): string {\n return `Opus Populi (${coords.region}) — ${FRIENDLY[coords.account]}`;\n}\n\nexport interface KeychainAvailability {\n /** True when the `security` CLI ran cleanly (macOS or compatible). On\n * non-macOS hosts this is false and callers should fall back to\n * prompt-only flows. */\n available: boolean;\n /** Free-text reason when unavailable. */\n reason?: string;\n}\n\nexport async function detectKeychain(): Promise<KeychainAvailability> {\n const res = await safeExeca('security', ['-h']);\n if (res === null) {\n return {\n available: false,\n reason: '`security` CLI not on PATH (Keychain requires macOS)',\n };\n }\n return { available: true };\n}\n\nexport interface SaveSecretResult {\n written: boolean;\n /** True when an item already existed and was updated (via -U upsert). */\n updated: boolean;\n reason?: string;\n}\n\n/**\n * Write a generic-password item, upserting if it already exists. Uses\n * `add-generic-password -U` so re-runs don't error on duplicates.\n */\nexport async function saveSecret(\n coords: SecretCoordinates,\n value: string,\n): Promise<SaveSecretResult> {\n const service = serviceFor(coords.region);\n const label = labelFor(coords);\n\n // Check whether the item exists ahead of the upsert so we can report\n // `updated: true` vs `written: true` to the caller (purely informational —\n // the operator sees a different message in the wizard).\n const existing = await safeExeca('security', [\n 'find-generic-password',\n '-s',\n service,\n '-a',\n coords.account,\n ]);\n const updated = existing !== null && existing.exitCode === 0;\n\n const res = await safeExeca('security', [\n 'add-generic-password',\n '-U', // upsert\n '-s', service,\n '-a', coords.account,\n '-l', label,\n '-D', 'Opus Populi secret',\n '-w', value, // argv-exposure caveat, see file header\n ]);\n if (res === null) {\n return { written: false, updated: false, reason: '`security` CLI not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n written: false,\n updated,\n reason: `security add-generic-password failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}${formatKeychainHint(res.exitCode)}`,\n };\n }\n return { written: true, updated };\n}\n\n/**\n * Read a generic-password item by service + account. Returns `null` when\n * the item doesn't exist, `security` isn't available, or the value is\n * empty. Callers branch to a paste prompt on `null`.\n */\nexport async function readSecret(coords: SecretCoordinates): Promise<string | null> {\n const service = serviceFor(coords.region);\n\n const res = await safeExeca('security', [\n 'find-generic-password',\n '-s', service,\n '-a', coords.account,\n '-w', // print the password to stdout (final flag = read mode)\n ]);\n if (res === null || res.exitCode !== 0) return null;\n const value = res.stdout.trim();\n return value.length > 0 ? value : null;\n}\n\n/** Delete a generic-password item. Idempotent — missing items return ok. */\nexport async function deleteSecret(coords: SecretCoordinates): Promise<{ ok: boolean; reason?: string }> {\n const service = serviceFor(coords.region);\n\n const res = await safeExeca('security', [\n 'delete-generic-password',\n '-s', service,\n '-a', coords.account,\n ]);\n if (res === null) return { ok: false, reason: '`security` CLI not on PATH' };\n // Exit 44 (errSecItemNotFound) is fine — already gone.\n if (res.exitCode === 0 || res.exitCode === ERR_SEC_ITEM_NOT_FOUND) return { ok: true };\n return {\n ok: false,\n reason: `security delete-generic-password failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}${formatKeychainHint(res.exitCode)}`,\n };\n}\n\n/**\n * macOS `security` exit codes we care about. Defined as constants so callers\n * can reason about them without sprinkling magic numbers.\n * 36 = errSecInteractionNotAllowed — keychain is locked / no UI session\n * 44 = errSecItemNotFound — item doesn't exist (treated as \"ok\" for delete)\n */\nexport const ERR_SEC_INTERACTION_NOT_ALLOWED = 36;\nexport const ERR_SEC_ITEM_NOT_FOUND = 44;\n\n/** Append an operator-friendly remediation hint to a `security` error\n * message when the exit code maps to one we recognize. Returns empty\n * string when no hint applies, so the call site can safely concatenate. */\nfunction formatKeychainHint(exitCode: number | null | undefined): string {\n if (exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED) {\n return (\n `\\n` +\n `Hint: the login keychain is locked (SSH sessions don't auto-unlock it).\\n` +\n `Run \\`security unlock-keychain ~/Library/Keychains/login.keychain-db\\` and re-run bootstrap.`\n );\n }\n return '';\n}\n\n/**\n * Probe whether the login keychain is currently locked. Implemented by\n * attempting a no-op `find-generic-password` against a service that won't\n * exist: exit 44 (errSecItemNotFound) → unlocked, exit 36 → locked.\n *\n * Used by bootstrap to proactively prompt SSH operators for their login\n * password before the first Keychain write — without this, the operator\n * gets nine identical failures (one per secret) before they figure out\n * the keychain is locked.\n */\nexport async function isKeychainLocked(): Promise<boolean> {\n const res = await safeExeca('security', [\n 'find-generic-password',\n '-s',\n `${SERVICE_PREFIX}.__op_node_lock_probe__`,\n '-a',\n '__nothing_here__',\n ]);\n if (res === null) return false; // no security CLI; can't be locked\n return res.exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED;\n}\n\nexport interface UnlockResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Unlock the login keychain via `security unlock-keychain -p <password>`.\n *\n * argv-exposure caveat: the password is visible briefly to `ps -E` while\n * the security child is alive. Same risk model as `saveSecret` writing\n * the secret value via `-w`. The `security` CLI doesn't expose a stdin\n * password form for unlock, so this is the cleanest option available.\n *\n * Callers should prompt the operator via clack's `p.password()` (which\n * doesn't echo) and pass the value here.\n */\nexport async function unlockKeychain(password: string): Promise<UnlockResult> {\n const res = await safeExeca('security', [\n 'unlock-keychain',\n '-p',\n password,\n // Default keychain path — same as the operator's GUI login keychain\n // on a stock macOS install. Lets us avoid a homedir lookup here.\n `${process.env['HOME'] ?? ''}/Library/Keychains/login.keychain-db`,\n ]);\n if (res === null) return { ok: false, reason: '`security` CLI not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `security unlock-keychain failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\n/** Heuristic: are we running inside an SSH session?\n * `SSH_CONNECTION` is set by sshd on every interactive login. `SSH_TTY`\n * is set on TTY-allocated sessions; we check both. Process-env only —\n * no syscalls. */\nexport function isSshSession(env: NodeJS.ProcessEnv = process.env): boolean {\n return Boolean(env['SSH_CONNECTION'] ?? env['SSH_TTY']);\n}\n\n/** Exported for tests + the rare caller that needs the raw service string. */\nexport const _internal = {\n serviceFor,\n labelFor,\n SERVICE_PREFIX,\n};\n","/**\n * Tiny shared helper around @clack/prompts' cancel sentinel.\n *\n * Every wizard subcommand wants the same shape: ask for a value, if the\n * operator hit Ctrl-C / Esc, exit cleanly with a \"Cancelled.\" note. Without\n * this helper each call site duplicates the `p.isCancel` check + `p.cancel`\n * + `process.exit(0)`.\n *\n * Keeping it dead-simple — no return-value transformation, no async, no\n * exit-code override. Subcommands that want a different exit policy\n * shouldn't use this helper.\n */\n\nimport * as p from '@clack/prompts';\n\nexport function unwrap<T>(value: T | symbol): T {\n if (p.isCancel(value)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n return value;\n}\n","/**\n * GitHub helpers used by `create-op-node init`.\n *\n * Every call goes through Octokit (REST) authenticated with the operator's\n * `--gh-token` PAT — a single identity for the whole flow (create-from-\n * template, content write, PR open, and Actions-secret seeding). Secret\n * seeding uses the `actions.getRepoPublicKey` + `createOrUpdateRepoSecret`\n * endpoints, encrypting the value with the repo's libsodium public key\n * (`crypto_box_seal`) before PUT, per GitHub's API contract.\n *\n * The Octokit instance is created lazily so a missing token surfaces as a\n * clear error rather than a cryptic auth failure inside a downstream call.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport _sodium from 'libsodium-wrappers';\n\nexport interface GhAuth {\n /** A GitHub Personal Access Token (Classic or Fine-grained) with at least\n * `repo` scope. */\n token: string;\n}\n\n// One Octokit per token — fine for a one-shot CLI. NOT safe to wire into a\n// long-running service that issues calls under different identities; the\n// memoization will hand out the wrong client. If that ever happens, key the\n// cache by (token, …other-dimensions) or drop the memoization.\nlet _client: Octokit | null = null;\nlet _clientToken: string | null = null;\n\nfunction client(token: string): Octokit {\n if (_client && _clientToken === token) return _client;\n _client = new Octokit({ auth: token });\n _clientToken = token;\n return _client;\n}\n\n// Test-only: reset the memoized client between cases. Not exported via\n// index, intentionally — tests reach into the module.\nexport function _resetClient(): void {\n _client = null;\n _clientToken = null;\n}\n\n// ----------------------------------------------------------------------------\n// Create from template\n// ----------------------------------------------------------------------------\n\nexport interface CreateFromTemplateInput extends GhAuth {\n /** `<owner>/<repo>` of the template repo, e.g. `OpusPopuli/opuspopuli-node`. */\n template: string;\n /** The new repo's owner (user or org). */\n owner: string;\n /** The new repo's name. */\n name: string;\n /** Optional repo description. */\n description?: string;\n /** When true, create the repo as private. Default: false (public). */\n private?: boolean;\n /** Include all template branches, not just default. Default: false. */\n includeAllBranches?: boolean;\n}\n\nexport interface CreatedRepo {\n fullName: string;\n htmlUrl: string;\n defaultBranch: string;\n}\n\n/**\n * Create a new repository from a template repository. Wraps\n * `POST /repos/{template_owner}/{template_repo}/generate`.\n *\n * Caller should handle \"repository already exists\" as a recoverable case —\n * the operator may have started + abandoned a previous run. We throw on the\n * 422 (already exists) so the caller can show a \"use existing? overwrite?\"\n * prompt.\n */\nexport async function createRepoFromTemplate(\n input: CreateFromTemplateInput,\n): Promise<CreatedRepo> {\n const [templateOwner, templateRepo] = input.template.split('/');\n if (!templateOwner || !templateRepo) {\n throw new Error(`Bad template spec \"${input.template}\" — expected <owner>/<repo>`);\n }\n\n const res = await client(input.token).request(\n 'POST /repos/{template_owner}/{template_repo}/generate',\n {\n template_owner: templateOwner,\n template_repo: templateRepo,\n owner: input.owner,\n name: input.name,\n private: input.private ?? false,\n include_all_branches: input.includeAllBranches ?? false,\n ...(input.description ? { description: input.description } : {}),\n },\n );\n\n return {\n fullName: res.data.full_name,\n htmlUrl: res.data.html_url,\n defaultBranch: res.data.default_branch ?? 'main',\n };\n}\n\n/**\n * Look up a repository's default branch. Used when `init` adopts a\n * pre-existing repo (the create-from-template path already gets it from the\n * generate response) so branch/PR operations target the branch that actually\n * exists rather than assuming `main`. Returns `null` on a malformed slug or\n * any API failure, so the caller can fall back deliberately. (#41)\n */\nexport async function getRepoDefaultBranch(input: {\n token: string;\n repo: string;\n}): Promise<string | null> {\n const parsed = parseRepoSlug(input.repo);\n if (!parsed) return null;\n try {\n const res = await client(input.token).repos.get({ owner: parsed.owner, repo: parsed.repo });\n return res.data.default_branch ?? null;\n } catch {\n return null;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Seed repository Actions secrets via the GitHub API (Octokit + libsodium)\n// ----------------------------------------------------------------------------\n\nexport interface SetRepoSecretsInput {\n /** PAT used for the whole `init` flow — needs Actions Secrets: write\n * (fine-grained) or `repo` scope (classic). */\n token: string;\n /** `<owner>/<repo>`. */\n repo: string;\n /** Secrets to seed, in order. Values are encrypted with the repo public key\n * before they leave the process — plaintext never lands in argv or on the\n * wire. */\n secrets: ReadonlyArray<{ name: string; value: string }>;\n}\n\nexport interface SetRepoSecretsResult {\n /** Secret names successfully written, in order. */\n seeded: string[];\n /** Set when a secret failed; seeding stops at the first failure (so `seeded`\n * is the prefix that succeeded and the rest are pending). */\n failed?: { name: string; reason: string };\n}\n\nfunction parseRepoSlug(repo: string): { owner: string; repo: string } | null {\n const slash = repo.indexOf('/');\n if (slash <= 0 || slash === repo.length - 1 || repo.indexOf('/', slash + 1) !== -1) return null;\n return { owner: repo.slice(0, slash), repo: repo.slice(slash + 1) };\n}\n\n/**\n * Seed repository Actions secrets via the GitHub API, authenticated with the\n * operator's PAT (single identity for the whole flow — no `gh` CLI / ambient\n * auth). GitHub requires each value to be sealed-box encrypted with the repo's\n * public key (`crypto_box_seal`); we fetch that key **once** and reuse it for\n * every secret. `createOrUpdateRepoSecret` is idempotent, so a re-run\n * overwrites cleanly. Stops at the first failure and reports what was seeded.\n */\nexport async function setRepoSecrets(input: SetRepoSecretsInput): Promise<SetRepoSecretsResult> {\n const firstName = input.secrets[0]?.name ?? '(none)';\n const parsed = parseRepoSlug(input.repo);\n if (!parsed) {\n return {\n seeded: [],\n failed: { name: firstName, reason: `invalid repo \"${input.repo}\" (expected <owner>/<repo>)` },\n };\n }\n const { owner, repo } = parsed;\n const octokit = client(input.token);\n\n let key: Awaited<ReturnType<typeof octokit.actions.getRepoPublicKey>>;\n try {\n key = await octokit.actions.getRepoPublicKey({ owner, repo });\n } catch (err) {\n return {\n seeded: [],\n failed: { name: firstName, reason: `fetching the repo public key failed: ${(err as Error).message}` },\n };\n }\n\n await _sodium.ready;\n const sodium = _sodium;\n const publicKey = sodium.from_base64(key.data.key, sodium.base64_variants.ORIGINAL);\n\n const seeded: string[] = [];\n for (const s of input.secrets) {\n const encrypted_value = sodium.to_base64(\n sodium.crypto_box_seal(sodium.from_string(s.value), publicKey),\n sodium.base64_variants.ORIGINAL,\n );\n try {\n await octokit.actions.createOrUpdateRepoSecret({\n owner,\n repo,\n secret_name: s.name,\n encrypted_value,\n key_id: key.data.key_id,\n });\n } catch (err) {\n return { seeded, failed: { name: s.name, reason: `setting secret ${s.name} failed: ${(err as Error).message}` } };\n }\n seeded.push(s.name);\n }\n return { seeded };\n}\n\n// ----------------------------------------------------------------------------\n// Content write + PR open\n// ----------------------------------------------------------------------------\n\nexport interface CommitFileInput extends GhAuth {\n /** `<owner>/<repo>`. */\n repo: string;\n /** Branch to commit on. The caller creates the branch first via\n * `createBranch` when committing to a non-default branch. */\n branch: string;\n /** Repo-relative path (e.g. `infra/cloudflare/environments/prod.tfvars`). */\n path: string;\n /** File contents, plain text. We base64-encode for the API. */\n content: string;\n /** Commit message. */\n message: string;\n}\n\nexport interface CommitFileResult {\n commitSha: string;\n contentSha: string;\n}\n\n/**\n * Create or update a file in a repo's branch via the Contents API. Handles\n * both cases transparently — looks up the existing file's SHA when present\n * and includes it in the update.\n */\nexport async function commitFile(input: CommitFileInput): Promise<CommitFileResult> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n\n const octokit = client(input.token);\n\n let existingSha: string | undefined;\n try {\n const existing = await octokit.repos.getContent({\n owner,\n repo,\n path: input.path,\n ref: input.branch,\n });\n if (!Array.isArray(existing.data) && existing.data.type === 'file') {\n existingSha = existing.data.sha;\n }\n } catch (err: unknown) {\n // 404 is fine — file just doesn't exist yet. Re-throw anything else.\n if (!is404(err)) throw err;\n }\n\n const res = await octokit.repos.createOrUpdateFileContents({\n owner,\n repo,\n path: input.path,\n branch: input.branch,\n message: input.message,\n content: Buffer.from(input.content, 'utf8').toString('base64'),\n ...(existingSha ? { sha: existingSha } : {}),\n });\n\n return {\n commitSha: res.data.commit.sha ?? '',\n contentSha: res.data.content?.sha ?? '',\n };\n}\n\nfunction is404(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'status' in err &&\n (err as { status: number }).status === 404\n );\n}\n\nexport interface CreateBranchInput extends GhAuth {\n repo: string;\n /** Name of the new branch. */\n branch: string;\n /** Name of the branch to fork from. */\n fromBranch: string;\n}\n\n/** Create a new branch by copying the head commit of `fromBranch`. */\nexport async function createBranch(input: CreateBranchInput): Promise<void> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n const octokit = client(input.token);\n\n const ref = await octokit.git.getRef({\n owner,\n repo,\n ref: `heads/${input.fromBranch}`,\n });\n await octokit.git.createRef({\n owner,\n repo,\n ref: `refs/heads/${input.branch}`,\n sha: ref.data.object.sha,\n });\n}\n\nexport interface OpenPrInput extends GhAuth {\n repo: string;\n /** Branch to merge from. */\n head: string;\n /** Branch to merge into. */\n base: string;\n title: string;\n body: string;\n}\n\nexport interface OpenedPr {\n number: number;\n htmlUrl: string;\n}\n\n/** Open a pull request. Returns the PR number + URL so the caller can show\n * it to the operator. */\nexport async function openPullRequest(input: OpenPrInput): Promise<OpenedPr> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n const octokit = client(input.token);\n\n const res = await octokit.pulls.create({\n owner,\n repo,\n head: input.head,\n base: input.base,\n title: input.title,\n body: input.body,\n });\n\n return { number: res.data.number, htmlUrl: res.data.html_url };\n}\n","/**\n * Small pure helpers for the local-state-only bits of `create-op-node init`:\n * generating a fresh pgsodium master key, and rendering a region's\n * `prod.tfvars` file.\n *\n * Both are side-effect free — they produce strings the caller decides what to\n * do with. Tests exercise them in isolation.\n */\n\nimport { createHmac, randomBytes } from 'node:crypto';\n\n/**\n * Generate a 32-byte (256-bit) key encoded as 64 lowercase hex characters —\n * the format `pgsodium` expects in `PGSODIUM_ROOT_KEY` and what the runbook\n * documents. The bytes come from Node's CSPRNG.\n */\nexport function generatePgsodiumRootKey(): string {\n return randomBytes(32).toString('hex');\n}\n\n/**\n * url-safe base64 helper (RFC 4648 §5) — the JWT spec mandates this variant\n * (no `+`, no `/`, no padding). `Buffer#toString('base64url')` exists on\n * Node ≥ 16 but expressing it locally keeps the dependency surface tiny and\n * avoids type-coverage games across older `@types/node`.\n */\nfunction base64url(input: Buffer | string): string {\n const buf = typeof input === 'string' ? Buffer.from(input) : input;\n return buf\n .toString('base64')\n // base64 padding `=` only ever appears at the end, so stripping every `=`\n // is equivalent to `/=+$/` and avoids the anchored-quantifier backtracking.\n .replace(/=/g, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_');\n}\n\n/**\n * 32-byte CSPRNG password rendered as base64url (no `+`, no `/`, no `=`).\n * Used for POSTGRES_PASSWORD — every Supabase admin user (supabase_admin,\n * authenticator, pgbouncer, supabase_auth_admin, supabase_functions_admin,\n * supabase_storage_admin) shares this one password by design of the\n * upstream init scripts.\n *\n * MUST be URL-safe: the value lands in postgres:// connection-string URIs\n * inside docker-compose env vars (gotrue, postgrest, storage). libpq parses\n * those as RFC 3986 URIs, so `/` would terminate the password component and\n * `+`/`=` are reserved sub-delims that can confuse some URI parsers. base64url\n * keeps the alphabet to `[A-Za-z0-9_-]` which is unambiguously safe in every\n * URI component.\n *\n * 32 bytes → 256 bits of entropy. The base64url encoding is ~43 chars (no\n * padding) — well above what any offline attack on a bcrypt store could\n * threaten.\n */\nexport function generatePostgresPassword(): string {\n return base64url(randomBytes(32));\n}\n\n/** Alias for clarity at the call site. Also base64url so it composes safely\n * into kong's declarative config (where DASHBOARD_PASSWORD is interpolated). */\nexport function generateDashboardPassword(): string {\n return base64url(randomBytes(24));\n}\n\n/**\n * 32-byte CSPRNG HMAC key rendered as base64url. Used for the prompt-service\n * client HMAC: prompt-service's `API_KEYS` env is a comma-separated list of\n * `<region>:<key>` pairs, and the consuming backend sends the same `<key>`\n * value in its HMAC header.\n *\n * Base64url alphabet ensures the value survives the `<region>:<key>` join\n * and any URL-component embedding without ambiguity.\n */\nexport function generateHmacApiKey(): string {\n return base64url(randomBytes(32));\n}\n\n/**\n * 32-byte CSPRNG HMAC secret rendered as base64url. Used for\n * `GATEWAY_HMAC_SECRET` — the shared secret the API Gateway signs\n * gateway→microservice requests with (X-HMAC-Auth). The same value is\n * JSON-wrapped into `API_KEYS` as `{\"api-gateway\":\"<this>\"}` so each\n * microservice accepts the gateway's signature.\n *\n * MUST replace the template's well-known compose default\n * (WELL_KNOWN_GATEWAY_HMAC_SECRET) on any node exposed via the Cloudflare\n * Tunnel — every checkout of the template ships that identical placeholder.\n *\n * Base64url alphabet (`[A-Za-z0-9_-]`) keeps the value safe to embed inside\n * the `API_KEYS` JSON string without escaping and inside HTTP headers.\n */\nexport function generateGatewayHmacSecret(): string {\n return base64url(randomBytes(32));\n}\n\n/**\n * Render the `API_KEYS` env value from a `GATEWAY_HMAC_SECRET`. The backend\n * microservices read `API_KEYS` as a JSON object mapping caller name → key;\n * the api-gateway's key MUST equal `GATEWAY_HMAC_SECRET` so the gateway's\n * HMAC signature verifies. `JSON.stringify` handles any escaping (the\n * base64url alphabet never needs it, but this keeps the contract explicit).\n */\nexport function renderApiKeys(gatewayHmacSecret: string): string {\n return JSON.stringify({ 'api-gateway': gatewayHmacSecret });\n}\n\n/**\n * 24-byte CSPRNG password rendered as base64url. Used for\n * `GRAFANA_ADMIN_PASSWORD` — overrides Grafana's `admin`/`admin` compose\n * default. Grafana is bound to loopback by default but the runbook's Phase 10\n * exposes it via the Tunnel, so a real value matters there. base64url keeps\n * it free of shell/URL metacharacters for the op-compose wrapper export.\n */\nexport function generateGrafanaAdminPassword(): string {\n return base64url(randomBytes(24));\n}\n\n/**\n * 48-byte (384-bit) base64 secret used to sign every Supabase-issued JWT.\n *\n * gotrue, postgrest, storage, and studio all verify tokens against this\n * value, so it must stay identical across the stack and across restarts.\n * Treat it like a master key — rotating it invalidates every session and\n * every long-lived ANON/SERVICE_ROLE token derived from it.\n */\nexport function generateJwtSecret(): string {\n return randomBytes(48).toString('base64');\n}\n\nexport type SupabaseRole = 'anon' | 'service_role';\n\nexport interface SupabaseJwtInput {\n role: SupabaseRole;\n /** HS256 signing key — same JWT_SECRET that gotrue/postgrest verify with. */\n secret: string;\n /** `iat` claim, seconds since epoch. Defaults to 1700000000 (2023-11-14)\n * — a stable past timestamp. This is deliberate, not a test artifact:\n * bootstrap re-runs generate the SAME token shape so we don't churn\n * the cached Keychain entry on every invocation. Pass `Date.now()/1000`\n * if you need a fresh `iat` (e.g. tests that exercise expiry handling). */\n issuedAtSeconds?: number;\n /** Token lifetime in seconds. Default: 10 years — Supabase's own\n * self-hosting docs ship `exp = iat + 10y` for the long-lived\n * anon + service_role keys. */\n ttlSeconds?: number;\n /** `iss` claim. Default: `supabase`. */\n issuer?: string;\n}\n\n/**\n * Verify that a stored JWT's signature was produced by the given secret.\n *\n * Constant-time-ish compare via Buffer length + manual byte loop — the\n * tokens are short and rare enough that the timing channel here doesn't\n * meaningfully advantage an attacker (and the attacker would need to be\n * able to feed bootstrap arbitrary candidate tokens, which they can't).\n *\n * Use case: bootstrap loaded supabase-anon-key from Keychain, but JWT_SECRET\n * may have rotated since. If the cached token's signature doesn't match the\n * current secret, we treat it as stale and regenerate. Without this check,\n * a partial Keychain wipe (e.g. operator deletes only jwt-secret) leaves\n * the derived tokens looking valid by shape but useless against gotrue/\n * postgrest, and every auth call silently fails 401.\n */\nexport function verifySupabaseJwt(token: string, secret: string): boolean {\n const parts = token.split('.');\n if (parts.length !== 3) return false;\n const [h, p, sig] = parts as [string, string, string];\n const expected = base64url(createHmac('sha256', secret).update(`${h}.${p}`).digest());\n if (sig.length !== expected.length) return false;\n let mismatch = 0;\n for (let i = 0; i < sig.length; i++) {\n mismatch |= sig.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return mismatch === 0;\n}\n\n/**\n * Mint a Supabase-shaped HS256 JWT for the `anon` or `service_role` claim.\n *\n * Shape matches what the official `supabase` CLI / hosted-Supabase docs\n * produce, so the token works with @supabase/supabase-js, postgrest's\n * `Authorization: Bearer …`, storage-api, and Studio out of the box.\n *\n * No third-party JWT lib — we'd have to add `jsonwebtoken` (+ its CVE\n * history) for ~30 lines of HMAC code. Implementing it here keeps the\n * dep tree clean and the algorithm pinned to HS256 by construction.\n */\nexport function signSupabaseJwt(input: SupabaseJwtInput): string {\n const iat = input.issuedAtSeconds ?? 1_700_000_000;\n const ttl = input.ttlSeconds ?? 10 * 365 * 24 * 60 * 60;\n const issuer = input.issuer ?? 'supabase';\n\n const header = { alg: 'HS256', typ: 'JWT' };\n const payload = {\n role: input.role,\n iss: issuer,\n iat,\n exp: iat + ttl,\n };\n\n const encodedHeader = base64url(JSON.stringify(header));\n const encodedPayload = base64url(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = base64url(\n createHmac('sha256', input.secret).update(signingInput).digest(),\n );\n return `${signingInput}.${signature}`;\n}\n\nexport interface ProdTfvarsInput {\n /** Resource-name prefix used across the Terraform module\n * (e.g. `<project>-tunnel-prod`). Defaults to `opuspopuli`. */\n project?: string;\n /** Operator's registered domain in Cloudflare (e.g. `civicfeed.tx`). */\n domain: string;\n /** Subdomain for the API tunnel (e.g. `api`). Default: `api`. */\n apiSubdomain?: string;\n /** Subdomain for the Cloudflare Pages frontend (e.g. `app`). Default: `app`. */\n appSubdomain?: string;\n /** Local port the API Gateway listens on inside the Studio. Default: 8080. */\n tunnelApiPort?: number;\n /** R2 region hint. Default: `WNAM` (Western North America). */\n r2LocationHint?: string;\n}\n\n/**\n * Render a region operator's `prod.tfvars` from their answers. Mirrors the\n * shape of `opuspopuli-node/infra/cloudflare/environments/prod.tfvars.example`\n * so the file lands ready for the cloudflare-infra workflow without any\n * post-processing.\n *\n * The output is the literal file contents — caller writes it to the repo via\n * the GitHub Contents API (`commitFile`).\n */\nexport function renderProdTfvars(input: ProdTfvarsInput): string {\n const project = input.project ?? 'opuspopuli';\n const api = input.apiSubdomain ?? 'api';\n const app = input.appSubdomain ?? 'app';\n const port = input.tunnelApiPort ?? 8080;\n const r2 = input.r2LocationHint ?? 'WNAM';\n\n return `# =============================================================================\n# Production environment — generated by create-op-node init\n# =============================================================================\n# Region-specific values for the OpusPopuli/opuspopuli-node template's\n# infra/cloudflare/ Terraform. Edit by hand to tweak.\n\nproject = ${JSON.stringify(project)}\n\ndomain_name = ${JSON.stringify(input.domain)}\n\napi_subdomain = ${JSON.stringify(api)}\napp_subdomain = ${JSON.stringify(app)}\n\ntunnel_api_port = ${port}\n\nr2_location_hint = ${JSON.stringify(r2)}\n\nenable_tunnel = true\nenable_frontend = true\nenable_r2 = true\n`;\n}\n","/**\n * Generic two-phase TFC apply-and-output wait. Two independent clocks:\n *\n * 1. **Discovery phase** — wait for the workspace to have a current run.\n * The cloudflare-infra workflow takes a few seconds to dispatch to TFC\n * after the operator merges the PR, so we re-poll the workspace until\n * a run id appears or the discovery budget elapses.\n * 2. **Run phase** — wait for that run to reach a terminal state. Sharing\n * one clock with discovery would let slow discovery eat the run-wait\n * budget; two independent clocks isolate them.\n *\n * Dependencies are injected so unit tests can drive the loop without real\n * timers or HTTP. `sleep` is a parameter; tests pass a no-op.\n */\n\nimport { fetchOutput, findWorkspace, getRunStatus, type OutputResult } from './tfc.js';\n\nexport interface WaitInput {\n token: string;\n organization: string;\n workspaceId: string;\n /** Last-known run id when starting. `null` triggers the discovery phase. */\n runId: string | null;\n /** Tags used to re-discover the workspace's current run id. */\n workspaceTags: string[];\n /** Output to pull once the run is `applied`. */\n outputName: string;\n}\n\nexport interface WaitBudgets {\n discoveryMs: number;\n runMs: number;\n pollMs: number;\n}\n\nexport const DEFAULT_BUDGETS: WaitBudgets = {\n discoveryMs: 60 * 1000,\n runMs: 10 * 60 * 1000,\n pollMs: 10 * 1000,\n};\n\nexport type WaitOutcome =\n | { kind: 'success'; value: string }\n | { kind: 'output-missing' }\n | { kind: 'no-run-started' }\n | { kind: 'run-failed'; status: string }\n | { kind: 'timeout' };\n\n/** Test seam: lets tests inject fake findWorkspace / getRunStatus / fetchOutput. */\nexport interface WaitDeps {\n findWorkspace: typeof findWorkspace;\n getRunStatus: typeof getRunStatus;\n fetchOutput: typeof fetchOutput;\n sleep: (ms: number) => Promise<void>;\n now: () => number;\n /** Optional progress callback for UI integration (spinner messages, etc.). */\n onProgress?: (phase: 'discovery' | 'run' | 'fetching' | 'retry') => void;\n}\n\nexport const realDeps: WaitDeps = {\n findWorkspace,\n getRunStatus,\n fetchOutput,\n sleep: (ms) => new Promise((res) => setTimeout(res, ms)),\n now: () => Date.now(),\n};\n\n/**\n * Pure polling implementation. Returns a discriminated outcome so the caller\n * can render the right message for each terminal state.\n */\nexport async function waitForApply(\n input: WaitInput,\n budgets: WaitBudgets = DEFAULT_BUDGETS,\n deps: WaitDeps = realDeps,\n): Promise<WaitOutcome> {\n let runId = input.runId;\n if (!runId) {\n runId = await discoverRunId(input, budgets, deps);\n if (!runId) return { kind: 'no-run-started' };\n }\n return waitForRunOutput(input, budgets, deps, runId);\n}\n\n// Run a single poll attempt, degrading any throw to `null` (treated as \"no\n// result this interval, try again\"). Keeps a transient network failure from\n// rejecting out of the multi-minute wait loops. `onRetry` fires on a swallowed\n// throw so the caller can surface the hiccup instead of retrying in silence.\nasync function safePoll<T>(\n fn: () => Promise<T | null>,\n onRetry?: () => void,\n): Promise<T | null> {\n try {\n return await fn();\n } catch {\n onRetry?.();\n return null;\n }\n}\n\n// Phase 1: discovery — poll the workspace until it has a current run, or the\n// discovery budget expires. Returns the run id, or null on timeout.\nasync function discoverRunId(\n input: WaitInput,\n budgets: WaitBudgets,\n deps: WaitDeps,\n): Promise<string | null> {\n deps.onProgress?.('discovery');\n const discoveryStart = deps.now();\n // Check first, THEN sleep: a run that already exists is found at t=0 rather\n // than a poll-interval late, and findWorkspace always runs at least once\n // regardless of the pollMs/discoveryMs ratio. (#35)\n while (deps.now() - discoveryStart < budgets.discoveryMs) {\n // A transient failure is not fatal to a multi-minute discovery window —\n // swallow it and retry on the next poll rather than rejecting the wait.\n // (The tfc helpers already degrade throws to null, so this is\n // belt-and-suspenders against any future throwing dep.)\n const ws = await safePoll(\n () =>\n deps.findWorkspace({\n token: input.token,\n organization: input.organization,\n tags: input.workspaceTags,\n }),\n () => deps.onProgress?.('retry'),\n );\n if (ws?.currentRunId) return ws.currentRunId;\n await deps.sleep(budgets.pollMs);\n }\n return null;\n}\n\n// Phase 2: run wait — poll the run until it finishes (fetching the output on\n// success), or the run budget expires.\nasync function waitForRunOutput(\n input: WaitInput,\n budgets: WaitBudgets,\n deps: WaitDeps,\n runId: string,\n): Promise<WaitOutcome> {\n deps.onProgress?.('run');\n const runStart = deps.now();\n while (deps.now() - runStart < budgets.runMs) {\n // Transient status-poll failure → retry next interval, don't abort the\n // ~10-minute run wait on a single bad packet.\n const r = await safePoll(\n () => deps.getRunStatus({ token: input.token, organization: input.organization }, runId),\n () => deps.onProgress?.('retry'),\n );\n if (r?.finished) {\n if (!r.succeeded) return { kind: 'run-failed', status: r.status };\n const out = await tryFetchOutput(input, deps);\n if (out.kind === 'value') return { kind: 'success', value: out.value };\n if (out.kind === 'absent') return { kind: 'output-missing' };\n // out.kind === 'error': a transient failure fetching the output of an\n // already-applied run. Don't misreport it as output-missing — fall\n // through, sleep, and retry within the remaining run budget. (#59)\n }\n await deps.sleep(budgets.pollMs);\n }\n\n return { kind: 'timeout' };\n}\n\n// Fetch the output once, normalizing a thrown/degraded call into the same\n// `error` case fetchOutput already uses for a non-200 — so the run loop has a\n// single retryable signal. `onProgress('retry')` fires on a transient error so\n// the UI can show the hiccup instead of stalling silently. (#59)\nasync function tryFetchOutput(input: WaitInput, deps: WaitDeps): Promise<OutputResult> {\n deps.onProgress?.('fetching');\n const out = await safePoll(\n () =>\n deps.fetchOutput(\n { token: input.token, organization: input.organization },\n input.workspaceId,\n input.outputName,\n ),\n () => deps.onProgress?.('retry'),\n );\n if (out === null) return { kind: 'error' }; // safePoll swallowed a throw\n if (out.kind === 'error') deps.onProgress?.('retry');\n return out;\n}\n","import { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { probeCloudflareToken } from '../lib/cloudflare.js';\nimport { probeTfcToken } from '../lib/tfc.js';\nimport { detectKeychain, readSecret, saveSecret } from '../lib/keychain.js';\nimport { safeExeca } from '../lib/exec.js';\nimport { unwrap } from '../lib/prompts.js';\nimport {\n commitFile,\n createBranch,\n createRepoFromTemplate,\n getRepoDefaultBranch,\n openPullRequest,\n setRepoSecrets,\n} from '../lib/github.js';\nimport { generatePgsodiumRootKey, renderProdTfvars } from '../lib/secrets.js';\nimport { findWorkspace } from '../lib/tfc.js';\nimport { waitForApply, realDeps as realWaitDeps } from '../lib/polling.js';\n\nexport interface InitOptions {\n domain?: string;\n region?: string;\n owner?: string;\n template?: string;\n project?: string;\n cfToken?: string;\n cfAccount?: string;\n cfZone?: string;\n tfToken?: string;\n tfOrg?: string;\n ghToken?: string;\n overwrite?: boolean;\n useExistingRepo?: boolean;\n skipWait?: boolean;\n localOnly?: boolean;\n yes?: boolean;\n}\n\n/** Pull the GitHub token from `gh auth token` if the CLI is signed in. Lets\n * operators who use `gh` skip pasting their PAT. Returns null cleanly when\n * `gh` isn't installed or isn't signed in. */\nasync function ghTokenFromCli(): Promise<string | null> {\n const r = await safeExeca('gh', ['auth', 'token']);\n if (r === null || r.exitCode !== 0) return null;\n const token = r.stdout.trim();\n return token.length > 0 ? token : null;\n}\n\nexport const initCommand = new Command('init')\n .description(\n 'Stand up the node repo + Cloudflare infrastructure for a new region. Run this on your laptop.',\n )\n .addOption(new Option('--domain <domain>', 'Your registered domain (e.g. example.org)'))\n .addOption(new Option('--region <slug>', 'Short label for your region (e.g. us-ca)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the new node repo').default('OpusPopuli'))\n .addOption(\n new Option('--template <owner/repo>', 'Template repo to clone from').default(\n 'OpusPopuli/opuspopuli-node',\n ),\n )\n .addOption(new Option('--project <name>', 'tfvars project prefix').default('opuspopuli'))\n .addOption(new Option('--cf-token <token>', 'Cloudflare Account API token').env('CF_TOKEN'))\n .addOption(new Option('--cf-account <id>', 'Cloudflare account ID').env('CF_ACCOUNT'))\n .addOption(new Option('--cf-zone <id>', 'Cloudflare zone ID for your domain').env('CF_ZONE'))\n .addOption(new Option('--tf-token <token>', 'Terraform Cloud user/team token').env('TF_API_TOKEN'))\n .addOption(new Option('--tf-org <org>', 'Terraform Cloud organization').env('TF_CLOUD_ORGANIZATION'))\n .addOption(new Option('--gh-token <token>', 'GitHub Personal Access Token (else gh CLI)').env('GH_TOKEN'))\n .addOption(\n new Option(\n '--overwrite',\n 'Overwrite existing Keychain items (pgsodium key, Tunnel token) on a re-run',\n ).default(false),\n )\n .addOption(\n new Option(\n '--use-existing-repo',\n \"Continue using a previously-created node repo (don't fail on 'already exists')\",\n ).default(false),\n )\n .addOption(new Option('--skip-wait', \"Don't poll for Terraform apply; exit after PR open\").default(false))\n .addOption(\n new Option(\n '--local-only',\n 'Skip the Cloudflare/TFC/PR/tunnel phases. Creates the region repo from template + stores a pgsodium key — enough for `bootstrap --local-only` to work.',\n ).default(false),\n )\n .addOption(new Option('-y, --yes', 'Skip the final confirmation').default(false))\n .action(async (opts: InitOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node init ')));\n printWelcomeNote(opts);\n\n const region = await resolveRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const newRepoName = `opuspopuli-node-${region}`;\n const newRepoFull = `${owner}/${newRepoName}`;\n warnIgnoredLocalOnlyFlags(opts);\n\n // Collect domain + Cloudflare + TFC creds when running in production mode.\n // Returns null in --local-only — downstream branches on this once and the\n // typed presence carries through (no non-null assertions). (S1)\n const publicConfig = opts.localOnly ? null : await collectPublicConfig(opts);\n const ghToken = await resolveGhToken(opts);\n const keychain = await detectKeychain();\n printSecretStoreNote(keychain);\n\n await confirmPlan({ opts, region, owner, newRepoFull, publicConfig });\n\n const created = await createRegionRepo({ opts, ghToken, owner, newRepoName, newRepoFull, region });\n if (publicConfig) {\n await seedRepoSecrets({ ghToken, publicConfig, newRepoFull });\n }\n const pr = publicConfig\n ? await openInfraPr({ opts, ghToken, region, newRepoFull, publicConfig, created })\n : null;\n\n await persistPgsodiumKey({ keychain, opts, region });\n\n // Local-only flow ends here. Gating on publicConfig (not opts.localOnly)\n // lets TS narrow it to non-null for the TFC poll block below.\n if (!publicConfig) {\n printLocalOnlyOutro({ region, newRepoFull });\n return;\n }\n if (!pr) {\n throw new Error('init: PR creation step did not run despite publicConfig present');\n }\n\n const proceed = await pauseForMerge({ pr, opts });\n if (!proceed) return;\n\n const tunnelToken = await fetchTunnelToken({ publicConfig });\n await persistTunnelToken({ keychain, region, tunnelToken });\n printDoneOutro(region);\n });\n\n// ----------------------------------------------------------------------------\n// Init phases\n// ----------------------------------------------------------------------------\n// The command action delegates to these phase helpers so no single function\n// exceeds the cognitive-complexity budget. Each is behavior-preserving — the\n// interactive prompts, spinners, and process.exit calls are relocated\n// verbatim, restructured only with early returns to flatten nesting.\n\nfunction printWelcomeNote(opts: InitOptions): void {\n p.note(\n opts.localOnly\n ? [\n 'Local-only setup — creates the region repo from template + a pgsodium key.',\n 'No Cloudflare, no Terraform Cloud, no public exposure.',\n '',\n pc.dim('Phase 1: laptop side (now) — GitHub repo from template + Keychain.'),\n pc.dim('Phase 2: Studio side — `create-op-node bootstrap --local-only`.'),\n '',\n pc.dim('When you\\'re ready to expose publicly, re-run `init` without --local-only.'),\n ].join('\\n')\n : [\n 'This walks you from a sealed Mac Studio + a Cloudflare account to a',\n 'live federation node serving traffic at api.<your-domain>.',\n '',\n pc.dim('Phase 1: laptop side (now) — Cloudflare, GitHub, Terraform Cloud.'),\n pc.dim('Phase 2: Studio side — run `create-op-node bootstrap` on the Mac.'),\n ].join('\\n'),\n 'Welcome',\n );\n}\n\n// Region label (used as the Keychain service suffix + R2 prefix).\nasync function resolveRegion(opts: InitOptions): Promise<string> {\n return opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Short region label (used as the Keychain service suffix + R2 prefix)?',\n placeholder: 'us-ca',\n validate: (v) =>\n /^[a-z0-9-]{2,32}$/.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n}\n\n// Warn if the operator passed flags that don't apply to --local-only. They'd\n// otherwise be silently ignored and the operator would wonder why their\n// token/domain/etc. seemed to do nothing. (S2/S3)\nfunction warnIgnoredLocalOnlyFlags(opts: InitOptions): void {\n if (!opts.localOnly) return;\n const ignored = listIgnoredLocalOnlyFlags(opts);\n if (ignored.length === 0) return;\n p.note(\n pc.yellow(\n `⚠ The following ${ignored.length === 1 ? 'flag is' : 'flags are'} ignored with --local-only:\\n` +\n ` ${ignored.join(', ')}\\n` +\n pc.dim('These configure Cloudflare / TFC / PR-merge flow, which --local-only skips.'),\n ),\n 'Notice',\n );\n}\n\n// ---- GitHub auth: flag > signed-in gh CLI > paste prompt ----\nasync function resolveGhToken(opts: InitOptions): Promise<string> {\n let ghToken = opts.ghToken;\n if (!ghToken) {\n const fromCli = await ghTokenFromCli();\n if (fromCli) {\n const useCli = unwrap(\n await p.confirm({\n message: 'Found a signed-in `gh` CLI — use its token?',\n initialValue: true,\n }),\n );\n if (useCli) ghToken = fromCli;\n }\n }\n if (!ghToken) {\n ghToken = await collectSecret(\n undefined,\n 'GitHub Personal Access Token (repo scope)',\n 'github',\n );\n }\n return ghToken;\n}\n\nfunction printSecretStoreNote(keychain: Awaited<ReturnType<typeof detectKeychain>>): void {\n const kcNote = keychain.available\n ? `✓ macOS Keychain available — pgsodium key + Tunnel token will be saved to your login keychain.\\n` +\n pc.dim('Note: items don\\'t sync to iCloud Keychain via the security CLI.\\n') +\n pc.dim('On the Studio, bootstrap will read locally and prompt you to paste if missing.')\n : `⚠ ${keychain.reason ?? 'Keychain unavailable'}. Secrets will be printed for manual stash.`;\n p.note(kcNote, 'Secret store');\n}\n\n// ---- Plan summary + confirm ----\nasync function confirmPlan(args: {\n opts: InitOptions;\n region: string;\n owner: string;\n newRepoFull: string;\n publicConfig: PublicConfig | null;\n}): Promise<void> {\n const { opts, region, owner, newRepoFull, publicConfig } = args;\n const orgWriteAccess = pc.dim(`required for ${owner}`);\n p.note(\n opts.localOnly\n ? [\n `Region label: ${pc.cyan(region)}`,\n `New node repo: ${pc.cyan(newRepoFull)}`,\n `Template: ${pc.dim(opts.template ?? 'OpusPopuli/opuspopuli-node')}`,\n `GH org write access: ${orgWriteAccess}`,\n ``,\n `Will create the repo from template (private, no Cloudflare),`,\n `and store a fresh pgsodium key in Keychain. That's it — no PR,`,\n `no terraform, no tunnel token. Bootstrap on the Studio with`,\n `\\`bootstrap --local-only --region ${region}\\` next.`,\n ].join('\\n')\n : [\n `Region label: ${pc.cyan(region)}`,\n `Domain: ${pc.cyan(publicConfig?.domain ?? '')}`,\n `New node repo: ${pc.cyan(newRepoFull)}`,\n `Template: ${pc.dim(opts.template ?? 'OpusPopuli/opuspopuli-node')}`,\n `TFC organization: ${pc.cyan(publicConfig?.tfOrg ?? '')}`,\n `GH org write access: ${orgWriteAccess}`,\n ``,\n `Will create the repo, seed 5 secrets, write prod.tfvars on a branch,`,\n `open a PR, generate a fresh pgsodium key, and (after you merge) wait`,\n `for terraform apply to finish and retrieve the Tunnel token.`,\n ].join('\\n'),\n 'Plan',\n );\n\n if (opts.yes) return;\n const go = unwrap(await p.confirm({ message: 'Proceed?', initialValue: true }));\n if (!go) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n}\n\n// ---- Execute: create repo (idempotent on HTTP 422 already-exists) ----\nasync function createRegionRepo(args: {\n opts: InitOptions;\n ghToken: string;\n owner: string;\n newRepoName: string;\n newRepoFull: string;\n region: string;\n}): Promise<{ fullName: string; defaultBranch: string }> {\n const { opts, ghToken, owner, newRepoName, newRepoFull, region } = args;\n const repoSpin = p.spinner();\n repoSpin.start(`Creating ${newRepoFull} from ${opts.template}…`);\n try {\n const created = await createRepoFromTemplate({\n token: ghToken,\n template: opts.template ?? 'OpusPopuli/opuspopuli-node',\n owner,\n name: newRepoName,\n description: `Opus Populi node deployment for ${region}`,\n });\n repoSpin.stop(pc.green(`✓ Created ${created.fullName}`));\n return { fullName: created.fullName, defaultBranch: created.defaultBranch };\n } catch (err) {\n // The most likely re-run failure mode: the repo already exists from a\n // previous partial run. The GitHub API responds with HTTP 422 for that\n // case — status code is the API contract, message text isn't. Don't\n // regex on the message; it can change.\n const status =\n typeof err === 'object' && err !== null && 'status' in err\n ? (err as { status: number }).status\n : 0;\n const message = (err as Error).message ?? 'unknown error';\n\n if (status !== 422) {\n repoSpin.stop(pc.red(`✗ Couldn't create repo: ${message}`));\n p.cancel('Fix the issue and re-run.');\n process.exit(1);\n }\n\n repoSpin.stop(pc.yellow(`⚠ ${newRepoFull} already exists.`));\n const reuse =\n opts.useExistingRepo ||\n unwrap(\n await p.confirm({\n message: `Continue with the existing ${newRepoFull}? (Re-seeds secrets + re-commits prod.tfvars on a fresh branch.)`,\n initialValue: true,\n }),\n );\n if (!reuse) {\n p.cancel(\n `Delete ${newRepoFull} on GitHub and re-run, or pass --use-existing-repo to skip this prompt.`,\n );\n process.exit(0);\n }\n // Synthesize the same shape `createRepoFromTemplate` returns so the rest\n // of the flow doesn't care which path got us here. Query the repo's ACTUAL\n // default branch (it may not be `main` — older operator habit, org default)\n // so the branch + PR steps target a branch that exists. (#41)\n const fetched = await getRepoDefaultBranch({ token: ghToken, repo: newRepoFull });\n if (fetched === null) {\n p.note(\n pc.yellow(\n `⚠ Couldn't read ${newRepoFull}'s default branch — assuming \"main\". ` +\n 'If the branch/PR steps fail, check the repo\\'s default branch on GitHub.',\n ),\n 'Notice',\n );\n }\n return { fullName: newRepoFull, defaultBranch: fetched ?? 'main' };\n }\n}\n\n// ---- Execute: seed 5 repo secrets (production mode only) ----\nasync function seedRepoSecrets(args: {\n ghToken: string;\n publicConfig: PublicConfig;\n newRepoFull: string;\n}): Promise<void> {\n const { ghToken, publicConfig, newRepoFull } = args;\n const secrets: Array<{ name: string; value: string }> = [\n { name: 'CLOUDFLARE_API_TOKEN', value: publicConfig.cfToken },\n { name: 'CLOUDFLARE_ACCOUNT_ID', value: publicConfig.cfAccount },\n { name: 'CLOUDFLARE_ZONE_ID', value: publicConfig.cfZone },\n { name: 'TF_API_TOKEN', value: publicConfig.tfToken },\n { name: 'TF_CLOUD_ORGANIZATION', value: publicConfig.tfOrg },\n ];\n const secSpin = p.spinner();\n secSpin.start(`Seeding ${secrets.length} repo secrets…`);\n const { seeded, failed } = await setRepoSecrets({ token: ghToken, repo: newRepoFull, secrets });\n if (failed) {\n secSpin.stop(pc.red(`✗ Failed to set ${failed.name}: ${failed.reason}`));\n const remaining = secrets.slice(seeded.length).map((x) => x.name);\n p.cancel(\n [\n seeded.length > 0\n ? `Already seeded on ${newRepoFull}: ${seeded.join(', ')}.`\n : `Nothing seeded yet on ${newRepoFull}.`,\n `Still pending: ${remaining.join(', ')}.`,\n '',\n `Make sure your --gh-token PAT has \"Actions Secrets: write\" (fine-grained) or \\`repo\\` scope (classic).`,\n `Re-run with --use-existing-repo to retry (GitHub will overwrite the already-set secrets idempotently).`,\n ].join('\\n'),\n );\n process.exit(1);\n }\n secSpin.stop(pc.green(`✓ Seeded ${secrets.length} secrets on ${newRepoFull}`));\n}\n\n// ---- Execute: branch + tfvars + PR (production mode only) ----\n// Branch name is timestamped (ISO compact, UTC) so re-runs don't collide\n// with a leftover branch from a previous partial run.\nasync function openInfraPr(args: {\n opts: InitOptions;\n ghToken: string;\n region: string;\n newRepoFull: string;\n publicConfig: PublicConfig;\n created: { defaultBranch: string };\n}): Promise<Awaited<ReturnType<typeof openPullRequest>>> {\n const { opts, ghToken, region, newRepoFull, publicConfig, created } = args;\n const branch = `init/region-${region}-${isoStampUtc(new Date())}`;\n const setupSpin = p.spinner();\n setupSpin.start(`Writing prod.tfvars on branch ${branch}…`);\n try {\n await createBranch({\n token: ghToken,\n repo: newRepoFull,\n branch,\n fromBranch: created.defaultBranch,\n });\n const tfvars = renderProdTfvars({\n project: opts.project ?? 'opuspopuli',\n domain: publicConfig.domain,\n });\n await commitFile({\n token: ghToken,\n repo: newRepoFull,\n branch,\n path: 'infra/cloudflare/environments/prod.tfvars',\n content: tfvars,\n message: `init: prod.tfvars for ${region}`,\n });\n } catch (err) {\n setupSpin.stop(pc.red(`✗ Couldn't write tfvars: ${(err as Error).message}`));\n p.cancel('The repo exists but the branch / commit failed. Open it on GitHub and inspect.');\n process.exit(1);\n }\n setupSpin.stop(pc.green('✓ Wrote prod.tfvars'));\n\n const prSpin = p.spinner();\n prSpin.start('Opening pull request…');\n try {\n const pr = await openPullRequest({\n token: ghToken,\n repo: newRepoFull,\n head: branch,\n base: created.defaultBranch,\n title: `init: bring up region ${region}`,\n body: [\n `Initial region deployment for **${region}** (${publicConfig.domain}).`,\n '',\n 'Adds `infra/cloudflare/environments/prod.tfvars`. Merging this PR triggers',\n '`cloudflare-infra.yml` which runs `terraform apply` against the',\n `\\`${publicConfig.tfOrg}\\` Terraform Cloud organization, provisioning the Cloudflare`,\n 'Tunnel, DNS records, R2 buckets, and Pages project.',\n '',\n `Generated by \\`create-op-node init\\`.`,\n ].join('\\n'),\n });\n prSpin.stop(pc.green(`✓ Opened PR #${pr.number}`));\n return pr;\n } catch (err) {\n prSpin.stop(pc.red(`✗ Couldn't open PR: ${(err as Error).message}`));\n p.cancel('Branch + tfvars are committed; open the PR by hand on GitHub.');\n process.exit(1);\n }\n}\n\n// ---- pgsodium master key (read existing OR generate fresh) ----\n//\n// Three branches: Keychain hit + key present + no --overwrite → surface the\n// existing key; Keychain hit + missing/--overwrite → generate + save; no\n// Keychain → generate + print for manual stash.\nasync function persistPgsodiumKey(args: {\n keychain: Awaited<ReturnType<typeof detectKeychain>>;\n opts: InitOptions;\n region: string;\n}): Promise<void> {\n const { keychain, opts, region } = args;\n const pgsodiumCoords = { region, account: 'pgsodium-root-key' as const };\n const keyLabel = `org.opuspopuli.${region}/pgsodium-root-key`;\n\n if (!keychain.available) {\n const fresh = generatePgsodiumRootKey();\n await printKeyForManualSave(fresh, keyLabel);\n return;\n }\n\n const existing = opts.overwrite ? null : await readSecret(pgsodiumCoords);\n if (existing && /^[a-f0-9]{64}$/.test(existing)) {\n p.note(\n `${pc.green('✓')} Re-using existing pgsodium master key from Keychain (${pc.cyan(keyLabel)}). Pass --overwrite to rotate.`,\n 'Secret',\n );\n return;\n }\n\n const fresh = generatePgsodiumRootKey();\n const r = await saveSecret(pgsodiumCoords, fresh);\n if (r.written) {\n p.note(\n `${pc.green('✓')} pgsodium master key${r.updated ? ' rotated' : ' saved'} to Keychain as ${pc.cyan(keyLabel)}.`,\n 'Secret',\n );\n } else {\n await printKeyForManualSave(fresh, keyLabel, r.reason);\n }\n}\n\nfunction printLocalOnlyOutro(args: { region: string; newRepoFull: string }): void {\n const { region, newRepoFull } = args;\n p.outro(\n pc.cyan(\n [\n `Region ${region} provisioned for local-only mode.`,\n `Repo: https://github.com/${newRepoFull}`,\n ``,\n `Next: on the Studio (fresh or otherwise — bootstrap installs`,\n `brew packages it needs), run:`,\n ` npx create-op-node bootstrap --region ${region} --local-only`,\n ``,\n `When you're ready to expose publicly, re-run BOTH \\`init\\` and`,\n `\\`bootstrap\\` without --local-only. Same region repo + pgsodium key`,\n `promote cleanly to the production-shaped deploy.`,\n ].join('\\n'),\n ),\n );\n}\n\n// Pause for the operator to merge the infra PR. Returns false when the flow\n// should stop here (--skip-wait, or the operator hasn't merged yet).\nasync function pauseForMerge(args: {\n pr: { htmlUrl: string };\n opts: InitOptions;\n}): Promise<boolean> {\n const { pr, opts } = args;\n if (opts.skipWait) {\n p.outro(\n pc.cyan(\n `Review + merge ${pr.htmlUrl} when ready. Re-run with no --skip-wait or run \\`npx create-op-node verify\\` afterwards.`,\n ),\n );\n return false;\n }\n\n p.note(\n [\n `Open the PR: ${pc.cyan(pr.htmlUrl)}`,\n '',\n 'Review the `terraform plan` comment, then merge to main.',\n 'The workflow then runs `terraform apply` against Terraform Cloud.',\n ].join('\\n'),\n 'Next step: review + merge',\n );\n const merged = unwrap(await p.confirm({ message: 'PR merged?', initialValue: false }));\n if (!merged) {\n p.outro(\n pc.cyan(`No worries — re-run \\`create-op-node init --skip-wait\\` later to skip this step, or finish manually.`),\n );\n return false;\n }\n return true;\n}\n\n// ---- Poll TFC for apply completion + fetch the tunnel token ----\nasync function fetchTunnelToken(args: { publicConfig: PublicConfig }): Promise<string> {\n const { publicConfig } = args;\n const ws = await findWorkspace({\n token: publicConfig.tfToken,\n organization: publicConfig.tfOrg,\n tags: ['opuspopuli', 'cloudflare'],\n });\n if (!ws) {\n p.cancel(\n `Couldn't find a TFC workspace tagged opuspopuli + cloudflare in ${publicConfig.tfOrg}. ` +\n `Check the workflow's run log; the workspace is created on first apply.`,\n );\n process.exit(1);\n }\n\n const tunnelToken = await waitForApplyAndFetchTunnelToken({\n token: publicConfig.tfToken,\n organization: publicConfig.tfOrg,\n workspaceId: ws.id,\n runId: ws.currentRunId,\n });\n if (!tunnelToken) {\n p.cancel(\n `Terraform apply didn't produce a tunnel_token output. Check the run on TFC; if it succeeded, the output may be named differently — patch and re-run, or fetch via 'terraform output -raw tunnel_token'.`,\n );\n process.exit(1);\n }\n return tunnelToken;\n}\n\nasync function persistTunnelToken(args: {\n keychain: Awaited<ReturnType<typeof detectKeychain>>;\n region: string;\n tunnelToken: string;\n}): Promise<void> {\n const { keychain, region, tunnelToken } = args;\n const tunnelCoords = { region, account: 'tunnel-token' as const };\n const tunnelLabel = `org.opuspopuli.${region}/tunnel-token`;\n if (!keychain.available) {\n await printKeyForManualSave(tunnelToken, tunnelLabel);\n return;\n }\n const r = await saveSecret(tunnelCoords, tunnelToken);\n if (r.written) {\n p.note(\n `${pc.green('✓')} Tunnel token saved to Keychain as ${pc.cyan(tunnelLabel)}.`,\n 'Secret',\n );\n } else {\n await printKeyForManualSave(tunnelToken, tunnelLabel, r.reason);\n }\n}\n\nfunction printDoneOutro(region: string): void {\n p.outro(\n pc.cyan(\n `Region ${region} is provisioned. Next: \\`npx create-op-node bootstrap\\` on the Mac Studio.`,\n ),\n );\n}\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n/** Source-specific minimums — every real-world token from these issuers is\n * longer than the floor, so a short input is a typo or paste error. */\nconst MIN_TOKEN_LENGTH: Record<SecretKind, number> = {\n cloudflare: 40,\n tfc: 40,\n github: 40,\n generic: 20,\n};\n\ntype SecretKind = 'cloudflare' | 'tfc' | 'github' | 'generic';\n\n/** Pure description of which init phases will run given the operator's\n * flags. Useful for testing the flag-routing logic without touching the\n * action handler (which shells out to GH / Cloudflare / TFC). The action\n * uses the same `opts.localOnly` directly; this is a docs + test seam. */\nexport function summarizePhases(opts: Pick<InitOptions, 'localOnly'>): {\n cloudflareProbe: boolean;\n tfcProbe: boolean;\n seedSecrets: boolean;\n branchAndPR: boolean;\n tunnelTokenWait: boolean;\n} {\n const production = !opts.localOnly;\n return {\n cloudflareProbe: production,\n tfcProbe: production,\n seedSecrets: production,\n branchAndPR: production,\n tunnelTokenWait: production,\n };\n}\n\n/** Which production-only flags the operator passed but which won't be used\n * in `--local-only` mode. Surfaced as a warning so the operator knows their\n * --cf-token / --domain / etc. weren't silently swallowed. (review S2/S3) */\nexport function listIgnoredLocalOnlyFlags(opts: InitOptions): string[] {\n const ignored: string[] = [];\n if (opts.domain) ignored.push('--domain');\n if (opts.cfToken) ignored.push('--cf-token');\n if (opts.cfAccount) ignored.push('--cf-account');\n if (opts.cfZone) ignored.push('--cf-zone');\n if (opts.tfToken) ignored.push('--tf-token');\n if (opts.tfOrg) ignored.push('--tf-org');\n if (opts.skipWait) ignored.push('--skip-wait');\n return ignored;\n}\n\n/** All the inputs init needs when running the full production flow.\n * Returned by `collectPublicConfig` (whose presence is gated on\n * `!opts.localOnly`). Carrying this around as a tagged shape lets the\n * downstream code use the fields without non-null assertions. */\nexport interface PublicConfig {\n domain: string;\n cfToken: string;\n cfAccount: string;\n cfZone: string;\n tfToken: string;\n tfOrg: string;\n}\n\n/** Prompt for + verify Cloudflare and Terraform Cloud creds. Exits the\n * process on any verification failure. Only called in production mode;\n * in --local-only mode the caller passes `null` straight through. */\nasync function collectPublicConfig(opts: InitOptions): Promise<PublicConfig> {\n const domain = opts.domain\n ? opts.domain\n : unwrap(\n await p.text({\n message: 'Domain registered in Cloudflare?',\n placeholder: 'example.org',\n validate: (v) => {\n if (!v) return 'Required';\n return v.includes('.') ? undefined : 'Missing a TLD?';\n },\n }),\n );\n\n // ---- Cloudflare token --------------------------------------------------\n const cfToken = await collectSecret(\n opts.cfToken,\n 'Cloudflare Account API token (input hidden)',\n 'cloudflare',\n );\n const cfAccount = await collectId(opts.cfAccount, 'Cloudflare account ID');\n const cfZone = await collectId(opts.cfZone, `Cloudflare zone ID for ${domain}`);\n\n const cfSpin = p.spinner();\n cfSpin.start('Verifying Cloudflare token + 5 scopes…');\n const cfProbe = await probeCloudflareToken({\n token: cfToken,\n accountId: cfAccount,\n zoneId: cfZone,\n });\n if (!cfProbe.ok) {\n cfSpin.stop(pc.red('✗ Cloudflare token check failed.'));\n for (const issue of cfProbe.issues) console.error(` - ${issue}`);\n p.cancel('Fix the token in the Cloudflare dashboard, then re-run.');\n process.exit(1);\n }\n cfSpin.stop(pc.green('✓ Cloudflare token valid, 5 scopes present.'));\n\n // ---- Terraform Cloud token ---------------------------------------------\n const tfToken = await collectSecret(\n opts.tfToken,\n 'Terraform Cloud user/team API token',\n 'tfc',\n );\n const tfOrg = opts.tfOrg\n ? opts.tfOrg\n : unwrap(\n await p.text({\n message: 'Terraform Cloud organization name?',\n placeholder: 'op-region-ca',\n }),\n );\n\n const tfSpin = p.spinner();\n tfSpin.start('Verifying Terraform Cloud token + organization…');\n const tfProbe = await probeTfcToken({ token: tfToken, organization: tfOrg });\n if (!tfProbe.ok) {\n tfSpin.stop(pc.red('✗ Terraform Cloud check failed.'));\n for (const issue of tfProbe.issues) console.error(` - ${issue}`);\n p.cancel('Fix the token / org, then re-run.');\n process.exit(1);\n }\n const asUser = tfProbe.userName ? ` (as ${tfProbe.userName})` : '';\n tfSpin.stop(\n pc.green(\n `✓ TFC token valid${asUser}, org \"${tfOrg}\" reachable.`,\n ),\n );\n\n return { domain, cfToken, cfAccount, cfZone, tfToken, tfOrg };\n}\n\nasync function collectSecret(\n preset: string | undefined,\n message: string,\n kind: SecretKind = 'generic',\n): Promise<string> {\n if (preset) return preset;\n const min = MIN_TOKEN_LENGTH[kind];\n const v = unwrap(\n await p.password({\n message,\n validate: (v) =>\n v && v.length >= min\n ? undefined\n : `That looks too short — expected at least ${min} characters for a ${kind} token`,\n }),\n );\n return v;\n}\n\nasync function collectId(preset: string | undefined, message: string): Promise<string> {\n if (preset) return preset;\n const v = unwrap(\n await p.text({\n message,\n placeholder: '0000000000000000000000000000000',\n validate: (v) =>\n /^[a-f0-9]{32}$/.test(v ?? '') ? undefined : 'Expected 32 hex characters',\n }),\n );\n return v;\n}\n\nasync function printKeyForManualSave(\n value: string,\n label: string,\n reason?: string,\n): Promise<void> {\n p.note(\n [\n reason ? `${pc.red('✗')} ${reason}` : '',\n `Save this value to your secret store as ${pc.cyan(label)}:`,\n '',\n pc.yellow(value),\n '',\n pc.dim('It will not be shown again.'),\n pc.dim('On the Studio, bootstrap will prompt you to paste it back.'),\n ]\n .filter((line) => line.length > 0)\n .join('\\n'),\n 'Manual save',\n );\n unwrap(\n await p.confirm({\n message: 'Value stashed?',\n initialValue: true,\n }),\n );\n}\n\n/** Compact ISO timestamp suitable for a git branch name: 20260618-184530Z.\n * UTC so re-runs across timezones sort coherently. */\nfunction isoStampUtc(d: Date): string {\n const pad = (n: number, w = 2) => n.toString().padStart(w, '0');\n return (\n `${d.getUTCFullYear()}` +\n `${pad(d.getUTCMonth() + 1)}` +\n `${pad(d.getUTCDate())}` +\n `-` +\n `${pad(d.getUTCHours())}` +\n `${pad(d.getUTCMinutes())}` +\n `${pad(d.getUTCSeconds())}Z`\n );\n}\n\ninterface WaitInput {\n token: string;\n organization: string;\n workspaceId: string;\n runId: string | null;\n}\n\n/** Thin command-side adapter for the polling lib — renders Clack spinner\n * state from the lib's progress callback + maps the discriminated outcome\n * to a single nullable result the command keeps using. */\nasync function waitForApplyAndFetchTunnelToken(input: WaitInput): Promise<string | null> {\n const spin = p.spinner();\n spin.start('Waiting for terraform apply to finish (polling every 10s)…');\n\n const outcome = await waitForApply(\n {\n token: input.token,\n organization: input.organization,\n workspaceId: input.workspaceId,\n runId: input.runId,\n workspaceTags: ['opuspopuli', 'cloudflare'],\n outputName: 'tunnel_token',\n },\n undefined,\n {\n ...realWaitDeps,\n // Surface a transient network hiccup instead of silently re-polling, so\n // a slow wait doesn't look like a hang.\n onProgress: (phase) => {\n if (phase === 'retry') spin.message('Transient network error — retrying next poll…');\n },\n },\n );\n\n switch (outcome.kind) {\n case 'success':\n spin.stop(pc.green('✓ Tunnel token retrieved.'));\n return outcome.value;\n case 'output-missing':\n spin.stop(pc.red('✗ Apply succeeded but tunnel_token output is missing.'));\n return null;\n case 'no-run-started':\n spin.stop(pc.red('✗ No run started in the workspace yet.'));\n return null;\n case 'run-failed':\n spin.stop(pc.red(`✗ Run finished with status \"${outcome.status}\".`));\n return null;\n case 'timeout':\n spin.stop(pc.red('✗ Timed out after 10 minutes.'));\n return null;\n }\n}\n","/**\n * Detect Homebrew + install packages (formulae or casks) idempotently.\n *\n * Bootstrap shells out to brew once per package — `brew install` is itself\n * idempotent (no-op when already installed) but we list-check first so the\n * wizard can print \"already present\" vs \"installing…\" and skip the\n * potentially-multi-minute download for packages that are already on the\n * Studio.\n *\n * We don't try to AUTO-install Homebrew itself. The official installer is a\n * curl-pipe-bash script that prompts for sudo + has its own UX; the wizard\n * detects its absence, prints the single-line install command, and waits for\n * the operator to confirm before proceeding.\n */\n\nimport { access } from 'node:fs/promises';\n\nimport { safeExeca } from './exec.js';\n\nexport type PackageKind = 'formula' | 'cask';\n\nexport interface PackageSpec {\n name: string;\n kind: PackageKind;\n /** For casks that install a GUI `.app`: if this path already exists, the app\n * is present — possibly installed directly (not via Homebrew) or under a\n * since-renamed cask. In that case `brew list` misses it and\n * `brew install --cask` fails with \"already an App at …\", so we skip the\n * install and report it as already present. (#89) */\n appPath?: string;\n}\n\n/** The package set the runbook installs on the Studio. Casks need GUI\n * authorization on first launch — Docker Desktop in particular requires\n * manual click-through after `brew install --cask docker`. The wizard\n * surfaces that as a follow-up prompt; this list is just what we'd shell\n * out for.\n *\n * Deep-readonly via `as const` — neither the array nor the individual\n * PackageSpec entries can be mutated by accident. */\nexport const STUDIO_PACKAGES = [\n { name: 'git', kind: 'formula' },\n { name: 'gh', kind: 'formula' },\n { name: 'pnpm', kind: 'formula' },\n { name: 'jq', kind: 'formula' },\n { name: 'cloudflared', kind: 'formula' },\n { name: 'rclone', kind: 'formula' },\n { name: 'ollama', kind: 'formula' },\n // Required for the fail-closed image-signature gate in `bootstrap` (#34).\n { name: 'cosign', kind: 'formula' },\n // Homebrew renamed the `docker` cask to `docker-desktop`. The appPath skip\n // means a directly-installed Docker Desktop (the common case) is treated as\n // present rather than tripping `brew install` on the existing app. (#89)\n { name: 'docker-desktop', kind: 'cask', appPath: '/Applications/Docker.app' },\n { name: 'tailscale', kind: 'cask', appPath: '/Applications/Tailscale.app' },\n] as const satisfies readonly PackageSpec[];\n\nexport interface BrewInfo {\n installed: boolean;\n /** Version string when installed (`Homebrew 4.x.y`). Undefined otherwise. */\n version?: string;\n}\n\nexport async function detectBrew(): Promise<BrewInfo> {\n const res = await safeExeca('brew', ['--version']);\n if (res === null || res.exitCode !== 0) {\n return { installed: false };\n }\n // `brew --version` prints e.g. \"Homebrew 4.4.10\".\n const version = res.stdout.split('\\n').find((l) => l.startsWith('Homebrew '));\n return { installed: true, ...(version ? { version } : {}) };\n}\n\n/** The one-shot install command operators paste into their shell when brew is\n * missing. Surfaced verbatim so the wizard can show + the docs can quote\n * the same string. */\nexport const HOMEBREW_INSTALL_COMMAND =\n '/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"';\n\n/** Does a filesystem path exist? Used to detect a GUI app installed outside\n * Homebrew. (#89) */\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Is the named package already installed? A cask carrying an `appPath` counts\n * as present when that app already exists (installed directly, or under a\n * renamed cask) — otherwise `brew list` misses it and `brew install` fails on\n * the existing app. (#89) Otherwise `brew list <name>` exits 0 when yes,\n * non-zero when no; cask vs formula lookup uses different flags.\n */\nexport async function isPackageInstalled(pkg: PackageSpec): Promise<boolean> {\n if (pkg.appPath && (await pathExists(pkg.appPath))) {\n return true;\n }\n const flag = pkg.kind === 'cask' ? '--cask' : '--formula';\n const res = await safeExeca('brew', ['list', flag, pkg.name]);\n return res !== null && res.exitCode === 0;\n}\n\nexport interface InstallResult {\n ok: boolean;\n /** Set when ok=false. Stderr or stdout from the failing command. */\n reason?: string;\n}\n\n/** Install one package. Caller should `isPackageInstalled` first to skip\n * re-installs when speed matters; brew install is itself idempotent. */\nexport async function installPackage(pkg: PackageSpec): Promise<InstallResult> {\n const args =\n pkg.kind === 'cask'\n ? ['install', '--cask', pkg.name]\n : ['install', pkg.name];\n const res = await safeExeca('brew', args);\n if (res === null) {\n return { ok: false, reason: '`brew` not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `brew install ${pkg.name} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface InstallReport {\n installed: PackageSpec[];\n alreadyPresent: PackageSpec[];\n failed: Array<{ pkg: PackageSpec; reason: string }>;\n}\n\n/**\n * Install every package in the spec list. Each is independently logged into\n * one of three buckets so the wizard can show a clean summary. A failure in\n * one package doesn't abort the rest — we want the operator to see the\n * whole landscape and decide which to retry.\n */\nexport async function installPackages(\n packages: readonly PackageSpec[],\n onEach?: (pkg: PackageSpec, status: 'checking' | 'installing' | 'present' | 'installed' | 'failed') => void,\n): Promise<InstallReport> {\n const report: InstallReport = {\n installed: [],\n alreadyPresent: [],\n failed: [],\n };\n for (const pkg of packages) {\n onEach?.(pkg, 'checking');\n if (await isPackageInstalled(pkg)) {\n report.alreadyPresent.push(pkg);\n onEach?.(pkg, 'present');\n continue;\n }\n onEach?.(pkg, 'installing');\n const r = await installPackage(pkg);\n if (r.ok) {\n report.installed.push(pkg);\n onEach?.(pkg, 'installed');\n } else {\n report.failed.push({ pkg, reason: r.reason ?? 'unknown' });\n onEach?.(pkg, 'failed');\n }\n }\n return report;\n}\n","/**\n * Read + write the small set of macOS settings `create-op-node bootstrap`\n * cares about on the Mac Studio:\n *\n * - Hostname and OS version (informational + sanity check we're on Apple Silicon).\n * - Power management (`pmset`): auto-restart-on-power-failure, disk sleep.\n * - FileVault status (`fdesetup`) — informational only; we don't toggle it,\n * since the operator's earlier decision (gate 0.7 in the runbook) was OFF.\n *\n * All probes shell out via `safeExeca` from `lib/exec.ts` so a missing binary\n * (extremely unusual on macOS, but it's the principle) doesn't crash the\n * wizard. Writers use `pmset -a` which requires sudo on macOS — execa\n * propagates the operator's stdin so the password prompt works inline.\n */\n\nimport { safeExeca } from './exec.js';\n\nexport interface SystemSnapshot {\n hostname: string;\n /** `sw_vers -productVersion` output, or `null` when the call failed. */\n osVersion: string | null;\n /** True when `pmset -g` reports `autorestart 1`. */\n autoRestartOnPowerFailure: boolean;\n /** True when `pmset -g` reports `disksleep 0` (i.e. disk sleep DISABLED — the\n * state the bootstrap wants). */\n diskSleepDisabled: boolean;\n /** `true` / `false` when `fdesetup status` reported decisively, `'unknown'`\n * when the call failed or the output was unexpected. We don't toggle\n * FileVault — this is for the operator-facing summary only. */\n fileVaultEnabled: boolean | 'unknown';\n /** True when `uname -m` returns `arm64` (i.e. Apple Silicon Mac).\n * Bootstrap is M-series-only; Intel Macs fail with a clear message. */\n isAppleSilicon: boolean;\n}\n\nexport async function inspectSystem(): Promise<SystemSnapshot> {\n const [hostnameOut, osVersionOut, pmsetOut, fdesetupOut, unameOut] =\n await Promise.all([\n safeExeca('hostname', []),\n safeExeca('sw_vers', ['-productVersion']),\n safeExeca('pmset', ['-g']),\n safeExeca('fdesetup', ['status']),\n safeExeca('uname', ['-m']),\n ]);\n\n return {\n hostname: hostnameOut?.stdout.trim() ?? 'unknown',\n osVersion:\n osVersionOut && osVersionOut.exitCode === 0\n ? osVersionOut.stdout.trim()\n : null,\n autoRestartOnPowerFailure: parsePmsetBool(pmsetOut?.stdout ?? '', 'autorestart', 1),\n diskSleepDisabled: parsePmsetBool(pmsetOut?.stdout ?? '', 'disksleep', 0),\n fileVaultEnabled: parseFileVault(fdesetupOut?.stdout ?? ''),\n isAppleSilicon: (unameOut?.stdout.trim() ?? '') === 'arm64',\n };\n}\n\n/**\n * `pmset -g` prints one space-separated `key value` per line, e.g.:\n *\n * ```\n * System-wide power settings:\n * Currently in use:\n * lidwake 1\n * autorestart 1\n * disksleep 0\n * ```\n *\n * Returns `true` when the named key's value matches `expected`. Tolerant of\n * leading/trailing whitespace; matches first occurrence.\n */\nexport function parsePmsetBool(\n output: string,\n key: string,\n expected: number,\n): boolean {\n for (const line of output.split('\\n')) {\n const match = line.match(/^\\s*([a-z]+)\\s+(-?\\d+)\\s*$/);\n if (match && match[1] === key) {\n return Number(match[2]) === expected;\n }\n }\n return false;\n}\n\n/**\n * `fdesetup status` prints either:\n * - `FileVault is On.`\n * - `FileVault is Off.`\n * - `Encryption in progress: ...` (treat as On)\n * - anything else → `'unknown'`\n */\nexport function parseFileVault(output: string): boolean | 'unknown' {\n const trimmed = output.trim();\n if (/^FileVault is On\\.?/i.test(trimmed)) return true;\n if (/^FileVault is Off\\.?/i.test(trimmed)) return false;\n if (/encryption in progress/i.test(trimmed)) return true;\n return 'unknown';\n}\n\nexport interface SetResult {\n ok: boolean;\n /** Set when `ok=false`. Stderr or stdout from the failing command. */\n reason?: string;\n}\n\n/**\n * Enable auto-restart-on-power-failure (`pmset -a autorestart 1`). Requires\n * sudo; the operator's password prompt is inherited from the parent shell.\n */\nexport async function enableAutoRestartOnPowerFailure(): Promise<SetResult> {\n return runSudoPmset(['autorestart', '1']);\n}\n\n/** Disable disk sleep (`pmset -a disksleep 0`). Same sudo behavior. */\nexport async function disableDiskSleep(): Promise<SetResult> {\n return runSudoPmset(['disksleep', '0']);\n}\n\n/**\n * Read the Studio's unified memory in GB via `sysctl hw.memsize`. Returns\n * `null` when sysctl is unavailable or the output is unparseable — callers\n * fall back to platform defaults in that case.\n *\n * `hw.memsize` reports bytes (e.g. `137438953472` for 128 GB). We divide\n * by 2^30 and round; vendors mostly ship integer GB so the rounding is\n * cosmetic, but the user may see `127` instead of `128` on rare configs.\n */\nexport async function detectUnifiedMemoryGB(): Promise<number | null> {\n const res = await safeExeca('sysctl', ['-n', 'hw.memsize']);\n if (res === null || res.exitCode !== 0) return null;\n const bytes = Number.parseInt(res.stdout.trim(), 10);\n if (!Number.isFinite(bytes) || bytes <= 0) return null;\n return Math.round(bytes / 2 ** 30);\n}\n\nasync function runSudoPmset(args: string[]): Promise<SetResult> {\n const res = await safeExeca('sudo', ['pmset', '-a', ...args]);\n if (res === null) {\n return { ok: false, reason: '`sudo` not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `pmset ${args.join(' ')} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n","/**\n * macOS LaunchAgent for the env-loader that the bootstrap puts in place.\n *\n * The plist's whole job is to inject two env vars into the launchd session at\n * login so Docker Desktop + the container stack see them:\n *\n * PGSODIUM_ROOT_KEY — 64-hex pgsodium master key, read from a `0400` file\n * outside the container so a `docker compose --build`\n * can never wipe it (runbook gate / #791).\n * TUNNEL_TOKEN — Cloudflare Tunnel token, baked into the plist literal.\n *\n * The pgsodium key is materialized as a separate `0400` file (not embedded in\n * the plist) so it can be backed up out-of-band + rotated independently. The\n * Tunnel token gets baked into the plist directly — it's a different rotation\n * cadence (rotates with the Tunnel resource, not on pgsodium key churn).\n *\n * File modes match the runbook:\n * - pgsodium key file: 0400 (owner-read-only)\n * - plist file: 0600 (owner read+write; contains TUNNEL_TOKEN)\n */\n\nimport { mkdir, writeFile, chmod, rm } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport {\n PGSODIUM_KEY_RE,\n SAFE_LAUNCHCTL_VALUE_RE,\n SAFE_PATH_RE,\n SAFE_URL_RE,\n TUNNEL_TOKEN_RE,\n} from './constants.js';\nimport { safeExeca } from './exec.js';\n\nexport const LAUNCH_AGENT_LABEL = 'org.opuspopuli.envloader';\n\nexport interface LaunchAgentPaths {\n /** Absolute path to the 64-hex pgsodium master key file (mode 0400). */\n keyFile: string;\n /** Absolute path to the LaunchAgent plist (mode 0600). */\n plistFile: string;\n}\n\n/** Default on-disk locations the runbook documents. Operators can override. */\nexport function defaultPaths(home: string = homedir()): LaunchAgentPaths {\n return {\n keyFile: `${home}/.config/opuspopuli/pgsodium_root_key`,\n plistFile: `${home}/Library/LaunchAgents/${LAUNCH_AGENT_LABEL}.plist`,\n };\n}\n\nexport interface WriteResult {\n ok: boolean;\n /** Set when ok=false. */\n reason?: string;\n}\n\n/**\n * Write the 64-hex pgsodium master key to `keyFile` with mode 0400. Creates\n * the parent directory tree (mode 0700 on the immediate parent) and refuses\n * non-64-hex input.\n */\nexport async function writePgsodiumKeyFile(\n key: string,\n keyFile: string,\n): Promise<WriteResult> {\n if (!PGSODIUM_KEY_RE.test(key)) {\n return {\n ok: false,\n reason: `pgsodium key must be 64 lowercase hex characters (got ${key.length} chars)`,\n };\n }\n try {\n const dir = dirname(keyFile);\n await mkdir(dir, { recursive: true, mode: 0o700 });\n // Remove any existing key file first. It's written mode 0400 (read-only),\n // so on a re-run `writeFile` (which opens O_WRONLY|O_TRUNC) would fail\n // EACCES — the `mode` option only applies when the file is created, not to\n // an existing one. `force: true` ignores a missing file, keeping the write\n // idempotent across bootstrap re-runs. (#93)\n await rm(keyFile, { force: true });\n await writeFile(keyFile, key, { mode: 0o400 });\n // mkdir's mode option respects umask; chmod is the belt to the suspenders.\n await chmod(dir, 0o700);\n await chmod(keyFile, 0o400);\n return { ok: true };\n } catch (err) {\n return { ok: false, reason: `writing ${keyFile} failed: ${(err as Error).message}` };\n }\n}\n\nexport interface PlistInput {\n /** Path the plist will exec — sourced from defaultPaths() unless an operator\n * overrides on the command line. */\n keyFilePath: string;\n /** Literal Cloudflare Tunnel token; embedded in the plist. Omit for\n * `bootstrap --local-only` flows where no Tunnel is provisioned — the\n * rendered plist will only set PGSODIUM_ROOT_KEY. */\n tunnelToken?: string;\n /** Self-hosted Supabase credentials. When provided, the plist exports each\n * value via `launchctl setenv` so docker-compose-prod.yml — and every\n * Supabase container the compose brings up — sees them. Omit individual\n * fields to skip emitting that var (e.g. for partial re-runs). */\n postgresPassword?: string;\n jwtSecret?: string;\n supabaseAnonKey?: string;\n supabaseServiceRoleKey?: string;\n dashboardPassword?: string;\n /** API Gateway HMAC secret (base64url). When set, plist exports\n * `GATEWAY_HMAC_SECRET`. The derived `API_KEYS` JSON is NOT emitted here:\n * its `{`/`\"`/`:` characters can't pass a `launchctl setenv` value safely,\n * so the op-compose wrapper (and bootstrap's own compose env) render it. */\n gatewayHmacSecret?: string;\n /** Grafana admin password (base64url). When set, plist exports\n * `GRAFANA_ADMIN_PASSWORD`. */\n grafanaAdminPassword?: string;\n /** Public-facing Supabase URL — what browsers + microservices use to reach\n * Kong. Local dev: `http://localhost:8000`. Tunnel: `https://supabase.<domain>`. */\n supabaseUrl?: string;\n}\n\n/**\n * Render the LaunchAgent plist XML. Pure function — caller writes it.\n *\n * The plist runs a `/bin/sh -c` at load that calls `launchctl setenv` for\n * each var. `launchctl setenv` exports into the running launchd session,\n * not just the agent's own env, so anything Docker Desktop launches\n * downstream sees the same values.\n *\n * Required: `PGSODIUM_ROOT_KEY`. Optional: `TUNNEL_TOKEN` + the Supabase\n * credentials — omitted from the setenv list when their inputs are undefined.\n *\n * Model config (`LLM_MODEL` / `EMBEDDINGS_MODEL` / `NODE_ENV`) is deliberately\n * NOT set here: those are non-secret substitution vars that live in the node's\n * `.env` (single source of truth). A launchctl setenv value would shadow\n * `.env` at compose interpolation time, so it stays out of the launchd session.\n */\nexport function renderLaunchAgentPlist(input: PlistInput): string {\n validatePlistInput(input);\n const command = buildSetenvCommand(input);\n\n return [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">',\n '<plist version=\"1.0\">',\n '<dict>',\n ` <key>Label</key><string>${LAUNCH_AGENT_LABEL}</string>`,\n ' <key>ProgramArguments</key>',\n ' <array>',\n ' <string>/bin/sh</string>',\n ' <string>-c</string>',\n ` <string>${command}</string>`,\n ' </array>',\n ' <key>RunAtLoad</key><true/>',\n '</dict>',\n '</plist>',\n '',\n ].join('\\n');\n}\n\n// Reject any input that would break the XML or inject shell metacharacters\n// into the `sh -c` body launchd runs at every login. Throws on the first\n// offending field. Our own generators only emit safe alphabets, but\n// operators can pass --import-* overrides, so re-validate here.\nfunction validatePlistInput(input: PlistInput): void {\n if (input.tunnelToken !== undefined && !TUNNEL_TOKEN_RE.test(input.tunnelToken)) {\n throw new Error('Tunnel token contains characters outside the expected base64-url set');\n }\n if (!SAFE_PATH_RE.test(input.keyFilePath)) {\n // The keyFilePath gets interpolated into a `sh -c` command run by launchd\n // at every login — reject shell metacharacters even though defaultPaths()\n // never produces one (defense in depth against operator overrides).\n throw new Error(\n `keyFilePath ${JSON.stringify(input.keyFilePath)} contains characters not allowed in a launchd path interpolation`,\n );\n }\n const supabaseFields: Array<[keyof PlistInput, string | undefined]> = [\n ['postgresPassword', input.postgresPassword],\n ['jwtSecret', input.jwtSecret],\n ['supabaseAnonKey', input.supabaseAnonKey],\n ['supabaseServiceRoleKey', input.supabaseServiceRoleKey],\n ['dashboardPassword', input.dashboardPassword],\n ['gatewayHmacSecret', input.gatewayHmacSecret],\n ['grafanaAdminPassword', input.grafanaAdminPassword],\n ];\n for (const [name, value] of supabaseFields) {\n if (value !== undefined && !SAFE_LAUNCHCTL_VALUE_RE.test(value)) {\n throw new Error(`${String(name)} contains characters not allowed in a launchd setenv value`);\n }\n }\n if (input.supabaseUrl !== undefined && !SAFE_URL_RE.test(input.supabaseUrl)) {\n throw new Error(\n `supabaseUrl ${JSON.stringify(input.supabaseUrl)} contains characters not allowed in a launchd setenv value`,\n );\n }\n}\n\n// Assemble the `; `-joined `launchctl setenv` command. PGSODIUM_ROOT_KEY is\n// always set; every other var is emitted only when its value is present.\nfunction buildSetenvCommand(input: PlistInput): string {\n return [\n // Quote the path inside `cat` so a space-containing keyFilePath (allowed by\n // SAFE_PATH_RE) doesn't word-split and leave PGSODIUM_ROOT_KEY empty. The\n // regex rejects `\"`/`$`/backticks, so the inner quotes can't be broken out\n // of — this is word-split safety, not new injection surface. (#36)\n `launchctl setenv PGSODIUM_ROOT_KEY \"$(cat \"${input.keyFilePath}\")\"`,\n ...(input.tunnelToken !== undefined\n ? [`launchctl setenv TUNNEL_TOKEN \"${input.tunnelToken}\"`]\n : []),\n ...(input.postgresPassword !== undefined\n ? [`launchctl setenv POSTGRES_PASSWORD \"${input.postgresPassword}\"`]\n : []),\n ...(input.jwtSecret !== undefined ? [`launchctl setenv JWT_SECRET \"${input.jwtSecret}\"`] : []),\n ...(input.supabaseAnonKey !== undefined\n ? [`launchctl setenv SUPABASE_ANON_KEY \"${input.supabaseAnonKey}\"`]\n : []),\n ...(input.supabaseServiceRoleKey !== undefined\n ? [`launchctl setenv SUPABASE_SERVICE_ROLE_KEY \"${input.supabaseServiceRoleKey}\"`]\n : []),\n ...(input.dashboardPassword !== undefined\n ? [`launchctl setenv DASHBOARD_PASSWORD \"${input.dashboardPassword}\"`]\n : []),\n ...(input.gatewayHmacSecret !== undefined\n ? [`launchctl setenv GATEWAY_HMAC_SECRET \"${input.gatewayHmacSecret}\"`]\n : []),\n ...(input.grafanaAdminPassword !== undefined\n ? [`launchctl setenv GRAFANA_ADMIN_PASSWORD \"${input.grafanaAdminPassword}\"`]\n : []),\n ...(input.supabaseUrl !== undefined\n ? [`launchctl setenv SUPABASE_URL \"${input.supabaseUrl}\"`]\n : []),\n ].join('; ');\n}\n\n/** Write the plist file to disk at mode 0600. */\nexport async function writeLaunchAgentPlist(\n plistFile: string,\n content: string,\n): Promise<WriteResult> {\n try {\n await mkdir(dirname(plistFile), { recursive: true });\n await writeFile(plistFile, content, { mode: 0o600 });\n await chmod(plistFile, 0o600);\n return { ok: true };\n } catch (err) {\n return { ok: false, reason: `writing ${plistFile} failed: ${(err as Error).message}` };\n }\n}\n\n/**\n * Load (or reload) the agent via `launchctl load`. Unload first to handle\n * re-runs; ignore errors on unload since it could just not be loaded yet.\n */\nexport async function loadLaunchAgent(plistFile: string): Promise<WriteResult> {\n await safeExeca('launchctl', ['unload', plistFile]); // ignore errors\n const load = await safeExeca('launchctl', ['load', plistFile]);\n if (load === null) {\n return { ok: false, reason: '`launchctl` not on PATH' };\n }\n if (load.exitCode !== 0) {\n return {\n ok: false,\n reason: `launchctl load failed (${load.exitCode ?? 'signal'}): ${load.stderr || load.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface SetupInput {\n pgsodiumKey: string;\n /** Omit for `bootstrap --local-only` flows — the rendered plist will only\n * set `PGSODIUM_ROOT_KEY`. */\n tunnelToken?: string;\n /** Self-hosted Supabase credentials — generated by `bootstrap` and stored\n * in Keychain. Each value here gets exported into the launchd session\n * via the plist's `launchctl setenv` lines. */\n postgresPassword?: string;\n jwtSecret?: string;\n supabaseAnonKey?: string;\n supabaseServiceRoleKey?: string;\n dashboardPassword?: string;\n /** API Gateway HMAC secret — exported as GATEWAY_HMAC_SECRET. */\n gatewayHmacSecret?: string;\n /** Grafana admin password — exported as GRAFANA_ADMIN_PASSWORD. */\n grafanaAdminPassword?: string;\n /** Public-facing Supabase URL. */\n supabaseUrl?: string;\n paths?: LaunchAgentPaths;\n}\n\nexport interface SetupReport {\n ok: boolean;\n paths: LaunchAgentPaths;\n step?: 'key-file' | 'plist' | 'load';\n reason?: string;\n}\n\n/**\n * One-shot: write the key file, render + write the plist, load the agent.\n * Returns a report that names which step failed (if any) for clean operator\n * messaging.\n */\n// Map the flat SetupInput onto a PlistInput, carrying only the fields that\n// are present (each optional secret is spread in only when defined).\nfunction plistInputFromSetup(input: SetupInput, keyFilePath: string): PlistInput {\n return {\n keyFilePath,\n ...(input.tunnelToken !== undefined ? { tunnelToken: input.tunnelToken } : {}),\n ...(input.postgresPassword !== undefined ? { postgresPassword: input.postgresPassword } : {}),\n ...(input.jwtSecret !== undefined ? { jwtSecret: input.jwtSecret } : {}),\n ...(input.supabaseAnonKey !== undefined ? { supabaseAnonKey: input.supabaseAnonKey } : {}),\n ...(input.supabaseServiceRoleKey !== undefined\n ? { supabaseServiceRoleKey: input.supabaseServiceRoleKey }\n : {}),\n ...(input.dashboardPassword !== undefined ? { dashboardPassword: input.dashboardPassword } : {}),\n ...(input.gatewayHmacSecret !== undefined ? { gatewayHmacSecret: input.gatewayHmacSecret } : {}),\n ...(input.grafanaAdminPassword !== undefined\n ? { grafanaAdminPassword: input.grafanaAdminPassword }\n : {}),\n ...(input.supabaseUrl !== undefined ? { supabaseUrl: input.supabaseUrl } : {}),\n };\n}\n\nexport async function setupLaunchAgent(input: SetupInput): Promise<SetupReport> {\n const paths = input.paths ?? defaultPaths();\n\n const keyResult = await writePgsodiumKeyFile(input.pgsodiumKey, paths.keyFile);\n if (!keyResult.ok) {\n return { ok: false, paths, step: 'key-file', ...(keyResult.reason ? { reason: keyResult.reason } : {}) };\n }\n\n let plistContent: string;\n try {\n plistContent = renderLaunchAgentPlist(plistInputFromSetup(input, paths.keyFile));\n } catch (err) {\n return { ok: false, paths, step: 'plist', reason: (err as Error).message };\n }\n\n const plistResult = await writeLaunchAgentPlist(paths.plistFile, plistContent);\n if (!plistResult.ok) {\n return { ok: false, paths, step: 'plist', ...(plistResult.reason ? { reason: plistResult.reason } : {}) };\n }\n\n const loadResult = await loadLaunchAgent(paths.plistFile);\n if (!loadResult.ok) {\n return { ok: false, paths, step: 'load', ...(loadResult.reason ? { reason: loadResult.reason } : {}) };\n }\n\n return { ok: true, paths };\n}\n\nexport interface TeardownResult {\n ok: boolean;\n /** Per-step outcome. Each step is independently logged so the operator can\n * see \"unload worked but the plist file was already gone.\" */\n steps: Array<{ step: 'unload' | 'rm-plist' | 'rm-key-file'; ok: boolean; reason?: string }>;\n}\n\nexport interface TeardownOptions {\n /** When true, leave the pgsodium key file in place. Useful when the\n * operator wants to unload the LaunchAgent + remove the plist but\n * keep the key as belt-and-suspenders backup. */\n keepKeyFile?: boolean;\n}\n\n/**\n * Reverse of `setupLaunchAgent`: unload the agent via `launchctl unload`,\n * then `rm -f` both the plist and (unless `keepKeyFile`) the pgsodium key\n * file. Idempotent — `rm -f` is a no-op when the file doesn't exist, and\n * we treat `launchctl unload` of an already-unloaded agent as success.\n *\n * Used by `reset`. Also useful as a test seam during integration tests.\n */\nexport async function teardownLaunchAgent(\n paths: LaunchAgentPaths,\n opts: TeardownOptions = {},\n): Promise<TeardownResult> {\n const steps: TeardownResult['steps'] = [];\n\n const unload = await safeExeca('launchctl', ['unload', paths.plistFile]);\n // `launchctl unload` exits non-zero when the agent isn't loaded — that's a\n // successful teardown from our point of view, so a non-zero exit is fine.\n // But a null result means `launchctl` isn't on PATH: nothing was unloaded,\n // so report ok:false rather than a clean teardown that didn't happen. (#36)\n steps.push({\n step: 'unload',\n ok: unload !== null,\n ...(unload === null ? { reason: '`launchctl` not on PATH' } : {}),\n });\n\n try {\n await rm(paths.plistFile, { force: true });\n steps.push({ step: 'rm-plist', ok: true });\n } catch (err) {\n steps.push({ step: 'rm-plist', ok: false, reason: (err as Error).message });\n }\n\n if (!opts.keepKeyFile) {\n try {\n await rm(paths.keyFile, { force: true });\n steps.push({ step: 'rm-key-file', ok: true });\n } catch (err) {\n steps.push({ step: 'rm-key-file', ok: false, reason: (err as Error).message });\n }\n }\n\n return { ok: steps.every((s) => s.ok), steps };\n}\n","/**\n * Renders the `bin/op-compose` wrapper script that lives in the operator's\n * region-node repo.\n *\n * **Why a wrapper instead of a `.env` file:**\n * The project's vault-first principle (#811) says runtime secrets read via\n * `secretsProvider.getSecret()` at point of use; env-on-disk is reserved\n * for bootstrap-critical config. The bootstrap-layer secrets (Postgres\n * password, JWT secret, Supabase admin tokens) ARE bootstrap-critical\n * (Postgres / kong / gotrue can't start without them, and Vault doesn't\n * exist until Postgres is up) — but they don't need to LIVE on disk in\n * plaintext to be available at compose-invocation time.\n *\n * This wrapper reads them from macOS Keychain (FileVault-encrypted at\n * rest) on every invocation and exports them only into the docker compose\n * subprocess's env. No plaintext .env file ever lands on disk; the\n * Keychain is the sole persistent store.\n *\n * **Why launchctl setenv isn't sufficient:**\n * `launchctl setenv` only propagates to processes spawned by launchd\n * AFTER the setenv call. SSH-spawned shells (sshd children) and\n * already-running Terminal.app instances never see the new vars, so\n * `docker compose` hard-fails on `${VAR:?…}` even though `launchctl\n * getenv` confirms launchd has them. The wrapper is shell-agnostic and\n * works the same in every invocation context.\n *\n * **Operator workflow:**\n * $ ./bin/op-compose -f docker-compose-prod.yml up -d\n * $ ./bin/op-compose -f docker-compose-prod.yml pull\n * $ ./bin/op-compose -f docker-compose-prod.yml down\n *\n * The wrapper accepts every argument `docker compose` accepts.\n *\n * **Security:**\n * - Script is mode 0755 (executable, world-readable). The script ITSELF\n * has no secrets — it's a static shell script with the region name\n * baked in. The secrets only exist in process env for the lifetime\n * of the docker compose invocation.\n * - Region name is the only baked-in value (used to scope the Keychain\n * service identifier `org.opuspopuli.<region>`); shell-injection is\n * prevented by the region-validation regex in bootstrap.ts.\n * - Errors when a required Keychain entry is missing point the operator\n * at `create-op-node bootstrap`.\n */\n\nconst REGION_RE = /^[a-z0-9-]{2,32}$/;\n\n/** URL-shape regex for values baked into the wrapper as\n * `export PROMPT_SERVICE_URL=\"…\"`. Matches what bootstrap.ts validates\n * via SAFE_URL_RE — letters, digits, `:`, `/`, `_`, `-`, `.`. Reject\n * shell metacharacters that would inject when the wrapper sources. */\nconst PROMPT_SERVICE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;\n\nexport interface OpComposeScriptInput {\n /** Region slug — gets interpolated into the Keychain service identifier\n * `org.opuspopuli.<region>`. Validated against the same regex bootstrap\n * uses, so a tampered call site can't inject shell metacharacters. */\n region: string;\n /** Default value the wrapper sets for `PROMPT_SERVICE_URL` when nothing\n * in the docker compose service-level env overrides it. For\n * `region-with-prompts` deployments this is the in-network address\n * `http://opuspopuli-prompts:3210` (and the overlay still wins via\n * service-level env). For `region` (remote prompts) it's whatever URL\n * the operator pointed at — typically https://prompts.opuspopuli.org.\n * Omit and the wrapper won't export PROMPT_SERVICE_URL at all. */\n promptServiceUrl?: string;\n}\n\n/**\n * Render the wrapper script. Pure function — caller writes it to disk and\n * `chmod 0755`s the result.\n *\n * Throws on an invalid region label rather than emit a script with a\n * shell-injectable service identifier.\n */\nexport function renderOpComposeScript(input: OpComposeScriptInput): string {\n if (!REGION_RE.test(input.region)) {\n throw new Error(\n `region ${JSON.stringify(input.region)} contains characters not allowed in a launchd / Keychain service identifier`,\n );\n }\n if (input.promptServiceUrl !== undefined && !PROMPT_SERVICE_URL_RE.test(input.promptServiceUrl)) {\n throw new Error(\n `promptServiceUrl ${JSON.stringify(input.promptServiceUrl)} contains characters not allowed in a wrapper export`,\n );\n }\n const promptServiceUrlExport =\n input.promptServiceUrl !== undefined\n ? `# Backend services call prompt-service via this URL. Service-level env\n# from docker-compose-prompt-service.yml overlay (when layered) wins\n# over this default — so colocated deployments still hit\n# http://opuspopuli-prompts:3210 even though we may have a public URL\n# baked in here.\nexport PROMPT_SERVICE_URL=\"\\${PROMPT_SERVICE_URL:-${input.promptServiceUrl}}\"\n\n`\n : '';\n\n return `#!/bin/bash\n# op-compose — wrapper that reads region secrets from macOS Keychain just\n# before invoking \\`docker compose\\`. Auto-generated by\n# \\`create-op-node bootstrap --region ${input.region}\\`. Do not edit by\n# hand; re-run bootstrap to regenerate.\n#\n# Why: launchctl setenv only propagates to launchd-spawned processes, so\n# SSH shells and pre-existing Terminal.app instances never see the env\n# vars bootstrap exports. This wrapper hydrates the docker compose\n# subprocess directly, so every invocation works regardless of how the\n# operator's shell was started.\n#\n# Usage:\n# ./bin/op-compose -f docker-compose-prod.yml up -d\n# ./bin/op-compose -f docker-compose-prod.yml pull\n# ./bin/op-compose -f docker-compose-prod.yml down\n\nset -euo pipefail\n\nSVC=\"org.opuspopuli.${input.region}\"\n\n# macOS \\`security\\` exit codes:\n# 0 = success\n# 36 = errSecInteractionNotAllowed (keychain is locked)\n# 44 = errSecItemNotFound (entry doesn't exist)\n# Earlier wrapper versions conflated 36 and 44 into a generic \"missing\"\n# message, which sent operators down the wrong path (re-bootstrap when\n# the real fix was \\`security unlock-keychain\\`).\nrequire_secret() {\n local account=\"$1\"\n local value\n local rc=0\n value=$(security find-generic-password -s \"$SVC\" -a \"$account\" -w 2>/dev/null) || rc=$?\n case \"$rc\" in\n 0)\n printf '%s' \"$value\"\n return 0\n ;;\n 36)\n cat >&2 <<EOM\nop-compose: keychain is LOCKED — could not read entry '$account'.\nSSH sessions don't auto-unlock the login keychain. Unlock with:\n security unlock-keychain ~/Library/Keychains/login.keychain-db\nThen re-run this command.\nEOM\n exit 1\n ;;\n 44)\n cat >&2 <<EOM\nop-compose: keychain entry '$account' is MISSING under service '$SVC'.\nRun: create-op-node bootstrap --region ${input.region}\nEOM\n exit 1\n ;;\n *)\n echo \"op-compose: \\`security\\` failed reading '$account' (exit $rc).\" >&2\n exit 1\n ;;\n esac\n}\n\n# Used for entries that may legitimately not exist (TUNNEL_TOKEN in\n# local-only mode, prompt-service secrets when colocation isn't active).\n# Treats exit 44 (missing) as a silent OK — returns empty string.\n# Treats exit 36 (locked) as a hard error, since the require_secret calls\n# at the top of the wrapper would have caught this first in normal use;\n# reaching this path means something else bypassed the lock check.\noptional_secret() {\n local account=\"$1\"\n local value\n local rc=0\n value=$(security find-generic-password -s \"$SVC\" -a \"$account\" -w 2>/dev/null) || rc=$?\n case \"$rc\" in\n 0) printf '%s' \"$value\" ;;\n 44) ;; # legitimately absent — empty string is correct\n 36)\n cat >&2 <<EOM\nop-compose: keychain is LOCKED — could not probe optional entry '$account'.\nUnlock with: security unlock-keychain ~/Library/Keychains/login.keychain-db\nEOM\n exit 1\n ;;\n *)\n echo \"op-compose: \\`security\\` failed reading '$account' (exit $rc).\" >&2\n exit 1\n ;;\n esac\n}\n\n# Bootstrap-critical: Postgres + Supabase admin credentials.\nexport PGSODIUM_ROOT_KEY=\"$(require_secret pgsodium-root-key)\"\nexport POSTGRES_PASSWORD=\"$(require_secret postgres-password)\"\nexport JWT_SECRET=\"$(require_secret jwt-secret)\"\nexport SUPABASE_ANON_KEY=\"$(require_secret supabase-anon-key)\"\nexport SUPABASE_SERVICE_ROLE_KEY=\"$(require_secret supabase-service-role-key)\"\nexport DASHBOARD_PASSWORD=\"$(require_secret dashboard-password)\"\n\n# API Gateway HMAC secret. The gateway signs gateway→microservice requests\n# with this (X-HMAC-Auth) in EVERY mode, so it is required. API_KEYS is the\n# JSON map each microservice reads to verify the caller; the api-gateway's\n# key MUST equal GATEWAY_HMAC_SECRET. We render the JSON from the single\n# Keychain value here so the compose \\`\\${GATEWAY_HMAC_SECRET:-…}\\` /\n# \\`\\${API_KEYS:-…}\\` well-known defaults are always overridden with a real\n# per-node value.\nexport GATEWAY_HMAC_SECRET=\"$(require_secret gateway-hmac-secret)\"\nexport API_KEYS=\"{\\\\\"api-gateway\\\\\":\\\\\"\\${GATEWAY_HMAC_SECRET}\\\\\"}\"\n\n# Grafana admin password — overrides the compose \\`admin\\`/\\`admin\\` default.\nexport GRAFANA_ADMIN_PASSWORD=\"$(require_secret grafana-admin-password)\"\n\n# AUTH_JWT_SECRET historically equals JWT_SECRET in dev/UAT — supply that\n# default if the operator hasn't set one independently.\nexport AUTH_JWT_SECRET=\"\\${AUTH_JWT_SECRET:-$JWT_SECRET}\"\n\n# Optional: Cloudflare Tunnel token (only present in non-local-only mode).\nTUNNEL_TOKEN_VAL=\"$(optional_secret tunnel-token)\"\nif [ -n \"$TUNNEL_TOKEN_VAL\" ]; then\n export TUNNEL_TOKEN=\"$TUNNEL_TOKEN_VAL\"\nfi\n\n# SUPABASE_URL is not a secret — read from env if the operator set one,\n# default to localhost for --local-only.\nexport SUPABASE_URL=\"\\${SUPABASE_URL:-http://localhost:8000}\"\n\n${promptServiceUrlExport}# prompt-service credentials. Always exported — harmless when the operator\n# is NOT colocating prompt-service (the main compose doesn't read these\n# vars; the overlay does). The PROMPT_SERVICE_API_KEYS list is built from\n# the operator's region + the single HMAC key in Keychain, matching the\n# prompt-service env format \\`<region>:<key>,<region>:<key>,…\\`.\nPROMPTS_DB_PASSWORD_VAL=\"$(optional_secret prompts-db-password)\"\nPROMPT_SERVICE_API_KEY_VAL=\"$(optional_secret prompt-service-api-key)\"\nPROMPT_SERVICE_ADMIN_API_KEY_VAL=\"$(optional_secret prompt-service-admin-api-key)\"\nif [ -n \"$PROMPTS_DB_PASSWORD_VAL\" ]; then\n export PROMPTS_DB_PASSWORD=\"$PROMPTS_DB_PASSWORD_VAL\"\nfi\nif [ -n \"$PROMPT_SERVICE_API_KEY_VAL\" ]; then\n export PROMPT_SERVICE_API_KEY=\"$PROMPT_SERVICE_API_KEY_VAL\"\n # API_KEYS env on prompt-service is \\`<region>:<key>,…\\` — render the\n # single-region pair here so prompt-service accepts the same key the\n # backend sends. The prompts team adds additional regions on the\n # central deployment for Phase 2.\n export PROMPT_SERVICE_API_KEYS=\"${input.region}:$PROMPT_SERVICE_API_KEY_VAL\"\nfi\nif [ -n \"$PROMPT_SERVICE_ADMIN_API_KEY_VAL\" ]; then\n export PROMPT_SERVICE_ADMIN_API_KEYS=\"$PROMPT_SERVICE_ADMIN_API_KEY_VAL\"\nfi\n\nexec docker compose \"$@\"\n`;\n}\n","/**\n * Side-effecting installer for the `bin/op-compose` wrapper script.\n *\n * Pure rendering lives in op-compose-script.ts so it stays unit-testable.\n * This file owns:\n * 1. Creating `<repo>/bin/` if needed\n * 2. Atomically writing the script (temp file + rename) so an\n * interrupted bootstrap never leaves a half-written wrapper that\n * `exec` would crash on\n * 3. `chmod 0755` so the operator can run `./bin/op-compose`\n */\n\nimport { chmod, mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { renderOpComposeScript, type OpComposeScriptInput } from './op-compose-script.js';\n\nexport interface InstallOpComposeInput extends OpComposeScriptInput {\n /** Directory containing the compose file. Script lands at `<repoDir>/bin/op-compose`. */\n repoDir: string;\n}\n\nexport interface InstallOpComposeResult {\n ok: boolean;\n /** Absolute path the script was written to, when ok=true. */\n path?: string;\n reason?: string;\n}\n\nexport async function installOpComposeWrapper(\n input: InstallOpComposeInput,\n): Promise<InstallOpComposeResult> {\n let content: string;\n try {\n content = renderOpComposeScript({\n region: input.region,\n ...(input.promptServiceUrl !== undefined ? { promptServiceUrl: input.promptServiceUrl } : {}),\n });\n } catch (err) {\n return { ok: false, reason: (err as Error).message };\n }\n\n const binDir = join(input.repoDir, 'bin');\n const target = join(binDir, 'op-compose');\n const tmp = `${target}.tmp.${process.pid}`;\n\n try {\n await mkdir(binDir, { recursive: true });\n await writeFile(tmp, content, { mode: 0o755 });\n // mkdir/writeFile respect umask; chmod ensures 0755 regardless.\n await chmod(tmp, 0o755);\n await rename(tmp, target); // atomic on POSIX\n return { ok: true, path: target };\n } catch (err) {\n return { ok: false, reason: `writing ${target} failed: ${(err as Error).message}` };\n }\n}\n","/**\n * Docker compose + ghcr.io login orchestration.\n *\n * Three concerns this lib covers:\n *\n * 1. Authenticate Docker to ghcr.io using the operator's `gh auth token`,\n * piped on stdin so the token never lands in argv.\n * 2. `docker compose pull / up -d` against the prod compose set in the\n * operator's node repo checkout.\n * 3. Poll `docker compose ps --format json` until every service reports\n * `(healthy)`, with the same two-phase-budget pattern as lib/polling.ts\n * (containers can take a while to start showing up; healthy check then\n * runs on its own clock).\n */\n\nimport { safeExeca } from './exec.js';\n\n/** Default registry. Constant so tests + the bootstrap command read the same\n * value and an op-region migration to a different registry only changes\n * one place. */\nexport const GHCR_REGISTRY = 'ghcr.io';\n\nexport interface LoginResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Authenticate Docker to ghcr.io. Pulls the token from `gh auth token`,\n * pipes it on stdin to `docker login --password-stdin`. The username comes\n * from `gh api user --jq .login`. Three execa calls; failure at any point\n * reports cleanly with the responsible step.\n */\nexport async function loginToGhcr(): Promise<LoginResult> {\n const tokenRes = await safeExeca('gh', ['auth', 'token']);\n if (tokenRes === null) return { ok: false, reason: '`gh` not installed' };\n if (tokenRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `gh auth token failed (${tokenRes.exitCode ?? 'signal'}): ${tokenRes.stderr || tokenRes.stdout}`,\n };\n }\n const token = tokenRes.stdout.trim();\n if (token.length === 0) {\n return { ok: false, reason: 'gh auth token returned empty — run `gh auth login` first' };\n }\n\n const userRes = await safeExeca('gh', ['api', 'user', '--jq', '.login']);\n if (userRes === null || userRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `couldn't resolve GitHub user via gh api: ${userRes?.stderr || userRes?.stdout || 'gh missing'}`,\n };\n }\n const user = userRes.stdout.trim();\n if (user.length === 0) {\n return { ok: false, reason: 'gh api user returned empty — gh not signed in' };\n }\n\n const loginRes = await safeExeca(\n 'docker',\n ['login', GHCR_REGISTRY, '-u', user, '--password-stdin'],\n { input: token },\n );\n if (loginRes === null) return { ok: false, reason: '`docker` not installed' };\n if (loginRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `docker login ${GHCR_REGISTRY} failed (${loginRes.exitCode ?? 'signal'}): ${loginRes.stderr || loginRes.stdout}`,\n };\n }\n return { ok: true };\n}\n\n// ----------------------------------------------------------------------------\n// Compose pull / up\n// ----------------------------------------------------------------------------\n\nexport interface ComposeOptions {\n /** Compose file paths, in order. Becomes `-f X -f Y …` on the command line. */\n files: string[];\n /** Working directory the compose command runs from. */\n cwd: string;\n /** Optional env-file flag, in the same convention as `--env-file`. */\n envFile?: string;\n /** Compose profiles to activate. Repeats as `--profile X --profile Y`. The\n * template's `cloudflared` service is gated behind the `public` profile;\n * bootstrap in local-only mode passes an empty array so cloudflared\n * stays down. */\n profiles?: ReadonlyArray<string>;\n /** Extra env vars passed to the docker compose subprocess. Used by\n * bootstrap to hydrate Keychain-loaded secrets (POSTGRES_PASSWORD,\n * JWT_SECRET, the Supabase JWTs, etc.) at compose-invocation time\n * without writing them to a plaintext `.env` file on disk. Per the\n * vault-first principle (#811), the wrapper script (`bin/op-compose`)\n * is the operator-facing version of the same pattern. */\n env?: NodeJS.ProcessEnv;\n}\n\nfunction composeArgs(opts: ComposeOptions, sub: string[]): string[] {\n const files = opts.files.flatMap((f) => ['-f', f]);\n const env = opts.envFile ? ['--env-file', opts.envFile] : [];\n const profiles = (opts.profiles ?? []).flatMap((pr) => ['--profile', pr]);\n return ['compose', ...files, ...env, ...profiles, ...sub];\n}\n\nexport interface ComposeResult {\n ok: boolean;\n reason?: string;\n}\n\n/** Build the execa options object once — both env and cwd flow from\n * ComposeOptions to safeExeca so subprocess hydration works uniformly. */\nfunction execOpts(opts: ComposeOptions): { cwd: string; env?: NodeJS.ProcessEnv } {\n return opts.env ? { cwd: opts.cwd, env: opts.env } : { cwd: opts.cwd };\n}\n\n/** `docker compose -f … pull`. Idempotent on first run; pulls new image tags. */\nexport async function composePull(opts: ComposeOptions): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['pull']), execOpts(opts));\n return result(res, 'compose pull');\n}\n\n/** Registry prefix for images published + cosign-signed by the opuspopuli\n * release workflow. Only these are verifiable against the release identity;\n * third-party images (postgres, kong, gotrue, ollama, …) are unsigned by us. */\nexport const OPUSPOPULI_IMAGE_PREFIX = 'ghcr.io/opuspopuli/';\n\n/**\n * `docker compose … config --images` — the resolved image refs the stack will\n * pull, one per line. Returns `null` when the command can't run (docker\n * missing) or config fails (e.g. a required `${VAR:?}` interpolation is unset),\n * so the caller can treat \"couldn't enumerate\" distinctly from \"no images\".\n */\nexport async function composeConfigImages(opts: ComposeOptions): Promise<string[] | null> {\n const res = await safeExeca('docker', composeArgs(opts, ['config', '--images']), execOpts(opts));\n if (res === null || res.exitCode !== 0) return null;\n return res.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\n/** Keep only the images the opuspopuli release workflow signs — the subset\n * cosign can verify against the release identity. Third-party base images are\n * dropped (they'd fail verification against our identity). Pure helper. */\nexport function filterVerifiableImages(\n images: string[],\n prefix: string = OPUSPOPULI_IMAGE_PREFIX,\n): string[] {\n return images.filter((img) => img.startsWith(prefix));\n}\n\n/** `docker compose -f … up -d --remove-orphans`. */\nexport async function composeUp(opts: ComposeOptions): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['up', '-d', '--remove-orphans']), execOpts(opts));\n return result(res, 'compose up');\n}\n\n/**\n * `docker compose -f … rm -sfv <service>`. Stops + removes a single service +\n * its anonymous volumes. Used by `bootstrap --local-only` to evict a\n * cloudflared container left over from a prior public bootstrap; otherwise it\n * lingers in `compose ps` and the health-check loop demands it reach healthy.\n *\n * Returns ok=true when the service doesn't exist (compose treats \"rm a\n * service that isn't there\" as a no-op exit 0), so callers can call this\n * unconditionally.\n */\nexport async function composeRemoveService(\n opts: ComposeOptions,\n service: string,\n): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['rm', '-sfv', service]), execOpts(opts));\n return result(res, `compose rm ${service}`);\n}\n\nexport interface ComposeDownOptions extends ComposeOptions {\n /** When true, adds `-v` — destroys named volumes. The default false is the\n * safe choice: stop the stack but preserve the database. Callers must\n * ALWAYS surface a typed confirmation before flipping this on. */\n wipeVolumes?: boolean;\n /** When true, adds `--remove-orphans` — drops containers from compose files\n * no longer present. Useful on first-after-rename runs. */\n removeOrphans?: boolean;\n /** When set, adds `--rmi <mode>` to also remove the images.\n * - `'all'`: removes all images referenced by services (forces re-pull\n * on next `compose up`).\n * - `'local'`: removes only images that don't have a custom tag (i.e.,\n * locally-built ones; pulled images stay).\n * Use 'all' for true \"wipe everything and start over\" iteration loops. */\n removeImages?: 'all' | 'local';\n}\n\n/** `docker compose -f … down [-v] [--remove-orphans] [--rmi MODE]`. */\nexport async function composeDown(opts: ComposeDownOptions): Promise<ComposeResult> {\n const flags: string[] = ['down'];\n if (opts.wipeVolumes) flags.push('-v');\n if (opts.removeOrphans) flags.push('--remove-orphans');\n if (opts.removeImages) flags.push('--rmi', opts.removeImages);\n const label = [\n 'compose down',\n opts.wipeVolumes ? '-v' : '',\n opts.removeImages ? `--rmi ${opts.removeImages}` : '',\n ]\n .filter(Boolean)\n .join(' ');\n const res = await safeExeca('docker', composeArgs(opts, flags), execOpts(opts));\n return result(res, label);\n}\n\n/**\n * `docker logout <registry>`.\n *\n * Behavior on \"not currently logged in\" varies by version: Docker 24+ returns\n * exit 0 with \"Not logged in to <registry>\" on stdout, but older Docker\n * Desktop releases (and some credential-helper configurations) return a\n * non-zero exit instead. `reset` therefore renders a non-zero outcome as a\n * warning rather than a failure — the goal is \"ensure no creds remain,\" and\n * \"no creds existed to begin with\" satisfies that goal.\n *\n * Note: this only clears the credential-store entry. If the operator's\n * credential helper has cached the token elsewhere, or if `~/.docker/config.json`\n * has stale entries from a different host, those need separate cleanup.\n */\nexport async function dockerLogout(registry: string = GHCR_REGISTRY): Promise<ComposeResult> {\n const res = await safeExeca('docker', ['logout', registry]);\n return result(res, `docker logout ${registry}`);\n}\n\nfunction result(\n res: { exitCode: number | undefined; stdout: string; stderr: string } | null,\n label: string,\n): ComposeResult {\n if (res === null) return { ok: false, reason: '`docker` not installed' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `${label} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\n// ----------------------------------------------------------------------------\n// Compose ps — for the health check loop\n// ----------------------------------------------------------------------------\n\nexport interface ContainerSnapshot {\n name: string;\n /** `running`, `exited`, etc. — the Docker container state. */\n state: string;\n /** `healthy`, `unhealthy`, `starting`, or `none` (no healthcheck defined). */\n health: 'healthy' | 'unhealthy' | 'starting' | 'none';\n exitCode: number | null;\n}\n\n/**\n * Parse `docker compose ps --format json` output. Compose v2 emits one JSON\n * object per line for each container. We tolerate either format (NDJSON or\n * a single-line JSON array, depending on version).\n */\nexport function parseComposePs(stdout: string): ContainerSnapshot[] {\n // First try NDJSON line-by-line.\n const trimmed = stdout.trim();\n if (trimmed.length === 0) return [];\n\n const lines = trimmed.split('\\n').map((l) => l.trim()).filter((l) => l.length > 0);\n const out: ContainerSnapshot[] = [];\n\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (Array.isArray(parsed)) {\n for (const item of parsed) out.push(normalize(item));\n } else {\n out.push(normalize(parsed));\n }\n } catch {\n // Skip non-JSON lines (compose sometimes emits warnings on stdout).\n }\n }\n return out;\n}\n\nfunction normalize(raw: unknown): ContainerSnapshot {\n const r = (raw ?? {}) as Record<string, unknown>;\n const name = (r['Name'] as string) ?? (r['Service'] as string) ?? '<unknown>';\n const state = ((r['State'] as string) ?? 'unknown').toLowerCase();\n const healthRaw = ((r['Health'] as string) ?? '').toLowerCase();\n const health: ContainerSnapshot['health'] =\n healthRaw === 'healthy' || healthRaw === 'unhealthy' || healthRaw === 'starting'\n ? healthRaw\n : 'none';\n const exitCodeRaw = r['ExitCode'];\n const exitCode = typeof exitCodeRaw === 'number' ? exitCodeRaw : null;\n return { name, state, health, exitCode };\n}\n\n/**\n * `docker compose ps --format json`. Returns:\n *\n * - `null` when the call itself failed (docker missing, compose file wrong,\n * non-zero exit). The caller can distinguish a real failure from a\n * stack-not-up-yet case.\n * - `[]` when the call succeeded but no containers are listed yet (compose\n * up still in flight).\n * - `ContainerSnapshot[]` populated on success.\n */\nexport async function composePs(opts: ComposeOptions): Promise<ContainerSnapshot[] | null> {\n const res = await safeExeca('docker', composeArgs(opts, ['ps', '--format', 'json']), execOpts(opts));\n if (res === null || res.exitCode !== 0) return null;\n return parseComposePs(res.stdout);\n}\n\n// ----------------------------------------------------------------------------\n// Health-check loop\n// ----------------------------------------------------------------------------\n\nexport interface WaitForHealthyOptions {\n /** Container names that MUST be healthy before we return success. Empty\n * array means \"every container compose ps reports must be healthy or no-op\n * (i.e. state=exited with code 0 — db-migrate-style one-shots).\" */\n requireHealthy?: string[];\n /** Max time to wait, ms. Default 5 minutes. */\n timeoutMs?: number;\n /** Poll interval, ms. Default 5s. */\n pollMs?: number;\n /** Optional progress callback. */\n onPoll?: (snapshots: ContainerSnapshot[]) => void;\n}\n\nexport type HealthOutcome =\n | { kind: 'healthy'; snapshots: ContainerSnapshot[] }\n | { kind: 'unhealthy'; snapshots: ContainerSnapshot[]; problem: string }\n | { kind: 'timeout'; snapshots: ContainerSnapshot[] };\n\nexport interface WaitForHealthyDeps {\n ps: (opts: ComposeOptions) => Promise<ContainerSnapshot[] | null>;\n sleep: (ms: number) => Promise<void>;\n now: () => number;\n}\n\nexport const realWaitDeps: WaitForHealthyDeps = {\n ps: composePs,\n sleep: (ms) => new Promise((res) => setTimeout(res, ms)),\n now: () => Date.now(),\n};\n\n/**\n * Poll `compose ps` until either every container reaches a happy terminal\n * state or the timeout fires. A \"happy\" state is:\n *\n * - `state=running` AND `health` ∈ {healthy, none}\n * - `state=exited` AND `exitCode === 0` (one-shot containers like db-migrate)\n *\n * `state=running` + `health=starting` keeps polling; `health=unhealthy` or\n * `state=exited` with non-zero exit returns immediately as `unhealthy`.\n */\n// Map a single non-empty poll result to a terminal HealthOutcome, or null\n// when the caller should keep polling ('pending' or no containers yet).\nfunction terminalOutcome(\n ps: ContainerSnapshot[],\n requireHealthy?: string[],\n): HealthOutcome | null {\n if (ps.length === 0) return null;\n const verdict = assessHealth(ps, requireHealthy);\n if (verdict.kind === 'healthy') return { kind: 'healthy', snapshots: ps };\n if (verdict.kind === 'unhealthy') {\n return { kind: 'unhealthy', snapshots: ps, problem: verdict.problem ?? 'unhealthy' };\n }\n return null;\n}\n\nexport async function waitForHealthy(\n composeOpts: ComposeOptions,\n options: WaitForHealthyOptions = {},\n deps: WaitForHealthyDeps = realWaitDeps,\n): Promise<HealthOutcome> {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000;\n const basePollMs = options.pollMs ?? 5 * 1000;\n const start = deps.now();\n let last: ContainerSnapshot[] = [];\n let pollCount = 0;\n\n while (deps.now() - start < timeoutMs) {\n pollCount++;\n const ps = await deps.ps(composeOpts);\n if (ps !== null) {\n last = ps;\n options.onPoll?.(ps);\n // A terminal verdict (healthy / unhealthy) returns immediately;\n // 'pending' (null here) falls through to the sleep + next iteration.\n const outcome = terminalOutcome(ps, options.requireHealthy);\n if (outcome) return outcome;\n }\n // Gentle backoff: 1× the base poll for the first 3 polls (fast feedback\n // while containers are settling), 2× after that. Caps wasted subprocess\n // startup on long timeouts without slowing down the typical case.\n const interval = pollCount < 3 ? basePollMs : basePollMs * 2;\n await deps.sleep(interval);\n }\n return { kind: 'timeout', snapshots: last };\n}\n\ninterface AssessVerdict {\n kind: 'healthy' | 'unhealthy' | 'pending';\n problem?: string;\n}\n\nexport function assessHealth(\n snapshots: ContainerSnapshot[],\n requireHealthy?: string[],\n): AssessVerdict {\n // Hard failures short-circuit regardless of the required-list mode.\n const hard = firstHardFailure(snapshots);\n if (hard) return hard;\n\n const required = requireHealthy ?? [];\n return required.length > 0\n ? assessRequired(snapshots, required)\n : assessAllRunning(snapshots);\n}\n\n// Hard failure conditions: any unhealthy, any exited-with-non-zero.\nfunction firstHardFailure(snapshots: ContainerSnapshot[]): AssessVerdict | null {\n for (const s of snapshots) {\n if (s.health === 'unhealthy') {\n return { kind: 'unhealthy', problem: `${s.name} reports unhealthy` };\n }\n if (s.state === 'exited' && (s.exitCode ?? 0) !== 0) {\n return { kind: 'unhealthy', problem: `${s.name} exited with code ${s.exitCode}` };\n }\n }\n return null;\n}\n\n// The caller specified a required-healthy list — gate on exactly those.\nfunction assessRequired(snapshots: ContainerSnapshot[], required: string[]): AssessVerdict {\n const byName = new Map(snapshots.map((s) => [s.name, s]));\n for (const name of required) {\n const s = byName.get(name);\n if (!s) return { kind: 'pending' };\n if (s.state === 'exited' && s.exitCode === 0) continue;\n if (s.state !== 'running') return { kind: 'pending' };\n if (s.health === 'starting') return { kind: 'pending' };\n if (s.health === 'unhealthy') {\n return { kind: 'unhealthy', problem: `${s.name} reports unhealthy` };\n }\n }\n return { kind: 'healthy' };\n}\n\n// No required list — all snapshots must be in a happy state.\nfunction assessAllRunning(snapshots: ContainerSnapshot[]): AssessVerdict {\n for (const s of snapshots) {\n if (s.state === 'exited' && s.exitCode === 0) continue;\n if (s.state !== 'running') return { kind: 'pending' };\n if (s.health === 'starting') return { kind: 'pending' };\n }\n return { kind: 'healthy' };\n}\n","/**\n * `cosign verify` wrapper for the verify wizard.\n *\n * Keyless verification path: cosign maps the image to a Fulcio-issued\n * certificate, checks the certificate's identity (GitHub Actions workflow URL)\n * + OIDC issuer, AND consults the Rekor transparency log (cosign default,\n * `rekor.sigstore.dev`) for an inclusion proof. So a passing verify means\n * the image was signed by the expected workflow AND that signing event is\n * publicly logged.\n *\n * If `cosign` isn't on PATH we report it as a skip rather than a failure —\n * verify can still pass without it (TLS + GraphQL probes are load-bearing).\n */\n\nimport { safeExeca } from './exec.js';\n\nexport const COSIGN_OIDC_ISSUER = 'https://token.actions.githubusercontent.com';\n\nexport interface CosignVerifyInput {\n image: string;\n /** Glob/regex passed as `--certificate-identity-regexp`. Defaults to the\n * publishing workflow path in the opuspopuli-node template. */\n certificateIdentityRegexp?: string;\n /** OIDC issuer that signed the image. Defaults to GitHub Actions. */\n certificateOidcIssuer?: string;\n}\n\nexport type CosignVerifyResult =\n | { ok: true; output: string }\n | { ok: false; skipped: true; reason: string }\n | { ok: false; skipped: false; reason: string };\n\n// Ref-pinned to the exact publishing workflow. Each `ghcr.io/opuspopuli/*`\n// image is keyless-signed by its source repo's `release.yml` on push to main\n// (or ad-hoc `workflow_dispatch` from a fix branch for an arm64 build) — both\n// carry a `.../release.yml@refs/heads/<branch>` certificate identity. We pin\n// the workflow FILE (not `.../workflows/.*`, which would accept any workflow in\n// the repo that ever obtained a Fulcio cert) and allow any `refs/heads/` branch\n// so legitimate ad-hoc builds still verify. (#34)\n//\n// The org publishes images from MORE than one repo: the `opuspopuli` monorepo\n// (api, users, documents, knowledge, region, workers) AND the private\n// `prompt-service` repo (`ghcr.io/opuspopuli/prompt-service`). Both sign with\n// their own `release.yml`, so the pin is an explicit allowlist of those repos\n// rather than the single monorepo — an arbitrary/spoofed org repo (`…/evil/…`)\n// still fails. Add a repo here when a new one starts publishing signed images.\n// (#94)\n//\n// Provenance of each segment (the cert SAN is GitHub's OIDC `job_workflow_ref`,\n// format `<owner>/<repo>/.github/workflows/<file>@<ref>`):\n// - `OpusPopuli/(opuspopuli|prompt-service)` — the canonical repo paths, the\n// exact casing OIDC emits.\n// - `release.yml@refs/heads/` — the signing workflow + trigger (push to main\n// / workflow_dispatch), confirmed in each repo's release.yml.\n// The fail-closed bootstrap gate exposes `--certificate-identity-regexp` as the\n// escape valve for any not-yet-listed signer.\nexport const DEFAULT_IDENTITY_REGEXP =\n '^https://github\\\\.com/OpusPopuli/(?:opuspopuli|prompt-service)/\\\\.github/workflows/release\\\\.yml@refs/heads/.*$';\n\n/**\n * Verify a single OCI image's cosign signature against the GitHub Actions\n * OIDC issuer. Returns one of three shapes:\n *\n * - `{ ok: true }` — signature valid.\n * - `{ ok: false, skipped: true }` — cosign binary not on PATH; caller\n * should render this as a warning, not a failure.\n * - `{ ok: false, skipped: false }` — cosign ran and rejected the image.\n */\nexport async function cosignVerifyImage(input: CosignVerifyInput): Promise<CosignVerifyResult> {\n const idRegex = input.certificateIdentityRegexp ?? DEFAULT_IDENTITY_REGEXP;\n const issuer = input.certificateOidcIssuer ?? COSIGN_OIDC_ISSUER;\n\n const res = await safeExeca('cosign', [\n 'verify',\n '--certificate-identity-regexp',\n idRegex,\n '--certificate-oidc-issuer',\n issuer,\n input.image,\n ]);\n\n if (res === null) {\n return {\n ok: false,\n skipped: true,\n reason: '`cosign` not on PATH (install with `brew install cosign` and rerun to enable signature checks)',\n };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n skipped: false,\n reason: `cosign verify ${input.image} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true, output: res.stdout || res.stderr };\n}\n","/**\n * Ollama service + model management.\n *\n * Ollama is installed via Homebrew (handled by `lib/homebrew.ts`) and started\n * as a `brew services` job. This lib covers what the wizard does after that:\n *\n * - HTTP health check on `localhost:11434` (the running daemon).\n * - List installed models via the HTTP API (avoids parsing `ollama list`'s\n * human-formatted output).\n * - Pull a model — shells out to `ollama pull <name>` because the HTTP\n * `/api/pull` endpoint streams NDJSON progress and is awkward to consume.\n * - Warm a model with a single trivial generation so the first user request\n * doesn't pay a ~90s cold-start.\n * - Probe that containers can reach the host's Ollama via\n * `host.docker.internal` — common Docker Desktop configuration mistake.\n */\n\nimport { safeExeca } from './exec.js';\n\nexport const OLLAMA_URL = 'http://localhost:11434';\n\n/** Health probe (`/api/tags`) is a metadata read — it should answer almost\n * instantly, so a short timeout keeps a hung daemon from stalling bootstrap. */\nconst OLLAMA_HEALTH_TIMEOUT_MS = 5_000;\n\n/** Warming (`/api/generate`) loads the model into VRAM on first call, which\n * for a 50 GB model legitimately takes minutes — hence a generous cap that\n * still bounds a truly-wedged daemon. */\nconst OLLAMA_WARM_TIMEOUT_MS = 120_000;\n\n/** Conservative default LLM for the `--yes` / scripted path and the fallback\n * when unified-memory detection fails. Sized to fit a 16 GB machine once the\n * ~22-container stack + Postgres take their share — capable enough to\n * validate the inference path end-to-end. Interactive bootstrap tiers UP from\n * here based on detected RAM (see `recommendLlmModel`); operators can override\n * at bootstrap time with `--llm-model`. */\nexport const DEFAULT_LLM_MODEL = 'qwen2.5:7b';\n\n/** Default embedding model used by the knowledge service when\n * `EMBEDDINGS_PROVIDER=ollama`. With the default `xenova` (in-process)\n * provider, this isn't pulled. Operators can override with\n * `--embedding-model`. */\nexport const DEFAULT_EMBEDDING_MODEL = 'nomic-embed-text';\n\n/** Where embeddings are computed: `xenova` runs in-process (no Ollama pull\n * needed), `ollama` uses the host daemon with DEFAULT_EMBEDDING_MODEL. */\nexport type EmbeddingsProvider = 'xenova' | 'ollama';\n\n/** Platform default — in-process embeddings, so a fresh node needs no\n * embedding-model pull unless the operator opts into the Ollama provider. */\nexport const DEFAULT_EMBEDDINGS_PROVIDER: EmbeddingsProvider = 'xenova';\n\n/** Default model pull set for `bootstrap`. Kept as a `as const`-typed array\n * so existing code can iterate without re-deriving from the two scalars. */\nexport const DEFAULT_MODELS = [DEFAULT_LLM_MODEL, DEFAULT_EMBEDDING_MODEL] as const;\n\n/** Pinned alpine tag for the host.docker.internal probe. Latest is fine in\n * practice (the image only runs `curl`) but pinning keeps the probe\n * reproducible across operator machines. Bump when alpine cuts a major. */\nexport const PROBE_ALPINE_TAG = '3.20';\n\nexport interface OllamaHealth {\n /** True when the daemon answered the `/api/tags` probe with 200. */\n reachable: boolean;\n /** Names of currently-installed models, when reachable. */\n models: string[];\n}\n\n/**\n * Probe the daemon. We use `/api/tags` because it's the cheapest endpoint\n * that proves both reachability AND that the server is past initial bring-up\n * (a bare TCP-accept-but-not-ready Ollama returns 404 here, not 200).\n */\n/**\n * Try to start the Ollama service via `brew services start ollama`.\n * Idempotent — brew services no-ops on an already-started service. Returns\n * `ok: false` only if brew itself is missing or the start command errored\n * for a non-trivial reason.\n */\nexport async function startOllamaService(): Promise<{ ok: boolean; reason?: string }> {\n const res = await safeExeca('brew', ['services', 'start', 'ollama']);\n if (res === null) return { ok: false, reason: '`brew` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `brew services start ollama failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport async function checkOllamaHealth(url: string = OLLAMA_URL): Promise<OllamaHealth> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), OLLAMA_HEALTH_TIMEOUT_MS);\n try {\n const res = await fetch(`${url}/api/tags`, { signal: ctrl.signal });\n if (!res.ok) return { reachable: false, models: [] };\n const body = (await res.json()) as { models?: Array<{ name?: string }> };\n const models = (body.models ?? [])\n .map((m) => m.name ?? '')\n .filter((n) => n.length > 0);\n return { reachable: true, models };\n } catch {\n // Unreachable, non-200, non-JSON, or timed out (AbortError) — all \"not\n // healthy\" from the caller's perspective.\n return { reachable: false, models: [] };\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Is `configured` present in the `installed` model list (from\n * `checkOllamaHealth().models` / `ollama list`)?\n *\n * Ollama treats a bare model name as its `:latest` tag — `ollama pull qwen2.5`\n * installs `qwen2.5:latest`, and `/api/tags` reports the fully-qualified name.\n * So we normalize BOTH sides to an explicit tag before comparing: a config of\n * `qwen2.5` matches an installed `qwen2.5:latest`, and vice-versa. A tag\n * mismatch (the incident: configured `qwen3.5:35b` vs installed `qwen2.5:72b`)\n * correctly returns false. Pure helper — the presence-check core for `verify`.\n */\nexport function modelPresent(configured: string, installed: readonly string[]): boolean {\n const norm = (m: string): string => (m.includes(':') ? m : `${m}:latest`);\n const target = norm(configured);\n return installed.some((m) => norm(m) === target);\n}\n\nexport interface PullResult {\n ok: boolean;\n /** Set when ok=false. */\n reason?: string;\n}\n\n/**\n * Pull a model. `ollama pull` is idempotent — re-pulling a present model is\n * a fast no-op — so we don't pre-check installation.\n */\nexport async function pullModel(name: string): Promise<PullResult> {\n const res = await safeExeca('ollama', ['pull', name]);\n if (res === null) return { ok: false, reason: '`ollama` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `ollama pull ${name} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface WarmResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Send a trivial `/api/generate` call so the model loads into memory. First\n * request on a cold daemon can take 30-90s; that latency lands on the wizard,\n * not on a real user. We stream=false + ignore the response body.\n */\nexport async function warmModel(name: string, url: string = OLLAMA_URL): Promise<WarmResult> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), OLLAMA_WARM_TIMEOUT_MS);\n try {\n const res = await fetch(`${url}/api/generate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model: name, prompt: 'hi', stream: false }),\n signal: ctrl.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n return {\n ok: false,\n reason: `warm ${name} returned HTTP ${res.status}: ${text || '(no body)'}`,\n };\n }\n // Drain the body to ensure the model finished loading.\n await res.text();\n return { ok: true };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `warm ${name} timed out after ${OLLAMA_WARM_TIMEOUT_MS / 1000}s`\n : `warm ${name} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Verify Docker containers can reach the host's Ollama via\n * `host.docker.internal`. Operators sometimes disable that hostname in Docker\n * Desktop settings; this probe catches the misconfig before the stack comes\n * up and fails opaquely.\n */\nexport async function probeHostDockerInternal(): Promise<{ ok: boolean; reason?: string }> {\n const res = await safeExeca('docker', [\n 'run',\n '--rm',\n `alpine:${PROBE_ALPINE_TAG}`,\n 'sh',\n '-c',\n 'apk add --no-cache curl >/dev/null 2>&1 && curl -fsS http://host.docker.internal:11434/api/tags',\n ]);\n if (res === null) return { ok: false, reason: '`docker` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason:\n `container couldn't reach host.docker.internal:11434 — check Docker Desktop ` +\n `settings → Resources → Network → Enable host.docker.internal`,\n };\n }\n return { ok: true };\n}\n\nexport interface SetupReport {\n pulled: string[];\n alreadyPresent: string[];\n failed: Array<{ model: string; reason: string }>;\n warmed: string[];\n}\n\n/**\n * Pull each model in `models` (skipping already-present ones) and warm the\n * first one. Continues past per-model failures so the operator sees the\n * whole landscape.\n */\nexport async function setupModels(\n models: readonly string[],\n onProgress?: (model: string, status: 'present' | 'pulling' | 'pulled' | 'failed' | 'warming' | 'warmed') => void,\n): Promise<SetupReport> {\n const report: SetupReport = {\n pulled: [],\n alreadyPresent: [],\n failed: [],\n warmed: [],\n };\n\n const health = await checkOllamaHealth();\n const present = new Set(health.models);\n\n for (const m of models) {\n if (present.has(m)) {\n report.alreadyPresent.push(m);\n onProgress?.(m, 'present');\n continue;\n }\n onProgress?.(m, 'pulling');\n const r = await pullModel(m);\n if (r.ok) {\n report.pulled.push(m);\n onProgress?.(m, 'pulled');\n } else {\n report.failed.push({ model: m, reason: r.reason ?? 'unknown' });\n onProgress?.(m, 'failed');\n }\n }\n\n // Warm the first model that exists by name in the user-supplied list, not\n // necessarily the first to pull successfully — keeps the warm target\n // predictable for tests + operator UX.\n const warmTarget = models.find((m) => present.has(m) || report.pulled.includes(m));\n if (warmTarget) {\n onProgress?.(warmTarget, 'warming');\n const w = await warmModel(warmTarget);\n if (w.ok) {\n report.warmed.push(warmTarget);\n onProgress?.(warmTarget, 'warmed');\n }\n // A failed warm-up isn't fatal — it just means the first real user\n // request pays the cold-start cost. Surface in the report.\n }\n\n return report;\n}\n","/**\n * Manages the model-config block inside the operator's region-node `.env`.\n *\n * **Why a `.env` file (and why only for THIS config):**\n * docker compose resolves `${LLM_MODEL:-…}` interpolation with the precedence\n * shell/launchd env > `.env` > compose default. Model identifiers used to be\n * pushed into the launchd session via `launchctl setenv` — but that shadows\n * `.env` and, worse, only reaches launchd-spawned processes (never SSH shells\n * or a Terminal.app that was already open), so partial container recreates\n * baked divergent `LLM_MODEL` values at creation time. Writing the model to a\n * compose-auto-loaded `.env` makes every service resolve the SAME value\n * regardless of recreate order or how the operator's shell was started.\n *\n * This file deliberately carries ONLY non-secret substitution config\n * (`LLM_MODEL`, `EMBEDDINGS_MODEL`, `EMBEDDINGS_PROVIDER`, `NODE_ENV`).\n * Bootstrap-critical SECRETS stay in the macOS Keychain and are hydrated into\n * the compose subprocess by `bin/op-compose` (see `op-compose-script.ts`) —\n * they never touch a plaintext `.env`, preserving the vault-first principle.\n *\n * **Managed block, not full ownership:**\n * In docker-compose semantics `.env` is fundamentally the operator's file, and\n * operators hand-edit it. So we own only a delimited region:\n *\n * # >>> op-node managed >>>\n * LLM_MODEL=…\n * # <<< op-node managed <<<\n *\n * Everything outside the markers is preserved verbatim. On first encounter\n * with a pre-existing `.env`, any managed keys the operator already set are\n * ADOPTED into the block (import-don't-clobber) rather than overwritten — the\n * exact drift this whole effort exists to prevent. The block is rewritten only\n * on an explicit model (re)selection (`overwrite: true`); a read-only consumer\n * like `verify` must never rewrite it.\n */\n\nimport { chmod, mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n/** Delimiters bounding the region create-op-node owns. Matched exactly (after\n * trimming) when locating an existing block. */\nexport const MANAGED_BEGIN = '# >>> op-node managed >>>';\nexport const MANAGED_END = '# <<< op-node managed <<<';\n\n/** Keys create-op-node manages inside the block, in stable emit order so diffs\n * across re-runs only show real value changes. */\nexport const MANAGED_KEYS = [\n 'LLM_MODEL',\n 'EMBEDDINGS_PROVIDER',\n 'EMBEDDINGS_MODEL',\n 'NODE_ENV',\n] as const;\nexport type ManagedKey = (typeof MANAGED_KEYS)[number];\n\n/** `.env` value safety: model names + provider/NODE_ENV enums never contain\n * whitespace, `#`, quotes, `$`, or newlines. Rejecting them keeps a value\n * from silently truncating the line (inline `#`), spawning interpolation\n * (`$`), or breaking the file across a newline. Mirrors launchagent's\n * MODEL_NAME_RE for model ids and is a strict superset-safe check for the\n * fixed enums. */\nconst ENV_VALUE_RE = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;\n\nexport interface ManagedEnvSelection {\n /** Resolved LLM model id (e.g. `qwen3.6:35b-a3b`). Always present — bootstrap\n * always resolves one via flag/prompt/default. */\n llmModel: string;\n /** Resolved embeddings model id. Emitted even under the `xenova` provider\n * (documents the intended model); only the knowledge service under\n * `EMBEDDINGS_PROVIDER=ollama` actually reads it. */\n embeddingModel?: string;\n /** `xenova` (in-process, default) or `ollama`. */\n embeddingsProvider?: string;\n /** `development` for `--local-only` nodes; omitted otherwise. */\n nodeEnv?: string;\n}\n\n/** The managed keys mapped from the caller's selection. */\nfunction selectionToPairs(sel: ManagedEnvSelection): ReadonlyArray<[ManagedKey, string | undefined]> {\n return [\n ['LLM_MODEL', sel.llmModel],\n ['EMBEDDINGS_PROVIDER', sel.embeddingsProvider],\n ['EMBEDDINGS_MODEL', sel.embeddingModel],\n ['NODE_ENV', sel.nodeEnv],\n ];\n}\n\nexport interface WriteEnvFileResult {\n ok: boolean;\n /** Absolute path to the written file, when ok=true. */\n path?: string;\n /** True when the managed block's rendered content was unchanged, so no write\n * happened. Lets bootstrap report \"already current\" instead of implying a\n * rewrite. */\n unchanged?: boolean;\n reason?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Pure parsing / rendering (exported for unit tests)\n// ----------------------------------------------------------------------------\n\n/**\n * Parse `KEY=value` lines into a last-wins map. Ignores blank lines and\n * comments. Deliberately simple — matches docker compose's own naive `.env`\n * reader (no quoting, no escapes, no multi-line). We only look up our own\n * MANAGED_KEYS, which are always simple tokens.\n */\nexport function parseEnvContent(content: string): Map<string, string> {\n const out = new Map<string, string>();\n for (const raw of content.split('\\n')) {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith('#')) continue;\n const eq = line.indexOf('=');\n if (eq <= 0) continue;\n out.set(line.slice(0, eq).trim(), line.slice(eq + 1).trim());\n }\n return out;\n}\n\ninterface SplitEnv {\n /** Operator lines before the managed block (or the whole file when absent). */\n before: string[];\n /** Operator lines after the managed block. Empty when no block existed. */\n after: string[];\n /** Parsed key=value pairs found INSIDE an existing managed block. */\n blockValues: Map<string, string>;\n hasBlock: boolean;\n}\n\n/**\n * Split file content into the operator regions surrounding our managed block\n * plus the block's parsed values. When no block exists, the whole file is\n * `before` and `hasBlock` is false.\n */\nexport function splitManaged(content: string): SplitEnv {\n const lines = content.split('\\n');\n const beginIdx = lines.findIndex((l) => l.trim() === MANAGED_BEGIN);\n if (beginIdx === -1) {\n return { before: lines, after: [], blockValues: new Map(), hasBlock: false };\n }\n const endIdx = lines.findIndex((l, i) => i > beginIdx && l.trim() === MANAGED_END);\n if (endIdx === -1) {\n // Opening marker but no close (hand-mangled). Treat everything from the\n // marker on as ours to replace — don't try to preserve a broken block.\n return {\n before: lines.slice(0, beginIdx),\n after: [],\n blockValues: parseEnvContent(lines.slice(beginIdx + 1).join('\\n')),\n hasBlock: true,\n };\n }\n return {\n before: lines.slice(0, beginIdx),\n after: lines.slice(endIdx + 1),\n blockValues: parseEnvContent(lines.slice(beginIdx + 1, endIdx).join('\\n')),\n hasBlock: true,\n };\n}\n\n/** Drop lines from an operator region that assign one of our managed keys —\n * those values get consolidated INTO the block, so leaving the bare line\n * would create a duplicate (and, if it sorts after the block, shadow it). */\nfunction stripManagedKeyLines(region: string[]): string[] {\n return region.filter((raw) => {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith('#')) return true;\n const eq = line.indexOf('=');\n if (eq <= 0) return true;\n return !MANAGED_KEYS.includes(line.slice(0, eq).trim() as ManagedKey);\n });\n}\n\n/** Render the managed block for a set of resolved key/value pairs (only keys\n * with a defined value are emitted). */\nfunction renderBlock(values: ReadonlyArray<[ManagedKey, string]>): string[] {\n return [\n MANAGED_BEGIN,\n '# Auto-generated by `create-op-node bootstrap`. Non-secret model config,',\n '# read by docker compose via `.env` auto-load. Edit LLM_MODEL here to',\n '# change the model for every service; re-running bootstrap preserves your',\n \"# edits unless you explicitly re-select a model. Secrets do NOT live here.\",\n ...values.map(([k, v]) => `${k}=${v}`),\n MANAGED_END,\n ];\n}\n\n/**\n * Compute the final managed content from the existing file + a selection.\n *\n * Reconciliation per key:\n * - `overwrite` (explicit model re-selection): the selection wins; fall back\n * to any existing/imported value when the selection omits the key.\n * - otherwise (import-don't-clobber, the default): an existing value —\n * whether already in the block or a bare operator line being imported —\n * is preserved; the selection only fills keys the operator hasn't set.\n *\n * Returns `null` when a resolved value fails `.env`-safety validation (caller\n * turns it into an error result).\n */\nexport function buildManagedEnvContent(\n existing: string,\n selection: ManagedEnvSelection,\n opts: { overwrite?: boolean } = {},\n): { content: string } | { error: string } {\n const split = splitManaged(existing);\n // Bare operator lines (outside any block) that set a managed key — the\n // import-don't-clobber source on first encounter.\n const importedBefore = filterManaged(parseEnvContent(split.before.join('\\n')));\n const importedAfter = filterManaged(parseEnvContent(split.after.join('\\n')));\n\n const resolved: Array<[ManagedKey, string]> = [];\n for (const [key, selected] of selectionToPairs(selection)) {\n const existingVal =\n split.blockValues.get(key) ?? importedBefore.get(key) ?? importedAfter.get(key);\n const final = opts.overwrite ? (selected ?? existingVal) : (existingVal ?? selected);\n if (final === undefined) continue;\n if (!ENV_VALUE_RE.test(final)) {\n return { error: `${key} value ${JSON.stringify(final)} is not safe for a .env line` };\n }\n resolved.push([key, final]);\n }\n\n const before = stripManagedKeyLines(split.before);\n const after = stripManagedKeyLines(split.after);\n const block = renderBlock(resolved);\n\n // Reassemble: operator preamble, exactly one blank separator, block,\n // operator postamble. Trailing newline so the file is POSIX-clean.\n const parts = [joinTrimmed(before), block.join('\\n'), joinTrimmed(after)].filter(\n (s) => s.length > 0,\n );\n return { content: parts.join('\\n\\n') + '\\n' };\n}\n\n/** Keep only entries whose key is one we manage. */\nfunction filterManaged(all: Map<string, string>): Map<string, string> {\n const out = new Map<string, string>();\n for (const key of MANAGED_KEYS) {\n const v = all.get(key);\n if (v !== undefined) out.set(key, v);\n }\n return out;\n}\n\n/** Join a region and trim surrounding newlines so reassembly doesn't\n * accumulate blank runs across re-runs. Hand-rolled (no regex) to avoid the\n * anchored-quantifier backtracking the Sonar gate flags. */\nfunction joinTrimmed(region: string[]): string {\n const joined = region.join('\\n');\n let start = 0;\n let end = joined.length;\n while (start < end && joined[start] === '\\n') start++;\n while (end > start && joined[end - 1] === '\\n') end--;\n return joined.slice(start, end);\n}\n\n// ----------------------------------------------------------------------------\n// Read (for verify / #97) + write\n// ----------------------------------------------------------------------------\n\nexport interface NodeEnvModelConfig {\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: string;\n nodeEnv?: string;\n}\n\n/**\n * Read the effective model config from `<repoDir>/.env` (last-wins across the\n * whole file, so the managed block and any operator override resolve the same\n * way docker compose would). Missing file → empty config. Read-only: never\n * rewrites the block.\n */\nexport async function readEnvModelConfig(repoDir: string): Promise<NodeEnvModelConfig> {\n let content: string;\n try {\n content = await readFile(join(repoDir, '.env'), 'utf8');\n } catch {\n return {};\n }\n const map = parseEnvContent(content);\n const cfg: NodeEnvModelConfig = {};\n const llm = map.get('LLM_MODEL');\n const emb = map.get('EMBEDDINGS_MODEL');\n const prov = map.get('EMBEDDINGS_PROVIDER');\n const node = map.get('NODE_ENV');\n if (llm !== undefined) cfg.llmModel = llm;\n if (emb !== undefined) cfg.embeddingModel = emb;\n if (prov !== undefined) cfg.embeddingsProvider = prov;\n if (node !== undefined) cfg.nodeEnv = node;\n return cfg;\n}\n\n/**\n * Upsert the managed block in `<repoDir>/.env`, preserving all operator\n * content outside it. Writes atomically (temp + rename) so an interrupted\n * bootstrap can't leave a half-written file. Skips the write (unchanged=true)\n * when the rendered file is byte-identical to what's on disk — so a re-run\n * that changed nothing doesn't churn the file mtime.\n *\n * `overwrite: true` signals an explicit model (re)selection — the selection\n * wins. Default (false) is import-don't-clobber: existing values are kept.\n */\nexport async function writeManagedEnv(\n repoDir: string,\n selection: ManagedEnvSelection,\n opts: { overwrite?: boolean } = {},\n): Promise<WriteEnvFileResult> {\n const target = join(repoDir, '.env');\n\n let existing = '';\n let existingMode: number | undefined;\n try {\n existing = await readFile(target, 'utf8');\n existingMode = (await stat(target)).mode & 0o777;\n } catch {\n // No file yet — first run.\n }\n\n const built = buildManagedEnvContent(existing, selection, opts);\n if ('error' in built) return { ok: false, reason: built.error };\n if (built.content === existing) return { ok: true, path: target, unchanged: true };\n\n // Non-secret config, but default to 0644 for a fresh file (world-readable is\n // fine and matches a normal `.env`); preserve the operator's mode if the\n // file already existed so we don't silently loosen/tighten it.\n const mode = existingMode ?? 0o644;\n const tmp = `${target}.tmp.${process.pid}`;\n try {\n await mkdir(dirname(target), { recursive: true });\n await writeFile(tmp, built.content, { mode });\n await chmod(tmp, mode);\n await rename(tmp, target); // atomic on POSIX\n return { ok: true, path: target };\n } catch (err) {\n return { ok: false, reason: `writing ${target} failed: ${(err as Error).message}` };\n }\n}\n","/**\n * Locate or clone the operator's node deployment repo on the Mac Studio.\n *\n * The bootstrap subcommand wants a working tree of the operator's region\n * deployment repo (created from `OpusPopuli/opuspopuli-node` by `init`) on\n * the Studio's filesystem — it's the source of `docker-compose-prod.yml`,\n * `supabase/init/`, `backup/scripts/`, `observability/`, etc.\n *\n * Three discovery paths the wizard tries in order:\n *\n * 1. **Explicit `--repo-dir`** — operator passed a path. Verify it's a\n * node repo (looks for the marker file) and use it.\n * 2. **Current directory** — operator may have already cloned + cd'd.\n * Same marker probe.\n * 3. **Clone fresh** — shell out to `gh repo clone <owner>/<repo>` into\n * `~/Development/<repo>`. The default location keeps it under the\n * operator's home (no sudo) and groups it with other dev work.\n */\n\nimport { access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { safeExeca } from './exec.js';\n\n/** Files that a freshly-cloned (or template-derived) node repo always has.\n * Probing for these is how we distinguish a node repo from an arbitrary\n * directory the operator pointed us at. */\nexport const NODE_REPO_MARKERS = [\n 'docker-compose-prod.yml',\n 'supabase/init/pgsodium_getkey_env.sh',\n] as const;\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** True when every marker file is present at `dir`. False otherwise. */\nexport async function looksLikeNodeRepo(dir: string): Promise<boolean> {\n const checks = await Promise.all(\n NODE_REPO_MARKERS.map((m) => fileExists(join(dir, m))),\n );\n return checks.every((ok) => ok);\n}\n\nexport interface LocateInput {\n /** Owner of the node repo, e.g. `OpusPopuli`. */\n owner: string;\n /** Repo name, e.g. `opuspopuli-node-us-ca`. */\n name: string;\n /** Operator-supplied override (--repo-dir). When set, we use it iff it\n * looks like a node repo; otherwise return an error rather than fall\n * through to cloning a fresh copy. */\n explicit?: string;\n /** Where to put a fresh clone when neither --repo-dir nor cwd matches.\n * Default: ~/Development/<name>. */\n cloneInto?: string;\n /** When false, refuse to clone and require the operator to provide\n * a working tree (skip the gh shell-out). Default: true. */\n allowClone?: boolean;\n /** Working directory to probe as the \"already-cloned-and-cd'd\" path. */\n cwd?: string;\n}\n\nexport type LocateOutcome =\n | { kind: 'found'; path: string; source: 'explicit' | 'cwd' }\n | { kind: 'cloned'; path: string }\n | { kind: 'explicit-not-a-node-repo'; path: string }\n | { kind: 'gh-not-installed' }\n | { kind: 'clone-failed'; reason: string }\n | { kind: 'clone-disallowed' };\n\n/**\n * Walk the three discovery paths and return a discriminated outcome the\n * wizard can render. Cleanly separates \"operator-intentional path\" failures\n * from \"we tried but couldn't help\" failures.\n */\nexport async function locateOrCloneRepo(input: LocateInput): Promise<LocateOutcome> {\n // 1. Explicit --repo-dir.\n if (input.explicit) {\n if (await looksLikeNodeRepo(input.explicit)) {\n return { kind: 'found', path: input.explicit, source: 'explicit' };\n }\n return { kind: 'explicit-not-a-node-repo', path: input.explicit };\n }\n\n // 2. CWD probe.\n const cwd = input.cwd ?? process.cwd();\n if (await looksLikeNodeRepo(cwd)) {\n return { kind: 'found', path: cwd, source: 'cwd' };\n }\n\n // 3. Clone fresh.\n if (input.allowClone === false) {\n return { kind: 'clone-disallowed' };\n }\n\n const target = input.cloneInto ?? join(homedir(), 'Development', input.name);\n const res = await safeExeca('gh', ['repo', 'clone', `${input.owner}/${input.name}`, target]);\n if (res === null) return { kind: 'gh-not-installed' };\n if (res.exitCode !== 0) {\n return {\n kind: 'clone-failed',\n reason: `gh repo clone failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { kind: 'cloned', path: target };\n}\n","/**\n * Compile-time exhaustiveness guard. Passing a value that TypeScript has\n * not narrowed to `never` is a type error, so an unhandled `switch` / `if`\n * variant fails the build. At runtime this is a no-op — callers keep their\n * existing control flow (fall through, `return`, etc.).\n */\nexport function assertNever(_value: never): void {\n /* compile-time only */\n}\n","import { join } from 'node:path';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport {\n PGSODIUM_KEY_RE,\n SAFE_LAUNCHCTL_VALUE_RE,\n SAFE_URL_RE,\n TUNNEL_TOKEN_RE,\n URL_SAFE_PASSWORD_RE,\n WELL_KNOWN_GATEWAY_HMAC_SECRET,\n} from '../lib/constants.js';\nimport {\n detectBrew,\n HOMEBREW_INSTALL_COMMAND,\n installPackages,\n STUDIO_PACKAGES,\n} from '../lib/homebrew.js';\nimport {\n detectUnifiedMemoryGB,\n disableDiskSleep,\n enableAutoRestartOnPowerFailure,\n inspectSystem,\n} from '../lib/macos.js';\nimport {\n detectKeychain,\n isKeychainLocked,\n isSshSession,\n readSecret,\n saveSecret,\n unlockKeychain,\n type SecretAccount,\n} from '../lib/keychain.js';\nimport {\n generateDashboardPassword,\n generateGatewayHmacSecret,\n generateGrafanaAdminPassword,\n generateHmacApiKey,\n generateJwtSecret,\n generatePgsodiumRootKey,\n generatePostgresPassword,\n renderApiKeys,\n signSupabaseJwt,\n verifySupabaseJwt,\n} from '../lib/secrets.js';\nimport { setupLaunchAgent } from '../lib/launchagent.js';\nimport { installOpComposeWrapper } from '../lib/op-compose-install.js';\nimport {\n composeConfigImages,\n composePull,\n composeRemoveService,\n composeUp,\n filterVerifiableImages,\n loginToGhcr,\n waitForHealthy,\n type ComposeOptions,\n} from '../lib/docker.js';\nimport { cosignVerifyImage } from '../lib/cosign.js';\nimport {\n DEFAULT_EMBEDDING_MODEL,\n DEFAULT_EMBEDDINGS_PROVIDER,\n DEFAULT_LLM_MODEL,\n checkOllamaHealth,\n probeHostDockerInternal,\n setupModels,\n startOllamaService,\n type EmbeddingsProvider,\n} from '../lib/ollama.js';\nimport { writeManagedEnv } from '../lib/env-file.js';\nimport { locateOrCloneRepo, type LocateOutcome } from '../lib/noderepo.js';\nimport { safeExeca } from '../lib/exec.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { assertNever } from '../lib/assert.js';\n\n/** Compose profile set used in production mode — activates cloudflared. */\nconst PUBLIC_PROFILES = ['public'] as const;\n/** Compose profile set used in --local-only mode — keeps cloudflared down\n * via the template's profile gating. */\nconst LOCAL_PROFILES = [] as const;\n\n/** Node deployment topology — selects which docker compose stack(s) +\n * Keychain entries bootstrap provisions.\n *\n * - `region` — standard region node (civic data for one region). Connects\n * to a REMOTE prompt-service via PROMPT_SERVICE_URL. The HMAC key for\n * that remote service is issued by the prompts team and pasted in;\n * bootstrap stores it under the same Keychain account as the colocated\n * case so the wrapper exports it transparently. This is the production\n * default for any operator who isn't on the prompts team.\n *\n * - `region-with-prompts` — region node + colocated prompt-service overlay\n * (the us-ca / team / dev case). Bootstrap generates a local HMAC key,\n * a prompt-service admin key, and a prompts-db password — all stored\n * in Keychain — and the op-compose wrapper exports them so the\n * `docker-compose-prompt-service.yml` overlay can layer on top.\n *\n * - `prompts-only` — STUB. Reserved for when the prompts team deploys the\n * central prompts.opuspopuli.org instance. No region services; only the\n * prompt-service + its DB. Bootstrap currently exits with a \"not yet\n * implemented\" message — the flag exists so the CLI surface is stable\n * for the future deployment.\n */\ntype NodeType = 'region' | 'region-with-prompts' | 'prompts-only';\n\ninterface BootstrapOptions {\n region?: string;\n owner?: string;\n repoDir?: string;\n composeFile?: string[];\n envFile?: string;\n skipBrew?: boolean;\n skipLaunchAgent?: boolean;\n skipOllama?: boolean;\n skipStack?: boolean;\n localOnly?: boolean;\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: EmbeddingsProvider;\n /** Public-facing Supabase URL. Defaults to `http://localhost:8000` in\n * --local-only mode, otherwise `https://supabase.<domain>` — operator\n * can override with --supabase-url. */\n supabaseUrl?: string;\n /** Bypass the fail-closed cosign signature gate before `compose pull`.\n * Not recommended — trusts the registry contents unverified. */\n skipSignatureCheck?: boolean;\n /** Override the cosign certificate-identity regexp used to verify images\n * (e.g. after a workflow rename). Escape valve for the pinned default. */\n certificateIdentityRegexp?: string;\n /** Selects which deployment stack to provision. Defaults to `region`. */\n nodeType?: NodeType;\n /** For `--node-type region` (remote prompt-service): the URL of the\n * central prompt-service the backend should call. Defaults to\n * `https://prompts.opuspopuli.org`. Ignored in `region-with-prompts`\n * (the overlay pins it to the in-network hostname). */\n promptServiceUrl?: string;\n yes?: boolean;\n}\n\nexport const bootstrapCommand = new Command('bootstrap')\n .description(\n 'Configure the Mac Studio and bring the stack up. Run this on the Studio itself, after `init` has finished on your laptop.',\n )\n .addOption(new Option('--region <slug>', 'Region label set during init (e.g. us-ca)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the node repo').default('OpusPopuli'))\n .addOption(new Option('--repo-dir <path>', 'Explicit path to a checked-out node repo (overrides cwd + clone)'))\n .addOption(\n new Option(\n '--compose-file <path>',\n 'Repeatable. Compose file relative to repo root. Default: prod + backup (production), prod only (--local-only).',\n ).argParser(collectComposeFile),\n )\n .addOption(new Option('--env-file <path>', 'Compose --env-file. Default: .env.production'))\n .addOption(new Option('--skip-brew', \"Skip the Homebrew package install pass\").default(false))\n .addOption(\n new Option(\n '--skip-launch-agent',\n \"Skip the LaunchAgent setup (assumes one is already in place)\",\n ).default(false),\n )\n .addOption(new Option('--skip-ollama', \"Skip the Ollama model pull + warm\").default(false))\n .addOption(\n new Option(\n '--llm-model <model>',\n `Ollama LLM model to pull and warm. Default: ${DEFAULT_LLM_MODEL}. Examples: \\`llama3.3:70b\\`, \\`qwen2.5:72b\\`. Memory sizing table: docs/docker-resources.md in the opuspopuli-node template (or your region repo's checkout).`,\n ),\n )\n .addOption(\n new Option(\n '--embedding-model <model>',\n `Ollama embedding model. Default: ${DEFAULT_EMBEDDING_MODEL}. Only takes effect when the knowledge service runs with EMBEDDINGS_PROVIDER=ollama (otherwise embeddings are computed in-process via xenova).`,\n ),\n )\n .addOption(\n new Option(\n '--embeddings-provider <provider>',\n `Where embeddings are computed. Default: ${DEFAULT_EMBEDDINGS_PROVIDER} (in-process). \\`ollama\\` uses the host daemon with the embedding model. Written to the node's .env as the single source of truth.`,\n ).choices(['xenova', 'ollama']),\n )\n .addOption(\n new Option(\n '--supabase-url <url>',\n 'Public-facing Supabase URL (what browsers + microservices use). Default: `http://localhost:8000` in --local-only mode, otherwise `https://supabase.<domain>` (which the operator can override).',\n ),\n )\n .addOption(\n new Option(\n '--node-type <type>',\n 'Deployment topology. `region` (default) = region node connecting to remote prompt-service. `region-with-prompts` = region node + colocated prompt-service overlay (team/dev use). `prompts-only` = future stub for the central prompts deployment.',\n ).choices(['region', 'region-with-prompts', 'prompts-only']),\n )\n .addOption(\n new Option(\n '--prompt-service-url <url>',\n \"Remote prompt-service URL. Only meaningful for --node-type=region (default: https://prompts.opuspopuli.org). Ignored for --node-type=region-with-prompts (the overlay pins it to http://opuspopuli-prompts:3210).\",\n ),\n )\n .addOption(new Option('--skip-stack', \"Stop before `docker compose pull && up`\").default(false))\n .addOption(\n new Option(\n '--skip-signature-check',\n 'Bypass the fail-closed cosign verification of opuspopuli images before pull (NOT recommended — trusts the registry unverified).',\n ).default(false),\n )\n .addOption(\n new Option(\n '--certificate-identity-regexp <regexp>',\n 'Override the cosign certificate-identity regexp used to verify images (escape valve for the pinned default).',\n ),\n )\n .addOption(\n new Option(\n '--local-only',\n \"Run for local dev / testing: no Tunnel token required, cloudflared stays down. Auto-generates the pgsodium key if not in Keychain (init unnecessary).\",\n ).default(false),\n )\n .addOption(new Option('-y, --yes', 'Skip confirmation prompts').default(false))\n .action(async (opts: BootstrapOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node bootstrap ')));\n\n const nodeType = await selectNodeType(opts);\n const region = await resolveRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const repoName = `opuspopuli-node-${region}`;\n const composeFile = opts.composeFile ?? defaultComposeFiles(opts);\n\n // Model selection: flags override > interactive prompt > defaults. The\n // resolved values flow to both Ollama (pull + warm) and the LaunchAgent\n // (LLM_MODEL / EMBEDDINGS_MODEL). bootstrap is the source of truth for\n // what model runs. (N3)\n const llmModelChoice = opts.llmModel ?? (await selectLlmModel(opts));\n const [embeddingModel, llmModel] = resolveModels({\n llmModel: llmModelChoice,\n ...(opts.embeddingModel !== undefined ? { embeddingModel: opts.embeddingModel } : {}),\n });\n const embeddingsProvider = opts.embeddingsProvider ?? DEFAULT_EMBEDDINGS_PROVIDER;\n\n // ---- Phases 1–4: system checks, Homebrew, auth, locate repo ----\n await runSystemChecksPhase();\n await runBrewPhase(opts);\n await ensureGhAuth();\n await promptTailscaleSignin();\n const repoPath = await locateRegionRepoPhase(opts, owner, repoName);\n\n // ---- Phase 5: secrets (Keychain unlock, load/generate, URLs) ----\n await unlockKeychainPhase();\n\n const secrets = await collectSecretsPhase({ region, nodeType, opts });\n await runLaunchAgentPhase({ opts, secrets });\n await installWrapperPhase({ repoPath, region, promptServiceUrl: secrets.promptServiceUrl });\n await loginGhcrPhase();\n await runOllamaPhase({ opts, embeddingModel, llmModel, embeddingsProvider });\n await runEnvFilePhase({\n repoPath,\n llmModel,\n embeddingModel,\n embeddingsProvider,\n localOnly: Boolean(opts.localOnly),\n });\n await runStackPhase({ opts, repoPath, region, composeFile, secrets });\n });\n\n// ----------------------------------------------------------------------------\n// Bootstrap phases\n// ----------------------------------------------------------------------------\n// The command action delegates to these phase helpers so no single function\n// exceeds the cognitive-complexity budget. Each is behavior-preserving — the\n// interactive prompts, spinners, and `process.exit` calls are relocated\n// verbatim, not changed. The orchestrator threads values through explicitly.\n\ninterface CollectedSecrets {\n pgsodiumKey: string;\n tunnelToken: string | undefined;\n postgresPassword: string;\n jwtSecret: string;\n supabaseAnonKey: string;\n supabaseServiceRoleKey: string;\n dashboardPassword: string;\n /** API Gateway HMAC secret — signs gateway→microservice requests. Real\n * per-node value; MUST NOT equal WELL_KNOWN_GATEWAY_HMAC_SECRET on a\n * Tunnel-exposed node. */\n gatewayHmacSecret: string;\n /** Grafana admin password — overrides the `admin`/`admin` compose default. */\n grafanaAdminPassword: string;\n promptServiceUrl: string;\n supabaseUrl: string;\n /** prompt-service overlay secrets. Present for `--node-type\n * region-with-prompts` (all three) and, for `region`, just the API key used\n * to authenticate to the REMOTE prompt-service. These mirror what the\n * op-compose wrapper exports so bootstrap's OWN compose calls can process\n * the prompt-service overlay instead of failing on `${PROMPTS_DB_PASSWORD:?}`.\n * (#90) */\n promptsDbPassword?: string;\n promptServiceApiKey?: string;\n /** `<region>:<key>` — the value prompt-service reads as its API_KEYS list. */\n promptServiceApiKeys?: string;\n promptServiceAdminApiKeys?: string;\n}\n\n// Default compose file set by mode (review S4): production runs the\n// backup stack (restic / rclone) alongside the main stack; local-only\n// skips it (don't burn dev-machine disk on backups; don't try to push\n// to an R2 bucket that may not exist). Operator can still override\n// with explicit --compose-file flags.\nfunction defaultComposeFiles(opts: BootstrapOptions): string[] {\n return opts.localOnly\n ? ['docker-compose-prod.yml']\n : ['docker-compose-prod.yml', 'docker-compose-backup.yml'];\n}\n\n// Node type selects which stack to provision. Default is `region` — the\n// common case for any operator who isn't on the prompts team.\n// `region-with-prompts` covers the team/dev case where the operator runs\n// prompt-service alongside the region stack. `prompts-only` is a documented\n// stub for the future central prompts deployment — exits early to keep the\n// CLI surface stable now.\nasync function selectNodeType(opts: BootstrapOptions): Promise<NodeType> {\n const nodeType: NodeType = opts.nodeType\n ? opts.nodeType\n : (unwrap(\n await p.select({\n message: 'What kind of node are you provisioning?',\n options: [\n {\n value: 'region',\n label: 'Region node (civic data for one region, remote prompt-service)',\n },\n {\n value: 'region-with-prompts',\n label: 'Region + colocated prompt-service (team / dev)',\n },\n {\n value: 'prompts-only',\n label: 'Prompt-service node (central prompts deployment — future)',\n },\n ],\n initialValue: 'region',\n }),\n ) as NodeType);\n\n if (nodeType === 'prompts-only') {\n p.cancel(\n 'prompts-only node deployment is not yet implemented. ' +\n 'This flag exists so the CLI surface is stable for when the prompts team ' +\n 'deploys the central prompts.opuspopuli.org instance — but the deployment ' +\n 'stack (compose file, healthchecks, observability) is filled in later, ' +\n 'when there is an actual central prompt-service to deploy.',\n );\n process.exit(1);\n }\n return nodeType;\n}\n\n// Region label (required to find Keychain items + repo name).\nasync function resolveRegion(opts: BootstrapOptions): Promise<string> {\n return opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Region label (the slug used during init — e.g. us-ca)?',\n placeholder: 'us-ca',\n validate: (v) =>\n /^[a-z0-9-]{2,32}$/.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n}\n\n// ---- Phase 1: macOS sanity ----\nasync function runSystemChecksPhase(): Promise<void> {\n const sysSpin = p.spinner();\n sysSpin.start('Inspecting macOS…');\n const snap = await inspectSystem();\n sysSpin.stop(pc.green('✓ macOS inspected.'));\n\n if (!snap.isAppleSilicon) {\n p.cancel(\n `Bootstrap requires an Apple Silicon Mac (the runbook targets M-series). Detected: ${snap.osVersion ?? 'unknown'} (uname -m != arm64).`,\n );\n process.exit(1);\n }\n\n p.note(\n [\n `Hostname: ${pc.cyan(snap.hostname)}`,\n `macOS: ${pc.cyan(snap.osVersion ?? '(sw_vers failed)')}`,\n `Auto-restart on power: ${kvBool(snap.autoRestartOnPowerFailure)}`,\n `Disk sleep disabled: ${kvBool(snap.diskSleepDisabled)}`,\n `FileVault: ${kvFileVault(snap.fileVaultEnabled)}`,\n ].join('\\n'),\n 'System snapshot',\n );\n\n if (!snap.autoRestartOnPowerFailure) {\n const fix = unwrap(\n await p.confirm({\n message: 'Auto-restart-on-power-failure is OFF. Enable now (requires sudo)?',\n initialValue: true,\n }),\n );\n if (fix) {\n const r = await enableAutoRestartOnPowerFailure();\n if (!r.ok) p.note(`${pc.red('✗')} ${r.reason}`, 'pmset failed');\n }\n }\n if (!snap.diskSleepDisabled) {\n const fix = unwrap(\n await p.confirm({\n message: 'Disk sleep is enabled. Disable now (requires sudo)?',\n initialValue: true,\n }),\n );\n if (fix) {\n const r = await disableDiskSleep();\n if (!r.ok) p.note(`${pc.red('✗')} ${r.reason}`, 'pmset failed');\n }\n }\n}\n\n// ---- Phase 2: Homebrew + tool installs ----\nasync function runBrewPhase(opts: BootstrapOptions): Promise<void> {\n if (opts.skipBrew) return;\n\n const brewInfo = await detectBrew();\n if (!brewInfo.installed) {\n p.note(\n [\n `Homebrew is not installed. Open another shell and run:`,\n '',\n pc.cyan(HOMEBREW_INSTALL_COMMAND),\n '',\n pc.dim('Then come back and press Enter.'),\n ].join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'Homebrew installed?', initialValue: true }));\n }\n\n const brewSpin = p.spinner();\n brewSpin.start('Installing Studio packages… (~5–15 min first run)');\n const report = await installPackages(STUDIO_PACKAGES, (pkg, status) => {\n brewSpin.message(`${status}: ${pkg.name}`);\n });\n brewSpin.stop(\n report.failed.length === 0\n ? pc.green(\n `✓ ${report.installed.length} installed, ${report.alreadyPresent.length} already present`,\n )\n : pc.yellow(\n `⚠ ${report.installed.length} installed, ${report.alreadyPresent.length} present, ${report.failed.length} failed`,\n ),\n );\n if (report.failed.length > 0) {\n p.note(\n [\n report.failed.map((f) => `${pc.red('•')} ${f.pkg.name}: ${f.reason}`).join('\\n'),\n '',\n pc.dim('A partial install usually fails downstream (Docker / Ollama / compose).'),\n pc.dim('Install the failed packages manually and re-run with --skip-brew.'),\n ].join('\\n'),\n 'Brew failures',\n );\n const cont = unwrap(\n await p.confirm({\n message: 'Continue anyway? (Default no — recommended to fix and re-run.)',\n initialValue: false,\n }),\n );\n if (!cont) process.exit(1);\n }\n}\n\n// ---- Phase 4: Locate / clone the region repo (fail-fast — S6 review fix) ----\n// Moved up from Phase 8: a repo-not-found error after 5-10 minutes of\n// brew + Ollama work is operator-hostile. The clone only needs `gh`\n// (Phase 3), so we can validate the repo exists early and bail before\n// the slow stuff if it doesn't.\nasync function locateRegionRepoPhase(\n opts: BootstrapOptions,\n owner: string,\n repoName: string,\n): Promise<string> {\n const repoSpin = p.spinner();\n repoSpin.start('Locating your region node repo…');\n const located = await locateOrCloneRepo({\n owner,\n name: repoName,\n cwd: process.cwd(),\n ...(opts.repoDir ? { explicit: opts.repoDir } : {}),\n });\n const repoPath = repoPathFromLocate(located);\n if (!repoPath) {\n repoSpin.stop(pc.red('✗ Couldn\\'t locate or clone the region repo.'));\n handleLocateError(located, owner, repoName);\n process.exit(1);\n }\n repoSpin.stop(\n located.kind === 'cloned'\n ? pc.green(`✓ Cloned ${owner}/${repoName} to ${repoPath}`)\n : pc.green(`✓ Found region repo at ${repoPath}`),\n );\n return repoPath;\n}\n\n// ---- Phase 5: keychain availability + SSH unlock ----\n//\n// The Keychain item is local to the machine that wrote it (`init` on the\n// laptop). On a fresh Studio, both items will be missing on first run —\n// bootstrap prompts the operator to paste, validates the format, and writes\n// to the Studio's local Keychain for re-runs.\nasync function unlockKeychainPhase(): Promise<void> {\n const keychain = await detectKeychain();\n if (!keychain.available) {\n p.cancel(\n `${keychain.reason ?? 'Keychain unavailable'}. Bootstrap requires the macOS Keychain.`,\n );\n process.exit(1);\n }\n\n // SSH sessions don't auto-unlock the login keychain at session start.\n // When the operator is over SSH AND the keychain is currently locked,\n // every `security add-generic-password` call will fail with exit 36\n // (errSecInteractionNotAllowed). Prompt for the login password once\n // up front, unlock, then proceed — much better UX than 9 identical\n // failures (one per secret) before the operator figures it out.\n if (isSshSession() && (await isKeychainLocked())) {\n p.note(\n [\n 'SSH session detected with a locked login keychain.',\n 'macOS keychain operations require an unlocked keychain — your',\n 'login password will be used once to unlock it for this session.',\n 'The keychain remains unlocked until the session ends or it',\n 'idle-locks. To skip and unlock manually, press Ctrl+C and run',\n '`security unlock-keychain` yourself.',\n ].join('\\n'),\n 'Keychain unlock required',\n );\n const pw = unwrap(\n await p.password({\n message: 'macOS login password (for `security unlock-keychain`):',\n validate: (v) => (v && v.length > 0 ? undefined : 'password required'),\n }),\n );\n const unlock = await unlockKeychain(pw);\n if (!unlock.ok) {\n p.cancel(unlock.reason ?? 'security unlock-keychain failed.');\n process.exit(1);\n }\n p.note(`${pc.green('✓')} Keychain unlocked for this session.`, 'Keychain');\n }\n}\n\n// ---- Phase 5a: pgsodium key, tunnel token, and Supabase self-hosted creds ----\n//\n// In --local-only mode there's no Tunnel token at all (cloudflared stays\n// down via compose profile gating). The pgsodium key is still required\n// since the data services use it; if missing, we generate a fresh one\n// inline rather than requiring an `init` call first.\n//\n// The five Supabase values (postgres password, JWT secret, anon +\n// service_role JWTs, dashboard password) are auto-generated on first run\n// via the same `loadSecret` path used for the pgsodium key. The two JWTs\n// are derived from JWT_SECRET and re-validated against it so a stale token\n// cached from a prior bootstrap can't silently break auth.\nasync function collectCoreSecrets(args: {\n region: string;\n opts: BootstrapOptions;\n}): Promise<Omit<CollectedSecrets, 'promptServiceUrl' | 'supabaseUrl'>> {\n const { region, opts } = args;\n const pgsodiumKey = await loadSecret({\n region,\n account: 'pgsodium-root-key',\n label: 'pgsodium master key',\n validate: (v) =>\n PGSODIUM_KEY_RE.test(v) ? undefined : 'must be exactly 64 lowercase hex characters',\n ...(opts.localOnly ? { generate: generatePgsodiumRootKey } : {}),\n });\n\n const tunnelToken = opts.localOnly\n ? undefined\n : await loadSecret({\n region,\n account: 'tunnel-token',\n label: 'Cloudflare Tunnel token',\n placeholder: 'JWT-style base64url string from `terraform output tunnel_token`',\n validate: (v) =>\n TUNNEL_TOKEN_RE.test(v) ? undefined : 'tunnel token must be a base64-url JWT',\n });\n\n const postgresPassword = await loadSecret({\n region,\n account: 'postgres-password',\n label: 'Postgres password',\n // URL-safe alphabet required — value lands in postgres:// URIs where\n // `+`/`/`/`=` cause parser ambiguity in gotrue/postgrest/storage.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generatePostgresPassword,\n });\n\n const jwtSecret = await loadSecret({\n region,\n account: 'jwt-secret',\n label: 'JWT signing secret',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && v.length >= 32\n ? undefined\n : 'must be ≥32 base64 characters',\n generate: generateJwtSecret,\n });\n\n // Derived JWTs MUST match the current jwtSecret's signature — otherwise\n // a stale anon/service_role token (cached from a previous bootstrap with\n // a different JWT_SECRET) sails past the shape check and breaks every\n // auth call silently. verifySupabaseJwt re-runs the HMAC and rejects on\n // mismatch, triggering regeneration with the current secret.\n const supabaseAnonKey = await loadSecret({\n region,\n account: 'supabase-anon-key',\n label: 'Supabase anon key',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && verifySupabaseJwt(v, jwtSecret)\n ? undefined\n : 'must be a base64url JWT signed by the current JWT_SECRET',\n generate: () => signSupabaseJwt({ role: 'anon', secret: jwtSecret }),\n });\n\n const supabaseServiceRoleKey = await loadSecret({\n region,\n account: 'supabase-service-role-key',\n label: 'Supabase service role key',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && verifySupabaseJwt(v, jwtSecret)\n ? undefined\n : 'must be a base64url JWT signed by the current JWT_SECRET',\n generate: () => signSupabaseJwt({ role: 'service_role', secret: jwtSecret }),\n });\n\n const dashboardPassword = await loadSecret({\n region,\n account: 'dashboard-password',\n label: 'Supabase Studio dashboard password',\n // URL-safe alphabet required — value lands in basic-auth headers via\n // kong's declarative config. Avoid `+`/`/`/`=` for the same reasons.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateDashboardPassword,\n });\n\n // API Gateway HMAC secret. Always generated so a bootstrapped node never\n // runs on the template's well-known compose default (which every checkout\n // shares). The value ALSO drives API_KEYS `{\"api-gateway\":\"<this>\"}`, so\n // the api-gateway's key equals GATEWAY_HMAC_SECRET and its signature\n // verifies. URL-safe alphabet keeps it clean inside the API_KEYS JSON.\n // Reject the well-known default explicitly: if a prior run (or a manual\n // paste) stored the placeholder, treat it as invalid and regenerate.\n const gatewayHmacSecret = await loadSecret({\n region,\n account: 'gateway-hmac-secret',\n label: 'API Gateway HMAC secret',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) && v !== WELL_KNOWN_GATEWAY_HMAC_SECRET\n ? undefined\n : 'must be base64url chars only (no + / =) and not the well-known template default',\n generate: generateGatewayHmacSecret,\n });\n\n const grafanaAdminPassword = await loadSecret({\n region,\n account: 'grafana-admin-password',\n label: 'Grafana admin password',\n // URL-safe alphabet — exported into the compose env for Grafana's\n // GF_SECURITY_ADMIN_PASSWORD; keep it free of shell/URL metacharacters.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateGrafanaAdminPassword,\n });\n\n return {\n pgsodiumKey,\n tunnelToken,\n postgresPassword,\n jwtSecret,\n supabaseAnonKey,\n supabaseServiceRoleKey,\n dashboardPassword,\n gatewayHmacSecret,\n grafanaAdminPassword,\n };\n}\n\n// ---- Phase 5b: prompt-service credentials + URL ----\n//\n// Branches on nodeType:\n// `region-with-prompts` — operator owns both ends. Generate all three\n// secrets (DB password + HMAC + admin HMAC); the colocated overlay\n// consumes them via env.\n// `region` — operator's prompt-service is REMOTE. They received an HMAC\n// key from the prompts team; bootstrap prompts them to paste it. The DB\n// password + admin key are skipped (no local DB, no admin access).\ninterface PromptServiceSecrets {\n url: string;\n promptsDbPassword?: string;\n promptServiceApiKey?: string;\n promptServiceApiKeys?: string;\n promptServiceAdminApiKeys?: string;\n}\n\nasync function collectPromptServiceSecrets(args: {\n region: string;\n nodeType: NodeType;\n opts: BootstrapOptions;\n}): Promise<PromptServiceSecrets> {\n const { region, nodeType, opts } = args;\n // Capture each loaded/generated value — bootstrap's own compose calls need\n // them in the env (via buildComposeEnv) to bring the prompt-service overlay\n // up, mirroring the op-compose wrapper. (#90)\n let promptsDbPassword: string | undefined;\n let promptServiceApiKey: string | undefined;\n let promptServiceAdminApiKeys: string | undefined;\n if (nodeType === 'region-with-prompts') {\n promptsDbPassword = await loadSecret({\n region,\n account: 'prompts-db-password',\n label: 'prompt-service Postgres password',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generatePostgresPassword,\n });\n\n promptServiceApiKey = await loadSecret({\n region,\n account: 'prompt-service-api-key',\n label: 'prompt-service HMAC API key',\n // Same URL-safe alphabet as other HMAC keys; embedded in the\n // `<region>:<key>` API_KEYS list and in Authorization headers.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateHmacApiKey,\n });\n\n promptServiceAdminApiKeys = await loadSecret({\n region,\n account: 'prompt-service-admin-api-key',\n label: 'prompt-service admin API key',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateHmacApiKey,\n });\n } else {\n // nodeType === 'region': paste-only path. No `generate`, so loadSecret\n // falls through to the operator-paste prompt.\n promptServiceApiKey = await loadSecret({\n region,\n account: 'prompt-service-api-key',\n label: 'prompt-service HMAC API key (issued by the prompts team)',\n placeholder: 'paste the region-specific HMAC key',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n });\n }\n\n // Remote prompt-service URL — only resolved when NOT colocating.\n // For region-with-prompts the overlay hardcodes http://opuspopuli-prompts:3210\n // on the relevant services; no shell env needed.\n const promptServiceUrl =\n nodeType === 'region-with-prompts'\n ? // eslint-disable-next-line sonarjs/no-clear-text-protocols -- in-network (docker) prompt-service URL is legitimately plaintext http; no TLS on the internal bridge\n 'http://opuspopuli-prompts:3210'\n : (opts.promptServiceUrl ?? 'https://prompts.opuspopuli.org');\n if (!SAFE_URL_RE.test(promptServiceUrl)) {\n p.cancel(\n `--prompt-service-url ${JSON.stringify(promptServiceUrl)} contains characters outside the allowed URL set`,\n );\n process.exit(1);\n }\n return {\n url: promptServiceUrl,\n ...(promptsDbPassword !== undefined ? { promptsDbPassword } : {}),\n // PROMPT_SERVICE_API_KEY is the raw key; PROMPT_SERVICE_API_KEYS is the\n // `<region>:<key>` list prompt-service validates against — same derivation\n // the op-compose wrapper does.\n ...(promptServiceApiKey !== undefined\n ? { promptServiceApiKey, promptServiceApiKeys: `${region}:${promptServiceApiKey}` }\n : {}),\n ...(promptServiceAdminApiKeys !== undefined ? { promptServiceAdminApiKeys } : {}),\n };\n}\n\n// SUPABASE_URL gets baked into gotrue's API_EXTERNAL_URL and into every\n// magic-link callback gotrue emails to users. localhost is only correct\n// in --local-only mode; for a Tunnel-exposed production node, emailing\n// links pointing at http://localhost:8000 silently breaks signups.\n//\n// Resolution order:\n// --local-only mode → default http://localhost:8000 (no prompt)\n// non-local-only → require --supabase-url OR prompt for the\n// public-facing URL.\nasync function resolveSupabaseUrl(opts: BootstrapOptions): Promise<string> {\n let supabaseUrl: string;\n if (opts.supabaseUrl) {\n supabaseUrl = opts.supabaseUrl;\n } else if (opts.localOnly) {\n supabaseUrl = 'http://localhost:8000';\n } else {\n supabaseUrl = unwrap(\n await p.text({\n message: 'Public-facing Supabase URL (what browsers + microservices use to reach kong)?',\n placeholder: 'https://supabase.civicfeed.tx',\n validate: (v) => {\n if (!v) return 'required';\n return SAFE_URL_RE.test(v)\n ? undefined\n : 'contains characters outside the allowed URL set';\n },\n }),\n );\n }\n if (!SAFE_URL_RE.test(supabaseUrl)) {\n p.cancel(\n `--supabase-url ${JSON.stringify(supabaseUrl)} contains characters outside the allowed URL set`,\n );\n process.exit(1);\n }\n return supabaseUrl;\n}\n\n// Phase 5 aggregate: run all secret-collection sub-phases in order.\nasync function collectSecretsPhase(args: {\n region: string;\n nodeType: NodeType;\n opts: BootstrapOptions;\n}): Promise<CollectedSecrets> {\n const core = await collectCoreSecrets({ region: args.region, opts: args.opts });\n const { url: promptServiceUrl, ...promptSecrets } = await collectPromptServiceSecrets(args);\n const supabaseUrl = await resolveSupabaseUrl(args.opts);\n return { ...core, ...promptSecrets, promptServiceUrl, supabaseUrl };\n}\n\n// ---- Phase 6: LaunchAgent ----\n// Note: model config (LLM_MODEL / EMBEDDINGS_MODEL / NODE_ENV) is deliberately\n// NOT exported here. Those are non-secret substitution vars that live in the\n// node's `.env` (see runEnvFilePhase) — a launchctl setenv value would shadow\n// `.env` at compose interpolation time (shell env > .env), defeating the\n// single-source-of-truth. Only Keychain secrets flow through the LaunchAgent.\nasync function runLaunchAgentPhase(args: {\n opts: BootstrapOptions;\n secrets: CollectedSecrets;\n}): Promise<void> {\n const { opts, secrets } = args;\n if (opts.skipLaunchAgent) return;\n\n const laSpin = p.spinner();\n laSpin.start('Writing pgsodium key file + LaunchAgent plist…');\n const la = await setupLaunchAgent({\n pgsodiumKey: secrets.pgsodiumKey,\n ...(secrets.tunnelToken !== undefined ? { tunnelToken: secrets.tunnelToken } : {}),\n postgresPassword: secrets.postgresPassword,\n jwtSecret: secrets.jwtSecret,\n supabaseAnonKey: secrets.supabaseAnonKey,\n supabaseServiceRoleKey: secrets.supabaseServiceRoleKey,\n dashboardPassword: secrets.dashboardPassword,\n gatewayHmacSecret: secrets.gatewayHmacSecret,\n grafanaAdminPassword: secrets.grafanaAdminPassword,\n supabaseUrl: secrets.supabaseUrl,\n });\n if (!la.ok) {\n laSpin.stop(pc.red(`✗ LaunchAgent step ${la.step} failed.`));\n p.cancel(la.reason ?? 'LaunchAgent setup failed.');\n process.exit(1);\n }\n laSpin.stop(\n pc.green(\n `✓ LaunchAgent loaded (${la.paths.plistFile})${opts.localOnly ? ' — local-only mode, no TUNNEL_TOKEN set' : ''}.`,\n ),\n );\n}\n\n// ---- Phase 6b: install op-compose wrapper ----\n//\n// launchctl setenv doesn't reach pre-existing shells or sshd children, so\n// operator-driven `docker compose` invocations would hard-fail on the\n// `${VAR:?…}` enforcement in the template even though the values sit safely\n// in Keychain. The wrapper reads Keychain on every invocation and exports\n// the values only into the docker compose subprocess's env.\nasync function installWrapperPhase(args: {\n repoPath: string;\n region: string;\n promptServiceUrl: string;\n}): Promise<void> {\n const { repoPath, region, promptServiceUrl } = args;\n const wrapperSpin = p.spinner();\n wrapperSpin.start('Installing bin/op-compose wrapper…');\n const wrapper = await installOpComposeWrapper({ repoDir: repoPath, region, promptServiceUrl });\n if (!wrapper.ok) {\n wrapperSpin.stop(pc.red('✗ op-compose wrapper install failed.'));\n p.cancel(wrapper.reason ?? 'op-compose wrapper install failed.');\n process.exit(1);\n }\n wrapperSpin.stop(pc.green(`✓ Installed ${wrapper.path} (mode 0755).`));\n}\n\n// ---- Phase 7: ghcr.io login ----\nasync function loginGhcrPhase(): Promise<void> {\n const ghcrSpin = p.spinner();\n ghcrSpin.start('Authenticating Docker to ghcr.io…');\n const ghcr = await loginToGhcr();\n if (!ghcr.ok) {\n ghcrSpin.stop(pc.red('✗ ghcr.io login failed.'));\n p.cancel(ghcr.reason ?? 'ghcr.io login failed.');\n process.exit(1);\n }\n ghcrSpin.stop(pc.green('✓ Logged in to ghcr.io.'));\n}\n\n/**\n * The models bootstrap pulls into Ollama, in pull order. The LLM is always\n * pulled. The embedding model is pulled ONLY when the knowledge service will\n * use the Ollama daemon for embeddings (`EMBEDDINGS_PROVIDER=ollama`); under\n * the default `xenova` (in-process) provider it's never loaded, so pulling\n * nomic-embed-text would just waste a download on a fresh node. When present,\n * the embedding pulls first — it's small, giving fast \"✓ pulled\" feedback\n * before the LLM's multi-GB download dominates the spinner. Pure helper.\n */\nexport function modelsToPull(args: {\n provider: EmbeddingsProvider;\n llmModel: string;\n embeddingModel: string;\n}): string[] {\n const { provider, llmModel, embeddingModel } = args;\n return provider === 'ollama' ? [embeddingModel, llmModel] : [llmModel];\n}\n\n// ---- Phase 8: Ollama ----\nasync function runOllamaPhase(args: {\n opts: BootstrapOptions;\n embeddingModel: string;\n llmModel: string;\n embeddingsProvider: EmbeddingsProvider;\n}): Promise<void> {\n const { opts, embeddingModel, llmModel, embeddingsProvider } = args;\n if (opts.skipOllama) return;\n\n const olSpin = p.spinner();\n olSpin.start(`Pulling + warming Ollama models… (${estimatedPullTime(llmModel)})`);\n let olHealth = await checkOllamaHealth();\n if (!olHealth.reachable) {\n // S5 review fix: try to start the service before bailing. The\n // operator's pretty much always going to want this anyway, and\n // `brew services start` is no-op-safe.\n olSpin.message('Ollama not reachable — running `brew services start ollama`…');\n const start = await startOllamaService();\n if (!start.ok) {\n olSpin.stop(pc.red('✗ Couldn\\'t start Ollama service.'));\n p.cancel(\n `${start.reason ?? 'unknown'} — start it manually with \\`brew services start ollama\\` and re-run with --skip-brew --skip-launch-agent.`,\n );\n process.exit(1);\n }\n // Brew services start returns immediately; the daemon needs a few\n // seconds before /api/tags responds. Quick wait + re-probe.\n await new Promise((res) => setTimeout(res, 3000));\n olHealth = await checkOllamaHealth();\n if (!olHealth.reachable) {\n olSpin.stop(\n pc.yellow('⚠ Ollama service started but daemon not yet answering on :11434.'),\n );\n p.cancel(\n 'Give it another few seconds, then re-run with --skip-brew --skip-launch-agent.',\n );\n process.exit(1);\n }\n }\n const toPull = modelsToPull({ provider: embeddingsProvider, llmModel, embeddingModel });\n const modelReport = await setupModels(toPull, (model, status) => {\n olSpin.message(`${status}: ${model}`);\n });\n olSpin.stop(\n modelReport.failed.length === 0\n ? pc.green(\n `✓ ${modelReport.pulled.length} pulled, ${modelReport.alreadyPresent.length} present, ${modelReport.warmed.length} warmed`,\n )\n : pc.yellow(`⚠ ${modelReport.failed.length} model pull(s) failed`),\n );\n if (embeddingsProvider !== 'ollama') {\n p.note(\n `${pc.dim('·')} Skipped pulling the embedding model — EMBEDDINGS_PROVIDER=${embeddingsProvider} computes embeddings in-process (no Ollama model needed).`,\n 'Embeddings',\n );\n }\n const probe = await probeHostDockerInternal();\n if (!probe.ok) {\n p.note(`${pc.yellow('⚠')} ${probe.reason}`, 'Docker host networking');\n }\n}\n\n// ---- Phase 8c: write the single-source `.env` (model config) ----\n//\n// docker compose auto-loads `.env` from the compose file's directory, so the\n// resolved model config lands there as the single source of truth — every\n// service (and every future partial recreate) interpolates `${LLM_MODEL:-…}`\n// to the SAME value regardless of shell/launchd env. Only non-secret config\n// is written; secrets stay in Keychain (op-compose hydrates them).\n//\n// Runs even under --skip-stack so the operator's later `./bin/op-compose up`\n// reads it. `overwrite: true` because bootstrap IS an explicit model\n// (re)selection — the operator either passed --llm-model or picked one\n// interactively, so their choice is authoritative over a stale block. Operator\n// lines OUTSIDE the managed block are always preserved.\nasync function runEnvFilePhase(args: {\n repoPath: string;\n llmModel: string;\n embeddingModel: string;\n embeddingsProvider: EmbeddingsProvider;\n localOnly: boolean;\n}): Promise<void> {\n const { repoPath, llmModel, embeddingModel, embeddingsProvider, localOnly } = args;\n const envSpin = p.spinner();\n envSpin.start('Writing model config to the node .env…');\n const res = await writeManagedEnv(\n repoPath,\n {\n llmModel,\n embeddingModel,\n embeddingsProvider,\n // NODE_ENV=development only for local-dev nodes; production nodes leave\n // it unset (the compose default / container images decide).\n ...(localOnly ? { nodeEnv: 'development' } : {}),\n },\n { overwrite: true },\n );\n if (!res.ok) {\n envSpin.stop(pc.red('✗ Failed to write the node .env.'));\n p.cancel(res.reason ?? 'writing .env failed.');\n process.exit(1);\n }\n envSpin.stop(\n res.unchanged\n ? pc.green(`✓ Model config already current in ${res.path}.`)\n : pc.green(`✓ Wrote model config to ${res.path} (LLM_MODEL=${llmModel}).`),\n );\n}\n\n// Hydrate every `${VAR:?…}`-enforced env var on the compose subprocess.\n// launchctl setenv doesn't reach pre-existing shells or sshd children, so\n// bootstrap's own compose calls would otherwise hard-fail even though every\n// value sits in process scope from the loadSecret pass. Pure builder — kept\n// separate so the env-hydration rule stays unit-testable.\nexport function buildComposeEnv(args: {\n secrets: CollectedSecrets;\n}): NodeJS.ProcessEnv {\n const { secrets } = args;\n return {\n PGSODIUM_ROOT_KEY: secrets.pgsodiumKey,\n POSTGRES_PASSWORD: secrets.postgresPassword,\n JWT_SECRET: secrets.jwtSecret,\n SUPABASE_ANON_KEY: secrets.supabaseAnonKey,\n SUPABASE_SERVICE_ROLE_KEY: secrets.supabaseServiceRoleKey,\n DASHBOARD_PASSWORD: secrets.dashboardPassword,\n // Real per-node gateway HMAC secret + the derived API_KEYS map. These\n // override the template's well-known `${GATEWAY_HMAC_SECRET:-…}` /\n // `${API_KEYS:-…}` compose defaults so a Tunnel-exposed node never signs\n // with the shared placeholder. The api-gateway's key MUST equal\n // GATEWAY_HMAC_SECRET, which renderApiKeys guarantees.\n GATEWAY_HMAC_SECRET: secrets.gatewayHmacSecret,\n API_KEYS: renderApiKeys(secrets.gatewayHmacSecret),\n GRAFANA_ADMIN_PASSWORD: secrets.grafanaAdminPassword,\n SUPABASE_URL: secrets.supabaseUrl,\n AUTH_JWT_SECRET: process.env['AUTH_JWT_SECRET'] ?? secrets.jwtSecret,\n ...(secrets.tunnelToken !== undefined ? { TUNNEL_TOKEN: secrets.tunnelToken } : {}),\n // prompt-service wiring — mirrors the op-compose wrapper so bootstrap's OWN\n // compose calls can process the region-with-prompts overlay instead of\n // aborting on `${PROMPTS_DB_PASSWORD:?}`. PROMPT_SERVICE_URL is always set\n // (in-network for colocated, remote otherwise); the rest are present only\n // when the node runs or calls a prompt-service. (#90)\n PROMPT_SERVICE_URL: secrets.promptServiceUrl,\n ...(secrets.promptsDbPassword !== undefined\n ? { PROMPTS_DB_PASSWORD: secrets.promptsDbPassword }\n : {}),\n ...(secrets.promptServiceApiKey !== undefined\n ? { PROMPT_SERVICE_API_KEY: secrets.promptServiceApiKey }\n : {}),\n ...(secrets.promptServiceApiKeys !== undefined\n ? { PROMPT_SERVICE_API_KEYS: secrets.promptServiceApiKeys }\n : {}),\n ...(secrets.promptServiceAdminApiKeys !== undefined\n ? { PROMPT_SERVICE_ADMIN_API_KEYS: secrets.promptServiceAdminApiKeys }\n : {}),\n // Model config (LLM_MODEL / EMBEDDINGS_MODEL / NODE_ENV) is intentionally\n // NOT injected here — it lives in the node's `.env` (runEnvFilePhase),\n // which docker compose auto-loads. Injecting it into the subprocess env\n // would shadow `.env` (shell env > .env) and reintroduce the drift the\n // single-source `.env` exists to eliminate.\n };\n}\n\n// ---- Public-profile secret guard (#27) ----\n// A node exposed via the Cloudflare Tunnel (the `public` compose profile,\n// activated for every non-`--local-only` bootstrap) MUST NOT sign\n// gateway→microservice requests with the template's well-known\n// GATEWAY_HMAC_SECRET / API_KEYS default — every checkout of the template\n// carries that identical string. buildComposeEnv always injects a real\n// per-node value, so in normal bootstrap this guard never trips; it is a\n// fail-closed backstop against a future refactor that lets the placeholder\n// (or an unset value) reach a Tunnel-exposed compose `up`.\n//\n// `--local-only` bootstraps do NOT activate the public profile, so the\n// defaults are acceptable there and MUST NOT be blocked.\nexport type PublicProfileSecretVerdict =\n | { ok: true }\n | { ok: false; reason: string };\n\n// Pure decision — unit-tested independently of the interactive compose flow.\n// `env` is the resolved compose env buildComposeEnv produced.\nexport function checkPublicProfileSecrets(\n env: NodeJS.ProcessEnv,\n): PublicProfileSecretVerdict {\n const gateway = env['GATEWAY_HMAC_SECRET'];\n const apiKeys = env['API_KEYS'];\n const bad = (v: string | undefined): boolean =>\n v === undefined || v.length === 0 || v.includes(WELL_KNOWN_GATEWAY_HMAC_SECRET);\n if (bad(gateway) || bad(apiKeys)) {\n return {\n ok: false,\n reason:\n 'Refusing to expose this node via the Cloudflare Tunnel (public profile) with the ' +\n 'well-known GATEWAY_HMAC_SECRET / API_KEYS default. Every copy of the template ships ' +\n 'the same placeholder value — a Tunnel-exposed gateway signed with it is trivially ' +\n 'forgeable. Re-run `create-op-node bootstrap` so it generates a real per-node secret ' +\n '(or use `--local-only` to run without the public profile).',\n };\n }\n return { ok: true };\n}\n\n// Enforce the guard, aborting bootstrap with an operator-friendly message\n// when the public profile would carry the well-known default. No-op when\n// the public profile isn't in play (--local-only).\nfunction enforcePublicProfileSecrets(args: {\n localOnly: boolean;\n env: NodeJS.ProcessEnv;\n}): void {\n if (args.localOnly) return;\n const verdict = checkPublicProfileSecrets(args.env);\n if (!verdict.ok) {\n p.cancel(verdict.reason);\n process.exit(1);\n }\n}\n\n// ---- Phase 8b: fail-closed image-signature gate ----\n// Before pulling, confirm each opuspopuli-published image carries a valid\n// cosign signature from the release workflow (keyless, Rekor-logged). This is\n// FAIL-CLOSED: a missing cosign binary, an un-enumerable compose config, or any\n// failed verification aborts the bootstrap — unless the operator opts out with\n// --skip-signature-check. Third-party base images (postgres, kong, ollama, …)\n// aren't signed by us, so they're excluded. Images are verified by their\n// compose ref (tag); cosign resolves the tag to a digest.\n//\n// This gate verifies the *images* we publish, not the compose file itself — a\n// compromised compose that points services off `ghcr.io/opuspopuli/*` resolves\n// to zero verifiable images (handled loudly by the `no-images` case).\n\nexport type SignatureGatePlan =\n | { kind: 'skip' }\n | { kind: 'enumerate-failed' }\n | { kind: 'no-images' }\n | { kind: 'verify'; images: string[] };\n\n// Pure decision for the signature gate — separated so the branch logic\n// (bypass / can't-enumerate / nothing-to-verify / verify-these) is unit-tested\n// independently of the interactive cosign loop. `allImages` is the resolved\n// compose image list, or null when enumeration failed.\nexport function planSignatureGate(\n allImages: string[] | null,\n opts: Pick<BootstrapOptions, 'skipSignatureCheck'>,\n): SignatureGatePlan {\n if (opts.skipSignatureCheck) return { kind: 'skip' };\n if (allImages === null) return { kind: 'enumerate-failed' };\n const images = filterVerifiableImages(allImages);\n if (images.length === 0) return { kind: 'no-images' };\n return { kind: 'verify', images };\n}\n\nasync function verifyImageSignaturesPhase(\n composeOpts: ComposeOptions,\n opts: BootstrapOptions,\n): Promise<void> {\n // Only enumerate when we're actually going to verify (skip avoids the call).\n const allImages = opts.skipSignatureCheck ? null : await composeConfigImages(composeOpts);\n const plan = planSignatureGate(allImages, opts);\n\n if (plan.kind === 'skip') {\n p.note(\n pc.yellow(\n '⚠ Skipping cosign signature verification (--skip-signature-check). ' +\n 'Images will be pulled unverified — you are trusting the registry contents.',\n ),\n 'Supply chain',\n );\n return;\n }\n if (plan.kind === 'enumerate-failed') {\n p.cancel(\n '`docker compose config --images` failed, so signatures can\\'t be verified. ' +\n 'Fix the compose config (or re-run with --skip-signature-check to bypass).',\n );\n process.exit(1);\n }\n if (plan.kind === 'no-images') {\n // Loud on purpose: prod compose should carry opuspopuli images, so an empty\n // set is either a custom compose or a tampered one pointing elsewhere.\n p.note(\n pc.yellow(\n '⚠ No `ghcr.io/opuspopuli/*` images in the resolved compose set, so there is ' +\n 'nothing to verify. If you did not expect this, inspect your compose files — ' +\n 'this gate verifies the images we publish, not the compose file itself.',\n ),\n 'Supply chain',\n );\n return;\n }\n\n // plan.kind === 'verify'. cosign reads docker's ghcr credentials (populated by\n // the earlier ghcr.io login phase) to fetch each signature.\n const spin = p.spinner();\n spin.start('Verifying image signatures with cosign…');\n for (const image of plan.images) {\n spin.message(`cosign verify ${image}`);\n const verdict = await cosignVerifyImage({\n image,\n ...(opts.certificateIdentityRegexp\n ? { certificateIdentityRegexp: opts.certificateIdentityRegexp }\n : {}),\n });\n if (!verdict.ok) {\n spin.stop(pc.red(`✗ Signature verification failed for ${image}.`));\n const detail = verdict.skipped\n ? `${verdict.reason}\\n` +\n 'cosign is required for the fail-closed signature gate — install it ' +\n '(`brew install cosign`, or re-run without --skip-brew) or bypass with --skip-signature-check.'\n : verdict.reason;\n p.cancel(detail);\n process.exit(1);\n }\n }\n spin.stop(\n pc.green(\n `✓ ${plan.images.length} image signature${plan.images.length === 1 ? '' : 's'} verified.`,\n ),\n );\n}\n\n// ---- Phase 9 + 10: docker compose pull + up, then health-check loop ----\nasync function runStackPhase(args: {\n opts: BootstrapOptions;\n repoPath: string;\n region: string;\n composeFile: string[];\n secrets: CollectedSecrets;\n}): Promise<void> {\n const { opts, repoPath, region, composeFile, secrets } = args;\n\n if (opts.skipStack) {\n const profileFlag = opts.localOnly ? '' : '--profile public ';\n p.outro(\n pc.cyan(\n `Stack-up skipped. Run \\`./bin/op-compose -f ${composeFile.join(' -f ')} ${profileFlag}pull && ./bin/op-compose -f ${composeFile.join(' -f ')} ${profileFlag}up -d\\` from ${repoPath} when ready. (op-compose hydrates Keychain secrets per-invocation; use it instead of raw \\`docker compose\\`.)`,\n ),\n );\n return;\n }\n\n const composeFiles = resolveComposeFiles(repoPath, composeFile);\n const composeEnv = buildComposeEnv({ secrets });\n // In production mode, activate the `public` compose profile so cloudflared\n // starts. In --local-only mode pass no profiles — the template gates\n // cloudflared behind `public`, so an empty profiles array keeps it down.\n const composeOpts = {\n files: composeFiles,\n cwd: repoPath,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n profiles: opts.localOnly ? LOCAL_PROFILES : PUBLIC_PROFILES,\n env: composeEnv,\n };\n\n // Fail-closed: never bring up the public (Tunnel-exposed) profile with the\n // template's well-known GATEWAY_HMAC_SECRET / API_KEYS default. (#27)\n enforcePublicProfileSecrets({ localOnly: Boolean(opts.localOnly), env: composeEnv });\n\n // In --local-only mode, evict any cloudflared container left over from a\n // prior public bootstrap on this Studio. Without this, `compose ps` would\n // still list cloudflared and the health-check loop would demand it reach\n // healthy with no TUNNEL_TOKEN — hanging until timeout. (review S3)\n if (opts.localOnly) {\n const evict = p.spinner();\n evict.start('Evicting any cloudflared from a prior public bootstrap…');\n const rm = await composeRemoveService(\n { ...composeOpts, profiles: PUBLIC_PROFILES },\n 'cloudflared',\n );\n evict.stop(\n rm.ok\n ? pc.green('✓ cloudflared not present (or removed).')\n : pc.yellow(`⚠ cloudflared eviction reported: ${rm.reason ?? 'unknown'} — continuing.`),\n );\n }\n\n await verifyImageSignaturesPhase(composeOpts, opts);\n\n const pullSpin = p.spinner();\n pullSpin.start('Pulling images from ghcr.io… (~5–15 min first run, < 1 min cached)');\n const pull = await composePull(composeOpts);\n if (!pull.ok) {\n pullSpin.stop(pc.red('✗ compose pull failed.'));\n p.cancel(pull.reason ?? 'compose pull failed.');\n process.exit(1);\n }\n pullSpin.stop(pc.green('✓ Images pulled.'));\n\n const upSpin = p.spinner();\n upSpin.start('Starting the stack…');\n const up = await composeUp(composeOpts);\n if (!up.ok) {\n upSpin.stop(pc.red('✗ compose up failed.'));\n p.cancel(up.reason ?? 'compose up failed.');\n process.exit(1);\n }\n upSpin.stop(pc.green('✓ Containers started — waiting for healthy…'));\n\n // ---- Phase 10: health-check loop ----\n const healthSpin = p.spinner();\n healthSpin.start('Polling for healthy containers… (every 5s, up to 5 min)');\n const outcome = await waitForHealthy(composeOpts, {\n onPoll: (snaps) => {\n const healthy = snaps.filter((s) => s.health === 'healthy').length;\n const running = snaps.filter((s) => s.state === 'running').length;\n healthSpin.message(`${healthy}/${running} healthy`);\n },\n });\n healthSpin.stop(healthOutcomeHeadline(outcome));\n finishHealthOutcome(outcome, { region, opts, composeFiles });\n}\n\n// Spinner headline for the terminal state of the health loop.\nfunction healthOutcomeHeadline(\n outcome: Awaited<ReturnType<typeof waitForHealthy>>,\n): string {\n switch (outcome.kind) {\n case 'healthy':\n return pc.green(`✓ All ${outcome.snapshots.length} containers healthy.`);\n case 'unhealthy':\n return pc.red(`✗ ${outcome.problem}`);\n case 'timeout':\n return pc.yellow('⚠ Timed out waiting for all containers to report healthy.');\n default:\n return assertNever(outcome) as never;\n }\n}\n\n// Print the outro / diagnostics and exit for the terminal health state.\nfunction finishHealthOutcome(\n outcome: Awaited<ReturnType<typeof waitForHealthy>>,\n args: { region: string; opts: BootstrapOptions; composeFiles: string[] },\n): void {\n const { region, opts, composeFiles } = args;\n switch (outcome.kind) {\n case 'healthy':\n if (opts.localOnly) {\n p.outro(\n pc.cyan(\n [\n `Region ${region} is up locally (no public Cloudflare Tunnel — cloudflared stays down).`,\n `Access from your laptop over Tailscale at this Studio's tailnet IP.`,\n `When you're ready to expose publicly, re-run \\`bootstrap\\` without --local-only.`,\n ].join('\\n'),\n ),\n );\n } else {\n p.outro(\n pc.cyan(\n `Region ${region} is up. Next: verify off-LAN with \\`npx create-op-node verify --domain <your-domain>\\`.`,\n ),\n );\n }\n return;\n case 'unhealthy':\n // Surface the full snapshot table for diagnosis — N10 review fix.\n p.note(\n outcome.snapshots\n .map((s) => ` ${kvHealth(s.health)} ${s.name} (${s.state})`)\n .join('\\n'),\n 'Container state',\n );\n p.cancel(\n `Inspect with \\`docker compose -f ${composeFiles.join(' -f ')} logs\\`. Fix and re-run.`,\n );\n process.exit(1);\n // eslint-disable-next-line no-fallthrough\n case 'timeout':\n p.note(\n outcome.snapshots\n .map((s) => ` ${kvHealth(s.health)} ${s.name} (${s.state})`)\n .join('\\n'),\n 'Container state at timeout',\n );\n // B1 review fix: don't print the success outro. The stack hasn't\n // settled and `verify` would mislead — instruct the operator to\n // re-poll and exit non-zero.\n p.cancel(\n `Re-run \\`create-op-node bootstrap --skip-brew --skip-launch-agent --skip-ollama\\` to skip the already-done phases and poll again once containers settle.`,\n );\n process.exit(1);\n // eslint-disable-next-line no-fallthrough\n default:\n // Exhaustiveness check — adding a new HealthOutcome variant without\n // updating this switch fails the type check.\n assertNever(outcome);\n return;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n/**\n * Resolve the compose-file paths the wizard will pass to docker. Absolute\n * paths pass through; relative paths are resolved against `repoPath`. Pure\n * helper for unit testing — keeps the path-resolution rule in one place.\n */\nexport function resolveComposeFiles(\n repoPath: string,\n composeFile: string[] | undefined,\n): string[] {\n const inputs = composeFile ?? ['docker-compose-prod.yml'];\n return inputs.map((f) => (f.startsWith('/') ? f : join(repoPath, f)));\n}\n\n/**\n * Commander `argParser` for the repeatable `--compose-file` option (shared by\n * `bootstrap` and `reset`).\n *\n * Without a reducer, commander stores a value-taking option as the LAST string\n * passed — NOT an array. So `--compose-file a --compose-file b` yields the bare\n * string `\"b\"`, and even a single `--compose-file a` yields `\"a\"`. Both then\n * hit `resolveComposeFiles`'s `.map`, which throws\n * `inputs.map is not a function`. (#82)\n *\n * This accumulates each occurrence into an array. `previous` is `undefined` on\n * the first invocation (the option carries no default), so it's seeded with an\n * empty array; downstream code keeps its `?? default` fallback for the\n * flag-absent case.\n */\nexport function collectComposeFile(value: string, previous: string[] | undefined): string[] {\n return [...(previous ?? []), value];\n}\n\n/**\n * Resolve the Ollama model identifiers from operator flags + defaults.\n * Pure helper — mirrors `resolveComposeFiles` so the flag-resolution rule\n * lives in one place and stays unit-testable.\n *\n * Returned in the order Ollama pulls + warms them: `[embedding, llm]`.\n * The embedding model is typically tiny (~500 MB), so emitting it first\n * gives the operator a visible \"✓ pulled\" milestone before the LLM's\n * potentially-tens-of-gigabytes download dominates the spinner. (S3)\n */\nexport function resolveModels(opts: {\n llmModel?: string;\n embeddingModel?: string;\n}): readonly [embedding: string, llm: string] {\n return [\n opts.embeddingModel ?? DEFAULT_EMBEDDING_MODEL,\n opts.llmModel ?? DEFAULT_LLM_MODEL,\n ] as const;\n}\n\n/** Curated LLM choices shown in the interactive picker. Qwen-only because\n * the Opus Populi platform serves Spanish-speaking civic users and Qwen\n * has the strongest Spanish (and broader multilingual) capability of the\n * open-weight models in this tier. Other Ollama models are still\n * reachable via the \"Other…\" sentinel. Sized per\n * docs/docker-resources.md in the opuspopuli-node template.\n * Order = display order. */\nexport const LLM_MODEL_CHOICES = [\n {\n value: 'qwen3.6:35b-a3b',\n label: 'qwen3.6:35b-a3b',\n hint: '35B MoE, ~3B active — fast on Apple Silicon. ~24 GB footprint. Pre-selected on 64 GB+ nodes. Best Spanish + multilingual quality. Pull ~24 GB, 30–60 min.',\n },\n {\n value: 'qwen3:14b',\n label: 'qwen3:14b',\n hint: '14B, ~9 GB footprint. Pre-selected on 32–64 GB nodes. Solid Spanish, faster than the 35B MoE. Pull ~9 GB, 10–20 min.',\n },\n {\n value: 'qwen2.5:7b',\n label: 'qwen2.5:7b',\n hint: '7B, ~5 GB footprint. Pre-selected on 16–32 GB nodes; also the -y / scripted default. Pull ~5 GB, 3–5 min.',\n },\n {\n value: 'qwen2.5:3b',\n label: 'qwen2.5:3b',\n hint: '3B, ~2–3 GB footprint. Pre-selected on ≤ 16 GB nodes (Mac Mini). Lightest option. Pull ~2 GB, 2–3 min.',\n },\n] as const;\n\nconst OTHER_SENTINEL = '__OTHER__';\n\n/**\n * Pick the LLM that fits the operator's unified-memory budget. Ollama uses\n * roughly the model's parameter count in GB (in q4 quantization), plus a\n * context-window buffer. The Studio also needs RAM for macOS + Docker +\n * the data services. Thresholds below leave 30–40 GB headroom for that.\n *\n * Returns null when `ramGB` is null (sysctl unavailable) so the caller\n * falls back to the platform-default recommendation. (Pure helper —\n * exported for unit tests.)\n */\nexport function recommendLlmModel(ramGB: number | null): string | null {\n if (ramGB === null) return null;\n // Tier on TOTAL model footprint, not param count: the LLM shares unified\n // memory with ~22 Docker containers + Postgres, so each tier leaves headroom\n // for the rest of the stack. Boundaries match the #98 sizing table.\n if (ramGB >= 64) return 'qwen3.6:35b-a3b';\n if (ramGB >= 32) return 'qwen3:14b';\n if (ramGB >= 16) return 'qwen2.5:7b';\n return 'qwen2.5:3b';\n}\n\n/**\n * Prompt the operator to pick an LLM model. Skipped when `--yes` is set\n * (returns the conservative default) or when `--llm-model` was passed\n * (caller short-circuits before this is reached).\n *\n * Pre-selects based on the node's detected unified memory — 64 GB+ gets the\n * qwen3.6:35b-a3b MoE, 32–64 GB gets qwen3:14b, 16–32 GB gets qwen2.5:7b,\n * ≤ 16 GB gets qwen2.5:3b. When detection fails (non-macOS, sysctl missing),\n * defaults to DEFAULT_LLM_MODEL (the conservative scripted default).\n *\n * \"Other...\" branches to a text input validated against the same\n * MODEL_NAME_RE the LaunchAgent uses for setenv injection safety.\n */\nasync function selectLlmModel(opts: { yes?: boolean }): Promise<string> {\n if (opts.yes) return DEFAULT_LLM_MODEL;\n\n const ramGB = await detectUnifiedMemoryGB();\n const recommended = recommendLlmModel(ramGB) ?? DEFAULT_LLM_MODEL;\n const ramNote = ramGB !== null\n ? `Detected ${ramGB} GB unified memory — pre-selecting ${recommended}.`\n : `Couldn't detect Studio memory — defaulting to ${recommended} (override if your config differs).`;\n\n p.note(ramNote, 'Hardware');\n\n const choice = unwrap(\n await p.select({\n message: 'Choose the LLM model to pull + run',\n initialValue: recommended,\n options: [\n ...LLM_MODEL_CHOICES.map((c) => ({ value: c.value, label: c.label, hint: c.hint })),\n {\n value: OTHER_SENTINEL,\n label: 'Other…',\n hint: 'Specify any Ollama model name (e.g. mistral-small:24b)',\n },\n ],\n }),\n );\n\n if (choice !== OTHER_SENTINEL) return choice;\n\n return unwrap(\n await p.text({\n message: 'Ollama model name',\n placeholder: 'e.g. mistral-small:24b',\n validate: (v) =>\n /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/.test(v ?? '')\n ? undefined\n : 'Letters, digits, `.`, `:`, `_`, `-`, `/` only; must start with alphanumeric',\n }),\n );\n}\n\n/** Rough wall-clock estimate for pulling an Ollama model, based on the\n * size suffix in the tag. Used to populate the Ollama-pull spinner so\n * the operator knows whether to wait or step away. Estimates assume a\n * ~100 Mbps connection; faster networks finish proportionally sooner.\n *\n * Sparse-MoE shapes (`8x22b`) are matched before the plain `Nb` parse\n * because their size suffix in the tag refers to per-expert size, not\n * the total model footprint. */\nexport function estimatedPullTime(model: string): string {\n // Bounded digit runs (real Ollama tags never exceed 3-digit expert counts\n // / 4-digit sizes) so the search can't backtrack super-linearly on a long\n // input.\n if (/\\d{1,3}x\\d{1,3}b/i.test(model)) return '~60+ min for frontier MoE';\n const match = /(\\d{1,4})b\\b/i.exec(model);\n if (!match) return 'time depends on model size';\n const size = Number.parseInt(match[1]!, 10);\n if (size <= 13) return '~3–5 min for ≤ 13B-class';\n if (size <= 35) return '~15–30 min for ~32B-class';\n if (size <= 80) return '~30–60 min for 70B-class';\n return '~60+ min for frontier-class';\n}\n\nfunction kvBool(b: boolean): string {\n return b ? pc.green('on') : pc.yellow('off');\n}\n\nfunction kvFileVault(v: boolean | 'unknown'): string {\n if (v === 'unknown') return pc.dim('unknown');\n return v ? pc.green('on') : pc.dim('off');\n}\n\nfunction kvHealth(h: 'healthy' | 'unhealthy' | 'starting' | 'none'): string {\n switch (h) {\n case 'healthy':\n return pc.green('✓');\n case 'unhealthy':\n return pc.red('✗');\n case 'starting':\n return pc.yellow('…');\n case 'none':\n return pc.dim('-');\n }\n}\n\nfunction repoPathFromLocate(out: LocateOutcome): string | null {\n if (out.kind === 'found' || out.kind === 'cloned') return out.path;\n return null;\n}\n\nfunction handleLocateError(out: LocateOutcome, owner: string, name: string): void {\n switch (out.kind) {\n case 'explicit-not-a-node-repo':\n p.cancel(\n `${out.path} doesn't look like a node repo (missing one of docker-compose-prod.yml / supabase/init/pgsodium_getkey_env.sh). Point --repo-dir at the right place.`,\n );\n return;\n case 'gh-not-installed':\n p.cancel('`gh` not installed — install via `brew install gh` and re-run.');\n return;\n case 'clone-failed':\n p.cancel(\n `Couldn't clone ${owner}/${name}: ${out.reason}. Check repo exists + you have access.`,\n );\n return;\n case 'clone-disallowed':\n p.cancel(\n 'No checked-out node repo found and --no-clone (or similar) was set. Provide --repo-dir.',\n );\n return;\n case 'found':\n case 'cloned':\n // Success cases — handleLocateError shouldn't be called for them, but\n // listing here makes the switch exhaustive so the `never` check below\n // catches any new variant added to LocateOutcome.\n return;\n default: {\n // Compile-time exhaustiveness — if LocateOutcome gains a new variant\n // and isn't handled above, TypeScript fails this assignment.\n assertNever(out);\n return;\n }\n }\n}\n\n/**\n * Verify `gh` is signed in. If not, surface the one-line command to fix and\n * wait for the operator. Doesn't auto-run `gh auth login` since it opens a\n * browser flow and we don't want to fight it. Surfaces `gh auth status`'s\n * stderr so a wrong-account / missing-scope situation isn't silent.\n */\nasync function ensureGhAuth(): Promise<void> {\n const status = await safeExeca('gh', ['auth', 'status']);\n if (status === null) {\n p.cancel('`gh` not on PATH. Install via `brew install gh` and re-run.');\n process.exit(1);\n }\n if (status.exitCode === 0) return;\n\n const detail = (status.stderr || status.stdout).trim();\n p.note(\n [\n '`gh` is not signed in (or signed in to a different account / missing scope).',\n detail ? '' : undefined,\n detail ? pc.dim(detail) : undefined,\n '',\n 'In another shell:',\n '',\n pc.cyan('gh auth login --web'),\n '',\n pc.dim('Then come back and press Enter.'),\n ]\n .filter((l): l is string => typeof l === 'string')\n .join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'gh signed in?', initialValue: true }));\n}\n\n/**\n * Tailscale needs an interactive browser signin. We surface the command +\n * wait for confirmation rather than spawning it ourselves — operators run\n * different node setups (start at login vs. on-demand) and we don't want\n * to second-guess. Tailscale is optional; the rest of the bootstrap\n * continues without it (out-of-band SSH is just less convenient).\n */\nasync function promptTailscaleSignin(): Promise<void> {\n const status = await safeExeca('tailscale', ['status']);\n if (status !== null && status.exitCode === 0) return;\n\n p.note(\n [\n 'Tailscale needs to be signed in (or you can skip — Tailscale is',\n 'optional; it provides out-of-band SSH from your laptop. The rest',\n 'of the bootstrap continues without it).',\n '',\n 'In another shell:',\n '',\n pc.cyan('tailscale up'),\n '',\n pc.dim('Accept the device on your tailnet, then come back and press Enter.'),\n ].join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'Tailscale signed in (or skipped)?', initialValue: true }));\n}\n\ninterface LoadSecretInput {\n region: string;\n account: SecretAccount;\n /** Friendly name for prompts and notes. */\n label: string;\n /** Placeholder hint shown in the paste prompt. Ignored when `generate` is set. */\n placeholder?: string;\n /** Format check applied to both Keychain reads (so a stale-bad value is\n * treated as missing) and operator paste input. */\n validate: (v: string) => string | undefined;\n /** When set, on Keychain miss / validate-fail, generate a fresh value\n * instead of prompting. Used by `--local-only` for the pgsodium key —\n * no `init` needed.\n *\n * CRITICAL: when `generate` is set we MUST be able to persist the\n * generated value to Keychain. Otherwise the next bootstrap re-run\n * generates a different fresh key and silently destroys any data\n * encrypted under the previous key. So save failure in the generate\n * path is a hard exit, not a warning. (review B1) */\n generate?: () => string;\n}\n\n/**\n * Materialize a secret. Three paths, in order:\n *\n * 1. Keychain hit + valid → return it.\n * 2. Else if `generate` is set → generate fresh, MUST persist (hard fail\n * if save fails), return. The Keychain item is the durable record;\n * losing it later means losing whatever it encrypted.\n * 3. Else → prompt operator to paste, validate, persist with a warning\n * on save failure (the operator can paste again next time).\n *\n * If `validate` rejects an existing Keychain item, we surface the swap\n * explicitly before regenerating/reprompting — destructive overwrites\n * shouldn't be invisible. (review S1)\n */\nasync function loadSecret(input: LoadSecretInput): Promise<string> {\n const coords = { region: input.region, account: input.account };\n const spin = p.spinner();\n spin.start(`Reading ${input.label} from Keychain…`);\n const existing = await readSecret(coords);\n if (existing && input.validate(existing) === undefined) {\n spin.stop(pc.green(`✓ ${input.label} read from Keychain.`));\n return existing;\n }\n\n // Differentiate \"missing\" from \"present-but-bad-format\" — the latter is a\n // destructive replacement so we say so out loud.\n spin.stop(\n existing\n ? pc.yellow(`⚠ ${input.label} in Keychain failed format validation — will replace.`)\n : pc.dim(`· ${input.label} not in Keychain.`),\n );\n\n if (input.generate) {\n const fresh = input.generate();\n const save = await saveSecret(coords, fresh);\n if (!save.written) {\n // Hard fail (review B1) — we generated a fresh value but couldn't\n // persist it. If we continued, the next bootstrap re-run would\n // generate a DIFFERENT fresh value and destroy whatever this one\n // encrypted. Better to bail loudly and let the operator fix the\n // underlying Keychain issue.\n p.cancel(\n `Generated a fresh ${input.label} but couldn't persist it to Keychain: ${save.reason ?? 'unknown'}. ` +\n `Continuing would risk silent key rotation on the next re-run. ` +\n `Resolve the Keychain access (re-grant via Keychain Access.app or check the security CLI) and re-run.`,\n );\n process.exit(1);\n }\n p.note(`${pc.green('✓')} Generated fresh ${input.label} and stored in Keychain.`, 'Keychain');\n return fresh;\n }\n\n const pasted = unwrap(\n await p.password({\n message: `Paste the ${input.label} for region ${input.region}:`,\n validate: (v) => input.validate(v ?? ''),\n }),\n );\n const save = await saveSecret(coords, pasted);\n if (!save.written) {\n // Paste path: warning is fine since the operator can paste again on the\n // next run. The value isn't lost — it's still wherever they pasted from.\n p.note(\n `${pc.yellow('⚠')} Couldn't persist to Keychain: ${save.reason ?? 'unknown'}. You'll need to paste it again next run.`,\n 'Keychain',\n );\n } else {\n p.note(`${pc.green('✓')} Stored ${input.label} in Keychain for re-runs.`, 'Keychain');\n }\n return pasted;\n}\n","/**\n * `create-op-node reset` — reverse of bootstrap. Stops the stack, unloads\n * the LaunchAgent, removes the pgsodium key file. By default the docker\n * volumes (and therefore the database) are PRESERVED. Pass `--wipe-data`\n * for the destructive variant; it requires retyping the region label as\n * confirmation.\n *\n * Reset does NOT touch cloud-side state (Cloudflare resources, the GitHub\n * repo, the TFC workspace). It also leaves the Keychain items in place —\n * delete those manually via Keychain Access or `security delete-generic-\n * password -s org.opuspopuli.<region> -a <account>` if you want a truly\n * clean slate.\n *\n * Accounts to wipe (under service `org.opuspopuli.<region>`):\n * pgsodium-root-key, tunnel-token, postgres-password, jwt-secret,\n * supabase-anon-key, supabase-service-role-key, dashboard-password,\n * gateway-hmac-secret, grafana-admin-password\n *\n * Wiping pgsodium-root-key permanently destroys every value in\n * supabase_vault for this region. Wiping postgres-password locks you out\n * of the existing database. Don't do either without a backup.\n */\n\nimport { access, readFile } from 'node:fs/promises';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { composeDown, composePs, dockerLogout, GHCR_REGISTRY } from '../lib/docker.js';\nimport { defaultPaths as defaultLaunchAgentPaths, teardownLaunchAgent } from '../lib/launchagent.js';\nimport { locateOrCloneRepo, NODE_REPO_MARKERS } from '../lib/noderepo.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { assertNever } from '../lib/assert.js';\nimport type { ContainerSnapshot } from '../lib/docker.js';\nimport type { LaunchAgentPaths, TeardownResult } from '../lib/launchagent.js';\n\nimport { collectComposeFile, resolveComposeFiles } from './bootstrap.js';\n\ninterface ResetOptions {\n region?: string;\n owner?: string;\n repoDir?: string;\n composeFile?: string[];\n envFile?: string;\n wipeData?: boolean;\n wipeImages?: boolean;\n removeOrphans?: boolean;\n skipStack?: boolean;\n skipLaunchAgent?: boolean;\n keepKeyFile?: boolean;\n skipDockerLogout?: boolean;\n registry?: string;\n dryRun?: boolean;\n yes?: boolean;\n}\n\nconst REGION_RE = /^[a-z0-9-]{2,32}$/;\n\n/* ------------------------------------------------------------------ *\n * Phase-name constants (review S4 / N7) *\n * *\n * Exported so the CLI wrapper, runReset, and tests all share one *\n * source of truth — renames flow through automatically instead of *\n * drifting between the CLI's spinner setup and the orchestration's *\n * emitted phase names. *\n * ------------------------------------------------------------------ */\n\nexport const RESET_PHASES = {\n STOP_STACK: 'Stop stack',\n LAUNCH_AGENT: 'LaunchAgent',\n DOCKER_LOGOUT: 'docker logout',\n} as const;\n\ntype ResetPhaseName = (typeof RESET_PHASES)[keyof typeof RESET_PHASES];\n\n/* ------------------------------------------------------------------ *\n * Orchestration *\n * ------------------------------------------------------------------ */\n\nexport interface ResetPhase {\n readonly name: string;\n /** `dry-run` is reset-specific — verify uses `skipped` for both\n * \"configured-off\" and \"would-do-but-not-running\" because verify\n * has no preview mode. Reset's preview mode wants a distinct icon. */\n readonly status: 'ok' | 'warn' | 'fail' | 'skipped' | 'dry-run';\n readonly detail: string;\n}\n\nexport interface ResetReport {\n readonly phases: ReadonlyArray<ResetPhase>;\n}\n\nexport interface ResetDeps {\n composeDown: typeof composeDown;\n teardownLaunchAgent: typeof teardownLaunchAgent;\n dockerLogout: typeof dockerLogout;\n /** Notification fan-out — lets the CLI render spinners. */\n onPhase?: (phase: ResetPhase) => void;\n}\n\nexport interface ResetInput {\n /** Set when we have a repo path + compose files. When missing the stack\n * phase is reported as skipped. */\n stack?: {\n repoPath: string;\n composeFiles: string[];\n envFile?: string;\n wipeVolumes: boolean;\n /** When true, also remove all images referenced by the compose files\n * (passes `--rmi all` to compose down). Forces a fresh pull on the\n * next bootstrap — used for \"wipe everything and start over\" loops. */\n wipeImages: boolean;\n removeOrphans: boolean;\n /** Placeholder env overlay so `docker compose down` can interpolate the\n * template's `${VAR:?…}`-required variables. `down` never uses the\n * values, so placeholders suffice — and reset then works even when the\n * Keychain secrets are already gone. (#85) */\n env?: NodeJS.ProcessEnv;\n };\n launchAgent?: {\n paths: LaunchAgentPaths;\n keepKeyFile: boolean;\n };\n /** Set when the docker-logout phase should run. The registry value is\n * the argument passed to `docker logout <registry>`. */\n dockerLogout?: { registry: string };\n dryRun: boolean;\n}\n\nconst DEFAULT_DEPS: ResetDeps = {\n composeDown,\n teardownLaunchAgent,\n dockerLogout,\n};\n\n/**\n * Run the three reset phases in reverse-bootstrap order.\n *\n * **Continue-on-failure policy**: each phase runs independently — a\n * `composeDown` failure does NOT short-circuit the LaunchAgent or\n * docker-logout phases. This is intentional: reset is best-effort\n * cleanup, and the operator usually wants the LaunchAgent gone even if\n * the docker daemon is down. Use the returned `ResetReport` to inspect\n * which phases failed.\n *\n * Each phase calls `deps.onPhase` exactly once before runReset moves\n * on, so a CLI consumer can render spinners in lockstep.\n */\nexport async function runReset(input: ResetInput, deps: ResetDeps = DEFAULT_DEPS): Promise<ResetReport> {\n // Each phase computes its ResetPhase; push() records it and fires onPhase\n // in lockstep (same order + timing as the original inline loop) so CLI\n // consumers can render spinners one at a time.\n const phases: ResetPhase[] = [];\n const push = (ph: ResetPhase): void => {\n phases.push(ph);\n deps.onPhase?.(ph);\n };\n\n push(await resetStopStackPhase(input, deps));\n push(await resetLaunchAgentPhase(input, deps));\n push(await resetDockerLogoutPhase(input, deps));\n\n return { phases };\n}\n\n// ---- Phase 1: stop the stack ---------------------------------------\nasync function resetStopStackPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.stack) {\n return {\n name: RESET_PHASES.STOP_STACK,\n status: 'skipped',\n detail: '--skip-stack or no repo path resolved',\n };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.STOP_STACK,\n status: 'dry-run',\n detail: `would run: docker compose -f ${input.stack.composeFiles.join(' -f ')} down${input.stack.wipeVolumes ? ' -v' : ''}${input.stack.removeOrphans ? ' --remove-orphans' : ''}${input.stack.wipeImages ? ' --rmi all' : ''}`,\n };\n }\n const result = await deps.composeDown({\n files: input.stack.composeFiles,\n cwd: input.stack.repoPath,\n ...(input.stack.envFile ? { envFile: input.stack.envFile } : {}),\n // Hydrate placeholder values for the template's `${VAR:?…}` required vars\n // so interpolation succeeds; `down` doesn't use the values. (#85)\n ...(input.stack.env ? { env: input.stack.env } : {}),\n wipeVolumes: input.stack.wipeVolumes,\n removeOrphans: input.stack.removeOrphans,\n ...(input.stack.wipeImages ? { removeImages: 'all' as const } : {}),\n });\n if (!result.ok) {\n return { name: RESET_PHASES.STOP_STACK, status: 'fail', detail: result.reason ?? 'unknown failure' };\n }\n const bits = [\n input.stack.wipeVolumes ? 'volumes destroyed' : 'containers stopped, volumes preserved',\n input.stack.wipeImages ? 'images removed (next bootstrap will re-pull)' : null,\n ].filter(Boolean);\n return { name: RESET_PHASES.STOP_STACK, status: 'ok', detail: bits.join('; ') };\n}\n\n// ---- Phase 2: LaunchAgent ------------------------------------------\nasync function resetLaunchAgentPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.launchAgent) {\n return { name: RESET_PHASES.LAUNCH_AGENT, status: 'skipped', detail: '--skip-launch-agent or no plist found' };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.LAUNCH_AGENT,\n status: 'dry-run',\n detail: `would unload ${input.launchAgent.paths.plistFile}, rm plist${\n input.launchAgent.keepKeyFile ? '' : ' + key file'\n }`,\n };\n }\n const result: TeardownResult = await deps.teardownLaunchAgent(\n input.launchAgent.paths,\n { keepKeyFile: input.launchAgent.keepKeyFile },\n );\n if (!result.ok) {\n const fail = result.steps.find((s) => !s.ok);\n return {\n name: RESET_PHASES.LAUNCH_AGENT,\n status: 'fail',\n detail: `${fail?.step}: ${fail?.reason ?? 'unknown'}`,\n };\n }\n const removed = result.steps.filter((s) => s.step !== 'unload').map((s) => s.step).join(', ');\n return { name: RESET_PHASES.LAUNCH_AGENT, status: 'ok', detail: `unloaded + ${removed}` };\n}\n\n// ---- Phase 3: docker logout ----------------------------------------\nasync function resetDockerLogoutPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.dockerLogout) {\n return { name: RESET_PHASES.DOCKER_LOGOUT, status: 'skipped', detail: '--skip-docker-logout' };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.DOCKER_LOGOUT,\n status: 'dry-run',\n detail: `would run: docker logout ${input.dockerLogout.registry}`,\n };\n }\n const result = await deps.dockerLogout(input.dockerLogout.registry);\n if (result.ok) {\n return {\n name: RESET_PHASES.DOCKER_LOGOUT,\n status: 'ok',\n detail: `credentials removed from ${input.dockerLogout.registry}`,\n };\n }\n // See dockerLogout() docstring — older Docker versions return non-zero\n // when not currently logged in. Render as warn so reset doesn't fail\n // overall when the operator wasn't logged in to begin with.\n return { name: RESET_PHASES.DOCKER_LOGOUT, status: 'warn', detail: result.reason ?? 'unknown' };\n}\n\n/* ------------------------------------------------------------------ *\n * CLI wrapper *\n * ------------------------------------------------------------------ */\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction phaseIcon(ph: ResetPhase): string {\n switch (ph.status) {\n case 'ok': return pc.green('✓');\n case 'warn': return pc.yellow('⚠');\n case 'skipped': return pc.dim('·');\n case 'dry-run': return pc.cyan('?');\n case 'fail': return pc.red('✗');\n }\n}\n\nexport const resetCommand = new Command('reset')\n .description(\n 'Reverse the Mac Studio side of bootstrap: stop containers, unload the LaunchAgent, ' +\n 'remove the pgsodium key file. Preserves docker volumes by default — pass --wipe-data ' +\n 'for a full data nuke (requires retyping the region label).',\n )\n .addOption(new Option('--region <slug>', 'Region label (used for --wipe-data confirmation + finding the repo)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the node repo').default('OpusPopuli'))\n .addOption(new Option('--repo-dir <path>', 'Explicit path to a checked-out node repo'))\n .addOption(\n new Option(\n '--compose-file <path>',\n 'Repeatable. Compose file relative to repo root. Default: docker-compose-prod.yml',\n ).argParser(collectComposeFile),\n )\n .addOption(new Option('--env-file <path>', 'Compose --env-file. Default: .env.production'))\n .addOption(\n new Option(\n '--wipe-data',\n 'DESTROYS docker volumes (adds -v to `compose down`). Requires retyping the region label as confirmation. Default off — volumes preserved.',\n ).default(false),\n )\n .addOption(\n new Option(\n '--wipe-images',\n 'ALSO remove all docker images referenced by the compose file (adds --rmi all). Forces a fresh pull on next bootstrap. Implies --wipe-data semantics for the iteration loop (\"wipe everything and start over\"). Default off.',\n ).default(false),\n )\n .addOption(\n new Option(\n '--no-remove-orphans',\n 'Do NOT pass --remove-orphans to compose down. Preserves containers from compose files no longer included.',\n ),\n )\n .addOption(new Option('--skip-stack', \"Don't touch docker compose\").default(false))\n .addOption(new Option('--skip-launch-agent', \"Don't touch the LaunchAgent\").default(false))\n .addOption(\n new Option(\n '--keep-key-file',\n \"Preserve the pgsodium key file (only matters when LaunchAgent teardown runs). Useful as belt-and-suspenders backup before a wipe-data run.\",\n ).default(false),\n )\n .addOption(new Option('--skip-docker-logout', \"Don't run `docker logout`\").default(false))\n .addOption(new Option('--registry <registry>', 'Registry to log out of').default(GHCR_REGISTRY))\n .addOption(new Option('--dry-run', 'Show what would happen without acting').default(false))\n .addOption(new Option('-y, --yes', 'Skip non-destructive confirmations (wipe still confirms)').default(false))\n .action(async (opts: ResetOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node reset ')));\n\n const wipeImages = opts.wipeImages ?? false;\n // --wipe-images implies --wipe-data — \"wipe everything\" semantics: no\n // point keeping data tied to images that are about to disappear.\n const wipeData = (opts.wipeData ?? false) || wipeImages;\n const removeOrphans = opts.removeOrphans ?? true; // commander --no-remove-orphans sets this to false\n\n const region = await resolveResetRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const repoName = `opuspopuli-node-${region}`;\n\n const launchAgentPaths = defaultLaunchAgentPaths();\n const plistExists = await fileExists(launchAgentPaths.plistFile);\n const keyFileExists = await fileExists(launchAgentPaths.keyFile);\n const { repoPath, stackSkipReason } = await locateResetRepo(opts, owner, repoName);\n\n const runningContainers = repoPath\n ? await composePs({\n files: resolveComposeFiles(repoPath, opts.composeFile),\n cwd: repoPath,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n })\n : null;\n\n renderSnapshotNote({\n region,\n repoPath,\n stackSkipReason,\n runningContainers,\n plistExists,\n keyFileExists,\n launchAgentPaths,\n opts,\n wipeData,\n wipeImages,\n });\n\n await confirmReset({ opts, region, wipeData });\n\n // Scan the compose files for `${VAR:?…}`-required vars so `compose down`\n // can interpolate — otherwise it aborts before removing anything. (#85)\n const teardownEnv = repoPath\n ? await computeTeardownEnv(resolveComposeFiles(repoPath, opts.composeFile))\n : undefined;\n\n const input = buildResetInput({\n opts,\n repoPath,\n plistExists,\n launchAgentPaths,\n wipeData,\n wipeImages,\n removeOrphans,\n ...(teardownEnv ? { teardownEnv } : {}),\n });\n await runResetWithSpinners({ opts, region, wipeData, input });\n });\n\n// ----------------------------------------------------------------------------\n// Reset command phases\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: interactive prompts,\n// spinners, and process.exit calls are relocated verbatim.\n\n// ---- Region (needed for confirmation phrase + repo discovery) ----\nasync function resolveResetRegion(opts: ResetOptions): Promise<string> {\n const region = opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Region label (the slug used during init — e.g. us-ca)?',\n placeholder: 'us-ca',\n validate: (v) =>\n REGION_RE.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n if (!REGION_RE.test(region)) {\n p.cancel(`--region ${JSON.stringify(region)} is not a valid region slug.`);\n process.exit(2);\n }\n return region;\n}\n\n// ---- Locate the node repo (or explain why the stack phase is skipped) ----\n// Exhaustive: every LocateOutcome variant has a deliberate path —\n// operator-supplied --repo-dir mismatch is HARD-fail, ambient cwd miss is\n// SOFT-skip with a visible reason. (review B1)\nasync function locateResetRepo(\n opts: ResetOptions,\n owner: string,\n repoName: string,\n): Promise<{ repoPath?: string; stackSkipReason?: string }> {\n if (opts.skipStack) {\n return { stackSkipReason: '--skip-stack' };\n }\n const located = await locateOrCloneRepo({\n owner,\n name: repoName,\n cwd: process.cwd(),\n allowClone: false,\n ...(opts.repoDir ? { explicit: opts.repoDir } : {}),\n });\n switch (located.kind) {\n case 'found':\n return { repoPath: located.path };\n case 'explicit-not-a-node-repo':\n p.cancel(\n `--repo-dir ${JSON.stringify(located.path)} doesn't look like a node repo ` +\n `(missing one of: ${NODE_REPO_MARKERS.join(', ')}). ` +\n `Verify the path or drop --repo-dir to let reset search the cwd.`,\n );\n return process.exit(2);\n case 'clone-disallowed':\n return { stackSkipReason: `no checkout found at ${process.cwd()}; pass --repo-dir to target one` };\n case 'cloned':\n case 'gh-not-installed':\n case 'clone-failed':\n // Should not be reachable — allowClone: false above. Treat as\n // soft-skip if it ever happens.\n return {\n stackSkipReason: `unexpected outcome ${located.kind} from locateOrCloneRepo with allowClone=false`,\n };\n default:\n return assertNever(located) as never;\n }\n}\n\n// ---- Snapshot note: what's currently present ----\nfunction renderSnapshotNote(args: {\n region: string;\n repoPath: string | undefined;\n stackSkipReason: string | undefined;\n runningContainers: ContainerSnapshot[] | null;\n plistExists: boolean;\n keyFileExists: boolean;\n launchAgentPaths: LaunchAgentPaths;\n opts: ResetOptions;\n wipeData: boolean;\n wipeImages: boolean;\n}): void {\n const {\n region,\n repoPath,\n stackSkipReason,\n runningContainers,\n plistExists,\n keyFileExists,\n launchAgentPaths,\n opts,\n wipeData,\n wipeImages,\n } = args;\n\n let runningContainersLabel: string;\n if (runningContainers === null) {\n runningContainersLabel = pc.dim('unknown');\n } else if (runningContainers.length === 0) {\n runningContainersLabel = pc.dim('none');\n } else {\n runningContainersLabel = pc.cyan(`${runningContainers.length} listed by compose ps`);\n }\n\n p.note(\n [\n `Region: ${pc.cyan(region)}`,\n `Repo path: ${\n repoPath\n ? pc.cyan(repoPath)\n : pc.dim(`not used (${stackSkipReason ?? 'no repo path resolved'})`)\n }`,\n `Running containers: ${runningContainersLabel}`,\n `LaunchAgent plist: ${plistExists ? pc.cyan(launchAgentPaths.plistFile) : pc.dim('not present')}`,\n `pgsodium key file: ${keyFileExists ? pc.cyan(launchAgentPaths.keyFile) : pc.dim('not present')}`,\n `Registry to log out: ${pc.cyan(opts.registry ?? GHCR_REGISTRY)}`,\n `Volume policy: ${wipeData ? pc.red('WIPE') : pc.green('preserve (default)')}`,\n `Image policy: ${wipeImages ? pc.red('WIPE (re-pull on next bootstrap)') : pc.green('keep (default)')}`,\n `Dry run: ${opts.dryRun ? pc.yellow('yes') : pc.dim('no')}`,\n ].join('\\n'),\n 'Snapshot',\n );\n}\n\n// ---- Confirmation gates ----\n// wipe-data requires retyping the region label (modeled on `terraform\n// destroy` — the friction is the point, review B2); otherwise a plain\n// proceed confirm unless --yes / --dry-run.\nasync function confirmReset(args: {\n opts: ResetOptions;\n region: string;\n wipeData: boolean;\n}): Promise<void> {\n const { opts, region, wipeData } = args;\n if (wipeData && !opts.dryRun) {\n unwrap(\n await p.text({\n message: pc.red(`Type the region label to confirm WIPING all volumes (the slug you'd use with --region):`),\n validate: (v) => (v === region ? undefined : `must match the region label exactly`),\n }),\n );\n return;\n }\n if (!opts.dryRun && !opts.yes) {\n const cont = unwrap(\n await p.confirm({\n message: 'Proceed with reset? (volumes will be preserved)',\n initialValue: true,\n }),\n );\n if (!cont) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n }\n}\n\n// ---- Teardown env hydration (#85) ----\n//\n// `docker compose down` interpolates the WHOLE compose file, so the template's\n// `${POSTGRES_PASSWORD:?…}` / `${JWT_SECRET:?…}` required variables must be\n// defined or `down` aborts before removing anything — even though teardown\n// never USES the values. Rather than hydrate real secrets from Keychain (which\n// reset shouldn't depend on — you may be tearing down precisely because the\n// secrets are gone), we scan the compose files for their `:?`-required variable\n// names and fill each with a benign placeholder. Reading the required set from\n// the compose text keeps it in sync with the template instead of drifting\n// against a hardcoded list.\n\n/** A value only needs to be non-empty to satisfy `${VAR:?…}` interpolation;\n * `down` doesn't parse it. */\nconst TEARDOWN_PLACEHOLDER = 'reset-teardown-placeholder';\n\n/** Captures NAME in `${NAME:?…}` and `${NAME?…}` — the interpolation forms that\n * FAIL when the variable is unset. Deliberately does NOT match\n * `${NAME:-default}` (uses its default) or bare `${NAME}` (resolves to empty,\n * no error), which don't need filling. */\nconst REQUIRED_VAR_RE = /\\$\\{([A-Za-z_]\\w*):?\\?/g;\n\n/**\n * Build a minimal env overlay defining every `${VAR:?…}`-required variable\n * referenced by the given compose file contents, using a placeholder for any\n * not already present (non-empty) in `baseEnv`. Pure — unit-tested. (#85)\n */\nexport function buildTeardownEnv(\n composeFileContents: string[],\n baseEnv: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const overlay: NodeJS.ProcessEnv = {};\n for (const text of composeFileContents) {\n for (const match of text.matchAll(REQUIRED_VAR_RE)) {\n const name = match[1]!;\n const existing = baseEnv[name];\n if (existing === undefined || existing === '') {\n overlay[name] = TEARDOWN_PLACEHOLDER;\n }\n }\n }\n return overlay;\n}\n\n/**\n * Read the resolved compose files and compute the teardown env overlay.\n * Unreadable files are skipped (a genuinely-missing compose file surfaces\n * later when `down` runs); an empty overlay results when nothing is readable.\n */\nasync function computeTeardownEnv(composeFiles: string[]): Promise<NodeJS.ProcessEnv> {\n const contents: string[] = [];\n for (const file of composeFiles) {\n try {\n contents.push(await readFile(file, 'utf8'));\n } catch {\n // Skip — `down` will report a genuinely-missing compose file itself.\n }\n }\n return buildTeardownEnv(contents);\n}\n\n// ---- Build the runReset input from the resolved snapshot + flags ----\nexport function buildResetInput(args: {\n opts: ResetOptions;\n repoPath: string | undefined;\n plistExists: boolean;\n launchAgentPaths: LaunchAgentPaths;\n wipeData: boolean;\n wipeImages: boolean;\n removeOrphans: boolean;\n teardownEnv?: NodeJS.ProcessEnv;\n}): ResetInput {\n const { opts, repoPath, plistExists, launchAgentPaths, wipeData, wipeImages, removeOrphans, teardownEnv } = args;\n const stack = repoPath\n ? {\n repoPath,\n composeFiles: resolveComposeFiles(repoPath, opts.composeFile),\n wipeVolumes: wipeData,\n wipeImages,\n removeOrphans,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n ...(teardownEnv ? { env: teardownEnv } : {}),\n }\n : undefined;\n const launchAgent =\n plistExists && !opts.skipLaunchAgent\n ? {\n paths: launchAgentPaths,\n keepKeyFile: opts.keepKeyFile ?? false,\n }\n : undefined;\n const dockerLogoutInput = !opts.skipDockerLogout\n ? { registry: opts.registry ?? GHCR_REGISTRY }\n : undefined;\n return {\n ...(stack ? { stack } : {}),\n ...(launchAgent ? { launchAgent } : {}),\n ...(dockerLogoutInput ? { dockerLogout: dockerLogoutInput } : {}),\n dryRun: opts.dryRun ?? false,\n };\n}\n\n// ---- Run runReset with a spinner per acting phase, then report ----\nasync function runResetWithSpinners(args: {\n opts: ResetOptions;\n region: string;\n wipeData: boolean;\n input: ResetInput;\n}): Promise<void> {\n const { opts, region, wipeData, input } = args;\n\n // Start a spinner per phase that will actually act (not skipped, not\n // dry-run). The phase name comes from RESET_PHASES so it can't drift from\n // runReset's emitted names. (review S4 / N7)\n const phaseSpins = new Map<ResetPhaseName, ReturnType<typeof p.spinner>>();\n const actingPhases: ResetPhaseName[] = [];\n if (input.stack && !input.dryRun) actingPhases.push(RESET_PHASES.STOP_STACK);\n if (input.launchAgent && !input.dryRun) actingPhases.push(RESET_PHASES.LAUNCH_AGENT);\n if (input.dockerLogout && !input.dryRun) actingPhases.push(RESET_PHASES.DOCKER_LOGOUT);\n for (const name of actingPhases) {\n const s = p.spinner();\n s.start(`${name}…`);\n phaseSpins.set(name, s);\n }\n\n const renderPhase = (ph: ResetPhase): void => {\n const spin = phaseSpins.get(ph.name as ResetPhaseName);\n const line = `${phaseIcon(ph)} ${ph.name}: ${pc.dim(ph.detail)}`;\n if (spin) {\n spin.stop(line);\n phaseSpins.delete(ph.name as ResetPhaseName);\n } else {\n p.log.info(line);\n }\n };\n\n const report = await runReset(input, { ...DEFAULT_DEPS, onPhase: renderPhase });\n\n // Belt-and-suspenders: stop any orphan spinners runReset didn't fire\n // onPhase for. Shouldn't happen given the constants-based wiring above.\n for (const [, spin] of phaseSpins) spin.stop(pc.dim('— skipped'));\n\n reportResetOutcome({ report, opts, wipeData, region });\n}\n\n// ---- Final outro / exit code ----\nfunction reportResetOutcome(args: {\n report: ResetReport;\n opts: ResetOptions;\n wipeData: boolean;\n region: string;\n}): void {\n const { report, opts, wipeData, region } = args;\n const failed = report.phases.filter((ph) => ph.status === 'fail').length;\n if (failed > 0) {\n p.outro(pc.red(`${failed} step${failed === 1 ? '' : 's'} failed.`));\n process.exit(1);\n }\n if (opts.dryRun) {\n p.outro(pc.cyan('Dry run complete. Re-run without --dry-run to apply.'));\n return;\n }\n p.outro(\n pc.green(\n wipeData\n ? `Reset complete — volumes wiped. Re-run \\`create-op-node bootstrap --region ${region}\\` to start fresh.`\n : `Reset complete — volumes preserved. Re-run \\`create-op-node bootstrap --region ${region}\\` to bring the stack back up.`,\n ),\n );\n}\n","/**\n * HTTP probes for `verify`. Two helpers:\n *\n * - `httpProbe` — GET against a URL, return status + truncated body.\n * Used for the `/health` endpoint check.\n * - `graphqlProbe` — POST `{ query: \"{ __typename }\" }`, parse the\n * envelope, confirm it looks like a GraphQL response\n * rather than (say) an HTML error page from the proxy.\n *\n * Both swallow network errors into a `{ ok: false, reason }` so the verify\n * wizard reports them as a phase failure instead of crashing.\n */\n\nimport { BODY_PREVIEW_MAX, VERIFY_NETWORK_TIMEOUT_MS } from './constants.js';\n\n/** Spec-preferred GraphQL response media type. Apollo Gateway accepts plain\n * `application/json` too, but stricter or future implementations may not —\n * send both. (graphql-over-http spec) */\nconst GRAPHQL_ACCEPT = 'application/graphql-response+json, application/json';\n\n/** Slice cap when reading a response body for diagnostics. Streaming would\n * let us bail at this byte count too; for now we read the whole text and\n * cap on display, which is fine for the small bodies these endpoints\n * return. If a pathological server returns gigabytes, the AbortController\n * will fire first. */\nasync function readBodyCapped(res: Response): Promise<string> {\n const text = await res.text();\n return text.slice(0, BODY_PREVIEW_MAX);\n}\n\nexport interface HttpProbeOk {\n ok: true;\n status: number;\n /** First N chars of the response body — useful for surface-level diagnostics\n * (\"got HTML when expecting JSON\"). Capped at BODY_PREVIEW_MAX. */\n bodyPreview: string;\n}\n\nexport interface HttpProbeFailed {\n ok: false;\n reason: string;\n /** Set when we got a response back but the status was unexpected; the\n * wizard renders this in the failure block. */\n status?: number;\n}\n\nexport type HttpProbeResult = HttpProbeOk | HttpProbeFailed;\n\nexport interface HttpProbeInput {\n url: string;\n /** Default 200. Set to e.g. 204 if you're probing a no-content endpoint. */\n expectedStatus?: number;\n timeoutMs?: number;\n /** Injectable for tests. Defaults to globalThis.fetch. */\n fetchImpl?: typeof fetch;\n}\n\nexport async function httpProbe(input: HttpProbeInput): Promise<HttpProbeResult> {\n const expected = input.expectedStatus ?? 200;\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const fetchImpl = input.fetchImpl ?? fetch;\n\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), timeoutMs);\n try {\n const res = await fetchImpl(input.url, { method: 'GET', signal: ctrl.signal });\n const bodyPreview = await readBodyCapped(res);\n if (res.status !== expected) {\n // (review N5) Surface the body on a status mismatch the same way\n // graphqlProbe does, so the operator can see the actual error page.\n return {\n ok: false,\n status: res.status,\n reason: bodyPreview\n ? `expected HTTP ${expected}, got ${res.status}: ${bodyPreview}`\n : `expected HTTP ${expected}, got ${res.status}`,\n };\n }\n return { ok: true, status: res.status, bodyPreview };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `GET ${input.url} timed out after ${timeoutMs}ms`\n : `GET ${input.url} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport interface GraphqlProbeOk {\n ok: true;\n /** The value of `data.__typename` from the response envelope. Usually\n * \"Query\" on a healthy Apollo Gateway. */\n typename: string;\n}\n\nexport interface GraphqlProbeFailed {\n ok: false;\n reason: string;\n status?: number;\n}\n\nexport type GraphqlProbeResult = GraphqlProbeOk | GraphqlProbeFailed;\n\nexport interface GraphqlProbeInput {\n url: string;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\n/**\n * POST `{ \"query\": \"{ __typename }\" }` and confirm the envelope shape. Apollo\n * Federation gateways respond with `{ data: { __typename: \"Query\" } }` for\n * this; a misconfigured proxy or a 404 from a wrong path returns HTML or a\n * JSON error envelope that we surface as a failure reason.\n */\nexport async function graphqlProbe(input: GraphqlProbeInput): Promise<GraphqlProbeResult> {\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const fetchImpl = input.fetchImpl ?? fetch;\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), timeoutMs);\n try {\n const res = await fetchImpl(input.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: GRAPHQL_ACCEPT },\n body: JSON.stringify({ query: '{ __typename }' }),\n signal: ctrl.signal,\n });\n const text = await readBodyCapped(res);\n if (res.status !== 200) {\n return {\n ok: false,\n status: res.status,\n reason: `expected HTTP 200, got ${res.status}: ${text}`,\n };\n }\n let envelope: unknown;\n try {\n envelope = JSON.parse(text);\n } catch {\n return {\n ok: false,\n status: res.status,\n reason: `response was not JSON: ${text}`,\n };\n }\n const data = (envelope as { data?: { __typename?: unknown } }).data;\n const typename = data?.__typename;\n if (typeof typename !== 'string') {\n return {\n ok: false,\n status: res.status,\n reason: `response missing { data: { __typename: string } }: ${text}`,\n };\n }\n return { ok: true, typename };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `POST ${input.url} timed out after ${timeoutMs}ms`\n : `POST ${input.url} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n","/**\n * Off-LAN TLS handshake probe. Verify uses this to confirm `api.<domain>`\n * actually negotiates a real, in-date cert from anywhere on the internet\n * before bothering with HTTP probes.\n *\n * We use `tls.connect` rather than just letting fetch do its thing because\n * fetch swallows cert-chain details — we want to surface days-to-expiry so\n * the operator can see \"TLS green, but cert expires in 12 days\" as a soft\n * warning, not just \"fetch failed.\"\n */\n\nimport * as tls from 'node:tls';\n\nimport { VERIFY_NETWORK_TIMEOUT_MS } from './constants.js';\n\nexport interface TlsHandshakeOk {\n ok: true;\n /** Negotiated subject CN (from the leaf cert). */\n subject: string;\n /** Issuer organization (e.g. \"Let's Encrypt\"). */\n issuer: string;\n /** Whole days until the leaf cert's `notAfter` field. Negative when the\n * cert is already expired but the server still happened to return one. */\n daysToExpiry: number;\n}\n\nexport interface TlsHandshakeFailed {\n ok: false;\n reason: string;\n}\n\nexport type TlsHandshakeResult = TlsHandshakeOk | TlsHandshakeFailed;\n\nexport interface TlsProbeInput {\n host: string;\n port?: number;\n /** Socket-level timeout in milliseconds. Anything that doesn't ALPN/SNI\n * within this window is reported as a timeout reason, not a hang. */\n timeoutMs?: number;\n /** Injectable for tests. Defaults to the real `tls.connect`. */\n connect?: typeof tls.connect;\n /** Reference time for daysToExpiry math. Injectable for tests so the\n * expected value doesn't drift. */\n now?: Date;\n}\n\n/** Cert subject/issuer fields can be string or string[] (multi-valued RDNs).\n * We render the first item for display. */\nfunction first(v: string | string[] | undefined): string | undefined {\n if (v === undefined) return undefined;\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * One-shot TLS handshake. Returns the result rather than throwing — the\n * verify wizard wants to fold every failure into a single report.\n */\nexport function tlsHandshake(input: TlsProbeInput): Promise<TlsHandshakeResult> {\n const host = input.host;\n const port = input.port ?? 443;\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const connect = input.connect ?? tls.connect;\n const now = input.now ?? new Date();\n\n return new Promise<TlsHandshakeResult>((resolve) => {\n let socket: tls.TLSSocket;\n let settled = false;\n const settle = (r: TlsHandshakeResult): void => {\n if (settled) return;\n settled = true;\n socket?.destroy();\n resolve(r);\n };\n\n // `tls.connect` is async by contract, but the injectable `connect` plus\n // certain pathological options (bad servername length, etc.) can throw\n // synchronously. Convert that into a failure result so callers keep\n // seeing the discriminated union instead of a rejection. (review B2)\n try {\n socket = connect({\n host,\n port,\n servername: host,\n timeout: timeoutMs,\n });\n } catch (err) {\n settle({ ok: false, reason: `tls.connect to ${host}:${port} threw: ${(err as Error).message}` });\n return;\n }\n\n socket.once('secureConnect', () => {\n const cert = socket.getPeerCertificate(false);\n if (!cert || Object.keys(cert).length === 0) {\n settle({ ok: false, reason: 'TLS connected but peer presented no certificate' });\n return;\n }\n const notAfter = new Date(cert.valid_to);\n if (Number.isNaN(notAfter.getTime())) {\n settle({ ok: false, reason: `cert presented an unparseable notAfter: ${cert.valid_to}` });\n return;\n }\n const msPerDay = 1000 * 60 * 60 * 24;\n const daysToExpiry = Math.floor((notAfter.getTime() - now.getTime()) / msPerDay);\n const subject = first(cert.subject?.CN) ?? '<no CN>';\n const issuer = first(cert.issuer?.O) ?? first(cert.issuer?.CN) ?? '<no issuer>';\n settle({ ok: true, subject, issuer, daysToExpiry });\n });\n\n socket.once('timeout', () => {\n settle({ ok: false, reason: `TLS handshake to ${host}:${port} timed out after ${timeoutMs}ms` });\n });\n\n socket.once('error', (err) => {\n settle({ ok: false, reason: `TLS handshake to ${host}:${port} failed: ${err.message}` });\n });\n });\n}\n","import { readFileSync } from 'node:fs';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { tunnelStatus, type TunnelStatusInput, type TunnelStatusResult } from '../lib/cloudflare.js';\nimport { cosignVerifyImage, type CosignVerifyInput, type CosignVerifyResult } from '../lib/cosign.js';\nimport { graphqlProbe, httpProbe, type GraphqlProbeInput, type GraphqlProbeResult, type HttpProbeInput, type HttpProbeResult } from '../lib/http.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { tlsHandshake, type TlsProbeInput, type TlsHandshakeResult } from '../lib/tls.js';\nimport { checkOllamaHealth, modelPresent, type EmbeddingsProvider, type OllamaHealth } from '../lib/ollama.js';\nimport { readEnvModelConfig, type NodeEnvModelConfig } from '../lib/env-file.js';\nimport { looksLikeNodeRepo } from '../lib/noderepo.js';\n\ninterface VerifyOptions {\n domain?: string;\n apiHost?: string;\n cfToken?: string;\n cfTokenFile?: string;\n cfAccountId?: string;\n tunnelId?: string;\n image?: string[];\n certWarnDays?: string;\n showSkipped?: boolean;\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: EmbeddingsProvider;\n repoDir?: string;\n localOnly?: boolean;\n}\n\nconst DOMAIN_RE = /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i;\n\nexport interface VerifyPhase {\n readonly name: string;\n readonly status: 'ok' | 'warn' | 'fail' | 'skipped';\n readonly detail: string;\n}\n\nexport interface VerifyReport {\n readonly phases: ReadonlyArray<VerifyPhase>;\n}\n\nexport function summarize(report: VerifyReport): { ok: boolean; failed: number; warned: number } {\n let failed = 0;\n let warned = 0;\n for (const ph of report.phases) {\n if (ph.status === 'fail') failed++;\n if (ph.status === 'warn') warned++;\n }\n return { ok: failed === 0, failed, warned };\n}\n\nfunction formatExpiry(days: number): string {\n if (days < 0) return `expired ${-days}d ago`;\n if (days === 0) return 'expires today';\n return `${days}d to expiry`;\n}\n\n/* ------------------------------------------------------------------ *\n * Injectable orchestration (review S3) *\n * ------------------------------------------------------------------ */\n\nexport interface VerifyDeps {\n tls: (input: TlsProbeInput) => Promise<TlsHandshakeResult>;\n http: (input: HttpProbeInput) => Promise<HttpProbeResult>;\n graphql: (input: GraphqlProbeInput) => Promise<GraphqlProbeResult>;\n tunnel: (input: TunnelStatusInput) => Promise<TunnelStatusResult>;\n cosign: (input: CosignVerifyInput) => Promise<CosignVerifyResult>;\n /** Local Ollama health probe (`/api/tags`). Defaults to checkOllamaHealth\n * against localhost — meaningful only when verify runs ON the node. */\n ollama: (url?: string) => Promise<OllamaHealth>;\n /** Called once per phase as it resolves — lets the CLI render spinners.\n * Pass a no-op for tests that just want the report. */\n onPhase?: (phase: VerifyPhase) => void;\n}\n\nexport interface VerifyInput {\n apiHost: string;\n certWarnDays: number;\n /** All three OR none. Mid-set is treated as a `warn` phase by runVerify. */\n cf?: {\n token?: string;\n accountId?: string;\n tunnelId?: string;\n };\n images: ReadonlyArray<string>;\n /** Configured model(s) to assert are present in the LOCAL Ollama. Resolved\n * from `--llm-model` or the node `.env` (readEnvModelConfig). Absent →\n * the Ollama phase is skipped (preserves off-LAN \"run from anywhere\"). */\n ollama?: {\n llmModel: string;\n embeddingModel?: string;\n provider?: EmbeddingsProvider;\n };\n /** Node has no public domain/tunnel (bootstrap --local-only). Skips the\n * domain-dependent probes (TLS, /health, GraphQL, Cloudflare) as `skipped`\n * rather than failing them, leaving the node-local checks (Ollama, cosign)\n * to decide the outcome. See #104. */\n localOnly?: boolean;\n}\n\nconst DEFAULT_DEPS: VerifyDeps = {\n tls: tlsHandshake,\n http: httpProbe,\n graphql: graphqlProbe,\n tunnel: tunnelStatus,\n cosign: cosignVerifyImage,\n ollama: checkOllamaHealth,\n};\n\ntype PushVerifyPhase = (ph: VerifyPhase) => void;\n\nexport async function runVerify(input: VerifyInput, deps: VerifyDeps = DEFAULT_DEPS): Promise<VerifyReport> {\n // Each phase pushes its result(s) via push(), which records + fires onPhase\n // in lockstep. push is threaded into the phase helpers (rather than having\n // them return arrays) so the cosign loop keeps firing onPhase per-image,\n // interleaved with its async calls — exactly as the original inline loop.\n const phases: VerifyPhase[] = [];\n const push: PushVerifyPhase = (ph) => {\n phases.push(ph);\n deps.onPhase?.(ph);\n };\n\n await verifyTlsPhase(input, deps, push);\n await verifyHealthPhase(input, deps, push);\n await verifyGraphqlPhase(input, deps, push);\n await verifyOllamaModelsPhase(input, deps, push);\n await verifyCloudflarePhase(input, deps, push);\n await verifyCosignPhase(input, deps, push);\n\n return { phases };\n}\n\n// Record a domain-dependent phase as `skipped` on a --local-only node (no\n// public endpoint / tunnel to reach), preserving phase ordering + counts so a\n// healthy local node exits 0 instead of failing inapplicable probes. See #104.\nfunction skipLocalOnly(name: string, detail: string, push: PushVerifyPhase): void {\n push({ name, status: 'skipped', detail });\n}\n\nconst LOCAL_ONLY_NO_ENDPOINT = 'local-only node — no public endpoint to probe';\n\n// ---- Phase 1: TLS handshake ---------------------------------------\nasync function verifyTlsPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('TLS handshake', LOCAL_ONLY_NO_ENDPOINT, push);\n const tls = await deps.tls({ host: input.apiHost });\n if (!tls.ok) {\n push({ name: 'TLS handshake', status: 'fail', detail: tls.reason });\n return;\n }\n const line = `subject=${tls.subject}, issuer=${tls.issuer}, ${formatExpiry(tls.daysToExpiry)}`;\n if (tls.daysToExpiry < input.certWarnDays) {\n push({\n name: 'TLS handshake',\n status: 'warn',\n detail: tls.daysToExpiry < 0 ? line : `${line} (< warn threshold ${input.certWarnDays}d)`,\n });\n return;\n }\n push({ name: 'TLS handshake', status: 'ok', detail: line });\n}\n\n// ---- Phase 2: GET /health ------------------------------------------\nasync function verifyHealthPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('GET /health', LOCAL_ONLY_NO_ENDPOINT, push);\n const health = await deps.http({ url: `https://${input.apiHost}/health` });\n if (health.ok) {\n push({ name: 'GET /health', status: 'ok', detail: `HTTP ${health.status}` });\n } else {\n push({ name: 'GET /health', status: 'fail', detail: health.reason });\n }\n}\n\n// ---- Phase 3: GraphQL { __typename } -------------------------------\nasync function verifyGraphqlPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('GraphQL { __typename }', LOCAL_ONLY_NO_ENDPOINT, push);\n const gql = await deps.graphql({ url: `https://${input.apiHost}/api` });\n if (gql.ok) {\n push({ name: 'GraphQL { __typename }', status: 'ok', detail: `typename=${gql.typename}` });\n } else {\n push({ name: 'GraphQL { __typename }', status: 'fail', detail: gql.reason });\n }\n}\n\n// ---- Phase 4: Ollama model presence (optional, node-local) ---------\n//\n// Catches the config↔runtime drift that silently 404s at inference time: the\n// configured LLM_MODEL naming a model that was never pulled into the host\n// Ollama. Probes the LOCAL daemon, so it's meaningful only when verify runs\n// ON the node — hence skipped (not failed) when no model was resolved, which\n// keeps an off-LAN `verify --domain …` from tripping it.\nasync function verifyOllamaModelsPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n const cfg = input.ollama;\n if (!cfg?.llmModel) {\n push({\n name: 'Ollama models',\n status: 'skipped',\n detail: 'pass --llm-model (or run on the node so its .env is read) to enable',\n });\n return;\n }\n\n const health = await deps.ollama();\n if (!health.reachable) {\n push({\n name: 'Ollama models',\n status: 'fail',\n detail:\n 'configured model set but the local Ollama daemon is unreachable on :11434 — ' +\n 'start it with `brew services start ollama` (run this check on the node)',\n });\n return;\n }\n\n // Assert the LLM always; assert the embedding model only when the knowledge\n // service actually uses the Ollama provider for it (xenova is in-process).\n const required = [cfg.llmModel];\n if (cfg.provider === 'ollama' && cfg.embeddingModel) required.push(cfg.embeddingModel);\n\n const missing = required.filter((m) => !modelPresent(m, health.models));\n if (missing.length > 0) {\n const remedy = missing.map((m) => `ollama pull ${m}`).join(' && ');\n push({\n name: 'Ollama models',\n status: 'fail',\n detail: `not installed: ${missing.join(', ')} — remedy: ${remedy}`,\n });\n return;\n }\n push({ name: 'Ollama models', status: 'ok', detail: `${required.join(', ')} present` });\n}\n\n// ---- Phase 5: Cloudflare Tunnel status (optional) ------------------\nasync function verifyCloudflarePhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('Cloudflare Tunnel', 'local-only node — no tunnel', push);\n const cfFields: ReadonlyArray<[string, string | undefined]> = [\n ['--cf-token', input.cf?.token],\n ['--cf-account-id', input.cf?.accountId],\n ['--tunnel-id', input.cf?.tunnelId],\n ];\n const cfSet = cfFields.filter(([, v]) => v !== undefined && v !== '');\n if (cfSet.length === 0) {\n push({\n name: 'Cloudflare Tunnel',\n status: 'skipped',\n detail: 'pass --cf-token + --cf-account-id + --tunnel-id to enable',\n });\n return;\n }\n if (cfSet.length < cfFields.length) {\n // (review S1) Partial config is operator-hostile — they almost certainly\n // meant to enable the check. Warn so the missing flag names are visible.\n const missing = cfFields.filter(([, v]) => v === undefined || v === '').map(([name]) => name).join(', ');\n push({\n name: 'Cloudflare Tunnel',\n status: 'warn',\n detail: `partial CF config — missing ${missing}; check skipped`,\n });\n return;\n }\n const tun = await deps.tunnel({\n token: input.cf!.token!,\n accountId: input.cf!.accountId!,\n tunnelId: input.cf!.tunnelId!,\n });\n if (!tun.ok) {\n push({ name: 'Cloudflare Tunnel', status: 'fail', detail: tun.reason });\n } else if (tun.connections === 0) {\n push({\n name: 'Cloudflare Tunnel',\n status: 'warn',\n detail: `status=${tun.status}, 0 connections — cloudflared on the Studio appears offline`,\n });\n } else {\n push({\n name: 'Cloudflare Tunnel',\n status: 'ok',\n detail: `${tun.connections} connections, status=${tun.status}`,\n });\n }\n}\n\n// ---- Phase 6: cosign signature check (optional) --------------------\nasync function verifyCosignPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.images.length === 0) {\n push({\n name: 'cosign verify',\n status: 'skipped',\n detail: 'pass --image <ref> (repeatable) to enable',\n });\n return;\n }\n for (const image of input.images) {\n const cos = await deps.cosign({ image });\n if (cos.ok) {\n push({ name: `cosign verify ${image}`, status: 'ok', detail: 'signature valid' });\n } else if (cos.skipped) {\n push({ name: `cosign verify ${image}`, status: 'skipped', detail: cos.reason });\n } else {\n push({ name: `cosign verify ${image}`, status: 'fail', detail: cos.reason });\n }\n }\n}\n\n/* ------------------------------------------------------------------ *\n * CLI wrapper *\n * ------------------------------------------------------------------ */\n\nfunction readTokenFile(path: string): string {\n const raw = readFileSync(path, 'utf8').trim();\n if (!raw) throw new Error(`--cf-token-file ${path} was empty`);\n return raw;\n}\n\n/**\n * Commander array collector for the repeatable `--image` option. Without an\n * argParser, commander stores only the last value as a plain string, which the\n * cosign phase then iterates character-by-character (verifying \"g\", \"h\", \"c\", …\n * as image refs). Mirrors `collectComposeFile` (#82). See #103.\n */\nexport function collectImage(value: string, previous: string[] | undefined): string[] {\n return [...(previous ?? []), value];\n}\n\nexport const verifyCommand = new Command('verify')\n .description(\n 'Off-LAN health probe of a live node — TLS, Apollo Federation reachability, GraphQL smoke. ' +\n 'Run from anywhere with internet access.',\n )\n .addOption(\n new Option('--domain <domain>', 'Domain to probe (e.g. example.org → checks api.example.org)'),\n )\n .addOption(new Option('--api-host <host>', 'Override the API hostname (default: api.<domain>)'))\n .addOption(new Option('--cf-token <token>', 'Cloudflare API token (enables tunnel-status probe)'))\n .addOption(\n new Option('--cf-token-file <path>', 'Read CF token from a file (avoids exposing it via ps)'),\n )\n .addOption(new Option('--cf-account-id <id>', 'Cloudflare account ID (required with --cf-token)'))\n .addOption(\n new Option('--tunnel-id <id>', 'Cloudflare Tunnel ID to query (required with --cf-token)'),\n )\n .addOption(\n new Option('--image <ref>', 'Repeatable. Image to cosign-verify (e.g. ghcr.io/opuspopuli/api:tag)')\n .default([] as string[])\n .argParser(collectImage),\n )\n .addOption(\n new Option('--cert-warn-days <n>', 'Warn if cert expires within N days').default('14'),\n )\n .addOption(\n new Option(\n '--llm-model <model>',\n 'Assert this model is present in the local Ollama (catches config↔runtime drift). Defaults to LLM_MODEL from the node .env when run on the node.',\n ),\n )\n .addOption(\n new Option('--embedding-model <model>', 'Also assert this embedding model is present (only checked when --embeddings-provider=ollama).'),\n )\n .addOption(\n new Option('--embeddings-provider <provider>', 'Embeddings provider the node runs; the embedding model is only asserted for `ollama`.').choices(['xenova', 'ollama']),\n )\n .addOption(\n new Option('--repo-dir <path>', \"Node repo dir whose .env supplies the model config when --llm-model is omitted (default: cwd).\"),\n )\n .addOption(\n new Option(\n '--local-only',\n 'Node has no public domain/tunnel — skip the TLS/health/GraphQL/tunnel probes (no domain prompt) and run only the node-local checks (Ollama model presence, cosign).',\n ).default(false),\n )\n .addOption(\n new Option('--show-skipped', 'Include skipped phases in the summary').default(false),\n )\n .action(async (opts: VerifyOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node verify ')));\n\n const localOnly = opts.localOnly ?? false;\n // A local-only node has no public endpoint, so don't resolve/prompt for a\n // domain — the domain-dependent phases self-skip below.\n const domain = localOnly ? undefined : await resolveDomain(opts);\n const certWarnDays = resolveCertWarnDays(opts);\n const cfToken = resolveCfToken(opts);\n\n const apiHost = localOnly ? '' : (opts.apiHost ?? `api.${domain}`);\n const images = opts.image ?? [];\n const ollama = await resolveOllamaVerifyInput(opts);\n // Fixed phases: TLS, health, GraphQL, Ollama, Cloudflare (5) + cosign\n // (one line when no --image, else one per image).\n const totalPhases = 5 + (images.length === 0 ? 1 : images.length);\n\n const report = await runVerifyWithSpinner({\n apiHost,\n certWarnDays,\n cfToken,\n opts,\n images,\n totalPhases,\n localOnly,\n ...(ollama ? { ollama } : {}),\n });\n\n renderVerifySummary(report, { opts, totalPhases });\n reportVerifyOutcome(report);\n });\n\nfunction phaseIcon(ph: VerifyPhase): string {\n switch (ph.status) {\n case 'ok': return pc.green('✓');\n case 'warn': return pc.yellow('⚠');\n case 'skipped': return pc.dim('·');\n case 'fail': return pc.red('✗');\n }\n}\n\nfunction phaseColor(status: VerifyPhase['status']): (text: string) => string {\n switch (status) {\n case 'ok': return pc.green;\n case 'warn': return pc.yellow;\n case 'skipped': return pc.dim;\n case 'fail': return pc.red;\n }\n}\n\nfunction formatPhaseLine(prefix: string, ph: VerifyPhase): string {\n const icon = phaseIcon(ph);\n const colorize = phaseColor(ph.status);\n return colorize(`${icon} ${prefix}: ${ph.detail}`);\n}\n\n// ----------------------------------------------------------------------------\n// Verify command phases\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: interactive prompts,\n// spinners, and process.exit calls are relocated verbatim.\n\nasync function resolveDomain(opts: VerifyOptions): Promise<string> {\n const domain = opts.domain\n ? opts.domain\n : unwrap(\n await p.text({\n message: 'Public domain of the node?',\n placeholder: 'yournode.example.org',\n validate: (v) =>\n DOMAIN_RE.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens, dots; must contain a dot and a TLD',\n }),\n );\n if (!DOMAIN_RE.test(domain)) {\n p.cancel(`--domain ${JSON.stringify(domain)} doesn't look like a domain.`);\n process.exit(2);\n }\n return domain;\n}\n\n// (review B1) Validate --cert-warn-days to a non-negative integer.\nfunction resolveCertWarnDays(opts: VerifyOptions): number {\n const rawDays = opts.certWarnDays ?? '14';\n const certWarnDays = Number.parseInt(rawDays, 10);\n if (!Number.isFinite(certWarnDays) || certWarnDays < 0 || !/^\\d+$/.test(rawDays)) {\n p.cancel(`--cert-warn-days must be a non-negative integer (got ${JSON.stringify(rawDays)}).`);\n process.exit(2);\n }\n return certWarnDays;\n}\n\n// Resolve the CF token from --cf-token or --cf-token-file (mutually exclusive).\nfunction resolveCfToken(opts: VerifyOptions): string | undefined {\n if (opts.cfToken && opts.cfTokenFile) {\n p.cancel('Pass either --cf-token or --cf-token-file, not both.');\n process.exit(2);\n }\n if (opts.cfToken) return opts.cfToken;\n if (!opts.cfTokenFile) return undefined;\n try {\n return readTokenFile(opts.cfTokenFile);\n } catch (err) {\n p.cancel((err as Error).message);\n process.exit(2);\n }\n}\n\n/** Narrow an arbitrary `.env` string to a known provider, or undefined. */\nfunction normalizeProvider(v: string | undefined): EmbeddingsProvider | undefined {\n return v === 'ollama' || v === 'xenova' ? v : undefined;\n}\n\n/**\n * Merge CLI flags over the node `.env` config, per field. A flag always wins\n * over the file for its own field, but a field the flag omits still falls back\n * to `.env` — so `--llm-model foo` on the node still picks up the provider /\n * embedding model from `.env`. Undefined when no model resolves at all (the\n * phase then skips). Pure — unit-tested independently of the filesystem.\n */\nexport function mergeOllamaModelConfig(\n opts: Pick<VerifyOptions, 'llmModel' | 'embeddingModel' | 'embeddingsProvider'>,\n envCfg: NodeEnvModelConfig,\n): VerifyInput['ollama'] {\n const llmModel = opts.llmModel ?? envCfg.llmModel;\n if (!llmModel) return undefined;\n const embeddingModel = opts.embeddingModel ?? envCfg.embeddingModel;\n const provider = normalizeProvider(opts.embeddingsProvider ?? envCfg.embeddingsProvider);\n return {\n llmModel,\n ...(embeddingModel ? { embeddingModel } : {}),\n ...(provider ? { provider } : {}),\n };\n}\n\n// Resolve the model config the Ollama presence phase asserts. Reads the node\n// `.env` (single source of truth written by bootstrap) and merges flags over\n// it per field. The `.env` is only read from a dir we trust — an explicit\n// --repo-dir, or a cwd that actually looks like a node repo — so a stray\n// `.env` in an unrelated cwd can't trigger a localhost probe (false fail).\nasync function resolveOllamaVerifyInput(opts: VerifyOptions): Promise<VerifyInput['ollama']> {\n const explicit = opts.repoDir !== undefined;\n const dir = opts.repoDir ?? process.cwd();\n const envCfg: NodeEnvModelConfig =\n explicit || (await looksLikeNodeRepo(dir)) ? await readEnvModelConfig(dir) : {};\n\n // Surface a typo'd EMBEDDINGS_PROVIDER instead of silently skipping the\n // embedding-model check (only the .env can carry a bad value — the flag is\n // constrained by commander `.choices`).\n if (\n opts.embeddingsProvider === undefined &&\n envCfg.embeddingsProvider !== undefined &&\n normalizeProvider(envCfg.embeddingsProvider) === undefined\n ) {\n p.note(\n `${pc.yellow('⚠')} Unrecognized EMBEDDINGS_PROVIDER=${envCfg.embeddingsProvider} in .env — expected xenova|ollama; the embedding-model check is disabled.`,\n 'verify',\n );\n }\n\n return mergeOllamaModelConfig(opts, envCfg);\n}\n\n// Run the checks behind a single spinner that advances per phase.\nasync function runVerifyWithSpinner(args: {\n apiHost: string;\n certWarnDays: number;\n cfToken: string | undefined;\n opts: VerifyOptions;\n images: string[];\n totalPhases: number;\n localOnly: boolean;\n ollama?: VerifyInput['ollama'];\n}): Promise<VerifyReport> {\n const { apiHost, certWarnDays, cfToken, opts, images, totalPhases, localOnly, ollama } = args;\n\n let phaseIndex = 0;\n let activeSpin: ReturnType<typeof p.spinner> | null = null;\n const renderPhase = (ph: VerifyPhase): void => {\n phaseIndex++;\n const prefix = `[${phaseIndex}/${totalPhases}] ${ph.name}`;\n activeSpin?.stop(formatPhaseLine(prefix, ph));\n activeSpin = null;\n };\n\n const deps: VerifyDeps = { ...DEFAULT_DEPS, onPhase: renderPhase };\n\n activeSpin = p.spinner();\n activeSpin.start('Running checks…');\n\n const report = await runVerify(\n {\n apiHost,\n certWarnDays,\n cf: {\n ...(cfToken ? { token: cfToken } : {}),\n ...(opts.cfAccountId ? { accountId: opts.cfAccountId } : {}),\n ...(opts.tunnelId ? { tunnelId: opts.tunnelId } : {}),\n },\n images,\n localOnly,\n ...(ollama ? { ollama } : {}),\n },\n deps,\n );\n // If `runVerify` finished without firing onPhase for some pathological\n // reason, stop the spinner cleanly.\n activeSpin?.stop('Done.');\n return report;\n}\n\n// Render the per-phase summary note (hiding skipped phases unless asked).\nfunction renderVerifySummary(\n report: VerifyReport,\n args: { opts: VerifyOptions; totalPhases: number },\n): void {\n const { opts, totalPhases } = args;\n const visible = (opts.showSkipped ?? false)\n ? report.phases\n : report.phases.filter((ph) => ph.status !== 'skipped');\n const lines = visible.map((ph) => {\n const idx = report.phases.indexOf(ph) + 1;\n return `${phaseIcon(ph)} [${idx}/${totalPhases}] ${ph.name}: ${pc.dim(ph.detail)}`;\n });\n const skippedCount = report.phases.length - visible.length;\n if (skippedCount > 0 && !opts.showSkipped) {\n lines.push(pc.dim(`· ${skippedCount} phase${skippedCount === 1 ? '' : 's'} skipped (run with --show-skipped to see them)`));\n }\n p.note(lines.join('\\n'), 'Summary');\n}\n\n// Final outro + exit code from the phase report.\nfunction reportVerifyOutcome(report: VerifyReport): void {\n const summary = summarize(report);\n if (!summary.ok) {\n p.outro(pc.red(`${summary.failed} check${summary.failed === 1 ? '' : 's'} failed.`));\n process.exit(1);\n }\n if (summary.warned === 0) {\n p.outro(pc.green('All checks passed.'));\n } else {\n p.outro(pc.yellow(`Passed with ${summary.warned} warning${summary.warned === 1 ? '' : 's'}.`));\n }\n}\n","{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://github.com/OpusPopuli/opuspopuli-regions/schema/region-plugin.schema.json\",\n \"title\": \"Region Plugin File\",\n \"description\": \"A declarative region configuration file for the Opus Populi civic data platform. A handful of string-valued fields (ApiSourceConfig.queryParams, BulkDownloadConfig.filters) support ${variableName} placeholders that the consumer resolves at runtime — see those field descriptions for the supported variable list.\",\n \"type\": \"object\",\n \"required\": [\"name\", \"displayName\", \"description\", \"version\", \"config\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier (e.g., 'california')\"\n },\n \"displayName\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Human-readable region name (e.g., 'California')\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Brief description of this region's data coverage\"\n },\n \"version\": {\n \"type\": \"string\",\n \"pattern\": \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\",\n \"description\": \"Semantic version of this config file\"\n },\n \"config\": {\n \"$ref\": \"#/definitions/DeclarativeRegionConfig\"\n }\n },\n \"definitions\": {\n \"DeclarativeRegionConfig\": {\n \"type\": \"object\",\n \"required\": [\"regionId\", \"regionName\", \"description\", \"timezone\", \"dataSources\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"regionId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier (e.g., 'california')\"\n },\n \"regionName\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Human-readable region name (e.g., 'California')\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Region description\"\n },\n \"timezone\": {\n \"type\": \"string\",\n \"description\": \"IANA timezone (e.g., 'America/Los_Angeles')\"\n },\n \"stateCode\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Z]{2}$\",\n \"description\": \"Two-letter US state code (e.g., 'CA')\"\n },\n \"parentRegionId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier of this region's parent in the geographic hierarchy. Top-level regions (states, federal) omit this field. Counties set parentRegionId to their state's regionId (e.g., 'california'); cities will set it to their county's regionId. Presence of this field is the canonical signal that a region is a sub-region; the consumer loader uses it to build the region tree.\"\n },\n \"fipsCode\": {\n \"type\": \"string\",\n \"pattern\": \"^\\\\d{2,7}$\",\n \"description\": \"Census FIPS code: 2 digits for states (e.g., '06' for CA), 5 digits for counties (e.g., '06037' for Los Angeles County — state FIPS + county FIPS), 7 digits for places/cities. This is the canonical join key against the consumer's PostGIS counties/places tables used today for user-to-district placement.\"\n },\n \"dataSources\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"$ref\": \"#/definitions/DataSourceConfig\"\n },\n \"description\": \"Data sources to scrape\"\n },\n \"rateLimit\": {\n \"type\": \"object\",\n \"properties\": {\n \"requestsPerSecond\": { \"type\": \"number\", \"minimum\": 0 },\n \"burstSize\": { \"type\": \"integer\", \"minimum\": 1 }\n },\n \"required\": [\"requestsPerSecond\", \"burstSize\"],\n \"additionalProperties\": false,\n \"description\": \"Rate limiting defaults\"\n },\n \"cacheTtlMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Cache TTL in milliseconds\"\n },\n \"requestTimeoutMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Request timeout in milliseconds\"\n },\n \"normalizeExternalIdDistrict\": {\n \"type\": \"boolean\",\n \"description\": \"Strip leading zeros from representative externalId trailing segment (e.g. ca-assembly-01 → ca-assembly-1). Opt-in; default false. Only needed for regions whose LLM manifests emit zero-padded district numbers.\"\n },\n \"bioNoisePatterns\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Regex pattern strings (case-insensitive) matched against scraped representative bio text. Bios matching any pattern are treated as nav junk and discarded. Defaults to no filtering if omitted.\"\n },\n \"boundarySources\": {\n \"$ref\": \"#/definitions/BoundarySourcesConfig\",\n \"description\": \"Civic-boundary geometry sources used to populate the consumer's `jurisdictions` table (counties, cities, state legislative districts, school districts, special districts). The consumer's BoundaryLoaderService reads this block, dispatches to TIGER and ArcGIS FeatureServer fetchers, and upserts on fipsCode/ocdId. Omit when a region has no public boundary data — addresses still resolve via Census Geocoder string fields, but PostGIS point-in-polygon queries return no matches. See opuspopuli#804.\"\n }\n }\n },\n \"BoundarySourcesConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"ocdIdPrefix\"],\n \"description\": \"Per-region declarative recipe for loading civic boundaries. Pure config — no per-region code lives in the consumer.\",\n \"properties\": {\n \"ocdIdPrefix\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Open Civic Data ID prefix for this region, e.g. 'ocd-division/country:us/state:ca'. All jurisdiction OCD-IDs are composed as `${ocdIdPrefix}${TigerLayerConfig.ocdIdSegment}` (or the Geoportal equivalent).\"\n },\n \"tigerLayers\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/definitions/TigerLayerConfig\" },\n \"description\": \"US Census TIGER/Line layers to ingest as jurisdictions. Each entry maps one ArcGIS MapServer layer to a JurisdictionType. Omit the field entirely when the region has no TIGER coverage — do not pass an empty array (the schema rejects it to prevent silent typos that strip the configured layers).\"\n },\n \"geoportalLayers\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/definitions/GeoportalLayerConfig\" },\n \"description\": \"Region-specific ArcGIS FeatureServer endpoints — typically state geoportals serving boundary data Census TIGER doesn't cover (fire districts, water districts, transit districts, etc.). Omit when unused — empty arrays are rejected (see tigerLayers note).\"\n }\n }\n },\n \"JurisdictionTypeEnum\": {\n \"type\": \"string\",\n \"enum\": [\"COUNTY\", \"CITY\", \"STATE_SENATE_DISTRICT\", \"STATE_ASSEMBLY_DISTRICT\", \"CONGRESSIONAL_DISTRICT\", \"SCHOOL_DISTRICT_UNIFIED\", \"SCHOOL_DISTRICT_ELEMENTARY\", \"SCHOOL_DISTRICT_HIGH\", \"COMMUNITY_COLLEGE_DISTRICT\", \"WATER_DISTRICT\", \"FIRE_DISTRICT\", \"TRANSIT_DISTRICT\", \"SPECIAL_DISTRICT\"],\n \"description\": \"Maps each feature to a JurisdictionType row in the consumer's `jurisdictions` table. Single source of truth — TigerLayerConfig and GeoportalLayerConfig both reference this so a new jurisdiction type can't be added to one without the other.\"\n },\n \"JurisdictionLevelEnum\": {\n \"type\": \"string\",\n \"enum\": [\"FEDERAL\", \"STATE\", \"COUNTY\", \"MUNICIPAL\", \"DISTRICT\"],\n \"description\": \"Hierarchy level for the resulting jurisdiction rows. Single source of truth — referenced from TigerLayerConfig and GeoportalLayerConfig.\"\n },\n \"TigerLayerConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"layer\", \"outFields\", \"jurisdictionType\", \"level\", \"nameField\"],\n \"description\": \"One TIGER/Line layer mapped to a JurisdictionType. The consumer hits `https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/${layer}/query` with GeoJSON output. Supported placeholders inside `where`, `ocdIdSegment`, `nameTemplate`: ${fipsCode} (this region's fipsCode), ${stateCode} (two-letter code), ${name} (the layer's nameField value for a given feature), ${district} (the districtField value).\",\n \"properties\": {\n \"layer\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"TIGER MapServer service+layer path, e.g. 'State_County/MapServer/1', 'Legislative/MapServer/1' (state senate), 'Legislative/MapServer/2' (state assembly), 'School/MapServer/0' (unified school districts).\"\n },\n \"where\": {\n \"type\": \"string\",\n \"description\": \"ESRI WHERE clause filtering features. Defaults to `STATE='${fipsCode}'` when omitted. Use `${fipsCode}` / `${stateCode}` placeholders.\"\n },\n \"outFields\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Comma-separated TIGER attribute fields to return, e.g. 'GEOID,NAME' or 'GEOID,SLDUST'.\"\n },\n \"jurisdictionType\": {\n \"$ref\": \"#/definitions/JurisdictionTypeEnum\"\n },\n \"level\": {\n \"$ref\": \"#/definitions/JurisdictionLevelEnum\"\n },\n \"nameField\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"TIGER attribute key whose value becomes the substitution for `${name}` placeholders. Typically 'NAME' for human-readable layers, or a district code field like 'SLDUST'/'SLDLST' for legislative layers.\"\n },\n \"fipsField\": {\n \"type\": \"string\",\n \"description\": \"TIGER attribute key holding the canonical fips_code for an upsert. Defaults to 'GEOID'.\"\n },\n \"fipsPrefix\": {\n \"type\": \"string\",\n \"description\": \"Optional prefix prepended to the fipsField value before persisting as fips_code. Use when the raw GEOID would collide with another layer's GEOID (e.g. state senate GEOID overlapping county GEOID format). Example: 'sldu-' for state senate, 'sldl-' for state assembly.\"\n },\n \"districtField\": {\n \"type\": \"string\",\n \"description\": \"TIGER attribute key supplying the ${district} placeholder. Required when ocdIdSegment or nameTemplate contains ${district}.\"\n },\n \"ocdIdSegment\": {\n \"type\": \"string\",\n \"description\": \"Segment appended to `boundarySources.ocdIdPrefix` to form the full OCD-ID, e.g. '/county:${name}', '/sldu:${district}'. Supports ${name} and ${district} placeholders. Inside `${name}` substitutions the consumer normalizes whitespace to underscores and lowercases the value for OCD-ID compatibility — so a NAME of 'Alameda County' produces 'alameda_county' in the OCD-ID. Omit when this layer's rows don't carry an OCD-ID.\"\n },\n \"nameTemplate\": {\n \"type\": \"string\",\n \"description\": \"Template for the persisted jurisdiction name (NOT for OCD-ID composition). Supports ${name}, ${district}, ${stateCode}. The ${name} value is substituted verbatim (case + whitespace preserved). Defaults to ${name} when omitted.\"\n }\n }\n },\n \"GeoportalLayerConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"url\", \"outFields\", \"jurisdictionType\", \"level\", \"nameField\"],\n \"description\": \"One arbitrary ArcGIS FeatureServer layer for jurisdictions Census TIGER doesn't cover. Same placeholder rules as TigerLayerConfig.\",\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https://\",\n \"description\": \"Full ArcGIS FeatureServer layer URL ending in /FeatureServer/<n>. Must be HTTPS — the consumer rejects other schemes. The consumer paginates via resultOffset/resultRecordCount.\"\n },\n \"where\": {\n \"type\": \"string\",\n \"description\": \"ESRI WHERE clause. Defaults to '1=1'.\"\n },\n \"outFields\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Comma-separated FeatureServer attribute fields to return.\"\n },\n \"jurisdictionType\": {\n \"$ref\": \"#/definitions/JurisdictionTypeEnum\"\n },\n \"level\": {\n \"$ref\": \"#/definitions/JurisdictionLevelEnum\"\n },\n \"nameField\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"FeatureServer attribute key supplying the human-readable name and the ${name} placeholder.\"\n },\n \"fipsField\": {\n \"type\": \"string\",\n \"description\": \"FeatureServer attribute key used as fips_code. No default — geoportal attribute names vary widely (no GEOID convention). Omit when the layer has no FIPS analog; the upsert then matches on ocdId only.\"\n },\n \"fipsPrefix\": {\n \"type\": \"string\",\n \"description\": \"Optional prefix prepended to fipsField, mirroring TigerLayerConfig.fipsPrefix.\"\n },\n \"ocdIdSegment\": {\n \"type\": \"string\",\n \"description\": \"Appended to boundarySources.ocdIdPrefix. Supports ${name} placeholder. Same OCD-ID normalization as TigerLayerConfig.ocdIdSegment — whitespace to underscores, lowercased.\"\n },\n \"nameTemplate\": {\n \"type\": \"string\",\n \"description\": \"Template for persisted name (NOT for OCD-ID). ${name} substituted verbatim. Defaults to ${name}.\"\n }\n }\n },\n \"DataSourceConfig\": {\n \"type\": \"object\",\n \"required\": [\"url\", \"dataType\", \"contentGoal\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"description\": \"URL to fetch data from\"\n },\n \"dataType\": {\n \"type\": \"string\",\n \"enum\": [\"propositions\", \"meetings\", \"representatives\", \"campaign_finance\", \"lobbying\", \"civics\", \"bills\"],\n \"description\": \"What type of content this source provides. Daily journals / meeting minutes go under 'meetings' with sourceType=pdf_archive — the consumer partitions by sourceType internally. 'civics' marks a source of region governmental structure, process, and vocabulary; the civics-ingest handler scrapes it and uses the private prompt-service to extract structured shape (chambers, measure types, lifecycle stages with status patterns, glossary) plus a plain-language rewrite for laypeople. Verbatim source text and the AI rewrite are stored together — never one without the other. 'bills' marks a source of individual legislative bills (AB, SB, ACA, SCA, etc.) scraped from an official legislature website; the bills-ingest handler BFS-crawls from the seed URL and extracts one Bill record per detail page. See opuspopuli#686.\"\n },\n \"contentGoal\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Natural language description of what to find/extract\"\n },\n \"category\": {\n \"type\": \"string\",\n \"description\": \"Sub-category for grouping (e.g., 'Assembly', 'Senate')\"\n },\n \"hints\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Hints to help the AI find the right content\"\n },\n \"rateLimitOverride\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"description\": \"Override rate limit for this specific source\"\n },\n \"syncCadence\": {\n \"type\": \"string\",\n \"pattern\": \"^[^ ]+ [^ ]+ [^ ]+ [^ ]+ [^ ]+$\",\n \"description\": \"5-field cron expression (minute hour dom month dow) controlling how often this source is synced. The worker applies a deterministic per-source minute offset at registration time to spread load across gov hosts — the minute field you specify is the base, not the exact fire time. Omit to inherit the global daily fallback. Common patterns: '0 2 * * *' daily at 2 AM, '0 2 * * 0' weekly on Sunday, '0 * * * *' hourly.\"\n },\n \"statusScanCadence\": {\n \"type\": \"string\",\n \"pattern\": \"^[^ ]+ [^ ]+ [^ ]+ [^ ]+ [^ ]+$\",\n \"description\": \"5-field cron expression for a periodic full status-page sweep of all bills (dataType='bills' only). Runs forceStatusRecheck=true — bypasses the needsStatusRecheck flag and the sourcePublishedAt skip to catch governor actions and off-session changes the journal linker can't see. Per-source minute offset is applied like syncCadence. Typical: '0 2 * * 0' weekly Sunday 2 AM. See #689.\"\n },\n \"sourceType\": {\n \"type\": \"string\",\n \"enum\": [\"html_scrape\", \"bulk_download\", \"api\", \"pdf\", \"pdf_archive\"],\n \"description\": \"Source type determines the extraction strategy (default: html_scrape). 'pdf_archive' selects the listing-walk + per-PDF-extract pipeline: the URL is a paginated listing page that links to a series of dated PDF documents, each fetched and parsed (text only at V1) into one Minutes record.\"\n },\n \"bulk\": {\n \"$ref\": \"#/definitions/BulkDownloadConfig\"\n },\n \"api\": {\n \"$ref\": \"#/definitions/ApiSourceConfig\"\n },\n \"pdf\": {\n \"$ref\": \"#/definitions/PdfSourceConfig\"\n },\n \"pdfArchive\": {\n \"$ref\": \"#/definitions/PdfArchiveConfig\"\n },\n \"billDiscovery\": {\n \"$ref\": \"#/definitions/BillDiscoveryConfig\"\n },\n \"detailFields\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/StructuredFieldConfig\" }\n ]\n },\n \"description\": \"Detail page extraction plan: maps domain field names to CSS selectors (string) or structured array configs (object). Supports dot notation and '|attr:name' suffix.\"\n },\n \"staticManifest\": {\n \"type\": \"object\",\n \"required\": [\"containerSelector\", \"itemSelector\", \"fieldMappings\"],\n \"additionalProperties\": false,\n \"description\": \"Explicit extraction selectors that bypass AI structural analysis entirely. Use when the page structure is known and stable, or when the local LLM consistently generates wrong selectors.\",\n \"properties\": {\n \"containerSelector\": { \"type\": \"string\" },\n \"itemSelector\": { \"type\": \"string\" },\n \"fieldMappings\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"fieldName\", \"selector\", \"extractionMethod\", \"required\"],\n \"additionalProperties\": true,\n \"properties\": {\n \"fieldName\": { \"type\": \"string\" },\n \"selector\": { \"type\": \"string\" },\n \"extractionMethod\": { \"type\": \"string\" },\n \"attribute\": { \"type\": \"string\" },\n \"regexPattern\": { \"type\": \"string\" },\n \"regexGroup\": { \"type\": \"integer\" },\n \"transform\": { \"type\": \"object\" },\n \"required\": { \"type\": \"boolean\" },\n \"defaultValue\": { \"type\": \"string\" },\n \"scope\": {\n \"type\": \"string\",\n \"enum\": [\"item\", \"container\"]\n },\n \"children\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/ChildFieldConfig\" }\n ]\n },\n \"description\": \"For extractionMethod='structured': child field selectors. Each value is a string shortcut or a ChildFieldConfig object.\"\n }\n }\n }\n }\n }\n },\n \"crawlDepth\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Crawl depth from the seed URL for sync handlers that walk a site's link graph (currently civics — see opuspopuli#669). 0 (default) = no crawl, fetch only the seed. N = N hops from seed. Crawls are scoped to same host + same path prefix as the seed, HTML responses only.\"\n },\n \"crawlMaxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Cap on total pages a crawler will visit per sync run regardless of crawlDepth. Defaults to 20. Each page costs one LLM call, so this bounds runtime + token spend.\"\n },\n \"llmMaxTokens\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Per-source override for the LLM maxTokens generation cap. Useful when a source needs a much longer or shorter output than its siblings (e.g., a 150-term glossary needs ~32000; a short bio prompt finishes well under 2000). Overrides the sync handler's hardcoded default.\"\n },\n \"llmRequestTimeoutMs\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Per-source override for the LLM provider request timeout (milliseconds). Useful when a single source legitimately runs much longer than the platform-wide default — civics-glossary extraction on qwen3.5:9b can take 15-20 min, while bio gen finishes in 2 min on the same hardware. Overrides the provider's constructor-configured default.\"\n }\n }\n },\n \"BulkDownloadConfig\": {\n \"type\": \"object\",\n \"required\": [\"format\", \"columnMappings\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"format\": {\n \"type\": \"string\",\n \"enum\": [\"tsv\", \"csv\", \"zip_tsv\", \"zip_csv\"],\n \"description\": \"File format\"\n },\n \"filePattern\": {\n \"type\": \"string\",\n \"description\": \"For ZIP archives: path/glob of target file(s) within the ZIP\"\n },\n \"delimiter\": {\n \"type\": \"string\",\n \"description\": \"Column delimiter override\"\n },\n \"headerLines\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Number of header lines to skip\"\n },\n \"headers\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Explicit column headers for files without a header row (e.g., FEC bulk files)\"\n },\n \"columnMappings\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Column name mappings: source column name -> domain field name\"\n },\n \"filters\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Filter expressions applied during parse. Values support ${variableName} placeholders that the consumer resolves at runtime from the active local region. Supported variables: ${stateCode} (the 2-letter US state code of the active local region, e.g. 'CA'). Placeholders must appear verbatim. Example: '\\\"STATE\\\": \\\"${stateCode}\\\"' on an FEC bulk filter.\"\n },\n \"batchSize\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Records per batch for streaming processing (default: 10000)\"\n }\n }\n },\n \"ApiSourceConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"method\": {\n \"type\": \"string\",\n \"enum\": [\"GET\", \"POST\"],\n \"description\": \"HTTP method (default: GET)\"\n },\n \"apiKeyEnvVar\": {\n \"type\": \"string\",\n \"description\": \"Environment variable name containing the API key\"\n },\n \"apiKeyHeader\": {\n \"type\": \"string\",\n \"description\": \"Header name for the API key\"\n },\n \"pagination\": {\n \"$ref\": \"#/definitions/ApiPaginationConfig\"\n },\n \"resultsPath\": {\n \"type\": \"string\",\n \"description\": \"JSON path to the items array in the response\"\n },\n \"queryParams\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Query parameters appended to every request. Values support ${variableName} placeholders that the consumer resolves at runtime from the active local region. Supported variables: ${stateCode} (the 2-letter US state code of the active local region, e.g. 'CA'). Placeholders must appear verbatim — no escaping, no nested expressions. Example: '\\\"contributor_state\\\": \\\"${stateCode}\\\"'.\"\n },\n \"fieldMappings\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Field name mappings: API response field -> domain model field (e.g., committee_id -> committeeId)\"\n }\n }\n },\n \"ApiPaginationConfig\": {\n \"type\": \"object\",\n \"required\": [\"type\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"offset\", \"cursor\", \"page\"],\n \"description\": \"Pagination strategy type\"\n },\n \"pageParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name for page/offset\"\n },\n \"limitParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name for page size\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Number of items per page\"\n }\n }\n },\n \"PdfSourceConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"skipPages\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Skip first N pages (e.g., skip cover page)\"\n },\n \"maxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Maximum pages to process (default: all)\"\n },\n \"followPdfLink\": {\n \"type\": \"boolean\",\n \"description\": \"If true, treats the URL as a gateway page and follows the first PDF link\"\n }\n }\n },\n \"StructuredFieldConfig\": {\n \"type\": \"object\",\n \"required\": [\"selector\", \"children\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"selector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector matching each repeating item (e.g., '.office-card')\"\n },\n \"children\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/ChildFieldConfig\" }\n ]\n },\n \"description\": \"Child field selectors relative to each item. Each entry is either a string shortcut (e.g. 'h3', 'a|attr:href') or a richer ChildFieldConfig object with extractionMethod / regex / transform.\"\n },\n \"multiple\": {\n \"type\": \"boolean\",\n \"description\": \"If true, extracts all matches as an array (default: true)\"\n }\n }\n },\n \"ChildFieldConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"description\": \"Per-child extraction config for structured extraction. Object form supports the same shape as the top-level FieldMapping (selector + extractionMethod + attribute / regex / transform), minus fieldName/required/defaultValue which don't apply at child scope.\",\n \"properties\": {\n \"selector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector relative to the matched parent item. Optional for regex on full element text.\"\n },\n \"extractionMethod\": {\n \"type\": \"string\",\n \"description\": \"How to extract: 'text', 'attribute', 'regex', 'html', etc.\"\n },\n \"attribute\": {\n \"type\": \"string\",\n \"description\": \"For extractionMethod='attribute': which attribute to read (e.g. 'href', 'src').\"\n },\n \"regexPattern\": {\n \"type\": \"string\",\n \"description\": \"For extractionMethod='regex': the pattern.\"\n },\n \"regexGroup\": {\n \"type\": \"integer\",\n \"description\": \"For extractionMethod='regex': capture group (default: 1).\"\n },\n \"transform\": {\n \"type\": \"object\",\n \"description\": \"Optional transform applied after extraction (e.g. trim, regex_replace, url_resolve).\"\n }\n }\n },\n \"BillDiscoveryConfig\": {\n \"type\": \"object\",\n \"required\": [\"navLinkPattern\", \"statusPageTemplate\", \"votesPageTemplate\"],\n \"additionalProperties\": false,\n \"description\": \"Declarative bill discovery for legislature sites that list per-bill nav-hub links on a search results page (e.g. CA leginfo). The bills-ingest handler fetches the seed once, extracts bill IDs with navLinkPattern, and constructs status + votes URLs from the templates — bypassing generic BFS which would exhaust crawlMaxPages with nav-hub links before reaching detail pages.\",\n \"properties\": {\n \"navLinkPattern\": {\n \"type\": \"string\",\n \"description\": \"Regex string applied to the decoded seed-page HTML to extract bill IDs. Capture group 1 must be the bill ID. Example for CA leginfo: \\\"/faces/billNavClient\\\\\\\\.xhtml\\\\\\\\?bill_id=([^\\\\\\\"&\\\\\\\\s]+)\\\"\"\n },\n \"statusPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"URL path + query template for the bill status page. Use {bill_id} as the placeholder; the service prepends the seed origin. Example: \\\"/faces/billStatusClient.xhtml?bill_id={bill_id}\\\"\"\n },\n \"votesPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"URL path + query template for the bill votes page. Same substitution as statusPageTemplate. Example: \\\"/faces/billVotesClient.xhtml?bill_id={bill_id}\\\"\"\n },\n \"textPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"Optional URL path + query template for the bill text page. When set, the sync fetches this page before LLM extraction to check the 'Date Published' timestamp and skip unchanged bills. Example: \\\"/faces/billTextClient.xhtml?bill_id={bill_id}\\\"\"\n }\n }\n },\n \"PdfArchiveConfig\": {\n \"type\": \"object\",\n \"required\": [\"linkSelector\"],\n \"additionalProperties\": false,\n \"description\": \"Listing-walk configuration for sourceType=pdf_archive. The page at `url` is treated as a paginated index of dated PDF documents; each linked PDF is fetched, pdf-parsed, and stored as a Minutes record. Cold-start work is bounded by maxNew (default 10) so first-run sync doesn't ingest years of historical archives. Per-document parsing (text → action records) is a downstream backend pass — this block carries no parser DSL.\",\n \"properties\": {\n \"linkSelector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector for PDF anchor elements on the listing page. Each match yields a candidate document.\"\n },\n \"datePattern\": {\n \"type\": \"string\",\n \"description\": \"Regex applied to the link href (falling back to anchor text) to extract the document's date. Capture groups depend on dateFormat.\"\n },\n \"dateFormat\": {\n \"type\": \"string\",\n \"description\": \"Date format hint for interpreting datePattern's captures. Supported: 'MMDDYY' (3 captures: month, day, two-digit year — assumed 20YY), 'YYYY-MM-DD' (3 captures), 'MM/DD/YYYY' (3 captures).\"\n },\n \"revisionPattern\": {\n \"type\": \"string\",\n \"description\": \"Regex against the link href whose match indicates this URL is a revision. Capture group 1 is the revision sequence number (1, 2, ...). Unmatched URLs are revisionSeq=0.\"\n },\n \"maxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Maximum number of listing pages to walk during one sync cycle. Default: 10.\"\n },\n \"maxNew\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Hard cap on number of new documents ingested per sync cycle. Cold-start protection. Default: 10.\"\n },\n \"paginationParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name used to paginate the listing page (e.g., 'page'). Omitted when the listing isn't paginated.\"\n }\n }\n }\n }\n}","/**\n * Pure logic for scaffolding a region config for the\n * [`OpusPopuli/opuspopuli-regions`](https://github.com/OpusPopuli/opuspopuli-regions)\n * repo.\n *\n * Region configs are declarative JSON files validated against\n * `schema/region-plugin.schema.json` in that repo. We vendor a copy of that\n * schema at `./region-schema.json` so the wizard is self-contained and\n * validates against the **canonical contract** rather than a hand-rolled\n * approximation. Anything the schema enforces is enforced here; we layer a\n * small set of cross-field invariants on top that the regions repo's\n * `pnpm test` also checks (e.g. `name === config.regionId`).\n *\n * Everything here is side-effect free and unit tested. The interactive shell\n * and filesystem writes live in `src/commands/region.ts`.\n */\n\n// ESM-native JSON Schema validator. Picked over Ajv 8 because Ajv ships only\n// CJS, which forces a `.default` interop dance under `verbatimModuleSyntax`.\n// `@cfworker/json-schema` is a clean ESM module with no peer dep and supports\n// the Draft 7 / 2019-09 / 2020-12 schemas the regions repo uses.\nimport { Validator, type Schema } from '@cfworker/json-schema';\n\n// Schema imported as JSON so tsup inlines it into the bundle — no need to\n// ship a separate file in dist/.\nimport REGION_SCHEMA from './region-schema.json' with { type: 'json' };\n\n/** `dataType` values the regions schema accepts on a data source. Mirrors the\n * enum block in `region-plugin.schema.json` so the CLI prompt matches. */\nexport const DATA_TYPES = [\n 'propositions',\n 'meetings',\n 'representatives',\n 'campaign_finance',\n 'lobbying',\n 'civics',\n 'bills',\n] as const;\nexport type DataType = (typeof DATA_TYPES)[number];\n\n/** `sourceType` values the regions schema accepts on a data source. */\nexport const SOURCE_TYPES = [\n 'html_scrape',\n 'bulk_download',\n 'api',\n 'pdf',\n 'pdf_archive',\n] as const;\nexport type SourceType = (typeof SOURCE_TYPES)[number];\n\n/** The two region levels this scaffolder authors. `federal` is a singleton that\n * already exists in the regions repo, so it is intentionally not offered. */\nexport type RegionLevel = 'state' | 'county';\n\nexport interface DataSourceInput {\n url: string;\n dataType: DataType;\n sourceType: SourceType;\n contentGoal: string;\n category?: string;\n}\n\nexport interface RegionInput {\n level: RegionLevel;\n /** kebab-case; for a county this is the combined `state-county` id. */\n regionId: string;\n /** kebab-case county slug only — the trailing segment of a county regionId.\n * Required for counties so we never have to re-derive it from string\n * prefixes; ignored for states. */\n countySlug?: string;\n displayName: string;\n regionName: string;\n description: string;\n /** semver, e.g. `0.1.0`. */\n version: string;\n /** IANA tz, e.g. `America/Los_Angeles`. */\n timezone: string;\n /** Two-letter US state code, uppercase. */\n stateCode: string;\n /** 2 digits for a state, 5 digits for a county. */\n fipsCode: string;\n /** kebab-case parent state id; required for counties, omitted for states. */\n parentRegionId?: string;\n dataSources: DataSourceInput[];\n}\n\ninterface DeclarativeRegionConfig {\n regionId: string;\n regionName: string;\n description: string;\n timezone: string;\n stateCode?: string;\n parentRegionId?: string;\n fipsCode?: string;\n dataSources: DataSourceInput[];\n}\n\nexport interface RegionPluginFile {\n name: string;\n displayName: string;\n description: string;\n version: string;\n config: DeclarativeRegionConfig;\n}\n\nexport const SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst STATE_CODE_RE = /^[A-Z]{2}$/;\n\n/** Lower-cases, strips accents, and collapses anything non-alphanumeric into\n * single hyphens — turning \"Los Angeles County\" into \"los-angeles\". */\nexport function slugify(input: string): string {\n return input\n .normalize('NFKD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n // The collapse above leaves at most a single hyphen at each edge, so a\n // quantifier-free `^-|-$` trim is equivalent to `^-+|-+$` and can't\n // backtrack super-linearly.\n .replace(/^-|-$/g, '');\n}\n\nexport function isValidSlug(v: string): boolean {\n return SLUG_RE.test(v);\n}\n\nexport function isValidStateCode(v: string): boolean {\n return STATE_CODE_RE.test(v);\n}\n\n/** A state FIPS is exactly 2 digits; a county FIPS is exactly 5 (state prefix +\n * 3-digit county). */\nexport function isValidFips(v: string, level: RegionLevel): boolean {\n return level === 'state' ? /^\\d{2}$/.test(v) : /^\\d{5}$/.test(v);\n}\n\n/** Set of IANA zone names on this runtime, or `null` if the host VM doesn't\n * expose `Intl.supportedValuesOf` (in which case callers should skip the\n * membership check rather than reject everything). */\nfunction supportedTimeZones(): Set<string> | null {\n const intl = Intl as typeof Intl & {\n supportedValuesOf?: (key: string) => string[];\n };\n if (typeof intl.supportedValuesOf !== 'function') return null;\n try {\n return new Set(intl.supportedValuesOf('timeZone'));\n } catch {\n return null;\n }\n}\n\nexport function isValidTimezone(v: string): boolean {\n if (!v.includes('/')) return false;\n const zones = supportedTimeZones();\n // If the runtime can't enumerate zones, fall back to a shape check so we\n // don't reject a perfectly good \"Region/City\" string.\n return zones ? zones.has(v) : true;\n}\n\n/**\n * Build the `RegionPluginFile` object from collected input. Optional config\n * fields are only set when present so the JSON stays minimal and we don't trip\n * the schema's `additionalProperties: false` / `exactOptionalPropertyTypes`.\n */\nexport function buildRegionConfig(input: RegionInput): RegionPluginFile {\n const config: DeclarativeRegionConfig = {\n // The regions repo requires `name === config.regionId`; we tie them\n // together at construction so they can never drift.\n regionId: input.regionId,\n regionName: input.regionName,\n description: input.description,\n timezone: input.timezone,\n stateCode: input.stateCode,\n fipsCode: input.fipsCode,\n dataSources: input.dataSources.map(normalizeDataSource),\n };\n if (input.parentRegionId) {\n config.parentRegionId = input.parentRegionId;\n }\n\n return {\n name: input.regionId,\n displayName: input.displayName,\n description: input.description,\n version: input.version,\n config,\n };\n}\n\nfunction normalizeDataSource(src: DataSourceInput): DataSourceInput {\n const out: DataSourceInput = {\n url: src.url,\n dataType: src.dataType,\n sourceType: src.sourceType,\n contentGoal: src.contentGoal,\n };\n if (src.category) out.category = src.category;\n return out;\n}\n\n/**\n * Canonical path of a region file inside the regions repo, relative to the repo\n * root:\n * state → `regions/<state>/<state>.json`\n * county → `regions/<state>/counties/<county>/<county>.json`\n *\n * Counties pass `countySlug` explicitly so we never have to back out a slug\n * from a string prefix — important when a parent state slug contains a hyphen\n * (`new-jersey-cumberland` shouldn't be sliced on the first `-`).\n */\nexport function regionFilePath(input: {\n level: RegionLevel;\n regionId: string;\n parentRegionId?: string;\n countySlug?: string;\n}): string {\n if (input.level === 'state') {\n return `regions/${input.regionId}/${input.regionId}.json`;\n }\n const parent = input.parentRegionId;\n const countySlug = input.countySlug;\n if (!parent || !countySlug) {\n throw new Error(\n 'regionFilePath: county requires both parentRegionId and countySlug',\n );\n }\n return `regions/${parent}/counties/${countySlug}/${countySlug}.json`;\n}\n\n// ---------------------------------------------------------------------------\n// Schema-based validation (single source of truth)\n// ---------------------------------------------------------------------------\n\n// The JSON import resolves to a narrower literal type than `Schema` accepts\n// (e.g. `type: \"object\"` as a string literal vs the union enum). The cast is\n// a TS-only widening — runtime data is unchanged.\nconst schemaValidator = new Validator(REGION_SCHEMA as unknown as Schema, '7');\n\n/**\n * Re-check the invariants the regions repo enforces in CI, returning a list of\n * human-readable problems (empty means valid). Two layers:\n *\n * 1. **JSON Schema** — run the vendored `region-plugin.schema.json` (the same\n * file `pnpm test` validates against). Catches every structural rule the\n * schema declares.\n * 2. **Cross-field invariants** — checks the regions repo enforces in custom\n * test code that don't live in the schema: `name === config.regionId`,\n * county regionId prefixed by its parent, no duplicate data sources keyed by\n * `(dataType, url)`.\n */\nexport function validateRegionConfig(file: RegionPluginFile): string[] {\n // Cross-field invariants run first so their human-friendlier messages\n // (\"not a valid semver\", \"must be 5 digits for a county\", \"name mismatch\")\n // surface ahead of the corresponding raw Ajv pattern errors. Order of the\n // groups here IS the order issues are reported in.\n return [\n ...validateVersionAndIds(file),\n ...validateFipsCode(file),\n ...validateDataSourceUniqueness(file),\n ...validateAgainstSchema(file),\n ];\n}\n\n// version semver + name/regionId agreement + kebab-case + county prefix.\nfunction validateVersionAndIds(file: RegionPluginFile): string[] {\n const issues: string[] = [];\n const { config } = file;\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(file.version)) {\n issues.push(`version \"${file.version}\" is not a valid semver (expected MAJOR.MINOR.PATCH)`);\n }\n if (file.name !== config.regionId) {\n issues.push(`name \"${file.name}\" must equal config.regionId \"${config.regionId}\"`);\n }\n if (!isValidSlug(config.regionId)) {\n issues.push(`regionId \"${config.regionId}\" must be kebab-case`);\n }\n if (\n config.parentRegionId !== undefined &&\n !config.regionId.startsWith(`${config.parentRegionId}-`)\n ) {\n issues.push(\n `county regionId \"${config.regionId}\" should be prefixed with its parent \"${config.parentRegionId}-\"`,\n );\n }\n return issues;\n}\n\n// The JSON schema only checks the FIPS shape (2–7 digits). Per-level lengths\n// (\"2 for state, 5 for county\") are a cross-field rule the regions repo\n// enforces in custom test code — re-checked here.\nfunction validateFipsCode(file: RegionPluginFile): string[] {\n const { config } = file;\n if (config.fipsCode === undefined) return [];\n const isCounty = config.parentRegionId !== undefined;\n const expected = isCounty ? 5 : 2;\n if (!/^\\d+$/.test(config.fipsCode) || config.fipsCode.length !== expected) {\n return [\n `fipsCode \"${config.fipsCode}\" must be ${expected} digits for a ${isCounty ? 'county' : 'state'}`,\n ];\n }\n return [];\n}\n\n// dataSources is required by the schema — if it's missing the schema layer\n// below will flag that, so we just skip the duplicate scan here rather than\n// throwing on a malformed-but-not-yet-validated file.\nfunction validateDataSourceUniqueness(file: RegionPluginFile): string[] {\n const { config } = file;\n if (!Array.isArray(config.dataSources)) return [];\n const issues: string[] = [];\n const seen = new Set<string>();\n for (const src of config.dataSources) {\n const key = `${src.dataType} ${src.url}`;\n if (seen.has(key)) {\n issues.push(`duplicate data source: ${src.dataType} ${src.url}`);\n }\n seen.add(key);\n }\n return issues;\n}\n\n// Layer the schema on last — catches anything the friendly checks didn't\n// pre-empt (missing required fields, wrong types, unknown extras, etc.).\nfunction validateAgainstSchema(file: RegionPluginFile): string[] {\n const result = schemaValidator.validate(file);\n if (result.valid) return [];\n return result.errors.map((err) => `schema: ${err.instanceLocation || '<root>'} ${err.error}`);\n}\n","import { mkdir, writeFile, access } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport {\n DATA_TYPES,\n SOURCE_TYPES,\n buildRegionConfig,\n isValidFips,\n isValidSlug,\n isValidStateCode,\n isValidTimezone,\n regionFilePath,\n slugify,\n validateRegionConfig,\n type DataSourceInput,\n type DataType,\n type RegionInput,\n type RegionLevel,\n type RegionPluginFile,\n type SourceType,\n} from '../lib/region.js';\nimport { unwrap } from '../lib/prompts.js';\n\ninterface RegionOptions {\n level?: string;\n name?: string;\n parent?: string;\n stateCode?: string;\n fips?: string;\n timezone?: string;\n outDir?: string;\n force?: boolean;\n}\n\nexport const regionCommand = new Command('region')\n .description(\n 'Scaffold a schema-valid region config for the OpusPopuli/opuspopuli-regions repo. ' +\n 'Run this from inside your checkout of that repo.',\n )\n .addOption(\n new Option('--level <level>', 'Region level').choices(['state', 'county']),\n )\n .addOption(new Option('--name <name>', 'Region name (e.g. \"California\" or \"Alameda\")'))\n .addOption(\n new Option('--parent <slug>', 'Parent state slug for a county (e.g. california)'),\n )\n .addOption(new Option('--state-code <code>', 'Two-letter US state code (e.g. CA)'))\n .addOption(new Option('--fips <code>', 'FIPS code (2 digits state, 5 digits county)'))\n .addOption(new Option('--timezone <tz>', 'IANA timezone (e.g. America/Los_Angeles)'))\n .addOption(\n new Option('--out-dir <dir>', 'Repo root to write under').default(\n process.cwd(),\n 'current directory',\n ),\n )\n .addOption(new Option('-f, --force', 'Overwrite an existing config file').default(false))\n .action(async (opts: RegionOptions) => {\n p.intro(pc.bgMagenta(pc.black(' create-op-node region ')));\n printRegionWelcome();\n\n const targetDir = await resolveTargetDir(opts);\n const level = await resolveLevel(opts);\n const identity = await collectIdentity(opts, level);\n const codes = await collectCodes(opts, level);\n const dataSources = await collectDataSources();\n\n const input = buildRegionInput({ level, identity, codes, dataSources });\n const file = buildAndValidateConfig(input);\n await writeRegionConfig({ opts, targetDir, level, identity, file });\n });\n\n// ----------------------------------------------------------------------------\n// Region wizard steps\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: prompts, validation, and\n// process.exit calls are relocated verbatim.\n\ninterface RegionIdentity {\n rawName: string;\n parentSlug: string | undefined;\n ownSlug: string;\n regionId: string;\n regionName: string;\n description: string;\n}\n\ninterface RegionCodes {\n stateCode: string;\n fipsCode: string;\n timezone: string;\n}\n\nconst requireNonEmpty = (v: string | undefined): string | undefined =>\n v && v.trim().length > 0 ? undefined : 'Required';\n\nfunction printRegionWelcome(): void {\n p.note(\n [\n 'Scaffolds a declarative region config JSON for opuspopuli-regions —',\n 'the file that defines WHAT civic data a region collects.',\n '',\n pc.dim('Run this from the root of your opuspopuli-regions checkout.'),\n pc.dim('It validates the same invariants the repo’s `pnpm test` enforces,'),\n pc.dim('so the file lands green and you just commit + open a PR.'),\n ].join('\\n'),\n 'Welcome',\n );\n}\n\n// ---- Step 0: sanity-check we're inside an opuspopuli-regions checkout ----\nasync function resolveTargetDir(opts: RegionOptions): Promise<string> {\n const targetDir = opts.outDir ?? process.cwd();\n const looksRight = await looksLikeRegionsRepo(targetDir);\n if (!looksRight) {\n const proceed = unwrap(\n await p.confirm({\n message: `${targetDir} doesn't look like an opuspopuli-regions checkout (no schema/region-plugin.schema.json). Continue anyway?`,\n initialValue: false,\n }),\n );\n if (!proceed) {\n p.cancel('Cancelled — run again from your opuspopuli-regions checkout, or pass --out-dir.');\n process.exit(0);\n }\n }\n return targetDir;\n}\n\n// ---- Step 1: level ----\nasync function resolveLevel(opts: RegionOptions): Promise<RegionLevel> {\n return opts.level === 'state' || opts.level === 'county'\n ? opts.level\n : unwrap(\n await p.select({\n message: 'What level is this region?',\n options: [\n { value: 'state', label: 'State', hint: 'e.g. California' },\n { value: 'county', label: 'County', hint: 'e.g. Alameda, within California' },\n ],\n }),\n );\n}\n\n// Parent state slug — only prompted for counties.\nasync function resolveParentSlug(opts: RegionOptions, level: RegionLevel): Promise<string | undefined> {\n if (level !== 'county') return undefined;\n const parentSlug =\n opts.parent ??\n unwrap(\n await p.text({\n message: 'Parent state slug?',\n placeholder: 'california',\n validate: (v) =>\n isValidSlug(v ?? '') ? undefined : 'kebab-case (lowercase letters, digits, hyphens)',\n }),\n );\n if (!isValidSlug(parentSlug)) {\n p.cancel(`Parent slug \"${parentSlug}\" must be kebab-case.`);\n process.exit(1);\n }\n return parentSlug;\n}\n\n// ---- Step 2: identity (name, slug, parent, display, description) ----\nasync function collectIdentity(opts: RegionOptions, level: RegionLevel): Promise<RegionIdentity> {\n const rawName =\n opts.name ??\n unwrap(\n await p.text({\n message: level === 'county' ? 'County name?' : 'State name?',\n placeholder: level === 'county' ? 'Alameda' : 'California',\n validate: requireNonEmpty,\n }),\n );\n\n const parentSlug = await resolveParentSlug(opts, level);\n\n const ownSlug = slugify(rawName);\n const regionId = level === 'county' ? `${parentSlug}-${ownSlug}` : ownSlug;\n if (!isValidSlug(regionId)) {\n p.cancel(`Derived regionId \"${regionId}\" is not valid kebab-case. Try a simpler name.`);\n process.exit(1);\n }\n\n const displayName = unwrap(\n await p.text({\n message: 'Display name?',\n defaultValue: rawName,\n }),\n );\n const regionName = displayName || rawName;\n\n const description = unwrap(\n await p.text({\n message: 'One-line description of the data coverage?',\n placeholder:\n level === 'county'\n ? `Civic data for ${rawName} County`\n : `Civic data for the state of ${rawName}`,\n validate: requireNonEmpty,\n }),\n );\n\n return { rawName, parentSlug, ownSlug, regionId, regionName, description };\n}\n\n// ---- Step 3: codes (state code, FIPS, timezone) ----\nasync function collectCodes(opts: RegionOptions, level: RegionLevel): Promise<RegionCodes> {\n const stateCode = (\n opts.stateCode ??\n unwrap(\n await p.text({\n message: 'Two-letter state code?',\n placeholder: 'CA',\n validate: (v) =>\n isValidStateCode((v ?? '').toUpperCase()) ? undefined : 'Two letters, e.g. CA',\n }),\n )\n ).toUpperCase();\n if (!isValidStateCode(stateCode)) {\n p.cancel(`State code \"${stateCode}\" must be two letters.`);\n process.exit(1);\n }\n\n const fipsCode =\n opts.fips ??\n unwrap(\n await p.text({\n message: level === 'county' ? 'County FIPS (5 digits)?' : 'State FIPS (2 digits)?',\n placeholder: level === 'county' ? '06001' : '06',\n validate: (v) => {\n if (isValidFips(v ?? '', level)) return undefined;\n const expectedDigits = level === 'county' ? '5' : '2';\n return `Expected ${expectedDigits} digits`;\n },\n }),\n );\n if (!isValidFips(fipsCode, level)) {\n p.cancel(`FIPS \"${fipsCode}\" is the wrong length for a ${level}.`);\n process.exit(1);\n }\n\n const timezone =\n opts.timezone ??\n unwrap(\n await p.text({\n message: 'IANA timezone?',\n defaultValue: 'America/Los_Angeles',\n placeholder: 'America/Los_Angeles',\n validate: (v) =>\n isValidTimezone(v || 'America/Los_Angeles')\n ? undefined\n : 'Not a recognized IANA zone (e.g. America/New_York)',\n }),\n );\n\n return { stateCode, fipsCode, timezone };\n}\n\n// ---- Step 4: at least one data source ----\nasync function collectOneDataSource(index: number): Promise<DataSourceInput> {\n const url = unwrap(\n await p.text({\n message: `Data source #${index} — URL?`,\n placeholder: 'https://example.gov/meetings',\n validate: (v) => (/^https?:\\/\\//.test(v ?? '') ? undefined : 'Must start with http(s)://'),\n }),\n );\n const dataType = unwrap(\n await p.select({\n message: 'Data type?',\n options: DATA_TYPES.map((t) => ({ value: t, label: t })),\n }),\n ) as DataType;\n const sourceType = unwrap(\n await p.select({\n message: 'Source type?',\n initialValue: 'html_scrape' as SourceType,\n options: SOURCE_TYPES.map((t) => ({ value: t, label: t })),\n }),\n ) as SourceType;\n const contentGoal = unwrap(\n await p.text({\n message: 'Content goal (what should the scraper extract)?',\n placeholder: 'Fetch upcoming board meeting agendas and minutes',\n validate: requireNonEmpty,\n }),\n );\n const category = unwrap(\n await p.text({\n message: 'Category label (optional)?',\n placeholder: 'Board of Supervisors',\n }),\n );\n\n const src: DataSourceInput = { url, dataType, sourceType, contentGoal };\n if (category && category.trim().length > 0) src.category = category.trim();\n return src;\n}\n\nasync function collectDataSources(): Promise<DataSourceInput[]> {\n const dataSources: DataSourceInput[] = [];\n do {\n dataSources.push(await collectOneDataSource(dataSources.length + 1));\n const again = unwrap(\n await p.confirm({ message: 'Add another data source?', initialValue: false }),\n );\n if (!again) break;\n // eslint-disable-next-line no-constant-condition\n } while (true);\n return dataSources;\n}\n\n// ---- Step 5: build the RegionInput from the collected answers ----\nexport function buildRegionInput(args: {\n level: RegionLevel;\n identity: RegionIdentity;\n codes: RegionCodes;\n dataSources: DataSourceInput[];\n}): RegionInput {\n const { level, identity, codes, dataSources } = args;\n return {\n level,\n regionId: identity.regionId,\n displayName: identity.regionName,\n regionName: identity.regionName,\n description: identity.description,\n // New region configs start at 0.1.0 — the documented convention in the\n // regions repo's CLAUDE.md. Bump manually as the config matures.\n version: '0.1.0',\n timezone: codes.timezone,\n stateCode: codes.stateCode,\n fipsCode: codes.fipsCode,\n dataSources,\n ...(identity.parentSlug ? { parentRegionId: identity.parentSlug } : {}),\n ...(level === 'county' ? { countySlug: identity.ownSlug } : {}),\n };\n}\n\n// Build + validate the config; exits if the generated file would fail CI.\nfunction buildAndValidateConfig(input: RegionInput): RegionPluginFile {\n const file = buildRegionConfig(input);\n const issues = validateRegionConfig(file);\n if (issues.length > 0) {\n p.note(issues.map((i) => `${pc.red('•')} ${i}`).join('\\n'), 'Validation failed');\n p.cancel('The generated config would not pass the regions repo CI. Re-run and adjust.');\n process.exit(1);\n }\n return file;\n}\n\n// ---- Step 6: preview + write ----\nasync function writeRegionConfig(args: {\n opts: RegionOptions;\n targetDir: string;\n level: RegionLevel;\n identity: RegionIdentity;\n file: RegionPluginFile;\n}): Promise<void> {\n const { opts, targetDir, level, identity, file } = args;\n const relPath = regionFilePath({\n level,\n regionId: identity.regionId,\n ...(identity.parentSlug ? { parentRegionId: identity.parentSlug } : {}),\n ...(level === 'county' ? { countySlug: identity.ownSlug } : {}),\n });\n const absPath = resolve(targetDir, relPath);\n const json = `${JSON.stringify(file, null, 2)}\\n`;\n\n p.note(json, `${relPath} (preview)`);\n\n if (!opts.force && (await fileExists(absPath))) {\n p.cancel(`${relPath} already exists. Re-run with --force to overwrite.`);\n process.exit(1);\n }\n\n const write = unwrap(\n await p.confirm({ message: `Write ${relPath}?`, initialValue: true }),\n );\n if (!write) {\n p.cancel('Nothing written.');\n process.exit(0);\n }\n\n await mkdir(dirname(absPath), { recursive: true });\n await writeFile(absPath, json, 'utf8');\n\n p.note(\n [\n `${pc.green('✓')} Wrote ${pc.cyan(relPath)}`,\n '',\n 'Next steps in your opuspopuli-regions checkout:',\n pc.dim(' pnpm test # schema + hierarchy validation'),\n pc.dim(' pnpm test:connectivity # URL reachability (informational)'),\n pc.dim(` git add ${relPath} && git commit && open a PR`),\n ].join('\\n'),\n 'Done',\n );\n p.outro(pc.magenta(`Region scaffolded: ${identity.regionId}`));\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Heuristic: the regions repo always has `schema/region-plugin.schema.json`\n * and a top-level `regions/` directory. If both are present we're confident\n * we're in the right checkout; if neither we warn before writing anywhere. */\nasync function looksLikeRegionsRepo(dir: string): Promise<boolean> {\n const [hasSchema, hasRegions] = await Promise.all([\n fileExists(join(dir, 'schema', 'region-plugin.schema.json')),\n fileExists(join(dir, 'regions')),\n ]);\n return hasSchema && hasRegions;\n}\n","/**\n * argv helpers for the CLI entrypoint. Kept in their own module (not `cli.ts`)\n * so they're unit-testable without triggering `cli.ts`'s top-level\n * `program.parseAsync` side effect on import.\n */\n\n/** Program-level flags Commander handles itself — never route these to a\n * subcommand. */\nconst GLOBAL_FLAGS = new Set(['-v', '--version', '-h', '--help']);\n\n/**\n * Inject the default `init` subcommand when the caller didn't name one, so the\n * create-* convention holds: `npx create-op-node` AND `npx create-op-node\n * --region us-ca` both \"just work\" instead of erroring on an unknown program\n * option. (#36 — previously only the zero-arg case was handled.)\n *\n * `argv` is the full `process.argv` (`[node, script, ...rest]`). Returns a new\n * array — the input is not mutated. `init` is inserted before the first user\n * arg UNLESS that arg is already a known subcommand or a global flag\n * (`-v`/`--version`/`-h`/`--help`).\n */\nexport function withDefaultSubcommand(argv: string[], known: readonly string[]): string[] {\n const first = argv[2];\n if (first !== undefined && (known.includes(first) || GLOBAL_FLAGS.has(first))) {\n return argv;\n }\n return [...argv.slice(0, 2), 'init', ...argv.slice(2)];\n}\n","import { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { initCommand } from './commands/init.js';\nimport { bootstrapCommand } from './commands/bootstrap.js';\nimport { resetCommand } from './commands/reset.js';\nimport { verifyCommand } from './commands/verify.js';\nimport { regionCommand } from './commands/region.js';\nimport { withDefaultSubcommand } from './lib/cli-args.js';\n\n// release-please updates the string in `const VERSION = '...'` on each\n// release. See release-please-config.json's extra-files entry that points\n// at this file with type: generic — that scanner finds the version string\n// in package.json (via the manifest file) and updates literals on lines\n// like the one below.\n// x-release-please-start-version\nconst VERSION = '0.15.0';\n// x-release-please-end\n\nconst program = new Command();\n\nprogram\n .name('create-op-node')\n .description(\n 'Interactive bootstrap for an Opus Populi federation node.\\n' +\n 'Cloudflare infrastructure → Mac Studio → live public API.',\n )\n .version(VERSION, '-v, --version', 'show version');\n\nprogram.addCommand(initCommand);\nprogram.addCommand(bootstrapCommand);\nprogram.addCommand(resetCommand);\nprogram.addCommand(verifyCommand);\nprogram.addCommand(regionCommand);\n\n// Default to `init` — the create-* convention is that `npx create-op-node`\n// (and `npx create-op-node --region us-ca`) \"just work\" without naming a\n// subcommand. Only skip when the first arg is already a known subcommand or a\n// global flag. Known names are derived from the registered commands so the\n// list can't drift.\nprocess.argv = withDefaultSubcommand(\n process.argv,\n program.commands.map((c) => c.name()),\n);\n\nawait program.parseAsync(process.argv).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`\\n${pc.red('✗')} ${msg}\\n`);\n process.exit(1);\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/constants.ts","../src/lib/cloudflare.ts","../src/lib/tfc.ts","../src/lib/exec.ts","../src/lib/keychain.ts","../src/lib/prompts.ts","../src/lib/github.ts","../src/lib/secrets.ts","../src/lib/polling.ts","../src/commands/init.ts","../src/lib/homebrew.ts","../src/lib/macos.ts","../src/lib/launchagent.ts","../src/lib/op-compose-script.ts","../src/lib/op-compose-install.ts","../src/lib/docker.ts","../src/lib/cosign.ts","../src/lib/ollama.ts","../src/lib/env-file.ts","../src/lib/noderepo.ts","../src/lib/assert.ts","../src/commands/bootstrap.ts","../src/commands/reset.ts","../src/lib/http.ts","../src/lib/tls.ts","../src/commands/verify.ts","../src/lib/region-schema.json","../src/lib/region.ts","../src/commands/region.ts","../src/lib/cli-args.ts","../src/cli.ts"],"names":["result","password","p","p2","pc","fresh","v","mkdir","writeFile","chmod","text","join","dirname","rename","access","homedir","Command","Option","resolveRegion","rm","save","REGION_RE","fileExists","p4","readFile","connect","resolve","DEFAULT_DEPS","tls","p5","phaseIcon","p6","first"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Shared invariants reused across libs + commands. Each constant has exactly\n * one definition so a format change can't drift between callers (which\n * happened during review: the pgsodium-key shape was hand-rolled in three\n * places).\n */\n\n/** A pgsodium master key is 32 bytes of CSPRNG output, encoded as 64\n * lowercase hex characters. Match it everywhere with this regex so an\n * uppercase-hex or wrong-length value gets a consistent reason. */\nexport const PGSODIUM_KEY_RE = /^[a-f0-9]{64}$/;\n\n/** Allowed character set for a Cloudflare Tunnel token before we\n * interpolate it into a launchd plist string. JWT-style tokens\n * (header.payload.signature) use base64-url — letters, digits, `-`,\n * `_`, `.`, `=`. We deliberately reject anything outside that set so\n * a crafted token can't inject XML attributes or break the plist\n * string content.\n *\n * Stricter than SAFE_LAUNCHCTL_VALUE_RE on purpose: Cloudflare Tunnel\n * tokens are guaranteed base64url by the issuer, so allowing `+` or `/`\n * here would silently accept malformed tokens that would later fail at\n * cloudflared startup with a less actionable error. Kept separate from\n * SAFE_LAUNCHCTL_VALUE_RE for that reason. */\nexport const TUNNEL_TOKEN_RE = /^[A-Za-z0-9_\\-.=]+$/;\n\n/** Operator-friendly path safety check used before interpolating a path\n * into a launchd `sh -c` command. Any shell metacharacter would let an\n * attacker-supplied path execute arbitrary code at every login. The set\n * permits everything macOS allows in a normal path (letters, digits,\n * `/`, `-`, `_`, `.`, space) — and rejects `;`, `$`, backticks, quotes,\n * newlines, etc. */\nexport const SAFE_PATH_RE = /^[A-Za-z0-9_\\-./ ]+$/;\n\n/** Character set allowed for any value we interpolate into the launchd\n * `sh -c` body as a `launchctl setenv VAR \"<value>\"` argument. Permits\n * every character that base64 (`+`, `/`, `=`), base64url (`-`, `_`), and\n * JWT (`.`) produce, plus alphanumerics — covers JWT_SECRET and the signed\n * Supabase tokens (which use JWT shape `xxx.yyy.zzz`). Rejects shell\n * metacharacters (`;`, `$`, backticks, quotes, spaces, newlines) that\n * would let a tampered value inject commands into the login session.\n *\n * POSTGRES_PASSWORD and DASHBOARD_PASSWORD use the stricter\n * URL_SAFE_PASSWORD_RE — they land in postgres:// URIs where `+`/`/`/`=`\n * cause parser ambiguity. */\nexport const SAFE_LAUNCHCTL_VALUE_RE = /^[A-Za-z0-9+/=._-]+$/;\n\n/** Subset of SAFE_LAUNCHCTL_VALUE_RE for values that ALSO land in URI\n * components (postgres:// connection strings, basic-auth headers).\n * base64url alphabet — no `+`, no `/`, no `=`. */\nexport const URL_SAFE_PASSWORD_RE = /^[A-Za-z0-9_-]+$/;\n\n/** Same shape as TUNNEL_TOKEN_RE but documented separately because the\n * SUPABASE_URL value also lands in the plist and we want to allow `://`\n * and `:` for the port. Letters, digits, `-`, `_`, `.`, `:`, `/`. */\nexport const SAFE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;\n\n/** The well-known placeholder the opuspopuli-node template ships as the\n * compose-level default for `GATEWAY_HMAC_SECRET` (and, JSON-wrapped, for\n * `API_KEYS`). Every checkout of the template carries this identical string,\n * so it MUST never be the live value on a node exposed via the Cloudflare\n * Tunnel (`public` profile). bootstrap generates a real per-node value and\n * refuses to activate the public profile if this default is still in force.\n *\n * Kept as a single constant so the generator, the guard, and the tests all\n * compare against the exact same literal. */\nexport const WELL_KNOWN_GATEWAY_HMAC_SECRET =\n // eslint-disable-next-line sonarjs/hardcoded-secret-signatures, sonarjs/no-hardcoded-passwords -- this is the PUBLIC well-known template default we are guarding AGAINST, not a live credential\n 'local-only-hmac-secret-rotate-before-tunnel-exposure';\n\n/** Default network timeout used by `verify`'s probes (TLS handshake, HTTP\n * GET /health, GraphQL POST). One number so tls.ts and http.ts don't drift. */\nexport const VERIFY_NETWORK_TIMEOUT_MS = 10_000;\n\n/** Per-request timeout for the Terraform Cloud + Cloudflare API helpers\n * (`tfc.ts`, `cloudflare.ts`). Deliberately separate from the `verify`\n * probe timeout: these are control-plane API calls, and the overall\n * apply-wait budget is governed by `polling.ts`, so each individual\n * request just needs a sane cap to fail fast on a stalled connection\n * instead of hanging `init` indefinitely. */\nexport const API_REQUEST_TIMEOUT_MS = 15_000;\n\n/** First N chars of a probe response body that get echoed back to the\n * operator for diagnostics. Capped low because the wizard renders this\n * inline; for the real body, use `curl -v` and friends. */\nexport const BODY_PREVIEW_MAX = 200;\n","/**\n * Cloudflare API helpers used by `create-op-node init`.\n *\n * The probe replicates what we built interactively on 2026-06-16: hit each of\n * the 5 endpoints we need so we know the token has every scope before going any\n * further. Failing early here saves a ~60-second Terraform plan that would fail\n * with a less useful error.\n *\n * Account-owned tokens (`cfat_…`) cannot use `/user/tokens/verify`. We hit\n * `/accounts/{id}/tokens/verify` for validity and the 5 resource endpoints for\n * scope coverage.\n */\n\nimport { API_REQUEST_TIMEOUT_MS } from './constants.js';\n\nconst CF_API = 'https://api.cloudflare.com/client/v4';\n\ninterface ProbeInput {\n token: string;\n accountId: string;\n zoneId: string;\n}\n\nexport interface ProbeResult {\n ok: boolean;\n issues: string[];\n}\n\n/**\n * GET a Cloudflare API path as JSON, with a hard per-request timeout.\n *\n * Native `fetch` has no default timeout, so a stalled connection would hang\n * `init` indefinitely (`probeCloudflareToken` makes 6 sequential calls). We\n * wrap the call in an `AbortController` and, on any throw (timeout / DNS blip\n * / TLS reset / proxy error), return `{ status: 0, body: null }`. Callers\n * treat a non-200 status as a soft failure, so a `0` degrades to a\n * network-error message instead of rejecting out of the wizard.\n */\nasync function get(\n token: string,\n path: string,\n fetchImpl: typeof fetch = fetch,\n): Promise<{ status: number; body: unknown }> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);\n try {\n const res = await fetchImpl(`${CF_API}${path}`, {\n headers: { Authorization: `Bearer ${token}` },\n signal: ctrl.signal,\n });\n let body: unknown = null;\n try {\n body = await res.json();\n } catch {\n /* non-JSON body — leave as null */\n }\n return { status: res.status, body };\n } catch {\n // Timeout (AbortError) or any network-layer throw. status 0 = \"never got\n // a response\" — see the docstring above.\n return { status: 0, body: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction shortError(body: unknown): string {\n if (\n typeof body === 'object' &&\n body !== null &&\n 'errors' in body &&\n Array.isArray((body as { errors: unknown[] }).errors)\n ) {\n const errs = (body as { errors: Array<{ message?: string; code?: number }> }).errors;\n return errs\n .map((e) => {\n const prefix = e.code ? `CF ${e.code}: ` : '';\n return `${prefix}${e.message ?? 'unknown'}`;\n })\n .join('; ');\n }\n return 'no error message returned';\n}\n\ninterface ScopeCheck {\n name: string;\n path: string;\n /** Endpoints that 404 when the underlying feature isn't enabled but the scope\n * IS present (e.g. R2 before \"Enable R2\"). We treat those as passes with a\n * note rather than failures. */\n treat404AsPass?: boolean;\n}\n\nexport async function probeCloudflareToken(input: ProbeInput): Promise<ProbeResult> {\n const issues: string[] = [];\n\n // ---- Validity probe (Account-owned token endpoint) ----\n const verify = await get(input.token, `/accounts/${input.accountId}/tokens/verify`);\n if (verify.status === 0) {\n issues.push(\n \"Couldn't reach Cloudflare (network error or timeout). Check your connection and retry.\",\n );\n return { ok: false, issues };\n }\n if (verify.status !== 200) {\n issues.push(\n `Token verify failed (HTTP ${verify.status}): ${shortError(verify.body)}`,\n );\n return { ok: false, issues };\n }\n\n // ---- Scope probes ----\n const checks: ScopeCheck[] = [\n { name: 'Zone : Zone : Read', path: `/zones/${input.zoneId}` },\n { name: 'Zone : DNS : Edit', path: `/zones/${input.zoneId}/dns_records?per_page=1` },\n { name: 'Account : Cloudflare Tunnel : Edit', path: `/accounts/${input.accountId}/cfd_tunnel` },\n { name: 'Account : Workers R2 Storage : Edit', path: `/accounts/${input.accountId}/r2/buckets` },\n { name: 'Account : Cloudflare Pages : Edit', path: `/accounts/${input.accountId}/pages/projects` },\n ];\n\n for (const check of checks) {\n const res = await get(input.token, check.path);\n if (res.status === 200) continue;\n if (res.status === 404 && check.treat404AsPass) continue;\n if (res.status === 0) {\n issues.push(`Couldn't reach Cloudflare while checking ${check.name} (network error or timeout).`);\n } else if (res.status === 401 || res.status === 403) {\n issues.push(`Missing scope: ${check.name}`);\n } else if (\n res.status === 400 &&\n typeof res.body === 'object' &&\n res.body !== null &&\n 'errors' in res.body &&\n Array.isArray((res.body as { errors: Array<{ code?: number }> }).errors) &&\n (res.body as { errors: Array<{ code?: number }> }).errors.some((e) => e.code === 10042)\n ) {\n // R2 not enabled yet — actionable, not a scope problem.\n issues.push(\n `R2 not enabled on this account. ` +\n `Enable it once in Cloudflare dashboard → R2 → Get started, then re-run.`,\n );\n } else {\n issues.push(`${check.name} probe returned HTTP ${res.status}: ${shortError(res.body)}`);\n }\n }\n\n return { ok: issues.length === 0, issues };\n}\n\n/* ------------------------------------------------------------------ *\n * Tunnel-status probe (used by `verify`, not `init`) *\n * ------------------------------------------------------------------ */\n\nexport interface TunnelStatusInput {\n token: string;\n accountId: string;\n tunnelId: string;\n /** Injectable for tests. */\n fetchImpl?: typeof fetch;\n}\n\nexport interface TunnelStatusOk {\n ok: true;\n /** Active connector connections registered with Cloudflare's edge. Zero on\n * a freshly-created tunnel that hasn't been started, > 0 on a healthy one. */\n connections: number;\n /** Cloudflare's own status field — `healthy`, `degraded`, `inactive`, etc. */\n status: string;\n}\n\nexport interface TunnelStatusFailed {\n ok: false;\n reason: string;\n}\n\nexport type TunnelStatusResult = TunnelStatusOk | TunnelStatusFailed;\n\ninterface CfTunnelEnvelope {\n result?: {\n status?: string;\n connections?: Array<unknown>;\n };\n}\n\n/**\n * Look up a single tunnel's current edge-side status. The CF API endpoint\n * returns `connections: []` until at least one cloudflared connector\n * registers — useful as a verify signal that the Studio's cloudflared is\n * actually online.\n */\nexport async function tunnelStatus(input: TunnelStatusInput): Promise<TunnelStatusResult> {\n const fetchImpl = input.fetchImpl ?? fetch;\n try {\n const res = await get(\n input.token,\n `/accounts/${input.accountId}/cfd_tunnel/${input.tunnelId}`,\n fetchImpl,\n );\n if (res.status === 0) {\n return { ok: false, reason: \"couldn't reach Cloudflare (network error or timeout)\" };\n }\n if (res.status !== 200) {\n return {\n ok: false,\n reason: `tunnel lookup failed (HTTP ${res.status}): ${shortError(res.body)}`,\n };\n }\n const env = res.body as CfTunnelEnvelope;\n const status = env.result?.status ?? '<no status>';\n const connections = env.result?.connections?.length ?? 0;\n return { ok: true, connections, status };\n } catch (err) {\n return { ok: false, reason: `tunnel lookup threw: ${(err as Error).message}` };\n }\n}\n","/**\n * Terraform Cloud (HCP Terraform) API helpers used by `create-op-node init`.\n *\n * We hit a tiny subset of the TFC v2 API directly via native `fetch` — no\n * client library. Three needs:\n *\n * 1. Verify the operator's TFC token is valid and has access to the org\n * they typed.\n * 2. Resolve a workspace by tag set so we can poll its state for outputs.\n * 3. Fetch the Tunnel token output after `terraform apply` completes.\n *\n * The TFC API responds with JSON:API-shaped documents; helpers below narrow\n * each call to the minimal shape we actually consume.\n */\n\nimport { API_REQUEST_TIMEOUT_MS } from './constants.js';\n\nconst TFC_API = 'https://app.terraform.io/api/v2';\n\n/** TFC organization slug rules: alphanumerics, underscores, hyphens; the API\n * doesn't formally publish a max but slugs over 40 chars are rejected in\n * practice. We validate before any URL interpolation to neutralise typos\n * that would otherwise hit unintended endpoints (e.g. `?` or `/` in the\n * slug bouncing us into a different route). */\nconst ORG_SLUG_RE = /^[A-Za-z0-9_-]{1,40}$/;\n\nexport function isValidTfcOrgSlug(slug: string): boolean {\n return ORG_SLUG_RE.test(slug);\n}\n\ninterface TfcAuth {\n token: string;\n organization: string;\n}\n\ntype Headers = Record<string, string>;\n\nfunction authHeaders(token: string): Headers {\n return {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/vnd.api+json',\n };\n}\n\n/**\n * GET a TFC API path as JSON, with a hard per-request timeout.\n *\n * A stalled or half-open connection (native `fetch` has no default timeout)\n * would otherwise hang `init` — including the ~10-minute apply-wait in\n * `polling.ts` — forever. We wrap the call in an `AbortController` and, on\n * any throw (timeout / DNS blip / TLS reset / proxy error), return\n * `{ status: 0, body: null }`. Every caller already treats a non-200 status\n * as a soft failure, so a `0` degrades to `null` / a network-error message\n * instead of rejecting out of the poll loop and crashing the wizard.\n */\nasync function getJson(\n token: string,\n path: string,\n): Promise<{ status: number; body: unknown }> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), API_REQUEST_TIMEOUT_MS);\n try {\n const res = await fetch(`${TFC_API}${path}`, {\n headers: authHeaders(token),\n signal: ctrl.signal,\n });\n let body: unknown = null;\n try {\n body = await res.json();\n } catch {\n /* non-JSON body — leave as null */\n }\n return { status: res.status, body };\n } catch {\n // Timeout (AbortError) or any network-layer throw. status 0 = \"never got\n // a response\" — see the docstring above.\n return { status: 0, body: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport interface TfcProbeResult {\n ok: boolean;\n /** TFC user's display name when the token belongs to a user (`null` when it's a team / org token). */\n userName?: string;\n issues: string[];\n}\n\n/**\n * Sanity-check the token + organization at the same time:\n *\n * - GET /account/details — confirms the token itself is valid.\n * - GET /organizations/{org} — confirms the org exists AND that the token\n * has the membership/permissions to see it.\n *\n * Both must pass before we let the wizard proceed; a token that's valid but\n * scoped to a different org would silently fail at the workspace step.\n */\nexport async function probeTfcToken(input: TfcAuth): Promise<TfcProbeResult> {\n const issues: string[] = [];\n\n if (!isValidTfcOrgSlug(input.organization)) {\n issues.push(\n `Organization \"${input.organization}\" isn't a valid TFC slug (letters, digits, hyphens, underscores; up to 40 chars).`,\n );\n return { ok: false, issues };\n }\n\n const account = await getJson(input.token, '/account/details');\n if (account.status === 0) {\n issues.push(\n \"Couldn't reach Terraform Cloud (network error or timeout). Check your connection and retry.\",\n );\n return { ok: false, issues };\n }\n if (account.status !== 200) {\n issues.push(\n `TFC token invalid (HTTP ${account.status}). Regenerate at https://app.terraform.io/app/settings/tokens.`,\n );\n return { ok: false, issues };\n }\n const userName = extractUserName(account.body);\n\n const org = await getJson(\n input.token,\n `/organizations/${encodeURIComponent(input.organization)}`,\n );\n if (org.status === 0) {\n issues.push(\n \"Couldn't reach Terraform Cloud while checking the organization (network error or timeout).\",\n );\n } else if (org.status === 404) {\n issues.push(\n `TFC organization \"${input.organization}\" not found, or this token lacks access. Check the org slug at https://app.terraform.io.`,\n );\n } else if (org.status === 401 || org.status === 403) {\n issues.push(\n `TFC token doesn't have permission to access org \"${input.organization}\".`,\n );\n } else if (org.status !== 200) {\n issues.push(`TFC org probe returned HTTP ${org.status}.`);\n }\n\n return {\n ok: issues.length === 0,\n issues,\n ...(userName ? { userName } : {}),\n };\n}\n\nfunction extractUserName(body: unknown): string | undefined {\n if (\n typeof body === 'object' &&\n body !== null &&\n 'data' in body &&\n typeof (body as { data: unknown }).data === 'object'\n ) {\n const data = (body as { data: { attributes?: { username?: string } } }).data;\n return data.attributes?.username;\n }\n return undefined;\n}\n\nexport interface FindWorkspaceInput extends TfcAuth {\n /** Tag set the workspace must carry. For our use case: `['opuspopuli', 'cloudflare']`. */\n tags: string[];\n /** Optional name to disambiguate when multiple workspaces share the tag set. */\n name?: string;\n}\n\nexport interface TfcWorkspace {\n id: string;\n name: string;\n /** Latest run id, used to poll for apply completion. */\n currentRunId: string | null;\n}\n\n/**\n * Find the workspace this region's Terraform code will run in.\n *\n * TFC's filter syntax for tags is `filter[tagged]=tag1,tag2`. We ask for all\n * matches and let the caller pick by `name` when there's ambiguity (one TFC\n * org can host many workspaces with the same tag set).\n */\nexport async function findWorkspace(input: FindWorkspaceInput): Promise<TfcWorkspace | null> {\n if (!isValidTfcOrgSlug(input.organization)) return null;\n const tagFilter = encodeURIComponent(input.tags.join(','));\n const res = await getJson(\n input.token,\n `/organizations/${encodeURIComponent(input.organization)}/workspaces?filter[tagged]=${tagFilter}&page[size]=100`,\n );\n if (res.status !== 200) return null;\n\n const items = extractWorkspaceList(res.body);\n if (items.length === 0) return null;\n\n const match = input.name ? items.find((w) => w.name === input.name) : items[0];\n return match ?? null;\n}\n\ninterface RawWorkspace {\n id: string;\n attributes?: { name?: string };\n relationships?: { 'current-run'?: { data?: { id?: string } | null } };\n}\n\nfunction extractWorkspaceList(body: unknown): TfcWorkspace[] {\n if (\n typeof body !== 'object' ||\n body === null ||\n !('data' in body) ||\n !Array.isArray((body as { data: unknown }).data)\n ) {\n return [];\n }\n const data = (body as { data: RawWorkspace[] }).data;\n return data.map((w) => ({\n id: w.id,\n name: w.attributes?.name ?? '',\n currentRunId: w.relationships?.['current-run']?.data?.id ?? null,\n }));\n}\n\nexport interface TfcRunStatus {\n id: string;\n status: string;\n /** `true` once the run reached a terminal state (applied / errored / canceled / discarded). */\n finished: boolean;\n /** `true` only when the run finished successfully (`applied`). */\n succeeded: boolean;\n}\n\nconst TERMINAL_STATUSES = new Set([\n 'applied',\n 'errored',\n 'canceled',\n 'discarded',\n 'policy_soft_failed',\n 'force_canceled',\n]);\n\n/**\n * Look up a single TFC run by id. Used while we're waiting for the first\n * `terraform apply` to finish.\n */\nexport async function getRunStatus(\n auth: TfcAuth,\n runId: string,\n): Promise<TfcRunStatus | null> {\n // runId comes from a previous TFC response — trusted shape — but\n // encodeURIComponent is cheap defense if it's ever sourced from elsewhere.\n const res = await getJson(auth.token, `/runs/${encodeURIComponent(runId)}`);\n if (res.status !== 200) return null;\n\n const body = res.body as {\n data?: { id?: string; attributes?: { status?: string } };\n };\n const id = body.data?.id;\n const status = body.data?.attributes?.status;\n if (!id || !status) return null;\n\n return {\n id,\n status,\n finished: TERMINAL_STATUSES.has(status),\n succeeded: status === 'applied',\n };\n}\n\n/**\n * Discriminated result of pulling a named output. The three cases must stay\n * distinct so the poll loop can tell a recoverable transient apart from a\n * genuine absence (#59):\n *\n * - `value` — the output is present and usable.\n * - `absent` — the request succeeded (HTTP 200) but the named output isn't\n * in the state, or its value isn't a string (e.g. the operator\n * changed the type). Permanent — retrying won't help.\n * - `error` — the HTTP call failed (`getJson` degraded a timeout/blip to\n * `status: 0`, or a non-200 such as a 404/425 while the state\n * version is still settling). Retryable.\n */\nexport type OutputResult =\n | { kind: 'value'; value: string }\n | { kind: 'absent' }\n | { kind: 'error' };\n\n/**\n * Pull a named output value from a workspace's current state version.\n *\n * Caller should poll the matching run for `applied` status first; an\n * in-flight workspace returns a 404 / 425 here, which surfaces as `error`\n * (retryable) rather than `absent` — a network blip on the final fetch must\n * not be misreported as a missing output. See {@link OutputResult}.\n */\nexport async function fetchOutput(\n auth: TfcAuth,\n workspaceId: string,\n outputName: string,\n): Promise<OutputResult> {\n const res = await getJson(\n auth.token,\n `/workspaces/${encodeURIComponent(workspaceId)}/current-state-version-outputs`,\n );\n // status 0 (timeout/network) or any non-200: could be transient (the state\n // version may still be settling right after apply), so let the caller retry.\n if (res.status !== 200) return { kind: 'error' };\n\n const body = res.body as {\n data?: Array<{ attributes?: { name?: string; value?: unknown; sensitive?: boolean } }>;\n };\n const match = body.data?.find((o) => o.attributes?.name === outputName);\n if (!match) return { kind: 'absent' };\n\n const value = match.attributes?.value;\n return typeof value === 'string' ? { kind: 'value', value } : { kind: 'absent' };\n}\n","/**\n * Shared `execa` wrapper for the few CLIs the wizard shells out to (`op`, `gh`).\n *\n * Two patterns this exists to share:\n *\n * 1. `reject: false` is opt-out on every call, since we want to inspect the\n * exit code rather than have a thrown error fan out across the wizard.\n * 2. **ENOENT doesn't suppress** under `reject: false` — that's a spawn\n * error, not a child-process exit. Callers that don't catch it crash.\n * `safeExeca` traps `ENOENT` / `ENOTDIR` and returns `null` so callers\n * can branch on \"binary not installed at all\" cleanly.\n *\n * The shape kept narrow on purpose — adds nothing execa doesn't, just makes\n * the failure modes uniform across call sites.\n */\n\nimport { execa, ExecaError } from 'execa';\n\nexport interface SafeExecaResult {\n /** Exit code from the child. `undefined` when the child was killed by a\n * signal — we pass it through honestly so callers can distinguish\n * signal-killed from clean zero. */\n exitCode: number | undefined;\n stdout: string;\n stderr: string;\n}\n\n/**\n * Run a command; return `null` when the binary isn't on PATH at all, an\n * object with exit code + output otherwise. Never throws on a missing\n * binary, never throws on a non-zero exit.\n */\nexport async function safeExeca(\n cmd: string,\n args: string[],\n options?: {\n input?: string;\n /** Working directory for the child. Defaults to the parent's cwd. */\n cwd?: string;\n /** Extra env vars merged into the child's env (execa's default\n * extendEnv: true means these add to process.env rather than\n * replace). Used by bootstrap's compose subprocess calls so the\n * Keychain-loaded secrets reach docker compose without first\n * being written to a plaintext .env file on disk. */\n env?: NodeJS.ProcessEnv;\n },\n): Promise<SafeExecaResult | null> {\n try {\n const result = await execa(cmd, args, { reject: false, ...options });\n return {\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n };\n } catch (err) {\n const e = err as ExecaError & NodeJS.ErrnoException;\n if (e.code === 'ENOENT' || e.code === 'ENOTDIR') return null;\n throw err;\n }\n}\n","/**\n * macOS Keychain wrapper around the built-in `security` CLI.\n *\n * Replaces the 1Password integration as of v0.3.0: secrets live in the\n * operator's login keychain (FileVault-encrypted at rest, locked with\n * the user session). Generic-password items only — we don't need\n * internet-password semantics.\n *\n * **Cross-device caveat:** the `security` CLI cannot create iCloud-\n * Keychain-synchronizable items (no `kSecAttrSynchronizable` flag is\n * exposed). Items written here stay on the machine they were written\n * on. `init` writes on the laptop; `bootstrap` reads on the Studio.\n * On a Studio miss, bootstrap falls back to prompting the operator to\n * paste the value and persists it locally for re-runs.\n *\n * **Argv exposure caveat:** `security add-generic-password -w <value>`\n * passes the secret via argv. It's briefly visible to anyone running\n * `ps -E` while the child is alive. Same risk model as the\n * `op item create notesPlain=<value>` pattern we previously accepted.\n * If a future `security` release adds a stdin form, swap to it here.\n */\n\nimport { safeExeca } from './exec.js';\n\n/** Reverse-DNS prefix for all Opus Populi entries in Keychain Access. */\nconst SERVICE_PREFIX = 'org.opuspopuli';\n\nexport type SecretAccount =\n | 'pgsodium-root-key'\n | 'tunnel-token'\n | 'postgres-password'\n | 'jwt-secret'\n | 'supabase-anon-key'\n | 'supabase-service-role-key'\n | 'dashboard-password'\n | 'prompts-db-password'\n | 'prompt-service-api-key'\n | 'prompt-service-admin-api-key'\n | 'gateway-hmac-secret'\n | 'grafana-admin-password';\n\nexport interface SecretCoordinates {\n /** Region label, used to scope the service identifier. */\n region: string;\n /** Which secret within the region. */\n account: SecretAccount;\n}\n\nfunction serviceFor(region: string): string {\n return `${SERVICE_PREFIX}.${region}`;\n}\n\nconst FRIENDLY: Record<SecretAccount, string> = {\n 'pgsodium-root-key': 'pgsodium root key',\n 'tunnel-token': 'Cloudflare Tunnel token',\n 'postgres-password': 'Postgres password',\n 'jwt-secret': 'JWT signing secret',\n 'supabase-anon-key': 'Supabase anon key',\n 'supabase-service-role-key': 'Supabase service role key',\n 'dashboard-password': 'Supabase Studio dashboard password',\n 'prompts-db-password': 'prompt-service Postgres password',\n 'prompt-service-api-key': 'prompt-service HMAC API key',\n 'prompt-service-admin-api-key': 'prompt-service admin API key',\n 'gateway-hmac-secret': 'API Gateway HMAC secret',\n 'grafana-admin-password': 'Grafana admin password',\n};\n\nfunction labelFor(coords: SecretCoordinates): string {\n return `Opus Populi (${coords.region}) — ${FRIENDLY[coords.account]}`;\n}\n\nexport interface KeychainAvailability {\n /** True when the `security` CLI ran cleanly (macOS or compatible). On\n * non-macOS hosts this is false and callers should fall back to\n * prompt-only flows. */\n available: boolean;\n /** Free-text reason when unavailable. */\n reason?: string;\n}\n\nexport async function detectKeychain(): Promise<KeychainAvailability> {\n const res = await safeExeca('security', ['-h']);\n if (res === null) {\n return {\n available: false,\n reason: '`security` CLI not on PATH (Keychain requires macOS)',\n };\n }\n return { available: true };\n}\n\nexport interface SaveSecretResult {\n written: boolean;\n /** True when an item already existed and was updated (via -U upsert). */\n updated: boolean;\n reason?: string;\n}\n\n/**\n * Write a generic-password item, upserting if it already exists. Uses\n * `add-generic-password -U` so re-runs don't error on duplicates.\n */\nexport async function saveSecret(\n coords: SecretCoordinates,\n value: string,\n): Promise<SaveSecretResult> {\n const service = serviceFor(coords.region);\n const label = labelFor(coords);\n\n // Check whether the item exists ahead of the upsert so we can report\n // `updated: true` vs `written: true` to the caller (purely informational —\n // the operator sees a different message in the wizard).\n const existing = await safeExeca('security', [\n 'find-generic-password',\n '-s',\n service,\n '-a',\n coords.account,\n ]);\n const updated = existing !== null && existing.exitCode === 0;\n\n const res = await safeExeca('security', [\n 'add-generic-password',\n '-U', // upsert\n '-s', service,\n '-a', coords.account,\n '-l', label,\n '-D', 'Opus Populi secret',\n '-w', value, // argv-exposure caveat, see file header\n ]);\n if (res === null) {\n return { written: false, updated: false, reason: '`security` CLI not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n written: false,\n updated,\n reason: `security add-generic-password failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}${formatKeychainHint(res.exitCode)}`,\n };\n }\n return { written: true, updated };\n}\n\n/**\n * Read a generic-password item by service + account. Returns `null` when\n * the item doesn't exist, `security` isn't available, or the value is\n * empty. Callers branch to a paste prompt on `null`.\n */\nexport async function readSecret(coords: SecretCoordinates): Promise<string | null> {\n const service = serviceFor(coords.region);\n\n const res = await safeExeca('security', [\n 'find-generic-password',\n '-s', service,\n '-a', coords.account,\n '-w', // print the password to stdout (final flag = read mode)\n ]);\n if (res === null || res.exitCode !== 0) return null;\n const value = res.stdout.trim();\n return value.length > 0 ? value : null;\n}\n\n/** Delete a generic-password item. Idempotent — missing items return ok. */\nexport async function deleteSecret(coords: SecretCoordinates): Promise<{ ok: boolean; reason?: string }> {\n const service = serviceFor(coords.region);\n\n const res = await safeExeca('security', [\n 'delete-generic-password',\n '-s', service,\n '-a', coords.account,\n ]);\n if (res === null) return { ok: false, reason: '`security` CLI not on PATH' };\n // Exit 44 (errSecItemNotFound) is fine — already gone.\n if (res.exitCode === 0 || res.exitCode === ERR_SEC_ITEM_NOT_FOUND) return { ok: true };\n return {\n ok: false,\n reason: `security delete-generic-password failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}${formatKeychainHint(res.exitCode)}`,\n };\n}\n\n/**\n * macOS `security` exit codes we care about. Defined as constants so callers\n * can reason about them without sprinkling magic numbers.\n * 36 = errSecInteractionNotAllowed — keychain is locked / no UI session\n * 44 = errSecItemNotFound — item doesn't exist (treated as \"ok\" for delete)\n */\nexport const ERR_SEC_INTERACTION_NOT_ALLOWED = 36;\nexport const ERR_SEC_ITEM_NOT_FOUND = 44;\n\n/** Append an operator-friendly remediation hint to a `security` error\n * message when the exit code maps to one we recognize. Returns empty\n * string when no hint applies, so the call site can safely concatenate. */\nfunction formatKeychainHint(exitCode: number | null | undefined): string {\n if (exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED) {\n return (\n `\\n` +\n `Hint: the login keychain is locked (SSH sessions don't auto-unlock it).\\n` +\n `Run \\`security unlock-keychain ~/Library/Keychains/login.keychain-db\\` and re-run bootstrap.`\n );\n }\n return '';\n}\n\n/**\n * Probe whether the login keychain is currently locked. Implemented by\n * attempting a no-op `find-generic-password` against a service that won't\n * exist: exit 44 (errSecItemNotFound) → unlocked, exit 36 → locked.\n *\n * Used by bootstrap to proactively prompt SSH operators for their login\n * password before the first Keychain write — without this, the operator\n * gets nine identical failures (one per secret) before they figure out\n * the keychain is locked.\n */\nexport async function isKeychainLocked(): Promise<boolean> {\n const res = await safeExeca('security', [\n 'find-generic-password',\n '-s',\n `${SERVICE_PREFIX}.__op_node_lock_probe__`,\n '-a',\n '__nothing_here__',\n ]);\n if (res === null) return false; // no security CLI; can't be locked\n return res.exitCode === ERR_SEC_INTERACTION_NOT_ALLOWED;\n}\n\nexport interface UnlockResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Unlock the login keychain via `security unlock-keychain -p <password>`.\n *\n * argv-exposure caveat: the password is visible briefly to `ps -E` while\n * the security child is alive. Same risk model as `saveSecret` writing\n * the secret value via `-w`. The `security` CLI doesn't expose a stdin\n * password form for unlock, so this is the cleanest option available.\n *\n * Callers should prompt the operator via clack's `p.password()` (which\n * doesn't echo) and pass the value here.\n */\nexport async function unlockKeychain(password: string): Promise<UnlockResult> {\n const res = await safeExeca('security', [\n 'unlock-keychain',\n '-p',\n password,\n // Default keychain path — same as the operator's GUI login keychain\n // on a stock macOS install. Lets us avoid a homedir lookup here.\n `${process.env['HOME'] ?? ''}/Library/Keychains/login.keychain-db`,\n ]);\n if (res === null) return { ok: false, reason: '`security` CLI not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `security unlock-keychain failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\n/** Heuristic: are we running inside an SSH session?\n * `SSH_CONNECTION` is set by sshd on every interactive login. `SSH_TTY`\n * is set on TTY-allocated sessions; we check both. Process-env only —\n * no syscalls. */\nexport function isSshSession(env: NodeJS.ProcessEnv = process.env): boolean {\n return Boolean(env['SSH_CONNECTION'] ?? env['SSH_TTY']);\n}\n\n/** Exported for tests + the rare caller that needs the raw service string. */\nexport const _internal = {\n serviceFor,\n labelFor,\n SERVICE_PREFIX,\n};\n","/**\n * Tiny shared helper around @clack/prompts' cancel sentinel.\n *\n * Every wizard subcommand wants the same shape: ask for a value, if the\n * operator hit Ctrl-C / Esc, exit cleanly with a \"Cancelled.\" note. Without\n * this helper each call site duplicates the `p.isCancel` check + `p.cancel`\n * + `process.exit(0)`.\n *\n * Keeping it dead-simple — no return-value transformation, no async, no\n * exit-code override. Subcommands that want a different exit policy\n * shouldn't use this helper.\n */\n\nimport * as p from '@clack/prompts';\n\nexport function unwrap<T>(value: T | symbol): T {\n if (p.isCancel(value)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n return value;\n}\n","/**\n * GitHub helpers used by `create-op-node init`.\n *\n * Every call goes through Octokit (REST) authenticated with the operator's\n * `--gh-token` PAT — a single identity for the whole flow (create-from-\n * template, content write, PR open, and Actions-secret seeding). Secret\n * seeding uses the `actions.getRepoPublicKey` + `createOrUpdateRepoSecret`\n * endpoints, encrypting the value with the repo's libsodium public key\n * (`crypto_box_seal`) before PUT, per GitHub's API contract.\n *\n * The Octokit instance is created lazily so a missing token surfaces as a\n * clear error rather than a cryptic auth failure inside a downstream call.\n */\n\nimport { Octokit } from '@octokit/rest';\nimport _sodium from 'libsodium-wrappers';\n\nexport interface GhAuth {\n /** A GitHub Personal Access Token (Classic or Fine-grained) with at least\n * `repo` scope. */\n token: string;\n}\n\n// One Octokit per token — fine for a one-shot CLI. NOT safe to wire into a\n// long-running service that issues calls under different identities; the\n// memoization will hand out the wrong client. If that ever happens, key the\n// cache by (token, …other-dimensions) or drop the memoization.\nlet _client: Octokit | null = null;\nlet _clientToken: string | null = null;\n\nfunction client(token: string): Octokit {\n if (_client && _clientToken === token) return _client;\n _client = new Octokit({ auth: token });\n _clientToken = token;\n return _client;\n}\n\n// Test-only: reset the memoized client between cases. Not exported via\n// index, intentionally — tests reach into the module.\nexport function _resetClient(): void {\n _client = null;\n _clientToken = null;\n}\n\n// ----------------------------------------------------------------------------\n// Create from template\n// ----------------------------------------------------------------------------\n\nexport interface CreateFromTemplateInput extends GhAuth {\n /** `<owner>/<repo>` of the template repo, e.g. `OpusPopuli/opuspopuli-node`. */\n template: string;\n /** The new repo's owner (user or org). */\n owner: string;\n /** The new repo's name. */\n name: string;\n /** Optional repo description. */\n description?: string;\n /** When true, create the repo as private. Default: false (public). */\n private?: boolean;\n /** Include all template branches, not just default. Default: false. */\n includeAllBranches?: boolean;\n}\n\nexport interface CreatedRepo {\n fullName: string;\n htmlUrl: string;\n defaultBranch: string;\n}\n\n/**\n * Create a new repository from a template repository. Wraps\n * `POST /repos/{template_owner}/{template_repo}/generate`.\n *\n * Caller should handle \"repository already exists\" as a recoverable case —\n * the operator may have started + abandoned a previous run. We throw on the\n * 422 (already exists) so the caller can show a \"use existing? overwrite?\"\n * prompt.\n */\nexport async function createRepoFromTemplate(\n input: CreateFromTemplateInput,\n): Promise<CreatedRepo> {\n const [templateOwner, templateRepo] = input.template.split('/');\n if (!templateOwner || !templateRepo) {\n throw new Error(`Bad template spec \"${input.template}\" — expected <owner>/<repo>`);\n }\n\n const res = await client(input.token).request(\n 'POST /repos/{template_owner}/{template_repo}/generate',\n {\n template_owner: templateOwner,\n template_repo: templateRepo,\n owner: input.owner,\n name: input.name,\n private: input.private ?? false,\n include_all_branches: input.includeAllBranches ?? false,\n ...(input.description ? { description: input.description } : {}),\n },\n );\n\n return {\n fullName: res.data.full_name,\n htmlUrl: res.data.html_url,\n defaultBranch: res.data.default_branch ?? 'main',\n };\n}\n\n/**\n * Look up a repository's default branch. Used when `init` adopts a\n * pre-existing repo (the create-from-template path already gets it from the\n * generate response) so branch/PR operations target the branch that actually\n * exists rather than assuming `main`. Returns `null` on a malformed slug or\n * any API failure, so the caller can fall back deliberately. (#41)\n */\nexport async function getRepoDefaultBranch(input: {\n token: string;\n repo: string;\n}): Promise<string | null> {\n const parsed = parseRepoSlug(input.repo);\n if (!parsed) return null;\n try {\n const res = await client(input.token).repos.get({ owner: parsed.owner, repo: parsed.repo });\n return res.data.default_branch ?? null;\n } catch {\n return null;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Seed repository Actions secrets via the GitHub API (Octokit + libsodium)\n// ----------------------------------------------------------------------------\n\nexport interface SetRepoSecretsInput {\n /** PAT used for the whole `init` flow — needs Actions Secrets: write\n * (fine-grained) or `repo` scope (classic). */\n token: string;\n /** `<owner>/<repo>`. */\n repo: string;\n /** Secrets to seed, in order. Values are encrypted with the repo public key\n * before they leave the process — plaintext never lands in argv or on the\n * wire. */\n secrets: ReadonlyArray<{ name: string; value: string }>;\n}\n\nexport interface SetRepoSecretsResult {\n /** Secret names successfully written, in order. */\n seeded: string[];\n /** Set when a secret failed; seeding stops at the first failure (so `seeded`\n * is the prefix that succeeded and the rest are pending). */\n failed?: { name: string; reason: string };\n}\n\nfunction parseRepoSlug(repo: string): { owner: string; repo: string } | null {\n const slash = repo.indexOf('/');\n if (slash <= 0 || slash === repo.length - 1 || repo.indexOf('/', slash + 1) !== -1) return null;\n return { owner: repo.slice(0, slash), repo: repo.slice(slash + 1) };\n}\n\n/**\n * Seed repository Actions secrets via the GitHub API, authenticated with the\n * operator's PAT (single identity for the whole flow — no `gh` CLI / ambient\n * auth). GitHub requires each value to be sealed-box encrypted with the repo's\n * public key (`crypto_box_seal`); we fetch that key **once** and reuse it for\n * every secret. `createOrUpdateRepoSecret` is idempotent, so a re-run\n * overwrites cleanly. Stops at the first failure and reports what was seeded.\n */\nexport async function setRepoSecrets(input: SetRepoSecretsInput): Promise<SetRepoSecretsResult> {\n const firstName = input.secrets[0]?.name ?? '(none)';\n const parsed = parseRepoSlug(input.repo);\n if (!parsed) {\n return {\n seeded: [],\n failed: { name: firstName, reason: `invalid repo \"${input.repo}\" (expected <owner>/<repo>)` },\n };\n }\n const { owner, repo } = parsed;\n const octokit = client(input.token);\n\n let key: Awaited<ReturnType<typeof octokit.actions.getRepoPublicKey>>;\n try {\n key = await octokit.actions.getRepoPublicKey({ owner, repo });\n } catch (err) {\n return {\n seeded: [],\n failed: { name: firstName, reason: `fetching the repo public key failed: ${(err as Error).message}` },\n };\n }\n\n await _sodium.ready;\n const sodium = _sodium;\n const publicKey = sodium.from_base64(key.data.key, sodium.base64_variants.ORIGINAL);\n\n const seeded: string[] = [];\n for (const s of input.secrets) {\n const encrypted_value = sodium.to_base64(\n sodium.crypto_box_seal(sodium.from_string(s.value), publicKey),\n sodium.base64_variants.ORIGINAL,\n );\n try {\n await octokit.actions.createOrUpdateRepoSecret({\n owner,\n repo,\n secret_name: s.name,\n encrypted_value,\n key_id: key.data.key_id,\n });\n } catch (err) {\n return { seeded, failed: { name: s.name, reason: `setting secret ${s.name} failed: ${(err as Error).message}` } };\n }\n seeded.push(s.name);\n }\n return { seeded };\n}\n\n// ----------------------------------------------------------------------------\n// Content write + PR open\n// ----------------------------------------------------------------------------\n\nexport interface CommitFileInput extends GhAuth {\n /** `<owner>/<repo>`. */\n repo: string;\n /** Branch to commit on. The caller creates the branch first via\n * `createBranch` when committing to a non-default branch. */\n branch: string;\n /** Repo-relative path (e.g. `infra/cloudflare/environments/prod.tfvars`). */\n path: string;\n /** File contents, plain text. We base64-encode for the API. */\n content: string;\n /** Commit message. */\n message: string;\n}\n\nexport interface CommitFileResult {\n commitSha: string;\n contentSha: string;\n}\n\n/**\n * Create or update a file in a repo's branch via the Contents API. Handles\n * both cases transparently — looks up the existing file's SHA when present\n * and includes it in the update.\n */\nexport async function commitFile(input: CommitFileInput): Promise<CommitFileResult> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n\n const octokit = client(input.token);\n\n let existingSha: string | undefined;\n try {\n const existing = await octokit.repos.getContent({\n owner,\n repo,\n path: input.path,\n ref: input.branch,\n });\n if (!Array.isArray(existing.data) && existing.data.type === 'file') {\n existingSha = existing.data.sha;\n }\n } catch (err: unknown) {\n // 404 is fine — file just doesn't exist yet. Re-throw anything else.\n if (!is404(err)) throw err;\n }\n\n const res = await octokit.repos.createOrUpdateFileContents({\n owner,\n repo,\n path: input.path,\n branch: input.branch,\n message: input.message,\n content: Buffer.from(input.content, 'utf8').toString('base64'),\n ...(existingSha ? { sha: existingSha } : {}),\n });\n\n return {\n commitSha: res.data.commit.sha ?? '',\n contentSha: res.data.content?.sha ?? '',\n };\n}\n\nfunction is404(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'status' in err &&\n (err as { status: number }).status === 404\n );\n}\n\nexport interface CreateBranchInput extends GhAuth {\n repo: string;\n /** Name of the new branch. */\n branch: string;\n /** Name of the branch to fork from. */\n fromBranch: string;\n}\n\n/** Create a new branch by copying the head commit of `fromBranch`. */\nexport async function createBranch(input: CreateBranchInput): Promise<void> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n const octokit = client(input.token);\n\n const ref = await octokit.git.getRef({\n owner,\n repo,\n ref: `heads/${input.fromBranch}`,\n });\n await octokit.git.createRef({\n owner,\n repo,\n ref: `refs/heads/${input.branch}`,\n sha: ref.data.object.sha,\n });\n}\n\nexport interface OpenPrInput extends GhAuth {\n repo: string;\n /** Branch to merge from. */\n head: string;\n /** Branch to merge into. */\n base: string;\n title: string;\n body: string;\n}\n\nexport interface OpenedPr {\n number: number;\n htmlUrl: string;\n}\n\n/** Open a pull request. Returns the PR number + URL so the caller can show\n * it to the operator. */\nexport async function openPullRequest(input: OpenPrInput): Promise<OpenedPr> {\n const [owner, repo] = input.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Bad repo \"${input.repo}\" — expected <owner>/<repo>`);\n }\n const octokit = client(input.token);\n\n const res = await octokit.pulls.create({\n owner,\n repo,\n head: input.head,\n base: input.base,\n title: input.title,\n body: input.body,\n });\n\n return { number: res.data.number, htmlUrl: res.data.html_url };\n}\n","/**\n * Small pure helpers for the local-state-only bits of `create-op-node init`:\n * generating a fresh pgsodium master key, and rendering a region's\n * `prod.tfvars` file.\n *\n * Both are side-effect free — they produce strings the caller decides what to\n * do with. Tests exercise them in isolation.\n */\n\nimport { createHmac, randomBytes } from 'node:crypto';\n\n/**\n * Generate a 32-byte (256-bit) key encoded as 64 lowercase hex characters —\n * the format `pgsodium` expects in `PGSODIUM_ROOT_KEY` and what the runbook\n * documents. The bytes come from Node's CSPRNG.\n */\nexport function generatePgsodiumRootKey(): string {\n return randomBytes(32).toString('hex');\n}\n\n/**\n * url-safe base64 helper (RFC 4648 §5) — the JWT spec mandates this variant\n * (no `+`, no `/`, no padding). `Buffer#toString('base64url')` exists on\n * Node ≥ 16 but expressing it locally keeps the dependency surface tiny and\n * avoids type-coverage games across older `@types/node`.\n */\nfunction base64url(input: Buffer | string): string {\n const buf = typeof input === 'string' ? Buffer.from(input) : input;\n return buf\n .toString('base64')\n // base64 padding `=` only ever appears at the end, so stripping every `=`\n // is equivalent to `/=+$/` and avoids the anchored-quantifier backtracking.\n .replace(/=/g, '')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_');\n}\n\n/**\n * 32-byte CSPRNG password rendered as base64url (no `+`, no `/`, no `=`).\n * Used for POSTGRES_PASSWORD — every Supabase admin user (supabase_admin,\n * authenticator, pgbouncer, supabase_auth_admin, supabase_functions_admin,\n * supabase_storage_admin) shares this one password by design of the\n * upstream init scripts.\n *\n * MUST be URL-safe: the value lands in postgres:// connection-string URIs\n * inside docker-compose env vars (gotrue, postgrest, storage). libpq parses\n * those as RFC 3986 URIs, so `/` would terminate the password component and\n * `+`/`=` are reserved sub-delims that can confuse some URI parsers. base64url\n * keeps the alphabet to `[A-Za-z0-9_-]` which is unambiguously safe in every\n * URI component.\n *\n * 32 bytes → 256 bits of entropy. The base64url encoding is ~43 chars (no\n * padding) — well above what any offline attack on a bcrypt store could\n * threaten.\n */\nexport function generatePostgresPassword(): string {\n return base64url(randomBytes(32));\n}\n\n/** Alias for clarity at the call site. Also base64url so it composes safely\n * into kong's declarative config (where DASHBOARD_PASSWORD is interpolated). */\nexport function generateDashboardPassword(): string {\n return base64url(randomBytes(24));\n}\n\n/**\n * 32-byte CSPRNG HMAC key rendered as base64url. Used for the prompt-service\n * client HMAC: prompt-service's `API_KEYS` env is a comma-separated list of\n * `<region>:<key>` pairs, and the consuming backend sends the same `<key>`\n * value in its HMAC header.\n *\n * Base64url alphabet ensures the value survives the `<region>:<key>` join\n * and any URL-component embedding without ambiguity.\n */\nexport function generateHmacApiKey(): string {\n return base64url(randomBytes(32));\n}\n\n/**\n * 32-byte CSPRNG HMAC secret rendered as base64url. Used for\n * `GATEWAY_HMAC_SECRET` — the shared secret the API Gateway signs\n * gateway→microservice requests with (X-HMAC-Auth). The same value is\n * JSON-wrapped into `API_KEYS` as `{\"api-gateway\":\"<this>\"}` so each\n * microservice accepts the gateway's signature.\n *\n * MUST replace the template's well-known compose default\n * (WELL_KNOWN_GATEWAY_HMAC_SECRET) on any node exposed via the Cloudflare\n * Tunnel — every checkout of the template ships that identical placeholder.\n *\n * Base64url alphabet (`[A-Za-z0-9_-]`) keeps the value safe to embed inside\n * the `API_KEYS` JSON string without escaping and inside HTTP headers.\n */\nexport function generateGatewayHmacSecret(): string {\n return base64url(randomBytes(32));\n}\n\n/**\n * Render the `API_KEYS` env value from a `GATEWAY_HMAC_SECRET`. The backend\n * microservices read `API_KEYS` as a JSON object mapping caller name → key;\n * the api-gateway's key MUST equal `GATEWAY_HMAC_SECRET` so the gateway's\n * HMAC signature verifies. `JSON.stringify` handles any escaping (the\n * base64url alphabet never needs it, but this keeps the contract explicit).\n */\nexport function renderApiKeys(gatewayHmacSecret: string): string {\n return JSON.stringify({ 'api-gateway': gatewayHmacSecret });\n}\n\n/**\n * 24-byte CSPRNG password rendered as base64url. Used for\n * `GRAFANA_ADMIN_PASSWORD` — overrides Grafana's `admin`/`admin` compose\n * default. Grafana is bound to loopback by default but the runbook's Phase 10\n * exposes it via the Tunnel, so a real value matters there. base64url keeps\n * it free of shell/URL metacharacters for the op-compose wrapper export.\n */\nexport function generateGrafanaAdminPassword(): string {\n return base64url(randomBytes(24));\n}\n\n/**\n * 48-byte (384-bit) base64 secret used to sign every Supabase-issued JWT.\n *\n * gotrue, postgrest, storage, and studio all verify tokens against this\n * value, so it must stay identical across the stack and across restarts.\n * Treat it like a master key — rotating it invalidates every session and\n * every long-lived ANON/SERVICE_ROLE token derived from it.\n */\nexport function generateJwtSecret(): string {\n return randomBytes(48).toString('base64');\n}\n\nexport type SupabaseRole = 'anon' | 'service_role';\n\nexport interface SupabaseJwtInput {\n role: SupabaseRole;\n /** HS256 signing key — same JWT_SECRET that gotrue/postgrest verify with. */\n secret: string;\n /** `iat` claim, seconds since epoch. Defaults to 1700000000 (2023-11-14)\n * — a stable past timestamp. This is deliberate, not a test artifact:\n * bootstrap re-runs generate the SAME token shape so we don't churn\n * the cached Keychain entry on every invocation. Pass `Date.now()/1000`\n * if you need a fresh `iat` (e.g. tests that exercise expiry handling). */\n issuedAtSeconds?: number;\n /** Token lifetime in seconds. Default: 10 years — Supabase's own\n * self-hosting docs ship `exp = iat + 10y` for the long-lived\n * anon + service_role keys. */\n ttlSeconds?: number;\n /** `iss` claim. Default: `supabase`. */\n issuer?: string;\n}\n\n/**\n * Verify that a stored JWT's signature was produced by the given secret.\n *\n * Constant-time-ish compare via Buffer length + manual byte loop — the\n * tokens are short and rare enough that the timing channel here doesn't\n * meaningfully advantage an attacker (and the attacker would need to be\n * able to feed bootstrap arbitrary candidate tokens, which they can't).\n *\n * Use case: bootstrap loaded supabase-anon-key from Keychain, but JWT_SECRET\n * may have rotated since. If the cached token's signature doesn't match the\n * current secret, we treat it as stale and regenerate. Without this check,\n * a partial Keychain wipe (e.g. operator deletes only jwt-secret) leaves\n * the derived tokens looking valid by shape but useless against gotrue/\n * postgrest, and every auth call silently fails 401.\n */\nexport function verifySupabaseJwt(token: string, secret: string): boolean {\n const parts = token.split('.');\n if (parts.length !== 3) return false;\n const [h, p, sig] = parts as [string, string, string];\n const expected = base64url(createHmac('sha256', secret).update(`${h}.${p}`).digest());\n if (sig.length !== expected.length) return false;\n let mismatch = 0;\n for (let i = 0; i < sig.length; i++) {\n mismatch |= sig.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return mismatch === 0;\n}\n\n/**\n * Mint a Supabase-shaped HS256 JWT for the `anon` or `service_role` claim.\n *\n * Shape matches what the official `supabase` CLI / hosted-Supabase docs\n * produce, so the token works with @supabase/supabase-js, postgrest's\n * `Authorization: Bearer …`, storage-api, and Studio out of the box.\n *\n * No third-party JWT lib — we'd have to add `jsonwebtoken` (+ its CVE\n * history) for ~30 lines of HMAC code. Implementing it here keeps the\n * dep tree clean and the algorithm pinned to HS256 by construction.\n */\nexport function signSupabaseJwt(input: SupabaseJwtInput): string {\n const iat = input.issuedAtSeconds ?? 1_700_000_000;\n const ttl = input.ttlSeconds ?? 10 * 365 * 24 * 60 * 60;\n const issuer = input.issuer ?? 'supabase';\n\n const header = { alg: 'HS256', typ: 'JWT' };\n const payload = {\n role: input.role,\n iss: issuer,\n iat,\n exp: iat + ttl,\n };\n\n const encodedHeader = base64url(JSON.stringify(header));\n const encodedPayload = base64url(JSON.stringify(payload));\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n const signature = base64url(\n createHmac('sha256', input.secret).update(signingInput).digest(),\n );\n return `${signingInput}.${signature}`;\n}\n\nexport interface ProdTfvarsInput {\n /** Resource-name prefix used across the Terraform module\n * (e.g. `<project>-tunnel-prod`). Defaults to `opuspopuli`. */\n project?: string;\n /** Operator's registered domain in Cloudflare (e.g. `civicfeed.tx`). */\n domain: string;\n /** Subdomain for the API tunnel (e.g. `api`). Default: `api`. */\n apiSubdomain?: string;\n /** Subdomain for the Cloudflare Pages frontend (e.g. `app`). Default: `app`. */\n appSubdomain?: string;\n /** Local port the API Gateway listens on inside the Studio. Default: 8080. */\n tunnelApiPort?: number;\n /** R2 region hint. Default: `WNAM` (Western North America). */\n r2LocationHint?: string;\n}\n\n/**\n * Render a region operator's `prod.tfvars` from their answers. Mirrors the\n * shape of `opuspopuli-node/infra/cloudflare/environments/prod.tfvars.example`\n * so the file lands ready for the cloudflare-infra workflow without any\n * post-processing.\n *\n * The output is the literal file contents — caller writes it to the repo via\n * the GitHub Contents API (`commitFile`).\n */\nexport function renderProdTfvars(input: ProdTfvarsInput): string {\n const project = input.project ?? 'opuspopuli';\n const api = input.apiSubdomain ?? 'api';\n const app = input.appSubdomain ?? 'app';\n const port = input.tunnelApiPort ?? 8080;\n const r2 = input.r2LocationHint ?? 'WNAM';\n\n return `# =============================================================================\n# Production environment — generated by create-op-node init\n# =============================================================================\n# Region-specific values for the OpusPopuli/opuspopuli-node template's\n# infra/cloudflare/ Terraform. Edit by hand to tweak.\n\nproject = ${JSON.stringify(project)}\n\ndomain_name = ${JSON.stringify(input.domain)}\n\napi_subdomain = ${JSON.stringify(api)}\napp_subdomain = ${JSON.stringify(app)}\n\ntunnel_api_port = ${port}\n\nr2_location_hint = ${JSON.stringify(r2)}\n\nenable_tunnel = true\nenable_frontend = true\nenable_r2 = true\n`;\n}\n","/**\n * Generic two-phase TFC apply-and-output wait. Two independent clocks:\n *\n * 1. **Discovery phase** — wait for the workspace to have a current run.\n * The cloudflare-infra workflow takes a few seconds to dispatch to TFC\n * after the operator merges the PR, so we re-poll the workspace until\n * a run id appears or the discovery budget elapses.\n * 2. **Run phase** — wait for that run to reach a terminal state. Sharing\n * one clock with discovery would let slow discovery eat the run-wait\n * budget; two independent clocks isolate them.\n *\n * Dependencies are injected so unit tests can drive the loop without real\n * timers or HTTP. `sleep` is a parameter; tests pass a no-op.\n */\n\nimport { fetchOutput, findWorkspace, getRunStatus, type OutputResult } from './tfc.js';\n\nexport interface WaitInput {\n token: string;\n organization: string;\n workspaceId: string;\n /** Last-known run id when starting. `null` triggers the discovery phase. */\n runId: string | null;\n /** Tags used to re-discover the workspace's current run id. */\n workspaceTags: string[];\n /** Output to pull once the run is `applied`. */\n outputName: string;\n}\n\nexport interface WaitBudgets {\n discoveryMs: number;\n runMs: number;\n pollMs: number;\n}\n\nexport const DEFAULT_BUDGETS: WaitBudgets = {\n discoveryMs: 60 * 1000,\n runMs: 10 * 60 * 1000,\n pollMs: 10 * 1000,\n};\n\nexport type WaitOutcome =\n | { kind: 'success'; value: string }\n | { kind: 'output-missing' }\n | { kind: 'no-run-started' }\n | { kind: 'run-failed'; status: string }\n | { kind: 'timeout' };\n\n/** Test seam: lets tests inject fake findWorkspace / getRunStatus / fetchOutput. */\nexport interface WaitDeps {\n findWorkspace: typeof findWorkspace;\n getRunStatus: typeof getRunStatus;\n fetchOutput: typeof fetchOutput;\n sleep: (ms: number) => Promise<void>;\n now: () => number;\n /** Optional progress callback for UI integration (spinner messages, etc.). */\n onProgress?: (phase: 'discovery' | 'run' | 'fetching' | 'retry') => void;\n}\n\nexport const realDeps: WaitDeps = {\n findWorkspace,\n getRunStatus,\n fetchOutput,\n sleep: (ms) => new Promise((res) => setTimeout(res, ms)),\n now: () => Date.now(),\n};\n\n/**\n * Pure polling implementation. Returns a discriminated outcome so the caller\n * can render the right message for each terminal state.\n */\nexport async function waitForApply(\n input: WaitInput,\n budgets: WaitBudgets = DEFAULT_BUDGETS,\n deps: WaitDeps = realDeps,\n): Promise<WaitOutcome> {\n let runId = input.runId;\n if (!runId) {\n runId = await discoverRunId(input, budgets, deps);\n if (!runId) return { kind: 'no-run-started' };\n }\n return waitForRunOutput(input, budgets, deps, runId);\n}\n\n// Run a single poll attempt, degrading any throw to `null` (treated as \"no\n// result this interval, try again\"). Keeps a transient network failure from\n// rejecting out of the multi-minute wait loops. `onRetry` fires on a swallowed\n// throw so the caller can surface the hiccup instead of retrying in silence.\nasync function safePoll<T>(\n fn: () => Promise<T | null>,\n onRetry?: () => void,\n): Promise<T | null> {\n try {\n return await fn();\n } catch {\n onRetry?.();\n return null;\n }\n}\n\n// Phase 1: discovery — poll the workspace until it has a current run, or the\n// discovery budget expires. Returns the run id, or null on timeout.\nasync function discoverRunId(\n input: WaitInput,\n budgets: WaitBudgets,\n deps: WaitDeps,\n): Promise<string | null> {\n deps.onProgress?.('discovery');\n const discoveryStart = deps.now();\n // Check first, THEN sleep: a run that already exists is found at t=0 rather\n // than a poll-interval late, and findWorkspace always runs at least once\n // regardless of the pollMs/discoveryMs ratio. (#35)\n while (deps.now() - discoveryStart < budgets.discoveryMs) {\n // A transient failure is not fatal to a multi-minute discovery window —\n // swallow it and retry on the next poll rather than rejecting the wait.\n // (The tfc helpers already degrade throws to null, so this is\n // belt-and-suspenders against any future throwing dep.)\n const ws = await safePoll(\n () =>\n deps.findWorkspace({\n token: input.token,\n organization: input.organization,\n tags: input.workspaceTags,\n }),\n () => deps.onProgress?.('retry'),\n );\n if (ws?.currentRunId) return ws.currentRunId;\n await deps.sleep(budgets.pollMs);\n }\n return null;\n}\n\n// Phase 2: run wait — poll the run until it finishes (fetching the output on\n// success), or the run budget expires.\nasync function waitForRunOutput(\n input: WaitInput,\n budgets: WaitBudgets,\n deps: WaitDeps,\n runId: string,\n): Promise<WaitOutcome> {\n deps.onProgress?.('run');\n const runStart = deps.now();\n while (deps.now() - runStart < budgets.runMs) {\n // Transient status-poll failure → retry next interval, don't abort the\n // ~10-minute run wait on a single bad packet.\n const r = await safePoll(\n () => deps.getRunStatus({ token: input.token, organization: input.organization }, runId),\n () => deps.onProgress?.('retry'),\n );\n if (r?.finished) {\n if (!r.succeeded) return { kind: 'run-failed', status: r.status };\n const out = await tryFetchOutput(input, deps);\n if (out.kind === 'value') return { kind: 'success', value: out.value };\n if (out.kind === 'absent') return { kind: 'output-missing' };\n // out.kind === 'error': a transient failure fetching the output of an\n // already-applied run. Don't misreport it as output-missing — fall\n // through, sleep, and retry within the remaining run budget. (#59)\n }\n await deps.sleep(budgets.pollMs);\n }\n\n return { kind: 'timeout' };\n}\n\n// Fetch the output once, normalizing a thrown/degraded call into the same\n// `error` case fetchOutput already uses for a non-200 — so the run loop has a\n// single retryable signal. `onProgress('retry')` fires on a transient error so\n// the UI can show the hiccup instead of stalling silently. (#59)\nasync function tryFetchOutput(input: WaitInput, deps: WaitDeps): Promise<OutputResult> {\n deps.onProgress?.('fetching');\n const out = await safePoll(\n () =>\n deps.fetchOutput(\n { token: input.token, organization: input.organization },\n input.workspaceId,\n input.outputName,\n ),\n () => deps.onProgress?.('retry'),\n );\n if (out === null) return { kind: 'error' }; // safePoll swallowed a throw\n if (out.kind === 'error') deps.onProgress?.('retry');\n return out;\n}\n","import { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { probeCloudflareToken } from '../lib/cloudflare.js';\nimport { probeTfcToken } from '../lib/tfc.js';\nimport { detectKeychain, readSecret, saveSecret } from '../lib/keychain.js';\nimport { safeExeca } from '../lib/exec.js';\nimport { unwrap } from '../lib/prompts.js';\nimport {\n commitFile,\n createBranch,\n createRepoFromTemplate,\n getRepoDefaultBranch,\n openPullRequest,\n setRepoSecrets,\n} from '../lib/github.js';\nimport { generatePgsodiumRootKey, renderProdTfvars } from '../lib/secrets.js';\nimport { findWorkspace } from '../lib/tfc.js';\nimport { waitForApply, realDeps as realWaitDeps } from '../lib/polling.js';\n\nexport interface InitOptions {\n domain?: string;\n region?: string;\n owner?: string;\n template?: string;\n project?: string;\n cfToken?: string;\n cfAccount?: string;\n cfZone?: string;\n tfToken?: string;\n tfOrg?: string;\n ghToken?: string;\n overwrite?: boolean;\n useExistingRepo?: boolean;\n skipWait?: boolean;\n localOnly?: boolean;\n yes?: boolean;\n}\n\n/** Pull the GitHub token from `gh auth token` if the CLI is signed in. Lets\n * operators who use `gh` skip pasting their PAT. Returns null cleanly when\n * `gh` isn't installed or isn't signed in. */\nasync function ghTokenFromCli(): Promise<string | null> {\n const r = await safeExeca('gh', ['auth', 'token']);\n if (r === null || r.exitCode !== 0) return null;\n const token = r.stdout.trim();\n return token.length > 0 ? token : null;\n}\n\nexport const initCommand = new Command('init')\n .description(\n 'Stand up the node repo + Cloudflare infrastructure for a new region. Run this on your laptop.',\n )\n .addOption(new Option('--domain <domain>', 'Your registered domain (e.g. example.org)'))\n .addOption(new Option('--region <slug>', 'Short label for your region (e.g. us-ca)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the new node repo').default('OpusPopuli'))\n .addOption(\n new Option('--template <owner/repo>', 'Template repo to clone from').default(\n 'OpusPopuli/opuspopuli-node',\n ),\n )\n .addOption(new Option('--project <name>', 'tfvars project prefix').default('opuspopuli'))\n .addOption(new Option('--cf-token <token>', 'Cloudflare Account API token').env('CF_TOKEN'))\n .addOption(new Option('--cf-account <id>', 'Cloudflare account ID').env('CF_ACCOUNT'))\n .addOption(new Option('--cf-zone <id>', 'Cloudflare zone ID for your domain').env('CF_ZONE'))\n .addOption(new Option('--tf-token <token>', 'Terraform Cloud user/team token').env('TF_API_TOKEN'))\n .addOption(new Option('--tf-org <org>', 'Terraform Cloud organization').env('TF_CLOUD_ORGANIZATION'))\n .addOption(new Option('--gh-token <token>', 'GitHub Personal Access Token (else gh CLI)').env('GH_TOKEN'))\n .addOption(\n new Option(\n '--overwrite',\n 'Overwrite existing Keychain items (pgsodium key, Tunnel token) on a re-run',\n ).default(false),\n )\n .addOption(\n new Option(\n '--use-existing-repo',\n \"Continue using a previously-created node repo (don't fail on 'already exists')\",\n ).default(false),\n )\n .addOption(new Option('--skip-wait', \"Don't poll for Terraform apply; exit after PR open\").default(false))\n .addOption(\n new Option(\n '--local-only',\n 'Skip the Cloudflare/TFC/PR/tunnel phases. Creates the region repo from template + stores a pgsodium key — enough for `bootstrap --local-only` to work.',\n ).default(false),\n )\n .addOption(new Option('-y, --yes', 'Skip the final confirmation').default(false))\n .action(async (opts: InitOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node init ')));\n printWelcomeNote(opts);\n\n const region = await resolveRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const newRepoName = `opuspopuli-node-${region}`;\n const newRepoFull = `${owner}/${newRepoName}`;\n warnIgnoredLocalOnlyFlags(opts);\n\n // Collect domain + Cloudflare + TFC creds when running in production mode.\n // Returns null in --local-only — downstream branches on this once and the\n // typed presence carries through (no non-null assertions). (S1)\n const publicConfig = opts.localOnly ? null : await collectPublicConfig(opts);\n const ghToken = await resolveGhToken(opts);\n const keychain = await detectKeychain();\n printSecretStoreNote(keychain);\n\n await confirmPlan({ opts, region, owner, newRepoFull, publicConfig });\n\n const created = await createRegionRepo({ opts, ghToken, owner, newRepoName, newRepoFull, region });\n if (publicConfig) {\n await seedRepoSecrets({ ghToken, publicConfig, newRepoFull });\n }\n const pr = publicConfig\n ? await openInfraPr({ opts, ghToken, region, newRepoFull, publicConfig, created })\n : null;\n\n await persistPgsodiumKey({ keychain, opts, region });\n\n // Local-only flow ends here. Gating on publicConfig (not opts.localOnly)\n // lets TS narrow it to non-null for the TFC poll block below.\n if (!publicConfig) {\n printLocalOnlyOutro({ region, newRepoFull });\n return;\n }\n if (!pr) {\n throw new Error('init: PR creation step did not run despite publicConfig present');\n }\n\n const proceed = await pauseForMerge({ pr, opts });\n if (!proceed) return;\n\n const tunnelToken = await fetchTunnelToken({ publicConfig });\n await persistTunnelToken({ keychain, region, tunnelToken });\n printDoneOutro(region);\n });\n\n// ----------------------------------------------------------------------------\n// Init phases\n// ----------------------------------------------------------------------------\n// The command action delegates to these phase helpers so no single function\n// exceeds the cognitive-complexity budget. Each is behavior-preserving — the\n// interactive prompts, spinners, and process.exit calls are relocated\n// verbatim, restructured only with early returns to flatten nesting.\n\nfunction printWelcomeNote(opts: InitOptions): void {\n p.note(\n opts.localOnly\n ? [\n 'Local-only setup — creates the region repo from template + a pgsodium key.',\n 'No Cloudflare, no Terraform Cloud, no public exposure.',\n '',\n pc.dim('Phase 1: laptop side (now) — GitHub repo from template + Keychain.'),\n pc.dim('Phase 2: Studio side — `create-op-node bootstrap --local-only`.'),\n '',\n pc.dim('When you\\'re ready to expose publicly, re-run `init` without --local-only.'),\n ].join('\\n')\n : [\n 'This walks you from a sealed Mac Studio + a Cloudflare account to a',\n 'live federation node serving traffic at api.<your-domain>.',\n '',\n pc.dim('Phase 1: laptop side (now) — Cloudflare, GitHub, Terraform Cloud.'),\n pc.dim('Phase 2: Studio side — run `create-op-node bootstrap` on the Mac.'),\n ].join('\\n'),\n 'Welcome',\n );\n}\n\n// Region label (used as the Keychain service suffix + R2 prefix).\nasync function resolveRegion(opts: InitOptions): Promise<string> {\n return opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Short region label (used as the Keychain service suffix + R2 prefix)?',\n placeholder: 'us-ca',\n validate: (v) =>\n /^[a-z0-9-]{2,32}$/.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n}\n\n// Warn if the operator passed flags that don't apply to --local-only. They'd\n// otherwise be silently ignored and the operator would wonder why their\n// token/domain/etc. seemed to do nothing. (S2/S3)\nfunction warnIgnoredLocalOnlyFlags(opts: InitOptions): void {\n if (!opts.localOnly) return;\n const ignored = listIgnoredLocalOnlyFlags(opts);\n if (ignored.length === 0) return;\n p.note(\n pc.yellow(\n `⚠ The following ${ignored.length === 1 ? 'flag is' : 'flags are'} ignored with --local-only:\\n` +\n ` ${ignored.join(', ')}\\n` +\n pc.dim('These configure Cloudflare / TFC / PR-merge flow, which --local-only skips.'),\n ),\n 'Notice',\n );\n}\n\n// ---- GitHub auth: flag > signed-in gh CLI > paste prompt ----\nasync function resolveGhToken(opts: InitOptions): Promise<string> {\n let ghToken = opts.ghToken;\n if (!ghToken) {\n const fromCli = await ghTokenFromCli();\n if (fromCli) {\n const useCli = unwrap(\n await p.confirm({\n message: 'Found a signed-in `gh` CLI — use its token?',\n initialValue: true,\n }),\n );\n if (useCli) ghToken = fromCli;\n }\n }\n if (!ghToken) {\n ghToken = await collectSecret(\n undefined,\n 'GitHub Personal Access Token (repo scope)',\n 'github',\n );\n }\n return ghToken;\n}\n\nfunction printSecretStoreNote(keychain: Awaited<ReturnType<typeof detectKeychain>>): void {\n const kcNote = keychain.available\n ? `✓ macOS Keychain available — pgsodium key + Tunnel token will be saved to your login keychain.\\n` +\n pc.dim('Note: items don\\'t sync to iCloud Keychain via the security CLI.\\n') +\n pc.dim('On the Studio, bootstrap will read locally and prompt you to paste if missing.')\n : `⚠ ${keychain.reason ?? 'Keychain unavailable'}. Secrets will be printed for manual stash.`;\n p.note(kcNote, 'Secret store');\n}\n\n// ---- Plan summary + confirm ----\nasync function confirmPlan(args: {\n opts: InitOptions;\n region: string;\n owner: string;\n newRepoFull: string;\n publicConfig: PublicConfig | null;\n}): Promise<void> {\n const { opts, region, owner, newRepoFull, publicConfig } = args;\n const orgWriteAccess = pc.dim(`required for ${owner}`);\n p.note(\n opts.localOnly\n ? [\n `Region label: ${pc.cyan(region)}`,\n `New node repo: ${pc.cyan(newRepoFull)}`,\n `Template: ${pc.dim(opts.template ?? 'OpusPopuli/opuspopuli-node')}`,\n `GH org write access: ${orgWriteAccess}`,\n ``,\n `Will create the repo from template (private, no Cloudflare),`,\n `and store a fresh pgsodium key in Keychain. That's it — no PR,`,\n `no terraform, no tunnel token. Bootstrap on the Studio with`,\n `\\`bootstrap --local-only --region ${region}\\` next.`,\n ].join('\\n')\n : [\n `Region label: ${pc.cyan(region)}`,\n `Domain: ${pc.cyan(publicConfig?.domain ?? '')}`,\n `New node repo: ${pc.cyan(newRepoFull)}`,\n `Template: ${pc.dim(opts.template ?? 'OpusPopuli/opuspopuli-node')}`,\n `TFC organization: ${pc.cyan(publicConfig?.tfOrg ?? '')}`,\n `GH org write access: ${orgWriteAccess}`,\n ``,\n `Will create the repo, seed 5 secrets, write prod.tfvars on a branch,`,\n `open a PR, generate a fresh pgsodium key, and (after you merge) wait`,\n `for terraform apply to finish and retrieve the Tunnel token.`,\n ].join('\\n'),\n 'Plan',\n );\n\n if (opts.yes) return;\n const go = unwrap(await p.confirm({ message: 'Proceed?', initialValue: true }));\n if (!go) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n}\n\n// ---- Execute: create repo (idempotent on HTTP 422 already-exists) ----\nasync function createRegionRepo(args: {\n opts: InitOptions;\n ghToken: string;\n owner: string;\n newRepoName: string;\n newRepoFull: string;\n region: string;\n}): Promise<{ fullName: string; defaultBranch: string }> {\n const { opts, ghToken, owner, newRepoName, newRepoFull, region } = args;\n const repoSpin = p.spinner();\n repoSpin.start(`Creating ${newRepoFull} from ${opts.template}…`);\n try {\n const created = await createRepoFromTemplate({\n token: ghToken,\n template: opts.template ?? 'OpusPopuli/opuspopuli-node',\n owner,\n name: newRepoName,\n description: `Opus Populi node deployment for ${region}`,\n });\n repoSpin.stop(pc.green(`✓ Created ${created.fullName}`));\n return { fullName: created.fullName, defaultBranch: created.defaultBranch };\n } catch (err) {\n // The most likely re-run failure mode: the repo already exists from a\n // previous partial run. The GitHub API responds with HTTP 422 for that\n // case — status code is the API contract, message text isn't. Don't\n // regex on the message; it can change.\n const status =\n typeof err === 'object' && err !== null && 'status' in err\n ? (err as { status: number }).status\n : 0;\n const message = (err as Error).message ?? 'unknown error';\n\n if (status !== 422) {\n repoSpin.stop(pc.red(`✗ Couldn't create repo: ${message}`));\n p.cancel('Fix the issue and re-run.');\n process.exit(1);\n }\n\n repoSpin.stop(pc.yellow(`⚠ ${newRepoFull} already exists.`));\n const reuse =\n opts.useExistingRepo ||\n unwrap(\n await p.confirm({\n message: `Continue with the existing ${newRepoFull}? (Re-seeds secrets + re-commits prod.tfvars on a fresh branch.)`,\n initialValue: true,\n }),\n );\n if (!reuse) {\n p.cancel(\n `Delete ${newRepoFull} on GitHub and re-run, or pass --use-existing-repo to skip this prompt.`,\n );\n process.exit(0);\n }\n // Synthesize the same shape `createRepoFromTemplate` returns so the rest\n // of the flow doesn't care which path got us here. Query the repo's ACTUAL\n // default branch (it may not be `main` — older operator habit, org default)\n // so the branch + PR steps target a branch that exists. (#41)\n const fetched = await getRepoDefaultBranch({ token: ghToken, repo: newRepoFull });\n if (fetched === null) {\n p.note(\n pc.yellow(\n `⚠ Couldn't read ${newRepoFull}'s default branch — assuming \"main\". ` +\n 'If the branch/PR steps fail, check the repo\\'s default branch on GitHub.',\n ),\n 'Notice',\n );\n }\n return { fullName: newRepoFull, defaultBranch: fetched ?? 'main' };\n }\n}\n\n// ---- Execute: seed 5 repo secrets (production mode only) ----\nasync function seedRepoSecrets(args: {\n ghToken: string;\n publicConfig: PublicConfig;\n newRepoFull: string;\n}): Promise<void> {\n const { ghToken, publicConfig, newRepoFull } = args;\n const secrets: Array<{ name: string; value: string }> = [\n { name: 'CLOUDFLARE_API_TOKEN', value: publicConfig.cfToken },\n { name: 'CLOUDFLARE_ACCOUNT_ID', value: publicConfig.cfAccount },\n { name: 'CLOUDFLARE_ZONE_ID', value: publicConfig.cfZone },\n { name: 'TF_API_TOKEN', value: publicConfig.tfToken },\n { name: 'TF_CLOUD_ORGANIZATION', value: publicConfig.tfOrg },\n ];\n const secSpin = p.spinner();\n secSpin.start(`Seeding ${secrets.length} repo secrets…`);\n const { seeded, failed } = await setRepoSecrets({ token: ghToken, repo: newRepoFull, secrets });\n if (failed) {\n secSpin.stop(pc.red(`✗ Failed to set ${failed.name}: ${failed.reason}`));\n const remaining = secrets.slice(seeded.length).map((x) => x.name);\n p.cancel(\n [\n seeded.length > 0\n ? `Already seeded on ${newRepoFull}: ${seeded.join(', ')}.`\n : `Nothing seeded yet on ${newRepoFull}.`,\n `Still pending: ${remaining.join(', ')}.`,\n '',\n `Make sure your --gh-token PAT has \"Actions Secrets: write\" (fine-grained) or \\`repo\\` scope (classic).`,\n `Re-run with --use-existing-repo to retry (GitHub will overwrite the already-set secrets idempotently).`,\n ].join('\\n'),\n );\n process.exit(1);\n }\n secSpin.stop(pc.green(`✓ Seeded ${secrets.length} secrets on ${newRepoFull}`));\n}\n\n// ---- Execute: branch + tfvars + PR (production mode only) ----\n// Branch name is timestamped (ISO compact, UTC) so re-runs don't collide\n// with a leftover branch from a previous partial run.\nasync function openInfraPr(args: {\n opts: InitOptions;\n ghToken: string;\n region: string;\n newRepoFull: string;\n publicConfig: PublicConfig;\n created: { defaultBranch: string };\n}): Promise<Awaited<ReturnType<typeof openPullRequest>>> {\n const { opts, ghToken, region, newRepoFull, publicConfig, created } = args;\n const branch = `init/region-${region}-${isoStampUtc(new Date())}`;\n const setupSpin = p.spinner();\n setupSpin.start(`Writing prod.tfvars on branch ${branch}…`);\n try {\n await createBranch({\n token: ghToken,\n repo: newRepoFull,\n branch,\n fromBranch: created.defaultBranch,\n });\n const tfvars = renderProdTfvars({\n project: opts.project ?? 'opuspopuli',\n domain: publicConfig.domain,\n });\n await commitFile({\n token: ghToken,\n repo: newRepoFull,\n branch,\n path: 'infra/cloudflare/environments/prod.tfvars',\n content: tfvars,\n message: `init: prod.tfvars for ${region}`,\n });\n } catch (err) {\n setupSpin.stop(pc.red(`✗ Couldn't write tfvars: ${(err as Error).message}`));\n p.cancel('The repo exists but the branch / commit failed. Open it on GitHub and inspect.');\n process.exit(1);\n }\n setupSpin.stop(pc.green('✓ Wrote prod.tfvars'));\n\n const prSpin = p.spinner();\n prSpin.start('Opening pull request…');\n try {\n const pr = await openPullRequest({\n token: ghToken,\n repo: newRepoFull,\n head: branch,\n base: created.defaultBranch,\n title: `init: bring up region ${region}`,\n body: [\n `Initial region deployment for **${region}** (${publicConfig.domain}).`,\n '',\n 'Adds `infra/cloudflare/environments/prod.tfvars`. Merging this PR triggers',\n '`cloudflare-infra.yml` which runs `terraform apply` against the',\n `\\`${publicConfig.tfOrg}\\` Terraform Cloud organization, provisioning the Cloudflare`,\n 'Tunnel, DNS records, R2 buckets, and Pages project.',\n '',\n `Generated by \\`create-op-node init\\`.`,\n ].join('\\n'),\n });\n prSpin.stop(pc.green(`✓ Opened PR #${pr.number}`));\n return pr;\n } catch (err) {\n prSpin.stop(pc.red(`✗ Couldn't open PR: ${(err as Error).message}`));\n p.cancel('Branch + tfvars are committed; open the PR by hand on GitHub.');\n process.exit(1);\n }\n}\n\n// ---- pgsodium master key (read existing OR generate fresh) ----\n//\n// Three branches: Keychain hit + key present + no --overwrite → surface the\n// existing key; Keychain hit + missing/--overwrite → generate + save; no\n// Keychain → generate + print for manual stash.\nasync function persistPgsodiumKey(args: {\n keychain: Awaited<ReturnType<typeof detectKeychain>>;\n opts: InitOptions;\n region: string;\n}): Promise<void> {\n const { keychain, opts, region } = args;\n const pgsodiumCoords = { region, account: 'pgsodium-root-key' as const };\n const keyLabel = `org.opuspopuli.${region}/pgsodium-root-key`;\n\n if (!keychain.available) {\n const fresh = generatePgsodiumRootKey();\n await printKeyForManualSave(fresh, keyLabel);\n return;\n }\n\n const existing = opts.overwrite ? null : await readSecret(pgsodiumCoords);\n if (existing && /^[a-f0-9]{64}$/.test(existing)) {\n p.note(\n `${pc.green('✓')} Re-using existing pgsodium master key from Keychain (${pc.cyan(keyLabel)}). Pass --overwrite to rotate.`,\n 'Secret',\n );\n return;\n }\n\n const fresh = generatePgsodiumRootKey();\n const r = await saveSecret(pgsodiumCoords, fresh);\n if (r.written) {\n p.note(\n `${pc.green('✓')} pgsodium master key${r.updated ? ' rotated' : ' saved'} to Keychain as ${pc.cyan(keyLabel)}.`,\n 'Secret',\n );\n } else {\n await printKeyForManualSave(fresh, keyLabel, r.reason);\n }\n}\n\nfunction printLocalOnlyOutro(args: { region: string; newRepoFull: string }): void {\n const { region, newRepoFull } = args;\n p.outro(\n pc.cyan(\n [\n `Region ${region} provisioned for local-only mode.`,\n `Repo: https://github.com/${newRepoFull}`,\n ``,\n `Next: on the Studio (fresh or otherwise — bootstrap installs`,\n `brew packages it needs), run:`,\n ` npx create-op-node bootstrap --region ${region} --local-only`,\n ``,\n `When you're ready to expose publicly, re-run BOTH \\`init\\` and`,\n `\\`bootstrap\\` without --local-only. Same region repo + pgsodium key`,\n `promote cleanly to the production-shaped deploy.`,\n ].join('\\n'),\n ),\n );\n}\n\n// Pause for the operator to merge the infra PR. Returns false when the flow\n// should stop here (--skip-wait, or the operator hasn't merged yet).\nasync function pauseForMerge(args: {\n pr: { htmlUrl: string };\n opts: InitOptions;\n}): Promise<boolean> {\n const { pr, opts } = args;\n if (opts.skipWait) {\n p.outro(\n pc.cyan(\n `Review + merge ${pr.htmlUrl} when ready. Re-run with no --skip-wait or run \\`npx create-op-node verify\\` afterwards.`,\n ),\n );\n return false;\n }\n\n p.note(\n [\n `Open the PR: ${pc.cyan(pr.htmlUrl)}`,\n '',\n 'Review the `terraform plan` comment, then merge to main.',\n 'The workflow then runs `terraform apply` against Terraform Cloud.',\n ].join('\\n'),\n 'Next step: review + merge',\n );\n const merged = unwrap(await p.confirm({ message: 'PR merged?', initialValue: false }));\n if (!merged) {\n p.outro(\n pc.cyan(`No worries — re-run \\`create-op-node init --skip-wait\\` later to skip this step, or finish manually.`),\n );\n return false;\n }\n return true;\n}\n\n// ---- Poll TFC for apply completion + fetch the tunnel token ----\nasync function fetchTunnelToken(args: { publicConfig: PublicConfig }): Promise<string> {\n const { publicConfig } = args;\n const ws = await findWorkspace({\n token: publicConfig.tfToken,\n organization: publicConfig.tfOrg,\n tags: ['opuspopuli', 'cloudflare'],\n });\n if (!ws) {\n p.cancel(\n `Couldn't find a TFC workspace tagged opuspopuli + cloudflare in ${publicConfig.tfOrg}. ` +\n `Check the workflow's run log; the workspace is created on first apply.`,\n );\n process.exit(1);\n }\n\n const tunnelToken = await waitForApplyAndFetchTunnelToken({\n token: publicConfig.tfToken,\n organization: publicConfig.tfOrg,\n workspaceId: ws.id,\n runId: ws.currentRunId,\n });\n if (!tunnelToken) {\n p.cancel(\n `Terraform apply didn't produce a tunnel_token output. Check the run on TFC; if it succeeded, the output may be named differently — patch and re-run, or fetch via 'terraform output -raw tunnel_token'.`,\n );\n process.exit(1);\n }\n return tunnelToken;\n}\n\nasync function persistTunnelToken(args: {\n keychain: Awaited<ReturnType<typeof detectKeychain>>;\n region: string;\n tunnelToken: string;\n}): Promise<void> {\n const { keychain, region, tunnelToken } = args;\n const tunnelCoords = { region, account: 'tunnel-token' as const };\n const tunnelLabel = `org.opuspopuli.${region}/tunnel-token`;\n if (!keychain.available) {\n await printKeyForManualSave(tunnelToken, tunnelLabel);\n return;\n }\n const r = await saveSecret(tunnelCoords, tunnelToken);\n if (r.written) {\n p.note(\n `${pc.green('✓')} Tunnel token saved to Keychain as ${pc.cyan(tunnelLabel)}.`,\n 'Secret',\n );\n } else {\n await printKeyForManualSave(tunnelToken, tunnelLabel, r.reason);\n }\n}\n\nfunction printDoneOutro(region: string): void {\n p.outro(\n pc.cyan(\n `Region ${region} is provisioned. Next: \\`npx create-op-node bootstrap\\` on the Mac Studio.`,\n ),\n );\n}\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n/** Source-specific minimums — every real-world token from these issuers is\n * longer than the floor, so a short input is a typo or paste error. */\nconst MIN_TOKEN_LENGTH: Record<SecretKind, number> = {\n cloudflare: 40,\n tfc: 40,\n github: 40,\n generic: 20,\n};\n\ntype SecretKind = 'cloudflare' | 'tfc' | 'github' | 'generic';\n\n/** Pure description of which init phases will run given the operator's\n * flags. Useful for testing the flag-routing logic without touching the\n * action handler (which shells out to GH / Cloudflare / TFC). The action\n * uses the same `opts.localOnly` directly; this is a docs + test seam. */\nexport function summarizePhases(opts: Pick<InitOptions, 'localOnly'>): {\n cloudflareProbe: boolean;\n tfcProbe: boolean;\n seedSecrets: boolean;\n branchAndPR: boolean;\n tunnelTokenWait: boolean;\n} {\n const production = !opts.localOnly;\n return {\n cloudflareProbe: production,\n tfcProbe: production,\n seedSecrets: production,\n branchAndPR: production,\n tunnelTokenWait: production,\n };\n}\n\n/** Which production-only flags the operator passed but which won't be used\n * in `--local-only` mode. Surfaced as a warning so the operator knows their\n * --cf-token / --domain / etc. weren't silently swallowed. (review S2/S3) */\nexport function listIgnoredLocalOnlyFlags(opts: InitOptions): string[] {\n const ignored: string[] = [];\n if (opts.domain) ignored.push('--domain');\n if (opts.cfToken) ignored.push('--cf-token');\n if (opts.cfAccount) ignored.push('--cf-account');\n if (opts.cfZone) ignored.push('--cf-zone');\n if (opts.tfToken) ignored.push('--tf-token');\n if (opts.tfOrg) ignored.push('--tf-org');\n if (opts.skipWait) ignored.push('--skip-wait');\n return ignored;\n}\n\n/** All the inputs init needs when running the full production flow.\n * Returned by `collectPublicConfig` (whose presence is gated on\n * `!opts.localOnly`). Carrying this around as a tagged shape lets the\n * downstream code use the fields without non-null assertions. */\nexport interface PublicConfig {\n domain: string;\n cfToken: string;\n cfAccount: string;\n cfZone: string;\n tfToken: string;\n tfOrg: string;\n}\n\n/** Prompt for + verify Cloudflare and Terraform Cloud creds. Exits the\n * process on any verification failure. Only called in production mode;\n * in --local-only mode the caller passes `null` straight through. */\nasync function collectPublicConfig(opts: InitOptions): Promise<PublicConfig> {\n const domain = opts.domain\n ? opts.domain\n : unwrap(\n await p.text({\n message: 'Domain registered in Cloudflare?',\n placeholder: 'example.org',\n validate: (v) => {\n if (!v) return 'Required';\n return v.includes('.') ? undefined : 'Missing a TLD?';\n },\n }),\n );\n\n // ---- Cloudflare token --------------------------------------------------\n const cfToken = await collectSecret(\n opts.cfToken,\n 'Cloudflare Account API token (input hidden)',\n 'cloudflare',\n );\n const cfAccount = await collectId(opts.cfAccount, 'Cloudflare account ID');\n const cfZone = await collectId(opts.cfZone, `Cloudflare zone ID for ${domain}`);\n\n const cfSpin = p.spinner();\n cfSpin.start('Verifying Cloudflare token + 5 scopes…');\n const cfProbe = await probeCloudflareToken({\n token: cfToken,\n accountId: cfAccount,\n zoneId: cfZone,\n });\n if (!cfProbe.ok) {\n cfSpin.stop(pc.red('✗ Cloudflare token check failed.'));\n for (const issue of cfProbe.issues) console.error(` - ${issue}`);\n p.cancel('Fix the token in the Cloudflare dashboard, then re-run.');\n process.exit(1);\n }\n cfSpin.stop(pc.green('✓ Cloudflare token valid, 5 scopes present.'));\n\n // ---- Terraform Cloud token ---------------------------------------------\n const tfToken = await collectSecret(\n opts.tfToken,\n 'Terraform Cloud user/team API token',\n 'tfc',\n );\n const tfOrg = opts.tfOrg\n ? opts.tfOrg\n : unwrap(\n await p.text({\n message: 'Terraform Cloud organization name?',\n placeholder: 'op-region-ca',\n }),\n );\n\n const tfSpin = p.spinner();\n tfSpin.start('Verifying Terraform Cloud token + organization…');\n const tfProbe = await probeTfcToken({ token: tfToken, organization: tfOrg });\n if (!tfProbe.ok) {\n tfSpin.stop(pc.red('✗ Terraform Cloud check failed.'));\n for (const issue of tfProbe.issues) console.error(` - ${issue}`);\n p.cancel('Fix the token / org, then re-run.');\n process.exit(1);\n }\n const asUser = tfProbe.userName ? ` (as ${tfProbe.userName})` : '';\n tfSpin.stop(\n pc.green(\n `✓ TFC token valid${asUser}, org \"${tfOrg}\" reachable.`,\n ),\n );\n\n return { domain, cfToken, cfAccount, cfZone, tfToken, tfOrg };\n}\n\nasync function collectSecret(\n preset: string | undefined,\n message: string,\n kind: SecretKind = 'generic',\n): Promise<string> {\n if (preset) return preset;\n const min = MIN_TOKEN_LENGTH[kind];\n const v = unwrap(\n await p.password({\n message,\n validate: (v) =>\n v && v.length >= min\n ? undefined\n : `That looks too short — expected at least ${min} characters for a ${kind} token`,\n }),\n );\n return v;\n}\n\nasync function collectId(preset: string | undefined, message: string): Promise<string> {\n if (preset) return preset;\n const v = unwrap(\n await p.text({\n message,\n placeholder: '0000000000000000000000000000000',\n validate: (v) =>\n /^[a-f0-9]{32}$/.test(v ?? '') ? undefined : 'Expected 32 hex characters',\n }),\n );\n return v;\n}\n\nasync function printKeyForManualSave(\n value: string,\n label: string,\n reason?: string,\n): Promise<void> {\n p.note(\n [\n reason ? `${pc.red('✗')} ${reason}` : '',\n `Save this value to your secret store as ${pc.cyan(label)}:`,\n '',\n pc.yellow(value),\n '',\n pc.dim('It will not be shown again.'),\n pc.dim('On the Studio, bootstrap will prompt you to paste it back.'),\n ]\n .filter((line) => line.length > 0)\n .join('\\n'),\n 'Manual save',\n );\n unwrap(\n await p.confirm({\n message: 'Value stashed?',\n initialValue: true,\n }),\n );\n}\n\n/** Compact ISO timestamp suitable for a git branch name: 20260618-184530Z.\n * UTC so re-runs across timezones sort coherently. */\nfunction isoStampUtc(d: Date): string {\n const pad = (n: number, w = 2) => n.toString().padStart(w, '0');\n return (\n `${d.getUTCFullYear()}` +\n `${pad(d.getUTCMonth() + 1)}` +\n `${pad(d.getUTCDate())}` +\n `-` +\n `${pad(d.getUTCHours())}` +\n `${pad(d.getUTCMinutes())}` +\n `${pad(d.getUTCSeconds())}Z`\n );\n}\n\ninterface WaitInput {\n token: string;\n organization: string;\n workspaceId: string;\n runId: string | null;\n}\n\n/** Thin command-side adapter for the polling lib — renders Clack spinner\n * state from the lib's progress callback + maps the discriminated outcome\n * to a single nullable result the command keeps using. */\nasync function waitForApplyAndFetchTunnelToken(input: WaitInput): Promise<string | null> {\n const spin = p.spinner();\n spin.start('Waiting for terraform apply to finish (polling every 10s)…');\n\n const outcome = await waitForApply(\n {\n token: input.token,\n organization: input.organization,\n workspaceId: input.workspaceId,\n runId: input.runId,\n workspaceTags: ['opuspopuli', 'cloudflare'],\n outputName: 'tunnel_token',\n },\n undefined,\n {\n ...realWaitDeps,\n // Surface a transient network hiccup instead of silently re-polling, so\n // a slow wait doesn't look like a hang.\n onProgress: (phase) => {\n if (phase === 'retry') spin.message('Transient network error — retrying next poll…');\n },\n },\n );\n\n switch (outcome.kind) {\n case 'success':\n spin.stop(pc.green('✓ Tunnel token retrieved.'));\n return outcome.value;\n case 'output-missing':\n spin.stop(pc.red('✗ Apply succeeded but tunnel_token output is missing.'));\n return null;\n case 'no-run-started':\n spin.stop(pc.red('✗ No run started in the workspace yet.'));\n return null;\n case 'run-failed':\n spin.stop(pc.red(`✗ Run finished with status \"${outcome.status}\".`));\n return null;\n case 'timeout':\n spin.stop(pc.red('✗ Timed out after 10 minutes.'));\n return null;\n }\n}\n","/**\n * Detect Homebrew + install packages (formulae or casks) idempotently.\n *\n * Bootstrap shells out to brew once per package — `brew install` is itself\n * idempotent (no-op when already installed) but we list-check first so the\n * wizard can print \"already present\" vs \"installing…\" and skip the\n * potentially-multi-minute download for packages that are already on the\n * Studio.\n *\n * We don't try to AUTO-install Homebrew itself. The official installer is a\n * curl-pipe-bash script that prompts for sudo + has its own UX; the wizard\n * detects its absence, prints the single-line install command, and waits for\n * the operator to confirm before proceeding.\n */\n\nimport { access } from 'node:fs/promises';\n\nimport { safeExeca } from './exec.js';\n\nexport type PackageKind = 'formula' | 'cask';\n\nexport interface PackageSpec {\n name: string;\n kind: PackageKind;\n /** For casks that install a GUI `.app`: if this path already exists, the app\n * is present — possibly installed directly (not via Homebrew) or under a\n * since-renamed cask. In that case `brew list` misses it and\n * `brew install --cask` fails with \"already an App at …\", so we skip the\n * install and report it as already present. (#89) */\n appPath?: string;\n}\n\n/** The package set the runbook installs on the Studio. Casks need GUI\n * authorization on first launch — Docker Desktop in particular requires\n * manual click-through after `brew install --cask docker`. The wizard\n * surfaces that as a follow-up prompt; this list is just what we'd shell\n * out for.\n *\n * Deep-readonly via `as const` — neither the array nor the individual\n * PackageSpec entries can be mutated by accident. */\nexport const STUDIO_PACKAGES = [\n { name: 'git', kind: 'formula' },\n { name: 'gh', kind: 'formula' },\n { name: 'pnpm', kind: 'formula' },\n { name: 'jq', kind: 'formula' },\n { name: 'cloudflared', kind: 'formula' },\n { name: 'rclone', kind: 'formula' },\n { name: 'ollama', kind: 'formula' },\n // Required for the fail-closed image-signature gate in `bootstrap` (#34).\n { name: 'cosign', kind: 'formula' },\n // Homebrew renamed the `docker` cask to `docker-desktop`. The appPath skip\n // means a directly-installed Docker Desktop (the common case) is treated as\n // present rather than tripping `brew install` on the existing app. (#89)\n { name: 'docker-desktop', kind: 'cask', appPath: '/Applications/Docker.app' },\n { name: 'tailscale', kind: 'cask', appPath: '/Applications/Tailscale.app' },\n] as const satisfies readonly PackageSpec[];\n\nexport interface BrewInfo {\n installed: boolean;\n /** Version string when installed (`Homebrew 4.x.y`). Undefined otherwise. */\n version?: string;\n}\n\nexport async function detectBrew(): Promise<BrewInfo> {\n const res = await safeExeca('brew', ['--version']);\n if (res === null || res.exitCode !== 0) {\n return { installed: false };\n }\n // `brew --version` prints e.g. \"Homebrew 4.4.10\".\n const version = res.stdout.split('\\n').find((l) => l.startsWith('Homebrew '));\n return { installed: true, ...(version ? { version } : {}) };\n}\n\n/** The one-shot install command operators paste into their shell when brew is\n * missing. Surfaced verbatim so the wizard can show + the docs can quote\n * the same string. */\nexport const HOMEBREW_INSTALL_COMMAND =\n '/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"';\n\n/** Does a filesystem path exist? Used to detect a GUI app installed outside\n * Homebrew. (#89) */\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Is the named package already installed? A cask carrying an `appPath` counts\n * as present when that app already exists (installed directly, or under a\n * renamed cask) — otherwise `brew list` misses it and `brew install` fails on\n * the existing app. (#89) Otherwise `brew list <name>` exits 0 when yes,\n * non-zero when no; cask vs formula lookup uses different flags.\n */\nexport async function isPackageInstalled(pkg: PackageSpec): Promise<boolean> {\n if (pkg.appPath && (await pathExists(pkg.appPath))) {\n return true;\n }\n const flag = pkg.kind === 'cask' ? '--cask' : '--formula';\n const res = await safeExeca('brew', ['list', flag, pkg.name]);\n return res !== null && res.exitCode === 0;\n}\n\nexport interface InstallResult {\n ok: boolean;\n /** Set when ok=false. Stderr or stdout from the failing command. */\n reason?: string;\n}\n\n/** Install one package. Caller should `isPackageInstalled` first to skip\n * re-installs when speed matters; brew install is itself idempotent. */\nexport async function installPackage(pkg: PackageSpec): Promise<InstallResult> {\n const args =\n pkg.kind === 'cask'\n ? ['install', '--cask', pkg.name]\n : ['install', pkg.name];\n const res = await safeExeca('brew', args);\n if (res === null) {\n return { ok: false, reason: '`brew` not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `brew install ${pkg.name} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface InstallReport {\n installed: PackageSpec[];\n alreadyPresent: PackageSpec[];\n failed: Array<{ pkg: PackageSpec; reason: string }>;\n}\n\n/**\n * Install every package in the spec list. Each is independently logged into\n * one of three buckets so the wizard can show a clean summary. A failure in\n * one package doesn't abort the rest — we want the operator to see the\n * whole landscape and decide which to retry.\n */\nexport async function installPackages(\n packages: readonly PackageSpec[],\n onEach?: (pkg: PackageSpec, status: 'checking' | 'installing' | 'present' | 'installed' | 'failed') => void,\n): Promise<InstallReport> {\n const report: InstallReport = {\n installed: [],\n alreadyPresent: [],\n failed: [],\n };\n for (const pkg of packages) {\n onEach?.(pkg, 'checking');\n if (await isPackageInstalled(pkg)) {\n report.alreadyPresent.push(pkg);\n onEach?.(pkg, 'present');\n continue;\n }\n onEach?.(pkg, 'installing');\n const r = await installPackage(pkg);\n if (r.ok) {\n report.installed.push(pkg);\n onEach?.(pkg, 'installed');\n } else {\n report.failed.push({ pkg, reason: r.reason ?? 'unknown' });\n onEach?.(pkg, 'failed');\n }\n }\n return report;\n}\n","/**\n * Read + write the small set of macOS settings `create-op-node bootstrap`\n * cares about on the Mac Studio:\n *\n * - Hostname and OS version (informational + sanity check we're on Apple Silicon).\n * - Power management (`pmset`): auto-restart-on-power-failure, disk sleep.\n * - FileVault status (`fdesetup`) — informational only; we don't toggle it,\n * since the operator's earlier decision (gate 0.7 in the runbook) was OFF.\n *\n * All probes shell out via `safeExeca` from `lib/exec.ts` so a missing binary\n * (extremely unusual on macOS, but it's the principle) doesn't crash the\n * wizard. Writers use `pmset -a` which requires sudo on macOS — execa\n * propagates the operator's stdin so the password prompt works inline.\n */\n\nimport { safeExeca } from './exec.js';\n\nexport interface SystemSnapshot {\n hostname: string;\n /** `sw_vers -productVersion` output, or `null` when the call failed. */\n osVersion: string | null;\n /** True when `pmset -g` reports `autorestart 1`. */\n autoRestartOnPowerFailure: boolean;\n /** True when `pmset -g` reports `disksleep 0` (i.e. disk sleep DISABLED — the\n * state the bootstrap wants). */\n diskSleepDisabled: boolean;\n /** `true` / `false` when `fdesetup status` reported decisively, `'unknown'`\n * when the call failed or the output was unexpected. We don't toggle\n * FileVault — this is for the operator-facing summary only. */\n fileVaultEnabled: boolean | 'unknown';\n /** True when `uname -m` returns `arm64` (i.e. Apple Silicon Mac).\n * Bootstrap is M-series-only; Intel Macs fail with a clear message. */\n isAppleSilicon: boolean;\n}\n\nexport async function inspectSystem(): Promise<SystemSnapshot> {\n const [hostnameOut, osVersionOut, pmsetOut, fdesetupOut, unameOut] =\n await Promise.all([\n safeExeca('hostname', []),\n safeExeca('sw_vers', ['-productVersion']),\n safeExeca('pmset', ['-g']),\n safeExeca('fdesetup', ['status']),\n safeExeca('uname', ['-m']),\n ]);\n\n return {\n hostname: hostnameOut?.stdout.trim() ?? 'unknown',\n osVersion:\n osVersionOut && osVersionOut.exitCode === 0\n ? osVersionOut.stdout.trim()\n : null,\n autoRestartOnPowerFailure: parsePmsetBool(pmsetOut?.stdout ?? '', 'autorestart', 1),\n diskSleepDisabled: parsePmsetBool(pmsetOut?.stdout ?? '', 'disksleep', 0),\n fileVaultEnabled: parseFileVault(fdesetupOut?.stdout ?? ''),\n isAppleSilicon: (unameOut?.stdout.trim() ?? '') === 'arm64',\n };\n}\n\n/**\n * `pmset -g` prints one space-separated `key value` per line, e.g.:\n *\n * ```\n * System-wide power settings:\n * Currently in use:\n * lidwake 1\n * autorestart 1\n * disksleep 0\n * ```\n *\n * Returns `true` when the named key's value matches `expected`. Tolerant of\n * leading/trailing whitespace; matches first occurrence.\n */\nexport function parsePmsetBool(\n output: string,\n key: string,\n expected: number,\n): boolean {\n for (const line of output.split('\\n')) {\n const match = line.match(/^\\s*([a-z]+)\\s+(-?\\d+)\\s*$/);\n if (match && match[1] === key) {\n return Number(match[2]) === expected;\n }\n }\n return false;\n}\n\n/**\n * `fdesetup status` prints either:\n * - `FileVault is On.`\n * - `FileVault is Off.`\n * - `Encryption in progress: ...` (treat as On)\n * - anything else → `'unknown'`\n */\nexport function parseFileVault(output: string): boolean | 'unknown' {\n const trimmed = output.trim();\n if (/^FileVault is On\\.?/i.test(trimmed)) return true;\n if (/^FileVault is Off\\.?/i.test(trimmed)) return false;\n if (/encryption in progress/i.test(trimmed)) return true;\n return 'unknown';\n}\n\nexport interface SetResult {\n ok: boolean;\n /** Set when `ok=false`. Stderr or stdout from the failing command. */\n reason?: string;\n}\n\n/**\n * Enable auto-restart-on-power-failure (`pmset -a autorestart 1`). Requires\n * sudo; the operator's password prompt is inherited from the parent shell.\n */\nexport async function enableAutoRestartOnPowerFailure(): Promise<SetResult> {\n return runSudoPmset(['autorestart', '1']);\n}\n\n/** Disable disk sleep (`pmset -a disksleep 0`). Same sudo behavior. */\nexport async function disableDiskSleep(): Promise<SetResult> {\n return runSudoPmset(['disksleep', '0']);\n}\n\n/**\n * Read the Studio's unified memory in GB via `sysctl hw.memsize`. Returns\n * `null` when sysctl is unavailable or the output is unparseable — callers\n * fall back to platform defaults in that case.\n *\n * `hw.memsize` reports bytes (e.g. `137438953472` for 128 GB). We divide\n * by 2^30 and round; vendors mostly ship integer GB so the rounding is\n * cosmetic, but the user may see `127` instead of `128` on rare configs.\n */\nexport async function detectUnifiedMemoryGB(): Promise<number | null> {\n const res = await safeExeca('sysctl', ['-n', 'hw.memsize']);\n if (res === null || res.exitCode !== 0) return null;\n const bytes = Number.parseInt(res.stdout.trim(), 10);\n if (!Number.isFinite(bytes) || bytes <= 0) return null;\n return Math.round(bytes / 2 ** 30);\n}\n\nasync function runSudoPmset(args: string[]): Promise<SetResult> {\n const res = await safeExeca('sudo', ['pmset', '-a', ...args]);\n if (res === null) {\n return { ok: false, reason: '`sudo` not on PATH' };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `pmset ${args.join(' ')} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n","/**\n * macOS LaunchAgent for the env-loader that the bootstrap puts in place.\n *\n * The plist's whole job is to inject two env vars into the launchd session at\n * login so Docker Desktop + the container stack see them:\n *\n * PGSODIUM_ROOT_KEY — 64-hex pgsodium master key, read from a `0400` file\n * outside the container so a `docker compose --build`\n * can never wipe it (runbook gate / #791).\n * TUNNEL_TOKEN — Cloudflare Tunnel token, baked into the plist literal.\n *\n * The pgsodium key is materialized as a separate `0400` file (not embedded in\n * the plist) so it can be backed up out-of-band + rotated independently. The\n * Tunnel token gets baked into the plist directly — it's a different rotation\n * cadence (rotates with the Tunnel resource, not on pgsodium key churn).\n *\n * File modes match the runbook:\n * - pgsodium key file: 0400 (owner-read-only)\n * - plist file: 0600 (owner read+write; contains TUNNEL_TOKEN)\n */\n\nimport { mkdir, writeFile, chmod, rm } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport {\n PGSODIUM_KEY_RE,\n SAFE_LAUNCHCTL_VALUE_RE,\n SAFE_PATH_RE,\n SAFE_URL_RE,\n TUNNEL_TOKEN_RE,\n} from './constants.js';\nimport { safeExeca } from './exec.js';\n\nexport const LAUNCH_AGENT_LABEL = 'org.opuspopuli.envloader';\n\nexport interface LaunchAgentPaths {\n /** Absolute path to the 64-hex pgsodium master key file (mode 0400). */\n keyFile: string;\n /** Absolute path to the LaunchAgent plist (mode 0600). */\n plistFile: string;\n}\n\n/** Default on-disk locations the runbook documents. Operators can override. */\nexport function defaultPaths(home: string = homedir()): LaunchAgentPaths {\n return {\n keyFile: `${home}/.config/opuspopuli/pgsodium_root_key`,\n plistFile: `${home}/Library/LaunchAgents/${LAUNCH_AGENT_LABEL}.plist`,\n };\n}\n\nexport interface WriteResult {\n ok: boolean;\n /** Set when ok=false. */\n reason?: string;\n}\n\n/**\n * Write the 64-hex pgsodium master key to `keyFile` with mode 0400. Creates\n * the parent directory tree (mode 0700 on the immediate parent) and refuses\n * non-64-hex input.\n */\nexport async function writePgsodiumKeyFile(\n key: string,\n keyFile: string,\n): Promise<WriteResult> {\n if (!PGSODIUM_KEY_RE.test(key)) {\n return {\n ok: false,\n reason: `pgsodium key must be 64 lowercase hex characters (got ${key.length} chars)`,\n };\n }\n try {\n const dir = dirname(keyFile);\n await mkdir(dir, { recursive: true, mode: 0o700 });\n // Remove any existing key file first. It's written mode 0400 (read-only),\n // so on a re-run `writeFile` (which opens O_WRONLY|O_TRUNC) would fail\n // EACCES — the `mode` option only applies when the file is created, not to\n // an existing one. `force: true` ignores a missing file, keeping the write\n // idempotent across bootstrap re-runs. (#93)\n await rm(keyFile, { force: true });\n await writeFile(keyFile, key, { mode: 0o400 });\n // mkdir's mode option respects umask; chmod is the belt to the suspenders.\n await chmod(dir, 0o700);\n await chmod(keyFile, 0o400);\n return { ok: true };\n } catch (err) {\n return { ok: false, reason: `writing ${keyFile} failed: ${(err as Error).message}` };\n }\n}\n\nexport interface PlistInput {\n /** Path the plist will exec — sourced from defaultPaths() unless an operator\n * overrides on the command line. */\n keyFilePath: string;\n /** Literal Cloudflare Tunnel token; embedded in the plist. Omit for\n * `bootstrap --local-only` flows where no Tunnel is provisioned — the\n * rendered plist will only set PGSODIUM_ROOT_KEY. */\n tunnelToken?: string;\n /** Self-hosted Supabase credentials. When provided, the plist exports each\n * value via `launchctl setenv` so docker-compose-prod.yml — and every\n * Supabase container the compose brings up — sees them. Omit individual\n * fields to skip emitting that var (e.g. for partial re-runs). */\n postgresPassword?: string;\n jwtSecret?: string;\n supabaseAnonKey?: string;\n supabaseServiceRoleKey?: string;\n dashboardPassword?: string;\n /** API Gateway HMAC secret (base64url). When set, plist exports\n * `GATEWAY_HMAC_SECRET`. The derived `API_KEYS` JSON is NOT emitted here:\n * its `{`/`\"`/`:` characters can't pass a `launchctl setenv` value safely,\n * so the op-compose wrapper (and bootstrap's own compose env) render it. */\n gatewayHmacSecret?: string;\n /** Grafana admin password (base64url). When set, plist exports\n * `GRAFANA_ADMIN_PASSWORD`. */\n grafanaAdminPassword?: string;\n /** Public-facing Supabase URL — what browsers + microservices use to reach\n * Kong. Local dev: `http://localhost:8000`. Tunnel: `https://supabase.<domain>`. */\n supabaseUrl?: string;\n}\n\n/**\n * Render the LaunchAgent plist XML. Pure function — caller writes it.\n *\n * The plist runs a `/bin/sh -c` at load that calls `launchctl setenv` for\n * each var. `launchctl setenv` exports into the running launchd session,\n * not just the agent's own env, so anything Docker Desktop launches\n * downstream sees the same values.\n *\n * Required: `PGSODIUM_ROOT_KEY`. Optional: `TUNNEL_TOKEN` + the Supabase\n * credentials — omitted from the setenv list when their inputs are undefined.\n *\n * Model config (`LLM_MODEL` / `EMBEDDINGS_OLLAMA_MODEL` / `NODE_ENV`) is deliberately\n * NOT set here: those are non-secret substitution vars that live in the node's\n * `.env` (single source of truth). A launchctl setenv value would shadow\n * `.env` at compose interpolation time, so it stays out of the launchd session.\n */\nexport function renderLaunchAgentPlist(input: PlistInput): string {\n validatePlistInput(input);\n const command = buildSetenvCommand(input);\n\n return [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">',\n '<plist version=\"1.0\">',\n '<dict>',\n ` <key>Label</key><string>${LAUNCH_AGENT_LABEL}</string>`,\n ' <key>ProgramArguments</key>',\n ' <array>',\n ' <string>/bin/sh</string>',\n ' <string>-c</string>',\n ` <string>${command}</string>`,\n ' </array>',\n ' <key>RunAtLoad</key><true/>',\n '</dict>',\n '</plist>',\n '',\n ].join('\\n');\n}\n\n// Reject any input that would break the XML or inject shell metacharacters\n// into the `sh -c` body launchd runs at every login. Throws on the first\n// offending field. Our own generators only emit safe alphabets, but\n// operators can pass --import-* overrides, so re-validate here.\nfunction validatePlistInput(input: PlistInput): void {\n if (input.tunnelToken !== undefined && !TUNNEL_TOKEN_RE.test(input.tunnelToken)) {\n throw new Error('Tunnel token contains characters outside the expected base64-url set');\n }\n if (!SAFE_PATH_RE.test(input.keyFilePath)) {\n // The keyFilePath gets interpolated into a `sh -c` command run by launchd\n // at every login — reject shell metacharacters even though defaultPaths()\n // never produces one (defense in depth against operator overrides).\n throw new Error(\n `keyFilePath ${JSON.stringify(input.keyFilePath)} contains characters not allowed in a launchd path interpolation`,\n );\n }\n const supabaseFields: Array<[keyof PlistInput, string | undefined]> = [\n ['postgresPassword', input.postgresPassword],\n ['jwtSecret', input.jwtSecret],\n ['supabaseAnonKey', input.supabaseAnonKey],\n ['supabaseServiceRoleKey', input.supabaseServiceRoleKey],\n ['dashboardPassword', input.dashboardPassword],\n ['gatewayHmacSecret', input.gatewayHmacSecret],\n ['grafanaAdminPassword', input.grafanaAdminPassword],\n ];\n for (const [name, value] of supabaseFields) {\n if (value !== undefined && !SAFE_LAUNCHCTL_VALUE_RE.test(value)) {\n throw new Error(`${String(name)} contains characters not allowed in a launchd setenv value`);\n }\n }\n if (input.supabaseUrl !== undefined && !SAFE_URL_RE.test(input.supabaseUrl)) {\n throw new Error(\n `supabaseUrl ${JSON.stringify(input.supabaseUrl)} contains characters not allowed in a launchd setenv value`,\n );\n }\n}\n\n// Assemble the `; `-joined `launchctl setenv` command. PGSODIUM_ROOT_KEY is\n// always set; every other var is emitted only when its value is present.\nfunction buildSetenvCommand(input: PlistInput): string {\n return [\n // Quote the path inside `cat` so a space-containing keyFilePath (allowed by\n // SAFE_PATH_RE) doesn't word-split and leave PGSODIUM_ROOT_KEY empty. The\n // regex rejects `\"`/`$`/backticks, so the inner quotes can't be broken out\n // of — this is word-split safety, not new injection surface. (#36)\n `launchctl setenv PGSODIUM_ROOT_KEY \"$(cat \"${input.keyFilePath}\")\"`,\n ...(input.tunnelToken !== undefined\n ? [`launchctl setenv TUNNEL_TOKEN \"${input.tunnelToken}\"`]\n : []),\n ...(input.postgresPassword !== undefined\n ? [`launchctl setenv POSTGRES_PASSWORD \"${input.postgresPassword}\"`]\n : []),\n ...(input.jwtSecret !== undefined ? [`launchctl setenv JWT_SECRET \"${input.jwtSecret}\"`] : []),\n ...(input.supabaseAnonKey !== undefined\n ? [`launchctl setenv SUPABASE_ANON_KEY \"${input.supabaseAnonKey}\"`]\n : []),\n ...(input.supabaseServiceRoleKey !== undefined\n ? [`launchctl setenv SUPABASE_SERVICE_ROLE_KEY \"${input.supabaseServiceRoleKey}\"`]\n : []),\n ...(input.dashboardPassword !== undefined\n ? [`launchctl setenv DASHBOARD_PASSWORD \"${input.dashboardPassword}\"`]\n : []),\n ...(input.gatewayHmacSecret !== undefined\n ? [`launchctl setenv GATEWAY_HMAC_SECRET \"${input.gatewayHmacSecret}\"`]\n : []),\n ...(input.grafanaAdminPassword !== undefined\n ? [`launchctl setenv GRAFANA_ADMIN_PASSWORD \"${input.grafanaAdminPassword}\"`]\n : []),\n ...(input.supabaseUrl !== undefined\n ? [`launchctl setenv SUPABASE_URL \"${input.supabaseUrl}\"`]\n : []),\n ].join('; ');\n}\n\n/** Write the plist file to disk at mode 0600. */\nexport async function writeLaunchAgentPlist(\n plistFile: string,\n content: string,\n): Promise<WriteResult> {\n try {\n await mkdir(dirname(plistFile), { recursive: true });\n await writeFile(plistFile, content, { mode: 0o600 });\n await chmod(plistFile, 0o600);\n return { ok: true };\n } catch (err) {\n return { ok: false, reason: `writing ${plistFile} failed: ${(err as Error).message}` };\n }\n}\n\n/**\n * Load (or reload) the agent via `launchctl load`. Unload first to handle\n * re-runs; ignore errors on unload since it could just not be loaded yet.\n */\nexport async function loadLaunchAgent(plistFile: string): Promise<WriteResult> {\n await safeExeca('launchctl', ['unload', plistFile]); // ignore errors\n const load = await safeExeca('launchctl', ['load', plistFile]);\n if (load === null) {\n return { ok: false, reason: '`launchctl` not on PATH' };\n }\n if (load.exitCode !== 0) {\n return {\n ok: false,\n reason: `launchctl load failed (${load.exitCode ?? 'signal'}): ${load.stderr || load.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface SetupInput {\n pgsodiumKey: string;\n /** Omit for `bootstrap --local-only` flows — the rendered plist will only\n * set `PGSODIUM_ROOT_KEY`. */\n tunnelToken?: string;\n /** Self-hosted Supabase credentials — generated by `bootstrap` and stored\n * in Keychain. Each value here gets exported into the launchd session\n * via the plist's `launchctl setenv` lines. */\n postgresPassword?: string;\n jwtSecret?: string;\n supabaseAnonKey?: string;\n supabaseServiceRoleKey?: string;\n dashboardPassword?: string;\n /** API Gateway HMAC secret — exported as GATEWAY_HMAC_SECRET. */\n gatewayHmacSecret?: string;\n /** Grafana admin password — exported as GRAFANA_ADMIN_PASSWORD. */\n grafanaAdminPassword?: string;\n /** Public-facing Supabase URL. */\n supabaseUrl?: string;\n paths?: LaunchAgentPaths;\n}\n\nexport interface SetupReport {\n ok: boolean;\n paths: LaunchAgentPaths;\n step?: 'key-file' | 'plist' | 'load';\n reason?: string;\n}\n\n/**\n * One-shot: write the key file, render + write the plist, load the agent.\n * Returns a report that names which step failed (if any) for clean operator\n * messaging.\n */\n// Map the flat SetupInput onto a PlistInput, carrying only the fields that\n// are present (each optional secret is spread in only when defined).\nfunction plistInputFromSetup(input: SetupInput, keyFilePath: string): PlistInput {\n return {\n keyFilePath,\n ...(input.tunnelToken !== undefined ? { tunnelToken: input.tunnelToken } : {}),\n ...(input.postgresPassword !== undefined ? { postgresPassword: input.postgresPassword } : {}),\n ...(input.jwtSecret !== undefined ? { jwtSecret: input.jwtSecret } : {}),\n ...(input.supabaseAnonKey !== undefined ? { supabaseAnonKey: input.supabaseAnonKey } : {}),\n ...(input.supabaseServiceRoleKey !== undefined\n ? { supabaseServiceRoleKey: input.supabaseServiceRoleKey }\n : {}),\n ...(input.dashboardPassword !== undefined ? { dashboardPassword: input.dashboardPassword } : {}),\n ...(input.gatewayHmacSecret !== undefined ? { gatewayHmacSecret: input.gatewayHmacSecret } : {}),\n ...(input.grafanaAdminPassword !== undefined\n ? { grafanaAdminPassword: input.grafanaAdminPassword }\n : {}),\n ...(input.supabaseUrl !== undefined ? { supabaseUrl: input.supabaseUrl } : {}),\n };\n}\n\nexport async function setupLaunchAgent(input: SetupInput): Promise<SetupReport> {\n const paths = input.paths ?? defaultPaths();\n\n const keyResult = await writePgsodiumKeyFile(input.pgsodiumKey, paths.keyFile);\n if (!keyResult.ok) {\n return { ok: false, paths, step: 'key-file', ...(keyResult.reason ? { reason: keyResult.reason } : {}) };\n }\n\n let plistContent: string;\n try {\n plistContent = renderLaunchAgentPlist(plistInputFromSetup(input, paths.keyFile));\n } catch (err) {\n return { ok: false, paths, step: 'plist', reason: (err as Error).message };\n }\n\n const plistResult = await writeLaunchAgentPlist(paths.plistFile, plistContent);\n if (!plistResult.ok) {\n return { ok: false, paths, step: 'plist', ...(plistResult.reason ? { reason: plistResult.reason } : {}) };\n }\n\n const loadResult = await loadLaunchAgent(paths.plistFile);\n if (!loadResult.ok) {\n return { ok: false, paths, step: 'load', ...(loadResult.reason ? { reason: loadResult.reason } : {}) };\n }\n\n return { ok: true, paths };\n}\n\nexport interface TeardownResult {\n ok: boolean;\n /** Per-step outcome. Each step is independently logged so the operator can\n * see \"unload worked but the plist file was already gone.\" */\n steps: Array<{ step: 'unload' | 'rm-plist' | 'rm-key-file'; ok: boolean; reason?: string }>;\n}\n\nexport interface TeardownOptions {\n /** When true, leave the pgsodium key file in place. Useful when the\n * operator wants to unload the LaunchAgent + remove the plist but\n * keep the key as belt-and-suspenders backup. */\n keepKeyFile?: boolean;\n}\n\n/**\n * Reverse of `setupLaunchAgent`: unload the agent via `launchctl unload`,\n * then `rm -f` both the plist and (unless `keepKeyFile`) the pgsodium key\n * file. Idempotent — `rm -f` is a no-op when the file doesn't exist, and\n * we treat `launchctl unload` of an already-unloaded agent as success.\n *\n * Used by `reset`. Also useful as a test seam during integration tests.\n */\nexport async function teardownLaunchAgent(\n paths: LaunchAgentPaths,\n opts: TeardownOptions = {},\n): Promise<TeardownResult> {\n const steps: TeardownResult['steps'] = [];\n\n const unload = await safeExeca('launchctl', ['unload', paths.plistFile]);\n // `launchctl unload` exits non-zero when the agent isn't loaded — that's a\n // successful teardown from our point of view, so a non-zero exit is fine.\n // But a null result means `launchctl` isn't on PATH: nothing was unloaded,\n // so report ok:false rather than a clean teardown that didn't happen. (#36)\n steps.push({\n step: 'unload',\n ok: unload !== null,\n ...(unload === null ? { reason: '`launchctl` not on PATH' } : {}),\n });\n\n try {\n await rm(paths.plistFile, { force: true });\n steps.push({ step: 'rm-plist', ok: true });\n } catch (err) {\n steps.push({ step: 'rm-plist', ok: false, reason: (err as Error).message });\n }\n\n if (!opts.keepKeyFile) {\n try {\n await rm(paths.keyFile, { force: true });\n steps.push({ step: 'rm-key-file', ok: true });\n } catch (err) {\n steps.push({ step: 'rm-key-file', ok: false, reason: (err as Error).message });\n }\n }\n\n return { ok: steps.every((s) => s.ok), steps };\n}\n","/**\n * Renders the `bin/op-compose` wrapper script that lives in the operator's\n * region-node repo.\n *\n * **Why a wrapper instead of a `.env` file:**\n * The project's vault-first principle (#811) says runtime secrets read via\n * `secretsProvider.getSecret()` at point of use; env-on-disk is reserved\n * for bootstrap-critical config. The bootstrap-layer secrets (Postgres\n * password, JWT secret, Supabase admin tokens) ARE bootstrap-critical\n * (Postgres / kong / gotrue can't start without them, and Vault doesn't\n * exist until Postgres is up) — but they don't need to LIVE on disk in\n * plaintext to be available at compose-invocation time.\n *\n * This wrapper reads them from macOS Keychain (FileVault-encrypted at\n * rest) on every invocation and exports them only into the docker compose\n * subprocess's env. No plaintext .env file ever lands on disk; the\n * Keychain is the sole persistent store.\n *\n * **Why launchctl setenv isn't sufficient:**\n * `launchctl setenv` only propagates to processes spawned by launchd\n * AFTER the setenv call. SSH-spawned shells (sshd children) and\n * already-running Terminal.app instances never see the new vars, so\n * `docker compose` hard-fails on `${VAR:?…}` even though `launchctl\n * getenv` confirms launchd has them. The wrapper is shell-agnostic and\n * works the same in every invocation context.\n *\n * **Operator workflow:**\n * $ ./bin/op-compose -f docker-compose-prod.yml up -d\n * $ ./bin/op-compose -f docker-compose-prod.yml pull\n * $ ./bin/op-compose -f docker-compose-prod.yml down\n *\n * The wrapper accepts every argument `docker compose` accepts.\n *\n * **Security:**\n * - Script is mode 0755 (executable, world-readable). The script ITSELF\n * has no secrets — it's a static shell script with the region name\n * baked in. The secrets only exist in process env for the lifetime\n * of the docker compose invocation.\n * - Region name is the only baked-in value (used to scope the Keychain\n * service identifier `org.opuspopuli.<region>`); shell-injection is\n * prevented by the region-validation regex in bootstrap.ts.\n * - Errors when a required Keychain entry is missing point the operator\n * at `create-op-node bootstrap`.\n */\n\nconst REGION_RE = /^[a-z0-9-]{2,32}$/;\n\n/** URL-shape regex for values baked into the wrapper as\n * `export PROMPT_SERVICE_URL=\"…\"`. Matches what bootstrap.ts validates\n * via SAFE_URL_RE — letters, digits, `:`, `/`, `_`, `-`, `.`. Reject\n * shell metacharacters that would inject when the wrapper sources. */\nconst PROMPT_SERVICE_URL_RE = /^[A-Za-z0-9:/_.-]+$/;\n\nexport interface OpComposeScriptInput {\n /** Region slug — gets interpolated into the Keychain service identifier\n * `org.opuspopuli.<region>`. Validated against the same regex bootstrap\n * uses, so a tampered call site can't inject shell metacharacters. */\n region: string;\n /** Default value the wrapper sets for `PROMPT_SERVICE_URL` when nothing\n * in the docker compose service-level env overrides it. For\n * `region-with-prompts` deployments this is the in-network address\n * `http://opuspopuli-prompts:3210` (and the overlay still wins via\n * service-level env). For `region` (remote prompts) it's whatever URL\n * the operator pointed at — typically https://prompts.opuspopuli.org.\n * Omit and the wrapper won't export PROMPT_SERVICE_URL at all. */\n promptServiceUrl?: string;\n}\n\n/**\n * Render the wrapper script. Pure function — caller writes it to disk and\n * `chmod 0755`s the result.\n *\n * Throws on an invalid region label rather than emit a script with a\n * shell-injectable service identifier.\n */\nexport function renderOpComposeScript(input: OpComposeScriptInput): string {\n if (!REGION_RE.test(input.region)) {\n throw new Error(\n `region ${JSON.stringify(input.region)} contains characters not allowed in a launchd / Keychain service identifier`,\n );\n }\n if (input.promptServiceUrl !== undefined && !PROMPT_SERVICE_URL_RE.test(input.promptServiceUrl)) {\n throw new Error(\n `promptServiceUrl ${JSON.stringify(input.promptServiceUrl)} contains characters not allowed in a wrapper export`,\n );\n }\n const promptServiceUrlExport =\n input.promptServiceUrl !== undefined\n ? `# Backend services call prompt-service via this URL. Service-level env\n# from docker-compose-prompt-service.yml overlay (when layered) wins\n# over this default — so colocated deployments still hit\n# http://opuspopuli-prompts:3210 even though we may have a public URL\n# baked in here.\nexport PROMPT_SERVICE_URL=\"\\${PROMPT_SERVICE_URL:-${input.promptServiceUrl}}\"\n\n`\n : '';\n\n return `#!/bin/bash\n# op-compose — wrapper that reads region secrets from macOS Keychain just\n# before invoking \\`docker compose\\`. Auto-generated by\n# \\`create-op-node bootstrap --region ${input.region}\\`. Do not edit by\n# hand; re-run bootstrap to regenerate.\n#\n# Why: launchctl setenv only propagates to launchd-spawned processes, so\n# SSH shells and pre-existing Terminal.app instances never see the env\n# vars bootstrap exports. This wrapper hydrates the docker compose\n# subprocess directly, so every invocation works regardless of how the\n# operator's shell was started.\n#\n# Usage:\n# ./bin/op-compose -f docker-compose-prod.yml up -d\n# ./bin/op-compose -f docker-compose-prod.yml pull\n# ./bin/op-compose -f docker-compose-prod.yml down\n\nset -euo pipefail\n\nSVC=\"org.opuspopuli.${input.region}\"\n\n# macOS \\`security\\` exit codes:\n# 0 = success\n# 36 = errSecInteractionNotAllowed (keychain is locked)\n# 44 = errSecItemNotFound (entry doesn't exist)\n# Earlier wrapper versions conflated 36 and 44 into a generic \"missing\"\n# message, which sent operators down the wrong path (re-bootstrap when\n# the real fix was \\`security unlock-keychain\\`).\nrequire_secret() {\n local account=\"$1\"\n local value\n local rc=0\n value=$(security find-generic-password -s \"$SVC\" -a \"$account\" -w 2>/dev/null) || rc=$?\n case \"$rc\" in\n 0)\n printf '%s' \"$value\"\n return 0\n ;;\n 36)\n cat >&2 <<EOM\nop-compose: keychain is LOCKED — could not read entry '$account'.\nSSH sessions don't auto-unlock the login keychain. Unlock with:\n security unlock-keychain ~/Library/Keychains/login.keychain-db\nThen re-run this command.\nEOM\n exit 1\n ;;\n 44)\n cat >&2 <<EOM\nop-compose: keychain entry '$account' is MISSING under service '$SVC'.\nRun: create-op-node bootstrap --region ${input.region}\nEOM\n exit 1\n ;;\n *)\n echo \"op-compose: \\`security\\` failed reading '$account' (exit $rc).\" >&2\n exit 1\n ;;\n esac\n}\n\n# Used for entries that may legitimately not exist (TUNNEL_TOKEN in\n# local-only mode, prompt-service secrets when colocation isn't active).\n# Treats exit 44 (missing) as a silent OK — returns empty string.\n# Treats exit 36 (locked) as a hard error, since the require_secret calls\n# at the top of the wrapper would have caught this first in normal use;\n# reaching this path means something else bypassed the lock check.\noptional_secret() {\n local account=\"$1\"\n local value\n local rc=0\n value=$(security find-generic-password -s \"$SVC\" -a \"$account\" -w 2>/dev/null) || rc=$?\n case \"$rc\" in\n 0) printf '%s' \"$value\" ;;\n 44) ;; # legitimately absent — empty string is correct\n 36)\n cat >&2 <<EOM\nop-compose: keychain is LOCKED — could not probe optional entry '$account'.\nUnlock with: security unlock-keychain ~/Library/Keychains/login.keychain-db\nEOM\n exit 1\n ;;\n *)\n echo \"op-compose: \\`security\\` failed reading '$account' (exit $rc).\" >&2\n exit 1\n ;;\n esac\n}\n\n# Bootstrap-critical: Postgres + Supabase admin credentials.\nexport PGSODIUM_ROOT_KEY=\"$(require_secret pgsodium-root-key)\"\nexport POSTGRES_PASSWORD=\"$(require_secret postgres-password)\"\nexport JWT_SECRET=\"$(require_secret jwt-secret)\"\nexport SUPABASE_ANON_KEY=\"$(require_secret supabase-anon-key)\"\nexport SUPABASE_SERVICE_ROLE_KEY=\"$(require_secret supabase-service-role-key)\"\nexport DASHBOARD_PASSWORD=\"$(require_secret dashboard-password)\"\n\n# API Gateway HMAC secret. The gateway signs gateway→microservice requests\n# with this (X-HMAC-Auth) in EVERY mode, so it is required. API_KEYS is the\n# JSON map each microservice reads to verify the caller; the api-gateway's\n# key MUST equal GATEWAY_HMAC_SECRET. We render the JSON from the single\n# Keychain value here so the compose \\`\\${GATEWAY_HMAC_SECRET:-…}\\` /\n# \\`\\${API_KEYS:-…}\\` well-known defaults are always overridden with a real\n# per-node value.\nexport GATEWAY_HMAC_SECRET=\"$(require_secret gateway-hmac-secret)\"\nexport API_KEYS=\"{\\\\\"api-gateway\\\\\":\\\\\"\\${GATEWAY_HMAC_SECRET}\\\\\"}\"\n\n# Grafana admin password — overrides the compose \\`admin\\`/\\`admin\\` default.\nexport GRAFANA_ADMIN_PASSWORD=\"$(require_secret grafana-admin-password)\"\n\n# AUTH_JWT_SECRET historically equals JWT_SECRET in dev/UAT — supply that\n# default if the operator hasn't set one independently.\nexport AUTH_JWT_SECRET=\"\\${AUTH_JWT_SECRET:-$JWT_SECRET}\"\n\n# Optional: Cloudflare Tunnel token (only present in non-local-only mode).\nTUNNEL_TOKEN_VAL=\"$(optional_secret tunnel-token)\"\nif [ -n \"$TUNNEL_TOKEN_VAL\" ]; then\n export TUNNEL_TOKEN=\"$TUNNEL_TOKEN_VAL\"\nfi\n\n# SUPABASE_URL is NOT exported here — it's non-secret config that lives in the\n# node .env managed block (create-op-node writes it), which docker compose\n# auto-loads. Exporting it would override that .env value with a stale default\n# and silently break browser-facing auth URLs. See opuspopuli-node#43.\n\n${promptServiceUrlExport}# prompt-service credentials. Always exported — harmless when the operator\n# is NOT colocating prompt-service (the main compose doesn't read these\n# vars; the overlay does). The PROMPT_SERVICE_API_KEYS list is built from\n# the operator's region + the single HMAC key in Keychain, matching the\n# prompt-service env format \\`<region>:<key>,<region>:<key>,…\\`.\nPROMPTS_DB_PASSWORD_VAL=\"$(optional_secret prompts-db-password)\"\nPROMPT_SERVICE_API_KEY_VAL=\"$(optional_secret prompt-service-api-key)\"\nPROMPT_SERVICE_ADMIN_API_KEY_VAL=\"$(optional_secret prompt-service-admin-api-key)\"\nif [ -n \"$PROMPTS_DB_PASSWORD_VAL\" ]; then\n export PROMPTS_DB_PASSWORD=\"$PROMPTS_DB_PASSWORD_VAL\"\nfi\nif [ -n \"$PROMPT_SERVICE_API_KEY_VAL\" ]; then\n export PROMPT_SERVICE_API_KEY=\"$PROMPT_SERVICE_API_KEY_VAL\"\n # API_KEYS env on prompt-service is \\`<region>:<key>,…\\` — render the\n # single-region pair here so prompt-service accepts the same key the\n # backend sends. The prompts team adds additional regions on the\n # central deployment for Phase 2.\n export PROMPT_SERVICE_API_KEYS=\"${input.region}:$PROMPT_SERVICE_API_KEY_VAL\"\nfi\nif [ -n \"$PROMPT_SERVICE_ADMIN_API_KEY_VAL\" ]; then\n export PROMPT_SERVICE_ADMIN_API_KEYS=\"$PROMPT_SERVICE_ADMIN_API_KEY_VAL\"\nfi\n\nexec docker compose \"$@\"\n`;\n}\n","/**\n * Side-effecting installer for the `bin/op-compose` wrapper script.\n *\n * Pure rendering lives in op-compose-script.ts so it stays unit-testable.\n * This file owns:\n * 1. Creating `<repo>/bin/` if needed\n * 2. Atomically writing the script (temp file + rename) so an\n * interrupted bootstrap never leaves a half-written wrapper that\n * `exec` would crash on\n * 3. `chmod 0755` so the operator can run `./bin/op-compose`\n */\n\nimport { chmod, mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { renderOpComposeScript, type OpComposeScriptInput } from './op-compose-script.js';\n\nexport interface InstallOpComposeInput extends OpComposeScriptInput {\n /** Directory containing the compose file. Script lands at `<repoDir>/bin/op-compose`. */\n repoDir: string;\n}\n\nexport interface InstallOpComposeResult {\n ok: boolean;\n /** Absolute path the script was written to, when ok=true. */\n path?: string;\n reason?: string;\n}\n\nexport async function installOpComposeWrapper(\n input: InstallOpComposeInput,\n): Promise<InstallOpComposeResult> {\n let content: string;\n try {\n content = renderOpComposeScript({\n region: input.region,\n ...(input.promptServiceUrl !== undefined ? { promptServiceUrl: input.promptServiceUrl } : {}),\n });\n } catch (err) {\n return { ok: false, reason: (err as Error).message };\n }\n\n const binDir = join(input.repoDir, 'bin');\n const target = join(binDir, 'op-compose');\n const tmp = `${target}.tmp.${process.pid}`;\n\n try {\n await mkdir(binDir, { recursive: true });\n await writeFile(tmp, content, { mode: 0o755 });\n // mkdir/writeFile respect umask; chmod ensures 0755 regardless.\n await chmod(tmp, 0o755);\n await rename(tmp, target); // atomic on POSIX\n return { ok: true, path: target };\n } catch (err) {\n return { ok: false, reason: `writing ${target} failed: ${(err as Error).message}` };\n }\n}\n","/**\n * Docker compose + ghcr.io login orchestration.\n *\n * Three concerns this lib covers:\n *\n * 1. Authenticate Docker to ghcr.io using the operator's `gh auth token`,\n * piped on stdin so the token never lands in argv.\n * 2. `docker compose pull / up -d` against the prod compose set in the\n * operator's node repo checkout.\n * 3. Poll `docker compose ps --format json` until every service reports\n * `(healthy)`, with the same two-phase-budget pattern as lib/polling.ts\n * (containers can take a while to start showing up; healthy check then\n * runs on its own clock).\n */\n\nimport { safeExeca } from './exec.js';\n\n/** Default registry. Constant so tests + the bootstrap command read the same\n * value and an op-region migration to a different registry only changes\n * one place. */\nexport const GHCR_REGISTRY = 'ghcr.io';\n\nexport interface LoginResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Authenticate Docker to ghcr.io. Pulls the token from `gh auth token`,\n * pipes it on stdin to `docker login --password-stdin`. The username comes\n * from `gh api user --jq .login`. Three execa calls; failure at any point\n * reports cleanly with the responsible step.\n */\nexport async function loginToGhcr(): Promise<LoginResult> {\n const tokenRes = await safeExeca('gh', ['auth', 'token']);\n if (tokenRes === null) return { ok: false, reason: '`gh` not installed' };\n if (tokenRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `gh auth token failed (${tokenRes.exitCode ?? 'signal'}): ${tokenRes.stderr || tokenRes.stdout}`,\n };\n }\n const token = tokenRes.stdout.trim();\n if (token.length === 0) {\n return { ok: false, reason: 'gh auth token returned empty — run `gh auth login` first' };\n }\n\n const userRes = await safeExeca('gh', ['api', 'user', '--jq', '.login']);\n if (userRes === null || userRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `couldn't resolve GitHub user via gh api: ${userRes?.stderr || userRes?.stdout || 'gh missing'}`,\n };\n }\n const user = userRes.stdout.trim();\n if (user.length === 0) {\n return { ok: false, reason: 'gh api user returned empty — gh not signed in' };\n }\n\n const loginRes = await safeExeca(\n 'docker',\n ['login', GHCR_REGISTRY, '-u', user, '--password-stdin'],\n { input: token },\n );\n if (loginRes === null) return { ok: false, reason: '`docker` not installed' };\n if (loginRes.exitCode !== 0) {\n return {\n ok: false,\n reason: `docker login ${GHCR_REGISTRY} failed (${loginRes.exitCode ?? 'signal'}): ${loginRes.stderr || loginRes.stdout}`,\n };\n }\n return { ok: true };\n}\n\n// ----------------------------------------------------------------------------\n// Compose pull / up\n// ----------------------------------------------------------------------------\n\nexport interface ComposeOptions {\n /** Compose file paths, in order. Becomes `-f X -f Y …` on the command line. */\n files: string[];\n /** Working directory the compose command runs from. */\n cwd: string;\n /** Optional env-file flag, in the same convention as `--env-file`. */\n envFile?: string;\n /** Compose profiles to activate. Repeats as `--profile X --profile Y`. The\n * template's `cloudflared` service is gated behind the `public` profile;\n * bootstrap in local-only mode passes an empty array so cloudflared\n * stays down. */\n profiles?: ReadonlyArray<string>;\n /** Extra env vars passed to the docker compose subprocess. Used by\n * bootstrap to hydrate Keychain-loaded secrets (POSTGRES_PASSWORD,\n * JWT_SECRET, the Supabase JWTs, etc.) at compose-invocation time\n * without writing them to a plaintext `.env` file on disk. Per the\n * vault-first principle (#811), the wrapper script (`bin/op-compose`)\n * is the operator-facing version of the same pattern. */\n env?: NodeJS.ProcessEnv;\n}\n\nfunction composeArgs(opts: ComposeOptions, sub: string[]): string[] {\n const files = opts.files.flatMap((f) => ['-f', f]);\n const env = opts.envFile ? ['--env-file', opts.envFile] : [];\n const profiles = (opts.profiles ?? []).flatMap((pr) => ['--profile', pr]);\n return ['compose', ...files, ...env, ...profiles, ...sub];\n}\n\nexport interface ComposeResult {\n ok: boolean;\n reason?: string;\n}\n\n/** Build the execa options object once — both env and cwd flow from\n * ComposeOptions to safeExeca so subprocess hydration works uniformly. */\nfunction execOpts(opts: ComposeOptions): { cwd: string; env?: NodeJS.ProcessEnv } {\n return opts.env ? { cwd: opts.cwd, env: opts.env } : { cwd: opts.cwd };\n}\n\n/** `docker compose -f … pull`. Idempotent on first run; pulls new image tags. */\nexport async function composePull(opts: ComposeOptions): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['pull']), execOpts(opts));\n return result(res, 'compose pull');\n}\n\n/** Registry prefix for images published + cosign-signed by the opuspopuli\n * release workflow. Only these are verifiable against the release identity;\n * third-party images (postgres, kong, gotrue, ollama, …) are unsigned by us. */\nexport const OPUSPOPULI_IMAGE_PREFIX = 'ghcr.io/opuspopuli/';\n\n/**\n * `docker compose … config --images` — the resolved image refs the stack will\n * pull, one per line. Returns `null` when the command can't run (docker\n * missing) or config fails (e.g. a required `${VAR:?}` interpolation is unset),\n * so the caller can treat \"couldn't enumerate\" distinctly from \"no images\".\n */\nexport async function composeConfigImages(opts: ComposeOptions): Promise<string[] | null> {\n const res = await safeExeca('docker', composeArgs(opts, ['config', '--images']), execOpts(opts));\n if (res === null || res.exitCode !== 0) return null;\n return res.stdout\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\n/** Keep only the images the opuspopuli release workflow signs — the subset\n * cosign can verify against the release identity. Third-party base images are\n * dropped (they'd fail verification against our identity). Pure helper. */\nexport function filterVerifiableImages(\n images: string[],\n prefix: string = OPUSPOPULI_IMAGE_PREFIX,\n): string[] {\n return images.filter((img) => img.startsWith(prefix));\n}\n\n/** `docker compose -f … up -d --remove-orphans`. */\nexport async function composeUp(opts: ComposeOptions): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['up', '-d', '--remove-orphans']), execOpts(opts));\n return result(res, 'compose up');\n}\n\n/**\n * `docker compose -f … rm -sfv <service>`. Stops + removes a single service +\n * its anonymous volumes. Used by `bootstrap --local-only` to evict a\n * cloudflared container left over from a prior public bootstrap; otherwise it\n * lingers in `compose ps` and the health-check loop demands it reach healthy.\n *\n * Returns ok=true when the service doesn't exist (compose treats \"rm a\n * service that isn't there\" as a no-op exit 0), so callers can call this\n * unconditionally.\n */\nexport async function composeRemoveService(\n opts: ComposeOptions,\n service: string,\n): Promise<ComposeResult> {\n const res = await safeExeca('docker', composeArgs(opts, ['rm', '-sfv', service]), execOpts(opts));\n return result(res, `compose rm ${service}`);\n}\n\nexport interface ComposeDownOptions extends ComposeOptions {\n /** When true, adds `-v` — destroys named volumes. The default false is the\n * safe choice: stop the stack but preserve the database. Callers must\n * ALWAYS surface a typed confirmation before flipping this on. */\n wipeVolumes?: boolean;\n /** When true, adds `--remove-orphans` — drops containers from compose files\n * no longer present. Useful on first-after-rename runs. */\n removeOrphans?: boolean;\n /** When set, adds `--rmi <mode>` to also remove the images.\n * - `'all'`: removes all images referenced by services (forces re-pull\n * on next `compose up`).\n * - `'local'`: removes only images that don't have a custom tag (i.e.,\n * locally-built ones; pulled images stay).\n * Use 'all' for true \"wipe everything and start over\" iteration loops. */\n removeImages?: 'all' | 'local';\n}\n\n/** `docker compose -f … down [-v] [--remove-orphans] [--rmi MODE]`. */\nexport async function composeDown(opts: ComposeDownOptions): Promise<ComposeResult> {\n const flags: string[] = ['down'];\n if (opts.wipeVolumes) flags.push('-v');\n if (opts.removeOrphans) flags.push('--remove-orphans');\n if (opts.removeImages) flags.push('--rmi', opts.removeImages);\n const label = [\n 'compose down',\n opts.wipeVolumes ? '-v' : '',\n opts.removeImages ? `--rmi ${opts.removeImages}` : '',\n ]\n .filter(Boolean)\n .join(' ');\n const res = await safeExeca('docker', composeArgs(opts, flags), execOpts(opts));\n return result(res, label);\n}\n\n/**\n * `docker logout <registry>`.\n *\n * Behavior on \"not currently logged in\" varies by version: Docker 24+ returns\n * exit 0 with \"Not logged in to <registry>\" on stdout, but older Docker\n * Desktop releases (and some credential-helper configurations) return a\n * non-zero exit instead. `reset` therefore renders a non-zero outcome as a\n * warning rather than a failure — the goal is \"ensure no creds remain,\" and\n * \"no creds existed to begin with\" satisfies that goal.\n *\n * Note: this only clears the credential-store entry. If the operator's\n * credential helper has cached the token elsewhere, or if `~/.docker/config.json`\n * has stale entries from a different host, those need separate cleanup.\n */\nexport async function dockerLogout(registry: string = GHCR_REGISTRY): Promise<ComposeResult> {\n const res = await safeExeca('docker', ['logout', registry]);\n return result(res, `docker logout ${registry}`);\n}\n\nfunction result(\n res: { exitCode: number | undefined; stdout: string; stderr: string } | null,\n label: string,\n): ComposeResult {\n if (res === null) return { ok: false, reason: '`docker` not installed' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `${label} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\n// ----------------------------------------------------------------------------\n// Compose ps — for the health check loop\n// ----------------------------------------------------------------------------\n\nexport interface ContainerSnapshot {\n name: string;\n /** `running`, `exited`, etc. — the Docker container state. */\n state: string;\n /** `healthy`, `unhealthy`, `starting`, or `none` (no healthcheck defined). */\n health: 'healthy' | 'unhealthy' | 'starting' | 'none';\n exitCode: number | null;\n}\n\n/**\n * Parse `docker compose ps --format json` output. Compose v2 emits one JSON\n * object per line for each container. We tolerate either format (NDJSON or\n * a single-line JSON array, depending on version).\n */\nexport function parseComposePs(stdout: string): ContainerSnapshot[] {\n // First try NDJSON line-by-line.\n const trimmed = stdout.trim();\n if (trimmed.length === 0) return [];\n\n const lines = trimmed.split('\\n').map((l) => l.trim()).filter((l) => l.length > 0);\n const out: ContainerSnapshot[] = [];\n\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as unknown;\n if (Array.isArray(parsed)) {\n for (const item of parsed) out.push(normalize(item));\n } else {\n out.push(normalize(parsed));\n }\n } catch {\n // Skip non-JSON lines (compose sometimes emits warnings on stdout).\n }\n }\n return out;\n}\n\nfunction normalize(raw: unknown): ContainerSnapshot {\n const r = (raw ?? {}) as Record<string, unknown>;\n const name = (r['Name'] as string) ?? (r['Service'] as string) ?? '<unknown>';\n const state = ((r['State'] as string) ?? 'unknown').toLowerCase();\n const healthRaw = ((r['Health'] as string) ?? '').toLowerCase();\n const health: ContainerSnapshot['health'] =\n healthRaw === 'healthy' || healthRaw === 'unhealthy' || healthRaw === 'starting'\n ? healthRaw\n : 'none';\n const exitCodeRaw = r['ExitCode'];\n const exitCode = typeof exitCodeRaw === 'number' ? exitCodeRaw : null;\n return { name, state, health, exitCode };\n}\n\n/**\n * `docker compose ps --format json`. Returns:\n *\n * - `null` when the call itself failed (docker missing, compose file wrong,\n * non-zero exit). The caller can distinguish a real failure from a\n * stack-not-up-yet case.\n * - `[]` when the call succeeded but no containers are listed yet (compose\n * up still in flight).\n * - `ContainerSnapshot[]` populated on success.\n */\nexport async function composePs(opts: ComposeOptions): Promise<ContainerSnapshot[] | null> {\n const res = await safeExeca('docker', composeArgs(opts, ['ps', '--format', 'json']), execOpts(opts));\n if (res === null || res.exitCode !== 0) return null;\n return parseComposePs(res.stdout);\n}\n\n// ----------------------------------------------------------------------------\n// Health-check loop\n// ----------------------------------------------------------------------------\n\nexport interface WaitForHealthyOptions {\n /** Container names that MUST be healthy before we return success. Empty\n * array means \"every container compose ps reports must be healthy or no-op\n * (i.e. state=exited with code 0 — db-migrate-style one-shots).\" */\n requireHealthy?: string[];\n /** Max time to wait, ms. Default 5 minutes. */\n timeoutMs?: number;\n /** Poll interval, ms. Default 5s. */\n pollMs?: number;\n /** Optional progress callback. */\n onPoll?: (snapshots: ContainerSnapshot[]) => void;\n}\n\nexport type HealthOutcome =\n | { kind: 'healthy'; snapshots: ContainerSnapshot[] }\n | { kind: 'unhealthy'; snapshots: ContainerSnapshot[]; problem: string }\n | { kind: 'timeout'; snapshots: ContainerSnapshot[] };\n\nexport interface WaitForHealthyDeps {\n ps: (opts: ComposeOptions) => Promise<ContainerSnapshot[] | null>;\n sleep: (ms: number) => Promise<void>;\n now: () => number;\n}\n\nexport const realWaitDeps: WaitForHealthyDeps = {\n ps: composePs,\n sleep: (ms) => new Promise((res) => setTimeout(res, ms)),\n now: () => Date.now(),\n};\n\n/**\n * Poll `compose ps` until either every container reaches a happy terminal\n * state or the timeout fires. A \"happy\" state is:\n *\n * - `state=running` AND `health` ∈ {healthy, none}\n * - `state=exited` AND `exitCode === 0` (one-shot containers like db-migrate)\n *\n * `state=running` + `health=starting` keeps polling; `health=unhealthy` or\n * `state=exited` with non-zero exit returns immediately as `unhealthy`.\n */\n// Map a single non-empty poll result to a terminal HealthOutcome, or null\n// when the caller should keep polling ('pending' or no containers yet).\nfunction terminalOutcome(\n ps: ContainerSnapshot[],\n requireHealthy?: string[],\n): HealthOutcome | null {\n if (ps.length === 0) return null;\n const verdict = assessHealth(ps, requireHealthy);\n if (verdict.kind === 'healthy') return { kind: 'healthy', snapshots: ps };\n if (verdict.kind === 'unhealthy') {\n return { kind: 'unhealthy', snapshots: ps, problem: verdict.problem ?? 'unhealthy' };\n }\n return null;\n}\n\nexport async function waitForHealthy(\n composeOpts: ComposeOptions,\n options: WaitForHealthyOptions = {},\n deps: WaitForHealthyDeps = realWaitDeps,\n): Promise<HealthOutcome> {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000;\n const basePollMs = options.pollMs ?? 5 * 1000;\n const start = deps.now();\n let last: ContainerSnapshot[] = [];\n let pollCount = 0;\n\n while (deps.now() - start < timeoutMs) {\n pollCount++;\n const ps = await deps.ps(composeOpts);\n if (ps !== null) {\n last = ps;\n options.onPoll?.(ps);\n // A terminal verdict (healthy / unhealthy) returns immediately;\n // 'pending' (null here) falls through to the sleep + next iteration.\n const outcome = terminalOutcome(ps, options.requireHealthy);\n if (outcome) return outcome;\n }\n // Gentle backoff: 1× the base poll for the first 3 polls (fast feedback\n // while containers are settling), 2× after that. Caps wasted subprocess\n // startup on long timeouts without slowing down the typical case.\n const interval = pollCount < 3 ? basePollMs : basePollMs * 2;\n await deps.sleep(interval);\n }\n return { kind: 'timeout', snapshots: last };\n}\n\ninterface AssessVerdict {\n kind: 'healthy' | 'unhealthy' | 'pending';\n problem?: string;\n}\n\nexport function assessHealth(\n snapshots: ContainerSnapshot[],\n requireHealthy?: string[],\n): AssessVerdict {\n // Hard failures short-circuit regardless of the required-list mode.\n const hard = firstHardFailure(snapshots);\n if (hard) return hard;\n\n const required = requireHealthy ?? [];\n return required.length > 0\n ? assessRequired(snapshots, required)\n : assessAllRunning(snapshots);\n}\n\n// Hard failure conditions: any unhealthy, any exited-with-non-zero.\nfunction firstHardFailure(snapshots: ContainerSnapshot[]): AssessVerdict | null {\n for (const s of snapshots) {\n if (s.health === 'unhealthy') {\n return { kind: 'unhealthy', problem: `${s.name} reports unhealthy` };\n }\n if (s.state === 'exited' && (s.exitCode ?? 0) !== 0) {\n return { kind: 'unhealthy', problem: `${s.name} exited with code ${s.exitCode}` };\n }\n }\n return null;\n}\n\n// The caller specified a required-healthy list — gate on exactly those.\nfunction assessRequired(snapshots: ContainerSnapshot[], required: string[]): AssessVerdict {\n const byName = new Map(snapshots.map((s) => [s.name, s]));\n for (const name of required) {\n const s = byName.get(name);\n if (!s) return { kind: 'pending' };\n if (s.state === 'exited' && s.exitCode === 0) continue;\n if (s.state !== 'running') return { kind: 'pending' };\n if (s.health === 'starting') return { kind: 'pending' };\n if (s.health === 'unhealthy') {\n return { kind: 'unhealthy', problem: `${s.name} reports unhealthy` };\n }\n }\n return { kind: 'healthy' };\n}\n\n// No required list — all snapshots must be in a happy state.\nfunction assessAllRunning(snapshots: ContainerSnapshot[]): AssessVerdict {\n for (const s of snapshots) {\n if (s.state === 'exited' && s.exitCode === 0) continue;\n if (s.state !== 'running') return { kind: 'pending' };\n if (s.health === 'starting') return { kind: 'pending' };\n }\n return { kind: 'healthy' };\n}\n","/**\n * `cosign verify` wrapper for the verify wizard.\n *\n * Keyless verification path: cosign maps the image to a Fulcio-issued\n * certificate, checks the certificate's identity (GitHub Actions workflow URL)\n * + OIDC issuer, AND consults the Rekor transparency log (cosign default,\n * `rekor.sigstore.dev`) for an inclusion proof. So a passing verify means\n * the image was signed by the expected workflow AND that signing event is\n * publicly logged.\n *\n * If `cosign` isn't on PATH we report it as a skip rather than a failure —\n * verify can still pass without it (TLS + GraphQL probes are load-bearing).\n */\n\nimport { safeExeca } from './exec.js';\n\nexport const COSIGN_OIDC_ISSUER = 'https://token.actions.githubusercontent.com';\n\nexport interface CosignVerifyInput {\n image: string;\n /** Glob/regex passed as `--certificate-identity-regexp`. Defaults to the\n * publishing workflow path in the opuspopuli-node template. */\n certificateIdentityRegexp?: string;\n /** OIDC issuer that signed the image. Defaults to GitHub Actions. */\n certificateOidcIssuer?: string;\n}\n\nexport type CosignVerifyResult =\n | { ok: true; output: string }\n | { ok: false; skipped: true; reason: string }\n | { ok: false; skipped: false; reason: string };\n\n// Ref-pinned to the exact publishing workflow. Each `ghcr.io/opuspopuli/*`\n// image is keyless-signed by its source repo's `release.yml` on push to main\n// (or ad-hoc `workflow_dispatch` from a fix branch for an arm64 build) — both\n// carry a `.../release.yml@refs/heads/<branch>` certificate identity. We pin\n// the workflow FILE (not `.../workflows/.*`, which would accept any workflow in\n// the repo that ever obtained a Fulcio cert) and allow any `refs/heads/` branch\n// so legitimate ad-hoc builds still verify. (#34)\n//\n// The org publishes images from MORE than one repo: the `opuspopuli` monorepo\n// (api, users, documents, knowledge, region, workers) AND the private\n// `prompt-service` repo (`ghcr.io/opuspopuli/prompt-service`). Both sign with\n// their own `release.yml`, so the pin is an explicit allowlist of those repos\n// rather than the single monorepo — an arbitrary/spoofed org repo (`…/evil/…`)\n// still fails. Add a repo here when a new one starts publishing signed images.\n// (#94)\n//\n// Provenance of each segment (the cert SAN is GitHub's OIDC `job_workflow_ref`,\n// format `<owner>/<repo>/.github/workflows/<file>@<ref>`):\n// - `OpusPopuli/(opuspopuli|prompt-service)` — the canonical repo paths, the\n// exact casing OIDC emits.\n// - `release.yml@refs/heads/` — the signing workflow + trigger (push to main\n// / workflow_dispatch), confirmed in each repo's release.yml.\n// The fail-closed bootstrap gate exposes `--certificate-identity-regexp` as the\n// escape valve for any not-yet-listed signer.\nexport const DEFAULT_IDENTITY_REGEXP =\n '^https://github\\\\.com/OpusPopuli/(?:opuspopuli|prompt-service)/\\\\.github/workflows/release\\\\.yml@refs/heads/.*$';\n\n/**\n * Verify a single OCI image's cosign signature against the GitHub Actions\n * OIDC issuer. Returns one of three shapes:\n *\n * - `{ ok: true }` — signature valid.\n * - `{ ok: false, skipped: true }` — cosign binary not on PATH; caller\n * should render this as a warning, not a failure.\n * - `{ ok: false, skipped: false }` — cosign ran and rejected the image.\n */\nexport async function cosignVerifyImage(input: CosignVerifyInput): Promise<CosignVerifyResult> {\n const idRegex = input.certificateIdentityRegexp ?? DEFAULT_IDENTITY_REGEXP;\n const issuer = input.certificateOidcIssuer ?? COSIGN_OIDC_ISSUER;\n\n const res = await safeExeca('cosign', [\n 'verify',\n '--certificate-identity-regexp',\n idRegex,\n '--certificate-oidc-issuer',\n issuer,\n input.image,\n ]);\n\n if (res === null) {\n return {\n ok: false,\n skipped: true,\n reason: '`cosign` not on PATH (install with `brew install cosign` and rerun to enable signature checks)',\n };\n }\n if (res.exitCode !== 0) {\n return {\n ok: false,\n skipped: false,\n reason: `cosign verify ${input.image} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true, output: res.stdout || res.stderr };\n}\n","/**\n * Ollama service + model management.\n *\n * Ollama is installed via Homebrew (handled by `lib/homebrew.ts`) and started\n * as a `brew services` job. This lib covers what the wizard does after that:\n *\n * - HTTP health check on `localhost:11434` (the running daemon).\n * - List installed models via the HTTP API (avoids parsing `ollama list`'s\n * human-formatted output).\n * - Pull a model — shells out to `ollama pull <name>` because the HTTP\n * `/api/pull` endpoint streams NDJSON progress and is awkward to consume.\n * - Warm a model with a single trivial generation so the first user request\n * doesn't pay a ~90s cold-start.\n * - Probe that containers can reach the host's Ollama via\n * `host.docker.internal` — common Docker Desktop configuration mistake.\n */\n\nimport { safeExeca } from './exec.js';\n\nexport const OLLAMA_URL = 'http://localhost:11434';\n\n/** Health probe (`/api/tags`) is a metadata read — it should answer almost\n * instantly, so a short timeout keeps a hung daemon from stalling bootstrap. */\nconst OLLAMA_HEALTH_TIMEOUT_MS = 5_000;\n\n/** Warming (`/api/generate`) loads the model into VRAM on first call, which\n * for a 50 GB model legitimately takes minutes — hence a generous cap that\n * still bounds a truly-wedged daemon. */\nconst OLLAMA_WARM_TIMEOUT_MS = 120_000;\n\n/** Conservative default LLM for the `--yes` / scripted path and the fallback\n * when unified-memory detection fails. Sized to fit a 16 GB machine once the\n * ~22-container stack + Postgres take their share — capable enough to\n * validate the inference path end-to-end. Interactive bootstrap tiers UP from\n * here based on detected RAM (see `recommendLlmModel`); operators can override\n * at bootstrap time with `--llm-model`. */\nexport const DEFAULT_LLM_MODEL = 'qwen2.5:7b';\n\n/** Default embedding model used by the knowledge service when\n * `EMBEDDINGS_PROVIDER=ollama`. With the default `xenova` (in-process)\n * provider, this isn't pulled. Operators can override with\n * `--embedding-model`. */\nexport const DEFAULT_EMBEDDING_MODEL = 'nomic-embed-text';\n\n/** Where embeddings are computed: `xenova` runs in-process (no Ollama pull\n * needed), `ollama` uses the host daemon with DEFAULT_EMBEDDING_MODEL. */\nexport type EmbeddingsProvider = 'xenova' | 'ollama';\n\n/** Platform default — in-process embeddings, so a fresh node needs no\n * embedding-model pull unless the operator opts into the Ollama provider. */\nexport const DEFAULT_EMBEDDINGS_PROVIDER: EmbeddingsProvider = 'xenova';\n\n/** Default model pull set for `bootstrap`. Kept as a `as const`-typed array\n * so existing code can iterate without re-deriving from the two scalars. */\nexport const DEFAULT_MODELS = [DEFAULT_LLM_MODEL, DEFAULT_EMBEDDING_MODEL] as const;\n\n/** Pinned alpine tag for the host.docker.internal probe. Latest is fine in\n * practice (the image only runs `curl`) but pinning keeps the probe\n * reproducible across operator machines. Bump when alpine cuts a major. */\nexport const PROBE_ALPINE_TAG = '3.20';\n\nexport interface OllamaHealth {\n /** True when the daemon answered the `/api/tags` probe with 200. */\n reachable: boolean;\n /** Names of currently-installed models, when reachable. */\n models: string[];\n}\n\n/**\n * Probe the daemon. We use `/api/tags` because it's the cheapest endpoint\n * that proves both reachability AND that the server is past initial bring-up\n * (a bare TCP-accept-but-not-ready Ollama returns 404 here, not 200).\n */\n/**\n * Try to start the Ollama service via `brew services start ollama`.\n * Idempotent — brew services no-ops on an already-started service. Returns\n * `ok: false` only if brew itself is missing or the start command errored\n * for a non-trivial reason.\n */\nexport async function startOllamaService(): Promise<{ ok: boolean; reason?: string }> {\n const res = await safeExeca('brew', ['services', 'start', 'ollama']);\n if (res === null) return { ok: false, reason: '`brew` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `brew services start ollama failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport async function checkOllamaHealth(url: string = OLLAMA_URL): Promise<OllamaHealth> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), OLLAMA_HEALTH_TIMEOUT_MS);\n try {\n const res = await fetch(`${url}/api/tags`, { signal: ctrl.signal });\n if (!res.ok) return { reachable: false, models: [] };\n const body = (await res.json()) as { models?: Array<{ name?: string }> };\n const models = (body.models ?? [])\n .map((m) => m.name ?? '')\n .filter((n) => n.length > 0);\n return { reachable: true, models };\n } catch {\n // Unreachable, non-200, non-JSON, or timed out (AbortError) — all \"not\n // healthy\" from the caller's perspective.\n return { reachable: false, models: [] };\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Is `configured` present in the `installed` model list (from\n * `checkOllamaHealth().models` / `ollama list`)?\n *\n * Ollama treats a bare model name as its `:latest` tag — `ollama pull qwen2.5`\n * installs `qwen2.5:latest`, and `/api/tags` reports the fully-qualified name.\n * So we normalize BOTH sides to an explicit tag before comparing: a config of\n * `qwen2.5` matches an installed `qwen2.5:latest`, and vice-versa. A tag\n * mismatch (the incident: configured `qwen3.5:35b` vs installed `qwen2.5:72b`)\n * correctly returns false. Pure helper — the presence-check core for `verify`.\n */\nexport function modelPresent(configured: string, installed: readonly string[]): boolean {\n const norm = (m: string): string => (m.includes(':') ? m : `${m}:latest`);\n const target = norm(configured);\n return installed.some((m) => norm(m) === target);\n}\n\nexport interface PullResult {\n ok: boolean;\n /** Set when ok=false. */\n reason?: string;\n}\n\n/**\n * Pull a model. `ollama pull` is idempotent — re-pulling a present model is\n * a fast no-op — so we don't pre-check installation.\n */\nexport async function pullModel(name: string): Promise<PullResult> {\n const res = await safeExeca('ollama', ['pull', name]);\n if (res === null) return { ok: false, reason: '`ollama` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason: `ollama pull ${name} failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { ok: true };\n}\n\nexport interface WarmResult {\n ok: boolean;\n reason?: string;\n}\n\n/**\n * Send a trivial `/api/generate` call so the model loads into memory. First\n * request on a cold daemon can take 30-90s; that latency lands on the wizard,\n * not on a real user. We stream=false + ignore the response body.\n */\nexport async function warmModel(name: string, url: string = OLLAMA_URL): Promise<WarmResult> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), OLLAMA_WARM_TIMEOUT_MS);\n try {\n const res = await fetch(`${url}/api/generate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model: name, prompt: 'hi', stream: false }),\n signal: ctrl.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n return {\n ok: false,\n reason: `warm ${name} returned HTTP ${res.status}: ${text || '(no body)'}`,\n };\n }\n // Drain the body to ensure the model finished loading.\n await res.text();\n return { ok: true };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `warm ${name} timed out after ${OLLAMA_WARM_TIMEOUT_MS / 1000}s`\n : `warm ${name} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Verify Docker containers can reach the host's Ollama via\n * `host.docker.internal`. Operators sometimes disable that hostname in Docker\n * Desktop settings; this probe catches the misconfig before the stack comes\n * up and fails opaquely.\n */\nexport async function probeHostDockerInternal(): Promise<{ ok: boolean; reason?: string }> {\n const res = await safeExeca('docker', [\n 'run',\n '--rm',\n `alpine:${PROBE_ALPINE_TAG}`,\n 'sh',\n '-c',\n 'apk add --no-cache curl >/dev/null 2>&1 && curl -fsS http://host.docker.internal:11434/api/tags',\n ]);\n if (res === null) return { ok: false, reason: '`docker` not on PATH' };\n if (res.exitCode !== 0) {\n return {\n ok: false,\n reason:\n `container couldn't reach host.docker.internal:11434 — check Docker Desktop ` +\n `settings → Resources → Network → Enable host.docker.internal`,\n };\n }\n return { ok: true };\n}\n\nexport interface SetupReport {\n pulled: string[];\n alreadyPresent: string[];\n failed: Array<{ model: string; reason: string }>;\n warmed: string[];\n}\n\n/**\n * Pull each model in `models` (skipping already-present ones) and warm the\n * first one. Continues past per-model failures so the operator sees the\n * whole landscape.\n */\nexport async function setupModels(\n models: readonly string[],\n onProgress?: (model: string, status: 'present' | 'pulling' | 'pulled' | 'failed' | 'warming' | 'warmed') => void,\n): Promise<SetupReport> {\n const report: SetupReport = {\n pulled: [],\n alreadyPresent: [],\n failed: [],\n warmed: [],\n };\n\n const health = await checkOllamaHealth();\n const present = new Set(health.models);\n\n for (const m of models) {\n if (present.has(m)) {\n report.alreadyPresent.push(m);\n onProgress?.(m, 'present');\n continue;\n }\n onProgress?.(m, 'pulling');\n const r = await pullModel(m);\n if (r.ok) {\n report.pulled.push(m);\n onProgress?.(m, 'pulled');\n } else {\n report.failed.push({ model: m, reason: r.reason ?? 'unknown' });\n onProgress?.(m, 'failed');\n }\n }\n\n // Warm the first model that exists by name in the user-supplied list, not\n // necessarily the first to pull successfully — keeps the warm target\n // predictable for tests + operator UX.\n const warmTarget = models.find((m) => present.has(m) || report.pulled.includes(m));\n if (warmTarget) {\n onProgress?.(warmTarget, 'warming');\n const w = await warmModel(warmTarget);\n if (w.ok) {\n report.warmed.push(warmTarget);\n onProgress?.(warmTarget, 'warmed');\n }\n // A failed warm-up isn't fatal — it just means the first real user\n // request pays the cold-start cost. Surface in the report.\n }\n\n return report;\n}\n","/**\n * Manages the model-config block inside the operator's region-node `.env`.\n *\n * **Why a `.env` file (and why only for THIS config):**\n * docker compose resolves `${LLM_MODEL:-…}` interpolation with the precedence\n * shell/launchd env > `.env` > compose default. Model identifiers used to be\n * pushed into the launchd session via `launchctl setenv` — but that shadows\n * `.env` and, worse, only reaches launchd-spawned processes (never SSH shells\n * or a Terminal.app that was already open), so partial container recreates\n * baked divergent `LLM_MODEL` values at creation time. Writing the model to a\n * compose-auto-loaded `.env` makes every service resolve the SAME value\n * regardless of recreate order or how the operator's shell was started.\n *\n * This file deliberately carries ONLY non-secret substitution config\n * (`LLM_MODEL`, `EMBEDDINGS_PROVIDER`, `EMBEDDINGS_OLLAMA_MODEL`, `NODE_ENV`).\n * Bootstrap-critical SECRETS stay in the macOS Keychain and are hydrated into\n * the compose subprocess by `bin/op-compose` (see `op-compose-script.ts`) —\n * they never touch a plaintext `.env`, preserving the vault-first principle.\n *\n * **Managed block, not full ownership:**\n * In docker-compose semantics `.env` is fundamentally the operator's file, and\n * operators hand-edit it. So we own only a delimited region:\n *\n * # >>> op-node managed >>>\n * LLM_MODEL=…\n * # <<< op-node managed <<<\n *\n * Everything outside the markers is preserved verbatim. On first encounter\n * with a pre-existing `.env`, any managed keys the operator already set are\n * ADOPTED into the block (import-don't-clobber) rather than overwritten — the\n * exact drift this whole effort exists to prevent. The block is rewritten only\n * on an explicit model (re)selection (`overwrite: true`); a read-only consumer\n * like `verify` must never rewrite it.\n */\n\nimport { chmod, mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n/** Delimiters bounding the region create-op-node owns. Matched exactly (after\n * trimming) when locating an existing block. */\nexport const MANAGED_BEGIN = '# >>> op-node managed >>>';\nexport const MANAGED_END = '# <<< op-node managed <<<';\n\n/** Keys create-op-node manages inside the block, in stable emit order so diffs\n * across re-runs only show real value changes. */\nexport const MANAGED_KEYS = [\n 'LLM_MODEL',\n 'EMBEDDINGS_PROVIDER',\n 'EMBEDDINGS_OLLAMA_MODEL',\n 'NODE_ENV',\n 'SUPABASE_URL',\n] as const;\nexport type ManagedKey = (typeof MANAGED_KEYS)[number];\n\n/** `.env` value safety: model names + provider/NODE_ENV enums never contain\n * whitespace, `#`, quotes, `$`, or newlines. Rejecting them keeps a value\n * from silently truncating the line (inline `#`), spawning interpolation\n * (`$`), or breaking the file across a newline. Mirrors launchagent's\n * MODEL_NAME_RE for model ids and is a strict superset-safe check for the\n * fixed enums. */\nconst ENV_VALUE_RE = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;\n\nexport interface ManagedEnvSelection {\n /** Resolved LLM model id (e.g. `qwen3.6:35b-a3b`). Always present — bootstrap\n * always resolves one via flag/prompt/default. */\n llmModel: string;\n /** Resolved embeddings model id. Written as `EMBEDDINGS_OLLAMA_MODEL` — the\n * exact key the backend's embeddings config reads\n * (packages/config-provider/src/configs/embeddings.config.ts). Emitted even\n * under `xenova` (documents the intended model); only the knowledge service\n * under `EMBEDDINGS_PROVIDER=ollama` actually reads it. */\n embeddingModel?: string;\n /** `xenova` (in-process, default) or `ollama`. */\n embeddingsProvider?: string;\n /** `development` for `--local-only` nodes; omitted otherwise. */\n nodeEnv?: string;\n /** Public-facing Supabase URL (what browsers + microservices use). Written to\n * the managed block so `docker compose` resolves `${SUPABASE_URL:-…}` from\n * `.env` durably — the op-compose wrapper no longer exports it (#43). */\n supabaseUrl?: string;\n}\n\n/** The managed keys mapped from the caller's selection. */\nfunction selectionToPairs(sel: ManagedEnvSelection): ReadonlyArray<[ManagedKey, string | undefined]> {\n return [\n ['LLM_MODEL', sel.llmModel],\n ['EMBEDDINGS_PROVIDER', sel.embeddingsProvider],\n ['EMBEDDINGS_OLLAMA_MODEL', sel.embeddingModel],\n ['NODE_ENV', sel.nodeEnv],\n ['SUPABASE_URL', sel.supabaseUrl],\n ];\n}\n\nexport interface WriteEnvFileResult {\n ok: boolean;\n /** Absolute path to the written file, when ok=true. */\n path?: string;\n /** True when the managed block's rendered content was unchanged, so no write\n * happened. Lets bootstrap report \"already current\" instead of implying a\n * rewrite. */\n unchanged?: boolean;\n reason?: string;\n}\n\n// ----------------------------------------------------------------------------\n// Pure parsing / rendering (exported for unit tests)\n// ----------------------------------------------------------------------------\n\n/**\n * Parse `KEY=value` lines into a last-wins map. Ignores blank lines and\n * comments. Deliberately simple — matches docker compose's own naive `.env`\n * reader (no quoting, no escapes, no multi-line). We only look up our own\n * MANAGED_KEYS, which are always simple tokens.\n */\nexport function parseEnvContent(content: string): Map<string, string> {\n const out = new Map<string, string>();\n for (const raw of content.split('\\n')) {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith('#')) continue;\n const eq = line.indexOf('=');\n if (eq <= 0) continue;\n out.set(line.slice(0, eq).trim(), line.slice(eq + 1).trim());\n }\n return out;\n}\n\ninterface SplitEnv {\n /** Operator lines before the managed block (or the whole file when absent). */\n before: string[];\n /** Operator lines after the managed block. Empty when no block existed. */\n after: string[];\n /** Parsed key=value pairs found INSIDE an existing managed block. */\n blockValues: Map<string, string>;\n hasBlock: boolean;\n}\n\n/**\n * Split file content into the operator regions surrounding our managed block\n * plus the block's parsed values. When no block exists, the whole file is\n * `before` and `hasBlock` is false.\n */\nexport function splitManaged(content: string): SplitEnv {\n const lines = content.split('\\n');\n const beginIdx = lines.findIndex((l) => l.trim() === MANAGED_BEGIN);\n if (beginIdx === -1) {\n return { before: lines, after: [], blockValues: new Map(), hasBlock: false };\n }\n const endIdx = lines.findIndex((l, i) => i > beginIdx && l.trim() === MANAGED_END);\n if (endIdx === -1) {\n // Opening marker but no close (hand-mangled). Treat everything from the\n // marker on as ours to replace — don't try to preserve a broken block.\n return {\n before: lines.slice(0, beginIdx),\n after: [],\n blockValues: parseEnvContent(lines.slice(beginIdx + 1).join('\\n')),\n hasBlock: true,\n };\n }\n return {\n before: lines.slice(0, beginIdx),\n after: lines.slice(endIdx + 1),\n blockValues: parseEnvContent(lines.slice(beginIdx + 1, endIdx).join('\\n')),\n hasBlock: true,\n };\n}\n\n/** Drop lines from an operator region that assign one of our managed keys —\n * those values get consolidated INTO the block, so leaving the bare line\n * would create a duplicate (and, if it sorts after the block, shadow it). */\nfunction stripManagedKeyLines(region: string[]): string[] {\n return region.filter((raw) => {\n const line = raw.trim();\n if (line.length === 0 || line.startsWith('#')) return true;\n const eq = line.indexOf('=');\n if (eq <= 0) return true;\n return !MANAGED_KEYS.includes(line.slice(0, eq).trim() as ManagedKey);\n });\n}\n\n/** Render the managed block for a set of resolved key/value pairs (only keys\n * with a defined value are emitted). */\nfunction renderBlock(values: ReadonlyArray<[ManagedKey, string]>): string[] {\n return [\n MANAGED_BEGIN,\n '# Auto-generated by `create-op-node bootstrap`. Non-secret config (model',\n '# selection + SUPABASE_URL), read by docker compose via `.env` auto-load.',\n '# Edit a value here to change it for every service; re-running bootstrap',\n '# preserves your edits unless you explicitly re-select. Secrets do NOT live here.',\n ...values.map(([k, v]) => `${k}=${v}`),\n MANAGED_END,\n ];\n}\n\n/**\n * Compute the final managed content from the existing file + a selection.\n *\n * Reconciliation per key:\n * - `overwrite` (explicit model re-selection): the selection wins; fall back\n * to any existing/imported value when the selection omits the key.\n * - otherwise (import-don't-clobber, the default): an existing value —\n * whether already in the block or a bare operator line being imported —\n * is preserved; the selection only fills keys the operator hasn't set.\n *\n * Returns `null` when a resolved value fails `.env`-safety validation (caller\n * turns it into an error result).\n */\nexport function buildManagedEnvContent(\n existing: string,\n selection: ManagedEnvSelection,\n opts: { overwrite?: boolean } = {},\n): { content: string } | { error: string } {\n const split = splitManaged(existing);\n // Bare operator lines (outside any block) that set a managed key — the\n // import-don't-clobber source on first encounter.\n const importedBefore = filterManaged(parseEnvContent(split.before.join('\\n')));\n const importedAfter = filterManaged(parseEnvContent(split.after.join('\\n')));\n\n const resolved: Array<[ManagedKey, string]> = [];\n for (const [key, selected] of selectionToPairs(selection)) {\n const existingVal =\n split.blockValues.get(key) ?? importedBefore.get(key) ?? importedAfter.get(key);\n const final = opts.overwrite ? (selected ?? existingVal) : (existingVal ?? selected);\n if (final === undefined) continue;\n if (!ENV_VALUE_RE.test(final)) {\n return { error: `${key} value ${JSON.stringify(final)} is not safe for a .env line` };\n }\n resolved.push([key, final]);\n }\n\n const before = stripManagedKeyLines(split.before);\n const after = stripManagedKeyLines(split.after);\n const block = renderBlock(resolved);\n\n // Reassemble: operator preamble, exactly one blank separator, block,\n // operator postamble. Trailing newline so the file is POSIX-clean.\n const parts = [joinTrimmed(before), block.join('\\n'), joinTrimmed(after)].filter(\n (s) => s.length > 0,\n );\n return { content: parts.join('\\n\\n') + '\\n' };\n}\n\n/** Keep only entries whose key is one we manage. */\nfunction filterManaged(all: Map<string, string>): Map<string, string> {\n const out = new Map<string, string>();\n for (const key of MANAGED_KEYS) {\n const v = all.get(key);\n if (v !== undefined) out.set(key, v);\n }\n return out;\n}\n\n/** Join a region and trim surrounding newlines so reassembly doesn't\n * accumulate blank runs across re-runs. Hand-rolled (no regex) to avoid the\n * anchored-quantifier backtracking the Sonar gate flags. */\nfunction joinTrimmed(region: string[]): string {\n const joined = region.join('\\n');\n let start = 0;\n let end = joined.length;\n while (start < end && joined[start] === '\\n') start++;\n while (end > start && joined[end - 1] === '\\n') end--;\n return joined.slice(start, end);\n}\n\n// ----------------------------------------------------------------------------\n// Read (for verify / #97) + write\n// ----------------------------------------------------------------------------\n\nexport interface NodeEnvModelConfig {\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: string;\n nodeEnv?: string;\n /** Effective SUPABASE_URL — read so `verify` can flag a non-local node still\n * pinned to the localhost default (opuspopuli-node#43). */\n supabaseUrl?: string;\n}\n\n/**\n * Read the effective model config from `<repoDir>/.env` (last-wins across the\n * whole file, so the managed block and any operator override resolve the same\n * way docker compose would). Missing file → empty config. Read-only: never\n * rewrites the block.\n */\nexport async function readEnvModelConfig(repoDir: string): Promise<NodeEnvModelConfig> {\n let content: string;\n try {\n content = await readFile(join(repoDir, '.env'), 'utf8');\n } catch {\n return {};\n }\n const map = parseEnvContent(content);\n const cfg: NodeEnvModelConfig = {};\n const llm = map.get('LLM_MODEL');\n const emb = map.get('EMBEDDINGS_OLLAMA_MODEL');\n const prov = map.get('EMBEDDINGS_PROVIDER');\n const node = map.get('NODE_ENV');\n const supa = map.get('SUPABASE_URL');\n if (llm !== undefined) cfg.llmModel = llm;\n if (emb !== undefined) cfg.embeddingModel = emb;\n if (prov !== undefined) cfg.embeddingsProvider = prov;\n if (node !== undefined) cfg.nodeEnv = node;\n if (supa !== undefined) cfg.supabaseUrl = supa;\n return cfg;\n}\n\n/**\n * Upsert the managed block in `<repoDir>/.env`, preserving all operator\n * content outside it. Writes atomically (temp + rename) so an interrupted\n * bootstrap can't leave a half-written file. Skips the write (unchanged=true)\n * when the rendered file is byte-identical to what's on disk — so a re-run\n * that changed nothing doesn't churn the file mtime.\n *\n * `overwrite: true` signals an explicit model (re)selection — the selection\n * wins. Default (false) is import-don't-clobber: existing values are kept.\n */\nexport async function writeManagedEnv(\n repoDir: string,\n selection: ManagedEnvSelection,\n opts: { overwrite?: boolean } = {},\n): Promise<WriteEnvFileResult> {\n const target = join(repoDir, '.env');\n\n let existing = '';\n let existingMode: number | undefined;\n try {\n existing = await readFile(target, 'utf8');\n existingMode = (await stat(target)).mode & 0o777;\n } catch {\n // No file yet — first run.\n }\n\n const built = buildManagedEnvContent(existing, selection, opts);\n if ('error' in built) return { ok: false, reason: built.error };\n if (built.content === existing) return { ok: true, path: target, unchanged: true };\n\n // Non-secret config, but default to 0644 for a fresh file (world-readable is\n // fine and matches a normal `.env`); preserve the operator's mode if the\n // file already existed so we don't silently loosen/tighten it.\n const mode = existingMode ?? 0o644;\n const tmp = `${target}.tmp.${process.pid}`;\n try {\n await mkdir(dirname(target), { recursive: true });\n await writeFile(tmp, built.content, { mode });\n await chmod(tmp, mode);\n await rename(tmp, target); // atomic on POSIX\n return { ok: true, path: target };\n } catch (err) {\n return { ok: false, reason: `writing ${target} failed: ${(err as Error).message}` };\n }\n}\n","/**\n * Locate or clone the operator's node deployment repo on the Mac Studio.\n *\n * The bootstrap subcommand wants a working tree of the operator's region\n * deployment repo (created from `OpusPopuli/opuspopuli-node` by `init`) on\n * the Studio's filesystem — it's the source of `docker-compose-prod.yml`,\n * `supabase/init/`, `backup/scripts/`, `observability/`, etc.\n *\n * Three discovery paths the wizard tries in order:\n *\n * 1. **Explicit `--repo-dir`** — operator passed a path. Verify it's a\n * node repo (looks for the marker file) and use it.\n * 2. **Current directory** — operator may have already cloned + cd'd.\n * Same marker probe.\n * 3. **Clone fresh** — shell out to `gh repo clone <owner>/<repo>` into\n * `~/Development/<repo>`. The default location keeps it under the\n * operator's home (no sudo) and groups it with other dev work.\n */\n\nimport { access } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { safeExeca } from './exec.js';\n\n/** Files that a freshly-cloned (or template-derived) node repo always has.\n * Probing for these is how we distinguish a node repo from an arbitrary\n * directory the operator pointed us at. */\nexport const NODE_REPO_MARKERS = [\n 'docker-compose-prod.yml',\n 'supabase/init/pgsodium_getkey_env.sh',\n] as const;\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** True when every marker file is present at `dir`. False otherwise. */\nexport async function looksLikeNodeRepo(dir: string): Promise<boolean> {\n const checks = await Promise.all(\n NODE_REPO_MARKERS.map((m) => fileExists(join(dir, m))),\n );\n return checks.every((ok) => ok);\n}\n\nexport interface LocateInput {\n /** Owner of the node repo, e.g. `OpusPopuli`. */\n owner: string;\n /** Repo name, e.g. `opuspopuli-node-us-ca`. */\n name: string;\n /** Operator-supplied override (--repo-dir). When set, we use it iff it\n * looks like a node repo; otherwise return an error rather than fall\n * through to cloning a fresh copy. */\n explicit?: string;\n /** Where to put a fresh clone when neither --repo-dir nor cwd matches.\n * Default: ~/Development/<name>. */\n cloneInto?: string;\n /** When false, refuse to clone and require the operator to provide\n * a working tree (skip the gh shell-out). Default: true. */\n allowClone?: boolean;\n /** Working directory to probe as the \"already-cloned-and-cd'd\" path. */\n cwd?: string;\n}\n\nexport type LocateOutcome =\n | { kind: 'found'; path: string; source: 'explicit' | 'cwd' }\n | { kind: 'cloned'; path: string }\n | { kind: 'explicit-not-a-node-repo'; path: string }\n | { kind: 'gh-not-installed' }\n | { kind: 'clone-failed'; reason: string }\n | { kind: 'clone-disallowed' };\n\n/**\n * Walk the three discovery paths and return a discriminated outcome the\n * wizard can render. Cleanly separates \"operator-intentional path\" failures\n * from \"we tried but couldn't help\" failures.\n */\nexport async function locateOrCloneRepo(input: LocateInput): Promise<LocateOutcome> {\n // 1. Explicit --repo-dir.\n if (input.explicit) {\n if (await looksLikeNodeRepo(input.explicit)) {\n return { kind: 'found', path: input.explicit, source: 'explicit' };\n }\n return { kind: 'explicit-not-a-node-repo', path: input.explicit };\n }\n\n // 2. CWD probe.\n const cwd = input.cwd ?? process.cwd();\n if (await looksLikeNodeRepo(cwd)) {\n return { kind: 'found', path: cwd, source: 'cwd' };\n }\n\n // 3. Clone fresh.\n if (input.allowClone === false) {\n return { kind: 'clone-disallowed' };\n }\n\n const target = input.cloneInto ?? join(homedir(), 'Development', input.name);\n const res = await safeExeca('gh', ['repo', 'clone', `${input.owner}/${input.name}`, target]);\n if (res === null) return { kind: 'gh-not-installed' };\n if (res.exitCode !== 0) {\n return {\n kind: 'clone-failed',\n reason: `gh repo clone failed (${res.exitCode ?? 'signal'}): ${res.stderr || res.stdout}`,\n };\n }\n return { kind: 'cloned', path: target };\n}\n","/**\n * Compile-time exhaustiveness guard. Passing a value that TypeScript has\n * not narrowed to `never` is a type error, so an unhandled `switch` / `if`\n * variant fails the build. At runtime this is a no-op — callers keep their\n * existing control flow (fall through, `return`, etc.).\n */\nexport function assertNever(_value: never): void {\n /* compile-time only */\n}\n","import { join } from 'node:path';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport {\n PGSODIUM_KEY_RE,\n SAFE_LAUNCHCTL_VALUE_RE,\n SAFE_URL_RE,\n TUNNEL_TOKEN_RE,\n URL_SAFE_PASSWORD_RE,\n WELL_KNOWN_GATEWAY_HMAC_SECRET,\n} from '../lib/constants.js';\nimport {\n detectBrew,\n HOMEBREW_INSTALL_COMMAND,\n installPackages,\n STUDIO_PACKAGES,\n} from '../lib/homebrew.js';\nimport {\n detectUnifiedMemoryGB,\n disableDiskSleep,\n enableAutoRestartOnPowerFailure,\n inspectSystem,\n} from '../lib/macos.js';\nimport {\n detectKeychain,\n isKeychainLocked,\n isSshSession,\n readSecret,\n saveSecret,\n unlockKeychain,\n type SecretAccount,\n} from '../lib/keychain.js';\nimport {\n generateDashboardPassword,\n generateGatewayHmacSecret,\n generateGrafanaAdminPassword,\n generateHmacApiKey,\n generateJwtSecret,\n generatePgsodiumRootKey,\n generatePostgresPassword,\n renderApiKeys,\n signSupabaseJwt,\n verifySupabaseJwt,\n} from '../lib/secrets.js';\nimport { setupLaunchAgent } from '../lib/launchagent.js';\nimport { installOpComposeWrapper } from '../lib/op-compose-install.js';\nimport {\n composeConfigImages,\n composePull,\n composeRemoveService,\n composeUp,\n filterVerifiableImages,\n loginToGhcr,\n waitForHealthy,\n type ComposeOptions,\n} from '../lib/docker.js';\nimport { cosignVerifyImage } from '../lib/cosign.js';\nimport {\n DEFAULT_EMBEDDING_MODEL,\n DEFAULT_EMBEDDINGS_PROVIDER,\n DEFAULT_LLM_MODEL,\n checkOllamaHealth,\n probeHostDockerInternal,\n setupModels,\n startOllamaService,\n type EmbeddingsProvider,\n} from '../lib/ollama.js';\nimport { writeManagedEnv } from '../lib/env-file.js';\nimport { locateOrCloneRepo, type LocateOutcome } from '../lib/noderepo.js';\nimport { safeExeca } from '../lib/exec.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { assertNever } from '../lib/assert.js';\n\n/** Compose profile set used in production mode — activates cloudflared. */\nconst PUBLIC_PROFILES = ['public'] as const;\n/** Compose profile set used in --local-only mode — keeps cloudflared down\n * via the template's profile gating. */\nconst LOCAL_PROFILES = [] as const;\n\n/** Node deployment topology — selects which docker compose stack(s) +\n * Keychain entries bootstrap provisions.\n *\n * - `region` — standard region node (civic data for one region). Connects\n * to a REMOTE prompt-service via PROMPT_SERVICE_URL. The HMAC key for\n * that remote service is issued by the prompts team and pasted in;\n * bootstrap stores it under the same Keychain account as the colocated\n * case so the wrapper exports it transparently. This is the production\n * default for any operator who isn't on the prompts team.\n *\n * - `region-with-prompts` — region node + colocated prompt-service overlay\n * (the us-ca / team / dev case). Bootstrap generates a local HMAC key,\n * a prompt-service admin key, and a prompts-db password — all stored\n * in Keychain — and the op-compose wrapper exports them so the\n * `docker-compose-prompt-service.yml` overlay can layer on top.\n *\n * - `prompts-only` — STUB. Reserved for when the prompts team deploys the\n * central prompts.opuspopuli.org instance. No region services; only the\n * prompt-service + its DB. Bootstrap currently exits with a \"not yet\n * implemented\" message — the flag exists so the CLI surface is stable\n * for the future deployment.\n */\ntype NodeType = 'region' | 'region-with-prompts' | 'prompts-only';\n\ninterface BootstrapOptions {\n region?: string;\n owner?: string;\n repoDir?: string;\n composeFile?: string[];\n envFile?: string;\n skipBrew?: boolean;\n skipLaunchAgent?: boolean;\n skipOllama?: boolean;\n skipStack?: boolean;\n localOnly?: boolean;\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: EmbeddingsProvider;\n /** Public-facing Supabase URL. Defaults to `http://localhost:8000` in\n * --local-only mode, otherwise `https://supabase.<domain>` — operator\n * can override with --supabase-url. */\n supabaseUrl?: string;\n /** Bypass the fail-closed cosign signature gate before `compose pull`.\n * Not recommended — trusts the registry contents unverified. */\n skipSignatureCheck?: boolean;\n /** Override the cosign certificate-identity regexp used to verify images\n * (e.g. after a workflow rename). Escape valve for the pinned default. */\n certificateIdentityRegexp?: string;\n /** Selects which deployment stack to provision. Defaults to `region`. */\n nodeType?: NodeType;\n /** For `--node-type region` (remote prompt-service): the URL of the\n * central prompt-service the backend should call. Defaults to\n * `https://prompts.opuspopuli.org`. Ignored in `region-with-prompts`\n * (the overlay pins it to the in-network hostname). */\n promptServiceUrl?: string;\n yes?: boolean;\n}\n\nexport const bootstrapCommand = new Command('bootstrap')\n .description(\n 'Configure the Mac Studio and bring the stack up. Run this on the Studio itself, after `init` has finished on your laptop.',\n )\n .addOption(new Option('--region <slug>', 'Region label set during init (e.g. us-ca)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the node repo').default('OpusPopuli'))\n .addOption(new Option('--repo-dir <path>', 'Explicit path to a checked-out node repo (overrides cwd + clone)'))\n .addOption(\n new Option(\n '--compose-file <path>',\n 'Repeatable. Compose file relative to repo root. Default: prod + backup (production), prod only (--local-only).',\n ).argParser(collectComposeFile),\n )\n .addOption(new Option('--env-file <path>', 'Compose --env-file. Default: .env.production'))\n .addOption(new Option('--skip-brew', \"Skip the Homebrew package install pass\").default(false))\n .addOption(\n new Option(\n '--skip-launch-agent',\n \"Skip the LaunchAgent setup (assumes one is already in place)\",\n ).default(false),\n )\n .addOption(new Option('--skip-ollama', \"Skip the Ollama model pull + warm\").default(false))\n .addOption(\n new Option(\n '--llm-model <model>',\n `Ollama LLM model to pull and warm. Default: ${DEFAULT_LLM_MODEL}. Examples: \\`llama3.3:70b\\`, \\`qwen2.5:72b\\`. Memory sizing table: docs/docker-resources.md in the opuspopuli-node template (or your region repo's checkout).`,\n ),\n )\n .addOption(\n new Option(\n '--embedding-model <model>',\n `Ollama embedding model. Default: ${DEFAULT_EMBEDDING_MODEL}. Only takes effect when the knowledge service runs with EMBEDDINGS_PROVIDER=ollama (otherwise embeddings are computed in-process via xenova).`,\n ),\n )\n .addOption(\n new Option(\n '--embeddings-provider <provider>',\n `Where embeddings are computed. Default: ${DEFAULT_EMBEDDINGS_PROVIDER} (in-process). \\`ollama\\` uses the host daemon with the embedding model. Written to the node's .env as the single source of truth.`,\n ).choices(['xenova', 'ollama']),\n )\n .addOption(\n new Option(\n '--supabase-url <url>',\n 'Public-facing Supabase URL (what browsers + microservices use). Default: `http://localhost:8000` in --local-only mode, otherwise `https://supabase.<domain>` (which the operator can override).',\n ),\n )\n .addOption(\n new Option(\n '--node-type <type>',\n 'Deployment topology. `region` (default) = region node connecting to remote prompt-service. `region-with-prompts` = region node + colocated prompt-service overlay (team/dev use). `prompts-only` = future stub for the central prompts deployment.',\n ).choices(['region', 'region-with-prompts', 'prompts-only']),\n )\n .addOption(\n new Option(\n '--prompt-service-url <url>',\n \"Remote prompt-service URL. Only meaningful for --node-type=region (default: https://prompts.opuspopuli.org). Ignored for --node-type=region-with-prompts (the overlay pins it to http://opuspopuli-prompts:3210).\",\n ),\n )\n .addOption(new Option('--skip-stack', \"Stop before `docker compose pull && up`\").default(false))\n .addOption(\n new Option(\n '--skip-signature-check',\n 'Bypass the fail-closed cosign verification of opuspopuli images before pull (NOT recommended — trusts the registry unverified).',\n ).default(false),\n )\n .addOption(\n new Option(\n '--certificate-identity-regexp <regexp>',\n 'Override the cosign certificate-identity regexp used to verify images (escape valve for the pinned default).',\n ),\n )\n .addOption(\n new Option(\n '--local-only',\n \"Run for local dev / testing: no Tunnel token required, cloudflared stays down. Auto-generates the pgsodium key if not in Keychain (init unnecessary).\",\n ).default(false),\n )\n .addOption(new Option('-y, --yes', 'Skip confirmation prompts').default(false))\n .action(async (opts: BootstrapOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node bootstrap ')));\n\n const nodeType = await selectNodeType(opts);\n const region = await resolveRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const repoName = `opuspopuli-node-${region}`;\n const composeFile = opts.composeFile ?? defaultComposeFiles(opts);\n\n // Model selection: flags override > interactive prompt > defaults. The\n // resolved values flow to both Ollama (pull + warm) and the LaunchAgent\n // (LLM_MODEL / EMBEDDINGS_OLLAMA_MODEL). bootstrap is the source of truth for\n // what model runs. (N3)\n const llmModelChoice = opts.llmModel ?? (await selectLlmModel(opts));\n const [embeddingModel, llmModel] = resolveModels({\n llmModel: llmModelChoice,\n ...(opts.embeddingModel !== undefined ? { embeddingModel: opts.embeddingModel } : {}),\n });\n const embeddingsProvider = opts.embeddingsProvider ?? DEFAULT_EMBEDDINGS_PROVIDER;\n\n // ---- Phases 1–4: system checks, Homebrew, auth, locate repo ----\n await runSystemChecksPhase();\n await runBrewPhase(opts);\n await ensureGhAuth();\n await promptTailscaleSignin();\n const repoPath = await locateRegionRepoPhase(opts, owner, repoName);\n\n // ---- Phase 5: secrets (Keychain unlock, load/generate, URLs) ----\n await unlockKeychainPhase();\n\n const secrets = await collectSecretsPhase({ region, nodeType, opts });\n await runLaunchAgentPhase({ opts, secrets });\n await installWrapperPhase({ repoPath, region, promptServiceUrl: secrets.promptServiceUrl });\n await loginGhcrPhase();\n await runOllamaPhase({ opts, embeddingModel, llmModel, embeddingsProvider });\n await runEnvFilePhase({\n repoPath,\n llmModel,\n embeddingModel,\n embeddingsProvider,\n localOnly: Boolean(opts.localOnly),\n supabaseUrl: secrets.supabaseUrl,\n });\n await runStackPhase({ opts, repoPath, region, composeFile, secrets });\n });\n\n// ----------------------------------------------------------------------------\n// Bootstrap phases\n// ----------------------------------------------------------------------------\n// The command action delegates to these phase helpers so no single function\n// exceeds the cognitive-complexity budget. Each is behavior-preserving — the\n// interactive prompts, spinners, and `process.exit` calls are relocated\n// verbatim, not changed. The orchestrator threads values through explicitly.\n\ninterface CollectedSecrets {\n pgsodiumKey: string;\n tunnelToken: string | undefined;\n postgresPassword: string;\n jwtSecret: string;\n supabaseAnonKey: string;\n supabaseServiceRoleKey: string;\n dashboardPassword: string;\n /** API Gateway HMAC secret — signs gateway→microservice requests. Real\n * per-node value; MUST NOT equal WELL_KNOWN_GATEWAY_HMAC_SECRET on a\n * Tunnel-exposed node. */\n gatewayHmacSecret: string;\n /** Grafana admin password — overrides the `admin`/`admin` compose default. */\n grafanaAdminPassword: string;\n promptServiceUrl: string;\n supabaseUrl: string;\n /** prompt-service overlay secrets. Present for `--node-type\n * region-with-prompts` (all three) and, for `region`, just the API key used\n * to authenticate to the REMOTE prompt-service. These mirror what the\n * op-compose wrapper exports so bootstrap's OWN compose calls can process\n * the prompt-service overlay instead of failing on `${PROMPTS_DB_PASSWORD:?}`.\n * (#90) */\n promptsDbPassword?: string;\n promptServiceApiKey?: string;\n /** `<region>:<key>` — the value prompt-service reads as its API_KEYS list. */\n promptServiceApiKeys?: string;\n promptServiceAdminApiKeys?: string;\n}\n\n// Default compose file set by mode (review S4): production runs the\n// backup stack (restic / rclone) alongside the main stack; local-only\n// skips it (don't burn dev-machine disk on backups; don't try to push\n// to an R2 bucket that may not exist). Operator can still override\n// with explicit --compose-file flags.\nfunction defaultComposeFiles(opts: BootstrapOptions): string[] {\n return opts.localOnly\n ? ['docker-compose-prod.yml']\n : ['docker-compose-prod.yml', 'docker-compose-backup.yml'];\n}\n\n// Node type selects which stack to provision. Default is `region` — the\n// common case for any operator who isn't on the prompts team.\n// `region-with-prompts` covers the team/dev case where the operator runs\n// prompt-service alongside the region stack. `prompts-only` is a documented\n// stub for the future central prompts deployment — exits early to keep the\n// CLI surface stable now.\nasync function selectNodeType(opts: BootstrapOptions): Promise<NodeType> {\n const nodeType: NodeType = opts.nodeType\n ? opts.nodeType\n : (unwrap(\n await p.select({\n message: 'What kind of node are you provisioning?',\n options: [\n {\n value: 'region',\n label: 'Region node (civic data for one region, remote prompt-service)',\n },\n {\n value: 'region-with-prompts',\n label: 'Region + colocated prompt-service (team / dev)',\n },\n {\n value: 'prompts-only',\n label: 'Prompt-service node (central prompts deployment — future)',\n },\n ],\n initialValue: 'region',\n }),\n ) as NodeType);\n\n if (nodeType === 'prompts-only') {\n p.cancel(\n 'prompts-only node deployment is not yet implemented. ' +\n 'This flag exists so the CLI surface is stable for when the prompts team ' +\n 'deploys the central prompts.opuspopuli.org instance — but the deployment ' +\n 'stack (compose file, healthchecks, observability) is filled in later, ' +\n 'when there is an actual central prompt-service to deploy.',\n );\n process.exit(1);\n }\n return nodeType;\n}\n\n// Region label (required to find Keychain items + repo name).\nasync function resolveRegion(opts: BootstrapOptions): Promise<string> {\n return opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Region label (the slug used during init — e.g. us-ca)?',\n placeholder: 'us-ca',\n validate: (v) =>\n /^[a-z0-9-]{2,32}$/.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n}\n\n// ---- Phase 1: macOS sanity ----\nasync function runSystemChecksPhase(): Promise<void> {\n const sysSpin = p.spinner();\n sysSpin.start('Inspecting macOS…');\n const snap = await inspectSystem();\n sysSpin.stop(pc.green('✓ macOS inspected.'));\n\n if (!snap.isAppleSilicon) {\n p.cancel(\n `Bootstrap requires an Apple Silicon Mac (the runbook targets M-series). Detected: ${snap.osVersion ?? 'unknown'} (uname -m != arm64).`,\n );\n process.exit(1);\n }\n\n p.note(\n [\n `Hostname: ${pc.cyan(snap.hostname)}`,\n `macOS: ${pc.cyan(snap.osVersion ?? '(sw_vers failed)')}`,\n `Auto-restart on power: ${kvBool(snap.autoRestartOnPowerFailure)}`,\n `Disk sleep disabled: ${kvBool(snap.diskSleepDisabled)}`,\n `FileVault: ${kvFileVault(snap.fileVaultEnabled)}`,\n ].join('\\n'),\n 'System snapshot',\n );\n\n if (!snap.autoRestartOnPowerFailure) {\n const fix = unwrap(\n await p.confirm({\n message: 'Auto-restart-on-power-failure is OFF. Enable now (requires sudo)?',\n initialValue: true,\n }),\n );\n if (fix) {\n const r = await enableAutoRestartOnPowerFailure();\n if (!r.ok) p.note(`${pc.red('✗')} ${r.reason}`, 'pmset failed');\n }\n }\n if (!snap.diskSleepDisabled) {\n const fix = unwrap(\n await p.confirm({\n message: 'Disk sleep is enabled. Disable now (requires sudo)?',\n initialValue: true,\n }),\n );\n if (fix) {\n const r = await disableDiskSleep();\n if (!r.ok) p.note(`${pc.red('✗')} ${r.reason}`, 'pmset failed');\n }\n }\n}\n\n// ---- Phase 2: Homebrew + tool installs ----\nasync function runBrewPhase(opts: BootstrapOptions): Promise<void> {\n if (opts.skipBrew) return;\n\n const brewInfo = await detectBrew();\n if (!brewInfo.installed) {\n p.note(\n [\n `Homebrew is not installed. Open another shell and run:`,\n '',\n pc.cyan(HOMEBREW_INSTALL_COMMAND),\n '',\n pc.dim('Then come back and press Enter.'),\n ].join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'Homebrew installed?', initialValue: true }));\n }\n\n const brewSpin = p.spinner();\n brewSpin.start('Installing Studio packages… (~5–15 min first run)');\n const report = await installPackages(STUDIO_PACKAGES, (pkg, status) => {\n brewSpin.message(`${status}: ${pkg.name}`);\n });\n brewSpin.stop(\n report.failed.length === 0\n ? pc.green(\n `✓ ${report.installed.length} installed, ${report.alreadyPresent.length} already present`,\n )\n : pc.yellow(\n `⚠ ${report.installed.length} installed, ${report.alreadyPresent.length} present, ${report.failed.length} failed`,\n ),\n );\n if (report.failed.length > 0) {\n p.note(\n [\n report.failed.map((f) => `${pc.red('•')} ${f.pkg.name}: ${f.reason}`).join('\\n'),\n '',\n pc.dim('A partial install usually fails downstream (Docker / Ollama / compose).'),\n pc.dim('Install the failed packages manually and re-run with --skip-brew.'),\n ].join('\\n'),\n 'Brew failures',\n );\n const cont = unwrap(\n await p.confirm({\n message: 'Continue anyway? (Default no — recommended to fix and re-run.)',\n initialValue: false,\n }),\n );\n if (!cont) process.exit(1);\n }\n}\n\n// ---- Phase 4: Locate / clone the region repo (fail-fast — S6 review fix) ----\n// Moved up from Phase 8: a repo-not-found error after 5-10 minutes of\n// brew + Ollama work is operator-hostile. The clone only needs `gh`\n// (Phase 3), so we can validate the repo exists early and bail before\n// the slow stuff if it doesn't.\nasync function locateRegionRepoPhase(\n opts: BootstrapOptions,\n owner: string,\n repoName: string,\n): Promise<string> {\n const repoSpin = p.spinner();\n repoSpin.start('Locating your region node repo…');\n const located = await locateOrCloneRepo({\n owner,\n name: repoName,\n cwd: process.cwd(),\n ...(opts.repoDir ? { explicit: opts.repoDir } : {}),\n });\n const repoPath = repoPathFromLocate(located);\n if (!repoPath) {\n repoSpin.stop(pc.red('✗ Couldn\\'t locate or clone the region repo.'));\n handleLocateError(located, owner, repoName);\n process.exit(1);\n }\n repoSpin.stop(\n located.kind === 'cloned'\n ? pc.green(`✓ Cloned ${owner}/${repoName} to ${repoPath}`)\n : pc.green(`✓ Found region repo at ${repoPath}`),\n );\n return repoPath;\n}\n\n// ---- Phase 5: keychain availability + SSH unlock ----\n//\n// The Keychain item is local to the machine that wrote it (`init` on the\n// laptop). On a fresh Studio, both items will be missing on first run —\n// bootstrap prompts the operator to paste, validates the format, and writes\n// to the Studio's local Keychain for re-runs.\nasync function unlockKeychainPhase(): Promise<void> {\n const keychain = await detectKeychain();\n if (!keychain.available) {\n p.cancel(\n `${keychain.reason ?? 'Keychain unavailable'}. Bootstrap requires the macOS Keychain.`,\n );\n process.exit(1);\n }\n\n // SSH sessions don't auto-unlock the login keychain at session start.\n // When the operator is over SSH AND the keychain is currently locked,\n // every `security add-generic-password` call will fail with exit 36\n // (errSecInteractionNotAllowed). Prompt for the login password once\n // up front, unlock, then proceed — much better UX than 9 identical\n // failures (one per secret) before the operator figures it out.\n if (isSshSession() && (await isKeychainLocked())) {\n p.note(\n [\n 'SSH session detected with a locked login keychain.',\n 'macOS keychain operations require an unlocked keychain — your',\n 'login password will be used once to unlock it for this session.',\n 'The keychain remains unlocked until the session ends or it',\n 'idle-locks. To skip and unlock manually, press Ctrl+C and run',\n '`security unlock-keychain` yourself.',\n ].join('\\n'),\n 'Keychain unlock required',\n );\n const pw = unwrap(\n await p.password({\n message: 'macOS login password (for `security unlock-keychain`):',\n validate: (v) => (v && v.length > 0 ? undefined : 'password required'),\n }),\n );\n const unlock = await unlockKeychain(pw);\n if (!unlock.ok) {\n p.cancel(unlock.reason ?? 'security unlock-keychain failed.');\n process.exit(1);\n }\n p.note(`${pc.green('✓')} Keychain unlocked for this session.`, 'Keychain');\n }\n}\n\n// ---- Phase 5a: pgsodium key, tunnel token, and Supabase self-hosted creds ----\n//\n// In --local-only mode there's no Tunnel token at all (cloudflared stays\n// down via compose profile gating). The pgsodium key is still required\n// since the data services use it; if missing, we generate a fresh one\n// inline rather than requiring an `init` call first.\n//\n// The five Supabase values (postgres password, JWT secret, anon +\n// service_role JWTs, dashboard password) are auto-generated on first run\n// via the same `loadSecret` path used for the pgsodium key. The two JWTs\n// are derived from JWT_SECRET and re-validated against it so a stale token\n// cached from a prior bootstrap can't silently break auth.\nasync function collectCoreSecrets(args: {\n region: string;\n opts: BootstrapOptions;\n}): Promise<Omit<CollectedSecrets, 'promptServiceUrl' | 'supabaseUrl'>> {\n const { region, opts } = args;\n const pgsodiumKey = await loadSecret({\n region,\n account: 'pgsodium-root-key',\n label: 'pgsodium master key',\n validate: (v) =>\n PGSODIUM_KEY_RE.test(v) ? undefined : 'must be exactly 64 lowercase hex characters',\n ...(opts.localOnly ? { generate: generatePgsodiumRootKey } : {}),\n });\n\n const tunnelToken = opts.localOnly\n ? undefined\n : await loadSecret({\n region,\n account: 'tunnel-token',\n label: 'Cloudflare Tunnel token',\n placeholder: 'JWT-style base64url string from `terraform output tunnel_token`',\n validate: (v) =>\n TUNNEL_TOKEN_RE.test(v) ? undefined : 'tunnel token must be a base64-url JWT',\n });\n\n const postgresPassword = await loadSecret({\n region,\n account: 'postgres-password',\n label: 'Postgres password',\n // URL-safe alphabet required — value lands in postgres:// URIs where\n // `+`/`/`/`=` cause parser ambiguity in gotrue/postgrest/storage.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generatePostgresPassword,\n });\n\n const jwtSecret = await loadSecret({\n region,\n account: 'jwt-secret',\n label: 'JWT signing secret',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && v.length >= 32\n ? undefined\n : 'must be ≥32 base64 characters',\n generate: generateJwtSecret,\n });\n\n // Derived JWTs MUST match the current jwtSecret's signature — otherwise\n // a stale anon/service_role token (cached from a previous bootstrap with\n // a different JWT_SECRET) sails past the shape check and breaks every\n // auth call silently. verifySupabaseJwt re-runs the HMAC and rejects on\n // mismatch, triggering regeneration with the current secret.\n const supabaseAnonKey = await loadSecret({\n region,\n account: 'supabase-anon-key',\n label: 'Supabase anon key',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && verifySupabaseJwt(v, jwtSecret)\n ? undefined\n : 'must be a base64url JWT signed by the current JWT_SECRET',\n generate: () => signSupabaseJwt({ role: 'anon', secret: jwtSecret }),\n });\n\n const supabaseServiceRoleKey = await loadSecret({\n region,\n account: 'supabase-service-role-key',\n label: 'Supabase service role key',\n validate: (v) =>\n SAFE_LAUNCHCTL_VALUE_RE.test(v) && verifySupabaseJwt(v, jwtSecret)\n ? undefined\n : 'must be a base64url JWT signed by the current JWT_SECRET',\n generate: () => signSupabaseJwt({ role: 'service_role', secret: jwtSecret }),\n });\n\n const dashboardPassword = await loadSecret({\n region,\n account: 'dashboard-password',\n label: 'Supabase Studio dashboard password',\n // URL-safe alphabet required — value lands in basic-auth headers via\n // kong's declarative config. Avoid `+`/`/`/`=` for the same reasons.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateDashboardPassword,\n });\n\n // API Gateway HMAC secret. Always generated so a bootstrapped node never\n // runs on the template's well-known compose default (which every checkout\n // shares). The value ALSO drives API_KEYS `{\"api-gateway\":\"<this>\"}`, so\n // the api-gateway's key equals GATEWAY_HMAC_SECRET and its signature\n // verifies. URL-safe alphabet keeps it clean inside the API_KEYS JSON.\n // Reject the well-known default explicitly: if a prior run (or a manual\n // paste) stored the placeholder, treat it as invalid and regenerate.\n const gatewayHmacSecret = await loadSecret({\n region,\n account: 'gateway-hmac-secret',\n label: 'API Gateway HMAC secret',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) && v !== WELL_KNOWN_GATEWAY_HMAC_SECRET\n ? undefined\n : 'must be base64url chars only (no + / =) and not the well-known template default',\n generate: generateGatewayHmacSecret,\n });\n\n const grafanaAdminPassword = await loadSecret({\n region,\n account: 'grafana-admin-password',\n label: 'Grafana admin password',\n // URL-safe alphabet — exported into the compose env for Grafana's\n // GF_SECURITY_ADMIN_PASSWORD; keep it free of shell/URL metacharacters.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateGrafanaAdminPassword,\n });\n\n return {\n pgsodiumKey,\n tunnelToken,\n postgresPassword,\n jwtSecret,\n supabaseAnonKey,\n supabaseServiceRoleKey,\n dashboardPassword,\n gatewayHmacSecret,\n grafanaAdminPassword,\n };\n}\n\n// ---- Phase 5b: prompt-service credentials + URL ----\n//\n// Branches on nodeType:\n// `region-with-prompts` — operator owns both ends. Generate all three\n// secrets (DB password + HMAC + admin HMAC); the colocated overlay\n// consumes them via env.\n// `region` — operator's prompt-service is REMOTE. They received an HMAC\n// key from the prompts team; bootstrap prompts them to paste it. The DB\n// password + admin key are skipped (no local DB, no admin access).\ninterface PromptServiceSecrets {\n url: string;\n promptsDbPassword?: string;\n promptServiceApiKey?: string;\n promptServiceApiKeys?: string;\n promptServiceAdminApiKeys?: string;\n}\n\nasync function collectPromptServiceSecrets(args: {\n region: string;\n nodeType: NodeType;\n opts: BootstrapOptions;\n}): Promise<PromptServiceSecrets> {\n const { region, nodeType, opts } = args;\n // Capture each loaded/generated value — bootstrap's own compose calls need\n // them in the env (via buildComposeEnv) to bring the prompt-service overlay\n // up, mirroring the op-compose wrapper. (#90)\n let promptsDbPassword: string | undefined;\n let promptServiceApiKey: string | undefined;\n let promptServiceAdminApiKeys: string | undefined;\n if (nodeType === 'region-with-prompts') {\n promptsDbPassword = await loadSecret({\n region,\n account: 'prompts-db-password',\n label: 'prompt-service Postgres password',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generatePostgresPassword,\n });\n\n promptServiceApiKey = await loadSecret({\n region,\n account: 'prompt-service-api-key',\n label: 'prompt-service HMAC API key',\n // Same URL-safe alphabet as other HMAC keys; embedded in the\n // `<region>:<key>` API_KEYS list and in Authorization headers.\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateHmacApiKey,\n });\n\n promptServiceAdminApiKeys = await loadSecret({\n region,\n account: 'prompt-service-admin-api-key',\n label: 'prompt-service admin API key',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n generate: generateHmacApiKey,\n });\n } else {\n // nodeType === 'region': paste-only path. No `generate`, so loadSecret\n // falls through to the operator-paste prompt.\n promptServiceApiKey = await loadSecret({\n region,\n account: 'prompt-service-api-key',\n label: 'prompt-service HMAC API key (issued by the prompts team)',\n placeholder: 'paste the region-specific HMAC key',\n validate: (v) =>\n URL_SAFE_PASSWORD_RE.test(v) ? undefined : 'must be base64url chars only (no + / =)',\n });\n }\n\n // Remote prompt-service URL — only resolved when NOT colocating.\n // For region-with-prompts the overlay hardcodes http://opuspopuli-prompts:3210\n // on the relevant services; no shell env needed.\n const promptServiceUrl =\n nodeType === 'region-with-prompts'\n ? // eslint-disable-next-line sonarjs/no-clear-text-protocols -- in-network (docker) prompt-service URL is legitimately plaintext http; no TLS on the internal bridge\n 'http://opuspopuli-prompts:3210'\n : (opts.promptServiceUrl ?? 'https://prompts.opuspopuli.org');\n if (!SAFE_URL_RE.test(promptServiceUrl)) {\n p.cancel(\n `--prompt-service-url ${JSON.stringify(promptServiceUrl)} contains characters outside the allowed URL set`,\n );\n process.exit(1);\n }\n return {\n url: promptServiceUrl,\n ...(promptsDbPassword !== undefined ? { promptsDbPassword } : {}),\n // PROMPT_SERVICE_API_KEY is the raw key; PROMPT_SERVICE_API_KEYS is the\n // `<region>:<key>` list prompt-service validates against — same derivation\n // the op-compose wrapper does.\n ...(promptServiceApiKey !== undefined\n ? { promptServiceApiKey, promptServiceApiKeys: `${region}:${promptServiceApiKey}` }\n : {}),\n ...(promptServiceAdminApiKeys !== undefined ? { promptServiceAdminApiKeys } : {}),\n };\n}\n\n// SUPABASE_URL gets baked into gotrue's API_EXTERNAL_URL and into every\n// magic-link callback gotrue emails to users. localhost is only correct\n// in --local-only mode; for a Tunnel-exposed production node, emailing\n// links pointing at http://localhost:8000 silently breaks signups.\n//\n// Resolution order:\n// --local-only mode → default http://localhost:8000 (no prompt)\n// non-local-only → require --supabase-url OR prompt for the\n// public-facing URL.\nasync function resolveSupabaseUrl(opts: BootstrapOptions): Promise<string> {\n let supabaseUrl: string;\n if (opts.supabaseUrl) {\n supabaseUrl = opts.supabaseUrl;\n } else if (opts.localOnly) {\n supabaseUrl = 'http://localhost:8000';\n } else {\n supabaseUrl = unwrap(\n await p.text({\n message: 'Public-facing Supabase URL (what browsers + microservices use to reach kong)?',\n placeholder: 'https://supabase.civicfeed.tx',\n validate: (v) => {\n if (!v) return 'required';\n return SAFE_URL_RE.test(v)\n ? undefined\n : 'contains characters outside the allowed URL set';\n },\n }),\n );\n }\n if (!SAFE_URL_RE.test(supabaseUrl)) {\n p.cancel(\n `--supabase-url ${JSON.stringify(supabaseUrl)} contains characters outside the allowed URL set`,\n );\n process.exit(1);\n }\n return supabaseUrl;\n}\n\n// Phase 5 aggregate: run all secret-collection sub-phases in order.\nasync function collectSecretsPhase(args: {\n region: string;\n nodeType: NodeType;\n opts: BootstrapOptions;\n}): Promise<CollectedSecrets> {\n const core = await collectCoreSecrets({ region: args.region, opts: args.opts });\n const { url: promptServiceUrl, ...promptSecrets } = await collectPromptServiceSecrets(args);\n const supabaseUrl = await resolveSupabaseUrl(args.opts);\n return { ...core, ...promptSecrets, promptServiceUrl, supabaseUrl };\n}\n\n// ---- Phase 6: LaunchAgent ----\n// Note: model config (LLM_MODEL / EMBEDDINGS_OLLAMA_MODEL / NODE_ENV) is deliberately\n// NOT exported here. Those are non-secret substitution vars that live in the\n// node's `.env` (see runEnvFilePhase) — a launchctl setenv value would shadow\n// `.env` at compose interpolation time (shell env > .env), defeating the\n// single-source-of-truth. Only Keychain secrets flow through the LaunchAgent.\nasync function runLaunchAgentPhase(args: {\n opts: BootstrapOptions;\n secrets: CollectedSecrets;\n}): Promise<void> {\n const { opts, secrets } = args;\n if (opts.skipLaunchAgent) return;\n\n const laSpin = p.spinner();\n laSpin.start('Writing pgsodium key file + LaunchAgent plist…');\n const la = await setupLaunchAgent({\n pgsodiumKey: secrets.pgsodiumKey,\n ...(secrets.tunnelToken !== undefined ? { tunnelToken: secrets.tunnelToken } : {}),\n postgresPassword: secrets.postgresPassword,\n jwtSecret: secrets.jwtSecret,\n supabaseAnonKey: secrets.supabaseAnonKey,\n supabaseServiceRoleKey: secrets.supabaseServiceRoleKey,\n dashboardPassword: secrets.dashboardPassword,\n gatewayHmacSecret: secrets.gatewayHmacSecret,\n grafanaAdminPassword: secrets.grafanaAdminPassword,\n supabaseUrl: secrets.supabaseUrl,\n });\n if (!la.ok) {\n laSpin.stop(pc.red(`✗ LaunchAgent step ${la.step} failed.`));\n p.cancel(la.reason ?? 'LaunchAgent setup failed.');\n process.exit(1);\n }\n laSpin.stop(\n pc.green(\n `✓ LaunchAgent loaded (${la.paths.plistFile})${opts.localOnly ? ' — local-only mode, no TUNNEL_TOKEN set' : ''}.`,\n ),\n );\n}\n\n// ---- Phase 6b: install op-compose wrapper ----\n//\n// launchctl setenv doesn't reach pre-existing shells or sshd children, so\n// operator-driven `docker compose` invocations would hard-fail on the\n// `${VAR:?…}` enforcement in the template even though the values sit safely\n// in Keychain. The wrapper reads Keychain on every invocation and exports\n// the values only into the docker compose subprocess's env.\nasync function installWrapperPhase(args: {\n repoPath: string;\n region: string;\n promptServiceUrl: string;\n}): Promise<void> {\n const { repoPath, region, promptServiceUrl } = args;\n const wrapperSpin = p.spinner();\n wrapperSpin.start('Installing bin/op-compose wrapper…');\n const wrapper = await installOpComposeWrapper({ repoDir: repoPath, region, promptServiceUrl });\n if (!wrapper.ok) {\n wrapperSpin.stop(pc.red('✗ op-compose wrapper install failed.'));\n p.cancel(wrapper.reason ?? 'op-compose wrapper install failed.');\n process.exit(1);\n }\n wrapperSpin.stop(pc.green(`✓ Installed ${wrapper.path} (mode 0755).`));\n}\n\n// ---- Phase 7: ghcr.io login ----\nasync function loginGhcrPhase(): Promise<void> {\n const ghcrSpin = p.spinner();\n ghcrSpin.start('Authenticating Docker to ghcr.io…');\n const ghcr = await loginToGhcr();\n if (!ghcr.ok) {\n ghcrSpin.stop(pc.red('✗ ghcr.io login failed.'));\n p.cancel(ghcr.reason ?? 'ghcr.io login failed.');\n process.exit(1);\n }\n ghcrSpin.stop(pc.green('✓ Logged in to ghcr.io.'));\n}\n\n/**\n * The models bootstrap pulls into Ollama, in pull order. The LLM is always\n * pulled. The embedding model is pulled ONLY when the knowledge service will\n * use the Ollama daemon for embeddings (`EMBEDDINGS_PROVIDER=ollama`); under\n * the default `xenova` (in-process) provider it's never loaded, so pulling\n * nomic-embed-text would just waste a download on a fresh node. When present,\n * the embedding pulls first — it's small, giving fast \"✓ pulled\" feedback\n * before the LLM's multi-GB download dominates the spinner. Pure helper.\n */\nexport function modelsToPull(args: {\n provider: EmbeddingsProvider;\n llmModel: string;\n embeddingModel: string;\n}): string[] {\n const { provider, llmModel, embeddingModel } = args;\n return provider === 'ollama' ? [embeddingModel, llmModel] : [llmModel];\n}\n\n// ---- Phase 8: Ollama ----\nasync function runOllamaPhase(args: {\n opts: BootstrapOptions;\n embeddingModel: string;\n llmModel: string;\n embeddingsProvider: EmbeddingsProvider;\n}): Promise<void> {\n const { opts, embeddingModel, llmModel, embeddingsProvider } = args;\n if (opts.skipOllama) return;\n\n const olSpin = p.spinner();\n olSpin.start(`Pulling + warming Ollama models… (${estimatedPullTime(llmModel)})`);\n let olHealth = await checkOllamaHealth();\n if (!olHealth.reachable) {\n // S5 review fix: try to start the service before bailing. The\n // operator's pretty much always going to want this anyway, and\n // `brew services start` is no-op-safe.\n olSpin.message('Ollama not reachable — running `brew services start ollama`…');\n const start = await startOllamaService();\n if (!start.ok) {\n olSpin.stop(pc.red('✗ Couldn\\'t start Ollama service.'));\n p.cancel(\n `${start.reason ?? 'unknown'} — start it manually with \\`brew services start ollama\\` and re-run with --skip-brew --skip-launch-agent.`,\n );\n process.exit(1);\n }\n // Brew services start returns immediately; the daemon needs a few\n // seconds before /api/tags responds. Quick wait + re-probe.\n await new Promise((res) => setTimeout(res, 3000));\n olHealth = await checkOllamaHealth();\n if (!olHealth.reachable) {\n olSpin.stop(\n pc.yellow('⚠ Ollama service started but daemon not yet answering on :11434.'),\n );\n p.cancel(\n 'Give it another few seconds, then re-run with --skip-brew --skip-launch-agent.',\n );\n process.exit(1);\n }\n }\n const toPull = modelsToPull({ provider: embeddingsProvider, llmModel, embeddingModel });\n const modelReport = await setupModels(toPull, (model, status) => {\n olSpin.message(`${status}: ${model}`);\n });\n olSpin.stop(\n modelReport.failed.length === 0\n ? pc.green(\n `✓ ${modelReport.pulled.length} pulled, ${modelReport.alreadyPresent.length} present, ${modelReport.warmed.length} warmed`,\n )\n : pc.yellow(`⚠ ${modelReport.failed.length} model pull(s) failed`),\n );\n if (embeddingsProvider !== 'ollama') {\n p.note(\n `${pc.dim('·')} Skipped pulling the embedding model — EMBEDDINGS_PROVIDER=${embeddingsProvider} computes embeddings in-process (no Ollama model needed).`,\n 'Embeddings',\n );\n }\n const probe = await probeHostDockerInternal();\n if (!probe.ok) {\n p.note(`${pc.yellow('⚠')} ${probe.reason}`, 'Docker host networking');\n }\n}\n\n// ---- Phase 8c: write the single-source `.env` (model config) ----\n//\n// docker compose auto-loads `.env` from the compose file's directory, so the\n// resolved model config lands there as the single source of truth — every\n// service (and every future partial recreate) interpolates `${LLM_MODEL:-…}`\n// to the SAME value regardless of shell/launchd env. Only non-secret config\n// is written; secrets stay in Keychain (op-compose hydrates them).\n//\n// Runs even under --skip-stack so the operator's later `./bin/op-compose up`\n// reads it. `overwrite: true` because bootstrap IS an explicit model\n// (re)selection — the operator either passed --llm-model or picked one\n// interactively, so their choice is authoritative over a stale block. Operator\n// lines OUTSIDE the managed block are always preserved.\nasync function runEnvFilePhase(args: {\n repoPath: string;\n llmModel: string;\n embeddingModel: string;\n embeddingsProvider: EmbeddingsProvider;\n localOnly: boolean;\n supabaseUrl: string;\n}): Promise<void> {\n const { repoPath, llmModel, embeddingModel, embeddingsProvider, localOnly, supabaseUrl } = args;\n const envSpin = p.spinner();\n envSpin.start('Writing model config to the node .env…');\n const res = await writeManagedEnv(\n repoPath,\n {\n llmModel,\n embeddingModel,\n embeddingsProvider,\n // NODE_ENV=development only for local-dev nodes; production nodes leave\n // it unset (the compose default / container images decide).\n ...(localOnly ? { nodeEnv: 'development' } : {}),\n // SUPABASE_URL lives in the managed block (not an op-compose export) so\n // docker compose reads the node's real public URL from .env durably (#43).\n supabaseUrl,\n },\n { overwrite: true },\n );\n if (!res.ok) {\n envSpin.stop(pc.red('✗ Failed to write the node .env.'));\n p.cancel(res.reason ?? 'writing .env failed.');\n process.exit(1);\n }\n envSpin.stop(\n res.unchanged\n ? pc.green(`✓ Model config already current in ${res.path}.`)\n : pc.green(`✓ Wrote model config to ${res.path} (LLM_MODEL=${llmModel}).`),\n );\n}\n\n// Hydrate every `${VAR:?…}`-enforced env var on the compose subprocess.\n// launchctl setenv doesn't reach pre-existing shells or sshd children, so\n// bootstrap's own compose calls would otherwise hard-fail even though every\n// value sits in process scope from the loadSecret pass. Pure builder — kept\n// separate so the env-hydration rule stays unit-testable.\nexport function buildComposeEnv(args: {\n secrets: CollectedSecrets;\n}): NodeJS.ProcessEnv {\n const { secrets } = args;\n return {\n PGSODIUM_ROOT_KEY: secrets.pgsodiumKey,\n POSTGRES_PASSWORD: secrets.postgresPassword,\n JWT_SECRET: secrets.jwtSecret,\n SUPABASE_ANON_KEY: secrets.supabaseAnonKey,\n SUPABASE_SERVICE_ROLE_KEY: secrets.supabaseServiceRoleKey,\n DASHBOARD_PASSWORD: secrets.dashboardPassword,\n // Real per-node gateway HMAC secret + the derived API_KEYS map. These\n // override the template's well-known `${GATEWAY_HMAC_SECRET:-…}` /\n // `${API_KEYS:-…}` compose defaults so a Tunnel-exposed node never signs\n // with the shared placeholder. The api-gateway's key MUST equal\n // GATEWAY_HMAC_SECRET, which renderApiKeys guarantees.\n GATEWAY_HMAC_SECRET: secrets.gatewayHmacSecret,\n API_KEYS: renderApiKeys(secrets.gatewayHmacSecret),\n GRAFANA_ADMIN_PASSWORD: secrets.grafanaAdminPassword,\n SUPABASE_URL: secrets.supabaseUrl,\n AUTH_JWT_SECRET: process.env['AUTH_JWT_SECRET'] ?? secrets.jwtSecret,\n ...(secrets.tunnelToken !== undefined ? { TUNNEL_TOKEN: secrets.tunnelToken } : {}),\n // prompt-service wiring — mirrors the op-compose wrapper so bootstrap's OWN\n // compose calls can process the region-with-prompts overlay instead of\n // aborting on `${PROMPTS_DB_PASSWORD:?}`. PROMPT_SERVICE_URL is always set\n // (in-network for colocated, remote otherwise); the rest are present only\n // when the node runs or calls a prompt-service. (#90)\n PROMPT_SERVICE_URL: secrets.promptServiceUrl,\n ...(secrets.promptsDbPassword !== undefined\n ? { PROMPTS_DB_PASSWORD: secrets.promptsDbPassword }\n : {}),\n ...(secrets.promptServiceApiKey !== undefined\n ? { PROMPT_SERVICE_API_KEY: secrets.promptServiceApiKey }\n : {}),\n ...(secrets.promptServiceApiKeys !== undefined\n ? { PROMPT_SERVICE_API_KEYS: secrets.promptServiceApiKeys }\n : {}),\n ...(secrets.promptServiceAdminApiKeys !== undefined\n ? { PROMPT_SERVICE_ADMIN_API_KEYS: secrets.promptServiceAdminApiKeys }\n : {}),\n // Model config (LLM_MODEL / EMBEDDINGS_OLLAMA_MODEL / NODE_ENV) is intentionally\n // NOT injected here — it lives in the node's `.env` (runEnvFilePhase),\n // which docker compose auto-loads. Injecting it into the subprocess env\n // would shadow `.env` (shell env > .env) and reintroduce the drift the\n // single-source `.env` exists to eliminate.\n };\n}\n\n// ---- Public-profile secret guard (#27) ----\n// A node exposed via the Cloudflare Tunnel (the `public` compose profile,\n// activated for every non-`--local-only` bootstrap) MUST NOT sign\n// gateway→microservice requests with the template's well-known\n// GATEWAY_HMAC_SECRET / API_KEYS default — every checkout of the template\n// carries that identical string. buildComposeEnv always injects a real\n// per-node value, so in normal bootstrap this guard never trips; it is a\n// fail-closed backstop against a future refactor that lets the placeholder\n// (or an unset value) reach a Tunnel-exposed compose `up`.\n//\n// `--local-only` bootstraps do NOT activate the public profile, so the\n// defaults are acceptable there and MUST NOT be blocked.\nexport type PublicProfileSecretVerdict =\n | { ok: true }\n | { ok: false; reason: string };\n\n// Pure decision — unit-tested independently of the interactive compose flow.\n// `env` is the resolved compose env buildComposeEnv produced.\nexport function checkPublicProfileSecrets(\n env: NodeJS.ProcessEnv,\n): PublicProfileSecretVerdict {\n const gateway = env['GATEWAY_HMAC_SECRET'];\n const apiKeys = env['API_KEYS'];\n const bad = (v: string | undefined): boolean =>\n v === undefined || v.length === 0 || v.includes(WELL_KNOWN_GATEWAY_HMAC_SECRET);\n if (bad(gateway) || bad(apiKeys)) {\n return {\n ok: false,\n reason:\n 'Refusing to expose this node via the Cloudflare Tunnel (public profile) with the ' +\n 'well-known GATEWAY_HMAC_SECRET / API_KEYS default. Every copy of the template ships ' +\n 'the same placeholder value — a Tunnel-exposed gateway signed with it is trivially ' +\n 'forgeable. Re-run `create-op-node bootstrap` so it generates a real per-node secret ' +\n '(or use `--local-only` to run without the public profile).',\n };\n }\n return { ok: true };\n}\n\n// Enforce the guard, aborting bootstrap with an operator-friendly message\n// when the public profile would carry the well-known default. No-op when\n// the public profile isn't in play (--local-only).\nfunction enforcePublicProfileSecrets(args: {\n localOnly: boolean;\n env: NodeJS.ProcessEnv;\n}): void {\n if (args.localOnly) return;\n const verdict = checkPublicProfileSecrets(args.env);\n if (!verdict.ok) {\n p.cancel(verdict.reason);\n process.exit(1);\n }\n}\n\n// ---- Phase 8b: fail-closed image-signature gate ----\n// Before pulling, confirm each opuspopuli-published image carries a valid\n// cosign signature from the release workflow (keyless, Rekor-logged). This is\n// FAIL-CLOSED: a missing cosign binary, an un-enumerable compose config, or any\n// failed verification aborts the bootstrap — unless the operator opts out with\n// --skip-signature-check. Third-party base images (postgres, kong, ollama, …)\n// aren't signed by us, so they're excluded. Images are verified by their\n// compose ref (tag); cosign resolves the tag to a digest.\n//\n// This gate verifies the *images* we publish, not the compose file itself — a\n// compromised compose that points services off `ghcr.io/opuspopuli/*` resolves\n// to zero verifiable images (handled loudly by the `no-images` case).\n\nexport type SignatureGatePlan =\n | { kind: 'skip' }\n | { kind: 'enumerate-failed' }\n | { kind: 'no-images' }\n | { kind: 'verify'; images: string[] };\n\n// Pure decision for the signature gate — separated so the branch logic\n// (bypass / can't-enumerate / nothing-to-verify / verify-these) is unit-tested\n// independently of the interactive cosign loop. `allImages` is the resolved\n// compose image list, or null when enumeration failed.\nexport function planSignatureGate(\n allImages: string[] | null,\n opts: Pick<BootstrapOptions, 'skipSignatureCheck'>,\n): SignatureGatePlan {\n if (opts.skipSignatureCheck) return { kind: 'skip' };\n if (allImages === null) return { kind: 'enumerate-failed' };\n const images = filterVerifiableImages(allImages);\n if (images.length === 0) return { kind: 'no-images' };\n return { kind: 'verify', images };\n}\n\nasync function verifyImageSignaturesPhase(\n composeOpts: ComposeOptions,\n opts: BootstrapOptions,\n): Promise<void> {\n // Only enumerate when we're actually going to verify (skip avoids the call).\n const allImages = opts.skipSignatureCheck ? null : await composeConfigImages(composeOpts);\n const plan = planSignatureGate(allImages, opts);\n\n if (plan.kind === 'skip') {\n p.note(\n pc.yellow(\n '⚠ Skipping cosign signature verification (--skip-signature-check). ' +\n 'Images will be pulled unverified — you are trusting the registry contents.',\n ),\n 'Supply chain',\n );\n return;\n }\n if (plan.kind === 'enumerate-failed') {\n p.cancel(\n '`docker compose config --images` failed, so signatures can\\'t be verified. ' +\n 'Fix the compose config (or re-run with --skip-signature-check to bypass).',\n );\n process.exit(1);\n }\n if (plan.kind === 'no-images') {\n // Loud on purpose: prod compose should carry opuspopuli images, so an empty\n // set is either a custom compose or a tampered one pointing elsewhere.\n p.note(\n pc.yellow(\n '⚠ No `ghcr.io/opuspopuli/*` images in the resolved compose set, so there is ' +\n 'nothing to verify. If you did not expect this, inspect your compose files — ' +\n 'this gate verifies the images we publish, not the compose file itself.',\n ),\n 'Supply chain',\n );\n return;\n }\n\n // plan.kind === 'verify'. cosign reads docker's ghcr credentials (populated by\n // the earlier ghcr.io login phase) to fetch each signature.\n const spin = p.spinner();\n spin.start('Verifying image signatures with cosign…');\n for (const image of plan.images) {\n spin.message(`cosign verify ${image}`);\n const verdict = await cosignVerifyImage({\n image,\n ...(opts.certificateIdentityRegexp\n ? { certificateIdentityRegexp: opts.certificateIdentityRegexp }\n : {}),\n });\n if (!verdict.ok) {\n spin.stop(pc.red(`✗ Signature verification failed for ${image}.`));\n const detail = verdict.skipped\n ? `${verdict.reason}\\n` +\n 'cosign is required for the fail-closed signature gate — install it ' +\n '(`brew install cosign`, or re-run without --skip-brew) or bypass with --skip-signature-check.'\n : verdict.reason;\n p.cancel(detail);\n process.exit(1);\n }\n }\n spin.stop(\n pc.green(\n `✓ ${plan.images.length} image signature${plan.images.length === 1 ? '' : 's'} verified.`,\n ),\n );\n}\n\n// ---- Phase 9 + 10: docker compose pull + up, then health-check loop ----\nasync function runStackPhase(args: {\n opts: BootstrapOptions;\n repoPath: string;\n region: string;\n composeFile: string[];\n secrets: CollectedSecrets;\n}): Promise<void> {\n const { opts, repoPath, region, composeFile, secrets } = args;\n\n if (opts.skipStack) {\n const profileFlag = opts.localOnly ? '' : '--profile public ';\n p.outro(\n pc.cyan(\n `Stack-up skipped. Run \\`./bin/op-compose -f ${composeFile.join(' -f ')} ${profileFlag}pull && ./bin/op-compose -f ${composeFile.join(' -f ')} ${profileFlag}up -d\\` from ${repoPath} when ready. (op-compose hydrates Keychain secrets per-invocation; use it instead of raw \\`docker compose\\`.)`,\n ),\n );\n return;\n }\n\n const composeFiles = resolveComposeFiles(repoPath, composeFile);\n const composeEnv = buildComposeEnv({ secrets });\n // In production mode, activate the `public` compose profile so cloudflared\n // starts. In --local-only mode pass no profiles — the template gates\n // cloudflared behind `public`, so an empty profiles array keeps it down.\n const composeOpts = {\n files: composeFiles,\n cwd: repoPath,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n profiles: opts.localOnly ? LOCAL_PROFILES : PUBLIC_PROFILES,\n env: composeEnv,\n };\n\n // Fail-closed: never bring up the public (Tunnel-exposed) profile with the\n // template's well-known GATEWAY_HMAC_SECRET / API_KEYS default. (#27)\n enforcePublicProfileSecrets({ localOnly: Boolean(opts.localOnly), env: composeEnv });\n\n // In --local-only mode, evict any cloudflared container left over from a\n // prior public bootstrap on this Studio. Without this, `compose ps` would\n // still list cloudflared and the health-check loop would demand it reach\n // healthy with no TUNNEL_TOKEN — hanging until timeout. (review S3)\n if (opts.localOnly) {\n const evict = p.spinner();\n evict.start('Evicting any cloudflared from a prior public bootstrap…');\n const rm = await composeRemoveService(\n { ...composeOpts, profiles: PUBLIC_PROFILES },\n 'cloudflared',\n );\n evict.stop(\n rm.ok\n ? pc.green('✓ cloudflared not present (or removed).')\n : pc.yellow(`⚠ cloudflared eviction reported: ${rm.reason ?? 'unknown'} — continuing.`),\n );\n }\n\n await verifyImageSignaturesPhase(composeOpts, opts);\n\n const pullSpin = p.spinner();\n pullSpin.start('Pulling images from ghcr.io… (~5–15 min first run, < 1 min cached)');\n const pull = await composePull(composeOpts);\n if (!pull.ok) {\n pullSpin.stop(pc.red('✗ compose pull failed.'));\n p.cancel(pull.reason ?? 'compose pull failed.');\n process.exit(1);\n }\n pullSpin.stop(pc.green('✓ Images pulled.'));\n\n const upSpin = p.spinner();\n upSpin.start('Starting the stack…');\n const up = await composeUp(composeOpts);\n if (!up.ok) {\n upSpin.stop(pc.red('✗ compose up failed.'));\n p.cancel(up.reason ?? 'compose up failed.');\n process.exit(1);\n }\n upSpin.stop(pc.green('✓ Containers started — waiting for healthy…'));\n\n // ---- Phase 10: health-check loop ----\n const healthSpin = p.spinner();\n healthSpin.start('Polling for healthy containers… (every 5s, up to 5 min)');\n const outcome = await waitForHealthy(composeOpts, {\n onPoll: (snaps) => {\n const healthy = snaps.filter((s) => s.health === 'healthy').length;\n const running = snaps.filter((s) => s.state === 'running').length;\n healthSpin.message(`${healthy}/${running} healthy`);\n },\n });\n healthSpin.stop(healthOutcomeHeadline(outcome));\n finishHealthOutcome(outcome, { region, opts, composeFiles });\n}\n\n// Spinner headline for the terminal state of the health loop.\nfunction healthOutcomeHeadline(\n outcome: Awaited<ReturnType<typeof waitForHealthy>>,\n): string {\n switch (outcome.kind) {\n case 'healthy':\n return pc.green(`✓ All ${outcome.snapshots.length} containers healthy.`);\n case 'unhealthy':\n return pc.red(`✗ ${outcome.problem}`);\n case 'timeout':\n return pc.yellow('⚠ Timed out waiting for all containers to report healthy.');\n default:\n return assertNever(outcome) as never;\n }\n}\n\n// Print the outro / diagnostics and exit for the terminal health state.\nfunction finishHealthOutcome(\n outcome: Awaited<ReturnType<typeof waitForHealthy>>,\n args: { region: string; opts: BootstrapOptions; composeFiles: string[] },\n): void {\n const { region, opts, composeFiles } = args;\n switch (outcome.kind) {\n case 'healthy':\n if (opts.localOnly) {\n p.outro(\n pc.cyan(\n [\n `Region ${region} is up locally (no public Cloudflare Tunnel — cloudflared stays down).`,\n `Access from your laptop over Tailscale at this Studio's tailnet IP.`,\n `When you're ready to expose publicly, re-run \\`bootstrap\\` without --local-only.`,\n ].join('\\n'),\n ),\n );\n } else {\n p.outro(\n pc.cyan(\n `Region ${region} is up. Next: verify off-LAN with \\`npx create-op-node verify --domain <your-domain>\\`.`,\n ),\n );\n }\n return;\n case 'unhealthy':\n // Surface the full snapshot table for diagnosis — N10 review fix.\n p.note(\n outcome.snapshots\n .map((s) => ` ${kvHealth(s.health)} ${s.name} (${s.state})`)\n .join('\\n'),\n 'Container state',\n );\n p.cancel(\n `Inspect with \\`docker compose -f ${composeFiles.join(' -f ')} logs\\`. Fix and re-run.`,\n );\n process.exit(1);\n // eslint-disable-next-line no-fallthrough\n case 'timeout':\n p.note(\n outcome.snapshots\n .map((s) => ` ${kvHealth(s.health)} ${s.name} (${s.state})`)\n .join('\\n'),\n 'Container state at timeout',\n );\n // B1 review fix: don't print the success outro. The stack hasn't\n // settled and `verify` would mislead — instruct the operator to\n // re-poll and exit non-zero.\n p.cancel(\n `Re-run \\`create-op-node bootstrap --skip-brew --skip-launch-agent --skip-ollama\\` to skip the already-done phases and poll again once containers settle.`,\n );\n process.exit(1);\n // eslint-disable-next-line no-fallthrough\n default:\n // Exhaustiveness check — adding a new HealthOutcome variant without\n // updating this switch fails the type check.\n assertNever(outcome);\n return;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n/**\n * Resolve the compose-file paths the wizard will pass to docker. Absolute\n * paths pass through; relative paths are resolved against `repoPath`. Pure\n * helper for unit testing — keeps the path-resolution rule in one place.\n */\nexport function resolveComposeFiles(\n repoPath: string,\n composeFile: string[] | undefined,\n): string[] {\n const inputs = composeFile ?? ['docker-compose-prod.yml'];\n return inputs.map((f) => (f.startsWith('/') ? f : join(repoPath, f)));\n}\n\n/**\n * Commander `argParser` for the repeatable `--compose-file` option (shared by\n * `bootstrap` and `reset`).\n *\n * Without a reducer, commander stores a value-taking option as the LAST string\n * passed — NOT an array. So `--compose-file a --compose-file b` yields the bare\n * string `\"b\"`, and even a single `--compose-file a` yields `\"a\"`. Both then\n * hit `resolveComposeFiles`'s `.map`, which throws\n * `inputs.map is not a function`. (#82)\n *\n * This accumulates each occurrence into an array. `previous` is `undefined` on\n * the first invocation (the option carries no default), so it's seeded with an\n * empty array; downstream code keeps its `?? default` fallback for the\n * flag-absent case.\n */\nexport function collectComposeFile(value: string, previous: string[] | undefined): string[] {\n return [...(previous ?? []), value];\n}\n\n/**\n * Resolve the Ollama model identifiers from operator flags + defaults.\n * Pure helper — mirrors `resolveComposeFiles` so the flag-resolution rule\n * lives in one place and stays unit-testable.\n *\n * Returned in the order Ollama pulls + warms them: `[embedding, llm]`.\n * The embedding model is typically tiny (~500 MB), so emitting it first\n * gives the operator a visible \"✓ pulled\" milestone before the LLM's\n * potentially-tens-of-gigabytes download dominates the spinner. (S3)\n */\nexport function resolveModels(opts: {\n llmModel?: string;\n embeddingModel?: string;\n}): readonly [embedding: string, llm: string] {\n return [\n opts.embeddingModel ?? DEFAULT_EMBEDDING_MODEL,\n opts.llmModel ?? DEFAULT_LLM_MODEL,\n ] as const;\n}\n\n/** Curated LLM choices shown in the interactive picker. Qwen-only because\n * the Opus Populi platform serves Spanish-speaking civic users and Qwen\n * has the strongest Spanish (and broader multilingual) capability of the\n * open-weight models in this tier. Other Ollama models are still\n * reachable via the \"Other…\" sentinel. Sized per\n * docs/docker-resources.md in the opuspopuli-node template.\n * Order = display order. */\nexport const LLM_MODEL_CHOICES = [\n {\n value: 'qwen3.6:35b-a3b',\n label: 'qwen3.6:35b-a3b',\n hint: '35B MoE, ~3B active — fast on Apple Silicon. ~24 GB footprint. Pre-selected on 64 GB+ nodes. Best Spanish + multilingual quality. Pull ~24 GB, 30–60 min.',\n },\n {\n value: 'qwen3:14b',\n label: 'qwen3:14b',\n hint: '14B, ~9 GB footprint. Pre-selected on 32–64 GB nodes. Solid Spanish, faster than the 35B MoE. Pull ~9 GB, 10–20 min.',\n },\n {\n value: 'qwen2.5:7b',\n label: 'qwen2.5:7b',\n hint: '7B, ~5 GB footprint. Pre-selected on 16–32 GB nodes; also the -y / scripted default. Pull ~5 GB, 3–5 min.',\n },\n {\n value: 'qwen2.5:3b',\n label: 'qwen2.5:3b',\n hint: '3B, ~2–3 GB footprint. Pre-selected on ≤ 16 GB nodes (Mac Mini). Lightest option. Pull ~2 GB, 2–3 min.',\n },\n] as const;\n\nconst OTHER_SENTINEL = '__OTHER__';\n\n/**\n * Pick the LLM that fits the operator's unified-memory budget. Ollama uses\n * roughly the model's parameter count in GB (in q4 quantization), plus a\n * context-window buffer. The Studio also needs RAM for macOS + Docker +\n * the data services. Thresholds below leave 30–40 GB headroom for that.\n *\n * Returns null when `ramGB` is null (sysctl unavailable) so the caller\n * falls back to the platform-default recommendation. (Pure helper —\n * exported for unit tests.)\n */\nexport function recommendLlmModel(ramGB: number | null): string | null {\n if (ramGB === null) return null;\n // Tier on TOTAL model footprint, not param count: the LLM shares unified\n // memory with ~22 Docker containers + Postgres, so each tier leaves headroom\n // for the rest of the stack. Boundaries match the #98 sizing table.\n if (ramGB >= 64) return 'qwen3.6:35b-a3b';\n if (ramGB >= 32) return 'qwen3:14b';\n if (ramGB >= 16) return 'qwen2.5:7b';\n return 'qwen2.5:3b';\n}\n\n/**\n * Prompt the operator to pick an LLM model. Skipped when `--yes` is set\n * (returns the conservative default) or when `--llm-model` was passed\n * (caller short-circuits before this is reached).\n *\n * Pre-selects based on the node's detected unified memory — 64 GB+ gets the\n * qwen3.6:35b-a3b MoE, 32–64 GB gets qwen3:14b, 16–32 GB gets qwen2.5:7b,\n * ≤ 16 GB gets qwen2.5:3b. When detection fails (non-macOS, sysctl missing),\n * defaults to DEFAULT_LLM_MODEL (the conservative scripted default).\n *\n * \"Other...\" branches to a text input validated against the same\n * MODEL_NAME_RE the LaunchAgent uses for setenv injection safety.\n */\nasync function selectLlmModel(opts: { yes?: boolean }): Promise<string> {\n if (opts.yes) return DEFAULT_LLM_MODEL;\n\n const ramGB = await detectUnifiedMemoryGB();\n const recommended = recommendLlmModel(ramGB) ?? DEFAULT_LLM_MODEL;\n const ramNote = ramGB !== null\n ? `Detected ${ramGB} GB unified memory — pre-selecting ${recommended}.`\n : `Couldn't detect Studio memory — defaulting to ${recommended} (override if your config differs).`;\n\n p.note(ramNote, 'Hardware');\n\n const choice = unwrap(\n await p.select({\n message: 'Choose the LLM model to pull + run',\n initialValue: recommended,\n options: [\n ...LLM_MODEL_CHOICES.map((c) => ({ value: c.value, label: c.label, hint: c.hint })),\n {\n value: OTHER_SENTINEL,\n label: 'Other…',\n hint: 'Specify any Ollama model name (e.g. mistral-small:24b)',\n },\n ],\n }),\n );\n\n if (choice !== OTHER_SENTINEL) return choice;\n\n return unwrap(\n await p.text({\n message: 'Ollama model name',\n placeholder: 'e.g. mistral-small:24b',\n validate: (v) =>\n /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/.test(v ?? '')\n ? undefined\n : 'Letters, digits, `.`, `:`, `_`, `-`, `/` only; must start with alphanumeric',\n }),\n );\n}\n\n/** Rough wall-clock estimate for pulling an Ollama model, based on the\n * size suffix in the tag. Used to populate the Ollama-pull spinner so\n * the operator knows whether to wait or step away. Estimates assume a\n * ~100 Mbps connection; faster networks finish proportionally sooner.\n *\n * Sparse-MoE shapes (`8x22b`) are matched before the plain `Nb` parse\n * because their size suffix in the tag refers to per-expert size, not\n * the total model footprint. */\nexport function estimatedPullTime(model: string): string {\n // Bounded digit runs (real Ollama tags never exceed 3-digit expert counts\n // / 4-digit sizes) so the search can't backtrack super-linearly on a long\n // input.\n if (/\\d{1,3}x\\d{1,3}b/i.test(model)) return '~60+ min for frontier MoE';\n const match = /(\\d{1,4})b\\b/i.exec(model);\n if (!match) return 'time depends on model size';\n const size = Number.parseInt(match[1]!, 10);\n if (size <= 13) return '~3–5 min for ≤ 13B-class';\n if (size <= 35) return '~15–30 min for ~32B-class';\n if (size <= 80) return '~30–60 min for 70B-class';\n return '~60+ min for frontier-class';\n}\n\nfunction kvBool(b: boolean): string {\n return b ? pc.green('on') : pc.yellow('off');\n}\n\nfunction kvFileVault(v: boolean | 'unknown'): string {\n if (v === 'unknown') return pc.dim('unknown');\n return v ? pc.green('on') : pc.dim('off');\n}\n\nfunction kvHealth(h: 'healthy' | 'unhealthy' | 'starting' | 'none'): string {\n switch (h) {\n case 'healthy':\n return pc.green('✓');\n case 'unhealthy':\n return pc.red('✗');\n case 'starting':\n return pc.yellow('…');\n case 'none':\n return pc.dim('-');\n }\n}\n\nfunction repoPathFromLocate(out: LocateOutcome): string | null {\n if (out.kind === 'found' || out.kind === 'cloned') return out.path;\n return null;\n}\n\nfunction handleLocateError(out: LocateOutcome, owner: string, name: string): void {\n switch (out.kind) {\n case 'explicit-not-a-node-repo':\n p.cancel(\n `${out.path} doesn't look like a node repo (missing one of docker-compose-prod.yml / supabase/init/pgsodium_getkey_env.sh). Point --repo-dir at the right place.`,\n );\n return;\n case 'gh-not-installed':\n p.cancel('`gh` not installed — install via `brew install gh` and re-run.');\n return;\n case 'clone-failed':\n p.cancel(\n `Couldn't clone ${owner}/${name}: ${out.reason}. Check repo exists + you have access.`,\n );\n return;\n case 'clone-disallowed':\n p.cancel(\n 'No checked-out node repo found and --no-clone (or similar) was set. Provide --repo-dir.',\n );\n return;\n case 'found':\n case 'cloned':\n // Success cases — handleLocateError shouldn't be called for them, but\n // listing here makes the switch exhaustive so the `never` check below\n // catches any new variant added to LocateOutcome.\n return;\n default: {\n // Compile-time exhaustiveness — if LocateOutcome gains a new variant\n // and isn't handled above, TypeScript fails this assignment.\n assertNever(out);\n return;\n }\n }\n}\n\n/**\n * Verify `gh` is signed in. If not, surface the one-line command to fix and\n * wait for the operator. Doesn't auto-run `gh auth login` since it opens a\n * browser flow and we don't want to fight it. Surfaces `gh auth status`'s\n * stderr so a wrong-account / missing-scope situation isn't silent.\n */\nasync function ensureGhAuth(): Promise<void> {\n const status = await safeExeca('gh', ['auth', 'status']);\n if (status === null) {\n p.cancel('`gh` not on PATH. Install via `brew install gh` and re-run.');\n process.exit(1);\n }\n if (status.exitCode === 0) return;\n\n const detail = (status.stderr || status.stdout).trim();\n p.note(\n [\n '`gh` is not signed in (or signed in to a different account / missing scope).',\n detail ? '' : undefined,\n detail ? pc.dim(detail) : undefined,\n '',\n 'In another shell:',\n '',\n pc.cyan('gh auth login --web'),\n '',\n pc.dim('Then come back and press Enter.'),\n ]\n .filter((l): l is string => typeof l === 'string')\n .join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'gh signed in?', initialValue: true }));\n}\n\n/**\n * Tailscale needs an interactive browser signin. We surface the command +\n * wait for confirmation rather than spawning it ourselves — operators run\n * different node setups (start at login vs. on-demand) and we don't want\n * to second-guess. Tailscale is optional; the rest of the bootstrap\n * continues without it (out-of-band SSH is just less convenient).\n */\nasync function promptTailscaleSignin(): Promise<void> {\n const status = await safeExeca('tailscale', ['status']);\n if (status !== null && status.exitCode === 0) return;\n\n p.note(\n [\n 'Tailscale needs to be signed in (or you can skip — Tailscale is',\n 'optional; it provides out-of-band SSH from your laptop. The rest',\n 'of the bootstrap continues without it).',\n '',\n 'In another shell:',\n '',\n pc.cyan('tailscale up'),\n '',\n pc.dim('Accept the device on your tailnet, then come back and press Enter.'),\n ].join('\\n'),\n 'Manual step',\n );\n unwrap(await p.confirm({ message: 'Tailscale signed in (or skipped)?', initialValue: true }));\n}\n\ninterface LoadSecretInput {\n region: string;\n account: SecretAccount;\n /** Friendly name for prompts and notes. */\n label: string;\n /** Placeholder hint shown in the paste prompt. Ignored when `generate` is set. */\n placeholder?: string;\n /** Format check applied to both Keychain reads (so a stale-bad value is\n * treated as missing) and operator paste input. */\n validate: (v: string) => string | undefined;\n /** When set, on Keychain miss / validate-fail, generate a fresh value\n * instead of prompting. Used by `--local-only` for the pgsodium key —\n * no `init` needed.\n *\n * CRITICAL: when `generate` is set we MUST be able to persist the\n * generated value to Keychain. Otherwise the next bootstrap re-run\n * generates a different fresh key and silently destroys any data\n * encrypted under the previous key. So save failure in the generate\n * path is a hard exit, not a warning. (review B1) */\n generate?: () => string;\n}\n\n/**\n * Materialize a secret. Three paths, in order:\n *\n * 1. Keychain hit + valid → return it.\n * 2. Else if `generate` is set → generate fresh, MUST persist (hard fail\n * if save fails), return. The Keychain item is the durable record;\n * losing it later means losing whatever it encrypted.\n * 3. Else → prompt operator to paste, validate, persist with a warning\n * on save failure (the operator can paste again next time).\n *\n * If `validate` rejects an existing Keychain item, we surface the swap\n * explicitly before regenerating/reprompting — destructive overwrites\n * shouldn't be invisible. (review S1)\n */\nasync function loadSecret(input: LoadSecretInput): Promise<string> {\n const coords = { region: input.region, account: input.account };\n const spin = p.spinner();\n spin.start(`Reading ${input.label} from Keychain…`);\n const existing = await readSecret(coords);\n if (existing && input.validate(existing) === undefined) {\n spin.stop(pc.green(`✓ ${input.label} read from Keychain.`));\n return existing;\n }\n\n // Differentiate \"missing\" from \"present-but-bad-format\" — the latter is a\n // destructive replacement so we say so out loud.\n spin.stop(\n existing\n ? pc.yellow(`⚠ ${input.label} in Keychain failed format validation — will replace.`)\n : pc.dim(`· ${input.label} not in Keychain.`),\n );\n\n if (input.generate) {\n const fresh = input.generate();\n const save = await saveSecret(coords, fresh);\n if (!save.written) {\n // Hard fail (review B1) — we generated a fresh value but couldn't\n // persist it. If we continued, the next bootstrap re-run would\n // generate a DIFFERENT fresh value and destroy whatever this one\n // encrypted. Better to bail loudly and let the operator fix the\n // underlying Keychain issue.\n p.cancel(\n `Generated a fresh ${input.label} but couldn't persist it to Keychain: ${save.reason ?? 'unknown'}. ` +\n `Continuing would risk silent key rotation on the next re-run. ` +\n `Resolve the Keychain access (re-grant via Keychain Access.app or check the security CLI) and re-run.`,\n );\n process.exit(1);\n }\n p.note(`${pc.green('✓')} Generated fresh ${input.label} and stored in Keychain.`, 'Keychain');\n return fresh;\n }\n\n const pasted = unwrap(\n await p.password({\n message: `Paste the ${input.label} for region ${input.region}:`,\n validate: (v) => input.validate(v ?? ''),\n }),\n );\n const save = await saveSecret(coords, pasted);\n if (!save.written) {\n // Paste path: warning is fine since the operator can paste again on the\n // next run. The value isn't lost — it's still wherever they pasted from.\n p.note(\n `${pc.yellow('⚠')} Couldn't persist to Keychain: ${save.reason ?? 'unknown'}. You'll need to paste it again next run.`,\n 'Keychain',\n );\n } else {\n p.note(`${pc.green('✓')} Stored ${input.label} in Keychain for re-runs.`, 'Keychain');\n }\n return pasted;\n}\n","/**\n * `create-op-node reset` — reverse of bootstrap. Stops the stack, unloads\n * the LaunchAgent, removes the pgsodium key file. By default the docker\n * volumes (and therefore the database) are PRESERVED. Pass `--wipe-data`\n * for the destructive variant; it requires retyping the region label as\n * confirmation.\n *\n * Reset does NOT touch cloud-side state (Cloudflare resources, the GitHub\n * repo, the TFC workspace). It also leaves the Keychain items in place —\n * delete those manually via Keychain Access or `security delete-generic-\n * password -s org.opuspopuli.<region> -a <account>` if you want a truly\n * clean slate.\n *\n * Accounts to wipe (under service `org.opuspopuli.<region>`):\n * pgsodium-root-key, tunnel-token, postgres-password, jwt-secret,\n * supabase-anon-key, supabase-service-role-key, dashboard-password,\n * gateway-hmac-secret, grafana-admin-password\n *\n * Wiping pgsodium-root-key permanently destroys every value in\n * supabase_vault for this region. Wiping postgres-password locks you out\n * of the existing database. Don't do either without a backup.\n */\n\nimport { access, readFile } from 'node:fs/promises';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { composeDown, composePs, dockerLogout, GHCR_REGISTRY } from '../lib/docker.js';\nimport { defaultPaths as defaultLaunchAgentPaths, teardownLaunchAgent } from '../lib/launchagent.js';\nimport { locateOrCloneRepo, NODE_REPO_MARKERS } from '../lib/noderepo.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { assertNever } from '../lib/assert.js';\nimport type { ContainerSnapshot } from '../lib/docker.js';\nimport type { LaunchAgentPaths, TeardownResult } from '../lib/launchagent.js';\n\nimport { collectComposeFile, resolveComposeFiles } from './bootstrap.js';\n\ninterface ResetOptions {\n region?: string;\n owner?: string;\n repoDir?: string;\n composeFile?: string[];\n envFile?: string;\n wipeData?: boolean;\n wipeImages?: boolean;\n removeOrphans?: boolean;\n skipStack?: boolean;\n skipLaunchAgent?: boolean;\n keepKeyFile?: boolean;\n skipDockerLogout?: boolean;\n registry?: string;\n dryRun?: boolean;\n yes?: boolean;\n}\n\nconst REGION_RE = /^[a-z0-9-]{2,32}$/;\n\n/* ------------------------------------------------------------------ *\n * Phase-name constants (review S4 / N7) *\n * *\n * Exported so the CLI wrapper, runReset, and tests all share one *\n * source of truth — renames flow through automatically instead of *\n * drifting between the CLI's spinner setup and the orchestration's *\n * emitted phase names. *\n * ------------------------------------------------------------------ */\n\nexport const RESET_PHASES = {\n STOP_STACK: 'Stop stack',\n LAUNCH_AGENT: 'LaunchAgent',\n DOCKER_LOGOUT: 'docker logout',\n} as const;\n\ntype ResetPhaseName = (typeof RESET_PHASES)[keyof typeof RESET_PHASES];\n\n/* ------------------------------------------------------------------ *\n * Orchestration *\n * ------------------------------------------------------------------ */\n\nexport interface ResetPhase {\n readonly name: string;\n /** `dry-run` is reset-specific — verify uses `skipped` for both\n * \"configured-off\" and \"would-do-but-not-running\" because verify\n * has no preview mode. Reset's preview mode wants a distinct icon. */\n readonly status: 'ok' | 'warn' | 'fail' | 'skipped' | 'dry-run';\n readonly detail: string;\n}\n\nexport interface ResetReport {\n readonly phases: ReadonlyArray<ResetPhase>;\n}\n\nexport interface ResetDeps {\n composeDown: typeof composeDown;\n teardownLaunchAgent: typeof teardownLaunchAgent;\n dockerLogout: typeof dockerLogout;\n /** Notification fan-out — lets the CLI render spinners. */\n onPhase?: (phase: ResetPhase) => void;\n}\n\nexport interface ResetInput {\n /** Set when we have a repo path + compose files. When missing the stack\n * phase is reported as skipped. */\n stack?: {\n repoPath: string;\n composeFiles: string[];\n envFile?: string;\n wipeVolumes: boolean;\n /** When true, also remove all images referenced by the compose files\n * (passes `--rmi all` to compose down). Forces a fresh pull on the\n * next bootstrap — used for \"wipe everything and start over\" loops. */\n wipeImages: boolean;\n removeOrphans: boolean;\n /** Placeholder env overlay so `docker compose down` can interpolate the\n * template's `${VAR:?…}`-required variables. `down` never uses the\n * values, so placeholders suffice — and reset then works even when the\n * Keychain secrets are already gone. (#85) */\n env?: NodeJS.ProcessEnv;\n };\n launchAgent?: {\n paths: LaunchAgentPaths;\n keepKeyFile: boolean;\n };\n /** Set when the docker-logout phase should run. The registry value is\n * the argument passed to `docker logout <registry>`. */\n dockerLogout?: { registry: string };\n dryRun: boolean;\n}\n\nconst DEFAULT_DEPS: ResetDeps = {\n composeDown,\n teardownLaunchAgent,\n dockerLogout,\n};\n\n/**\n * Run the three reset phases in reverse-bootstrap order.\n *\n * **Continue-on-failure policy**: each phase runs independently — a\n * `composeDown` failure does NOT short-circuit the LaunchAgent or\n * docker-logout phases. This is intentional: reset is best-effort\n * cleanup, and the operator usually wants the LaunchAgent gone even if\n * the docker daemon is down. Use the returned `ResetReport` to inspect\n * which phases failed.\n *\n * Each phase calls `deps.onPhase` exactly once before runReset moves\n * on, so a CLI consumer can render spinners in lockstep.\n */\nexport async function runReset(input: ResetInput, deps: ResetDeps = DEFAULT_DEPS): Promise<ResetReport> {\n // Each phase computes its ResetPhase; push() records it and fires onPhase\n // in lockstep (same order + timing as the original inline loop) so CLI\n // consumers can render spinners one at a time.\n const phases: ResetPhase[] = [];\n const push = (ph: ResetPhase): void => {\n phases.push(ph);\n deps.onPhase?.(ph);\n };\n\n push(await resetStopStackPhase(input, deps));\n push(await resetLaunchAgentPhase(input, deps));\n push(await resetDockerLogoutPhase(input, deps));\n\n return { phases };\n}\n\n// ---- Phase 1: stop the stack ---------------------------------------\nasync function resetStopStackPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.stack) {\n return {\n name: RESET_PHASES.STOP_STACK,\n status: 'skipped',\n detail: '--skip-stack or no repo path resolved',\n };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.STOP_STACK,\n status: 'dry-run',\n detail: `would run: docker compose -f ${input.stack.composeFiles.join(' -f ')} down${input.stack.wipeVolumes ? ' -v' : ''}${input.stack.removeOrphans ? ' --remove-orphans' : ''}${input.stack.wipeImages ? ' --rmi all' : ''}`,\n };\n }\n const result = await deps.composeDown({\n files: input.stack.composeFiles,\n cwd: input.stack.repoPath,\n ...(input.stack.envFile ? { envFile: input.stack.envFile } : {}),\n // Hydrate placeholder values for the template's `${VAR:?…}` required vars\n // so interpolation succeeds; `down` doesn't use the values. (#85)\n ...(input.stack.env ? { env: input.stack.env } : {}),\n wipeVolumes: input.stack.wipeVolumes,\n removeOrphans: input.stack.removeOrphans,\n ...(input.stack.wipeImages ? { removeImages: 'all' as const } : {}),\n });\n if (!result.ok) {\n return { name: RESET_PHASES.STOP_STACK, status: 'fail', detail: result.reason ?? 'unknown failure' };\n }\n const bits = [\n input.stack.wipeVolumes ? 'volumes destroyed' : 'containers stopped, volumes preserved',\n input.stack.wipeImages ? 'images removed (next bootstrap will re-pull)' : null,\n ].filter(Boolean);\n return { name: RESET_PHASES.STOP_STACK, status: 'ok', detail: bits.join('; ') };\n}\n\n// ---- Phase 2: LaunchAgent ------------------------------------------\nasync function resetLaunchAgentPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.launchAgent) {\n return { name: RESET_PHASES.LAUNCH_AGENT, status: 'skipped', detail: '--skip-launch-agent or no plist found' };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.LAUNCH_AGENT,\n status: 'dry-run',\n detail: `would unload ${input.launchAgent.paths.plistFile}, rm plist${\n input.launchAgent.keepKeyFile ? '' : ' + key file'\n }`,\n };\n }\n const result: TeardownResult = await deps.teardownLaunchAgent(\n input.launchAgent.paths,\n { keepKeyFile: input.launchAgent.keepKeyFile },\n );\n if (!result.ok) {\n const fail = result.steps.find((s) => !s.ok);\n return {\n name: RESET_PHASES.LAUNCH_AGENT,\n status: 'fail',\n detail: `${fail?.step}: ${fail?.reason ?? 'unknown'}`,\n };\n }\n const removed = result.steps.filter((s) => s.step !== 'unload').map((s) => s.step).join(', ');\n return { name: RESET_PHASES.LAUNCH_AGENT, status: 'ok', detail: `unloaded + ${removed}` };\n}\n\n// ---- Phase 3: docker logout ----------------------------------------\nasync function resetDockerLogoutPhase(input: ResetInput, deps: ResetDeps): Promise<ResetPhase> {\n if (!input.dockerLogout) {\n return { name: RESET_PHASES.DOCKER_LOGOUT, status: 'skipped', detail: '--skip-docker-logout' };\n }\n if (input.dryRun) {\n return {\n name: RESET_PHASES.DOCKER_LOGOUT,\n status: 'dry-run',\n detail: `would run: docker logout ${input.dockerLogout.registry}`,\n };\n }\n const result = await deps.dockerLogout(input.dockerLogout.registry);\n if (result.ok) {\n return {\n name: RESET_PHASES.DOCKER_LOGOUT,\n status: 'ok',\n detail: `credentials removed from ${input.dockerLogout.registry}`,\n };\n }\n // See dockerLogout() docstring — older Docker versions return non-zero\n // when not currently logged in. Render as warn so reset doesn't fail\n // overall when the operator wasn't logged in to begin with.\n return { name: RESET_PHASES.DOCKER_LOGOUT, status: 'warn', detail: result.reason ?? 'unknown' };\n}\n\n/* ------------------------------------------------------------------ *\n * CLI wrapper *\n * ------------------------------------------------------------------ */\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction phaseIcon(ph: ResetPhase): string {\n switch (ph.status) {\n case 'ok': return pc.green('✓');\n case 'warn': return pc.yellow('⚠');\n case 'skipped': return pc.dim('·');\n case 'dry-run': return pc.cyan('?');\n case 'fail': return pc.red('✗');\n }\n}\n\nexport const resetCommand = new Command('reset')\n .description(\n 'Reverse the Mac Studio side of bootstrap: stop containers, unload the LaunchAgent, ' +\n 'remove the pgsodium key file. Preserves docker volumes by default — pass --wipe-data ' +\n 'for a full data nuke (requires retyping the region label).',\n )\n .addOption(new Option('--region <slug>', 'Region label (used for --wipe-data confirmation + finding the repo)'))\n .addOption(new Option('--owner <owner>', 'GitHub owner for the node repo').default('OpusPopuli'))\n .addOption(new Option('--repo-dir <path>', 'Explicit path to a checked-out node repo'))\n .addOption(\n new Option(\n '--compose-file <path>',\n 'Repeatable. Compose file relative to repo root. Default: docker-compose-prod.yml',\n ).argParser(collectComposeFile),\n )\n .addOption(new Option('--env-file <path>', 'Compose --env-file. Default: .env.production'))\n .addOption(\n new Option(\n '--wipe-data',\n 'DESTROYS docker volumes (adds -v to `compose down`). Requires retyping the region label as confirmation. Default off — volumes preserved.',\n ).default(false),\n )\n .addOption(\n new Option(\n '--wipe-images',\n 'ALSO remove all docker images referenced by the compose file (adds --rmi all). Forces a fresh pull on next bootstrap. Implies --wipe-data semantics for the iteration loop (\"wipe everything and start over\"). Default off.',\n ).default(false),\n )\n .addOption(\n new Option(\n '--no-remove-orphans',\n 'Do NOT pass --remove-orphans to compose down. Preserves containers from compose files no longer included.',\n ),\n )\n .addOption(new Option('--skip-stack', \"Don't touch docker compose\").default(false))\n .addOption(new Option('--skip-launch-agent', \"Don't touch the LaunchAgent\").default(false))\n .addOption(\n new Option(\n '--keep-key-file',\n \"Preserve the pgsodium key file (only matters when LaunchAgent teardown runs). Useful as belt-and-suspenders backup before a wipe-data run.\",\n ).default(false),\n )\n .addOption(new Option('--skip-docker-logout', \"Don't run `docker logout`\").default(false))\n .addOption(new Option('--registry <registry>', 'Registry to log out of').default(GHCR_REGISTRY))\n .addOption(new Option('--dry-run', 'Show what would happen without acting').default(false))\n .addOption(new Option('-y, --yes', 'Skip non-destructive confirmations (wipe still confirms)').default(false))\n .action(async (opts: ResetOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node reset ')));\n\n const wipeImages = opts.wipeImages ?? false;\n // --wipe-images implies --wipe-data — \"wipe everything\" semantics: no\n // point keeping data tied to images that are about to disappear.\n const wipeData = (opts.wipeData ?? false) || wipeImages;\n const removeOrphans = opts.removeOrphans ?? true; // commander --no-remove-orphans sets this to false\n\n const region = await resolveResetRegion(opts);\n const owner = opts.owner ?? 'OpusPopuli';\n const repoName = `opuspopuli-node-${region}`;\n\n const launchAgentPaths = defaultLaunchAgentPaths();\n const plistExists = await fileExists(launchAgentPaths.plistFile);\n const keyFileExists = await fileExists(launchAgentPaths.keyFile);\n const { repoPath, stackSkipReason } = await locateResetRepo(opts, owner, repoName);\n\n const runningContainers = repoPath\n ? await composePs({\n files: resolveComposeFiles(repoPath, opts.composeFile),\n cwd: repoPath,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n })\n : null;\n\n renderSnapshotNote({\n region,\n repoPath,\n stackSkipReason,\n runningContainers,\n plistExists,\n keyFileExists,\n launchAgentPaths,\n opts,\n wipeData,\n wipeImages,\n });\n\n await confirmReset({ opts, region, wipeData });\n\n // Scan the compose files for `${VAR:?…}`-required vars so `compose down`\n // can interpolate — otherwise it aborts before removing anything. (#85)\n const teardownEnv = repoPath\n ? await computeTeardownEnv(resolveComposeFiles(repoPath, opts.composeFile))\n : undefined;\n\n const input = buildResetInput({\n opts,\n repoPath,\n plistExists,\n launchAgentPaths,\n wipeData,\n wipeImages,\n removeOrphans,\n ...(teardownEnv ? { teardownEnv } : {}),\n });\n await runResetWithSpinners({ opts, region, wipeData, input });\n });\n\n// ----------------------------------------------------------------------------\n// Reset command phases\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: interactive prompts,\n// spinners, and process.exit calls are relocated verbatim.\n\n// ---- Region (needed for confirmation phrase + repo discovery) ----\nasync function resolveResetRegion(opts: ResetOptions): Promise<string> {\n const region = opts.region\n ? opts.region\n : unwrap(\n await p.text({\n message: 'Region label (the slug used during init — e.g. us-ca)?',\n placeholder: 'us-ca',\n validate: (v) =>\n REGION_RE.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens; 2–32 chars',\n }),\n );\n if (!REGION_RE.test(region)) {\n p.cancel(`--region ${JSON.stringify(region)} is not a valid region slug.`);\n process.exit(2);\n }\n return region;\n}\n\n// ---- Locate the node repo (or explain why the stack phase is skipped) ----\n// Exhaustive: every LocateOutcome variant has a deliberate path —\n// operator-supplied --repo-dir mismatch is HARD-fail, ambient cwd miss is\n// SOFT-skip with a visible reason. (review B1)\nasync function locateResetRepo(\n opts: ResetOptions,\n owner: string,\n repoName: string,\n): Promise<{ repoPath?: string; stackSkipReason?: string }> {\n if (opts.skipStack) {\n return { stackSkipReason: '--skip-stack' };\n }\n const located = await locateOrCloneRepo({\n owner,\n name: repoName,\n cwd: process.cwd(),\n allowClone: false,\n ...(opts.repoDir ? { explicit: opts.repoDir } : {}),\n });\n switch (located.kind) {\n case 'found':\n return { repoPath: located.path };\n case 'explicit-not-a-node-repo':\n p.cancel(\n `--repo-dir ${JSON.stringify(located.path)} doesn't look like a node repo ` +\n `(missing one of: ${NODE_REPO_MARKERS.join(', ')}). ` +\n `Verify the path or drop --repo-dir to let reset search the cwd.`,\n );\n return process.exit(2);\n case 'clone-disallowed':\n return { stackSkipReason: `no checkout found at ${process.cwd()}; pass --repo-dir to target one` };\n case 'cloned':\n case 'gh-not-installed':\n case 'clone-failed':\n // Should not be reachable — allowClone: false above. Treat as\n // soft-skip if it ever happens.\n return {\n stackSkipReason: `unexpected outcome ${located.kind} from locateOrCloneRepo with allowClone=false`,\n };\n default:\n return assertNever(located) as never;\n }\n}\n\n// ---- Snapshot note: what's currently present ----\nfunction renderSnapshotNote(args: {\n region: string;\n repoPath: string | undefined;\n stackSkipReason: string | undefined;\n runningContainers: ContainerSnapshot[] | null;\n plistExists: boolean;\n keyFileExists: boolean;\n launchAgentPaths: LaunchAgentPaths;\n opts: ResetOptions;\n wipeData: boolean;\n wipeImages: boolean;\n}): void {\n const {\n region,\n repoPath,\n stackSkipReason,\n runningContainers,\n plistExists,\n keyFileExists,\n launchAgentPaths,\n opts,\n wipeData,\n wipeImages,\n } = args;\n\n let runningContainersLabel: string;\n if (runningContainers === null) {\n runningContainersLabel = pc.dim('unknown');\n } else if (runningContainers.length === 0) {\n runningContainersLabel = pc.dim('none');\n } else {\n runningContainersLabel = pc.cyan(`${runningContainers.length} listed by compose ps`);\n }\n\n p.note(\n [\n `Region: ${pc.cyan(region)}`,\n `Repo path: ${\n repoPath\n ? pc.cyan(repoPath)\n : pc.dim(`not used (${stackSkipReason ?? 'no repo path resolved'})`)\n }`,\n `Running containers: ${runningContainersLabel}`,\n `LaunchAgent plist: ${plistExists ? pc.cyan(launchAgentPaths.plistFile) : pc.dim('not present')}`,\n `pgsodium key file: ${keyFileExists ? pc.cyan(launchAgentPaths.keyFile) : pc.dim('not present')}`,\n `Registry to log out: ${pc.cyan(opts.registry ?? GHCR_REGISTRY)}`,\n `Volume policy: ${wipeData ? pc.red('WIPE') : pc.green('preserve (default)')}`,\n `Image policy: ${wipeImages ? pc.red('WIPE (re-pull on next bootstrap)') : pc.green('keep (default)')}`,\n `Dry run: ${opts.dryRun ? pc.yellow('yes') : pc.dim('no')}`,\n ].join('\\n'),\n 'Snapshot',\n );\n}\n\n// ---- Confirmation gates ----\n// wipe-data requires retyping the region label (modeled on `terraform\n// destroy` — the friction is the point, review B2); otherwise a plain\n// proceed confirm unless --yes / --dry-run.\nasync function confirmReset(args: {\n opts: ResetOptions;\n region: string;\n wipeData: boolean;\n}): Promise<void> {\n const { opts, region, wipeData } = args;\n if (wipeData && !opts.dryRun) {\n unwrap(\n await p.text({\n message: pc.red(`Type the region label to confirm WIPING all volumes (the slug you'd use with --region):`),\n validate: (v) => (v === region ? undefined : `must match the region label exactly`),\n }),\n );\n return;\n }\n if (!opts.dryRun && !opts.yes) {\n const cont = unwrap(\n await p.confirm({\n message: 'Proceed with reset? (volumes will be preserved)',\n initialValue: true,\n }),\n );\n if (!cont) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n }\n}\n\n// ---- Teardown env hydration (#85) ----\n//\n// `docker compose down` interpolates the WHOLE compose file, so the template's\n// `${POSTGRES_PASSWORD:?…}` / `${JWT_SECRET:?…}` required variables must be\n// defined or `down` aborts before removing anything — even though teardown\n// never USES the values. Rather than hydrate real secrets from Keychain (which\n// reset shouldn't depend on — you may be tearing down precisely because the\n// secrets are gone), we scan the compose files for their `:?`-required variable\n// names and fill each with a benign placeholder. Reading the required set from\n// the compose text keeps it in sync with the template instead of drifting\n// against a hardcoded list.\n\n/** A value only needs to be non-empty to satisfy `${VAR:?…}` interpolation;\n * `down` doesn't parse it. */\nconst TEARDOWN_PLACEHOLDER = 'reset-teardown-placeholder';\n\n/** Captures NAME in `${NAME:?…}` and `${NAME?…}` — the interpolation forms that\n * FAIL when the variable is unset. Deliberately does NOT match\n * `${NAME:-default}` (uses its default) or bare `${NAME}` (resolves to empty,\n * no error), which don't need filling. */\nconst REQUIRED_VAR_RE = /\\$\\{([A-Za-z_]\\w*):?\\?/g;\n\n/**\n * Build a minimal env overlay defining every `${VAR:?…}`-required variable\n * referenced by the given compose file contents, using a placeholder for any\n * not already present (non-empty) in `baseEnv`. Pure — unit-tested. (#85)\n */\nexport function buildTeardownEnv(\n composeFileContents: string[],\n baseEnv: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n const overlay: NodeJS.ProcessEnv = {};\n for (const text of composeFileContents) {\n for (const match of text.matchAll(REQUIRED_VAR_RE)) {\n const name = match[1]!;\n const existing = baseEnv[name];\n if (existing === undefined || existing === '') {\n overlay[name] = TEARDOWN_PLACEHOLDER;\n }\n }\n }\n return overlay;\n}\n\n/**\n * Read the resolved compose files and compute the teardown env overlay.\n * Unreadable files are skipped (a genuinely-missing compose file surfaces\n * later when `down` runs); an empty overlay results when nothing is readable.\n */\nasync function computeTeardownEnv(composeFiles: string[]): Promise<NodeJS.ProcessEnv> {\n const contents: string[] = [];\n for (const file of composeFiles) {\n try {\n contents.push(await readFile(file, 'utf8'));\n } catch {\n // Skip — `down` will report a genuinely-missing compose file itself.\n }\n }\n return buildTeardownEnv(contents);\n}\n\n// ---- Build the runReset input from the resolved snapshot + flags ----\nexport function buildResetInput(args: {\n opts: ResetOptions;\n repoPath: string | undefined;\n plistExists: boolean;\n launchAgentPaths: LaunchAgentPaths;\n wipeData: boolean;\n wipeImages: boolean;\n removeOrphans: boolean;\n teardownEnv?: NodeJS.ProcessEnv;\n}): ResetInput {\n const { opts, repoPath, plistExists, launchAgentPaths, wipeData, wipeImages, removeOrphans, teardownEnv } = args;\n const stack = repoPath\n ? {\n repoPath,\n composeFiles: resolveComposeFiles(repoPath, opts.composeFile),\n wipeVolumes: wipeData,\n wipeImages,\n removeOrphans,\n ...(opts.envFile ? { envFile: opts.envFile } : {}),\n ...(teardownEnv ? { env: teardownEnv } : {}),\n }\n : undefined;\n const launchAgent =\n plistExists && !opts.skipLaunchAgent\n ? {\n paths: launchAgentPaths,\n keepKeyFile: opts.keepKeyFile ?? false,\n }\n : undefined;\n const dockerLogoutInput = !opts.skipDockerLogout\n ? { registry: opts.registry ?? GHCR_REGISTRY }\n : undefined;\n return {\n ...(stack ? { stack } : {}),\n ...(launchAgent ? { launchAgent } : {}),\n ...(dockerLogoutInput ? { dockerLogout: dockerLogoutInput } : {}),\n dryRun: opts.dryRun ?? false,\n };\n}\n\n// ---- Run runReset with a spinner per acting phase, then report ----\nasync function runResetWithSpinners(args: {\n opts: ResetOptions;\n region: string;\n wipeData: boolean;\n input: ResetInput;\n}): Promise<void> {\n const { opts, region, wipeData, input } = args;\n\n // Start a spinner per phase that will actually act (not skipped, not\n // dry-run). The phase name comes from RESET_PHASES so it can't drift from\n // runReset's emitted names. (review S4 / N7)\n const phaseSpins = new Map<ResetPhaseName, ReturnType<typeof p.spinner>>();\n const actingPhases: ResetPhaseName[] = [];\n if (input.stack && !input.dryRun) actingPhases.push(RESET_PHASES.STOP_STACK);\n if (input.launchAgent && !input.dryRun) actingPhases.push(RESET_PHASES.LAUNCH_AGENT);\n if (input.dockerLogout && !input.dryRun) actingPhases.push(RESET_PHASES.DOCKER_LOGOUT);\n for (const name of actingPhases) {\n const s = p.spinner();\n s.start(`${name}…`);\n phaseSpins.set(name, s);\n }\n\n const renderPhase = (ph: ResetPhase): void => {\n const spin = phaseSpins.get(ph.name as ResetPhaseName);\n const line = `${phaseIcon(ph)} ${ph.name}: ${pc.dim(ph.detail)}`;\n if (spin) {\n spin.stop(line);\n phaseSpins.delete(ph.name as ResetPhaseName);\n } else {\n p.log.info(line);\n }\n };\n\n const report = await runReset(input, { ...DEFAULT_DEPS, onPhase: renderPhase });\n\n // Belt-and-suspenders: stop any orphan spinners runReset didn't fire\n // onPhase for. Shouldn't happen given the constants-based wiring above.\n for (const [, spin] of phaseSpins) spin.stop(pc.dim('— skipped'));\n\n reportResetOutcome({ report, opts, wipeData, region });\n}\n\n// ---- Final outro / exit code ----\nfunction reportResetOutcome(args: {\n report: ResetReport;\n opts: ResetOptions;\n wipeData: boolean;\n region: string;\n}): void {\n const { report, opts, wipeData, region } = args;\n const failed = report.phases.filter((ph) => ph.status === 'fail').length;\n if (failed > 0) {\n p.outro(pc.red(`${failed} step${failed === 1 ? '' : 's'} failed.`));\n process.exit(1);\n }\n if (opts.dryRun) {\n p.outro(pc.cyan('Dry run complete. Re-run without --dry-run to apply.'));\n return;\n }\n p.outro(\n pc.green(\n wipeData\n ? `Reset complete — volumes wiped. Re-run \\`create-op-node bootstrap --region ${region}\\` to start fresh.`\n : `Reset complete — volumes preserved. Re-run \\`create-op-node bootstrap --region ${region}\\` to bring the stack back up.`,\n ),\n );\n}\n","/**\n * HTTP probes for `verify`. Two helpers:\n *\n * - `httpProbe` — GET against a URL, return status + truncated body.\n * Used for the `/health` endpoint check.\n * - `graphqlProbe` — POST `{ query: \"{ __typename }\" }`, parse the\n * envelope, confirm it looks like a GraphQL response\n * rather than (say) an HTML error page from the proxy.\n *\n * Both swallow network errors into a `{ ok: false, reason }` so the verify\n * wizard reports them as a phase failure instead of crashing.\n */\n\nimport { BODY_PREVIEW_MAX, VERIFY_NETWORK_TIMEOUT_MS } from './constants.js';\n\n/** Spec-preferred GraphQL response media type. Apollo Gateway accepts plain\n * `application/json` too, but stricter or future implementations may not —\n * send both. (graphql-over-http spec) */\nconst GRAPHQL_ACCEPT = 'application/graphql-response+json, application/json';\n\n/** Slice cap when reading a response body for diagnostics. Streaming would\n * let us bail at this byte count too; for now we read the whole text and\n * cap on display, which is fine for the small bodies these endpoints\n * return. If a pathological server returns gigabytes, the AbortController\n * will fire first. */\nasync function readBodyCapped(res: Response): Promise<string> {\n const text = await res.text();\n return text.slice(0, BODY_PREVIEW_MAX);\n}\n\nexport interface HttpProbeOk {\n ok: true;\n status: number;\n /** First N chars of the response body — useful for surface-level diagnostics\n * (\"got HTML when expecting JSON\"). Capped at BODY_PREVIEW_MAX. */\n bodyPreview: string;\n}\n\nexport interface HttpProbeFailed {\n ok: false;\n reason: string;\n /** Set when we got a response back but the status was unexpected; the\n * wizard renders this in the failure block. */\n status?: number;\n}\n\nexport type HttpProbeResult = HttpProbeOk | HttpProbeFailed;\n\nexport interface HttpProbeInput {\n url: string;\n /** Default 200. Set to e.g. 204 if you're probing a no-content endpoint. */\n expectedStatus?: number;\n timeoutMs?: number;\n /** Injectable for tests. Defaults to globalThis.fetch. */\n fetchImpl?: typeof fetch;\n}\n\nexport async function httpProbe(input: HttpProbeInput): Promise<HttpProbeResult> {\n const expected = input.expectedStatus ?? 200;\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const fetchImpl = input.fetchImpl ?? fetch;\n\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), timeoutMs);\n try {\n const res = await fetchImpl(input.url, { method: 'GET', signal: ctrl.signal });\n const bodyPreview = await readBodyCapped(res);\n if (res.status !== expected) {\n // (review N5) Surface the body on a status mismatch the same way\n // graphqlProbe does, so the operator can see the actual error page.\n return {\n ok: false,\n status: res.status,\n reason: bodyPreview\n ? `expected HTTP ${expected}, got ${res.status}: ${bodyPreview}`\n : `expected HTTP ${expected}, got ${res.status}`,\n };\n }\n return { ok: true, status: res.status, bodyPreview };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `GET ${input.url} timed out after ${timeoutMs}ms`\n : `GET ${input.url} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport interface GraphqlProbeOk {\n ok: true;\n /** The value of `data.__typename` from the response envelope. Usually\n * \"Query\" on a healthy Apollo Gateway. */\n typename: string;\n}\n\nexport interface GraphqlProbeFailed {\n ok: false;\n reason: string;\n status?: number;\n}\n\nexport type GraphqlProbeResult = GraphqlProbeOk | GraphqlProbeFailed;\n\nexport interface GraphqlProbeInput {\n url: string;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\n/**\n * POST `{ \"query\": \"{ __typename }\" }` and confirm the envelope shape. Apollo\n * Federation gateways respond with `{ data: { __typename: \"Query\" } }` for\n * this; a misconfigured proxy or a 404 from a wrong path returns HTML or a\n * JSON error envelope that we surface as a failure reason.\n */\nexport async function graphqlProbe(input: GraphqlProbeInput): Promise<GraphqlProbeResult> {\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const fetchImpl = input.fetchImpl ?? fetch;\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), timeoutMs);\n try {\n const res = await fetchImpl(input.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: GRAPHQL_ACCEPT },\n body: JSON.stringify({ query: '{ __typename }' }),\n signal: ctrl.signal,\n });\n const text = await readBodyCapped(res);\n if (res.status !== 200) {\n return {\n ok: false,\n status: res.status,\n reason: `expected HTTP 200, got ${res.status}: ${text}`,\n };\n }\n let envelope: unknown;\n try {\n envelope = JSON.parse(text);\n } catch {\n return {\n ok: false,\n status: res.status,\n reason: `response was not JSON: ${text}`,\n };\n }\n const data = (envelope as { data?: { __typename?: unknown } }).data;\n const typename = data?.__typename;\n if (typeof typename !== 'string') {\n return {\n ok: false,\n status: res.status,\n reason: `response missing { data: { __typename: string } }: ${text}`,\n };\n }\n return { ok: true, typename };\n } catch (err) {\n const reason =\n (err as Error).name === 'AbortError'\n ? `POST ${input.url} timed out after ${timeoutMs}ms`\n : `POST ${input.url} failed: ${(err as Error).message}`;\n return { ok: false, reason };\n } finally {\n clearTimeout(timer);\n }\n}\n","/**\n * Off-LAN TLS handshake probe. Verify uses this to confirm `api.<domain>`\n * actually negotiates a real, in-date cert from anywhere on the internet\n * before bothering with HTTP probes.\n *\n * We use `tls.connect` rather than just letting fetch do its thing because\n * fetch swallows cert-chain details — we want to surface days-to-expiry so\n * the operator can see \"TLS green, but cert expires in 12 days\" as a soft\n * warning, not just \"fetch failed.\"\n */\n\nimport * as tls from 'node:tls';\n\nimport { VERIFY_NETWORK_TIMEOUT_MS } from './constants.js';\n\nexport interface TlsHandshakeOk {\n ok: true;\n /** Negotiated subject CN (from the leaf cert). */\n subject: string;\n /** Issuer organization (e.g. \"Let's Encrypt\"). */\n issuer: string;\n /** Whole days until the leaf cert's `notAfter` field. Negative when the\n * cert is already expired but the server still happened to return one. */\n daysToExpiry: number;\n}\n\nexport interface TlsHandshakeFailed {\n ok: false;\n reason: string;\n}\n\nexport type TlsHandshakeResult = TlsHandshakeOk | TlsHandshakeFailed;\n\nexport interface TlsProbeInput {\n host: string;\n port?: number;\n /** Socket-level timeout in milliseconds. Anything that doesn't ALPN/SNI\n * within this window is reported as a timeout reason, not a hang. */\n timeoutMs?: number;\n /** Injectable for tests. Defaults to the real `tls.connect`. */\n connect?: typeof tls.connect;\n /** Reference time for daysToExpiry math. Injectable for tests so the\n * expected value doesn't drift. */\n now?: Date;\n}\n\n/** Cert subject/issuer fields can be string or string[] (multi-valued RDNs).\n * We render the first item for display. */\nfunction first(v: string | string[] | undefined): string | undefined {\n if (v === undefined) return undefined;\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * One-shot TLS handshake. Returns the result rather than throwing — the\n * verify wizard wants to fold every failure into a single report.\n */\nexport function tlsHandshake(input: TlsProbeInput): Promise<TlsHandshakeResult> {\n const host = input.host;\n const port = input.port ?? 443;\n const timeoutMs = input.timeoutMs ?? VERIFY_NETWORK_TIMEOUT_MS;\n const connect = input.connect ?? tls.connect;\n const now = input.now ?? new Date();\n\n return new Promise<TlsHandshakeResult>((resolve) => {\n let socket: tls.TLSSocket;\n let settled = false;\n const settle = (r: TlsHandshakeResult): void => {\n if (settled) return;\n settled = true;\n socket?.destroy();\n resolve(r);\n };\n\n // `tls.connect` is async by contract, but the injectable `connect` plus\n // certain pathological options (bad servername length, etc.) can throw\n // synchronously. Convert that into a failure result so callers keep\n // seeing the discriminated union instead of a rejection. (review B2)\n try {\n socket = connect({\n host,\n port,\n servername: host,\n timeout: timeoutMs,\n });\n } catch (err) {\n settle({ ok: false, reason: `tls.connect to ${host}:${port} threw: ${(err as Error).message}` });\n return;\n }\n\n socket.once('secureConnect', () => {\n const cert = socket.getPeerCertificate(false);\n if (!cert || Object.keys(cert).length === 0) {\n settle({ ok: false, reason: 'TLS connected but peer presented no certificate' });\n return;\n }\n const notAfter = new Date(cert.valid_to);\n if (Number.isNaN(notAfter.getTime())) {\n settle({ ok: false, reason: `cert presented an unparseable notAfter: ${cert.valid_to}` });\n return;\n }\n const msPerDay = 1000 * 60 * 60 * 24;\n const daysToExpiry = Math.floor((notAfter.getTime() - now.getTime()) / msPerDay);\n const subject = first(cert.subject?.CN) ?? '<no CN>';\n const issuer = first(cert.issuer?.O) ?? first(cert.issuer?.CN) ?? '<no issuer>';\n settle({ ok: true, subject, issuer, daysToExpiry });\n });\n\n socket.once('timeout', () => {\n settle({ ok: false, reason: `TLS handshake to ${host}:${port} timed out after ${timeoutMs}ms` });\n });\n\n socket.once('error', (err) => {\n settle({ ok: false, reason: `TLS handshake to ${host}:${port} failed: ${err.message}` });\n });\n });\n}\n","import { readFileSync } from 'node:fs';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport { tunnelStatus, type TunnelStatusInput, type TunnelStatusResult } from '../lib/cloudflare.js';\nimport { cosignVerifyImage, type CosignVerifyInput, type CosignVerifyResult } from '../lib/cosign.js';\nimport { graphqlProbe, httpProbe, type GraphqlProbeInput, type GraphqlProbeResult, type HttpProbeInput, type HttpProbeResult } from '../lib/http.js';\nimport { unwrap } from '../lib/prompts.js';\nimport { tlsHandshake, type TlsProbeInput, type TlsHandshakeResult } from '../lib/tls.js';\nimport { checkOllamaHealth, modelPresent, type EmbeddingsProvider, type OllamaHealth } from '../lib/ollama.js';\nimport { readEnvModelConfig, type NodeEnvModelConfig } from '../lib/env-file.js';\nimport { looksLikeNodeRepo } from '../lib/noderepo.js';\n\ninterface VerifyOptions {\n domain?: string;\n apiHost?: string;\n cfToken?: string;\n cfTokenFile?: string;\n cfAccountId?: string;\n tunnelId?: string;\n image?: string[];\n certWarnDays?: string;\n showSkipped?: boolean;\n llmModel?: string;\n embeddingModel?: string;\n embeddingsProvider?: EmbeddingsProvider;\n repoDir?: string;\n localOnly?: boolean;\n}\n\nconst DOMAIN_RE = /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i;\n\nexport interface VerifyPhase {\n readonly name: string;\n readonly status: 'ok' | 'warn' | 'fail' | 'skipped';\n readonly detail: string;\n}\n\nexport interface VerifyReport {\n readonly phases: ReadonlyArray<VerifyPhase>;\n}\n\nexport function summarize(report: VerifyReport): { ok: boolean; failed: number; warned: number } {\n let failed = 0;\n let warned = 0;\n for (const ph of report.phases) {\n if (ph.status === 'fail') failed++;\n if (ph.status === 'warn') warned++;\n }\n return { ok: failed === 0, failed, warned };\n}\n\nfunction formatExpiry(days: number): string {\n if (days < 0) return `expired ${-days}d ago`;\n if (days === 0) return 'expires today';\n return `${days}d to expiry`;\n}\n\n/* ------------------------------------------------------------------ *\n * Injectable orchestration (review S3) *\n * ------------------------------------------------------------------ */\n\nexport interface VerifyDeps {\n tls: (input: TlsProbeInput) => Promise<TlsHandshakeResult>;\n http: (input: HttpProbeInput) => Promise<HttpProbeResult>;\n graphql: (input: GraphqlProbeInput) => Promise<GraphqlProbeResult>;\n tunnel: (input: TunnelStatusInput) => Promise<TunnelStatusResult>;\n cosign: (input: CosignVerifyInput) => Promise<CosignVerifyResult>;\n /** Local Ollama health probe (`/api/tags`). Defaults to checkOllamaHealth\n * against localhost — meaningful only when verify runs ON the node. */\n ollama: (url?: string) => Promise<OllamaHealth>;\n /** Called once per phase as it resolves — lets the CLI render spinners.\n * Pass a no-op for tests that just want the report. */\n onPhase?: (phase: VerifyPhase) => void;\n}\n\nexport interface VerifyInput {\n apiHost: string;\n certWarnDays: number;\n /** All three OR none. Mid-set is treated as a `warn` phase by runVerify. */\n cf?: {\n token?: string;\n accountId?: string;\n tunnelId?: string;\n };\n images: ReadonlyArray<string>;\n /** Configured model(s) to assert are present in the LOCAL Ollama. Resolved\n * from `--llm-model` or the node `.env` (readEnvModelConfig). Absent →\n * the Ollama phase is skipped (preserves off-LAN \"run from anywhere\"). */\n ollama?: {\n llmModel: string;\n embeddingModel?: string;\n provider?: EmbeddingsProvider;\n };\n /** Node has no public domain/tunnel (bootstrap --local-only). Skips the\n * domain-dependent probes (TLS, /health, GraphQL, Cloudflare) as `skipped`\n * rather than failing them, leaving the node-local checks (Ollama, cosign)\n * to decide the outcome. See #104. */\n localOnly?: boolean;\n /** SUPABASE_URL read from the node `.env` managed block. Absent → the check\n * is skipped (verify not run on the node). A non-local node still pinned to\n * `http://localhost:8000` warns — browser-facing auth URLs would be wrong\n * (opuspopuli-node#43). */\n supabaseUrl?: string;\n}\n\nconst DEFAULT_DEPS: VerifyDeps = {\n tls: tlsHandshake,\n http: httpProbe,\n graphql: graphqlProbe,\n tunnel: tunnelStatus,\n cosign: cosignVerifyImage,\n ollama: checkOllamaHealth,\n};\n\ntype PushVerifyPhase = (ph: VerifyPhase) => void;\n\nexport async function runVerify(input: VerifyInput, deps: VerifyDeps = DEFAULT_DEPS): Promise<VerifyReport> {\n // Each phase pushes its result(s) via push(), which records + fires onPhase\n // in lockstep. push is threaded into the phase helpers (rather than having\n // them return arrays) so the cosign loop keeps firing onPhase per-image,\n // interleaved with its async calls — exactly as the original inline loop.\n const phases: VerifyPhase[] = [];\n const push: PushVerifyPhase = (ph) => {\n phases.push(ph);\n deps.onPhase?.(ph);\n };\n\n await verifyTlsPhase(input, deps, push);\n await verifyHealthPhase(input, deps, push);\n await verifyGraphqlPhase(input, deps, push);\n await verifyOllamaModelsPhase(input, deps, push);\n verifySupabaseUrlPhase(input, push);\n await verifyCloudflarePhase(input, deps, push);\n await verifyCosignPhase(input, deps, push);\n\n return { phases };\n}\n\n// Record a domain-dependent phase as `skipped` on a --local-only node (no\n// public endpoint / tunnel to reach), preserving phase ordering + counts so a\n// healthy local node exits 0 instead of failing inapplicable probes. See #104.\nfunction skipLocalOnly(name: string, detail: string, push: PushVerifyPhase): void {\n push({ name, status: 'skipped', detail });\n}\n\nconst LOCAL_ONLY_NO_ENDPOINT = 'local-only node — no public endpoint to probe';\n\n// ---- Phase 1: TLS handshake ---------------------------------------\nasync function verifyTlsPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('TLS handshake', LOCAL_ONLY_NO_ENDPOINT, push);\n const tls = await deps.tls({ host: input.apiHost });\n if (!tls.ok) {\n push({ name: 'TLS handshake', status: 'fail', detail: tls.reason });\n return;\n }\n const line = `subject=${tls.subject}, issuer=${tls.issuer}, ${formatExpiry(tls.daysToExpiry)}`;\n if (tls.daysToExpiry < input.certWarnDays) {\n push({\n name: 'TLS handshake',\n status: 'warn',\n detail: tls.daysToExpiry < 0 ? line : `${line} (< warn threshold ${input.certWarnDays}d)`,\n });\n return;\n }\n push({ name: 'TLS handshake', status: 'ok', detail: line });\n}\n\n// ---- Phase 2: GET /health ------------------------------------------\nasync function verifyHealthPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('GET /health', LOCAL_ONLY_NO_ENDPOINT, push);\n const health = await deps.http({ url: `https://${input.apiHost}/health` });\n if (health.ok) {\n push({ name: 'GET /health', status: 'ok', detail: `HTTP ${health.status}` });\n } else {\n push({ name: 'GET /health', status: 'fail', detail: health.reason });\n }\n}\n\n// ---- Phase 3: GraphQL { __typename } -------------------------------\nasync function verifyGraphqlPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('GraphQL { __typename }', LOCAL_ONLY_NO_ENDPOINT, push);\n const gql = await deps.graphql({ url: `https://${input.apiHost}/api` });\n if (gql.ok) {\n push({ name: 'GraphQL { __typename }', status: 'ok', detail: `typename=${gql.typename}` });\n } else {\n push({ name: 'GraphQL { __typename }', status: 'fail', detail: gql.reason });\n }\n}\n\n// ---- Phase 4: Ollama model presence (optional, node-local) ---------\n//\n// Catches the config↔runtime drift that silently 404s at inference time: the\n// configured LLM_MODEL naming a model that was never pulled into the host\n// Ollama. Probes the LOCAL daemon, so it's meaningful only when verify runs\n// ON the node — hence skipped (not failed) when no model was resolved, which\n// keeps an off-LAN `verify --domain …` from tripping it.\nasync function verifyOllamaModelsPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n const cfg = input.ollama;\n if (!cfg?.llmModel) {\n push({\n name: 'Ollama models',\n status: 'skipped',\n detail: 'pass --llm-model (or run on the node so its .env is read) to enable',\n });\n return;\n }\n\n const health = await deps.ollama();\n if (!health.reachable) {\n push({\n name: 'Ollama models',\n status: 'fail',\n detail:\n 'configured model set but the local Ollama daemon is unreachable on :11434 — ' +\n 'start it with `brew services start ollama` (run this check on the node)',\n });\n return;\n }\n\n // Assert the LLM always; assert the embedding model only when the knowledge\n // service actually uses the Ollama provider for it (xenova is in-process).\n const required = [cfg.llmModel];\n if (cfg.provider === 'ollama' && cfg.embeddingModel) required.push(cfg.embeddingModel);\n\n const missing = required.filter((m) => !modelPresent(m, health.models));\n if (missing.length > 0) {\n const remedy = missing.map((m) => `ollama pull ${m}`).join(' && ');\n push({\n name: 'Ollama models',\n status: 'fail',\n detail: `not installed: ${missing.join(', ')} — remedy: ${remedy}`,\n });\n return;\n }\n push({ name: 'Ollama models', status: 'ok', detail: `${required.join(', ')} present` });\n}\n\n// ---- Phase 4b: SUPABASE_URL sanity (node-local, optional) ---------\n//\n// The browser-facing auth URLs (API_EXTERNAL_URL, GOTRUE_JWT_ISSUER,\n// SUPABASE_PUBLIC_URL) all derive from SUPABASE_URL. A non-local node left at\n// the `http://localhost:8000` default silently ships magic-link / callback\n// URLs pointing at localhost. Skipped off-node (no .env to read) and on\n// --local-only nodes (localhost is correct there). See opuspopuli-node#43.\nfunction verifySupabaseUrlPhase(input: VerifyInput, push: PushVerifyPhase): void {\n if (input.localOnly) {\n return skipLocalOnly('SUPABASE_URL', 'local-only node — localhost:8000 is expected', push);\n }\n if (input.supabaseUrl === undefined) {\n push({\n name: 'SUPABASE_URL',\n status: 'skipped',\n detail: 'run on the node (or pass --repo-dir) so its .env is read',\n });\n return;\n }\n if (input.supabaseUrl === 'http://localhost:8000') {\n push({\n name: 'SUPABASE_URL',\n status: 'warn',\n detail:\n 'still http://localhost:8000 on a non-local node — browser-facing auth URLs ' +\n 'will point at localhost; set SUPABASE_URL in the node .env to the public URL',\n });\n return;\n }\n push({ name: 'SUPABASE_URL', status: 'ok', detail: input.supabaseUrl });\n}\n\n// ---- Phase 5: Cloudflare Tunnel status (optional) ------------------\nasync function verifyCloudflarePhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.localOnly) return skipLocalOnly('Cloudflare Tunnel', 'local-only node — no tunnel', push);\n const cfFields: ReadonlyArray<[string, string | undefined]> = [\n ['--cf-token', input.cf?.token],\n ['--cf-account-id', input.cf?.accountId],\n ['--tunnel-id', input.cf?.tunnelId],\n ];\n const cfSet = cfFields.filter(([, v]) => v !== undefined && v !== '');\n if (cfSet.length === 0) {\n push({\n name: 'Cloudflare Tunnel',\n status: 'skipped',\n detail: 'pass --cf-token + --cf-account-id + --tunnel-id to enable',\n });\n return;\n }\n if (cfSet.length < cfFields.length) {\n // (review S1) Partial config is operator-hostile — they almost certainly\n // meant to enable the check. Warn so the missing flag names are visible.\n const missing = cfFields.filter(([, v]) => v === undefined || v === '').map(([name]) => name).join(', ');\n push({\n name: 'Cloudflare Tunnel',\n status: 'warn',\n detail: `partial CF config — missing ${missing}; check skipped`,\n });\n return;\n }\n const tun = await deps.tunnel({\n token: input.cf!.token!,\n accountId: input.cf!.accountId!,\n tunnelId: input.cf!.tunnelId!,\n });\n if (!tun.ok) {\n push({ name: 'Cloudflare Tunnel', status: 'fail', detail: tun.reason });\n } else if (tun.connections === 0) {\n push({\n name: 'Cloudflare Tunnel',\n status: 'warn',\n detail: `status=${tun.status}, 0 connections — cloudflared on the Studio appears offline`,\n });\n } else {\n push({\n name: 'Cloudflare Tunnel',\n status: 'ok',\n detail: `${tun.connections} connections, status=${tun.status}`,\n });\n }\n}\n\n// ---- Phase 6: cosign signature check (optional) --------------------\nasync function verifyCosignPhase(input: VerifyInput, deps: VerifyDeps, push: PushVerifyPhase): Promise<void> {\n if (input.images.length === 0) {\n push({\n name: 'cosign verify',\n status: 'skipped',\n detail: 'pass --image <ref> (repeatable) to enable',\n });\n return;\n }\n for (const image of input.images) {\n const cos = await deps.cosign({ image });\n if (cos.ok) {\n push({ name: `cosign verify ${image}`, status: 'ok', detail: 'signature valid' });\n } else if (cos.skipped) {\n push({ name: `cosign verify ${image}`, status: 'skipped', detail: cos.reason });\n } else {\n push({ name: `cosign verify ${image}`, status: 'fail', detail: cos.reason });\n }\n }\n}\n\n/* ------------------------------------------------------------------ *\n * CLI wrapper *\n * ------------------------------------------------------------------ */\n\nfunction readTokenFile(path: string): string {\n const raw = readFileSync(path, 'utf8').trim();\n if (!raw) throw new Error(`--cf-token-file ${path} was empty`);\n return raw;\n}\n\n/**\n * Commander array collector for the repeatable `--image` option. Without an\n * argParser, commander stores only the last value as a plain string, which the\n * cosign phase then iterates character-by-character (verifying \"g\", \"h\", \"c\", …\n * as image refs). Mirrors `collectComposeFile` (#82). See #103.\n */\nexport function collectImage(value: string, previous: string[] | undefined): string[] {\n return [...(previous ?? []), value];\n}\n\nexport const verifyCommand = new Command('verify')\n .description(\n 'Off-LAN health probe of a live node — TLS, Apollo Federation reachability, GraphQL smoke. ' +\n 'Run from anywhere with internet access.',\n )\n .addOption(\n new Option('--domain <domain>', 'Domain to probe (e.g. example.org → checks api.example.org)'),\n )\n .addOption(new Option('--api-host <host>', 'Override the API hostname (default: api.<domain>)'))\n .addOption(new Option('--cf-token <token>', 'Cloudflare API token (enables tunnel-status probe)'))\n .addOption(\n new Option('--cf-token-file <path>', 'Read CF token from a file (avoids exposing it via ps)'),\n )\n .addOption(new Option('--cf-account-id <id>', 'Cloudflare account ID (required with --cf-token)'))\n .addOption(\n new Option('--tunnel-id <id>', 'Cloudflare Tunnel ID to query (required with --cf-token)'),\n )\n .addOption(\n new Option('--image <ref>', 'Repeatable. Image to cosign-verify (e.g. ghcr.io/opuspopuli/api:tag)')\n .default([] as string[])\n .argParser(collectImage),\n )\n .addOption(\n new Option('--cert-warn-days <n>', 'Warn if cert expires within N days').default('14'),\n )\n .addOption(\n new Option(\n '--llm-model <model>',\n 'Assert this model is present in the local Ollama (catches config↔runtime drift). Defaults to LLM_MODEL from the node .env when run on the node.',\n ),\n )\n .addOption(\n new Option('--embedding-model <model>', 'Also assert this embedding model is present (only checked when --embeddings-provider=ollama).'),\n )\n .addOption(\n new Option('--embeddings-provider <provider>', 'Embeddings provider the node runs; the embedding model is only asserted for `ollama`.').choices(['xenova', 'ollama']),\n )\n .addOption(\n new Option('--repo-dir <path>', \"Node repo dir whose .env supplies the model config when --llm-model is omitted (default: cwd).\"),\n )\n .addOption(\n new Option(\n '--local-only',\n 'Node has no public domain/tunnel — skip the TLS/health/GraphQL/tunnel probes (no domain prompt) and run only the node-local checks (Ollama model presence, cosign).',\n ).default(false),\n )\n .addOption(\n new Option('--show-skipped', 'Include skipped phases in the summary').default(false),\n )\n .action(async (opts: VerifyOptions) => {\n p.intro(pc.bgCyan(pc.black(' create-op-node verify ')));\n\n const localOnly = opts.localOnly ?? false;\n // A local-only node has no public endpoint, so don't resolve/prompt for a\n // domain — the domain-dependent phases self-skip below.\n const domain = localOnly ? undefined : await resolveDomain(opts);\n const certWarnDays = resolveCertWarnDays(opts);\n const cfToken = resolveCfToken(opts);\n\n const apiHost = localOnly ? '' : (opts.apiHost ?? `api.${domain}`);\n const images = opts.image ?? [];\n const ollama = await resolveOllamaVerifyInput(opts);\n const supabaseUrl = await resolveSupabaseUrlVerifyInput(opts);\n // Fixed phases: TLS, health, GraphQL, Ollama, SUPABASE_URL, Cloudflare (6)\n // + cosign (one line when no --image, else one per image).\n const totalPhases = 6 + (images.length === 0 ? 1 : images.length);\n\n const report = await runVerifyWithSpinner({\n apiHost,\n certWarnDays,\n cfToken,\n opts,\n images,\n totalPhases,\n localOnly,\n ...(ollama ? { ollama } : {}),\n ...(supabaseUrl !== undefined ? { supabaseUrl } : {}),\n });\n\n renderVerifySummary(report, { opts, totalPhases });\n reportVerifyOutcome(report);\n });\n\nfunction phaseIcon(ph: VerifyPhase): string {\n switch (ph.status) {\n case 'ok': return pc.green('✓');\n case 'warn': return pc.yellow('⚠');\n case 'skipped': return pc.dim('·');\n case 'fail': return pc.red('✗');\n }\n}\n\nfunction phaseColor(status: VerifyPhase['status']): (text: string) => string {\n switch (status) {\n case 'ok': return pc.green;\n case 'warn': return pc.yellow;\n case 'skipped': return pc.dim;\n case 'fail': return pc.red;\n }\n}\n\nfunction formatPhaseLine(prefix: string, ph: VerifyPhase): string {\n const icon = phaseIcon(ph);\n const colorize = phaseColor(ph.status);\n return colorize(`${icon} ${prefix}: ${ph.detail}`);\n}\n\n// ----------------------------------------------------------------------------\n// Verify command phases\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: interactive prompts,\n// spinners, and process.exit calls are relocated verbatim.\n\nasync function resolveDomain(opts: VerifyOptions): Promise<string> {\n const domain = opts.domain\n ? opts.domain\n : unwrap(\n await p.text({\n message: 'Public domain of the node?',\n placeholder: 'yournode.example.org',\n validate: (v) =>\n DOMAIN_RE.test(v ?? '') ? undefined : 'lowercase letters, digits, hyphens, dots; must contain a dot and a TLD',\n }),\n );\n if (!DOMAIN_RE.test(domain)) {\n p.cancel(`--domain ${JSON.stringify(domain)} doesn't look like a domain.`);\n process.exit(2);\n }\n return domain;\n}\n\n// (review B1) Validate --cert-warn-days to a non-negative integer.\nfunction resolveCertWarnDays(opts: VerifyOptions): number {\n const rawDays = opts.certWarnDays ?? '14';\n const certWarnDays = Number.parseInt(rawDays, 10);\n if (!Number.isFinite(certWarnDays) || certWarnDays < 0 || !/^\\d+$/.test(rawDays)) {\n p.cancel(`--cert-warn-days must be a non-negative integer (got ${JSON.stringify(rawDays)}).`);\n process.exit(2);\n }\n return certWarnDays;\n}\n\n// Resolve the CF token from --cf-token or --cf-token-file (mutually exclusive).\nfunction resolveCfToken(opts: VerifyOptions): string | undefined {\n if (opts.cfToken && opts.cfTokenFile) {\n p.cancel('Pass either --cf-token or --cf-token-file, not both.');\n process.exit(2);\n }\n if (opts.cfToken) return opts.cfToken;\n if (!opts.cfTokenFile) return undefined;\n try {\n return readTokenFile(opts.cfTokenFile);\n } catch (err) {\n p.cancel((err as Error).message);\n process.exit(2);\n }\n}\n\n/** Narrow an arbitrary `.env` string to a known provider, or undefined. */\nfunction normalizeProvider(v: string | undefined): EmbeddingsProvider | undefined {\n return v === 'ollama' || v === 'xenova' ? v : undefined;\n}\n\n/**\n * Merge CLI flags over the node `.env` config, per field. A flag always wins\n * over the file for its own field, but a field the flag omits still falls back\n * to `.env` — so `--llm-model foo` on the node still picks up the provider /\n * embedding model from `.env`. Undefined when no model resolves at all (the\n * phase then skips). Pure — unit-tested independently of the filesystem.\n */\nexport function mergeOllamaModelConfig(\n opts: Pick<VerifyOptions, 'llmModel' | 'embeddingModel' | 'embeddingsProvider'>,\n envCfg: NodeEnvModelConfig,\n): VerifyInput['ollama'] {\n const llmModel = opts.llmModel ?? envCfg.llmModel;\n if (!llmModel) return undefined;\n const embeddingModel = opts.embeddingModel ?? envCfg.embeddingModel;\n const provider = normalizeProvider(opts.embeddingsProvider ?? envCfg.embeddingsProvider);\n return {\n llmModel,\n ...(embeddingModel ? { embeddingModel } : {}),\n ...(provider ? { provider } : {}),\n };\n}\n\n// Resolve the model config the Ollama presence phase asserts. Reads the node\n// `.env` (single source of truth written by bootstrap) and merges flags over\n// it per field. The `.env` is only read from a dir we trust — an explicit\n// --repo-dir, or a cwd that actually looks like a node repo — so a stray\n// `.env` in an unrelated cwd can't trigger a localhost probe (false fail).\nasync function resolveOllamaVerifyInput(opts: VerifyOptions): Promise<VerifyInput['ollama']> {\n const explicit = opts.repoDir !== undefined;\n const dir = opts.repoDir ?? process.cwd();\n const envCfg: NodeEnvModelConfig =\n explicit || (await looksLikeNodeRepo(dir)) ? await readEnvModelConfig(dir) : {};\n\n // Surface a typo'd EMBEDDINGS_PROVIDER instead of silently skipping the\n // embedding-model check (only the .env can carry a bad value — the flag is\n // constrained by commander `.choices`).\n if (\n opts.embeddingsProvider === undefined &&\n envCfg.embeddingsProvider !== undefined &&\n normalizeProvider(envCfg.embeddingsProvider) === undefined\n ) {\n p.note(\n `${pc.yellow('⚠')} Unrecognized EMBEDDINGS_PROVIDER=${envCfg.embeddingsProvider} in .env — expected xenova|ollama; the embedding-model check is disabled.`,\n 'verify',\n );\n }\n\n return mergeOllamaModelConfig(opts, envCfg);\n}\n\n// Read SUPABASE_URL from the node `.env` for the sanity check. Same node-repo\n// gating as the Ollama resolver so an unrelated cwd never trips a false warn.\nasync function resolveSupabaseUrlVerifyInput(opts: VerifyOptions): Promise<string | undefined> {\n const explicit = opts.repoDir !== undefined;\n const dir = opts.repoDir ?? process.cwd();\n if (!explicit && !(await looksLikeNodeRepo(dir))) return undefined;\n return (await readEnvModelConfig(dir)).supabaseUrl;\n}\n\n// Run the checks behind a single spinner that advances per phase.\nasync function runVerifyWithSpinner(args: {\n apiHost: string;\n certWarnDays: number;\n cfToken: string | undefined;\n opts: VerifyOptions;\n images: string[];\n totalPhases: number;\n localOnly: boolean;\n ollama?: VerifyInput['ollama'];\n}): Promise<VerifyReport> {\n const { apiHost, certWarnDays, cfToken, opts, images, totalPhases, localOnly, ollama } = args;\n\n let phaseIndex = 0;\n let activeSpin: ReturnType<typeof p.spinner> | null = null;\n const renderPhase = (ph: VerifyPhase): void => {\n phaseIndex++;\n const prefix = `[${phaseIndex}/${totalPhases}] ${ph.name}`;\n activeSpin?.stop(formatPhaseLine(prefix, ph));\n activeSpin = null;\n };\n\n const deps: VerifyDeps = { ...DEFAULT_DEPS, onPhase: renderPhase };\n\n activeSpin = p.spinner();\n activeSpin.start('Running checks…');\n\n const report = await runVerify(\n {\n apiHost,\n certWarnDays,\n cf: {\n ...(cfToken ? { token: cfToken } : {}),\n ...(opts.cfAccountId ? { accountId: opts.cfAccountId } : {}),\n ...(opts.tunnelId ? { tunnelId: opts.tunnelId } : {}),\n },\n images,\n localOnly,\n ...(ollama ? { ollama } : {}),\n },\n deps,\n );\n // If `runVerify` finished without firing onPhase for some pathological\n // reason, stop the spinner cleanly.\n activeSpin?.stop('Done.');\n return report;\n}\n\n// Render the per-phase summary note (hiding skipped phases unless asked).\nfunction renderVerifySummary(\n report: VerifyReport,\n args: { opts: VerifyOptions; totalPhases: number },\n): void {\n const { opts, totalPhases } = args;\n const visible = (opts.showSkipped ?? false)\n ? report.phases\n : report.phases.filter((ph) => ph.status !== 'skipped');\n const lines = visible.map((ph) => {\n const idx = report.phases.indexOf(ph) + 1;\n return `${phaseIcon(ph)} [${idx}/${totalPhases}] ${ph.name}: ${pc.dim(ph.detail)}`;\n });\n const skippedCount = report.phases.length - visible.length;\n if (skippedCount > 0 && !opts.showSkipped) {\n lines.push(pc.dim(`· ${skippedCount} phase${skippedCount === 1 ? '' : 's'} skipped (run with --show-skipped to see them)`));\n }\n p.note(lines.join('\\n'), 'Summary');\n}\n\n// Final outro + exit code from the phase report.\nfunction reportVerifyOutcome(report: VerifyReport): void {\n const summary = summarize(report);\n if (!summary.ok) {\n p.outro(pc.red(`${summary.failed} check${summary.failed === 1 ? '' : 's'} failed.`));\n process.exit(1);\n }\n if (summary.warned === 0) {\n p.outro(pc.green('All checks passed.'));\n } else {\n p.outro(pc.yellow(`Passed with ${summary.warned} warning${summary.warned === 1 ? '' : 's'}.`));\n }\n}\n","{\n \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n \"$id\": \"https://github.com/OpusPopuli/opuspopuli-regions/schema/region-plugin.schema.json\",\n \"title\": \"Region Plugin File\",\n \"description\": \"A declarative region configuration file for the Opus Populi civic data platform. A handful of string-valued fields (ApiSourceConfig.queryParams, BulkDownloadConfig.filters) support ${variableName} placeholders that the consumer resolves at runtime — see those field descriptions for the supported variable list.\",\n \"type\": \"object\",\n \"required\": [\"name\", \"displayName\", \"description\", \"version\", \"config\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier (e.g., 'california')\"\n },\n \"displayName\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Human-readable region name (e.g., 'California')\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Brief description of this region's data coverage\"\n },\n \"version\": {\n \"type\": \"string\",\n \"pattern\": \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\",\n \"description\": \"Semantic version of this config file\"\n },\n \"config\": {\n \"$ref\": \"#/definitions/DeclarativeRegionConfig\"\n }\n },\n \"definitions\": {\n \"DeclarativeRegionConfig\": {\n \"type\": \"object\",\n \"required\": [\"regionId\", \"regionName\", \"description\", \"timezone\", \"dataSources\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"regionId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier (e.g., 'california')\"\n },\n \"regionName\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Human-readable region name (e.g., 'California')\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Region description\"\n },\n \"timezone\": {\n \"type\": \"string\",\n \"description\": \"IANA timezone (e.g., 'America/Los_Angeles')\"\n },\n \"stateCode\": {\n \"type\": \"string\",\n \"pattern\": \"^[A-Z]{2}$\",\n \"description\": \"Two-letter US state code (e.g., 'CA')\"\n },\n \"parentRegionId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Region identifier of this region's parent in the geographic hierarchy. Top-level regions (states, federal) omit this field. Counties set parentRegionId to their state's regionId (e.g., 'california'); cities will set it to their county's regionId. Presence of this field is the canonical signal that a region is a sub-region; the consumer loader uses it to build the region tree.\"\n },\n \"fipsCode\": {\n \"type\": \"string\",\n \"pattern\": \"^\\\\d{2,7}$\",\n \"description\": \"Census FIPS code: 2 digits for states (e.g., '06' for CA), 5 digits for counties (e.g., '06037' for Los Angeles County — state FIPS + county FIPS), 7 digits for places/cities. This is the canonical join key against the consumer's PostGIS counties/places tables used today for user-to-district placement.\"\n },\n \"dataSources\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": {\n \"$ref\": \"#/definitions/DataSourceConfig\"\n },\n \"description\": \"Data sources to scrape\"\n },\n \"rateLimit\": {\n \"type\": \"object\",\n \"properties\": {\n \"requestsPerSecond\": { \"type\": \"number\", \"minimum\": 0 },\n \"burstSize\": { \"type\": \"integer\", \"minimum\": 1 }\n },\n \"required\": [\"requestsPerSecond\", \"burstSize\"],\n \"additionalProperties\": false,\n \"description\": \"Rate limiting defaults\"\n },\n \"cacheTtlMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Cache TTL in milliseconds\"\n },\n \"requestTimeoutMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Request timeout in milliseconds\"\n },\n \"normalizeExternalIdDistrict\": {\n \"type\": \"boolean\",\n \"description\": \"Strip leading zeros from representative externalId trailing segment (e.g. ca-assembly-01 → ca-assembly-1). Opt-in; default false. Only needed for regions whose LLM manifests emit zero-padded district numbers.\"\n },\n \"bioNoisePatterns\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Regex pattern strings (case-insensitive) matched against scraped representative bio text. Bios matching any pattern are treated as nav junk and discarded. Defaults to no filtering if omitted.\"\n },\n \"boundarySources\": {\n \"$ref\": \"#/definitions/BoundarySourcesConfig\",\n \"description\": \"Civic-boundary geometry sources used to populate the consumer's `jurisdictions` table (counties, cities, state legislative districts, school districts, special districts). The consumer's BoundaryLoaderService reads this block, dispatches to TIGER and ArcGIS FeatureServer fetchers, and upserts on fipsCode/ocdId. Omit when a region has no public boundary data — addresses still resolve via Census Geocoder string fields, but PostGIS point-in-polygon queries return no matches. See opuspopuli#804.\"\n }\n }\n },\n \"BoundarySourcesConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"ocdIdPrefix\"],\n \"description\": \"Per-region declarative recipe for loading civic boundaries. Pure config — no per-region code lives in the consumer.\",\n \"properties\": {\n \"ocdIdPrefix\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Open Civic Data ID prefix for this region, e.g. 'ocd-division/country:us/state:ca'. All jurisdiction OCD-IDs are composed as `${ocdIdPrefix}${TigerLayerConfig.ocdIdSegment}` (or the Geoportal equivalent).\"\n },\n \"tigerLayers\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/definitions/TigerLayerConfig\" },\n \"description\": \"US Census TIGER/Line layers to ingest as jurisdictions. Each entry maps one ArcGIS MapServer layer to a JurisdictionType. Omit the field entirely when the region has no TIGER coverage — do not pass an empty array (the schema rejects it to prevent silent typos that strip the configured layers).\"\n },\n \"geoportalLayers\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/definitions/GeoportalLayerConfig\" },\n \"description\": \"Region-specific ArcGIS FeatureServer endpoints — typically state geoportals serving boundary data Census TIGER doesn't cover (fire districts, water districts, transit districts, etc.). Omit when unused — empty arrays are rejected (see tigerLayers note).\"\n }\n }\n },\n \"JurisdictionTypeEnum\": {\n \"type\": \"string\",\n \"enum\": [\"COUNTY\", \"CITY\", \"STATE_SENATE_DISTRICT\", \"STATE_ASSEMBLY_DISTRICT\", \"CONGRESSIONAL_DISTRICT\", \"SCHOOL_DISTRICT_UNIFIED\", \"SCHOOL_DISTRICT_ELEMENTARY\", \"SCHOOL_DISTRICT_HIGH\", \"COMMUNITY_COLLEGE_DISTRICT\", \"WATER_DISTRICT\", \"FIRE_DISTRICT\", \"TRANSIT_DISTRICT\", \"SPECIAL_DISTRICT\"],\n \"description\": \"Maps each feature to a JurisdictionType row in the consumer's `jurisdictions` table. Single source of truth — TigerLayerConfig and GeoportalLayerConfig both reference this so a new jurisdiction type can't be added to one without the other.\"\n },\n \"JurisdictionLevelEnum\": {\n \"type\": \"string\",\n \"enum\": [\"FEDERAL\", \"STATE\", \"COUNTY\", \"MUNICIPAL\", \"DISTRICT\"],\n \"description\": \"Hierarchy level for the resulting jurisdiction rows. Single source of truth — referenced from TigerLayerConfig and GeoportalLayerConfig.\"\n },\n \"TigerLayerConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"layer\", \"outFields\", \"jurisdictionType\", \"level\", \"nameField\"],\n \"description\": \"One TIGER/Line layer mapped to a JurisdictionType. The consumer hits `https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/${layer}/query` with GeoJSON output. Supported placeholders inside `where`, `ocdIdSegment`, `nameTemplate`: ${fipsCode} (this region's fipsCode), ${stateCode} (two-letter code), ${name} (the layer's nameField value for a given feature), ${district} (the districtField value).\",\n \"properties\": {\n \"layer\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"TIGER MapServer service+layer path, e.g. 'State_County/MapServer/1', 'Legislative/MapServer/1' (state senate), 'Legislative/MapServer/2' (state assembly), 'School/MapServer/0' (unified school districts).\"\n },\n \"where\": {\n \"type\": \"string\",\n \"description\": \"ESRI WHERE clause filtering features. Defaults to `STATE='${fipsCode}'` when omitted. Use `${fipsCode}` / `${stateCode}` placeholders.\"\n },\n \"outFields\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Comma-separated TIGER attribute fields to return, e.g. 'GEOID,NAME' or 'GEOID,SLDUST'.\"\n },\n \"jurisdictionType\": {\n \"$ref\": \"#/definitions/JurisdictionTypeEnum\"\n },\n \"level\": {\n \"$ref\": \"#/definitions/JurisdictionLevelEnum\"\n },\n \"nameField\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"TIGER attribute key whose value becomes the substitution for `${name}` placeholders. Typically 'NAME' for human-readable layers, or a district code field like 'SLDUST'/'SLDLST' for legislative layers.\"\n },\n \"fipsField\": {\n \"type\": \"string\",\n \"description\": \"TIGER attribute key holding the canonical fips_code for an upsert. Defaults to 'GEOID'.\"\n },\n \"fipsPrefix\": {\n \"type\": \"string\",\n \"description\": \"Optional prefix prepended to the fipsField value before persisting as fips_code. Use when the raw GEOID would collide with another layer's GEOID (e.g. state senate GEOID overlapping county GEOID format). Example: 'sldu-' for state senate, 'sldl-' for state assembly.\"\n },\n \"districtField\": {\n \"type\": \"string\",\n \"description\": \"TIGER attribute key supplying the ${district} placeholder. Required when ocdIdSegment or nameTemplate contains ${district}.\"\n },\n \"ocdIdSegment\": {\n \"type\": \"string\",\n \"description\": \"Segment appended to `boundarySources.ocdIdPrefix` to form the full OCD-ID, e.g. '/county:${name}', '/sldu:${district}'. Supports ${name} and ${district} placeholders. Inside `${name}` substitutions the consumer normalizes whitespace to underscores and lowercases the value for OCD-ID compatibility — so a NAME of 'Alameda County' produces 'alameda_county' in the OCD-ID. Omit when this layer's rows don't carry an OCD-ID.\"\n },\n \"nameTemplate\": {\n \"type\": \"string\",\n \"description\": \"Template for the persisted jurisdiction name (NOT for OCD-ID composition). Supports ${name}, ${district}, ${stateCode}. The ${name} value is substituted verbatim (case + whitespace preserved). Defaults to ${name} when omitted.\"\n }\n }\n },\n \"GeoportalLayerConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"url\", \"outFields\", \"jurisdictionType\", \"level\", \"nameField\"],\n \"description\": \"One arbitrary ArcGIS FeatureServer layer for jurisdictions Census TIGER doesn't cover. Same placeholder rules as TigerLayerConfig.\",\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"pattern\": \"^https://\",\n \"description\": \"Full ArcGIS FeatureServer layer URL ending in /FeatureServer/<n>. Must be HTTPS — the consumer rejects other schemes. The consumer paginates via resultOffset/resultRecordCount.\"\n },\n \"where\": {\n \"type\": \"string\",\n \"description\": \"ESRI WHERE clause. Defaults to '1=1'.\"\n },\n \"outFields\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Comma-separated FeatureServer attribute fields to return.\"\n },\n \"jurisdictionType\": {\n \"$ref\": \"#/definitions/JurisdictionTypeEnum\"\n },\n \"level\": {\n \"$ref\": \"#/definitions/JurisdictionLevelEnum\"\n },\n \"nameField\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"FeatureServer attribute key supplying the human-readable name and the ${name} placeholder.\"\n },\n \"fipsField\": {\n \"type\": \"string\",\n \"description\": \"FeatureServer attribute key used as fips_code. No default — geoportal attribute names vary widely (no GEOID convention). Omit when the layer has no FIPS analog; the upsert then matches on ocdId only.\"\n },\n \"fipsPrefix\": {\n \"type\": \"string\",\n \"description\": \"Optional prefix prepended to fipsField, mirroring TigerLayerConfig.fipsPrefix.\"\n },\n \"ocdIdSegment\": {\n \"type\": \"string\",\n \"description\": \"Appended to boundarySources.ocdIdPrefix. Supports ${name} placeholder. Same OCD-ID normalization as TigerLayerConfig.ocdIdSegment — whitespace to underscores, lowercased.\"\n },\n \"nameTemplate\": {\n \"type\": \"string\",\n \"description\": \"Template for persisted name (NOT for OCD-ID). ${name} substituted verbatim. Defaults to ${name}.\"\n }\n }\n },\n \"DataSourceConfig\": {\n \"type\": \"object\",\n \"required\": [\"url\", \"dataType\", \"contentGoal\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"format\": \"uri\",\n \"description\": \"URL to fetch data from\"\n },\n \"dataType\": {\n \"type\": \"string\",\n \"enum\": [\"propositions\", \"meetings\", \"representatives\", \"campaign_finance\", \"lobbying\", \"civics\", \"bills\"],\n \"description\": \"What type of content this source provides. Daily journals / meeting minutes go under 'meetings' with sourceType=pdf_archive — the consumer partitions by sourceType internally. 'civics' marks a source of region governmental structure, process, and vocabulary; the civics-ingest handler scrapes it and uses the private prompt-service to extract structured shape (chambers, measure types, lifecycle stages with status patterns, glossary) plus a plain-language rewrite for laypeople. Verbatim source text and the AI rewrite are stored together — never one without the other. 'bills' marks a source of individual legislative bills (AB, SB, ACA, SCA, etc.) scraped from an official legislature website; the bills-ingest handler BFS-crawls from the seed URL and extracts one Bill record per detail page. See opuspopuli#686.\"\n },\n \"contentGoal\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"description\": \"Natural language description of what to find/extract\"\n },\n \"category\": {\n \"type\": \"string\",\n \"description\": \"Sub-category for grouping (e.g., 'Assembly', 'Senate')\"\n },\n \"hints\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Hints to help the AI find the right content\"\n },\n \"rateLimitOverride\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"description\": \"Override rate limit for this specific source\"\n },\n \"syncCadence\": {\n \"type\": \"string\",\n \"pattern\": \"^[^ ]+ [^ ]+ [^ ]+ [^ ]+ [^ ]+$\",\n \"description\": \"5-field cron expression (minute hour dom month dow) controlling how often this source is synced. The worker applies a deterministic per-source minute offset at registration time to spread load across gov hosts — the minute field you specify is the base, not the exact fire time. Omit to inherit the global daily fallback. Common patterns: '0 2 * * *' daily at 2 AM, '0 2 * * 0' weekly on Sunday, '0 * * * *' hourly.\"\n },\n \"statusScanCadence\": {\n \"type\": \"string\",\n \"pattern\": \"^[^ ]+ [^ ]+ [^ ]+ [^ ]+ [^ ]+$\",\n \"description\": \"5-field cron expression for a periodic full status-page sweep of all bills (dataType='bills' only). Runs forceStatusRecheck=true — bypasses the needsStatusRecheck flag and the sourcePublishedAt skip to catch governor actions and off-session changes the journal linker can't see. Per-source minute offset is applied like syncCadence. Typical: '0 2 * * 0' weekly Sunday 2 AM. See #689.\"\n },\n \"sourceType\": {\n \"type\": \"string\",\n \"enum\": [\"html_scrape\", \"bulk_download\", \"api\", \"pdf\", \"pdf_archive\"],\n \"description\": \"Source type determines the extraction strategy (default: html_scrape). 'pdf_archive' selects the listing-walk + per-PDF-extract pipeline: the URL is a paginated listing page that links to a series of dated PDF documents, each fetched and parsed (text only at V1) into one Minutes record.\"\n },\n \"bulk\": {\n \"$ref\": \"#/definitions/BulkDownloadConfig\"\n },\n \"api\": {\n \"$ref\": \"#/definitions/ApiSourceConfig\"\n },\n \"pdf\": {\n \"$ref\": \"#/definitions/PdfSourceConfig\"\n },\n \"pdfArchive\": {\n \"$ref\": \"#/definitions/PdfArchiveConfig\"\n },\n \"billDiscovery\": {\n \"$ref\": \"#/definitions/BillDiscoveryConfig\"\n },\n \"detailFields\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/StructuredFieldConfig\" }\n ]\n },\n \"description\": \"Detail page extraction plan: maps domain field names to CSS selectors (string) or structured array configs (object). Supports dot notation and '|attr:name' suffix.\"\n },\n \"staticManifest\": {\n \"type\": \"object\",\n \"required\": [\"containerSelector\", \"itemSelector\", \"fieldMappings\"],\n \"additionalProperties\": false,\n \"description\": \"Explicit extraction selectors that bypass AI structural analysis entirely. Use when the page structure is known and stable, or when the local LLM consistently generates wrong selectors.\",\n \"properties\": {\n \"containerSelector\": { \"type\": \"string\" },\n \"itemSelector\": { \"type\": \"string\" },\n \"fieldMappings\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\"fieldName\", \"selector\", \"extractionMethod\", \"required\"],\n \"additionalProperties\": true,\n \"properties\": {\n \"fieldName\": { \"type\": \"string\" },\n \"selector\": { \"type\": \"string\" },\n \"extractionMethod\": { \"type\": \"string\" },\n \"attribute\": { \"type\": \"string\" },\n \"regexPattern\": { \"type\": \"string\" },\n \"regexGroup\": { \"type\": \"integer\" },\n \"transform\": { \"type\": \"object\" },\n \"required\": { \"type\": \"boolean\" },\n \"defaultValue\": { \"type\": \"string\" },\n \"scope\": {\n \"type\": \"string\",\n \"enum\": [\"item\", \"container\"]\n },\n \"children\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/ChildFieldConfig\" }\n ]\n },\n \"description\": \"For extractionMethod='structured': child field selectors. Each value is a string shortcut or a ChildFieldConfig object.\"\n }\n }\n }\n }\n }\n },\n \"crawlDepth\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Crawl depth from the seed URL for sync handlers that walk a site's link graph (currently civics — see opuspopuli#669). 0 (default) = no crawl, fetch only the seed. N = N hops from seed. Crawls are scoped to same host + same path prefix as the seed, HTML responses only.\"\n },\n \"crawlMaxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Cap on total pages a crawler will visit per sync run regardless of crawlDepth. Defaults to 20. Each page costs one LLM call, so this bounds runtime + token spend.\"\n },\n \"llmMaxTokens\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Per-source override for the LLM maxTokens generation cap. Useful when a source needs a much longer or shorter output than its siblings (e.g., a 150-term glossary needs ~32000; a short bio prompt finishes well under 2000). Overrides the sync handler's hardcoded default.\"\n },\n \"llmRequestTimeoutMs\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Per-source override for the LLM provider request timeout (milliseconds). Useful when a single source legitimately runs much longer than the platform-wide default — civics-glossary extraction on qwen3.5:9b can take 15-20 min, while bio gen finishes in 2 min on the same hardware. Overrides the provider's constructor-configured default.\"\n }\n }\n },\n \"BulkDownloadConfig\": {\n \"type\": \"object\",\n \"required\": [\"format\", \"columnMappings\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"format\": {\n \"type\": \"string\",\n \"enum\": [\"tsv\", \"csv\", \"zip_tsv\", \"zip_csv\"],\n \"description\": \"File format\"\n },\n \"filePattern\": {\n \"type\": \"string\",\n \"description\": \"For ZIP archives: path/glob of target file(s) within the ZIP\"\n },\n \"delimiter\": {\n \"type\": \"string\",\n \"description\": \"Column delimiter override\"\n },\n \"headerLines\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Number of header lines to skip\"\n },\n \"headers\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" },\n \"description\": \"Explicit column headers for files without a header row (e.g., FEC bulk files)\"\n },\n \"columnMappings\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Column name mappings: source column name -> domain field name\"\n },\n \"filters\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Filter expressions applied during parse. Values support ${variableName} placeholders that the consumer resolves at runtime from the active local region. Supported variables: ${stateCode} (the 2-letter US state code of the active local region, e.g. 'CA'). Placeholders must appear verbatim. Example: '\\\"STATE\\\": \\\"${stateCode}\\\"' on an FEC bulk filter.\"\n },\n \"batchSize\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Records per batch for streaming processing (default: 10000)\"\n }\n }\n },\n \"ApiSourceConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"method\": {\n \"type\": \"string\",\n \"enum\": [\"GET\", \"POST\"],\n \"description\": \"HTTP method (default: GET)\"\n },\n \"apiKeyEnvVar\": {\n \"type\": \"string\",\n \"description\": \"Environment variable name containing the API key\"\n },\n \"apiKeyHeader\": {\n \"type\": \"string\",\n \"description\": \"Header name for the API key\"\n },\n \"pagination\": {\n \"$ref\": \"#/definitions/ApiPaginationConfig\"\n },\n \"resultsPath\": {\n \"type\": \"string\",\n \"description\": \"JSON path to the items array in the response\"\n },\n \"queryParams\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Query parameters appended to every request. Values support ${variableName} placeholders that the consumer resolves at runtime from the active local region. Supported variables: ${stateCode} (the 2-letter US state code of the active local region, e.g. 'CA'). Placeholders must appear verbatim — no escaping, no nested expressions. Example: '\\\"contributor_state\\\": \\\"${stateCode}\\\"'.\"\n },\n \"fieldMappings\": {\n \"type\": \"object\",\n \"additionalProperties\": { \"type\": \"string\" },\n \"description\": \"Field name mappings: API response field -> domain model field (e.g., committee_id -> committeeId)\"\n }\n }\n },\n \"ApiPaginationConfig\": {\n \"type\": \"object\",\n \"required\": [\"type\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"offset\", \"cursor\", \"page\"],\n \"description\": \"Pagination strategy type\"\n },\n \"pageParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name for page/offset\"\n },\n \"limitParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name for page size\"\n },\n \"limit\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Number of items per page\"\n }\n }\n },\n \"PdfSourceConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"skipPages\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Skip first N pages (e.g., skip cover page)\"\n },\n \"maxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Maximum pages to process (default: all)\"\n },\n \"followPdfLink\": {\n \"type\": \"boolean\",\n \"description\": \"If true, treats the URL as a gateway page and follows the first PDF link\"\n }\n }\n },\n \"StructuredFieldConfig\": {\n \"type\": \"object\",\n \"required\": [\"selector\", \"children\"],\n \"additionalProperties\": false,\n \"properties\": {\n \"selector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector matching each repeating item (e.g., '.office-card')\"\n },\n \"children\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"oneOf\": [\n { \"type\": \"string\" },\n { \"$ref\": \"#/definitions/ChildFieldConfig\" }\n ]\n },\n \"description\": \"Child field selectors relative to each item. Each entry is either a string shortcut (e.g. 'h3', 'a|attr:href') or a richer ChildFieldConfig object with extractionMethod / regex / transform.\"\n },\n \"multiple\": {\n \"type\": \"boolean\",\n \"description\": \"If true, extracts all matches as an array (default: true)\"\n }\n }\n },\n \"ChildFieldConfig\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"description\": \"Per-child extraction config for structured extraction. Object form supports the same shape as the top-level FieldMapping (selector + extractionMethod + attribute / regex / transform), minus fieldName/required/defaultValue which don't apply at child scope.\",\n \"properties\": {\n \"selector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector relative to the matched parent item. Optional for regex on full element text.\"\n },\n \"extractionMethod\": {\n \"type\": \"string\",\n \"description\": \"How to extract: 'text', 'attribute', 'regex', 'html', etc.\"\n },\n \"attribute\": {\n \"type\": \"string\",\n \"description\": \"For extractionMethod='attribute': which attribute to read (e.g. 'href', 'src').\"\n },\n \"regexPattern\": {\n \"type\": \"string\",\n \"description\": \"For extractionMethod='regex': the pattern.\"\n },\n \"regexGroup\": {\n \"type\": \"integer\",\n \"description\": \"For extractionMethod='regex': capture group (default: 1).\"\n },\n \"transform\": {\n \"type\": \"object\",\n \"description\": \"Optional transform applied after extraction (e.g. trim, regex_replace, url_resolve).\"\n }\n }\n },\n \"BillDiscoveryConfig\": {\n \"type\": \"object\",\n \"required\": [\"navLinkPattern\", \"statusPageTemplate\", \"votesPageTemplate\"],\n \"additionalProperties\": false,\n \"description\": \"Declarative bill discovery for legislature sites that list per-bill nav-hub links on a search results page (e.g. CA leginfo). The bills-ingest handler fetches the seed once, extracts bill IDs with navLinkPattern, and constructs status + votes URLs from the templates — bypassing generic BFS which would exhaust crawlMaxPages with nav-hub links before reaching detail pages.\",\n \"properties\": {\n \"navLinkPattern\": {\n \"type\": \"string\",\n \"description\": \"Regex string applied to the decoded seed-page HTML to extract bill IDs. Capture group 1 must be the bill ID. Example for CA leginfo: \\\"/faces/billNavClient\\\\\\\\.xhtml\\\\\\\\?bill_id=([^\\\\\\\"&\\\\\\\\s]+)\\\"\"\n },\n \"statusPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"URL path + query template for the bill status page. Use {bill_id} as the placeholder; the service prepends the seed origin. Example: \\\"/faces/billStatusClient.xhtml?bill_id={bill_id}\\\"\"\n },\n \"votesPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"URL path + query template for the bill votes page. Same substitution as statusPageTemplate. Example: \\\"/faces/billVotesClient.xhtml?bill_id={bill_id}\\\"\"\n },\n \"textPageTemplate\": {\n \"type\": \"string\",\n \"description\": \"Optional URL path + query template for the bill text page. When set, the sync fetches this page before LLM extraction to check the 'Date Published' timestamp and skip unchanged bills. Example: \\\"/faces/billTextClient.xhtml?bill_id={bill_id}\\\"\"\n }\n }\n },\n \"PdfArchiveConfig\": {\n \"type\": \"object\",\n \"required\": [\"linkSelector\"],\n \"additionalProperties\": false,\n \"description\": \"Listing-walk configuration for sourceType=pdf_archive. The page at `url` is treated as a paginated index of dated PDF documents; each linked PDF is fetched, pdf-parsed, and stored as a Minutes record. Cold-start work is bounded by maxNew (default 10) so first-run sync doesn't ingest years of historical archives. Per-document parsing (text → action records) is a downstream backend pass — this block carries no parser DSL.\",\n \"properties\": {\n \"linkSelector\": {\n \"type\": \"string\",\n \"description\": \"CSS selector for PDF anchor elements on the listing page. Each match yields a candidate document.\"\n },\n \"datePattern\": {\n \"type\": \"string\",\n \"description\": \"Regex applied to the link href (falling back to anchor text) to extract the document's date. Capture groups depend on dateFormat.\"\n },\n \"dateFormat\": {\n \"type\": \"string\",\n \"description\": \"Date format hint for interpreting datePattern's captures. Supported: 'MMDDYY' (3 captures: month, day, two-digit year — assumed 20YY), 'YYYY-MM-DD' (3 captures), 'MM/DD/YYYY' (3 captures).\"\n },\n \"revisionPattern\": {\n \"type\": \"string\",\n \"description\": \"Regex against the link href whose match indicates this URL is a revision. Capture group 1 is the revision sequence number (1, 2, ...). Unmatched URLs are revisionSeq=0.\"\n },\n \"maxPages\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Maximum number of listing pages to walk during one sync cycle. Default: 10.\"\n },\n \"maxNew\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"description\": \"Hard cap on number of new documents ingested per sync cycle. Cold-start protection. Default: 10.\"\n },\n \"paginationParam\": {\n \"type\": \"string\",\n \"description\": \"Query parameter name used to paginate the listing page (e.g., 'page'). Omitted when the listing isn't paginated.\"\n }\n }\n }\n }\n}","/**\n * Pure logic for scaffolding a region config for the\n * [`OpusPopuli/opuspopuli-regions`](https://github.com/OpusPopuli/opuspopuli-regions)\n * repo.\n *\n * Region configs are declarative JSON files validated against\n * `schema/region-plugin.schema.json` in that repo. We vendor a copy of that\n * schema at `./region-schema.json` so the wizard is self-contained and\n * validates against the **canonical contract** rather than a hand-rolled\n * approximation. Anything the schema enforces is enforced here; we layer a\n * small set of cross-field invariants on top that the regions repo's\n * `pnpm test` also checks (e.g. `name === config.regionId`).\n *\n * Everything here is side-effect free and unit tested. The interactive shell\n * and filesystem writes live in `src/commands/region.ts`.\n */\n\n// ESM-native JSON Schema validator. Picked over Ajv 8 because Ajv ships only\n// CJS, which forces a `.default` interop dance under `verbatimModuleSyntax`.\n// `@cfworker/json-schema` is a clean ESM module with no peer dep and supports\n// the Draft 7 / 2019-09 / 2020-12 schemas the regions repo uses.\nimport { Validator, type Schema } from '@cfworker/json-schema';\n\n// Schema imported as JSON so tsup inlines it into the bundle — no need to\n// ship a separate file in dist/.\nimport REGION_SCHEMA from './region-schema.json' with { type: 'json' };\n\n/** `dataType` values the regions schema accepts on a data source. Mirrors the\n * enum block in `region-plugin.schema.json` so the CLI prompt matches. */\nexport const DATA_TYPES = [\n 'propositions',\n 'meetings',\n 'representatives',\n 'campaign_finance',\n 'lobbying',\n 'civics',\n 'bills',\n] as const;\nexport type DataType = (typeof DATA_TYPES)[number];\n\n/** `sourceType` values the regions schema accepts on a data source. */\nexport const SOURCE_TYPES = [\n 'html_scrape',\n 'bulk_download',\n 'api',\n 'pdf',\n 'pdf_archive',\n] as const;\nexport type SourceType = (typeof SOURCE_TYPES)[number];\n\n/** The two region levels this scaffolder authors. `federal` is a singleton that\n * already exists in the regions repo, so it is intentionally not offered. */\nexport type RegionLevel = 'state' | 'county';\n\nexport interface DataSourceInput {\n url: string;\n dataType: DataType;\n sourceType: SourceType;\n contentGoal: string;\n category?: string;\n}\n\nexport interface RegionInput {\n level: RegionLevel;\n /** kebab-case; for a county this is the combined `state-county` id. */\n regionId: string;\n /** kebab-case county slug only — the trailing segment of a county regionId.\n * Required for counties so we never have to re-derive it from string\n * prefixes; ignored for states. */\n countySlug?: string;\n displayName: string;\n regionName: string;\n description: string;\n /** semver, e.g. `0.1.0`. */\n version: string;\n /** IANA tz, e.g. `America/Los_Angeles`. */\n timezone: string;\n /** Two-letter US state code, uppercase. */\n stateCode: string;\n /** 2 digits for a state, 5 digits for a county. */\n fipsCode: string;\n /** kebab-case parent state id; required for counties, omitted for states. */\n parentRegionId?: string;\n dataSources: DataSourceInput[];\n}\n\ninterface DeclarativeRegionConfig {\n regionId: string;\n regionName: string;\n description: string;\n timezone: string;\n stateCode?: string;\n parentRegionId?: string;\n fipsCode?: string;\n dataSources: DataSourceInput[];\n}\n\nexport interface RegionPluginFile {\n name: string;\n displayName: string;\n description: string;\n version: string;\n config: DeclarativeRegionConfig;\n}\n\nexport const SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst STATE_CODE_RE = /^[A-Z]{2}$/;\n\n/** Lower-cases, strips accents, and collapses anything non-alphanumeric into\n * single hyphens — turning \"Los Angeles County\" into \"los-angeles\". */\nexport function slugify(input: string): string {\n return input\n .normalize('NFKD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n // The collapse above leaves at most a single hyphen at each edge, so a\n // quantifier-free `^-|-$` trim is equivalent to `^-+|-+$` and can't\n // backtrack super-linearly.\n .replace(/^-|-$/g, '');\n}\n\nexport function isValidSlug(v: string): boolean {\n return SLUG_RE.test(v);\n}\n\nexport function isValidStateCode(v: string): boolean {\n return STATE_CODE_RE.test(v);\n}\n\n/** A state FIPS is exactly 2 digits; a county FIPS is exactly 5 (state prefix +\n * 3-digit county). */\nexport function isValidFips(v: string, level: RegionLevel): boolean {\n return level === 'state' ? /^\\d{2}$/.test(v) : /^\\d{5}$/.test(v);\n}\n\n/** Set of IANA zone names on this runtime, or `null` if the host VM doesn't\n * expose `Intl.supportedValuesOf` (in which case callers should skip the\n * membership check rather than reject everything). */\nfunction supportedTimeZones(): Set<string> | null {\n const intl = Intl as typeof Intl & {\n supportedValuesOf?: (key: string) => string[];\n };\n if (typeof intl.supportedValuesOf !== 'function') return null;\n try {\n return new Set(intl.supportedValuesOf('timeZone'));\n } catch {\n return null;\n }\n}\n\nexport function isValidTimezone(v: string): boolean {\n if (!v.includes('/')) return false;\n const zones = supportedTimeZones();\n // If the runtime can't enumerate zones, fall back to a shape check so we\n // don't reject a perfectly good \"Region/City\" string.\n return zones ? zones.has(v) : true;\n}\n\n/**\n * Build the `RegionPluginFile` object from collected input. Optional config\n * fields are only set when present so the JSON stays minimal and we don't trip\n * the schema's `additionalProperties: false` / `exactOptionalPropertyTypes`.\n */\nexport function buildRegionConfig(input: RegionInput): RegionPluginFile {\n const config: DeclarativeRegionConfig = {\n // The regions repo requires `name === config.regionId`; we tie them\n // together at construction so they can never drift.\n regionId: input.regionId,\n regionName: input.regionName,\n description: input.description,\n timezone: input.timezone,\n stateCode: input.stateCode,\n fipsCode: input.fipsCode,\n dataSources: input.dataSources.map(normalizeDataSource),\n };\n if (input.parentRegionId) {\n config.parentRegionId = input.parentRegionId;\n }\n\n return {\n name: input.regionId,\n displayName: input.displayName,\n description: input.description,\n version: input.version,\n config,\n };\n}\n\nfunction normalizeDataSource(src: DataSourceInput): DataSourceInput {\n const out: DataSourceInput = {\n url: src.url,\n dataType: src.dataType,\n sourceType: src.sourceType,\n contentGoal: src.contentGoal,\n };\n if (src.category) out.category = src.category;\n return out;\n}\n\n/**\n * Canonical path of a region file inside the regions repo, relative to the repo\n * root:\n * state → `regions/<state>/<state>.json`\n * county → `regions/<state>/counties/<county>/<county>.json`\n *\n * Counties pass `countySlug` explicitly so we never have to back out a slug\n * from a string prefix — important when a parent state slug contains a hyphen\n * (`new-jersey-cumberland` shouldn't be sliced on the first `-`).\n */\nexport function regionFilePath(input: {\n level: RegionLevel;\n regionId: string;\n parentRegionId?: string;\n countySlug?: string;\n}): string {\n if (input.level === 'state') {\n return `regions/${input.regionId}/${input.regionId}.json`;\n }\n const parent = input.parentRegionId;\n const countySlug = input.countySlug;\n if (!parent || !countySlug) {\n throw new Error(\n 'regionFilePath: county requires both parentRegionId and countySlug',\n );\n }\n return `regions/${parent}/counties/${countySlug}/${countySlug}.json`;\n}\n\n// ---------------------------------------------------------------------------\n// Schema-based validation (single source of truth)\n// ---------------------------------------------------------------------------\n\n// The JSON import resolves to a narrower literal type than `Schema` accepts\n// (e.g. `type: \"object\"` as a string literal vs the union enum). The cast is\n// a TS-only widening — runtime data is unchanged.\nconst schemaValidator = new Validator(REGION_SCHEMA as unknown as Schema, '7');\n\n/**\n * Re-check the invariants the regions repo enforces in CI, returning a list of\n * human-readable problems (empty means valid). Two layers:\n *\n * 1. **JSON Schema** — run the vendored `region-plugin.schema.json` (the same\n * file `pnpm test` validates against). Catches every structural rule the\n * schema declares.\n * 2. **Cross-field invariants** — checks the regions repo enforces in custom\n * test code that don't live in the schema: `name === config.regionId`,\n * county regionId prefixed by its parent, no duplicate data sources keyed by\n * `(dataType, url)`.\n */\nexport function validateRegionConfig(file: RegionPluginFile): string[] {\n // Cross-field invariants run first so their human-friendlier messages\n // (\"not a valid semver\", \"must be 5 digits for a county\", \"name mismatch\")\n // surface ahead of the corresponding raw Ajv pattern errors. Order of the\n // groups here IS the order issues are reported in.\n return [\n ...validateVersionAndIds(file),\n ...validateFipsCode(file),\n ...validateDataSourceUniqueness(file),\n ...validateAgainstSchema(file),\n ];\n}\n\n// version semver + name/regionId agreement + kebab-case + county prefix.\nfunction validateVersionAndIds(file: RegionPluginFile): string[] {\n const issues: string[] = [];\n const { config } = file;\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(file.version)) {\n issues.push(`version \"${file.version}\" is not a valid semver (expected MAJOR.MINOR.PATCH)`);\n }\n if (file.name !== config.regionId) {\n issues.push(`name \"${file.name}\" must equal config.regionId \"${config.regionId}\"`);\n }\n if (!isValidSlug(config.regionId)) {\n issues.push(`regionId \"${config.regionId}\" must be kebab-case`);\n }\n if (\n config.parentRegionId !== undefined &&\n !config.regionId.startsWith(`${config.parentRegionId}-`)\n ) {\n issues.push(\n `county regionId \"${config.regionId}\" should be prefixed with its parent \"${config.parentRegionId}-\"`,\n );\n }\n return issues;\n}\n\n// The JSON schema only checks the FIPS shape (2–7 digits). Per-level lengths\n// (\"2 for state, 5 for county\") are a cross-field rule the regions repo\n// enforces in custom test code — re-checked here.\nfunction validateFipsCode(file: RegionPluginFile): string[] {\n const { config } = file;\n if (config.fipsCode === undefined) return [];\n const isCounty = config.parentRegionId !== undefined;\n const expected = isCounty ? 5 : 2;\n if (!/^\\d+$/.test(config.fipsCode) || config.fipsCode.length !== expected) {\n return [\n `fipsCode \"${config.fipsCode}\" must be ${expected} digits for a ${isCounty ? 'county' : 'state'}`,\n ];\n }\n return [];\n}\n\n// dataSources is required by the schema — if it's missing the schema layer\n// below will flag that, so we just skip the duplicate scan here rather than\n// throwing on a malformed-but-not-yet-validated file.\nfunction validateDataSourceUniqueness(file: RegionPluginFile): string[] {\n const { config } = file;\n if (!Array.isArray(config.dataSources)) return [];\n const issues: string[] = [];\n const seen = new Set<string>();\n for (const src of config.dataSources) {\n const key = `${src.dataType} ${src.url}`;\n if (seen.has(key)) {\n issues.push(`duplicate data source: ${src.dataType} ${src.url}`);\n }\n seen.add(key);\n }\n return issues;\n}\n\n// Layer the schema on last — catches anything the friendly checks didn't\n// pre-empt (missing required fields, wrong types, unknown extras, etc.).\nfunction validateAgainstSchema(file: RegionPluginFile): string[] {\n const result = schemaValidator.validate(file);\n if (result.valid) return [];\n return result.errors.map((err) => `schema: ${err.instanceLocation || '<root>'} ${err.error}`);\n}\n","import { mkdir, writeFile, access } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { Command, Option } from 'commander';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\n\nimport {\n DATA_TYPES,\n SOURCE_TYPES,\n buildRegionConfig,\n isValidFips,\n isValidSlug,\n isValidStateCode,\n isValidTimezone,\n regionFilePath,\n slugify,\n validateRegionConfig,\n type DataSourceInput,\n type DataType,\n type RegionInput,\n type RegionLevel,\n type RegionPluginFile,\n type SourceType,\n} from '../lib/region.js';\nimport { unwrap } from '../lib/prompts.js';\n\ninterface RegionOptions {\n level?: string;\n name?: string;\n parent?: string;\n stateCode?: string;\n fips?: string;\n timezone?: string;\n outDir?: string;\n force?: boolean;\n}\n\nexport const regionCommand = new Command('region')\n .description(\n 'Scaffold a schema-valid region config for the OpusPopuli/opuspopuli-regions repo. ' +\n 'Run this from inside your checkout of that repo.',\n )\n .addOption(\n new Option('--level <level>', 'Region level').choices(['state', 'county']),\n )\n .addOption(new Option('--name <name>', 'Region name (e.g. \"California\" or \"Alameda\")'))\n .addOption(\n new Option('--parent <slug>', 'Parent state slug for a county (e.g. california)'),\n )\n .addOption(new Option('--state-code <code>', 'Two-letter US state code (e.g. CA)'))\n .addOption(new Option('--fips <code>', 'FIPS code (2 digits state, 5 digits county)'))\n .addOption(new Option('--timezone <tz>', 'IANA timezone (e.g. America/Los_Angeles)'))\n .addOption(\n new Option('--out-dir <dir>', 'Repo root to write under').default(\n process.cwd(),\n 'current directory',\n ),\n )\n .addOption(new Option('-f, --force', 'Overwrite an existing config file').default(false))\n .action(async (opts: RegionOptions) => {\n p.intro(pc.bgMagenta(pc.black(' create-op-node region ')));\n printRegionWelcome();\n\n const targetDir = await resolveTargetDir(opts);\n const level = await resolveLevel(opts);\n const identity = await collectIdentity(opts, level);\n const codes = await collectCodes(opts, level);\n const dataSources = await collectDataSources();\n\n const input = buildRegionInput({ level, identity, codes, dataSources });\n const file = buildAndValidateConfig(input);\n await writeRegionConfig({ opts, targetDir, level, identity, file });\n });\n\n// ----------------------------------------------------------------------------\n// Region wizard steps\n// ----------------------------------------------------------------------------\n// The action delegates to these so no single function exceeds the\n// cognitive-complexity budget. Behavior-preserving: prompts, validation, and\n// process.exit calls are relocated verbatim.\n\ninterface RegionIdentity {\n rawName: string;\n parentSlug: string | undefined;\n ownSlug: string;\n regionId: string;\n regionName: string;\n description: string;\n}\n\ninterface RegionCodes {\n stateCode: string;\n fipsCode: string;\n timezone: string;\n}\n\nconst requireNonEmpty = (v: string | undefined): string | undefined =>\n v && v.trim().length > 0 ? undefined : 'Required';\n\nfunction printRegionWelcome(): void {\n p.note(\n [\n 'Scaffolds a declarative region config JSON for opuspopuli-regions —',\n 'the file that defines WHAT civic data a region collects.',\n '',\n pc.dim('Run this from the root of your opuspopuli-regions checkout.'),\n pc.dim('It validates the same invariants the repo’s `pnpm test` enforces,'),\n pc.dim('so the file lands green and you just commit + open a PR.'),\n ].join('\\n'),\n 'Welcome',\n );\n}\n\n// ---- Step 0: sanity-check we're inside an opuspopuli-regions checkout ----\nasync function resolveTargetDir(opts: RegionOptions): Promise<string> {\n const targetDir = opts.outDir ?? process.cwd();\n const looksRight = await looksLikeRegionsRepo(targetDir);\n if (!looksRight) {\n const proceed = unwrap(\n await p.confirm({\n message: `${targetDir} doesn't look like an opuspopuli-regions checkout (no schema/region-plugin.schema.json). Continue anyway?`,\n initialValue: false,\n }),\n );\n if (!proceed) {\n p.cancel('Cancelled — run again from your opuspopuli-regions checkout, or pass --out-dir.');\n process.exit(0);\n }\n }\n return targetDir;\n}\n\n// ---- Step 1: level ----\nasync function resolveLevel(opts: RegionOptions): Promise<RegionLevel> {\n return opts.level === 'state' || opts.level === 'county'\n ? opts.level\n : unwrap(\n await p.select({\n message: 'What level is this region?',\n options: [\n { value: 'state', label: 'State', hint: 'e.g. California' },\n { value: 'county', label: 'County', hint: 'e.g. Alameda, within California' },\n ],\n }),\n );\n}\n\n// Parent state slug — only prompted for counties.\nasync function resolveParentSlug(opts: RegionOptions, level: RegionLevel): Promise<string | undefined> {\n if (level !== 'county') return undefined;\n const parentSlug =\n opts.parent ??\n unwrap(\n await p.text({\n message: 'Parent state slug?',\n placeholder: 'california',\n validate: (v) =>\n isValidSlug(v ?? '') ? undefined : 'kebab-case (lowercase letters, digits, hyphens)',\n }),\n );\n if (!isValidSlug(parentSlug)) {\n p.cancel(`Parent slug \"${parentSlug}\" must be kebab-case.`);\n process.exit(1);\n }\n return parentSlug;\n}\n\n// ---- Step 2: identity (name, slug, parent, display, description) ----\nasync function collectIdentity(opts: RegionOptions, level: RegionLevel): Promise<RegionIdentity> {\n const rawName =\n opts.name ??\n unwrap(\n await p.text({\n message: level === 'county' ? 'County name?' : 'State name?',\n placeholder: level === 'county' ? 'Alameda' : 'California',\n validate: requireNonEmpty,\n }),\n );\n\n const parentSlug = await resolveParentSlug(opts, level);\n\n const ownSlug = slugify(rawName);\n const regionId = level === 'county' ? `${parentSlug}-${ownSlug}` : ownSlug;\n if (!isValidSlug(regionId)) {\n p.cancel(`Derived regionId \"${regionId}\" is not valid kebab-case. Try a simpler name.`);\n process.exit(1);\n }\n\n const displayName = unwrap(\n await p.text({\n message: 'Display name?',\n defaultValue: rawName,\n }),\n );\n const regionName = displayName || rawName;\n\n const description = unwrap(\n await p.text({\n message: 'One-line description of the data coverage?',\n placeholder:\n level === 'county'\n ? `Civic data for ${rawName} County`\n : `Civic data for the state of ${rawName}`,\n validate: requireNonEmpty,\n }),\n );\n\n return { rawName, parentSlug, ownSlug, regionId, regionName, description };\n}\n\n// ---- Step 3: codes (state code, FIPS, timezone) ----\nasync function collectCodes(opts: RegionOptions, level: RegionLevel): Promise<RegionCodes> {\n const stateCode = (\n opts.stateCode ??\n unwrap(\n await p.text({\n message: 'Two-letter state code?',\n placeholder: 'CA',\n validate: (v) =>\n isValidStateCode((v ?? '').toUpperCase()) ? undefined : 'Two letters, e.g. CA',\n }),\n )\n ).toUpperCase();\n if (!isValidStateCode(stateCode)) {\n p.cancel(`State code \"${stateCode}\" must be two letters.`);\n process.exit(1);\n }\n\n const fipsCode =\n opts.fips ??\n unwrap(\n await p.text({\n message: level === 'county' ? 'County FIPS (5 digits)?' : 'State FIPS (2 digits)?',\n placeholder: level === 'county' ? '06001' : '06',\n validate: (v) => {\n if (isValidFips(v ?? '', level)) return undefined;\n const expectedDigits = level === 'county' ? '5' : '2';\n return `Expected ${expectedDigits} digits`;\n },\n }),\n );\n if (!isValidFips(fipsCode, level)) {\n p.cancel(`FIPS \"${fipsCode}\" is the wrong length for a ${level}.`);\n process.exit(1);\n }\n\n const timezone =\n opts.timezone ??\n unwrap(\n await p.text({\n message: 'IANA timezone?',\n defaultValue: 'America/Los_Angeles',\n placeholder: 'America/Los_Angeles',\n validate: (v) =>\n isValidTimezone(v || 'America/Los_Angeles')\n ? undefined\n : 'Not a recognized IANA zone (e.g. America/New_York)',\n }),\n );\n\n return { stateCode, fipsCode, timezone };\n}\n\n// ---- Step 4: at least one data source ----\nasync function collectOneDataSource(index: number): Promise<DataSourceInput> {\n const url = unwrap(\n await p.text({\n message: `Data source #${index} — URL?`,\n placeholder: 'https://example.gov/meetings',\n validate: (v) => (/^https?:\\/\\//.test(v ?? '') ? undefined : 'Must start with http(s)://'),\n }),\n );\n const dataType = unwrap(\n await p.select({\n message: 'Data type?',\n options: DATA_TYPES.map((t) => ({ value: t, label: t })),\n }),\n ) as DataType;\n const sourceType = unwrap(\n await p.select({\n message: 'Source type?',\n initialValue: 'html_scrape' as SourceType,\n options: SOURCE_TYPES.map((t) => ({ value: t, label: t })),\n }),\n ) as SourceType;\n const contentGoal = unwrap(\n await p.text({\n message: 'Content goal (what should the scraper extract)?',\n placeholder: 'Fetch upcoming board meeting agendas and minutes',\n validate: requireNonEmpty,\n }),\n );\n const category = unwrap(\n await p.text({\n message: 'Category label (optional)?',\n placeholder: 'Board of Supervisors',\n }),\n );\n\n const src: DataSourceInput = { url, dataType, sourceType, contentGoal };\n if (category && category.trim().length > 0) src.category = category.trim();\n return src;\n}\n\nasync function collectDataSources(): Promise<DataSourceInput[]> {\n const dataSources: DataSourceInput[] = [];\n do {\n dataSources.push(await collectOneDataSource(dataSources.length + 1));\n const again = unwrap(\n await p.confirm({ message: 'Add another data source?', initialValue: false }),\n );\n if (!again) break;\n // eslint-disable-next-line no-constant-condition\n } while (true);\n return dataSources;\n}\n\n// ---- Step 5: build the RegionInput from the collected answers ----\nexport function buildRegionInput(args: {\n level: RegionLevel;\n identity: RegionIdentity;\n codes: RegionCodes;\n dataSources: DataSourceInput[];\n}): RegionInput {\n const { level, identity, codes, dataSources } = args;\n return {\n level,\n regionId: identity.regionId,\n displayName: identity.regionName,\n regionName: identity.regionName,\n description: identity.description,\n // New region configs start at 0.1.0 — the documented convention in the\n // regions repo's CLAUDE.md. Bump manually as the config matures.\n version: '0.1.0',\n timezone: codes.timezone,\n stateCode: codes.stateCode,\n fipsCode: codes.fipsCode,\n dataSources,\n ...(identity.parentSlug ? { parentRegionId: identity.parentSlug } : {}),\n ...(level === 'county' ? { countySlug: identity.ownSlug } : {}),\n };\n}\n\n// Build + validate the config; exits if the generated file would fail CI.\nfunction buildAndValidateConfig(input: RegionInput): RegionPluginFile {\n const file = buildRegionConfig(input);\n const issues = validateRegionConfig(file);\n if (issues.length > 0) {\n p.note(issues.map((i) => `${pc.red('•')} ${i}`).join('\\n'), 'Validation failed');\n p.cancel('The generated config would not pass the regions repo CI. Re-run and adjust.');\n process.exit(1);\n }\n return file;\n}\n\n// ---- Step 6: preview + write ----\nasync function writeRegionConfig(args: {\n opts: RegionOptions;\n targetDir: string;\n level: RegionLevel;\n identity: RegionIdentity;\n file: RegionPluginFile;\n}): Promise<void> {\n const { opts, targetDir, level, identity, file } = args;\n const relPath = regionFilePath({\n level,\n regionId: identity.regionId,\n ...(identity.parentSlug ? { parentRegionId: identity.parentSlug } : {}),\n ...(level === 'county' ? { countySlug: identity.ownSlug } : {}),\n });\n const absPath = resolve(targetDir, relPath);\n const json = `${JSON.stringify(file, null, 2)}\\n`;\n\n p.note(json, `${relPath} (preview)`);\n\n if (!opts.force && (await fileExists(absPath))) {\n p.cancel(`${relPath} already exists. Re-run with --force to overwrite.`);\n process.exit(1);\n }\n\n const write = unwrap(\n await p.confirm({ message: `Write ${relPath}?`, initialValue: true }),\n );\n if (!write) {\n p.cancel('Nothing written.');\n process.exit(0);\n }\n\n await mkdir(dirname(absPath), { recursive: true });\n await writeFile(absPath, json, 'utf8');\n\n p.note(\n [\n `${pc.green('✓')} Wrote ${pc.cyan(relPath)}`,\n '',\n 'Next steps in your opuspopuli-regions checkout:',\n pc.dim(' pnpm test # schema + hierarchy validation'),\n pc.dim(' pnpm test:connectivity # URL reachability (informational)'),\n pc.dim(` git add ${relPath} && git commit && open a PR`),\n ].join('\\n'),\n 'Done',\n );\n p.outro(pc.magenta(`Region scaffolded: ${identity.regionId}`));\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Heuristic: the regions repo always has `schema/region-plugin.schema.json`\n * and a top-level `regions/` directory. If both are present we're confident\n * we're in the right checkout; if neither we warn before writing anywhere. */\nasync function looksLikeRegionsRepo(dir: string): Promise<boolean> {\n const [hasSchema, hasRegions] = await Promise.all([\n fileExists(join(dir, 'schema', 'region-plugin.schema.json')),\n fileExists(join(dir, 'regions')),\n ]);\n return hasSchema && hasRegions;\n}\n","/**\n * argv helpers for the CLI entrypoint. Kept in their own module (not `cli.ts`)\n * so they're unit-testable without triggering `cli.ts`'s top-level\n * `program.parseAsync` side effect on import.\n */\n\n/** Program-level flags Commander handles itself — never route these to a\n * subcommand. */\nconst GLOBAL_FLAGS = new Set(['-v', '--version', '-h', '--help']);\n\n/**\n * Inject the default `init` subcommand when the caller didn't name one, so the\n * create-* convention holds: `npx create-op-node` AND `npx create-op-node\n * --region us-ca` both \"just work\" instead of erroring on an unknown program\n * option. (#36 — previously only the zero-arg case was handled.)\n *\n * `argv` is the full `process.argv` (`[node, script, ...rest]`). Returns a new\n * array — the input is not mutated. `init` is inserted before the first user\n * arg UNLESS that arg is already a known subcommand or a global flag\n * (`-v`/`--version`/`-h`/`--help`).\n */\nexport function withDefaultSubcommand(argv: string[], known: readonly string[]): string[] {\n const first = argv[2];\n if (first !== undefined && (known.includes(first) || GLOBAL_FLAGS.has(first))) {\n return argv;\n }\n return [...argv.slice(0, 2), 'init', ...argv.slice(2)];\n}\n","import { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { initCommand } from './commands/init.js';\nimport { bootstrapCommand } from './commands/bootstrap.js';\nimport { resetCommand } from './commands/reset.js';\nimport { verifyCommand } from './commands/verify.js';\nimport { regionCommand } from './commands/region.js';\nimport { withDefaultSubcommand } from './lib/cli-args.js';\n\n// release-please updates the string in `const VERSION = '...'` on each\n// release. See release-please-config.json's extra-files entry that points\n// at this file with type: generic — that scanner finds the version string\n// in package.json (via the manifest file) and updates literals on lines\n// like the one below.\n// x-release-please-start-version\nconst VERSION = '0.15.2';\n// x-release-please-end\n\nconst program = new Command();\n\nprogram\n .name('create-op-node')\n .description(\n 'Interactive bootstrap for an Opus Populi federation node.\\n' +\n 'Cloudflare infrastructure → Mac Studio → live public API.',\n )\n .version(VERSION, '-v, --version', 'show version');\n\nprogram.addCommand(initCommand);\nprogram.addCommand(bootstrapCommand);\nprogram.addCommand(resetCommand);\nprogram.addCommand(verifyCommand);\nprogram.addCommand(regionCommand);\n\n// Default to `init` — the create-* convention is that `npx create-op-node`\n// (and `npx create-op-node --region us-ca`) \"just work\" without naming a\n// subcommand. Only skip when the first arg is already a known subcommand or a\n// global flag. Known names are derived from the registered commands so the\n// list can't drift.\nprocess.argv = withDefaultSubcommand(\n process.argv,\n program.commands.map((c) => c.name()),\n);\n\nawait program.parseAsync(process.argv).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`\\n${pc.red('✗')} ${msg}\\n`);\n process.exit(1);\n});\n"]}
|