@impulselab/hepha 0.1.0 → 0.2.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/config.ts","../src/lib/errors.ts","../src/lib/is-http-url.ts","../src/lib/api.ts","../src/lib/args.ts","../src/lib/output.ts","../src/commands/approvals.ts","../src/commands/catalog.ts","../src/commands/help.ts","../src/commands/keys.ts","../src/commands/login.ts","../../../packages/database/constants.ts","../src/lib/open-browser.ts","../src/commands/logout.ts","../src/commands/questions.ts","../src/lib/format-event.ts","../src/lib/follow.ts","../src/lib/print-session.ts","../src/lib/session-outcome.ts","../src/commands/run.ts","../src/commands/sessions.ts","../src/commands/whoami.ts","../src/index.ts"],"sourcesContent":["import {\n chmodSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { CliError } from \"./errors\";\nimport { isHttpUrl } from \"./is-http-url\";\n\nexport interface CliConfig {\n /** Platform base URL, e.g. https://hephaistos.impulselab.ai. */\n baseUrl: string;\n /** Session token from the device flow. Absent until `hepha login`. */\n token?: string;\n user?: { id: string; name: string; email: string };\n}\n\nconst CONFIG_PATH = join(homedir(), \".hepha\", \"config.json\");\n\n/**\n * Production, because this binary is installed globally: a localhost default\n * would make the documented bare `hepha login` fail on every machine that is\n * not a Hephaistos dev box. Point elsewhere with HEPHA_URL, or once with\n * `hepha login --url http://localhost:3000`, which stores it.\n */\nconst DEFAULT_BASE_URL = \"https://hephaistos.impulselab.ai\";\n\nfunction readFileAsObject(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(readFileSync(CONFIG_PATH, \"utf8\"));\n // Valid JSON is not necessarily an object: a file holding `null` or a\n // bare string parses fine and then throws on the first property read,\n // taking down every command. Fall back to defaults instead.\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return parsed as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\n/** A hand-edited file can hold anything; only usable strings get through. */\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction readUser(value: unknown): CliConfig[\"user\"] {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n const candidate = value as Record<string, unknown>;\n const user = {\n id: readString(candidate.id),\n name: readString(candidate.name),\n email: readString(candidate.email),\n };\n\n return user.id && user.name && user.email\n ? { id: user.id, name: user.name, email: user.email }\n : undefined;\n}\n\n/** A usable base URL, or nothing — \"not a url\" would otherwise reach\n * `new URL()` in api.ts and break every command. */\nfunction readHttpUrl(value: unknown): string | undefined {\n const raw = readString(value);\n return raw && isHttpUrl(raw) ? raw : undefined;\n}\n\n/** Same deployment? Compared on origin, so a trailing slash does not matter. */\nfunction isSameOrigin(a: string, b: string): boolean {\n try {\n return new URL(a).origin === new URL(b).origin;\n } catch {\n return false;\n }\n}\n\n/**\n * `~/.hepha/config.json` — where a device-flow session lives between runs.\n *\n * Written 0600, because it holds a token that acts as the human. Agents are\n * expected to use HEPHA_API_KEY instead and never touch this file.\n */\nexport const config = {\n path: CONFIG_PATH,\n\n load(): CliConfig {\n const stored = readFileAsObject();\n const storedBaseUrl = readHttpUrl(stored.baseUrl);\n\n // A malformed HEPHA_URL is refused rather than ignored. Falling back would\n // run the command against production — with the production token, since\n // the origin would then match — which is the exact accident the\n // origin-binding below exists to prevent. A malformed value in the config\n // FILE still falls back: the user did not ask for it this run, and\n // bricking every command over a stale file helps nobody.\n const override = readString(process.env.HEPHA_URL);\n if (override && !readHttpUrl(override)) {\n throw new CliError(\n `HEPHA_URL is not a valid http(s) URL: \"${override}\".`,\n 2,\n );\n }\n\n const baseUrl = readHttpUrl(override) ?? storedBaseUrl ?? DEFAULT_BASE_URL;\n\n // The stored token is bound to the deployment it was issued by. Pointing\n // HEPHA_URL at staging or somebody else's instance must not send a human\n // bearer token for production to that origin — it would not authenticate\n // there, and it would hand the credential to whoever runs it.\n const token =\n storedBaseUrl && isSameOrigin(storedBaseUrl, baseUrl)\n ? readString(stored.token)\n : undefined;\n const user = token ? readUser(stored.user) : undefined;\n\n return {\n baseUrl,\n ...(token ? { token } : {}),\n ...(user ? { user } : {}),\n };\n },\n\n save(next: CliConfig): void {\n mkdirSync(dirname(CONFIG_PATH), { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_PATH, `${JSON.stringify(next, null, 2)}\\n`, {\n mode: 0o600,\n });\n chmodSync(CONFIG_PATH, 0o600);\n },\n\n clear(): void {\n rmSync(CONFIG_PATH, { force: true });\n },\n};\n","/**\n * A failure the user should read as a message, not a stack trace.\n *\n * `exitCode` is part of the contract for scripts and agents: 1 for a plain\n * failure, 2 for bad usage, 3 for \"the session needs a human\" — so a caller\n * can branch on it without parsing text.\n */\nexport class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n","export function isHttpUrl(value: string): boolean {\n try {\n const parsed = new URL(value);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n","import { config } from \"./config\";\nimport { CliError } from \"./errors\";\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n query?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n /**\n * Bypass the ambient credential resolution. `hepha login` uses this to read\n * `/me` with the token it just obtained: going through the environment there\n * would report whoever HEPHA_API_KEY belongs to, not the human who just\n * approved the device.\n */\n as?: { baseUrl: string; token: string };\n}\n\nfunction authHeaders(as: RequestOptions[\"as\"]): Record<string, string> {\n if (as) {\n return { authorization: `Bearer ${as.token}` };\n }\n\n const apiKey = process.env.HEPHA_API_KEY;\n if (apiKey) {\n // An agent's key wins over any stored human session, so a CI run is never\n // silently attributed to whoever last ran `hepha login` on the machine.\n return { \"x-api-key\": apiKey };\n }\n\n const token = process.env.HEPHA_TOKEN ?? config.load().token;\n if (token) {\n return { authorization: `Bearer ${token}` };\n }\n\n throw new CliError(\n \"Not signed in. Run `hepha login`, or set HEPHA_API_KEY to act as an agent.\",\n );\n}\n\nfunction messageFrom(status: number, payload: unknown): string {\n if (payload && typeof payload === \"object\" && \"message\" in payload) {\n const message = (payload as { message?: unknown }).message;\n if (typeof message === \"string\" && message.length > 0) {\n return message;\n }\n }\n if (status === 401) {\n return \"Unauthorized — your credential is missing, expired or revoked.\";\n }\n return `Request failed with status ${status}.`;\n}\n\n/**\n * The one place the CLI talks to the platform.\n *\n * Every command names its REST path once and gets its types from the router\n * (api-types.ts), so there is no generated client to keep in step and no\n * second copy of the API surface.\n */\nexport async function api<T>(\n path: string,\n options: RequestOptions = {},\n): Promise<T> {\n const baseUrl = options.as?.baseUrl ?? config.load().baseUrl;\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/api/v1${path}`);\n\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n\n // Resolved before the try: a missing credential is a usage error, not a\n // network failure, and must not be reported as one.\n const headers = {\n ...authHeaders(options.as),\n ...(options.body === undefined\n ? {}\n : { \"content-type\": \"application/json\" }),\n };\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: options.method ?? \"GET\",\n headers,\n ...(options.body === undefined\n ? {}\n : { body: JSON.stringify(options.body) }),\n });\n } catch (cause) {\n throw new CliError(\n `Cannot reach ${baseUrl}. Set HEPHA_URL if the platform lives elsewhere. (${String(cause)})`,\n );\n }\n\n const text = await response.text();\n\n // Not everything on the wire is JSON: a proxy, a CDN error page or a\n // sign-in redirect answers HTML, and parsing it blind surfaced as\n // \"Unexpected token '<'\" — useless to whoever pointed the CLI at the wrong\n // host. Report the status and the target instead.\n let payload: unknown = null;\n if (text) {\n try {\n payload = JSON.parse(text);\n } catch {\n throw new CliError(\n `${url.origin} answered ${response.status} with a non-JSON body. Is HEPHA_URL pointing at a Hephaistos deployment?`,\n );\n }\n }\n\n if (!response.ok) {\n throw new CliError(messageFrom(response.status, payload));\n }\n\n return payload as T;\n}\n","import { CliError } from \"./errors\";\n\nexport interface ParsedArgs {\n /** Non-flag arguments, in order. */\n positional: string[];\n /** `--flag value`, `--flag=value` and repeated flags (last wins). */\n flags: Record<string, string>;\n /** Every value seen for a repeatable flag, in order. */\n repeated: Record<string, string[]>;\n /** `--flag` with no value. */\n booleans: Set<string>;\n}\n\nconst BOOLEAN_FLAGS = new Set([\"json\", \"follow\", \"help\", \"all\", \"quiet\"]);\n\n/**\n * A deliberately small parser: no dependency, and the grammar stays something\n * an agent can generate blind — `hepha <group> <command> [args] [--flags]`.\n */\nexport const args = {\n parse(argv: string[]): ParsedArgs {\n const parsed: ParsedArgs = {\n positional: [],\n flags: {},\n repeated: {},\n booleans: new Set(),\n };\n\n let flagsEnded = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index]!;\n\n // `--` ends option parsing: a prompt or a steering message is allowed to\n // start with dashes, and without this there is no way to send one.\n if (!flagsEnded && token === \"--\") {\n flagsEnded = true;\n continue;\n }\n\n if (flagsEnded || !token.startsWith(\"--\")) {\n parsed.positional.push(token);\n continue;\n }\n\n const withoutDashes = token.slice(2);\n const equalsAt = withoutDashes.indexOf(\"=\");\n\n let name: string;\n let value: string | undefined;\n\n if (equalsAt >= 0) {\n name = withoutDashes.slice(0, equalsAt);\n value = withoutDashes.slice(equalsAt + 1);\n } else {\n name = withoutDashes;\n const next = argv[index + 1];\n if (\n !BOOLEAN_FLAGS.has(name) &&\n next !== undefined &&\n !next.startsWith(\"--\")\n ) {\n value = next;\n index += 1;\n }\n }\n\n if (value === undefined) {\n // A value-taking flag left bare is a typo, never an intent. Silently\n // ignoring it would let `hepha keys create x --scope` mint a key with\n // default scopes instead of the ones the caller thought they asked for.\n if (!BOOLEAN_FLAGS.has(name)) {\n throw new CliError(`--${name} expects a value.`, 2);\n }\n parsed.booleans.add(name);\n continue;\n }\n\n parsed.flags[name] = value;\n (parsed.repeated[name] ??= []).push(value);\n }\n\n return parsed;\n },\n\n required(parsed: ParsedArgs, index: number, name: string): string {\n const value = parsed.positional[index];\n if (!value) {\n throw new CliError(`Missing <${name}>.`, 2);\n }\n return value;\n },\n\n number(parsed: ParsedArgs, name: string): number | undefined {\n const raw = parsed.flags[name];\n if (raw === undefined) {\n return undefined;\n }\n const trimmed = raw.trim();\n const value = Number(trimmed);\n // Number(\"\") is 0, so an empty `--limit=` would quietly mean zero.\n if (trimmed === \"\" || !Number.isFinite(value)) {\n throw new CliError(`--${name} expects a number.`, 2);\n }\n return value;\n },\n};\n","const COLORS: Record<string, string> = {\n reset: \"\\u001b[0m\",\n dim: \"\\u001b[2m\",\n bold: \"\\u001b[1m\",\n red: \"\\u001b[31m\",\n green: \"\\u001b[32m\",\n yellow: \"\\u001b[33m\",\n blue: \"\\u001b[34m\",\n magenta: \"\\u001b[35m\",\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n running: \"blue\",\n provisioning: \"blue\",\n queued: \"dim\",\n created: \"dim\",\n delivering: \"blue\",\n verifying: \"blue\",\n waiting_human: \"yellow\",\n awaiting_approval: \"yellow\",\n completed: \"green\",\n failed: \"red\",\n killed: \"red\",\n abstained: \"yellow\",\n};\n\nfunction supportsColor(): boolean {\n return process.stdout.isTTY === true && process.env.NO_COLOR === undefined;\n}\n\n/**\n * Two audiences, one command set: humans read the aligned text, agents pass\n * `--json` and parse stdout. Everything a command prints goes through here, so\n * `--json` is never partially honoured.\n */\nexport const out = {\n json(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n },\n\n line(text = \"\"): void {\n process.stdout.write(`${text}\\n`);\n },\n\n error(text: string): void {\n // Sanitised like everything else: a failure message often carries a\n // session's statusReason, which is agent- or tool-authored text — and an\n // error line is the last thing that should be able to repaint the screen.\n process.stderr.write(`${out.paint(`error: ${out.safe(text)}`, \"red\")}\\n`);\n },\n\n paint(text: string, color: string): string {\n if (!supportsColor()) {\n return text;\n }\n return `${COLORS[color] ?? \"\"}${text}${COLORS.reset}`;\n },\n\n /**\n * Neutralise terminal control sequences in text the platform gives us.\n *\n * Transcript content, PR titles and question bodies carry model output, tool\n * output and repository contents — none of it trusted. Printed raw, an ESC\n * sequence could repaint or erase what the user already read, or emit an OSC\n * 8 hyperlink pointing somewhere else entirely. Newlines and tabs survive;\n * every other C0/C1 control does not. (`--json` is unaffected: JSON.stringify\n * already escapes control characters.)\n */\n safe(text: string): string {\n return text.replace(/[\\u0000-\\u0008\\u000b-\\u001f\\u007f-\\u009f]/g, \"\");\n },\n\n /** `safe`, flattened to one line — anything going into a table cell. */\n cell(text: string): string {\n return out.safe(text).replace(/\\s+/g, \" \").trim();\n },\n\n status(status: string): string {\n return out.paint(status, STATUS_COLORS[status] ?? \"reset\");\n },\n\n /** Left-aligned two-column block — the shape used by every list command. */\n table(rows: string[][]): void {\n if (rows.length === 0) {\n return;\n }\n const widths = rows[0]!.map((_, column) =>\n Math.max(...rows.map((row) => stripAnsi(row[column] ?? \"\").length)),\n );\n for (const row of rows) {\n const line = row\n .map((cell, column) => {\n const padding = widths[column]! - stripAnsi(cell).length;\n return column === row.length - 1 ? cell : cell + \" \".repeat(padding);\n })\n .join(\" \");\n out.line(line.trimEnd());\n }\n },\n};\n\n/** Width is measured on the visible text, so colour never breaks alignment. */\nfunction stripAnsi(text: string): string {\n return text.replace(/\\u001b\\[\\d+m/g, \"\");\n}\n","import { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { out } from \"../lib/output\";\n\n/**\n * Approving and rejecting require a human session and are refused for an API\n * key: a machine standing in for human validation would defeat the guardrail.\n */\nexport async function approvalsCommand(parsed: ParsedArgs): Promise<void> {\n const action = parsed.positional[0] ?? \"list\";\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n const result = await api<ApiOutputs[\"approvals\"][\"list\"]>(\"/approvals\");\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.items.length === 0) {\n out.line(\"No guardrail waiting on you.\");\n return;\n }\n out.table(\n result.items.map((item) => [\n out.cell(item.id),\n out.cell(item.guardrailKind),\n out.cell(item.repoName ?? \"—\"),\n out.cell(item.summary),\n ]),\n );\n return;\n }\n\n const guardrailId = args.required(parsed, 1, \"guardrailRequestId\");\n\n if (action === \"show\") {\n const detail = await api<ApiOutputs[\"approvals\"][\"get\"]>(\n `/approvals/${guardrailId}`,\n );\n if (asJson) {\n out.json(detail);\n return;\n }\n out.line(\n `${out.paint(out.cell(detail.guardrailKind), \"bold\")} ${detail.status}`,\n );\n out.line(out.safe(detail.summary));\n out.line();\n out.json(detail.payload);\n return;\n }\n\n if (action === \"approve\") {\n const result = await api<ApiOutputs[\"approvals\"][\"approve\"]>(\n `/approvals/${guardrailId}/approve`,\n { method: \"POST\", body: {} },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(`${out.paint(\"✓\", \"green\")} Approved ${out.cell(guardrailId)}`);\n return;\n }\n\n if (action === \"reject\") {\n const mode = parsed.flags.mode ?? \"rework\";\n if (mode !== \"rework\" && mode !== \"terminate\") {\n throw new CliError(\"--mode expects rework or terminate.\", 2);\n }\n if (mode === \"rework\" && !parsed.flags.feedback) {\n throw new CliError(\n \"--feedback is required with --mode rework: the agent needs to know what to change.\",\n 2,\n );\n }\n\n const result = await api<ApiOutputs[\"approvals\"][\"reject\"]>(\n `/approvals/${guardrailId}/reject`,\n {\n method: \"POST\",\n body: {\n mode,\n ...(parsed.flags.feedback ? { feedback: parsed.flags.feedback } : {}),\n },\n },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n `${out.paint(\"✓\", \"green\")} Rejected ${out.cell(guardrailId)} (${mode})`,\n );\n return;\n }\n\n throw new CliError(`Unknown approvals command \"${action}\".`, 2);\n}\n","import { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { out } from \"../lib/output\";\n\n/**\n * Read before creating a session: a repository outside `repos` is refused at\n * creation, and a model outside `models` is not routable.\n */\nexport async function catalogCommand(\n topic: string,\n parsed: ParsedArgs,\n): Promise<void> {\n const asJson = parsed.booleans.has(\"json\");\n\n if (topic === \"repos\") {\n const result = await api<ApiOutputs[\"catalog\"][\"repos\"]>(\"/repos\");\n if (asJson) {\n out.json(result);\n return;\n }\n for (const repo of result.repos) {\n out.line(out.cell(repo));\n }\n return;\n }\n\n if (topic === \"branches\") {\n const repoFullName = args.required(parsed, 0, \"owner/repo\");\n // Exactly two non-empty segments: \"a/b/c\" must be rejected, not silently\n // truncated to \"a/b\" and queried as a repository the caller never named.\n const segments = repoFullName.split(\"/\");\n const [owner, repo] = segments;\n if (segments.length !== 2 || !owner || !repo) {\n throw new CliError(\n `Expected a repository as \"owner/repo\", got \"${repoFullName}\".`,\n 2,\n );\n }\n\n const result = await api<ApiOutputs[\"catalog\"][\"branches\"]>(\n `/repos/${owner}/${repo}/branches`,\n );\n if (asJson) {\n out.json(result);\n return;\n }\n if (!result.result) {\n throw new CliError(`No GitHub installation covers ${repoFullName}.`);\n }\n for (const branch of result.result.branches) {\n out.line(\n branch === result.result.defaultBranch\n ? `${out.cell(branch)} ${out.paint(\"(default)\", \"dim\")}`\n : out.cell(branch),\n );\n }\n return;\n }\n\n if (topic === \"models\") {\n const result = await api<ApiOutputs[\"catalog\"][\"models\"]>(\"/models\");\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(out.paint(\"harnesses\", \"dim\"));\n for (const harness of result.harnesses) {\n out.line(` ${out.cell(harness)}`);\n }\n out.line();\n out.line(out.paint(\"gateway models\", \"dim\"));\n for (const model of result.gatewayModels) {\n out.line(` ${out.cell(model.id)}`);\n }\n return;\n }\n\n if (topic === \"skills\") {\n const result = await api<ApiOutputs[\"catalog\"][\"skills\"]>(\"/skills\");\n if (asJson) {\n out.json(result);\n return;\n }\n out.table(\n result.skills.map((skill) => [\n out.cell(skill.id),\n out.cell(skill.name),\n out.cell(skill.description ?? \"\"),\n ]),\n );\n return;\n }\n\n throw new CliError(`Unknown catalog topic \"${topic}\".`, 2);\n}\n","import { config } from \"../lib/config\";\nimport { out } from \"../lib/output\";\n\nconst HELP = `hepha — orchestrate Hephaistos sessions from a terminal or an agent.\n\nUSAGE\n hepha <command> [args] [--flags]\n\nTHE LOOP\n hepha run \"<prompt>\" --repo owner/repo --follow\n Start a session and follow it until it finishes or asks you something.\n Exit 0 completed · 3 waiting on a human · 1 failed.\n hepha questions list [--session <id>]\n hepha questions answer <batchId> --option <questionId>=1,2 --text <questionId>=\"…\"\n hepha approvals list | show <id> | approve <id> | reject <id> --mode rework --feedback \"…\"\n\nSESSIONS\n hepha sessions list [--status active|waiting|done] [--repo owner/repo]\n [--page N] [--limit N] [--all]\n hepha sessions get <id>\n hepha sessions logs <id> [--after <sequence>] [--follow]\n hepha sessions send <id> \"<message>\"\n hepha sessions pause|resume|kill|archive <id> [--reason \"…\"]\n hepha sessions checks|pr|verify <id>\n\nCATALOG\n hepha repos\n hepha branches <owner/repo>\n hepha models\n hepha skills\n\nAUTH\n hepha login [--url https://…] Device authorization: approve it in a browser.\n hepha logout\n hepha whoami\n hepha keys list\n hepha keys create <name> [--scope sessions:read]… [--expires-in-days 90]\n hepha keys revoke <keyId>\n\nENVIRONMENT\n HEPHA_API_KEY Act as an agent. Takes precedence over a stored login.\n HEPHA_TOKEN A device-flow session token, instead of ~/.hepha/config.json.\n HEPHA_URL Platform base URL.\n\nGLOBAL FLAGS\n --json Machine-readable output on stdout. Every command that\n returns data honours it; login is interactive and does not.\n\n`;\n\nexport function helpCommand(): void {\n // Resolved, not a placeholder: the reader can click straight through to the\n // Scalar reference for the platform this CLI is actually pointed at.\n const baseUrl = config.load().baseUrl.replace(/\\/$/, \"\");\n out.line(`${HELP}Full reference: ${baseUrl}/api/v1/docs`);\n}\n","import { api } from \"../lib/api\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { out } from \"../lib/output\";\n\ntype Scope = ApiInputs[\"keys\"][\"create\"][\"scopes\"];\n\n/**\n * Human sessions only, by design: a key cannot mint or revoke a key, so the\n * whole group fails with a 403 when HEPHA_API_KEY is set.\n */\nexport async function keysCommand(parsed: ParsedArgs): Promise<void> {\n const action = parsed.positional[0] ?? \"list\";\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n const result = await api<ApiOutputs[\"keys\"][\"list\"]>(\"/keys\");\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.keys.length === 0) {\n out.line(\"No keys. Create one with `hepha keys create <name>`.\");\n return;\n }\n out.table([\n [\n out.paint(\"ID\", \"dim\"),\n out.paint(\"NAME\", \"dim\"),\n out.paint(\"PREFIX\", \"dim\"),\n out.paint(\"SCOPES\", \"dim\"),\n ],\n ...result.keys.map((key) => [\n out.cell(key.id),\n out.cell(key.name ?? \"—\"),\n out.cell(key.start ?? \"—\"),\n key.scopes.join(\" \"),\n ]),\n ]);\n return;\n }\n\n if (action === \"create\") {\n const name = args.required(parsed, 1, \"name\");\n const scopes = parsed.repeated.scope as Scope;\n const expiresInDays = args.number(parsed, \"expires-in-days\");\n\n const created = await api<ApiOutputs[\"keys\"][\"create\"]>(\"/keys\", {\n method: \"POST\",\n body: {\n name,\n ...(scopes && scopes.length > 0 ? { scopes } : {}),\n ...(expiresInDays !== undefined ? { expiresInDays } : {}),\n },\n });\n\n if (asJson) {\n out.json(created);\n return;\n }\n\n out.line(\n `${out.paint(\"✓\", \"green\")} Created \"${out.cell(created.name ?? name)}\"`,\n );\n out.line();\n out.line(` ${out.paint(created.key, \"bold\")}`);\n out.line();\n out.line(\n out.paint(\n \" Copy it now — it is hashed at rest and never shown again.\",\n \"dim\",\n ),\n );\n out.line(out.paint(` Scopes: ${created.scopes.join(\" \")}`, \"dim\"));\n return;\n }\n\n if (action === \"revoke\") {\n const keyId = args.required(parsed, 1, \"keyId\");\n const result = await api<ApiOutputs[\"keys\"][\"revoke\"]>(`/keys/${keyId}`, {\n method: \"DELETE\",\n });\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(`${out.paint(\"✓\", \"green\")} Revoked ${out.cell(keyId)}`);\n return;\n }\n\n throw new CliError(`Unknown keys command \"${action}\".`, 2);\n}\n","import { createAuthClient } from \"better-auth/client\";\nimport { deviceAuthorizationClient } from \"better-auth/client/plugins\";\n\nimport { DEVICE_AUTHORIZATION } from \"@repo/database/constants\";\n\nimport { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport type { ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { isHttpUrl } from \"../lib/is-http-url\";\nimport { openBrowser } from \"../lib/open-browser\";\nimport { out } from \"../lib/output\";\n\nconst CLIENT_ID = DEVICE_AUTHORIZATION.CLIENT_IDS[0];\n\nfunction sleep(seconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, seconds * 1000));\n}\n\n/**\n * `hepha login` — OAuth 2.0 device authorization (RFC 8628).\n *\n * The CLI never sees a password and never asks for a pasted token: it gets a\n * short code, a human approves it in a browser that is already signed in to\n * Hephaistos, and only then does a session token exist. That approval is also\n * what makes a CLI session count as \"a human\" for guardrail decisions.\n */\nexport async function loginCommand(parsed: ParsedArgs): Promise<void> {\n const requested = parsed.flags.url?.trim();\n if (requested && !isHttpUrl(requested)) {\n throw new CliError(`--url is not a valid http(s) URL: \"${requested}\".`, 2);\n }\n\n const baseUrl = (requested ?? config.load().baseUrl).replace(/\\/$/, \"\");\n\n const authClient = createAuthClient({\n baseURL: baseUrl,\n plugins: [deviceAuthorizationClient()],\n });\n\n const { data: device, error: deviceError } = await authClient.device.code({\n client_id: CLIENT_ID,\n scope: \"openid profile email\",\n });\n\n if (deviceError || !device) {\n throw new CliError(\n deviceError?.error_description ??\n `Could not start a device login against ${baseUrl}.`,\n );\n }\n\n const verificationUrl =\n device.verification_uri_complete ?? device.verification_uri;\n\n out.line();\n out.line(` Code ${out.paint(out.cell(device.user_code), \"bold\")}`);\n out.line(` Open ${out.cell(verificationUrl)}`);\n out.line();\n out.line(out.paint(\" Waiting for approval…\", \"dim\"));\n\n openBrowser(verificationUrl);\n\n let interval = device.interval ?? 5;\n const deadline = Date.now() + (device.expires_in ?? 900) * 1000;\n\n while (Date.now() < deadline) {\n await sleep(interval);\n\n const { data: token, error } = await authClient.device.token({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: device.device_code,\n client_id: CLIENT_ID,\n });\n\n if (token?.access_token) {\n // Read /me with THIS token against THIS base URL. Falling back to the\n // ambient resolution would report HEPHA_API_KEY's owner, or query the\n // HEPHA_URL host rather than the one `--url` just authenticated against.\n const identity = await api<ApiOutputs[\"me\"][\"get\"]>(\"/me\", {\n as: { baseUrl, token: token.access_token },\n });\n\n config.save({\n baseUrl,\n token: token.access_token,\n user: {\n id: identity.user.id,\n name: identity.user.name,\n email: identity.user.email,\n },\n });\n\n out.line();\n out.line(\n `${out.paint(\"✓\", \"green\")} Signed in as ${identity.user.email} on ${baseUrl}`,\n );\n out.line(out.paint(` Session stored in ${config.path}`, \"dim\"));\n return;\n }\n\n if (!error) {\n continue;\n }\n\n switch (error.error) {\n case \"authorization_pending\":\n continue;\n case \"slow_down\":\n interval += 5;\n continue;\n case \"access_denied\":\n throw new CliError(\"Access denied — the request was rejected.\");\n default:\n throw new CliError(\n error.error_description || \"Device authorization failed.\",\n );\n }\n }\n\n throw new CliError(\"The code expired before it was approved. Try again.\");\n}\n","export const USER_ROLES = {\n ADMIN: \"admin\",\n MEMBER: \"member\",\n} as const;\n\nexport type UserRole = (typeof USER_ROLES)[keyof typeof USER_ROLES];\nexport const ALL_USER_ROLES = Object.values(USER_ROLES);\n\n/** The sign-up gate: only this email domain can create an account. */\nexport const ALLOWED_EMAIL_DOMAIN = \"@impulselab.ai\";\n\n/**\n * Public API scopes, in `resource:action` form. A Better Auth API key stores\n * them as its `permissions` map; a human session (browser cookie or a CLI\n * device-flow bearer token) implicitly holds every scope and is governed by\n * the user's role instead.\n *\n * Deliberately absent: `approvals:decide` and anything under `keys`. Guardrail\n * decisions (VISION \"never without explicit human validation\") and credential\n * issuance are human-only actions — no key can ever be granted them, so a\n * leaked key can neither approve a merge nor mint another key.\n */\nexport const API_SCOPES = [\n \"sessions:read\",\n \"sessions:write\",\n \"questions:read\",\n \"questions:answer\",\n \"approvals:read\",\n \"catalog:read\",\n \"pull_requests:read\",\n] as const;\n\nexport type ApiScope = (typeof API_SCOPES)[number];\n\n/** What a key gets when created without an explicit scope list: read-only. */\nexport const DEFAULT_API_SCOPES: readonly ApiScope[] = API_SCOPES.filter(\n (scope) => scope.endsWith(\":read\"),\n);\n\n/** Prefix stamped on every issued key, so leaks are greppable. */\nexport const API_KEY_PREFIX = \"hepha_\";\n\n/** Header carrying an API key. Honoured on `/api/v1` only — see\n * utils/strip-api-key-header.ts for why. */\nexport const API_KEY_HEADER = \"x-api-key\";\n\n/**\n * OAuth 2.0 device authorization grant (RFC 8628) — how the CLI logs a human\n * in without ever handling their password: it asks for a user code, the human\n * approves it on {BASE_URL}{VERIFICATION_PATH} in an already-signed-in\n * browser, and the CLI exchanges the device code for a session token.\n */\nexport const DEVICE_AUTHORIZATION = {\n /** Only these clients may open a device flow. */\n CLIENT_IDS: [\"hepha-cli\"],\n /** Lifetime of an unapproved user code. */\n EXPIRES_IN: \"15m\",\n /** Minimum delay the CLI must wait between two token polls. */\n INTERVAL: \"5s\",\n /** Page a human visits to approve a pending device. */\n VERIFICATION_PATH: \"/device\",\n} as const;\n","import { spawn } from \"node:child_process\";\n\n/**\n * Best effort: on a headless box or over SSH there is no browser to open, so a\n * failure here is not an error — the URL is always printed as well.\n */\nexport function openBrowser(url: string): void {\n const command =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"cmd\"\n : \"xdg-open\";\n const commandArgs =\n process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n\n try {\n const child = spawn(command, commandArgs, {\n stdio: \"ignore\",\n detached: true,\n });\n // A missing `xdg-open` (minimal containers, most SSH hosts) surfaces as an\n // ASYNCHRONOUS 'error' event that the try/catch cannot see. Unhandled, it\n // is an uncaught exception that kills the process mid-login — so the CLI\n // would stop polling instead of falling back to the printed URL.\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // Printing the URL is the fallback, and it already happened.\n }\n}\n","import type { ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { out } from \"../lib/output\";\n\n/** Forgets the local session only; issued API keys keep working. */\nexport function logoutCommand(parsed: ParsedArgs): void {\n config.clear();\n\n if (parsed.booleans.has(\"json\")) {\n out.json({ signedOut: true });\n return;\n }\n\n out.line(\"Signed out.\");\n}\n","import { api } from \"../lib/api\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { out } from \"../lib/output\";\n\ntype Batch = ApiOutputs[\"questions\"][\"get\"];\ntype Answers = ApiInputs[\"questions\"][\"submit\"][\"answers\"];\n\nfunction printBatch(batch: Batch): void {\n // Questions are agent-authored text — sanitise before printing (out.safe).\n out.line(\n `${out.paint(out.cell(batch.sessionTitle), \"bold\")} ${out.paint(`round ${batch.round}`, \"dim\")}`,\n );\n out.line(\n out.paint(\n `batch ${out.cell(batch.id)} · session ${out.cell(batch.sessionId)}`,\n \"dim\",\n ),\n );\n\n for (const question of batch.questions) {\n out.line();\n if (question.header) {\n out.line(out.paint(out.cell(question.header), \"dim\"));\n }\n out.line(\n `${out.paint(out.cell(question.id), \"dim\")} ${out.safe(question.body)}`,\n );\n if (question.image) {\n out.line(out.paint(` (image) ${out.cell(question.image)}`, \"dim\"));\n }\n for (const option of question.options) {\n const recommended = option.id === question.recommendedOptionId;\n // An option can be an image with no label — printing just a number\n // would leave the reader unable to tell what choosing it means.\n const label = option.label\n ? out.cell(option.label)\n : option.image\n ? out.paint(`(image) ${out.cell(option.image)}`, \"dim\")\n : out.paint(\"(no label)\", \"dim\");\n out.line(\n ` ${out.cell(option.id)}) ${label}${recommended ? out.paint(\" ← recommended\", \"green\") : \"\"}`,\n );\n }\n if (question.allowFreeText) {\n out.line(out.paint(\" free text accepted\", \"dim\"));\n }\n }\n}\n\n/** `--option <questionId>=1,2` and `--text <questionId>=…`, or `--answers <json>`. */\nfunction collectAnswers(parsed: ParsedArgs): Answers {\n if (parsed.flags.answers) {\n try {\n return JSON.parse(parsed.flags.answers) as Answers;\n } catch {\n throw new CliError(\"--answers expects a JSON array.\", 2);\n }\n }\n\n const byQuestion = new Map<string, Answers[number]>();\n\n const put = (pair: string, apply: (entry: Answers[number]) => void) => {\n const equalsAt = pair.indexOf(\"=\");\n if (equalsAt < 0) {\n throw new CliError(`Expected <questionId>=<value>, got \"${pair}\".`, 2);\n }\n const questionId = pair.slice(0, equalsAt);\n const entry = byQuestion.get(questionId) ?? { questionId };\n apply(entry);\n byQuestion.set(questionId, entry);\n };\n\n for (const pair of parsed.repeated.option ?? []) {\n put(pair, (entry) => {\n entry.selectedOptionIds = pair\n .slice(pair.indexOf(\"=\") + 1)\n .split(\",\")\n .map((id) => id.trim())\n .filter(Boolean);\n });\n }\n\n for (const pair of parsed.repeated.text ?? []) {\n put(pair, (entry) => {\n entry.freeText = pair.slice(pair.indexOf(\"=\") + 1);\n });\n }\n\n const answers = [...byQuestion.values()];\n if (answers.length === 0) {\n throw new CliError(\n \"Nothing to submit. Use --option <questionId>=<ids>, --text <questionId>=<answer>, or --answers <json>.\",\n 2,\n );\n }\n return answers;\n}\n\n/**\n * A session with an unanswered round parks forever. Answering is a normal\n * scope, so an agent can do it; only guardrail decisions need a human.\n */\nexport async function questionsCommand(parsed: ParsedArgs): Promise<void> {\n const action = parsed.positional[0] ?? \"list\";\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n const path = parsed.flags.session\n ? `/sessions/${parsed.flags.session}/questions`\n : \"/questions\";\n const result = await api<ApiOutputs[\"questions\"][\"list\"]>(path);\n\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.items.length === 0) {\n out.line(\"Nothing waiting on you.\");\n return;\n }\n out.table(\n result.items.map((batch) => [\n out.cell(batch.id),\n out.cell(batch.sessionId),\n `${batch.questions.length} question(s)`,\n out.cell(batch.sessionTitle),\n ]),\n );\n return;\n }\n\n const batchId = args.required(parsed, 1, \"batchId\");\n\n if (action === \"show\") {\n const batch = await api<Batch>(`/questions/${batchId}`);\n if (asJson) {\n out.json(batch);\n return;\n }\n printBatch(batch);\n return;\n }\n\n if (action === \"answer\") {\n const result = await api<ApiOutputs[\"questions\"][\"submit\"]>(\n `/questions/${batchId}/submit`,\n { method: \"POST\", body: { answers: collectAnswers(parsed) } },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n `${out.paint(\"✓\", \"green\")} Answered ${result.answeredCount} question(s); the session resumes.`,\n );\n return;\n }\n\n if (action === \"cancel\") {\n const result = await api<ApiOutputs[\"questions\"][\"cancel\"]>(\n `/questions/${batchId}/cancel`,\n { method: \"POST\", body: {} },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n 'Round cancelled. The session stays parked — send a message to steer it: `hepha sessions send <id> \"…\"`',\n );\n return;\n }\n\n throw new CliError(`Unknown questions command \"${action}\".`, 2);\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { out } from \"./output\";\n\ntype TranscriptEvent = ApiOutputs[\"sessions\"][\"events\"][\"items\"][number];\n\n/** Sanitised first: transcript text is model, tool and repository output. */\nfunction truncate(text: string, max = 2000): string {\n const trimmed = out.safe(text).trim();\n return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;\n}\n\n/**\n * One transcript event as one readable block.\n *\n * The transcript is the only honest account of what the agent did, so the\n * shapes that matter to a reviewer — tool calls, file changes, questions,\n * guardrails, errors — each keep a distinct marker instead of collapsing into\n * prose.\n */\nexport function formatEvent(event: TranscriptEvent): string | null {\n const part = event.part;\n\n switch (part.kind) {\n case \"text\":\n if (part.authorUserId) {\n return `${out.paint(\"you\", \"magenta\")} ${truncate(part.text)}`;\n }\n // Text with no author but a source was injected by the platform (an\n // integration trigger, an inbox event): the transcript contract says it\n // must never be attributed to the model.\n if (part.source) {\n return out.paint(`system ${truncate(part.text, 400)}`, \"dim\");\n }\n return `${out.paint(\"agent\", \"blue\")} ${truncate(part.text)}`;\n case \"reasoning\":\n return out.paint(`think ${truncate(part.text, 400)}`, \"dim\");\n case \"tool\":\n return `${out.paint(\"tool\", \"dim\")} ${out.cell(part.toolName)} ${out.paint(`(${part.status})`, \"dim\")}`;\n case \"file_change\":\n return `${out.paint(\"file\", \"dim\")} ${part.changeType.padEnd(8)} ${out.cell(part.path)}`;\n case \"question\":\n return out.paint(\n `ask question round ${part.questionBatchId} — answer with \\`hepha questions answer ${part.questionBatchId}\\``,\n \"yellow\",\n );\n case \"approval\":\n return out.paint(\n `gate guardrail ${part.guardrailRequestId} needs a human — \\`hepha approvals show ${part.guardrailRequestId}\\``,\n \"yellow\",\n );\n case \"media\": {\n // The signed URL is why this part exists: a screenshot or a recording is\n // the session's proof, and a reader who cannot open it has nothing.\n const target = part.url ?? part.pathname;\n return `${out.paint(\"media\", \"dim\")} ${part.mediaType}${part.caption ? ` — ${out.cell(part.caption)}` : \"\"}${target ? `\\n ${out.cell(target)}` : \"\"}`;\n }\n case \"error\":\n return out.paint(`error ${truncate(part.message)}`, \"red\");\n case \"external_event\":\n return `${out.paint(\"event\", \"dim\")} ${out.cell(part.title)}${part.conclusion ? ` — ${out.cell(part.conclusion)}` : \"\"}`;\n case \"system\":\n return out.paint(`system ${truncate(part.text, 300)}`, \"dim\");\n default:\n return null;\n }\n}\n","import { api } from \"./api\";\nimport type { ApiOutputs } from \"./api-types\";\nimport { formatEvent } from \"./format-event\";\nimport { out } from \"./output\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\nconst TERMINAL = new Set([\"completed\", \"failed\", \"killed\", \"abstained\"]);\nconst BLOCKED = new Set([\"waiting_human\", \"awaiting_approval\"]);\nconst POLL_SECONDS = 3;\n\nfunction sleep(seconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, seconds * 1000));\n}\n\n/**\n * Follow a session until it finishes or needs a person.\n *\n * Stopping on `waiting_human` / `awaiting_approval` is the important part: the\n * agent parks there and burns nothing, so a follower that kept waiting would\n * hang forever. The caller turns that into a distinct exit code, which is what\n * lets an orchestrating agent branch on \"it asked me something\".\n */\nexport async function followSession(\n sessionId: string,\n options: { quiet?: boolean; after?: number } = {},\n): Promise<SessionDetail> {\n // Resuming a follow starts where the caller left off, so `--after` does not\n // replay (and reprint) the whole transcript.\n let cursor = options.after ?? 0;\n\n for (;;) {\n const page = await api<ApiOutputs[\"sessions\"][\"events\"]>(\n `/sessions/${sessionId}/events`,\n { query: { after: cursor || undefined, limit: 200 } },\n );\n\n for (const event of page.items) {\n cursor = Math.max(cursor, event.sequence);\n if (options.quiet) {\n continue;\n }\n const line = formatEvent(event);\n if (line) {\n out.line(line);\n }\n }\n\n // Advance on the SERVER's cursor, not on what we could render. The API\n // paginates raw rows and drops the ones with no transcript representation,\n // so a page can come back empty with hasMore true — following the items\n // alone would re-request the same page forever, without even sleeping.\n if (page.nextCursor !== null) {\n cursor = Math.max(cursor, page.nextCursor);\n }\n\n if (page.hasMore) {\n continue;\n }\n\n const session = await api<SessionDetail>(`/sessions/${sessionId}`);\n if (TERMINAL.has(session.status) || BLOCKED.has(session.status)) {\n return session;\n }\n\n await sleep(POLL_SECONDS);\n }\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { out } from \"./output\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\n/** The single-session view shared by `get`, `run` and every control command. */\nexport function printSession(session: SessionDetail): void {\n // Titles, reasons, URLs and step names are agent-authored: sanitise before\n // they reach a terminal (see out.safe).\n out.line(\n `${out.paint(out.cell(session.title), \"bold\")} ${out.status(session.status)}`,\n );\n\n const rows: string[][] = [[\"id\", out.cell(session.id)]];\n if (session.statusReason) {\n rows.push([\"reason\", out.cell(session.statusReason)]);\n }\n if (session.repoFullName) {\n const branch = session.repos.find(\n (repo) => repo.repoFullName === session.repoFullName,\n )?.branch;\n rows.push([\n \"repo\",\n out.cell(session.repoFullName + (branch ? ` @ ${branch}` : \"\")),\n ]);\n }\n rows.push([\"task\", session.taskType]);\n if (session.model) {\n rows.push([\"model\", out.cell(session.model)]);\n }\n if (session.prUrl) {\n rows.push([\n \"pr\",\n out.cell(\n `${session.prUrl}${session.prState ? ` (${session.prState})` : \"\"}`,\n ),\n ]);\n }\n for (const deliverable of session.deliverables) {\n if (deliverable.url && deliverable.url !== session.prUrl) {\n rows.push([out.cell(deliverable.type), out.cell(deliverable.url)]);\n }\n }\n\n out.table(rows.map(([label, value]) => [out.paint(label!, \"dim\"), value!]));\n\n const steps = session.playbook?.steps ?? [];\n if (steps.length > 0) {\n out.line();\n for (const step of steps) {\n const done = step.todos.filter(\n (todo) => todo.status === \"completed\",\n ).length;\n const marker =\n done === step.todos.length && step.todos.length > 0 ? \"✓\" : \"·\";\n out.line(\n ` ${marker} ${out.cell(step.title)} ${out.paint(`${done}/${step.todos.length}`, \"dim\")}`,\n );\n }\n }\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { CliError } from \"./errors\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\n/**\n * What a followed session means for the caller's exit code.\n *\n * `followSession` returns on two very different conditions — the work is over,\n * or it needs a person — and both `run --follow` and `sessions logs --follow`\n * have to tell them apart the same way. Returns null when the session\n * completed (exit 0), a CliError carrying 3 when a human is needed, and 1 for\n * a real failure.\n */\nexport function sessionOutcome(session: SessionDetail): CliError | null {\n switch (session.status) {\n case \"completed\":\n return null;\n case \"waiting_human\":\n return new CliError(\n `Waiting on an answer — \\`hepha questions list --session ${session.id}\\``,\n 3,\n );\n case \"awaiting_approval\":\n return new CliError(\n \"Waiting on a guardrail approval — `hepha approvals list`\",\n 3,\n );\n default:\n return new CliError(\n `Session ended ${session.status}${session.statusReason ? `: ${session.statusReason}` : \".\"}`,\n );\n }\n}\n","import { api } from \"../lib/api\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { followSession } from \"../lib/follow\";\nimport { out } from \"../lib/output\";\nimport { printSession } from \"../lib/print-session\";\nimport { sessionOutcome } from \"../lib/session-outcome\";\n\ntype CreateInput = ApiInputs[\"sessions\"][\"create\"];\n\n/**\n * Exit code carries the outcome — 0 done, 3 waiting on a human, 1 failed — so\n * a caller can drive the loop without parsing text.\n */\nexport async function runCommand(parsed: ParsedArgs): Promise<void> {\n const prompt = args.required(parsed, 0, \"prompt\");\n const asJson = parsed.booleans.has(\"json\");\n\n const body: CreateInput = {\n prompt,\n ...(parsed.flags.title ? { title: parsed.flags.title } : {}),\n ...(parsed.flags[\"task-type\"]\n ? { taskType: parsed.flags[\"task-type\"] as CreateInput[\"taskType\"] }\n : {}),\n ...(parsed.flags.model ? { modelSelection: parsed.flags.model } : {}),\n ...(parsed.flags.harness\n ? { harnessPin: parsed.flags.harness as CreateInput[\"harnessPin\"] }\n : {}),\n ...(parsed.flags.repo ? { repoFullName: parsed.flags.repo } : {}),\n ...(parsed.flags.branch ? { branch: parsed.flags.branch } : {}),\n ...(parsed.repeated.skill ? { pinnedSkillIds: parsed.repeated.skill } : {}),\n };\n\n const session = await api<ApiOutputs[\"sessions\"][\"create\"]>(\"/sessions\", {\n method: \"POST\",\n body,\n });\n\n if (!parsed.booleans.has(\"follow\")) {\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n out.line();\n out.line(out.paint(` hepha sessions logs ${session.id} --follow`, \"dim\"));\n return;\n }\n\n if (!asJson) {\n out.line(out.paint(`session ${session.id}`, \"dim\"));\n out.line();\n }\n\n const final = await followSession(session.id, { quiet: asJson });\n\n if (asJson) {\n out.json(final);\n } else {\n out.line();\n printSession(final);\n }\n\n const outcome = sessionOutcome(final);\n if (outcome) {\n throw outcome;\n }\n}\n","import { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { followSession } from \"../lib/follow\";\nimport { formatEvent } from \"../lib/format-event\";\nimport { out } from \"../lib/output\";\nimport { printSession } from \"../lib/print-session\";\nimport { sessionOutcome } from \"../lib/session-outcome\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\nconst CONTROL_PATHS: Record<string, string> = {\n pause: \"pause\",\n resume: \"resume\",\n kill: \"kill\",\n archive: \"archive\",\n};\n\nasync function listSessions(parsed: ParsedArgs): Promise<void> {\n const result = await api<ApiOutputs[\"sessions\"][\"list\"]>(\"/sessions\", {\n query: {\n statusGroup: parsed.flags.status,\n repoFullName: parsed.flags.repo,\n search: parsed.flags.search,\n page: args.number(parsed, \"page\"),\n limit: args.number(parsed, \"limit\") ?? 20,\n scope: parsed.booleans.has(\"all\") ? \"all\" : undefined,\n },\n });\n\n if (parsed.booleans.has(\"json\")) {\n out.json(result);\n return;\n }\n\n if (result.data.length === 0) {\n out.line(\"No sessions.\");\n return;\n }\n\n if (result.pagination.hasNextPage) {\n out.line(\n out.paint(\n `page ${result.pagination.page}/${result.pagination.totalPages} — --page ${result.pagination.page + 1} for more`,\n \"dim\",\n ),\n );\n out.line();\n }\n\n out.table(\n result.data.map((session) => [\n out.cell(session.id),\n out.status(session.status),\n out.cell(session.repoFullName ?? \"—\"),\n out.cell(session.title),\n ]),\n );\n}\n\nasync function showLogs(parsed: ParsedArgs): Promise<void> {\n const sessionId = args.required(parsed, 1, \"sessionId\");\n const asJson = parsed.booleans.has(\"json\");\n const after = args.number(parsed, \"after\");\n\n if (parsed.booleans.has(\"follow\")) {\n // --json stays a single parseable value even here: the transcript is\n // suppressed and only the final session is written to stdout.\n const session = await followSession(sessionId, {\n quiet: asJson,\n ...(after !== undefined ? { after } : {}),\n });\n if (asJson) {\n out.json(session);\n } else {\n out.line();\n printSession(session);\n }\n // Only a blocked or failed session is an error; a completed one returns 0.\n const outcome = sessionOutcome(session);\n if (outcome) {\n throw outcome;\n }\n return;\n }\n\n const page = await api<ApiOutputs[\"sessions\"][\"events\"]>(\n `/sessions/${sessionId}/events`,\n {\n query: {\n after,\n limit: args.number(parsed, \"limit\") ?? 100,\n },\n },\n );\n\n if (asJson) {\n out.json(page);\n return;\n }\n\n for (const event of page.items) {\n const line = formatEvent(event);\n if (line) {\n out.line(line);\n }\n }\n\n // Never let a truncated transcript look complete. Formatted events do not\n // carry their sequence, so the continuation cursor has to be spelled out.\n if (page.hasMore && page.nextCursor !== null) {\n out.line();\n out.line(\n out.paint(\n `more events — hepha sessions logs ${sessionId} --after ${page.nextCursor}`,\n \"dim\",\n ),\n );\n }\n}\n\nexport async function sessionsCommand(parsed: ParsedArgs): Promise<void> {\n const action = parsed.positional[0] ?? \"list\";\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n return await listSessions(parsed);\n }\n\n if (action === \"logs\") {\n return await showLogs(parsed);\n }\n\n const sessionId = args.required(parsed, 1, \"sessionId\");\n\n if (action === \"get\") {\n const session = await api<SessionDetail>(`/sessions/${sessionId}`);\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n return;\n }\n\n if (action === \"send\") {\n const message = args.required(parsed, 2, \"message\");\n const result = await api<ApiOutputs[\"sessions\"][\"sendMessage\"]>(\n `/sessions/${sessionId}/messages`,\n { method: \"POST\", body: { message } },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n result.delivery === \"interrupt\"\n ? \"Delivered to the running agent.\"\n : \"Queued — the agent picks it up at the end of its turn.\",\n );\n return;\n }\n\n // hasOwn, not `in`: `in` also matches inherited keys, so `hepha sessions\n // toString <id>` would route as a control command with a garbage path\n // instead of reaching the unknown-command error.\n if (Object.hasOwn(CONTROL_PATHS, action)) {\n const session = await api<SessionDetail>(\n `/sessions/${sessionId}/${CONTROL_PATHS[action]}`,\n {\n method: \"POST\",\n body:\n action === \"kill\" && parsed.flags.reason\n ? { reason: parsed.flags.reason }\n : {},\n },\n );\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n return;\n }\n\n if (action === \"checks\") {\n const result = await api<ApiOutputs[\"sessions\"][\"runChecks\"]>(\n `/sessions/${sessionId}/checks`,\n { method: \"POST\", body: {} },\n );\n out.json(result);\n return;\n }\n\n if (action === \"pr\") {\n out.json(\n await api<ApiOutputs[\"sessions\"][\"prChecks\"]>(\n `/sessions/${sessionId}/pr-checks`,\n ),\n );\n return;\n }\n\n if (action === \"verify\") {\n out.json(\n await api<ApiOutputs[\"sessions\"][\"verification\"]>(\n `/sessions/${sessionId}/verification`,\n ),\n );\n return;\n }\n\n throw new CliError(`Unknown sessions command \"${action}\".`, 2);\n}\n","import { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport type { ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { out } from \"../lib/output\";\n\nexport async function whoamiCommand(parsed: ParsedArgs): Promise<void> {\n const identity = await api<ApiOutputs[\"me\"][\"get\"]>(\"/me\");\n\n if (parsed.booleans.has(\"json\")) {\n out.json(identity);\n return;\n }\n\n out.table([\n [\n out.paint(\"user\", \"dim\"),\n out.cell(`${identity.user.name} <${identity.user.email}>`),\n ],\n [out.paint(\"role\", \"dim\"), out.cell(identity.user.role ?? \"member\")],\n [\n out.paint(\"auth\", \"dim\"),\n out.cell(\n identity.auth.method === \"api_key\"\n ? `api key${identity.auth.keyName ? ` \"${identity.auth.keyName}\"` : \"\"}`\n : \"session\",\n ),\n ],\n [out.paint(\"scopes\", \"dim\"), identity.auth.scopes.join(\" \")],\n [out.paint(\"url\", \"dim\"), config.load().baseUrl],\n ]);\n}\n","import { approvalsCommand } from \"./commands/approvals\";\nimport { catalogCommand } from \"./commands/catalog\";\nimport { helpCommand } from \"./commands/help\";\nimport { keysCommand } from \"./commands/keys\";\nimport { loginCommand } from \"./commands/login\";\nimport { logoutCommand } from \"./commands/logout\";\nimport { questionsCommand } from \"./commands/questions\";\nimport { runCommand } from \"./commands/run\";\nimport { sessionsCommand } from \"./commands/sessions\";\nimport { whoamiCommand } from \"./commands/whoami\";\nimport { args } from \"./lib/args\";\nimport { CliError } from \"./lib/errors\";\nimport { out } from \"./lib/output\";\n\nconst CATALOG_TOPICS = new Set([\"repos\", \"branches\", \"models\", \"skills\"]);\n\nasync function dispatch(command: string, argv: string[]): Promise<void> {\n const parsed = args.parse(argv);\n\n if (parsed.booleans.has(\"help\")) {\n helpCommand();\n return;\n }\n\n if (CATALOG_TOPICS.has(command)) {\n return await catalogCommand(command, parsed);\n }\n\n switch (command) {\n case \"login\":\n return await loginCommand(parsed);\n case \"logout\":\n return logoutCommand(parsed);\n case \"whoami\":\n return await whoamiCommand(parsed);\n case \"keys\":\n return await keysCommand(parsed);\n case \"run\":\n return await runCommand(parsed);\n case \"sessions\":\n return await sessionsCommand(parsed);\n case \"questions\":\n return await questionsCommand(parsed);\n case \"approvals\":\n return await approvalsCommand(parsed);\n default:\n helpCommand();\n throw new CliError(`Unknown command \"${command}\".`, 2);\n }\n}\n\nasync function main(): Promise<void> {\n const [command, ...argv] = process.argv.slice(2);\n\n if (!command || command === \"help\" || command === \"--help\") {\n helpCommand();\n return;\n }\n\n await dispatch(command, argv);\n}\n\nmain().catch((error: unknown) => {\n if (error instanceof CliError) {\n out.error(error.message);\n process.exit(error.exitCode);\n }\n out.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n});\n"],"mappings":"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","names":["sleep"]}
1
+ {"version":3,"sources":["../src/lib/config.ts","../src/lib/errors.ts","../src/lib/is-http-url.ts","../src/lib/output.ts","../src/lib/api.ts","../src/lib/api-path.ts","../src/lib/args.ts","../src/lib/version.ts","../src/lib/expect-shape.ts","../src/lib/is.ts","../src/commands/approvals.ts","../src/commands/catalog.ts","../src/commands/help.ts","../src/commands/keys.ts","../src/commands/login.ts","../../../packages/database/constants.ts","../src/lib/device-token-error.ts","../src/commands/login-backoff.ts","../src/lib/open-browser.ts","../src/commands/logout.ts","../src/commands/collect-answers.ts","../src/commands/questions.ts","../src/lib/format-event.ts","../src/lib/follow.ts","../src/lib/print-session.ts","../src/lib/session-outcome.ts","../src/commands/run.ts","../src/commands/sessions.ts","../src/commands/whoami.ts","../src/lib/wants-json.ts","../src/index.ts"],"sourcesContent":["import {\n chmodSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { CliError } from \"./errors\";\nimport { isHttpUrl } from \"./is-http-url\";\n\nexport interface CliConfig {\n /** Platform base URL, e.g. https://hephaistos.impulselab.ai. */\n baseUrl: string;\n /** Session token from the device flow. Absent until `hepha login`. */\n token?: string;\n user?: { id: string; name: string; email: string };\n}\n\nconst CONFIG_PATH = join(homedir(), \".hepha\", \"config.json\");\n\n/**\n * Production, because this binary is installed globally: a localhost default\n * would make the documented bare `hepha login` fail on every machine that is\n * not a Hephaistos dev box. Point elsewhere with HEPHA_URL, or once with\n * `hepha login --url http://localhost:3000`, which stores it.\n */\nconst DEFAULT_BASE_URL = \"https://hephaistos.impulselab.ai\";\n\nfunction readFileAsObject(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(readFileSync(CONFIG_PATH, \"utf8\"));\n // Valid JSON is not necessarily an object: a file holding `null` or a\n // bare string parses fine and then throws on the first property read,\n // taking down every command. Fall back to defaults instead.\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return parsed as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\n/** A hand-edited file can hold anything; only usable strings get through. */\nfunction readString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction readUser(value: unknown): CliConfig[\"user\"] {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n const candidate = value as Record<string, unknown>;\n const user = {\n id: readString(candidate.id),\n name: readString(candidate.name),\n email: readString(candidate.email),\n };\n\n return user.id && user.name && user.email\n ? { id: user.id, name: user.name, email: user.email }\n : undefined;\n}\n\n/** A usable base URL, or nothing — \"not a url\" would otherwise reach\n * `new URL()` in api.ts and break every command. */\nfunction readHttpUrl(value: unknown): string | undefined {\n const raw = readString(value);\n return raw && isHttpUrl(raw) ? raw : undefined;\n}\n\n/** Same deployment? Compared on origin, so a trailing slash does not matter. */\nfunction isSameOrigin(a: string, b: string): boolean {\n try {\n return new URL(a).origin === new URL(b).origin;\n } catch {\n return false;\n }\n}\n\n/**\n * `~/.hepha/config.json` — where a device-flow session lives between runs.\n *\n * Written 0600, because it holds a token that acts as the human. Agents are\n * expected to use HEPHA_API_KEY instead and never touch this file.\n */\nexport const config = {\n path: CONFIG_PATH,\n\n load(): CliConfig {\n const stored = readFileAsObject();\n const storedBaseUrl = readHttpUrl(stored.baseUrl);\n\n // A malformed HEPHA_URL is refused rather than ignored. Falling back would\n // run the command against production — with the production token, since\n // the origin would then match — which is the exact accident the\n // origin-binding below exists to prevent. A malformed value in the config\n // FILE still falls back: the user did not ask for it this run, and\n // bricking every command over a stale file helps nobody.\n const override = readString(process.env.HEPHA_URL);\n if (override && !readHttpUrl(override)) {\n throw new CliError(\n `HEPHA_URL is not a valid http(s) URL: \"${override}\".`,\n 2,\n );\n }\n\n const baseUrl = readHttpUrl(override) ?? storedBaseUrl ?? DEFAULT_BASE_URL;\n\n // The stored token is bound to the deployment it was issued by. Pointing\n // HEPHA_URL at staging or somebody else's instance must not send a human\n // bearer token for production to that origin — it would not authenticate\n // there, and it would hand the credential to whoever runs it.\n const token =\n storedBaseUrl && isSameOrigin(storedBaseUrl, baseUrl)\n ? readString(stored.token)\n : undefined;\n const user = token ? readUser(stored.user) : undefined;\n\n return {\n baseUrl,\n ...(token ? { token } : {}),\n ...(user ? { user } : {}),\n };\n },\n\n save(next: CliConfig): void {\n mkdirSync(dirname(CONFIG_PATH), { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_PATH, `${JSON.stringify(next, null, 2)}\\n`, {\n mode: 0o600,\n });\n chmodSync(CONFIG_PATH, 0o600);\n },\n\n clear(): void {\n rmSync(CONFIG_PATH, { force: true });\n },\n};\n","/** Everything an agent needs to branch on a failure without parsing prose. */\nexport interface CliErrorDetails {\n status?: number;\n /** The API's own code, or one of CLI_ERROR_CODES. */\n code?: string;\n /** Validation paths from the API, verbatim. */\n issues?: unknown[];\n retryAfterSeconds?: number;\n}\n\n/** Codes the CLI raises on its own, before or instead of a request. */\nexport const CLI_ERROR_CODES = {\n BAD_USAGE: \"BAD_USAGE\",\n /** The session needs a person — the exit-3 family. */\n NEEDS_HUMAN: \"NEEDS_HUMAN\",\n NOT_AUTHENTICATED: \"NOT_AUTHENTICATED\",\n NETWORK: \"NETWORK\",\n TIMEOUT: \"TIMEOUT\",\n /** Ctrl-C: a cancellation, not a failure of ours. */\n INTERRUPTED: \"INTERRUPTED\",\n /** A 2xx whose shape this CLI version does not understand. */\n API_SCHEMA_MISMATCH: \"API_SCHEMA_MISMATCH\",\n /** Not JSON at all — wrong host, proxy, error page. */\n NON_JSON_RESPONSE: \"NON_JSON_RESPONSE\",\n ERROR: \"ERROR\",\n} as const;\n\n/**\n * A failure the user should read as a message, not a stack trace.\n *\n * `exitCode` is part of the contract for scripts and agents: 1 for a plain\n * failure, 2 for bad usage, 3 for \"the session needs a human\" — so a caller\n * can branch on it without parsing text. `details` carries the same failure in\n * machine form; under `--json` it is what gets printed (see output.ts).\n */\nexport class CliError extends Error {\n readonly exitCode: number;\n readonly details: CliErrorDetails;\n /**\n * A followed session parking on a question is a non-zero outcome AND a result\n * worth reading. Carried here so stdout stays ONE JSON document.\n */\n readonly result?: unknown;\n\n constructor(\n message: string,\n exitCode = 1,\n details: CliErrorDetails = {},\n result?: unknown,\n ) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n this.details = details;\n if (result !== undefined) {\n this.result = result;\n }\n }\n\n /** The code to report, defaulting to whatever the exit code implies. */\n get code(): string {\n if (this.details.code) {\n return this.details.code;\n }\n if (this.exitCode === 2) {\n return CLI_ERROR_CODES.BAD_USAGE;\n }\n if (this.exitCode === 3) {\n return CLI_ERROR_CODES.NEEDS_HUMAN;\n }\n return CLI_ERROR_CODES.ERROR;\n }\n}\n","export function isHttpUrl(value: string): boolean {\n try {\n const parsed = new URL(value);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n","import type { CliError } from \"./errors\";\n\nconst COLORS: Record<string, string> = {\n reset: \"\\u001b[0m\",\n dim: \"\\u001b[2m\",\n bold: \"\\u001b[1m\",\n red: \"\\u001b[31m\",\n green: \"\\u001b[32m\",\n yellow: \"\\u001b[33m\",\n blue: \"\\u001b[34m\",\n magenta: \"\\u001b[35m\",\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n running: \"blue\",\n provisioning: \"blue\",\n queued: \"dim\",\n created: \"dim\",\n delivering: \"blue\",\n verifying: \"blue\",\n waiting_human: \"yellow\",\n awaiting_approval: \"yellow\",\n completed: \"green\",\n failed: \"red\",\n killed: \"red\",\n abstained: \"yellow\",\n};\n\nfunction supportsColor(): boolean {\n return (\n process.stdout.isTTY === true &&\n process.env.NO_COLOR === undefined &&\n !jsonMode\n );\n}\n\n/** Held here because the failure path needs it too, and that path starts in\n * `main()`'s catch — after the command that knew about `--json` is gone. */\nlet jsonMode = false;\n\n/**\n * Two audiences, one command set: humans read the aligned text, agents pass\n * `--json` and parse stdout. Everything a command prints goes through here, so\n * `--json` is never partially honoured.\n */\nexport const out = {\n /** Declared once per run, before anything can fail. */\n setJson(enabled: boolean): void {\n jsonMode = enabled;\n },\n\n isJson(): boolean {\n return jsonMode;\n },\n\n json(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n },\n\n line(text = \"\"): void {\n process.stdout.write(`${text}\\n`);\n },\n\n error(text: string): void {\n // Sanitised like everything else: a failure message often carries a\n // session's statusReason, which is agent- or tool-authored text — and an\n // error line is the last thing that should be able to repaint the screen.\n process.stderr.write(`${out.paint(`error: ${out.safe(text)}`, \"red\")}\\n`);\n },\n\n /**\n * The one place a failure is reported. Under `--json` stdout must be\n * parseable, and it was not: failures went to stderr as prose. Success keeps\n * its bare shape, so nothing that already parses stdout has to change.\n */\n failure(error: CliError): void {\n if (!jsonMode) {\n out.error(error.message);\n return;\n }\n\n out.json({\n ok: false,\n error: {\n ...(error.details.status === undefined\n ? {}\n : { status: error.details.status }),\n code: error.code,\n message: out.safe(error.message),\n ...(error.details.issues ? { issues: error.details.issues } : {}),\n ...(error.details.retryAfterSeconds === undefined\n ? {}\n : { retryAfterSeconds: error.details.retryAfterSeconds }),\n },\n // Inside the envelope, so stdout stays one parseable document.\n ...(error.result === undefined ? {} : { result: error.result }),\n });\n },\n\n paint(text: string, color: string): string {\n if (!supportsColor()) {\n return text;\n }\n return `${COLORS[color] ?? \"\"}${text}${COLORS.reset}`;\n },\n\n /**\n * Neutralise terminal control sequences in text the platform gives us.\n *\n * Transcript content, PR titles and question bodies carry model output, tool\n * output and repository contents — none of it trusted. Printed raw, an ESC\n * sequence could repaint or erase what the user already read, or emit an OSC\n * 8 hyperlink pointing somewhere else entirely. Newlines and tabs survive;\n * every other C0/C1 control does not. (`--json` is unaffected: JSON.stringify\n * already escapes control characters.)\n */\n safe(text: string): string {\n return text.replace(/[\\u0000-\\u0008\\u000b-\\u001f\\u007f-\\u009f]/g, \"\");\n },\n\n /** `safe`, flattened to one line — anything going into a table cell. */\n cell(text: string): string {\n return out.safe(text).replace(/\\s+/g, \" \").trim();\n },\n\n status(status: string): string {\n return out.paint(status, STATUS_COLORS[status] ?? \"reset\");\n },\n\n /** Left-aligned two-column block — the shape used by every list command. */\n table(rows: string[][]): void {\n if (rows.length === 0) {\n return;\n }\n const widths = rows[0]!.map((_, column) =>\n Math.max(...rows.map((row) => stripAnsi(row[column] ?? \"\").length)),\n );\n for (const row of rows) {\n const line = row\n .map((cell, column) => {\n const padding = widths[column]! - stripAnsi(cell).length;\n return column === row.length - 1 ? cell : cell + \" \".repeat(padding);\n })\n .join(\" \");\n out.line(line.trimEnd());\n }\n },\n};\n\n/** Width is measured on the visible text, so colour never breaks alignment. */\nfunction stripAnsi(text: string): string {\n return text.replace(/\\u001b\\[\\d+m/g, \"\");\n}\n","import { config } from \"./config\";\nimport { CLI_ERROR_CODES, CliError } from \"./errors\";\nimport { out } from \"./output\";\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n query?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n /**\n * Bypass the ambient credential resolution. `hepha login` uses this to read\n * `/me` with the token it just obtained: going through the environment there\n * would report whoever HEPHA_API_KEY belongs to, not the human who just\n * approved the device.\n */\n as?: { baseUrl: string; token: string };\n /** Override the default deadline for a call known to be slow. */\n timeoutMs?: number;\n}\n\n/** Override with HEPHA_TIMEOUT_MS for a slow link. */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nfunction resolveTimeout(override?: number): number {\n if (override !== undefined) {\n return override;\n }\n const raw = process.env.HEPHA_TIMEOUT_MS?.trim();\n if (!raw) {\n return DEFAULT_TIMEOUT_MS;\n }\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n throw new CliError(\n `HEPHA_TIMEOUT_MS expects a positive number of milliseconds, got \"${raw}\".`,\n 2,\n );\n }\n return parsed;\n}\n\nfunction authHeaders(as: RequestOptions[\"as\"]): Record<string, string> {\n if (as) {\n return { authorization: `Bearer ${as.token}` };\n }\n\n const apiKey = process.env.HEPHA_API_KEY;\n if (apiKey) {\n // An agent's key wins over any stored human session, so a CI run is never\n // silently attributed to whoever last ran `hepha login` on the machine.\n return { \"x-api-key\": apiKey };\n }\n\n const token = process.env.HEPHA_TOKEN ?? config.load().token;\n if (token) {\n return { authorization: `Bearer ${token}` };\n }\n\n throw new CliError(\n \"Not signed in. Run `hepha login`, or set HEPHA_API_KEY to act as an agent.\",\n 1,\n { code: CLI_ERROR_CODES.NOT_AUTHENTICATED },\n );\n}\n\nfunction readIssues(payload: unknown): unknown[] | undefined {\n if (!payload || typeof payload !== \"object\") {\n return undefined;\n }\n const data = (payload as { data?: unknown }).data;\n if (!data || typeof data !== \"object\") {\n return undefined;\n }\n const issues = (data as { issues?: unknown }).issues;\n return Array.isArray(issues) ? issues : undefined;\n}\n\nfunction readString(payload: unknown, key: string): string | undefined {\n if (!payload || typeof payload !== \"object\") {\n return undefined;\n }\n const value = (payload as Record<string, unknown>)[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction retryAfterSeconds(response: Response): number | undefined {\n // Better Auth answers `x-retry-after`, the public API answers the standard\n // header — read both rather than pick a side.\n const raw =\n response.headers.get(\"retry-after\") ??\n response.headers.get(\"x-retry-after\");\n if (!raw) {\n return undefined;\n }\n const seconds = Number(raw.trim());\n return Number.isFinite(seconds) && seconds >= 0 ? seconds : undefined;\n}\n\nfunction messageFrom(status: number, payload: unknown): string {\n const message = readString(payload, \"message\");\n if (message) {\n // A 403 with HEPHA_API_KEY set is almost always the precedence rule biting.\n return status === 403 && process.env.HEPHA_API_KEY\n ? `${message} (HEPHA_API_KEY is set and takes precedence over your \\`hepha login\\` session — unset it to act as yourself.)`\n : message;\n }\n if (status === 401) {\n return \"Unauthorized — your credential is missing, expired or revoked.\";\n }\n return `Request failed with status ${status}.`;\n}\n\n/** Bounded and control-character-free: an HTML error page must not be able to\n * smuggle escape sequences into a terminal through a diagnostic. */\nfunction excerpt(text: string): string {\n const flattened = out.cell(text);\n return flattened.length > 200\n ? `${flattened.slice(0, 200)}\\u2026`\n : flattened;\n}\n\n/**\n * The one place the CLI talks to the platform.\n *\n * Every command names its REST path once and gets its types from the router\n * (api-types.ts), so there is no generated client to keep in step and no\n * second copy of the API surface.\n */\nexport async function api<T>(\n requestPath: string,\n options: RequestOptions = {},\n): Promise<T> {\n const baseUrl = options.as?.baseUrl ?? config.load().baseUrl;\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/api/v1${requestPath}`);\n\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n\n // Resolved before the try: a missing credential is a usage error, not a\n // network failure, and must not be reported as one.\n const headers = {\n ...authHeaders(options.as),\n ...(options.body === undefined\n ? {}\n : { \"content-type\": \"application/json\" }),\n };\n\n const method = options.method ?? \"GET\";\n const deadline = resolveTimeout(options.timeoutMs);\n const controller = new AbortController();\n // WHY it was aborted: the deadline and Ctrl-C share a controller, and\n // reporting a cancellation as a timeout would blame the clock for a\n // deliberate act. First cause wins.\n let abortedBy: \"timeout\" | \"interrupt\" | null = null;\n const timer = setTimeout(() => {\n abortedBy ??= \"timeout\";\n controller.abort();\n }, deadline);\n const onInterrupt = () => {\n abortedBy ??= \"interrupt\";\n controller.abort();\n };\n process.once(\"SIGINT\", onInterrupt);\n\n let response: Response;\n let text: string;\n try {\n response = await fetch(url, {\n method,\n headers,\n signal: controller.signal,\n ...(options.body === undefined\n ? {}\n : { body: JSON.stringify(options.body) }),\n });\n\n // Read INSIDE the guarded section: `fetch` resolves on the headers, so a\n // body that never finishes would hang past a deadline cleared any earlier.\n text = await response.text();\n } catch (cause) {\n if (abortedBy === \"interrupt\") {\n // 130 = 128 + SIGINT, the shell's convention.\n throw new CliError(`${method} ${url.pathname} interrupted.`, 130, {\n code: CLI_ERROR_CODES.INTERRUPTED,\n });\n }\n if (abortedBy === \"timeout\") {\n throw new CliError(\n `${method} ${url.pathname} timed out after ${deadline}ms. Raise HEPHA_TIMEOUT_MS if the platform is simply slow.`,\n 1,\n { code: CLI_ERROR_CODES.TIMEOUT },\n );\n }\n throw new CliError(\n `Cannot reach ${baseUrl}. Set HEPHA_URL if the platform lives elsewhere. (${String(cause)})`,\n 1,\n { code: CLI_ERROR_CODES.NETWORK },\n );\n } finally {\n clearTimeout(timer);\n process.removeListener(\"SIGINT\", onInterrupt);\n }\n\n const retryAfter = retryAfterSeconds(response);\n\n // Proxies, CDN error pages and sign-in redirects answer HTML. The STATUS\n // leads: blaming HEPHA_URL only makes sense when the response was otherwise\n // fine, not when the upstream is dead.\n let payload: unknown = null;\n if (text) {\n try {\n payload = JSON.parse(text);\n } catch {\n const body = excerpt(text);\n const contentType = response.headers.get(\"content-type\") ?? \"unknown\";\n throw new CliError(\n response.ok\n ? `${method} ${url.pathname} answered ${response.status} with a non-JSON body (${contentType}). Is HEPHA_URL pointing at a Hephaistos deployment?${body ? ` Body: ${body}` : \"\"}`\n : `${method} ${url.pathname} failed with ${response.status} and a non-JSON body (${contentType}).${body ? ` Body: ${body}` : \"\"}`,\n 1,\n {\n status: response.status,\n code: CLI_ERROR_CODES.NON_JSON_RESPONSE,\n ...(retryAfter === undefined\n ? {}\n : { retryAfterSeconds: retryAfter }),\n },\n );\n }\n }\n\n if (!response.ok) {\n // oRPC uses `code`; the refusals raised BEFORE the router (rate limiter,\n // rejected key) use `error`. Reading only `code` reported those as ERROR.\n const code = readString(payload, \"code\") ?? readString(payload, \"error\");\n const issues = readIssues(payload);\n\n throw new CliError(\n messageFrom(response.status, payload) +\n (response.status === 429 && retryAfter !== undefined\n ? ` Retry in ${retryAfter}s.`\n : \"\"),\n 1,\n {\n status: response.status,\n ...(code ? { code } : {}),\n ...(issues ? { issues } : {}),\n ...(retryAfter === undefined ? {} : { retryAfterSeconds: retryAfter }),\n },\n );\n }\n\n return payload as T;\n}\n","/**\n * Build a REST path with every dynamic segment escaped.\n *\n * Session ids, key ids and repository names were interpolated raw, so a value\n * holding `?`, `#`, `/` or `%` silently moved the request to another route or\n * grew a query string the caller never wrote. A tagged template makes the safe\n * form the easy one, and the structural slashes stay in the literal parts.\n */\nexport function path(\n strings: TemplateStringsArray,\n ...values: string[]\n): string {\n return strings.reduce(\n (accumulator, literal, index) =>\n accumulator +\n (index === 0 ? \"\" : encodeURIComponent(values[index - 1] ?? \"\")) +\n literal,\n \"\",\n );\n}\n","import { CliError } from \"./errors\";\n\nexport interface ParsedArgs {\n /** Non-flag arguments, in order. */\n positional: string[];\n /** `--flag value`, `--flag=value` and repeated flags (last wins). */\n flags: Record<string, string>;\n /** Every value seen for a repeatable flag, in order. */\n repeated: Record<string, string[]>;\n /** `--flag` with no value. */\n booleans: Set<string>;\n}\n\n/** What one command (or one of its actions) accepts. */\nexport interface ArgsSpec {\n /** Value-taking flags, without the leading dashes. */\n flags?: readonly string[];\n /** Boolean flags beyond the global ones. */\n booleans?: readonly string[];\n /** How many positional arguments this action reads, at most. */\n positional?: number;\n}\n\n/** Recognised everywhere, so no command has to list them. */\nconst GLOBAL_BOOLEANS = [\"json\", \"help\", \"quiet\"] as const;\n\nconst BOOLEAN_FLAGS = new Set<string>([\n ...GLOBAL_BOOLEANS,\n \"follow\",\n \"all\",\n \"version\",\n]);\n\n/**\n * A deliberately small parser: no dependency, and the grammar stays something an\n * agent can generate blind — `hepha <group> <command> [args] [--flags]`. Strict\n * on purpose: `hepha keys create x --scpoe admin` used to mint a key with the\n * DEFAULT scopes and exit 0.\n */\nexport const args = {\n parse(argv: string[]): ParsedArgs {\n const parsed: ParsedArgs = {\n positional: [],\n flags: {},\n repeated: {},\n booleans: new Set(),\n };\n\n let flagsEnded = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const token = argv[index]!;\n\n // `--` ends option parsing: a prompt or a steering message is allowed to\n // start with dashes, and without this there is no way to send one.\n if (!flagsEnded && token === \"--\") {\n flagsEnded = true;\n continue;\n }\n\n if (flagsEnded || !token.startsWith(\"--\")) {\n parsed.positional.push(token);\n continue;\n }\n\n const withoutDashes = token.slice(2);\n const equalsAt = withoutDashes.indexOf(\"=\");\n\n let name: string;\n let value: string | undefined;\n\n if (equalsAt >= 0) {\n name = withoutDashes.slice(0, equalsAt);\n value = withoutDashes.slice(equalsAt + 1);\n\n // `--json=false` set the flag and then read as truthy.\n if (BOOLEAN_FLAGS.has(name)) {\n throw new CliError(\n `--${name} is a boolean flag: pass --${name} to enable it, or omit it. \"--${name}=${value}\" is not a value.`,\n 2,\n );\n }\n } else {\n name = withoutDashes;\n const next = argv[index + 1];\n if (\n !BOOLEAN_FLAGS.has(name) &&\n next !== undefined &&\n !next.startsWith(\"--\")\n ) {\n value = next;\n index += 1;\n }\n }\n\n // A value-taking flag left bare or emptied is a typo, never an intent —\n // and a dangerous one: `--url=` would talk to the wrong deployment.\n if (value === undefined || value.trim() === \"\") {\n if (!BOOLEAN_FLAGS.has(name)) {\n throw new CliError(`--${name} expects a value.`, 2);\n }\n parsed.booleans.add(name);\n continue;\n }\n\n parsed.flags[name] = value;\n (parsed.repeated[name] ??= []).push(value);\n }\n\n return parsed;\n },\n\n /**\n * Refuse anything this action does not understand. Called once the action is\n * known, because `sessions list` and `sessions logs` accept different flags.\n */\n expect(parsed: ParsedArgs, spec: ArgsSpec): void {\n const allowed = new Set<string>([\n ...GLOBAL_BOOLEANS,\n ...(spec.flags ?? []),\n ...(spec.booleans ?? []),\n ]);\n\n for (const name of [...Object.keys(parsed.flags), ...parsed.booleans]) {\n if (!allowed.has(name)) {\n throw new CliError(`Unknown flag --${name}.`, 2);\n }\n }\n\n const max = spec.positional ?? 0;\n if (parsed.positional.length > max) {\n const surplus = parsed.positional\n .slice(max)\n .map((value) => `\"${value}\"`)\n .join(\", \");\n throw new CliError(\n `Unexpected argument${parsed.positional.length - max > 1 ? \"s\" : \"\"} ${surplus}.`,\n 2,\n );\n }\n },\n\n /** The action name, validated against what the group actually implements. */\n action(\n parsed: ParsedArgs,\n group: string,\n allowed: readonly string[],\n fallback: string,\n ): string {\n const action = parsed.positional[0] ?? fallback;\n // Checked BEFORE the action's own arguments: `hepha approvals frobnicate`\n // used to ask for a <guardrailRequestId> it was never going to use.\n if (!allowed.includes(action)) {\n throw new CliError(\n `Unknown ${group} command \"${action}\". Expected one of: ${allowed.join(\", \")}.`,\n 2,\n );\n }\n return action;\n },\n\n required(parsed: ParsedArgs, index: number, name: string): string {\n const value = parsed.positional[index];\n if (!value) {\n throw new CliError(`Missing <${name}>.`, 2);\n }\n return value;\n },\n\n /**\n * A whole number inside a range, refused locally: `--page -1` used to come\n * back from the API as a bare \"Input validation failed\".\n */\n integer(\n parsed: ParsedArgs,\n name: string,\n bounds: { min?: number; max?: number } = {},\n ): number | undefined {\n const raw = parsed.flags[name];\n if (raw === undefined) {\n return undefined;\n }\n const trimmed = raw.trim();\n const value = Number(trimmed);\n // Number(\"\") is 0, so an empty `--limit=` would quietly mean zero.\n if (trimmed === \"\" || !Number.isFinite(value)) {\n throw new CliError(`--${name} expects a number, got \"${raw}\".`, 2);\n }\n if (!Number.isInteger(value)) {\n throw new CliError(`--${name} expects a whole number, got \"${raw}\".`, 2);\n }\n if (bounds.min !== undefined && value < bounds.min) {\n throw new CliError(`--${name} must be at least ${bounds.min}.`, 2);\n }\n if (bounds.max !== undefined && value > bounds.max) {\n throw new CliError(`--${name} must be at most ${bounds.max}.`, 2);\n }\n return value;\n },\n\n /** One of a fixed set, named in the error so the fix is obvious. */\n choice<T extends string>(\n parsed: ParsedArgs,\n name: string,\n allowed: readonly T[],\n ): T | undefined {\n const raw = parsed.flags[name];\n if (raw === undefined) {\n return undefined;\n }\n if (!(allowed as readonly string[]).includes(raw)) {\n throw new CliError(\n `--${name} expects one of: ${allowed.join(\", \")}. Got \"${raw}\".`,\n 2,\n );\n }\n return raw as T;\n },\n};\n","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Read at runtime, not baked in: CI stamps the real version onto package.json\n * when it publishes. Walking up covers both `dist/index.js` (installed) and\n * `src/lib/version.ts` (`pnpm dev`).\n */\nfunction readVersion(): string {\n let directory = dirname(fileURLToPath(import.meta.url));\n\n for (let depth = 0; depth < 5; depth += 1) {\n try {\n const manifest: unknown = JSON.parse(\n readFileSync(join(directory, \"package.json\"), \"utf8\"),\n );\n const version = (manifest as { version?: unknown }).version;\n if (typeof version === \"string\" && version.length > 0) {\n return version;\n }\n } catch {\n // Keep walking: not every ancestor holds a manifest.\n }\n const parent = dirname(directory);\n if (parent === directory) {\n break;\n }\n directory = parent;\n }\n\n return \"unknown\";\n}\n\nexport const VERSION = readVersion();\n","import { CLI_ERROR_CODES, CliError } from \"./errors\";\nimport { VERSION } from \"./version\";\n\ntype Predicate = (value: unknown) => boolean;\n\nfunction read(payload: unknown, dotted: string): unknown {\n return dotted.split(\".\").reduce<unknown>((current, key) => {\n if (!current || typeof current !== \"object\") {\n return undefined;\n }\n return (current as Record<string, unknown>)[key];\n }, payload);\n}\n\n/**\n * Check a 2xx payload before the command destructures it. The client casts\n * responses to the router's types — a compile-time promise about a server that\n * may be older or newer than this binary. When it did not hold, the first\n * property read threw `Cannot read properties of undefined`.\n */\nexport function expectShape<T>(\n payload: unknown,\n endpoint: string,\n requirements: Record<string, Predicate>,\n): T {\n for (const [field, predicate] of Object.entries(requirements)) {\n if (!predicate(read(payload, field))) {\n throw new CliError(\n `${endpoint} returned a payload this CLI does not understand: \"${field}\" is missing or has the wrong type. hepha ${VERSION} may be out of step with the platform — try \\`npm install -g @impulselab/hepha\\`.`,\n 1,\n { code: CLI_ERROR_CODES.API_SCHEMA_MISMATCH },\n );\n }\n }\n\n return payload as T;\n}\n","/** The handful of shapes the CLI actually destructures. */\nexport const is = {\n string: (value: unknown) => typeof value === \"string\",\n number: (value: unknown) => typeof value === \"number\",\n array: (value: unknown) => Array.isArray(value),\n object: (value: unknown) =>\n Boolean(value) && typeof value === \"object\" && !Array.isArray(value),\n};\n","import { api } from \"../lib/api\";\nimport { path } from \"../lib/api-path\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { out } from \"../lib/output\";\n\nconst ACTIONS = [\"list\", \"show\", \"approve\", \"reject\"] as const;\nconst REJECT_MODES = [\"rework\", \"terminate\"] as const;\n\n/**\n * Approving and rejecting require a human session and are refused for an API\n * key: a machine standing in for human validation would defeat the guardrail.\n */\nexport async function approvalsCommand(parsed: ParsedArgs): Promise<void> {\n const action = args.action(parsed, \"approvals\", ACTIONS, \"list\");\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n args.expect(parsed, { positional: 1 });\n const result = expectShape<ApiOutputs[\"approvals\"][\"list\"]>(\n await api(\"/approvals\"),\n \"GET /approvals\",\n { items: is.array },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.items.length === 0) {\n out.line(\"No guardrail waiting on you.\");\n return;\n }\n out.table(\n result.items.map((item) => [\n out.cell(item.id),\n out.cell(item.guardrailKind),\n out.cell(item.repoName ?? \"—\"),\n out.cell(item.summary),\n ]),\n );\n return;\n }\n\n args.expect(parsed, {\n positional: 2,\n ...(action === \"reject\" ? { flags: [\"mode\", \"feedback\"] } : {}),\n });\n const guardrailId = args.required(parsed, 1, \"guardrailRequestId\");\n\n if (action === \"show\") {\n const detail = expectShape<ApiOutputs[\"approvals\"][\"get\"]>(\n await api(path`/approvals/${guardrailId}`),\n \"GET /approvals/{id}\",\n { guardrailKind: is.string, status: is.string, summary: is.string },\n );\n if (asJson) {\n out.json(detail);\n return;\n }\n out.line(\n `${out.paint(out.cell(detail.guardrailKind), \"bold\")} ${detail.status}`,\n );\n out.line(out.safe(detail.summary));\n out.line();\n out.json(detail.payload);\n return;\n }\n\n if (action === \"approve\") {\n const result = await api<ApiOutputs[\"approvals\"][\"approve\"]>(\n path`/approvals/${guardrailId}/approve`,\n { method: \"POST\", body: {} },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(`${out.paint(\"✓\", \"green\")} Approved ${out.cell(guardrailId)}`);\n return;\n }\n\n const mode = args.choice(parsed, \"mode\", REJECT_MODES) ?? \"rework\";\n if (mode === \"rework\" && !parsed.flags.feedback) {\n throw new CliError(\n \"--feedback is required with --mode rework: the agent needs to know what to change.\",\n 2,\n );\n }\n\n const result = await api<ApiOutputs[\"approvals\"][\"reject\"]>(\n path`/approvals/${guardrailId}/reject`,\n {\n method: \"POST\",\n body: {\n mode,\n ...(parsed.flags.feedback ? { feedback: parsed.flags.feedback } : {}),\n },\n },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n `${out.paint(\"✓\", \"green\")} Rejected ${out.cell(guardrailId)} (${mode})`,\n );\n}\n","import { api } from \"../lib/api\";\nimport { path } from \"../lib/api-path\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { out } from \"../lib/output\";\n\n/**\n * Read before creating a session: a repository outside `repos` is refused at\n * creation, and a model outside `models` is not routable.\n */\nexport async function catalogCommand(\n topic: string,\n parsed: ParsedArgs,\n): Promise<void> {\n const asJson = parsed.booleans.has(\"json\");\n\n if (topic === \"repos\") {\n args.expect(parsed, {});\n const result = expectShape<ApiOutputs[\"catalog\"][\"repos\"]>(\n await api(\"/repos\"),\n \"GET /repos\",\n { repos: is.array },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n for (const repo of result.repos) {\n out.line(out.cell(repo));\n }\n return;\n }\n\n if (topic === \"branches\") {\n args.expect(parsed, { positional: 1 });\n const repoFullName = args.required(parsed, 0, \"owner/repo\");\n // Exactly two non-empty segments: \"a/b/c\" must be rejected, not silently\n // truncated to \"a/b\" and queried as a repository the caller never named.\n const segments = repoFullName.split(\"/\");\n const [owner, repo] = segments;\n if (segments.length !== 2 || !owner || !repo) {\n throw new CliError(\n `Expected a repository as \"owner/repo\", got \"${repoFullName}\".`,\n 2,\n );\n }\n\n const result = await api<ApiOutputs[\"catalog\"][\"branches\"]>(\n path`/repos/${owner}/${repo}/branches`,\n );\n\n // Checked BEFORE the output branches. `--json` used to return first, so a\n // repository no installation covers printed `{\"result\": null}` and exited\n // 0, while the same command without `--json` exited 1. Two formats, one\n // meaning: the failure is a failure either way.\n if (!result.result) {\n throw new CliError(`No GitHub installation covers ${repoFullName}.`);\n }\n\n if (asJson) {\n out.json(result);\n return;\n }\n for (const branch of result.result.branches) {\n out.line(\n branch === result.result.defaultBranch\n ? `${out.cell(branch)} ${out.paint(\"(default)\", \"dim\")}`\n : out.cell(branch),\n );\n }\n return;\n }\n\n if (topic === \"models\") {\n args.expect(parsed, {});\n const result = expectShape<ApiOutputs[\"catalog\"][\"models\"]>(\n await api(\"/models\"),\n \"GET /models\",\n { harnesses: is.array, gatewayModels: is.array },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(out.paint(\"harnesses\", \"dim\"));\n for (const harness of result.harnesses) {\n out.line(` ${out.cell(harness)}`);\n }\n out.line();\n out.line(out.paint(\"gateway models\", \"dim\"));\n for (const model of result.gatewayModels) {\n out.line(` ${out.cell(model.id)}`);\n }\n return;\n }\n\n if (topic === \"skills\") {\n args.expect(parsed, {});\n const result = expectShape<ApiOutputs[\"catalog\"][\"skills\"]>(\n await api(\"/skills\"),\n \"GET /skills\",\n { skills: is.array },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.table(\n result.skills.map((skill) => [\n out.cell(skill.id),\n out.cell(skill.name),\n out.cell(skill.description ?? \"\"),\n ]),\n );\n return;\n }\n\n throw new CliError(`Unknown catalog topic \"${topic}\".`, 2);\n}\n","import { config } from \"../lib/config\";\nimport { out } from \"../lib/output\";\nimport { VERSION } from \"../lib/version\";\n\nconst HELP = `hepha — orchestrate Hephaistos sessions from a terminal or an agent.\n\nUSAGE\n hepha <command> [args] [--flags]\n\nTHE LOOP\n hepha run \"<prompt>\" --repo owner/repo --follow\n Start a session and follow it until it finishes or asks you something.\n Exit 0 completed · 3 waiting on a human · 1 failed.\n [--title \"…\"] [--task-type implement|new-project|question|draft]\n [--model <slug>] [--harness claude-code|codex] [--branch <name>]\n [--skill <id>]…\n hepha questions list [--session <id>]\n hepha questions show <batchId>\n hepha questions answer <batchId> --option <questionId>=1,2 --text <questionId>=\"…\"\n [--answers '<json array>']\n hepha questions cancel <batchId>\n hepha approvals list | show <id> | approve <id> | reject <id> --mode rework --feedback \"…\"\n\nSESSIONS\n hepha sessions list [--status active|waiting|done] [--repo owner/repo]\n [--search \"…\"] [--page N] [--limit N] [--all]\n hepha sessions get <id>\n hepha sessions logs <id> [--after <sequence>] [--limit N] [--follow]\n hepha sessions send <id> \"<message>\"\n hepha sessions pause|resume|archive <id>\n hepha sessions kill <id> [--reason \"…\"]\n hepha sessions checks|pr|verify <id>\n\nCATALOG\n hepha repos\n hepha branches <owner/repo>\n hepha models\n hepha skills\n\nAUTH\n hepha login [--url https://…] Device authorization: approve it in a browser.\n hepha logout\n hepha whoami\n hepha keys list\n hepha keys create <name> [--scope sessions:read]… [--expires-in-days 90]\n hepha keys revoke <keyId>\n\nENVIRONMENT\n HEPHA_API_KEY Act as an agent. Takes precedence over a stored login, so\n the human-only commands (approvals approve/reject, keys)\n answer 403 while it is set — unset it to act as yourself.\n HEPHA_TOKEN A device-flow session token, instead of ~/.hepha/config.json.\n HEPHA_URL Platform base URL.\n HEPHA_TIMEOUT_MS Per-request timeout in milliseconds (default 30000).\n\nGLOBAL FLAGS\n --json Machine-readable output on stdout. Every command that\n returns data honours it; login is interactive and does not.\n Failures print {\"ok\":false,\"error\":{…}} and keep their exit code.\n --quiet Suppress the streamed transcript while following a session.\n --version Print the version and exit.\n --help Print this.\n\nUnknown flags and surplus arguments are refused: for an agent, a typo must\nfail rather than run with default options.\n\n`;\n\nexport function helpCommand(): void {\n // Resolved, not a placeholder: the reader can click straight through to the\n // Scalar reference for the platform this CLI is actually pointed at.\n const baseUrl = config.load().baseUrl.replace(/\\/$/, \"\");\n out.line(`${HELP}hepha ${VERSION} · full reference: ${baseUrl}/api/v1/docs`);\n}\n","import { api } from \"../lib/api\";\nimport { path } from \"../lib/api-path\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { out } from \"../lib/output\";\n\ntype Scope = ApiInputs[\"keys\"][\"create\"][\"scopes\"];\n\nconst ACTIONS = [\"list\", \"create\", \"revoke\"] as const;\n\n/**\n * Human sessions only, by design: a key cannot mint or revoke a key, so the\n * whole group fails with a 403 when HEPHA_API_KEY is set.\n */\nexport async function keysCommand(parsed: ParsedArgs): Promise<void> {\n const action = args.action(parsed, \"keys\", ACTIONS, \"list\");\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n args.expect(parsed, { positional: 1 });\n const result = expectShape<ApiOutputs[\"keys\"][\"list\"]>(\n await api(\"/keys\"),\n \"GET /keys\",\n { keys: is.array },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.keys.length === 0) {\n out.line(\"No keys. Create one with `hepha keys create <name>`.\");\n return;\n }\n out.table([\n [\n out.paint(\"ID\", \"dim\"),\n out.paint(\"NAME\", \"dim\"),\n out.paint(\"PREFIX\", \"dim\"),\n out.paint(\"SCOPES\", \"dim\"),\n ],\n ...result.keys.map((key) => [\n out.cell(key.id),\n out.cell(key.name ?? \"—\"),\n out.cell(key.start ?? \"—\"),\n key.scopes.join(\" \"),\n ]),\n ]);\n return;\n }\n\n if (action === \"create\") {\n args.expect(parsed, {\n flags: [\"scope\", \"expires-in-days\"],\n positional: 2,\n });\n const name = args.required(parsed, 1, \"name\");\n const scopes = parsed.repeated.scope as Scope;\n const expiresInDays = args.integer(parsed, \"expires-in-days\", {\n min: 1,\n max: 365,\n });\n\n const created = expectShape<ApiOutputs[\"keys\"][\"create\"]>(\n await api(\"/keys\", {\n method: \"POST\",\n body: {\n name,\n ...(scopes && scopes.length > 0 ? { scopes } : {}),\n ...(expiresInDays !== undefined ? { expiresInDays } : {}),\n },\n }),\n \"POST /keys\",\n { key: is.string, scopes: is.array },\n );\n\n if (asJson) {\n out.json(created);\n return;\n }\n\n out.line(\n `${out.paint(\"✓\", \"green\")} Created \"${out.cell(created.name ?? name)}\"`,\n );\n out.line();\n out.line(` ${out.paint(created.key, \"bold\")}`);\n out.line();\n out.line(\n out.paint(\n \" Copy it now — it is hashed at rest and never shown again.\",\n \"dim\",\n ),\n );\n out.line(out.paint(` Scopes: ${created.scopes.join(\" \")}`, \"dim\"));\n return;\n }\n\n args.expect(parsed, { positional: 2 });\n const keyId = args.required(parsed, 1, \"keyId\");\n const result = await api<ApiOutputs[\"keys\"][\"revoke\"]>(path`/keys/${keyId}`, {\n method: \"DELETE\",\n });\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(`${out.paint(\"✓\", \"green\")} Revoked ${out.cell(keyId)}`);\n}\n","import { createAuthClient } from \"better-auth/client\";\nimport { deviceAuthorizationClient } from \"better-auth/client/plugins\";\n\nimport { DEVICE_AUTHORIZATION } from \"@repo/database/constants\";\n\nimport { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { deviceTokenError } from \"../lib/device-token-error\";\nimport { nextPollDelay } from \"./login-backoff\";\nimport { CliError } from \"../lib/errors\";\nimport { isHttpUrl } from \"../lib/is-http-url\";\nimport { openBrowser } from \"../lib/open-browser\";\nimport { out } from \"../lib/output\";\n\nconst CLIENT_ID = DEVICE_AUTHORIZATION.CLIENT_IDS[0];\n\n/** Never poll faster than this again once the server has pushed back. */\nconst MIN_BACKOFF = 10;\n\nfunction sleep(seconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, seconds * 1000));\n}\n\n/**\n * `hepha login` — OAuth 2.0 device authorization (RFC 8628).\n *\n * The CLI never sees a password and never asks for a pasted token: it gets a\n * short code, a human approves it in a browser that is already signed in to\n * Hephaistos, and only then does a session token exist. That approval is also\n * what makes a CLI session count as \"a human\" for guardrail decisions.\n */\nexport async function loginCommand(parsed: ParsedArgs): Promise<void> {\n args.expect(parsed, { flags: [\"url\"] });\n\n // Presence, not truthiness: `--url=` trims to \"\" and would otherwise skip\n // the guard and then survive `??`, leaving an empty base URL for the device\n // request. A flag the user typed is always validated.\n const requested = parsed.flags.url?.trim();\n if (requested !== undefined && !isHttpUrl(requested)) {\n throw new CliError(`--url is not a valid http(s) URL: \"${requested}\".`, 2);\n }\n\n const baseUrl = (requested ?? config.load().baseUrl).replace(/\\/$/, \"\");\n\n const authClient = createAuthClient({\n baseURL: baseUrl,\n plugins: [deviceAuthorizationClient()],\n });\n\n const { data: device, error: deviceError } = await authClient.device.code({\n client_id: CLIENT_ID,\n scope: \"openid profile email\",\n });\n\n if (deviceError || !device) {\n throw new CliError(\n deviceError?.error_description ??\n `Could not start a device login against ${baseUrl}.`,\n );\n }\n\n const verificationUrl =\n device.verification_uri_complete ?? device.verification_uri;\n\n out.line();\n out.line(` Code ${out.paint(out.cell(device.user_code), \"bold\")}`);\n out.line(` Open ${out.cell(verificationUrl)}`);\n out.line();\n out.line(out.paint(\" Waiting for approval…\", \"dim\"));\n\n openBrowser(verificationUrl);\n\n let interval = device.interval ?? 5;\n const deadline = Date.now() + (device.expires_in ?? 900) * 1000;\n\n while (Date.now() < deadline) {\n // Never sleep past the code's own expiry (see nextPollDelay).\n const delay = nextPollDelay(interval, (deadline - Date.now()) / 1000);\n if (delay === null) {\n break;\n }\n await sleep(delay);\n\n const { data: token, error } = await authClient.device.token({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: device.device_code,\n client_id: CLIENT_ID,\n });\n\n // A 429 is transient by definition, and giving up on one abandoned a login\n // the human was about to approve — with \"Device authorization failed.\" as\n // the only clue, because the rate limiter answers a plain message and none\n // of the OAuth error codes below. Back off for as long as the server asks\n // (it answers `x-retry-after`), with a floor, and keep polling.\n if (error?.status === 429) {\n interval = Math.max(\n deviceTokenError.retryAfter(error) ?? interval * 2,\n MIN_BACKOFF,\n );\n continue;\n }\n\n if (token?.access_token) {\n // Read /me with THIS token against THIS base URL. Falling back to the\n // ambient resolution would report HEPHA_API_KEY's owner, or query the\n // HEPHA_URL host rather than the one `--url` just authenticated against.\n const identity = await api<ApiOutputs[\"me\"][\"get\"]>(\"/me\", {\n as: { baseUrl, token: token.access_token },\n });\n\n config.save({\n baseUrl,\n token: token.access_token,\n user: {\n id: identity.user.id,\n name: identity.user.name,\n email: identity.user.email,\n },\n });\n\n out.line();\n out.line(\n `${out.paint(\"✓\", \"green\")} Signed in as ${identity.user.email} on ${baseUrl}`,\n );\n out.line(out.paint(` Session stored in ${config.path}`, \"dim\"));\n return;\n }\n\n if (!error) {\n continue;\n }\n\n switch (error.error) {\n case \"authorization_pending\":\n continue;\n case \"slow_down\":\n interval += 5;\n continue;\n case \"access_denied\":\n throw new CliError(\"Access denied — the request was rejected.\");\n default:\n // The server's own message, when it has one. Collapsing everything\n // that is not an OAuth code into \"Device authorization failed.\" is how\n // a rate-limit refusal looked like a broken device flow.\n throw new CliError(\n error.error_description ||\n deviceTokenError.message(error) ||\n `Device authorization failed (HTTP ${error.status}).`,\n );\n }\n }\n\n throw new CliError(\"The code expired before it was approved. Try again.\");\n}\n","export const USER_ROLES = {\n ADMIN: \"admin\",\n MEMBER: \"member\",\n} as const;\n\nexport type UserRole = (typeof USER_ROLES)[keyof typeof USER_ROLES];\nexport const ALL_USER_ROLES = Object.values(USER_ROLES);\n\n/** The sign-up gate: only this email domain can create an account. */\nexport const ALLOWED_EMAIL_DOMAIN = \"@impulselab.ai\";\n\n/**\n * Public API scopes, in `resource:action` form. A Better Auth API key stores\n * them as its `permissions` map; a human session (browser cookie or a CLI\n * device-flow bearer token) implicitly holds every scope and is governed by\n * the user's role instead.\n *\n * Deliberately absent: `approvals:decide` and anything under `keys`. Guardrail\n * decisions (VISION \"never without explicit human validation\") and credential\n * issuance are human-only actions — no key can ever be granted them, so a\n * leaked key can neither approve a merge nor mint another key.\n */\nexport const API_SCOPES = [\n \"sessions:read\",\n \"sessions:write\",\n \"questions:read\",\n \"questions:answer\",\n \"approvals:read\",\n \"catalog:read\",\n \"pull_requests:read\",\n] as const;\n\nexport type ApiScope = (typeof API_SCOPES)[number];\n\n/** What a key gets when created without an explicit scope list: read-only. */\nexport const DEFAULT_API_SCOPES: readonly ApiScope[] = API_SCOPES.filter(\n (scope) => scope.endsWith(\":read\"),\n);\n\n/** Prefix stamped on every issued key, so leaks are greppable. */\nexport const API_KEY_PREFIX = \"hepha_\";\n\n/** Header carrying an API key. Honoured on `/api/v1` only — see\n * utils/strip-api-key-header.ts for why. */\nexport const API_KEY_HEADER = \"x-api-key\";\n\n/**\n * Browser session lifetime. Signing in is always \"remember me\": there is no\n * opt-out in the UI, so every sign-in path writes a PERSISTENT cookie that\n * survives closing the browser. `UPDATE_AGE` slides the expiry forward on use,\n * so an active human never sees the sign-in screen again.\n */\nexport const SESSION = {\n /** Cookie + session row lifetime: 30 days. */\n EXPIRES_IN: 60 * 60 * 24 * 30,\n /** Refresh the expiry at most once a day, to avoid a write per request. */\n UPDATE_AGE: 60 * 60 * 24,\n} as const;\n\n/**\n * OAuth 2.0 device authorization grant (RFC 8628) — how the CLI logs a human\n * in without ever handling their password: it asks for a user code, the human\n * approves it on {BASE_URL}{VERIFICATION_PATH} in an already-signed-in\n * browser, and the CLI exchanges the device code for a session token.\n */\nexport const DEVICE_AUTHORIZATION = {\n /** Only these clients may open a device flow. */\n CLIENT_IDS: [\"hepha-cli\"],\n /** Lifetime of an unapproved user code. */\n EXPIRES_IN: \"15m\",\n /** Minimum delay the CLI must wait between two token polls. */\n INTERVAL: \"5s\",\n /** Page a human visits to approve a pending device. */\n VERIFICATION_PATH: \"/device\",\n /**\n * Per-IP ceiling on `/device/token`. The window is deliberately SHORTER than\n * INTERVAL: Better Auth only resets its counter when two requests are further\n * apart than the window, so a 5s poll under the default 60s window never reset\n * it and every login 429'd partway through the code's lifetime.\n */\n POLL_RATE_LIMIT: { WINDOW_SECONDS: 4, MAX_REQUESTS: 10 },\n} as const;\n","/**\n * The client types this error as the OAuth code set alone, but the refusals that\n * actually broke `hepha login` carry neither — a rate limiter answers a plain\n * message and a status. Hence reading defensively off `unknown`.\n */\nexport const deviceTokenError = {\n /** What the server said, when it said anything at all. */\n message(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const message = (error as { message?: unknown }).message;\n return typeof message === \"string\" && message.length > 0\n ? message\n : undefined;\n },\n\n /** Better Auth answers `X-Retry-After`, the platform the standard header. */\n retryAfter(error: unknown): number | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const headers = (error as { headers?: unknown }).headers;\n if (!(headers instanceof Headers)) {\n return undefined;\n }\n const raw =\n headers.get(\"x-retry-after\") ?? headers.get(\"retry-after\") ?? undefined;\n if (!raw) {\n return undefined;\n }\n const seconds = Number(raw.trim());\n return Number.isFinite(seconds) && seconds > 0 ? seconds : undefined;\n },\n};\n","/**\n * How long to wait before the next poll, or null when the code has no life left.\n * The loop tests the deadline only BEFORE sleeping, so a backoff grown by\n * repeated 429s used to be slept in full — minutes past the code's expiry.\n */\nexport function nextPollDelay(\n interval: number,\n remainingSeconds: number,\n): number | null {\n if (remainingSeconds <= 0) {\n return null;\n }\n return Math.min(interval, remainingSeconds);\n}\n","import { spawn } from \"node:child_process\";\n\n/**\n * Best effort: on a headless box or over SSH there is no browser to open, so a\n * failure here is not an error — the URL is always printed as well.\n */\nexport function openBrowser(url: string): void {\n const command =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"cmd\"\n : \"xdg-open\";\n const commandArgs =\n process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n\n try {\n const child = spawn(command, commandArgs, {\n stdio: \"ignore\",\n detached: true,\n });\n // A missing `xdg-open` (minimal containers, most SSH hosts) surfaces as an\n // ASYNCHRONOUS 'error' event that the try/catch cannot see. Unhandled, it\n // is an uncaught exception that kills the process mid-login — so the CLI\n // would stop polling instead of falling back to the printed URL.\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // Printing the URL is the fallback, and it already happened.\n }\n}\n","import { args, type ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { out } from \"../lib/output\";\n\n/** Forgets the local session only; issued API keys keep working. */\nexport function logoutCommand(parsed: ParsedArgs): void {\n args.expect(parsed, {});\n\n config.clear();\n\n if (parsed.booleans.has(\"json\")) {\n out.json({ signedOut: true });\n return;\n }\n\n out.line(\"Signed out.\");\n}\n","import type { ApiInputs } from \"../lib/api-types\";\nimport type { ParsedArgs } from \"../lib/args\";\nimport { CliError } from \"../lib/errors\";\n\ntype Answers = ApiInputs[\"questions\"][\"submit\"][\"answers\"];\ntype Answer = Answers[number];\n\n/**\n * The server's own bounds (packages/server .../clarification/validators.ts).\n * Mirrored so a bad round fails against the flag the user typed instead of\n * against a path after the POST — which means the numbers AND what they measure\n * must match: `.trim()` runs before min/max, so trimmed fields are bounded on\n * their trimmed length.\n */\nconst LIMITS = {\n QUESTION_ID: 40,\n OPTION_ID: 40,\n OPTIONS_PER_ANSWER: 50,\n FREE_TEXT: 10_000,\n ANSWERS: 50,\n} as const;\n\n/** `label` names the source — `--answers[2]` or `--option q1=…` — because both\n * entry paths build the same shape and must fail identically. */\nfunction validateAnswer(answer: Answer, label: string): void {\n // The ONE field the server does not trim, so its ceiling applies to the raw\n // value. Emptiness is checked more strictly than the API on purpose: a blank\n // id passes `min(1)` and then matches no question, leaving the round silently\n // unanswered.\n if (answer.questionId.trim().length === 0) {\n throw new CliError(`${label} needs a non-empty \"questionId\".`, 2);\n }\n if (answer.questionId.length > LIMITS.QUESTION_ID) {\n throw new CliError(\n `${label} has a \"questionId\" longer than ${LIMITS.QUESTION_ID} characters.`,\n 2,\n );\n }\n\n const options = answer.selectedOptionIds;\n if (options !== undefined) {\n if (options.length > LIMITS.OPTIONS_PER_ANSWER) {\n throw new CliError(\n `${label} selects more than ${LIMITS.OPTIONS_PER_ANSWER} options.`,\n 2,\n );\n }\n for (const id of options) {\n if (id.trim().length === 0) {\n throw new CliError(`${label} has an empty option id.`, 2);\n }\n // Trimmed, like the server: a padded 40-character id is accepted there.\n if (id.trim().length > LIMITS.OPTION_ID) {\n throw new CliError(\n `${label} has an option id longer than ${LIMITS.OPTION_ID} characters.`,\n 2,\n );\n }\n }\n }\n\n if (answer.freeText !== undefined) {\n const freeText = answer.freeText.trim();\n if (freeText.length === 0) {\n throw new CliError(`${label} has empty free text.`, 2);\n }\n if (freeText.length > LIMITS.FREE_TEXT) {\n throw new CliError(\n `${label} has free text longer than ${LIMITS.FREE_TEXT} characters.`,\n 2,\n );\n }\n }\n\n // The server's own rule; `--option q1=,,` reaches exactly this shape.\n if (\n (options === undefined || options.length === 0) &&\n answer.freeText === undefined\n ) {\n throw new CliError(\n `${label} answers nothing. Give it at least one option id or some free text.`,\n 2,\n );\n }\n}\n\n/** `--answers '{}'` used to sail through `JSON.parse` and be posted as\n * `{\"answers\": {}}`, contradicting the CLI's own error message. */\nfunction parseAnswersFlag(raw: string): Answers {\n let decoded: unknown;\n try {\n decoded = JSON.parse(raw);\n } catch {\n throw new CliError(\"--answers expects a JSON array.\", 2);\n }\n\n if (!Array.isArray(decoded) || decoded.length === 0) {\n throw new CliError(\n '--answers expects a non-empty JSON array, e.g. \\'[{\"questionId\":\"q1\",\"selectedOptionIds\":[\"1\"]}]\\'.',\n 2,\n );\n }\n\n if (decoded.length > LIMITS.ANSWERS) {\n throw new CliError(\n `--answers carries more than ${LIMITS.ANSWERS} entries.`,\n 2,\n );\n }\n\n for (const [index, entry] of decoded.entries()) {\n const label = `--answers[${index}]`;\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new CliError(`${label} must be an object.`, 2);\n }\n const answer = entry as Record<string, unknown>;\n if (typeof answer.questionId !== \"string\") {\n throw new CliError(`${label} needs a non-empty \"questionId\".`, 2);\n }\n if (\n answer.selectedOptionIds !== undefined &&\n (!Array.isArray(answer.selectedOptionIds) ||\n answer.selectedOptionIds.some((id) => typeof id !== \"string\"))\n ) {\n throw new CliError(\n `${label}.selectedOptionIds must be an array of strings.`,\n 2,\n );\n }\n if (answer.freeText !== undefined && typeof answer.freeText !== \"string\") {\n throw new CliError(`${label}.freeText must be a string.`, 2);\n }\n\n validateAnswer(entry as Answer, label);\n }\n\n return decoded as Answers;\n}\n\n/** `--option <questionId>=1,2` and `--text <questionId>=…`, or `--answers <json>`. */\nexport function collectAnswers(parsed: ParsedArgs): Answers {\n if (parsed.flags.answers) {\n return parseAnswersFlag(parsed.flags.answers);\n }\n\n const byQuestion = new Map<string, Answer>();\n\n const put = (pair: string, apply: (entry: Answer) => void) => {\n const equalsAt = pair.indexOf(\"=\");\n if (equalsAt < 0) {\n throw new CliError(`Expected <questionId>=<value>, got \"${pair}\".`, 2);\n }\n const questionId = pair.slice(0, equalsAt);\n const entry = byQuestion.get(questionId) ?? { questionId };\n apply(entry);\n byQuestion.set(questionId, entry);\n };\n\n for (const pair of parsed.repeated.option ?? []) {\n put(pair, (entry) => {\n entry.selectedOptionIds = pair\n .slice(pair.indexOf(\"=\") + 1)\n .split(\",\")\n .map((id) => id.trim())\n .filter(Boolean);\n });\n }\n\n for (const pair of parsed.repeated.text ?? []) {\n put(pair, (entry) => {\n entry.freeText = pair.slice(pair.indexOf(\"=\") + 1);\n });\n }\n\n const answers = [...byQuestion.values()];\n if (answers.length === 0) {\n throw new CliError(\n \"Nothing to submit. Use --option <questionId>=<ids>, --text <questionId>=<answer>, or --answers <json>.\",\n 2,\n );\n }\n if (answers.length > LIMITS.ANSWERS) {\n throw new CliError(\n `More than ${LIMITS.ANSWERS} answers in one submission.`,\n 2,\n );\n }\n\n for (const answer of answers) {\n validateAnswer(answer, `--option/--text ${answer.questionId}`);\n }\n\n return answers;\n}\n","import { api } from \"../lib/api\";\nimport { path } from \"../lib/api-path\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { collectAnswers } from \"./collect-answers\";\nimport { CliError } from \"../lib/errors\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { out } from \"../lib/output\";\n\ntype Batch = ApiOutputs[\"questions\"][\"get\"];\ntype Answers = ApiInputs[\"questions\"][\"submit\"][\"answers\"];\n\nconst ACTIONS = [\"list\", \"show\", \"answer\", \"cancel\"] as const;\n\nfunction printBatch(batch: Batch): void {\n // Questions are agent-authored text — sanitise before printing (out.safe).\n out.line(\n `${out.paint(out.cell(batch.sessionTitle), \"bold\")} ${out.paint(`round ${batch.round}`, \"dim\")}`,\n );\n out.line(\n out.paint(\n `batch ${out.cell(batch.id)} · session ${out.cell(batch.sessionId)}`,\n \"dim\",\n ),\n );\n\n for (const question of batch.questions) {\n out.line();\n if (question.header) {\n out.line(out.paint(out.cell(question.header), \"dim\"));\n }\n out.line(\n `${out.paint(out.cell(question.id), \"dim\")} ${out.safe(question.body)}`,\n );\n if (question.image) {\n out.line(out.paint(` (image) ${out.cell(question.image)}`, \"dim\"));\n }\n for (const option of question.options) {\n const recommended = option.id === question.recommendedOptionId;\n // An option can be an image with no label — printing just a number\n // would leave the reader unable to tell what choosing it means.\n const label = option.label\n ? out.cell(option.label)\n : option.image\n ? out.paint(`(image) ${out.cell(option.image)}`, \"dim\")\n : out.paint(\"(no label)\", \"dim\");\n out.line(\n ` ${out.cell(option.id)}) ${label}${recommended ? out.paint(\" ← recommended\", \"green\") : \"\"}`,\n );\n }\n if (question.allowFreeText) {\n out.line(out.paint(\" free text accepted\", \"dim\"));\n }\n }\n}\n\n/**\n * A session with an unanswered round parks forever. Answering is a normal\n * scope, so an agent can do it; only guardrail decisions need a human.\n */\nexport async function questionsCommand(parsed: ParsedArgs): Promise<void> {\n const action = args.action(parsed, \"questions\", ACTIONS, \"list\");\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n args.expect(parsed, { flags: [\"session\"], positional: 1 });\n const session = parsed.flags.session;\n const result = expectShape<ApiOutputs[\"questions\"][\"list\"]>(\n await api(session ? path`/sessions/${session}/questions` : \"/questions\"),\n \"GET /questions\",\n { items: is.array },\n );\n\n if (asJson) {\n out.json(result);\n return;\n }\n if (result.items.length === 0) {\n out.line(\"Nothing waiting on you.\");\n return;\n }\n out.table(\n result.items.map((batch) => [\n out.cell(batch.id),\n out.cell(batch.sessionId),\n `${batch.questions.length} question(s)`,\n out.cell(batch.sessionTitle),\n ]),\n );\n return;\n }\n\n args.expect(parsed, {\n positional: 2,\n ...(action === \"answer\" ? { flags: [\"option\", \"text\", \"answers\"] } : {}),\n });\n const batchId = args.required(parsed, 1, \"batchId\");\n\n if (action === \"show\") {\n const batch = expectShape<Batch>(\n await api(path`/questions/${batchId}`),\n \"GET /questions/{id}\",\n { id: is.string, questions: is.array, sessionTitle: is.string },\n );\n if (asJson) {\n out.json(batch);\n return;\n }\n printBatch(batch);\n return;\n }\n\n if (action === \"answer\") {\n const result = expectShape<ApiOutputs[\"questions\"][\"submit\"]>(\n await api(path`/questions/${batchId}/submit`, {\n method: \"POST\",\n body: { answers: collectAnswers(parsed) },\n }),\n \"POST /questions/{id}/submit\",\n { answeredCount: is.number },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n `${out.paint(\"✓\", \"green\")} Answered ${result.answeredCount} question(s); the session resumes.`,\n );\n return;\n }\n\n const result = await api<ApiOutputs[\"questions\"][\"cancel\"]>(\n path`/questions/${batchId}/cancel`,\n { method: \"POST\", body: {} },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n 'Round cancelled. The session stays parked — send a message to steer it: `hepha sessions send <id> \"…\"`',\n );\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { out } from \"./output\";\n\ntype TranscriptEvent = ApiOutputs[\"sessions\"][\"events\"][\"items\"][number];\n\n/** Sanitised first: transcript text is model, tool and repository output. */\nfunction truncate(text: string, max = 2000): string {\n const trimmed = out.safe(text).trim();\n return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;\n}\n\n/**\n * One transcript event as one readable block.\n *\n * The transcript is the only honest account of what the agent did, so the\n * shapes that matter to a reviewer — tool calls, file changes, questions,\n * guardrails, errors — each keep a distinct marker instead of collapsing into\n * prose.\n */\nexport function formatEvent(event: TranscriptEvent): string | null {\n const part = event.part;\n\n switch (part.kind) {\n case \"text\":\n if (part.authorUserId) {\n return `${out.paint(\"you\", \"magenta\")} ${truncate(part.text)}`;\n }\n // Text with no author but a source was injected by the platform (an\n // integration trigger, an inbox event): the transcript contract says it\n // must never be attributed to the model.\n if (part.source) {\n return out.paint(`system ${truncate(part.text, 400)}`, \"dim\");\n }\n return `${out.paint(\"agent\", \"blue\")} ${truncate(part.text)}`;\n case \"reasoning\":\n return out.paint(`think ${truncate(part.text, 400)}`, \"dim\");\n case \"tool\":\n return `${out.paint(\"tool\", \"dim\")} ${out.cell(part.toolName)} ${out.paint(`(${part.status})`, \"dim\")}`;\n case \"file_change\":\n return `${out.paint(\"file\", \"dim\")} ${part.changeType.padEnd(8)} ${out.cell(part.path)}`;\n case \"question\":\n return out.paint(\n `ask question round ${part.questionBatchId} — answer with \\`hepha questions answer ${part.questionBatchId}\\``,\n \"yellow\",\n );\n case \"approval\":\n return out.paint(\n `gate guardrail ${part.guardrailRequestId} needs a human — \\`hepha approvals show ${part.guardrailRequestId}\\``,\n \"yellow\",\n );\n case \"media\": {\n // The signed URL is why this part exists: a screenshot or a recording is\n // the session's proof, and a reader who cannot open it has nothing.\n const target = part.url ?? part.pathname;\n return `${out.paint(\"media\", \"dim\")} ${part.mediaType}${part.caption ? ` — ${out.cell(part.caption)}` : \"\"}${target ? `\\n ${out.cell(target)}` : \"\"}`;\n }\n case \"error\":\n return out.paint(`error ${truncate(part.message)}`, \"red\");\n case \"external_event\":\n return `${out.paint(\"event\", \"dim\")} ${out.cell(part.title)}${part.conclusion ? ` — ${out.cell(part.conclusion)}` : \"\"}`;\n case \"system\":\n return out.paint(`system ${truncate(part.text, 300)}`, \"dim\");\n default:\n return null;\n }\n}\n","import { api } from \"./api\";\nimport { path } from \"./api-path\";\nimport type { ApiOutputs } from \"./api-types\";\nimport { expectShape } from \"./expect-shape\";\nimport { is } from \"./is\";\nimport { formatEvent } from \"./format-event\";\nimport { out } from \"./output\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\nconst TERMINAL = new Set([\"completed\", \"failed\", \"killed\", \"abstained\"]);\nconst BLOCKED = new Set([\"waiting_human\", \"awaiting_approval\"]);\nconst POLL_SECONDS = 3;\n/** Matches the API's own ceiling for this route, so a page is never refused. */\nconst PAGE_SIZE = 200;\n\nfunction sleep(seconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, seconds * 1000));\n}\n\n/**\n * Follow a session until it finishes or needs a person.\n *\n * Stopping on `waiting_human` / `awaiting_approval` is the important part: the\n * agent parks there and burns nothing, so a follower that kept waiting would\n * hang forever. The caller turns that into a distinct exit code, which is what\n * lets an orchestrating agent branch on \"it asked me something\".\n */\nexport async function followSession(\n sessionId: string,\n options: { quiet?: boolean; after?: number } = {},\n): Promise<SessionDetail> {\n // Resuming a follow starts where the caller left off, so `--after` does not\n // replay (and reprint) the whole transcript.\n let cursor = options.after ?? 0;\n\n for (;;) {\n const page = expectShape<ApiOutputs[\"sessions\"][\"events\"]>(\n await api(path`/sessions/${sessionId}/events`, {\n query: { after: cursor || undefined, limit: PAGE_SIZE },\n }),\n \"GET /sessions/{id}/events\",\n { items: is.array },\n );\n\n for (const event of page.items) {\n cursor = Math.max(cursor, event.sequence);\n if (options.quiet) {\n continue;\n }\n const line = formatEvent(event);\n if (line) {\n out.line(line);\n }\n }\n\n // Advance on the SERVER's cursor, not on what we could render. The API\n // paginates raw rows and drops the ones with no transcript representation,\n // so a page can come back empty with hasMore true — following the items\n // alone would re-request the same page forever, without even sleeping.\n if (page.nextCursor !== null) {\n cursor = Math.max(cursor, page.nextCursor);\n }\n\n if (page.hasMore) {\n continue;\n }\n\n const session = await api<SessionDetail>(path`/sessions/${sessionId}`);\n if (TERMINAL.has(session.status) || BLOCKED.has(session.status)) {\n return session;\n }\n\n await sleep(POLL_SECONDS);\n }\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { out } from \"./output\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\n/** The single-session view shared by `get`, `run` and every control command. */\nexport function printSession(session: SessionDetail): void {\n // Titles, reasons, URLs and step names are agent-authored: sanitise before\n // they reach a terminal (see out.safe).\n out.line(\n `${out.paint(out.cell(session.title), \"bold\")} ${out.status(session.status)}`,\n );\n\n const rows: string[][] = [[\"id\", out.cell(session.id)]];\n if (session.statusReason) {\n rows.push([\"reason\", out.cell(session.statusReason)]);\n }\n if (session.repoFullName) {\n const branch = session.repos.find(\n (repo) => repo.repoFullName === session.repoFullName,\n )?.branch;\n rows.push([\n \"repo\",\n out.cell(session.repoFullName + (branch ? ` @ ${branch}` : \"\")),\n ]);\n }\n rows.push([\"task\", session.taskType]);\n if (session.model) {\n rows.push([\"model\", out.cell(session.model)]);\n }\n if (session.prUrl) {\n rows.push([\n \"pr\",\n out.cell(\n `${session.prUrl}${session.prState ? ` (${session.prState})` : \"\"}`,\n ),\n ]);\n }\n for (const deliverable of session.deliverables) {\n if (deliverable.url && deliverable.url !== session.prUrl) {\n rows.push([out.cell(deliverable.type), out.cell(deliverable.url)]);\n }\n }\n\n out.table(rows.map(([label, value]) => [out.paint(label!, \"dim\"), value!]));\n\n const steps = session.playbook?.steps ?? [];\n if (steps.length > 0) {\n out.line();\n for (const step of steps) {\n const done = step.todos.filter(\n (todo) => todo.status === \"completed\",\n ).length;\n const marker =\n done === step.todos.length && step.todos.length > 0 ? \"✓\" : \"·\";\n out.line(\n ` ${marker} ${out.cell(step.title)} ${out.paint(`${done}/${step.todos.length}`, \"dim\")}`,\n );\n }\n }\n}\n","import type { ApiOutputs } from \"./api-types\";\nimport { CliError } from \"./errors\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\n/**\n * What a followed session means for the caller's exit code.\n *\n * `followSession` returns on two very different conditions — the work is over,\n * or it needs a person — and both `run --follow` and `sessions logs --follow`\n * have to tell them apart the same way. Returns null when the session\n * completed (exit 0), a CliError carrying 3 when a human is needed, and 1 for\n * a real failure. The session rides on the error so `--json` can emit one\n * document holding both the outcome and what it applies to.\n */\nexport function sessionOutcome(session: SessionDetail): CliError | null {\n switch (session.status) {\n case \"completed\":\n return null;\n case \"waiting_human\":\n return new CliError(\n `Waiting on an answer — \\`hepha questions list --session ${session.id}\\``,\n 3,\n {},\n session,\n );\n case \"awaiting_approval\":\n return new CliError(\n \"Waiting on a guardrail approval — `hepha approvals list`\",\n 3,\n {},\n session,\n );\n default:\n return new CliError(\n `Session ended ${session.status}${session.statusReason ? `: ${session.statusReason}` : \".\"}`,\n 1,\n {},\n session,\n );\n }\n}\n","import { api } from \"../lib/api\";\nimport type { ApiInputs, ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { followSession } from \"../lib/follow\";\nimport { out } from \"../lib/output\";\nimport { printSession } from \"../lib/print-session\";\nimport { sessionOutcome } from \"../lib/session-outcome\";\n\ntype CreateInput = ApiInputs[\"sessions\"][\"create\"];\n\n/**\n * Validated locally so a typo names itself, instead of travelling to the API\n * and coming back as a bare \"Input validation failed\" that says nothing about\n * which flag was wrong.\n *\n * `satisfies` against the router's own input type is what keeps these lists\n * honest: adding a task type server-side without updating this one is a\n * `types:check` failure, not a CLI that quietly refuses a valid value.\n */\nconst TASK_TYPES = [\n \"implement\",\n \"new-project\",\n \"question\",\n \"draft\",\n] as const satisfies readonly NonNullable<CreateInput[\"taskType\"]>[];\n\nconst HARNESSES = [\n \"claude-code\",\n \"codex\",\n] as const satisfies readonly NonNullable<CreateInput[\"harnessPin\"]>[];\n\n/**\n * Exit code carries the outcome — 0 done, 3 waiting on a human, 1 failed — so\n * a caller can drive the loop without parsing text.\n */\nexport async function runCommand(parsed: ParsedArgs): Promise<void> {\n args.expect(parsed, {\n flags: [\n \"title\",\n \"task-type\",\n \"model\",\n \"harness\",\n \"repo\",\n \"branch\",\n \"skill\",\n ],\n booleans: [\"follow\"],\n positional: 1,\n });\n\n const prompt = args.required(parsed, 0, \"prompt\");\n const asJson = parsed.booleans.has(\"json\");\n const taskType = args.choice(parsed, \"task-type\", TASK_TYPES);\n const harness = args.choice(parsed, \"harness\", HARNESSES);\n\n const body: CreateInput = {\n prompt,\n ...(parsed.flags.title ? { title: parsed.flags.title } : {}),\n ...(taskType ? { taskType } : {}),\n ...(parsed.flags.model ? { modelSelection: parsed.flags.model } : {}),\n ...(harness ? { harnessPin: harness } : {}),\n ...(parsed.flags.repo ? { repoFullName: parsed.flags.repo } : {}),\n ...(parsed.flags.branch ? { branch: parsed.flags.branch } : {}),\n ...(parsed.repeated.skill ? { pinnedSkillIds: parsed.repeated.skill } : {}),\n };\n\n const session = expectShape<ApiOutputs[\"sessions\"][\"create\"]>(\n await api(\"/sessions\", { method: \"POST\", body }),\n \"POST /sessions\",\n { id: is.string, title: is.string, status: is.string },\n );\n\n if (!parsed.booleans.has(\"follow\")) {\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n out.line();\n out.line(out.paint(` hepha sessions logs ${session.id} --follow`, \"dim\"));\n return;\n }\n\n const quiet = asJson || parsed.booleans.has(\"quiet\");\n\n if (!quiet) {\n out.line(out.paint(`session ${session.id}`, \"dim\"));\n out.line();\n }\n\n const final = await followSession(session.id, { quiet });\n\n // Resolved BEFORE anything is written: on a non-zero outcome the envelope\n // carries the session, so stdout stays ONE JSON document.\n const outcome = sessionOutcome(final);\n\n if (asJson) {\n if (!outcome) {\n out.json(final);\n }\n } else {\n out.line();\n printSession(final);\n }\n\n if (outcome) {\n throw outcome;\n }\n}\n","import { api } from \"../lib/api\";\nimport { path } from \"../lib/api-path\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { followSession } from \"../lib/follow\";\nimport { formatEvent } from \"../lib/format-event\";\nimport { out } from \"../lib/output\";\nimport { printSession } from \"../lib/print-session\";\nimport { sessionOutcome } from \"../lib/session-outcome\";\n\ntype SessionDetail = ApiOutputs[\"sessions\"][\"get\"];\n\nconst ACTIONS = [\n \"list\",\n \"get\",\n \"logs\",\n \"send\",\n \"pause\",\n \"resume\",\n \"kill\",\n \"archive\",\n \"checks\",\n \"pr\",\n \"verify\",\n] as const;\n\nconst CONTROL_PATHS: Record<string, string> = {\n pause: \"pause\",\n resume: \"resume\",\n kill: \"kill\",\n archive: \"archive\",\n};\n\nconst STATUS_GROUPS = [\"active\", \"waiting\", \"done\"] as const;\n\n/** The session shape every printer here destructures. */\nconst SESSION_FIELDS = {\n id: is.string,\n title: is.string,\n status: is.string,\n taskType: is.string,\n repos: is.array,\n deliverables: is.array,\n};\n\nfunction detail(payload: unknown, endpoint: string): SessionDetail {\n return expectShape<SessionDetail>(payload, endpoint, SESSION_FIELDS);\n}\n\nasync function listSessions(parsed: ParsedArgs): Promise<void> {\n args.expect(parsed, {\n flags: [\"status\", \"repo\", \"search\", \"page\", \"limit\"],\n booleans: [\"all\"],\n positional: 1,\n });\n\n const result = expectShape<ApiOutputs[\"sessions\"][\"list\"]>(\n await api(\"/sessions\", {\n query: {\n statusGroup: args.choice(parsed, \"status\", STATUS_GROUPS),\n repoFullName: parsed.flags.repo,\n search: parsed.flags.search,\n page: args.integer(parsed, \"page\", { min: 1 }),\n limit: args.integer(parsed, \"limit\", { min: 1, max: 100 }),\n scope: parsed.booleans.has(\"all\") ? \"all\" : undefined,\n },\n }),\n \"GET /sessions\",\n { data: is.array, \"pagination.page\": is.number },\n );\n\n if (parsed.booleans.has(\"json\")) {\n out.json(result);\n return;\n }\n\n if (result.data.length === 0) {\n out.line(\"No sessions.\");\n return;\n }\n\n if (result.pagination.hasNextPage) {\n out.line(\n out.paint(\n `page ${result.pagination.page}/${result.pagination.totalPages} — --page ${result.pagination.page + 1} for more`,\n \"dim\",\n ),\n );\n out.line();\n }\n\n out.table(\n result.data.map((session) => [\n out.cell(session.id),\n out.status(session.status),\n out.cell(session.repoFullName ?? \"—\"),\n out.cell(session.title),\n ]),\n );\n}\n\nasync function showLogs(parsed: ParsedArgs): Promise<void> {\n args.expect(parsed, {\n flags: [\"after\", \"limit\"],\n booleans: [\"follow\"],\n positional: 2,\n });\n\n const sessionId = args.required(parsed, 1, \"sessionId\");\n const asJson = parsed.booleans.has(\"json\");\n const after = args.integer(parsed, \"after\", { min: 0 });\n\n if (parsed.booleans.has(\"follow\")) {\n // --json stays a single parseable value even here: the transcript is\n // suppressed and only the final session is written to stdout. `--quiet`\n // buys the same silence without forcing the JSON shape on the reader.\n const session = await followSession(sessionId, {\n quiet: asJson || parsed.booleans.has(\"quiet\"),\n ...(after !== undefined ? { after } : {}),\n });\n // Only a blocked or failed session is an error. Resolved BEFORE anything is\n // written: the envelope carries the session, so stdout stays ONE document.\n const outcome = sessionOutcome(session);\n\n if (asJson) {\n if (!outcome) {\n out.json(session);\n }\n } else {\n out.line();\n printSession(session);\n }\n\n if (outcome) {\n throw outcome;\n }\n return;\n }\n\n const page = expectShape<ApiOutputs[\"sessions\"][\"events\"]>(\n await api(path`/sessions/${sessionId}/events`, {\n query: {\n after,\n limit: args.integer(parsed, \"limit\", { min: 1, max: 200 }),\n },\n }),\n \"GET /sessions/{id}/events\",\n { items: is.array },\n );\n\n if (asJson) {\n out.json(page);\n return;\n }\n\n for (const event of page.items) {\n const line = formatEvent(event);\n if (line) {\n out.line(line);\n }\n }\n\n // Never let a truncated transcript look complete. Formatted events do not\n // carry their sequence, so the continuation cursor has to be spelled out.\n if (page.hasMore && page.nextCursor !== null) {\n out.line();\n out.line(\n out.paint(\n `more events — hepha sessions logs ${sessionId} --after ${page.nextCursor}`,\n \"dim\",\n ),\n );\n }\n}\n\nexport async function sessionsCommand(parsed: ParsedArgs): Promise<void> {\n // The action is validated FIRST, so `hepha sessions frobnicate <id>` names\n // the real problem instead of asking for an argument it would never use.\n const action = args.action(parsed, \"sessions\", ACTIONS, \"list\");\n const asJson = parsed.booleans.has(\"json\");\n\n if (action === \"list\") {\n return await listSessions(parsed);\n }\n\n if (action === \"logs\") {\n return await showLogs(parsed);\n }\n\n if (action === \"send\") {\n args.expect(parsed, { positional: 3 });\n const sessionId = args.required(parsed, 1, \"sessionId\");\n const message = args.required(parsed, 2, \"message\");\n const result = expectShape<ApiOutputs[\"sessions\"][\"sendMessage\"]>(\n await api(path`/sessions/${sessionId}/messages`, {\n method: \"POST\",\n body: { message },\n }),\n \"POST /sessions/{id}/messages\",\n { delivery: is.string },\n );\n if (asJson) {\n out.json(result);\n return;\n }\n out.line(\n result.delivery === \"interrupt\"\n ? \"Delivered to the running agent.\"\n : \"Queued — the agent picks it up at the end of its turn.\",\n );\n return;\n }\n\n // `--reason` belongs to `kill` alone; every other control command rejects it\n // rather than accepting it and dropping it on the floor, which is what the\n // old help text promised and the code never did.\n args.expect(parsed, {\n positional: 2,\n ...(action === \"kill\" ? { flags: [\"reason\"] } : {}),\n });\n\n const sessionId = args.required(parsed, 1, \"sessionId\");\n\n if (action === \"get\") {\n const session = detail(\n await api(path`/sessions/${sessionId}`),\n \"GET /sessions/{id}\",\n );\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n return;\n }\n\n // hasOwn, not `in`: `in` also matches inherited keys, so `hepha sessions\n // toString <id>` would route as a control command with a garbage path\n // instead of reaching the unknown-command error.\n if (Object.hasOwn(CONTROL_PATHS, action)) {\n const controlPath = CONTROL_PATHS[action]!;\n const session = detail(\n await api(path`/sessions/${sessionId}/${controlPath}`, {\n method: \"POST\",\n body:\n action === \"kill\" && parsed.flags.reason\n ? { reason: parsed.flags.reason }\n : {},\n }),\n `POST /sessions/{id}/${controlPath}`,\n );\n if (asJson) {\n out.json(session);\n return;\n }\n printSession(session);\n return;\n }\n\n if (action === \"checks\") {\n out.json(\n await api<ApiOutputs[\"sessions\"][\"runChecks\"]>(\n path`/sessions/${sessionId}/checks`,\n { method: \"POST\", body: {} },\n ),\n );\n return;\n }\n\n if (action === \"pr\") {\n out.json(\n await api<ApiOutputs[\"sessions\"][\"prChecks\"]>(\n path`/sessions/${sessionId}/pr-checks`,\n ),\n );\n return;\n }\n\n out.json(\n await api<ApiOutputs[\"sessions\"][\"verification\"]>(\n path`/sessions/${sessionId}/verification`,\n ),\n );\n}\n","import { api } from \"../lib/api\";\nimport type { ApiOutputs } from \"../lib/api-types\";\nimport { args, type ParsedArgs } from \"../lib/args\";\nimport { config } from \"../lib/config\";\nimport { expectShape } from \"../lib/expect-shape\";\nimport { is } from \"../lib/is\";\nimport { out } from \"../lib/output\";\n\nexport async function whoamiCommand(parsed: ParsedArgs): Promise<void> {\n args.expect(parsed, {});\n\n const identity = expectShape<ApiOutputs[\"me\"][\"get\"]>(\n await api(\"/me\"),\n \"GET /me\",\n {\n \"user.name\": is.string,\n \"user.email\": is.string,\n \"auth.method\": is.string,\n \"auth.scopes\": is.array,\n },\n );\n\n if (parsed.booleans.has(\"json\")) {\n out.json(identity);\n return;\n }\n\n out.table([\n [\n out.paint(\"user\", \"dim\"),\n out.cell(`${identity.user.name} <${identity.user.email}>`),\n ],\n [out.paint(\"role\", \"dim\"), out.cell(identity.user.role ?? \"member\")],\n [\n out.paint(\"auth\", \"dim\"),\n out.cell(\n identity.auth.method === \"api_key\"\n ? `api key${identity.auth.keyName ? ` \"${identity.auth.keyName}\"` : \"\"}`\n : \"session\",\n ),\n ],\n [out.paint(\"scopes\", \"dim\"), identity.auth.scopes.join(\" \")],\n [out.paint(\"url\", \"dim\"), config.load().baseUrl],\n ]);\n}\n","/**\n * Was machine output asked for, before anything can fail?\n *\n * The failure path needs to know, and it starts in `main()`'s catch — including\n * for errors raised BY the parser, which is exactly when an agent most needs a\n * parseable answer. Mirrors the parser's own rule: a bare `--json` token, and\n * `--` ends option parsing so a prompt may still contain the word.\n */\nexport function wantsJson(argv: string[]): boolean {\n for (const token of argv) {\n if (token === \"--\") {\n return false;\n }\n if (token === \"--json\") {\n return true;\n }\n }\n return false;\n}\n","import { approvalsCommand } from \"./commands/approvals\";\nimport { catalogCommand } from \"./commands/catalog\";\nimport { helpCommand } from \"./commands/help\";\nimport { keysCommand } from \"./commands/keys\";\nimport { loginCommand } from \"./commands/login\";\nimport { logoutCommand } from \"./commands/logout\";\nimport { questionsCommand } from \"./commands/questions\";\nimport { runCommand } from \"./commands/run\";\nimport { sessionsCommand } from \"./commands/sessions\";\nimport { whoamiCommand } from \"./commands/whoami\";\nimport { args } from \"./lib/args\";\nimport { CliError } from \"./lib/errors\";\nimport { out } from \"./lib/output\";\nimport { VERSION } from \"./lib/version\";\nimport { wantsJson } from \"./lib/wants-json\";\n\nconst CATALOG_TOPICS = new Set([\"repos\", \"branches\", \"models\", \"skills\"]);\n\nasync function dispatch(command: string, argv: string[]): Promise<void> {\n const parsed = args.parse(argv);\n\n if (parsed.booleans.has(\"help\")) {\n helpCommand();\n return;\n }\n\n if (CATALOG_TOPICS.has(command)) {\n return await catalogCommand(command, parsed);\n }\n\n switch (command) {\n case \"login\":\n return await loginCommand(parsed);\n case \"logout\":\n return logoutCommand(parsed);\n case \"whoami\":\n return await whoamiCommand(parsed);\n case \"keys\":\n return await keysCommand(parsed);\n case \"run\":\n return await runCommand(parsed);\n case \"sessions\":\n return await sessionsCommand(parsed);\n case \"questions\":\n return await questionsCommand(parsed);\n case \"approvals\":\n return await approvalsCommand(parsed);\n default:\n helpCommand();\n throw new CliError(`Unknown command \"${command}\".`, 2);\n }\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n out.setJson(wantsJson(argv));\n\n const [command, ...rest] = argv;\n\n if (!command || command === \"help\" || command === \"--help\") {\n helpCommand();\n return;\n }\n\n // Answered early, but NOT before the arguments are checked: returning ahead\n // of the parser would exempt this command from the strictness every other one\n // applies.\n if (command === \"--version\" || command === \"-v\" || command === \"version\") {\n args.expect(args.parse(rest), {});\n if (out.isJson()) {\n out.json({ version: VERSION });\n } else {\n out.line(VERSION);\n }\n return;\n }\n\n await dispatch(command, rest);\n}\n\nmain().catch((error: unknown) => {\n const failure =\n error instanceof CliError\n ? error\n : new CliError(error instanceof Error ? error.message : String(error));\n\n out.failure(failure);\n process.exit(failure.exitCode);\n});\n"],"mappings":"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","names":["readString","readFileSync","dirname","join","result","detail","ACTIONS","result","ACTIONS","result","sleep","ACTIONS","sessionId"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@impulselab/hepha",
3
- "version": "0.1.0",
3
+ "version": "0.2.44",
4
4
  "description": "Command-line interface for the Hepha platform.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -25,7 +25,8 @@
25
25
  "scripts": {
26
26
  "build": "tsup",
27
27
  "dev": "tsx src/index.ts",
28
- "types:check": "tsc --noEmit",
28
+ "types:check": "pnpm --filter @repo/ui run build && tsc --noEmit",
29
+ "test": "find src -name '*.test.ts' -type f -exec tsx --test {} +",
29
30
  "prepublishOnly": "npm run types:check",
30
31
  "prepack": "tsup"
31
32
  },