@agentconnect.md/daemon 1.56.0-rc.28 → 1.56.0-rc.29

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.
@@ -4,6 +4,29 @@ import { t as loadConfig } from "./load-config-Q6WiBdq1.js";
4
4
  import { Yt as installedRuntimeCatalog, c as probeAllRuntimes, en as ArchiveStore, i as defaultProbeHostFactory, nn as storedArchiveRuntimeDef, t as resolveRuntimeCatalog, tn as parseArchiveLaunch, zt as AcpHost } from "./registry-BbcxvsW8.js";
5
5
  import { createInterface } from "node:readline";
6
6
  import { spawn } from "node:child_process";
7
+ //#region src/runtimes/cli-login.ts
8
+ const CLI_LOGIN = { "grok-build": {
9
+ methods: ["grok.com"],
10
+ acpTail: ["agent", "stdio"],
11
+ loginArgs: ["login", "--device-auth"],
12
+ reason: "grok-build cannot run this login over ACP — handing your terminal to `grok login --device-auth`."
13
+ } };
14
+ /** The CLI login that logs `runtimeId` in, or undefined when ACP `authenticate` is the way. */
15
+ function cliLoginLaunch(runtimeId, methodId, runtime) {
16
+ const spec = CLI_LOGIN[runtimeId];
17
+ if (!spec?.methods.includes(methodId)) return void 0;
18
+ const head = runtime.args.slice(0, runtime.args.length - spec.acpTail.length);
19
+ const tail = runtime.args.slice(head.length);
20
+ if (tail.length !== spec.acpTail.length || tail.some((arg, i) => arg !== spec.acpTail[i])) return void 0;
21
+ return {
22
+ runtime: {
23
+ ...runtime,
24
+ args: [...head, ...spec.loginArgs]
25
+ },
26
+ reason: spec.reason
27
+ };
28
+ }
29
+ //#endregion
7
30
  //#region src/cli/auth-picker.ts
8
31
  /** A model for a list that will not change. */
9
32
  function fixedRows(rows) {
@@ -412,9 +435,11 @@ async function runAuth(opts) {
412
435
  if (!method) throw new Error(`"${answer}" is not one of the offered methods`);
413
436
  }
414
437
  out.write(`Using ${method.id} — ${method.name}\n`);
415
- if (isTerminalMethod(method)) {
438
+ const cli = cliLoginLaunch(runtimeId, method.id, runtime);
439
+ if (isTerminalMethod(method) || cli) {
440
+ if (cli) out.write(`${cli.reason}\n`);
416
441
  await host.stop(5e3, EOF_GRACE_MS);
417
- const code = await (opts.runTerminalAuth ?? spawnTerminalAuth)(runtime, method);
442
+ const code = await (opts.runTerminalAuth ?? spawnTerminalAuth)(cli?.runtime ?? runtime, method);
418
443
  if (code !== 0) throw new Error(`interactive login exited with code ${code}`);
419
444
  } else {
420
445
  const login = host.authenticate(method.id);
@@ -431,4 +456,4 @@ async function runAuth(opts) {
431
456
  //#endregion
432
457
  export { runAuth };
433
458
 
434
- //# sourceMappingURL=auth-Cj3OPO5i.js.map
459
+ //# sourceMappingURL=auth-DdXGZ3VX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-DdXGZ3VX.js","names":[],"sources":["../src/runtimes/cli-login.ts","../src/cli/auth-picker.ts","../src/cli/auth.ts"],"sourcesContent":["// Runtimes whose ACP `authenticate` cannot be finished from a headless client, and the login\n// subcommand of their own CLI that can. An entry here is not a preference: it is a runtime that\n// answers `authenticate` with silence, leaving the operator with nothing to act on.\n\nimport type { RuntimeDef } from '../config/config-schema.js'\n\ninterface CliLoginSpec {\n /** Only these method ids are redirected; anything else the runtime offers still goes over ACP. */\n methods: string[]\n /** The ACP-mode argv tail the launch ends with. Login is a different subcommand, so it replaces\n * this rather than appending — and a launch that does not end in it is left to ACP untouched. */\n acpTail: string[]\n /** What takes the tail's place. */\n loginArgs: string[]\n /** One line telling the operator why their terminal is being handed to the runtime's own CLI. */\n reason: string\n}\n\nconst CLI_LOGIN: Record<string, CliLoginSpec> = {\n // grok-build's inline flow silently tries to open a browser ON THE DAEMON HOST and then waits\n // forever: no elicitation, nothing on stderr, and no loopback listener for the redirect-paste\n // fallback to reach. `grok login --device-auth` prints a URL and a code, and writes the same\n // ~/.grok/auth.json that sessions are seeded from.\n 'grok-build': {\n methods: ['grok.com'],\n acpTail: ['agent', 'stdio'],\n loginArgs: ['login', '--device-auth'],\n reason: 'grok-build cannot run this login over ACP — handing your terminal to `grok login --device-auth`.'\n }\n}\n\nexport interface CliLoginLaunch {\n /** The interactive launch, spawned exactly like a `terminal` method's. */\n runtime: RuntimeDef\n reason: string\n}\n\n/** The CLI login that logs `runtimeId` in, or undefined when ACP `authenticate` is the way. */\nexport function cliLoginLaunch(runtimeId: string, methodId: string, runtime: RuntimeDef): CliLoginLaunch | undefined {\n const spec = CLI_LOGIN[runtimeId]\n if (!spec?.methods.includes(methodId)) return undefined\n const head = runtime.args.slice(0, runtime.args.length - spec.acpTail.length)\n const tail = runtime.args.slice(head.length)\n if (tail.length !== spec.acpTail.length || tail.some((arg, i) => arg !== spec.acpTail[i])) return undefined\n return { runtime: { ...runtime, args: [...head, ...spec.loginArgs] }, reason: spec.reason }\n}\n","/**\n * Arrow-key list for `agentconnect auth`.\n *\n * One flat list in a FIXED order: the login sweep launches every runtime and answers slowly, so a\n * verdict arrives as a per-row status rather than as a re-sort. A list that reorders itself under\n * the cursor is unusable. The same list drives both the runtime choice and the method choice.\n *\n * Deliberately dependency-free and stream-injected: the daemon ships no TUI library, and the key\n * decoding is what tests drive. Rendering redraws in place on a TTY and degrades to a plain list\n * when stdin is not a terminal, so a piped or CI invocation still shows what it would have offered.\n */\n\nexport interface PickerRow {\n id: string\n /** Display name, when there is one worth showing beside the id. */\n name?: string\n /** Trailing detail: the live login status, or what a method does. */\n hint?: string\n}\n\nexport interface PickerIo {\n input: NodeJS.ReadableStream & { isTTY?: boolean; setRawMode?: (raw: boolean) => void }\n output: NodeJS.WritableStream & { isTTY?: boolean }\n}\n\n/**\n * The rows to show, which may still be changing. Row ORDER is fixed for the life of the picker;\n * only each row's `hint` is expected to change, so the operator can select at any point —\n * including before the first verdict lands.\n */\nexport interface PickerModel {\n rows(): PickerRow[]\n /** Called on every change; returns its own unsubscribe. Absent means the list is final. */\n subscribe?: (listener: () => void) => () => void\n}\n\n/** A model for a list that will not change. */\nexport function fixedRows(rows: PickerRow[]): PickerModel {\n return { rows: () => rows }\n}\n\nconst ESC = '\\u001b'\nconst CTRL_C = '\\u0003'\n\nfunction label(row: PickerRow): string {\n const name = row.name && row.name !== row.id ? ` (${row.name})` : ''\n return `${row.id}${name}${row.hint ? ` — ${row.hint}` : ''}`\n}\n\n/** The list as lines, with `cursor` marked. Exported for tests and the non-TTY fallback. */\nexport function renderPicker(rows: PickerRow[], cursor: number): string[] {\n return rows.map((row, index) => `${index === cursor ? '❯' : ' '} ${label(row)}`)\n}\n\n/**\n * Show the list and resolve the chosen id, or undefined when the operator cancelled (q / Esc /\n * Ctrl-C). Non-TTY input prints the rows and resolves undefined — there is nothing to steer with,\n * and guessing a selection for someone is worse than saying so.\n */\nexport async function pickRow(model: PickerModel, io: PickerIo, prompt: string): Promise<string | undefined> {\n const write = (text: string): void => void io.output.write(text)\n if (model.rows().length === 0) return undefined\n\n if (!io.input.isTTY || !io.input.setRawMode) {\n for (const line of renderPicker(model.rows(), -1)) write(`${line}\\n`)\n return undefined\n }\n\n // The cursor follows the ROW ID, not the row number: the order is fixed, but a model is free to\n // grow, and an index would then point somewhere the operator never put it.\n let selected = model.rows()[0]!.id\n let painted = 0\n const paint = (): void => {\n const rows = model.rows()\n const cursor = Math.max(\n 0,\n rows.findIndex((row) => row.id === selected)\n )\n selected = rows[cursor]?.id ?? selected\n if (painted > 0) write(`${ESC}[${painted}A${ESC}[0J`)\n const lines = renderPicker(rows, cursor)\n write(`${lines.join('\\n')}\\n`)\n painted = lines.length\n }\n\n io.input.setRawMode(true)\n io.input.resume()\n if ('setEncoding' in io.input) (io.input as NodeJS.ReadStream).setEncoding('utf8')\n write(`${prompt} — ↑/↓ to move, Enter to select, q to cancel.\\n\\n`)\n paint()\n\n const unsubscribe = model.subscribe?.(paint)\n\n return await new Promise<string | undefined>((resolve) => {\n const finish = (value: string | undefined): void => {\n unsubscribe?.()\n io.input.removeListener('data', onData)\n io.input.setRawMode?.(false)\n io.input.pause()\n write('\\n')\n resolve(value)\n }\n const move = (delta: number): void => {\n const rows = model.rows()\n const at = Math.max(\n 0,\n rows.findIndex((row) => row.id === selected)\n )\n selected = rows[(at + delta + rows.length) % rows.length]!.id\n paint()\n }\n const onData = (chunk: string | Buffer): void => {\n const keys = typeof chunk === 'string' ? chunk : chunk.toString('utf8')\n // A single read can carry a whole escape sequence, or several keys at once when held down.\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n if (key === ESC && keys[i + 1] === '[') {\n const code = keys[i + 2]\n i += 2\n if (code === 'A') move(-1)\n else if (code === 'B') move(1)\n continue\n }\n if (key === ESC || key === CTRL_C || key === 'q') return finish(undefined)\n if (key === '\\r' || key === '\\n') return finish(selected)\n if (key === 'k') move(-1)\n else if (key === 'j') move(1)\n }\n }\n io.input.on('data', onData)\n })\n}\n","import { spawn } from 'node:child_process'\nimport { createInterface } from 'node:readline'\nimport type {\n AuthMethod,\n AuthMethodTerminal,\n CreateElicitationRequest,\n CreateElicitationResponse\n} from '@agentclientprotocol/sdk'\nimport { AcpHost } from '../acp/acp-host.js'\nimport { loadConfig } from '../config/load-config.js'\nimport { resolveRoot } from '../paths.js'\nimport { ArchiveStore, parseArchiveLaunch, storedArchiveRuntimeDef } from '../runtimes/archive-store.js'\nimport { cliLoginLaunch } from '../runtimes/cli-login.js'\nimport { installedRuntimeCatalog } from '../runtimes/probe.js'\nimport { probeAllRuntimes, type RuntimeProbeResult } from '../runtimes/runtime-prober.js'\nimport { defaultProbeHostFactory } from '../acp/probe-host-factory.js'\nimport { fixedRows, pickRow, type PickerIo, type PickerModel, type PickerRow } from './auth-picker.js'\nimport {\n CLI_ELICIT_SURFACE,\n elicitFieldLabel,\n elicitForm,\n elicitFormAccepts,\n elicitFormContent,\n elicitRequiredProps,\n fieldAccepts,\n type ElicitTarget\n} from '../slack/render.js'\nimport { resolveRuntimeCatalog, type ResolvedRuntimeCatalog } from '../runtimes/registry.js'\nimport type { RuntimeDef } from '../config/config-schema.js'\n\n/**\n * Interactive login for one runtime, run by the operator ON the daemon host.\n *\n * ACP gives an agent two ways to be logged in, and both need a human at a terminal, which is why\n * this is a CLI command and not something the daemon can do for itself:\n *\n * - `terminal` methods: the CLIENT re-launches the agent program as an interactive process (with\n * the method's extra args/env) and a zero exit means success. Agents may only offer these when\n * the client advertises `auth.terminal`, so a daemon session never sees them — this command does.\n * - `agent` methods (the default when a method carries no `type`): the agent runs its own flow\n * behind `authenticate`, asking through URL/form elicitation, or simply printing to its stderr.\n *\n * The runtime deliberately runs UNSANDBOXED against the operator's own HOME, exactly as if they had\n * run its CLI by hand: the credential must land in the host state dir that RUNTIME_STATE_LOCATIONS\n * seeds sessions FROM. A private-HOME launch would write the login into a directory that is thrown\n * away with the process.\n */\nexport interface RunAuthOpts {\n runtimeId?: string\n methodId?: string\n configPath?: string\n root?: string\n out?: NodeJS.WritableStream\n /** Test seams; production resolves the real catalog and spawns a real AcpHost. */\n resolveCatalog?: () => Promise<ResolvedRuntimeCatalog>\n installed?: (catalog: ResolvedRuntimeCatalog) => ResolvedRuntimeCatalog\n hostFactory?: (runtime: RuntimeDef, options: ConstructorParameters<typeof AcpHost>[1]) => AcpHost\n /** Test seam for the client-run `terminal` method; production spawns it on the real TTY. */\n runTerminalAuth?: (runtime: RuntimeDef, method: AuthMethod) => Promise<number>\n /** Test seams for the loopback-paste fallback: reading a line, and replaying the pasted URL.\n * An aborted `signal` must release a question already waiting on stdin, answering empty. */\n readLine?: (question: string, signal?: AbortSignal) => Promise<string>\n deliverLoopback?: (url: string) => Promise<void>\n /** How long to let an agent-run login settle before offering the paste fallback. */\n pasteAfterMs?: number\n /** Skip the login-state sweep and list every installed runtime in one group. */\n skipProbe?: boolean\n /** Test seams for the grouped picker. */\n probeRuntimes?: typeof probeAllRuntimes\n pick?: (model: PickerModel, io: PickerIo, prompt: string) => Promise<string | undefined>\n io?: PickerIo\n}\n\nfunction isTerminalMethod(method: AuthMethod): method is AuthMethodTerminal & { type: 'terminal' } {\n return 'type' in method && method.type === 'terminal'\n}\n\n/** Row detail for one login method: what it is, and who runs it. */\nfunction hintFor(method: AuthMethod): string {\n const kind = isTerminalMethod(method) ? 'in a terminal' : 'handled by the runtime'\n return `${method.description?.trim() || method.name} (${kind})`\n}\n\n/** Ask one line. An abort resolves it empty and closes the interface: a login that settles while\n * the operator is being prompted must not stay parked on stdin waiting for a keypress. */\nasync function readLine(question: string, signal?: AbortSignal): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n let onAbort: (() => void) | undefined\n try {\n return await new Promise<string>((resolve) => {\n if (signal?.aborted) return resolve('')\n onAbort = () => resolve('')\n signal?.addEventListener('abort', onAbort, { once: true })\n rl.question(question, resolve)\n })\n } finally {\n if (onAbort) signal?.removeEventListener('abort', onAbort)\n rl.close()\n }\n}\n\n/** Re-launch the agent program interactively on the operator's own terminal. */\nfunction spawnTerminalAuth(runtime: RuntimeDef, method: AuthMethod): Promise<number> {\n const extra = isTerminalMethod(method) ? { args: method.args, env: method.env } : {}\n const args = [...runtime.args, ...(extra.args ?? [])]\n const env = {\n ...process.env,\n ...Object.fromEntries(runtime.env.map((entry) => [entry.name, entry.value])),\n ...(extra.env ?? {})\n }\n return new Promise((resolve, reject) => {\n const child = spawn(runtime.command, args, { stdio: 'inherit', env })\n child.on('error', reject)\n child.on('exit', (code) => resolve(code ?? 1))\n })\n}\n\n/**\n * List the installed runtimes at once, then annotate each with whether it is logged in FOR THIS\n * OPERATOR as the verdicts arrive.\n *\n * The order is fixed the moment the list appears and never changes: the sweep launches every\n * runtime and answers over tens of seconds, so a verdict lands as a status on its own row rather\n * than moving it. A selection made before any verdict is honoured immediately.\n *\n * The status is a real probe, not a guess: nothing persists it (the daemon's `authRequired` lives\n * in its process, and its local store caches only model catalogs), and every on-disk heuristic\n * misreads a runtime that authenticates from an env var. The sweep runs the way this command logs\n * in — host HOME, unsandboxed — so \"logged in\" answers the question actually being asked.\n */\nasync function chooseRuntime(\n catalog: ResolvedRuntimeCatalog,\n root: string,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<string | undefined> {\n const ids = Object.keys(catalog.entries).sort()\n if (ids.length === 0) throw new Error('no runtimes are installed on this host')\n const io = opts.io ?? { input: process.stdin, output: process.stdout }\n const pick = opts.pick ?? pickRow\n const rowFor = (id: string, hint?: string): PickerRow => ({\n id,\n ...(catalog.entries[id]?.name ? { name: catalog.entries[id]!.name } : {}),\n ...(hint ? { hint } : {})\n })\n\n if (opts.skipProbe) {\n return pick(fixedRows(ids.map((id) => rowFor(id))), io, 'Select a runtime to log in')\n }\n\n const results = new Map<string, RuntimeProbeResult>()\n const listeners = new Set<() => void>()\n const statusFor = (id: string): string => {\n const result = results.get(id)\n if (!result) return 'checking…'\n if (result.ok) {\n const models = result.models.length > 0 ? `${result.models.length} model(s)` : 'no models offered'\n return `logged in — ${result.probedVersion ? `${models}, ${result.probedVersion}` : models}`\n }\n if (result.authRequired) return 'not logged in'\n return `not logged in — ${result.error ? result.error.slice(0, 60) : 'probe failed'}`\n }\n const model: PickerModel = {\n rows: () => ids.map((id) => rowFor(id, statusFor(id))),\n subscribe: (listener) => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n }\n }\n\n // Aborted the moment a runtime is chosen: nothing new is launched and every probe in flight\n // ends at once (runtime-prober races the signal), which is what makes the teardown below cheap\n // to wait for. The sweep is never awaited BEFORE a choice — that delay is what this list exists\n // to avoid.\n const sweep = new AbortController()\n const probe = opts.probeRuntimes ?? probeAllRuntimes\n const running = probe(Object.fromEntries(ids.map((id) => [id, catalog.entries[id]!.runtime])), {\n hostFactory: defaultProbeHostFactory({}),\n hostEnv: process.env,\n signal: sweep.signal,\n // The store owns an archive runtime's binary; probe what a login would actually launch.\n resolveRuntime: async (id, runtime) => {\n const entry = catalog.entries[id]\n const archive = entry ? parseArchiveLaunch(id, entry) : undefined\n if (!archive) return runtime\n return storedArchiveRuntimeDef(runtime, await new ArchiveStore({ root }).ensure(archive))\n },\n onResult: (result) => {\n results.set(result.runtime, result)\n for (const listener of listeners) listener()\n }\n })\n running.catch((err) => out.write(`login check failed: ${(err as Error).message}\\n`))\n\n try {\n return await pick(model, io, 'Select a runtime to log in')\n } finally {\n // Cancelled AND awaited: these probes are children of THIS process, and the CLI action exits\n // as soon as runAuth resolves, so a teardown nobody waited for leaves them running after the\n // command is gone. The abort ends each in-flight probe at once rather than at its deadline,\n // so waiting for it costs the operator nothing measurable.\n sweep.abort()\n await running.catch(() => undefined)\n }\n}\n\n// Long enough for a runtime to notice stdin EOF and exit on its own (Antigravity's ACP server\n// takes ~620ms), short enough that a wedged one still gets signalled promptly.\nconst EOF_GRACE_MS = 2500\n\n/** A loopback redirect the operator may replay locally: http(s) to 127.0.0.1/localhost, with a port. */\nfunction loopbackRedirect(value: string): URL | undefined {\n let url: URL\n try {\n url = new URL(value.trim())\n } catch {\n return undefined\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined\n if (url.hostname !== '127.0.0.1' && url.hostname !== 'localhost' && url.hostname !== '[::1]') return undefined\n if (url.username || url.password) return undefined\n return url\n}\n\n/**\n * Offer to finish a loopback OAuth login without a port forward.\n *\n * Google retired the copy/paste (OOB) flow in January 2023 and pointed desktop clients at the\n * loopback IP flow instead, so a runtime like Antigravity binds an HTTP server to 127.0.0.1 on the\n * DAEMON host and waits for the browser to be redirected there. On a headless host the browser\n * cannot reach it — but the redirect still happens, and the full `?code=…&state=…` URL is sitting\n * in the address bar of the tab that failed to load. Replaying that URL from this process, which\n * does run on the daemon host, hands the code to the waiting listener.\n *\n * Resolves as soon as the login settles; the prompt is only offered while it is still pending, so a\n * login completed through a port forward (or one that needed no browser at all) never sees it.\n */\nasync function offerLoopbackPaste(login: Promise<void>, opts: RunAuthOpts, out: NodeJS.WritableStream): Promise<void> {\n const ask = opts.readLine ?? readLine\n const deliver =\n opts.deliverLoopback ??\n (async (url: string) => {\n const res = await fetch(url, { redirect: 'manual', signal: AbortSignal.timeout(15_000) })\n // Any answer means the listener took the request; its body is a browser page, not our business.\n if (res.status >= 500) throw new Error(`the local listener answered HTTP ${res.status}`)\n })\n\n // The prompt is racing the login itself, so it gets a signal rather than a flag: a resolved\n // login has to close the readline question, which no amount of polling `settled` can do.\n let settled = false\n const done = new AbortController()\n const finish = (): void => {\n settled = true\n done.abort()\n }\n void login.then(finish, finish)\n await Promise.race([login.catch(() => undefined), new Promise((r) => setTimeout(r, opts.pasteAfterMs ?? 3000))])\n if (settled) return\n\n out.write('\\nIf the browser could not reach the redirect (this host is headless, no port forward),\\n')\n out.write('copy the URL of the tab that failed to load and paste it here — it carries the code.\\n')\n while (!settled) {\n const answer = (await ask('\\nRedirect URL (Enter to keep waiting): ', done.signal)).trim()\n if (settled || answer === '') return\n const url = loopbackRedirect(answer)\n if (!url) {\n out.write('That is not a loopback redirect URL (expected http://127.0.0.1:<port>/…). Ignored.\\n')\n continue\n }\n try {\n await deliver(url.toString())\n out.write('Delivered to the local listener; waiting for the runtime to finish…\\n')\n return\n } catch (err) {\n out.write(`Could not reach the local listener: ${(err as Error).message}\\n`)\n }\n }\n}\n\n/** Split a typed multi-select answer into the values the schema will be checked against. */\nfunction splitValues(line: string): string[] {\n return line\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value !== '')\n}\n\n/** The most times one field is re-asked before it is left unanswered — a typo deserves another\n * go, an operator who cannot satisfy the schema deserves to be let out of the loop. */\nconst FIELD_ATTEMPTS = 3\n\n/**\n * Ask one reduced field on the terminal, or return undefined when it was left unanswered.\n *\n * The pickable kinds are chosen from the options the AGENT offered, so a typo cannot invent a\n * value it never asked for; text, number and multi-select are typed and re-asked while the\n * field's own schema refuses them ({@link fieldAccepts} — the same gate the answer is checked\n * against, applied here so the refusal is explainable rather than a late blanket decline).\n */\nasync function askField(\n target: ElicitTarget,\n label: string,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<string | number | string[] | undefined> {\n if (target.kind === 'enum' || target.kind === 'boolean') {\n const io = opts.io ?? { input: process.stdin, output: process.stdout }\n const rows = target.options.map((option) => ({ id: option.value, name: option.label }))\n return await (opts.pick ?? pickRow)(fixedRows(rows), io, label)\n }\n\n const ask = opts.readLine ?? readLine\n if (target.kind === 'multi-enum') {\n out.write(`\\n${label} — one or more of: ${target.options.map((option) => option.value).join(', ')}\\n`)\n } else {\n out.write(`\\n${label}\\n`)\n }\n const prompt = target.kind === 'multi-enum' ? 'Values (comma-separated, empty to skip): ' : 'Value (empty to skip): '\n for (let attempt = 0; attempt < FIELD_ATTEMPTS; attempt++) {\n const line = (await ask(prompt)).trim()\n if (line === '') return undefined\n const value = target.kind === 'multi-enum' ? splitValues(line) : target.kind === 'number' ? Number(line) : line\n if (fieldAccepts(target, value)) return value\n out.write(`That is not a value ${target.propName} accepts.\\n`)\n }\n return undefined\n}\n\n/**\n * Answer a form elicitation with the properties the agent's own `requestedSchema` asked for.\n *\n * The reduction is the shared one — {@link elicitForm} over {@link CLI_ELICIT_SURFACE} — so this\n * terminal answers under the schema's own property names and types, and a form carrying a\n * required field it cannot render is declined whole rather than half-answered. An accept keyed\n * on anything else (a fixed `{type,text}`, say) is an answer the runtime never asked for: a\n * request for `projectId` would come back without one and the login would fail on it.\n */\nasync function answerAuthForm(\n params: CreateElicitationRequest,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<CreateElicitationResponse | undefined> {\n const form = elicitForm(params, CLI_ELICIT_SURFACE)\n if (!form) {\n out.write('\\nThe runtime asked for input this terminal cannot render whole — declining.\\n')\n return undefined\n }\n const message = (params as { message?: unknown }).message\n if (typeof message === 'string' && message.trim()) out.write(`\\n${message.trim()}\\n`)\n\n const answer: Record<string, string | number | string[]> = {}\n for (const target of form) {\n const value = await askField(target, elicitFieldLabel(params, target.propName), opts, out)\n if (value !== undefined) answer[target.propName] = value\n }\n // Nothing typed is a decline, not an empty accept: the spec has agents handle `decline`, and\n // an empty accept would report \"answered\" for a question the operator walked away from.\n if (Object.keys(answer).length === 0) return undefined\n if (!elicitFormAccepts(form, elicitRequiredProps(params), answer)) {\n out.write('\\nDeclined — the runtime needs every required field answered.\\n')\n return undefined\n }\n return { action: 'accept', content: elicitFormContent(form, answer) } as CreateElicitationResponse\n}\n\nexport async function runAuth(opts: RunAuthOpts): Promise<void> {\n const out = opts.out ?? process.stdout\n const root = resolveRoot(opts.root)\n const cfg = loadConfig({ root: opts.root, configPath: opts.configPath, optional: true })\n\n const resolved = opts.resolveCatalog\n ? await opts.resolveCatalog()\n : await resolveRuntimeCatalog(cfg, root, {\n ...(opts.runtimeId ? { neededRuntimes: [opts.runtimeId] } : {}),\n mode: 'cache-first'\n })\n const catalog = opts.installed ? opts.installed(resolved) : installedRuntimeCatalog(resolved)\n\n const runtimeId = opts.runtimeId ?? (await chooseRuntime(catalog, root, opts, out))\n if (!runtimeId) return\n\n const entry = catalog.entries[runtimeId]\n if (!entry) {\n const ids = Object.keys(catalog.entries).sort().join(', ') || '(none)'\n throw new Error(`runtime \"${runtimeId}\" is not installed on this host. Available: ${ids}`)\n }\n\n // Same store the daemon launches from: a vendor-archive runtime is not launchable until it is\n // extracted, and a login against a different binary than the sessions run would be a lie.\n const archive = parseArchiveLaunch(runtimeId, entry)\n const runtime = archive\n ? storedArchiveRuntimeDef(\n entry.runtime,\n await new ArchiveStore({\n root,\n log: { info: (message) => out.write(`${message}\\n`), warn: (message) => out.write(`${message}\\n`) }\n }).ensure(archive)\n )\n : entry.runtime\n\n const hostOptions: ConstructorParameters<typeof AcpHost>[1] = {\n onUpdate: () => {},\n runtimeId: runtimeId,\n isolateAccountApps: cfg.security.isolateAccountApps,\n authTerminalCapable: true,\n // The agent's own flow speaks through these two channels, and its stderr — which stays\n // unsuppressed here, because a runtime that prints a consent link has nowhere else to put it.\n onAuthElicit: async (params: CreateElicitationRequest): Promise<CreateElicitationResponse | undefined> => {\n const url = (params as { url?: unknown }).url\n if (typeof url === 'string') {\n out.write(`\\nOpen this URL to continue signing in:\\n\\n ${url}\\n\\n`)\n out.write('Waiting for the runtime to confirm…\\n')\n return { action: 'accept' } as CreateElicitationResponse\n }\n return await answerAuthForm(params, opts, out)\n }\n }\n const host = opts.hostFactory ? opts.hostFactory(runtime, hostOptions) : new AcpHost(runtime, hostOptions)\n\n const onSigint = (): void => {\n void host.stop(5000, EOF_GRACE_MS).finally(() => process.exit(130))\n }\n process.once('SIGINT', onSigint)\n try {\n out.write(`Starting ${runtimeId}…\\n`)\n await host.start()\n const methods = host.authMethods()\n if (methods.length === 0) {\n out.write(`${runtimeId} advertises no login methods — it either needs none or reads a credential from env.\\n`)\n return\n }\n\n let method = opts.methodId ? methods.find((m) => m.id === opts.methodId) : undefined\n if (opts.methodId && !method) {\n throw new Error(\n `\"${opts.methodId}\" is not offered by ${runtimeId}. Offered: ${methods.map((m) => m.id).join(', ')}`\n )\n }\n if (!method) {\n if (methods.length === 1) method = methods[0]!\n else {\n // The same arrow-key list the runtime was chosen from: a login is no place to make someone\n // retype an identifier they can already see.\n const rows = methods.map((entry) => ({ id: entry.id, name: entry.name, hint: hintFor(entry) }))\n const answer = await (opts.pick ?? pickRow)(\n fixedRows(rows),\n opts.io ?? { input: process.stdin, output: process.stdout },\n `How do you want to log in to ${runtimeId}?`\n )\n if (!answer) return\n method = methods.find((m) => m.id === answer)\n if (!method) throw new Error(`\"${answer}\" is not one of the offered methods`)\n }\n }\n out.write(`Using ${method.id} — ${method.name}\\n`)\n\n // A runtime that cannot finish this login over ACP is driven through its own CLI instead —\n // same handover as a `terminal` method, on a launch that names the login subcommand.\n const cli = cliLoginLaunch(runtimeId, method.id, runtime)\n if (isTerminalMethod(method) || cli) {\n // The client owns this one: hand the operator's terminal to the agent program itself.\n if (cli) out.write(`${cli.reason}\\n`)\n await host.stop(5000, EOF_GRACE_MS)\n const code = await (opts.runTerminalAuth ?? spawnTerminalAuth)(cli?.runtime ?? runtime, method)\n if (code !== 0) throw new Error(`interactive login exited with code ${code}`)\n } else {\n const login = host.authenticate(method.id)\n await offerLoopbackPaste(login, opts, out)\n await login\n }\n\n out.write(`\\n✓ ${runtimeId} is logged in on this host.\\n`)\n out.write('Sessions pick the credential up on their next start — the daemon needs no restart.\\n')\n } finally {\n process.removeListener('SIGINT', onSigint)\n // Graceful: a runtime that exits on stdin EOF then prints nothing. Some (Antigravity's ACP\n // server) install a signal handler that dumps a full stack trace over the operator's terminal\n // on SIGTERM, which reads like a crash right after a login that in fact succeeded.\n await host.stop(5000, EOF_GRACE_MS).catch(() => undefined)\n }\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,YAA0C,EAK9C,cAAc;CACZ,SAAS,CAAC,UAAU;CACpB,SAAS,CAAC,SAAS,OAAO;CAC1B,WAAW,CAAC,SAAS,eAAe;CACpC,QAAQ;AACV,EACF;;AASA,SAAgB,eAAe,WAAmB,UAAkB,SAAiD;CACnH,MAAM,OAAO,UAAU;CACvB,IAAI,CAAC,MAAM,QAAQ,SAAS,QAAQ,GAAG,OAAO,KAAA;CAC9C,MAAM,OAAO,QAAQ,KAAK,MAAM,GAAG,QAAQ,KAAK,SAAS,KAAK,QAAQ,MAAM;CAC5E,MAAM,OAAO,QAAQ,KAAK,MAAM,KAAK,MAAM;CAC3C,IAAI,KAAK,WAAW,KAAK,QAAQ,UAAU,KAAK,MAAM,KAAK,MAAM,QAAQ,KAAK,QAAQ,EAAE,GAAG,OAAO,KAAA;CAClG,OAAO;EAAE,SAAS;GAAE,GAAG;GAAS,MAAM,CAAC,GAAG,MAAM,GAAG,KAAK,SAAS;EAAE;EAAG,QAAQ,KAAK;CAAO;AAC5F;;;;ACRA,SAAgB,UAAU,MAAgC;CACxD,OAAO,EAAE,YAAY,KAAK;AAC5B;AAEA,MAAM,MAAM;AACZ,MAAM,SAAS;AAEf,SAAS,MAAM,KAAwB;CACrC,MAAM,OAAO,IAAI,QAAQ,IAAI,SAAS,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK;CAClE,OAAO,GAAG,IAAI,KAAK,OAAO,IAAI,OAAO,MAAM,IAAI,SAAS;AAC1D;;AAGA,SAAgB,aAAa,MAAmB,QAA0B;CACxE,OAAO,KAAK,KAAK,KAAK,UAAU,GAAG,UAAU,SAAS,MAAM,IAAI,GAAG,MAAM,GAAG,GAAG;AACjF;;;;;;AAOA,eAAsB,QAAQ,OAAoB,IAAc,QAA6C;CAC3G,MAAM,SAAS,SAAuB,KAAK,GAAG,OAAO,MAAM,IAAI;CAC/D,IAAI,MAAM,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO,KAAA;CAEtC,IAAI,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,MAAM,YAAY;EAC3C,KAAK,MAAM,QAAQ,aAAa,MAAM,KAAK,GAAG,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG;EACpE;CACF;CAIA,IAAI,WAAW,MAAM,KAAK,CAAC,CAAC,EAAE,CAAE;CAChC,IAAI,UAAU;CACd,MAAM,cAAoB;EACxB,MAAM,OAAO,MAAM,KAAK;EACxB,MAAM,SAAS,KAAK,IAClB,GACA,KAAK,WAAW,QAAQ,IAAI,OAAO,QAAQ,CAC7C;EACA,WAAW,KAAK,OAAO,EAAE,MAAM;EAC/B,IAAI,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,IAAI;EACpD,MAAM,QAAQ,aAAa,MAAM,MAAM;EACvC,MAAM,GAAG,MAAM,KAAK,IAAI,EAAE,GAAG;EAC7B,UAAU,MAAM;CAClB;CAEA,GAAG,MAAM,WAAW,IAAI;CACxB,GAAG,MAAM,OAAO;CAChB,IAAI,iBAAiB,GAAG,OAAO,GAAI,MAA4B,YAAY,MAAM;CACjF,MAAM,GAAG,OAAO,kDAAkD;CAClE,MAAM;CAEN,MAAM,cAAc,MAAM,YAAY,KAAK;CAE3C,OAAO,MAAM,IAAI,SAA6B,YAAY;EACxD,MAAM,UAAU,UAAoC;GAClD,cAAc;GACd,GAAG,MAAM,eAAe,QAAQ,MAAM;GACtC,GAAG,MAAM,aAAa,KAAK;GAC3B,GAAG,MAAM,MAAM;GACf,MAAM,IAAI;GACV,QAAQ,KAAK;EACf;EACA,MAAM,QAAQ,UAAwB;GACpC,MAAM,OAAO,MAAM,KAAK;GAKxB,WAAW,MAJA,KAAK,IACd,GACA,KAAK,WAAW,QAAQ,IAAI,OAAO,QAAQ,CAE3B,IAAI,QAAQ,KAAK,UAAU,KAAK,OAAO,CAAE;GAC3D,MAAM;EACR;EACA,MAAM,UAAU,UAAiC;GAC/C,MAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,MAAM,SAAS,MAAM;GAEtE,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;IACpC,MAAM,MAAM,KAAK;IACjB,IAAI,QAAQ,OAAO,KAAK,IAAI,OAAO,KAAK;KACtC,MAAM,OAAO,KAAK,IAAI;KACtB,KAAK;KACL,IAAI,SAAS,KAAK,KAAK,EAAE;UACpB,IAAI,SAAS,KAAK,KAAK,CAAC;KAC7B;IACF;IACA,IAAI,QAAQ,OAAO,QAAQ,UAAU,QAAQ,KAAK,OAAO,OAAO,KAAA,CAAS;IACzE,IAAI,QAAQ,QAAQ,QAAQ,MAAM,OAAO,OAAO,QAAQ;IACxD,IAAI,QAAQ,KAAK,KAAK,EAAE;SACnB,IAAI,QAAQ,KAAK,KAAK,CAAC;GAC9B;EACF;EACA,GAAG,MAAM,GAAG,QAAQ,MAAM;CAC5B,CAAC;AACH;;;AC1DA,SAAS,iBAAiB,QAAyE;CACjG,OAAO,UAAU,UAAU,OAAO,SAAS;AAC7C;;AAGA,SAAS,QAAQ,QAA4B;CAC3C,MAAM,OAAO,iBAAiB,MAAM,IAAI,kBAAkB;CAC1D,OAAO,GAAG,OAAO,aAAa,KAAK,KAAK,OAAO,KAAK,IAAI,KAAK;AAC/D;;;AAIA,eAAe,SAAS,UAAkB,QAAuC;CAC/E,MAAM,KAAK,gBAAgB;EAAE,OAAO,QAAQ;EAAO,QAAQ,QAAQ;CAAO,CAAC;CAC3E,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,SAAiB,YAAY;GAC5C,IAAI,QAAQ,SAAS,OAAO,QAAQ,EAAE;GACtC,gBAAgB,QAAQ,EAAE;GAC1B,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GACzD,GAAG,SAAS,UAAU,OAAO;EAC/B,CAAC;CACH,UAAU;EACR,IAAI,SAAS,QAAQ,oBAAoB,SAAS,OAAO;EACzD,GAAG,MAAM;CACX;AACF;;AAGA,SAAS,kBAAkB,SAAqB,QAAqC;CACnF,MAAM,QAAQ,iBAAiB,MAAM,IAAI;EAAE,MAAM,OAAO;EAAM,KAAK,OAAO;CAAI,IAAI,CAAC;CACnF,MAAM,OAAO,CAAC,GAAG,QAAQ,MAAM,GAAI,MAAM,QAAQ,CAAC,CAAE;CACpD,MAAM,MAAM;EACV,GAAG,QAAQ;EACX,GAAG,OAAO,YAAY,QAAQ,IAAI,KAAK,UAAU,CAAC,MAAM,MAAM,MAAM,KAAK,CAAC,CAAC;EAC3E,GAAI,MAAM,OAAO,CAAC;CACpB;CACA,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,QAAQ,SAAS,MAAM;GAAE,OAAO;GAAW;EAAI,CAAC;EACpE,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,SAAS,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAC/C,CAAC;AACH;;;;;;;;;;;;;;AAeA,eAAe,cACb,SACA,MACA,MACA,KAC6B;CAC7B,MAAM,MAAM,OAAO,KAAK,QAAQ,OAAO,CAAC,CAAC,KAAK;CAC9C,IAAI,IAAI,WAAW,GAAG,MAAM,IAAI,MAAM,wCAAwC;CAC9E,MAAM,KAAK,KAAK,MAAM;EAAE,OAAO,QAAQ;EAAO,QAAQ,QAAQ;CAAO;CACrE,MAAM,OAAO,KAAK,QAAQ;CAC1B,MAAM,UAAU,IAAY,UAA8B;EACxD;EACA,GAAI,QAAQ,QAAQ,GAAG,EAAE,OAAO,EAAE,MAAM,QAAQ,QAAQ,GAAG,CAAE,KAAK,IAAI,CAAC;EACvE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CACzB;CAEA,IAAI,KAAK,WACP,OAAO,KAAK,UAAU,IAAI,KAAK,OAAO,OAAO,EAAE,CAAC,CAAC,GAAG,IAAI,4BAA4B;CAGtF,MAAM,0BAAU,IAAI,IAAgC;CACpD,MAAM,4BAAY,IAAI,IAAgB;CACtC,MAAM,aAAa,OAAuB;EACxC,MAAM,SAAS,QAAQ,IAAI,EAAE;EAC7B,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,OAAO,IAAI;GACb,MAAM,SAAS,OAAO,OAAO,SAAS,IAAI,GAAG,OAAO,OAAO,OAAO,aAAa;GAC/E,OAAO,eAAe,OAAO,gBAAgB,GAAG,OAAO,IAAI,OAAO,kBAAkB;EACtF;EACA,IAAI,OAAO,cAAc,OAAO;EAChC,OAAO,mBAAmB,OAAO,QAAQ,OAAO,MAAM,MAAM,GAAG,EAAE,IAAI;CACvE;CACA,MAAM,QAAqB;EACzB,YAAY,IAAI,KAAK,OAAO,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC;EACrD,YAAY,aAAa;GACvB,UAAU,IAAI,QAAQ;GACtB,aAAa,UAAU,OAAO,QAAQ;EACxC;CACF;CAMA,MAAM,QAAQ,IAAI,gBAAgB;CAElC,MAAM,WADQ,KAAK,iBAAiB,iBAAA,CACd,OAAO,YAAY,IAAI,KAAK,OAAO,CAAC,IAAI,QAAQ,QAAQ,GAAG,CAAE,OAAO,CAAC,CAAC,GAAG;EAC7F,aAAa,wBAAwB,CAAC,CAAC;EACvC,SAAS,QAAQ;EACjB,QAAQ,MAAM;EAEd,gBAAgB,OAAO,IAAI,YAAY;GACrC,MAAM,QAAQ,QAAQ,QAAQ;GAC9B,MAAM,UAAU,QAAQ,mBAAmB,IAAI,KAAK,IAAI,KAAA;GACxD,IAAI,CAAC,SAAS,OAAO;GACrB,OAAO,wBAAwB,SAAS,MAAM,IAAI,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC;EAC1F;EACA,WAAW,WAAW;GACpB,QAAQ,IAAI,OAAO,SAAS,MAAM;GAClC,KAAK,MAAM,YAAY,WAAW,SAAS;EAC7C;CACF,CAAC;CACD,QAAQ,OAAO,QAAQ,IAAI,MAAM,uBAAwB,IAAc,QAAQ,GAAG,CAAC;CAEnF,IAAI;EACF,OAAO,MAAM,KAAK,OAAO,IAAI,4BAA4B;CAC3D,UAAU;EAKR,MAAM,MAAM;EACZ,MAAM,QAAQ,YAAY,KAAA,CAAS;CACrC;AACF;AAIA,MAAM,eAAe;;AAGrB,SAAS,iBAAiB,OAAgC;CACxD,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC;CAC5B,QAAQ;EACN;CACF;CACA,IAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAAU,OAAO,KAAA;CAClE,IAAI,IAAI,aAAa,eAAe,IAAI,aAAa,eAAe,IAAI,aAAa,SAAS,OAAO,KAAA;CACrG,IAAI,IAAI,YAAY,IAAI,UAAU,OAAO,KAAA;CACzC,OAAO;AACT;;;;;;;;;;;;;;AAeA,eAAe,mBAAmB,OAAsB,MAAmB,KAA2C;CACpH,MAAM,MAAM,KAAK,YAAY;CAC7B,MAAM,UACJ,KAAK,oBACJ,OAAO,QAAgB;EACtB,MAAM,MAAM,MAAM,MAAM,KAAK;GAAE,UAAU;GAAU,QAAQ,YAAY,QAAQ,IAAM;EAAE,CAAC;EAExF,IAAI,IAAI,UAAU,KAAK,MAAM,IAAI,MAAM,oCAAoC,IAAI,QAAQ;CACzF;CAIF,IAAI,UAAU;CACd,MAAM,OAAO,IAAI,gBAAgB;CACjC,MAAM,eAAqB;EACzB,UAAU;EACV,KAAK,MAAM;CACb;CACA,MAAW,KAAK,QAAQ,MAAM;CAC9B,MAAM,QAAQ,KAAK,CAAC,MAAM,YAAY,KAAA,CAAS,GAAG,IAAI,SAAS,MAAM,WAAW,GAAG,KAAK,gBAAgB,GAAI,CAAC,CAAC,CAAC;CAC/G,IAAI,SAAS;CAEb,IAAI,MAAM,2FAA2F;CACrG,IAAI,MAAM,wFAAwF;CAClG,OAAO,CAAC,SAAS;EACf,MAAM,UAAU,MAAM,IAAI,4CAA4C,KAAK,MAAM,EAAA,CAAG,KAAK;EACzF,IAAI,WAAW,WAAW,IAAI;EAC9B,MAAM,MAAM,iBAAiB,MAAM;EACnC,IAAI,CAAC,KAAK;GACR,IAAI,MAAM,sFAAsF;GAChG;EACF;EACA,IAAI;GACF,MAAM,QAAQ,IAAI,SAAS,CAAC;GAC5B,IAAI,MAAM,uEAAuE;GACjF;EACF,SAAS,KAAK;GACZ,IAAI,MAAM,uCAAwC,IAAc,QAAQ,GAAG;EAC7E;CACF;AACF;;AAGA,SAAS,YAAY,MAAwB;CAC3C,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,KAAK,UAAU,MAAM,KAAK,CAAC,CAAC,CAC5B,QAAQ,UAAU,UAAU,EAAE;AACnC;;;AAIA,MAAM,iBAAiB;;;;;;;;;AAUvB,eAAe,SACb,QACA,OACA,MACA,KACiD;CACjD,IAAI,OAAO,SAAS,UAAU,OAAO,SAAS,WAAW;EACvD,MAAM,KAAK,KAAK,MAAM;GAAE,OAAO,QAAQ;GAAO,QAAQ,QAAQ;EAAO;EACrE,MAAM,OAAO,OAAO,QAAQ,KAAK,YAAY;GAAE,IAAI,OAAO;GAAO,MAAM,OAAO;EAAM,EAAE;EACtF,OAAO,OAAO,KAAK,QAAQ,QAAA,CAAS,UAAU,IAAI,GAAG,IAAI,KAAK;CAChE;CAEA,MAAM,MAAM,KAAK,YAAY;CAC7B,IAAI,OAAO,SAAS,cAClB,IAAI,MAAM,KAAK,MAAM,qBAAqB,OAAO,QAAQ,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,GAAG;MAErG,IAAI,MAAM,KAAK,MAAM,GAAG;CAE1B,MAAM,SAAS,OAAO,SAAS,eAAe,8CAA8C;CAC5F,KAAK,IAAI,UAAU,GAAG,UAAU,gBAAgB,WAAW;EACzD,MAAM,QAAQ,MAAM,IAAI,MAAM,EAAA,CAAG,KAAK;EACtC,IAAI,SAAS,IAAI,OAAO,KAAA;EACxB,MAAM,QAAQ,OAAO,SAAS,eAAe,YAAY,IAAI,IAAI,OAAO,SAAS,WAAW,OAAO,IAAI,IAAI;EAC3G,IAAI,aAAa,QAAQ,KAAK,GAAG,OAAO;EACxC,IAAI,MAAM,uBAAuB,OAAO,SAAS,YAAY;CAC/D;AAEF;;;;;;;;;;AAWA,eAAe,eACb,QACA,MACA,KACgD;CAChD,MAAM,OAAO,WAAW,QAAQ,kBAAkB;CAClD,IAAI,CAAC,MAAM;EACT,IAAI,MAAM,gFAAgF;EAC1F;CACF;CACA,MAAM,UAAW,OAAiC;CAClD,IAAI,OAAO,YAAY,YAAY,QAAQ,KAAK,GAAG,IAAI,MAAM,KAAK,QAAQ,KAAK,EAAE,GAAG;CAEpF,MAAM,SAAqD,CAAC;CAC5D,KAAK,MAAM,UAAU,MAAM;EACzB,MAAM,QAAQ,MAAM,SAAS,QAAQ,iBAAiB,QAAQ,OAAO,QAAQ,GAAG,MAAM,GAAG;EACzF,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,YAAY;CACrD;CAGA,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GAAG,OAAO,KAAA;CAC7C,IAAI,CAAC,kBAAkB,MAAM,oBAAoB,MAAM,GAAG,MAAM,GAAG;EACjE,IAAI,MAAM,iEAAiE;EAC3E;CACF;CACA,OAAO;EAAE,QAAQ;EAAU,SAAS,kBAAkB,MAAM,MAAM;CAAE;AACtE;AAEA,eAAsB,QAAQ,MAAkC;CAC9D,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,MAAM,MAAM,WAAW;EAAE,MAAM,KAAK;EAAM,YAAY,KAAK;EAAY,UAAU;CAAK,CAAC;CAEvF,MAAM,WAAW,KAAK,iBAClB,MAAM,KAAK,eAAe,IAC1B,MAAM,sBAAsB,KAAK,MAAM;EACrC,GAAI,KAAK,YAAY,EAAE,gBAAgB,CAAC,KAAK,SAAS,EAAE,IAAI,CAAC;EAC7D,MAAM;CACR,CAAC;CACL,MAAM,UAAU,KAAK,YAAY,KAAK,UAAU,QAAQ,IAAI,wBAAwB,QAAQ;CAE5F,MAAM,YAAY,KAAK,aAAc,MAAM,cAAc,SAAS,MAAM,MAAM,GAAG;CACjF,IAAI,CAAC,WAAW;CAEhB,MAAM,QAAQ,QAAQ,QAAQ;CAC9B,IAAI,CAAC,OAAO;EACV,MAAM,MAAM,OAAO,KAAK,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,KAAK;EAC9D,MAAM,IAAI,MAAM,YAAY,UAAU,8CAA8C,KAAK;CAC3F;CAIA,MAAM,UAAU,mBAAmB,WAAW,KAAK;CACnD,MAAM,UAAU,UACZ,wBACE,MAAM,SACN,MAAM,IAAI,aAAa;EACrB;EACA,KAAK;GAAE,OAAO,YAAY,IAAI,MAAM,GAAG,QAAQ,GAAG;GAAG,OAAO,YAAY,IAAI,MAAM,GAAG,QAAQ,GAAG;EAAE;CACpG,CAAC,CAAC,CAAC,OAAO,OAAO,CACnB,IACA,MAAM;CAEV,MAAM,cAAwD;EAC5D,gBAAgB,CAAC;EACN;EACX,oBAAoB,IAAI,SAAS;EACjC,qBAAqB;EAGrB,cAAc,OAAO,WAAqF;GACxG,MAAM,MAAO,OAA6B;GAC1C,IAAI,OAAO,QAAQ,UAAU;IAC3B,IAAI,MAAM,gDAAgD,IAAI,KAAK;IACnE,IAAI,MAAM,uCAAuC;IACjD,OAAO,EAAE,QAAQ,SAAS;GAC5B;GACA,OAAO,MAAM,eAAe,QAAQ,MAAM,GAAG;EAC/C;CACF;CACA,MAAM,OAAO,KAAK,cAAc,KAAK,YAAY,SAAS,WAAW,IAAI,IAAI,QAAQ,SAAS,WAAW;CAEzG,MAAM,iBAAuB;EAC3B,KAAU,KAAK,KAAM,YAAY,CAAC,CAAC,cAAc,QAAQ,KAAK,GAAG,CAAC;CACpE;CACA,QAAQ,KAAK,UAAU,QAAQ;CAC/B,IAAI;EACF,IAAI,MAAM,YAAY,UAAU,IAAI;EACpC,MAAM,KAAK,MAAM;EACjB,MAAM,UAAU,KAAK,YAAY;EACjC,IAAI,QAAQ,WAAW,GAAG;GACxB,IAAI,MAAM,GAAG,UAAU,sFAAsF;GAC7G;EACF;EAEA,IAAI,SAAS,KAAK,WAAW,QAAQ,MAAM,MAAM,EAAE,OAAO,KAAK,QAAQ,IAAI,KAAA;EAC3E,IAAI,KAAK,YAAY,CAAC,QACpB,MAAM,IAAI,MACR,IAAI,KAAK,SAAS,sBAAsB,UAAU,aAAa,QAAQ,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,GACnG;EAEF,IAAI,CAAC,QACH,IAAI,QAAQ,WAAW,GAAG,SAAS,QAAQ;OACtC;GAGH,MAAM,OAAO,QAAQ,KAAK,WAAW;IAAE,IAAI,MAAM;IAAI,MAAM,MAAM;IAAM,MAAM,QAAQ,KAAK;GAAE,EAAE;GAC9F,MAAM,SAAS,OAAO,KAAK,QAAQ,QAAA,CACjC,UAAU,IAAI,GACd,KAAK,MAAM;IAAE,OAAO,QAAQ;IAAO,QAAQ,QAAQ;GAAO,GAC1D,gCAAgC,UAAU,EAC5C;GACA,IAAI,CAAC,QAAQ;GACb,SAAS,QAAQ,MAAM,MAAM,EAAE,OAAO,MAAM;GAC5C,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,IAAI,OAAO,oCAAoC;EAC9E;EAEF,IAAI,MAAM,SAAS,OAAO,GAAG,KAAK,OAAO,KAAK,GAAG;EAIjD,MAAM,MAAM,eAAe,WAAW,OAAO,IAAI,OAAO;EACxD,IAAI,iBAAiB,MAAM,KAAK,KAAK;GAEnC,IAAI,KAAK,IAAI,MAAM,GAAG,IAAI,OAAO,GAAG;GACpC,MAAM,KAAK,KAAK,KAAM,YAAY;GAClC,MAAM,OAAO,OAAO,KAAK,mBAAmB,kBAAA,CAAmB,KAAK,WAAW,SAAS,MAAM;GAC9F,IAAI,SAAS,GAAG,MAAM,IAAI,MAAM,sCAAsC,MAAM;EAC9E,OAAO;GACL,MAAM,QAAQ,KAAK,aAAa,OAAO,EAAE;GACzC,MAAM,mBAAmB,OAAO,MAAM,GAAG;GACzC,MAAM;EACR;EAEA,IAAI,MAAM,OAAO,UAAU,8BAA8B;EACzD,IAAI,MAAM,sFAAsF;CAClG,UAAU;EACR,QAAQ,eAAe,UAAU,QAAQ;EAIzC,MAAM,KAAK,KAAK,KAAM,YAAY,CAAC,CAAC,YAAY,KAAA,CAAS;CAC3D;AACF"}
package/dist/index.js CHANGED
@@ -58909,7 +58909,7 @@ program.command("chat [message]").description("Discover an agent under --agents-
58909
58909
  program.command("auth").description("Log a runtime in on this host (ACP authenticate, or the runtime's own interactive login)").option("--runtime <id>", "runtime to log in; omit to list what is installed here").option("--method <id>", "login method to use; omit to be shown what the runtime offers").option("--skip-probe", "skip the login-state check and list every installed runtime").action(async (cmd) => {
58910
58910
  const opts = program.opts();
58911
58911
  try {
58912
- const { runAuth } = await import("./auth-Cj3OPO5i.js");
58912
+ const { runAuth } = await import("./auth-DdXGZ3VX.js");
58913
58913
  await runAuth({
58914
58914
  ...cmd.runtime ? { runtimeId: cmd.runtime } : {},
58915
58915
  ...cmd.method ? { methodId: cmd.method } : {},
package/dist/release.json CHANGED
@@ -1 +1 @@
1
- {"runtimeSandboxImage":"ghcr.io/agentconnect-md/runtime-sandbox-full:v1.56.0-rc.28"}
1
+ {"runtimeSandboxImage":"ghcr.io/agentconnect-md/runtime-sandbox-full:v1.56.0-rc.29"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentconnect.md/daemon",
3
- "version": "1.56.0-rc.28",
3
+ "version": "1.56.0-rc.29",
4
4
  "description": "AgentConnect daemon — edge message + agent execution unit",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-Cj3OPO5i.js","names":[],"sources":["../src/cli/auth-picker.ts","../src/cli/auth.ts"],"sourcesContent":["/**\n * Arrow-key list for `agentconnect auth`.\n *\n * One flat list in a FIXED order: the login sweep launches every runtime and answers slowly, so a\n * verdict arrives as a per-row status rather than as a re-sort. A list that reorders itself under\n * the cursor is unusable. The same list drives both the runtime choice and the method choice.\n *\n * Deliberately dependency-free and stream-injected: the daemon ships no TUI library, and the key\n * decoding is what tests drive. Rendering redraws in place on a TTY and degrades to a plain list\n * when stdin is not a terminal, so a piped or CI invocation still shows what it would have offered.\n */\n\nexport interface PickerRow {\n id: string\n /** Display name, when there is one worth showing beside the id. */\n name?: string\n /** Trailing detail: the live login status, or what a method does. */\n hint?: string\n}\n\nexport interface PickerIo {\n input: NodeJS.ReadableStream & { isTTY?: boolean; setRawMode?: (raw: boolean) => void }\n output: NodeJS.WritableStream & { isTTY?: boolean }\n}\n\n/**\n * The rows to show, which may still be changing. Row ORDER is fixed for the life of the picker;\n * only each row's `hint` is expected to change, so the operator can select at any point —\n * including before the first verdict lands.\n */\nexport interface PickerModel {\n rows(): PickerRow[]\n /** Called on every change; returns its own unsubscribe. Absent means the list is final. */\n subscribe?: (listener: () => void) => () => void\n}\n\n/** A model for a list that will not change. */\nexport function fixedRows(rows: PickerRow[]): PickerModel {\n return { rows: () => rows }\n}\n\nconst ESC = '\\u001b'\nconst CTRL_C = '\\u0003'\n\nfunction label(row: PickerRow): string {\n const name = row.name && row.name !== row.id ? ` (${row.name})` : ''\n return `${row.id}${name}${row.hint ? ` — ${row.hint}` : ''}`\n}\n\n/** The list as lines, with `cursor` marked. Exported for tests and the non-TTY fallback. */\nexport function renderPicker(rows: PickerRow[], cursor: number): string[] {\n return rows.map((row, index) => `${index === cursor ? '❯' : ' '} ${label(row)}`)\n}\n\n/**\n * Show the list and resolve the chosen id, or undefined when the operator cancelled (q / Esc /\n * Ctrl-C). Non-TTY input prints the rows and resolves undefined — there is nothing to steer with,\n * and guessing a selection for someone is worse than saying so.\n */\nexport async function pickRow(model: PickerModel, io: PickerIo, prompt: string): Promise<string | undefined> {\n const write = (text: string): void => void io.output.write(text)\n if (model.rows().length === 0) return undefined\n\n if (!io.input.isTTY || !io.input.setRawMode) {\n for (const line of renderPicker(model.rows(), -1)) write(`${line}\\n`)\n return undefined\n }\n\n // The cursor follows the ROW ID, not the row number: the order is fixed, but a model is free to\n // grow, and an index would then point somewhere the operator never put it.\n let selected = model.rows()[0]!.id\n let painted = 0\n const paint = (): void => {\n const rows = model.rows()\n const cursor = Math.max(\n 0,\n rows.findIndex((row) => row.id === selected)\n )\n selected = rows[cursor]?.id ?? selected\n if (painted > 0) write(`${ESC}[${painted}A${ESC}[0J`)\n const lines = renderPicker(rows, cursor)\n write(`${lines.join('\\n')}\\n`)\n painted = lines.length\n }\n\n io.input.setRawMode(true)\n io.input.resume()\n if ('setEncoding' in io.input) (io.input as NodeJS.ReadStream).setEncoding('utf8')\n write(`${prompt} — ↑/↓ to move, Enter to select, q to cancel.\\n\\n`)\n paint()\n\n const unsubscribe = model.subscribe?.(paint)\n\n return await new Promise<string | undefined>((resolve) => {\n const finish = (value: string | undefined): void => {\n unsubscribe?.()\n io.input.removeListener('data', onData)\n io.input.setRawMode?.(false)\n io.input.pause()\n write('\\n')\n resolve(value)\n }\n const move = (delta: number): void => {\n const rows = model.rows()\n const at = Math.max(\n 0,\n rows.findIndex((row) => row.id === selected)\n )\n selected = rows[(at + delta + rows.length) % rows.length]!.id\n paint()\n }\n const onData = (chunk: string | Buffer): void => {\n const keys = typeof chunk === 'string' ? chunk : chunk.toString('utf8')\n // A single read can carry a whole escape sequence, or several keys at once when held down.\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]!\n if (key === ESC && keys[i + 1] === '[') {\n const code = keys[i + 2]\n i += 2\n if (code === 'A') move(-1)\n else if (code === 'B') move(1)\n continue\n }\n if (key === ESC || key === CTRL_C || key === 'q') return finish(undefined)\n if (key === '\\r' || key === '\\n') return finish(selected)\n if (key === 'k') move(-1)\n else if (key === 'j') move(1)\n }\n }\n io.input.on('data', onData)\n })\n}\n","import { spawn } from 'node:child_process'\nimport { createInterface } from 'node:readline'\nimport type {\n AuthMethod,\n AuthMethodTerminal,\n CreateElicitationRequest,\n CreateElicitationResponse\n} from '@agentclientprotocol/sdk'\nimport { AcpHost } from '../acp/acp-host.js'\nimport { loadConfig } from '../config/load-config.js'\nimport { resolveRoot } from '../paths.js'\nimport { ArchiveStore, parseArchiveLaunch, storedArchiveRuntimeDef } from '../runtimes/archive-store.js'\nimport { installedRuntimeCatalog } from '../runtimes/probe.js'\nimport { probeAllRuntimes, type RuntimeProbeResult } from '../runtimes/runtime-prober.js'\nimport { defaultProbeHostFactory } from '../acp/probe-host-factory.js'\nimport { fixedRows, pickRow, type PickerIo, type PickerModel, type PickerRow } from './auth-picker.js'\nimport {\n CLI_ELICIT_SURFACE,\n elicitFieldLabel,\n elicitForm,\n elicitFormAccepts,\n elicitFormContent,\n elicitRequiredProps,\n fieldAccepts,\n type ElicitTarget\n} from '../slack/render.js'\nimport { resolveRuntimeCatalog, type ResolvedRuntimeCatalog } from '../runtimes/registry.js'\nimport type { RuntimeDef } from '../config/config-schema.js'\n\n/**\n * Interactive login for one runtime, run by the operator ON the daemon host.\n *\n * ACP gives an agent two ways to be logged in, and both need a human at a terminal, which is why\n * this is a CLI command and not something the daemon can do for itself:\n *\n * - `terminal` methods: the CLIENT re-launches the agent program as an interactive process (with\n * the method's extra args/env) and a zero exit means success. Agents may only offer these when\n * the client advertises `auth.terminal`, so a daemon session never sees them — this command does.\n * - `agent` methods (the default when a method carries no `type`): the agent runs its own flow\n * behind `authenticate`, asking through URL/form elicitation, or simply printing to its stderr.\n *\n * The runtime deliberately runs UNSANDBOXED against the operator's own HOME, exactly as if they had\n * run its CLI by hand: the credential must land in the host state dir that RUNTIME_STATE_LOCATIONS\n * seeds sessions FROM. A private-HOME launch would write the login into a directory that is thrown\n * away with the process.\n */\nexport interface RunAuthOpts {\n runtimeId?: string\n methodId?: string\n configPath?: string\n root?: string\n out?: NodeJS.WritableStream\n /** Test seams; production resolves the real catalog and spawns a real AcpHost. */\n resolveCatalog?: () => Promise<ResolvedRuntimeCatalog>\n installed?: (catalog: ResolvedRuntimeCatalog) => ResolvedRuntimeCatalog\n hostFactory?: (runtime: RuntimeDef, options: ConstructorParameters<typeof AcpHost>[1]) => AcpHost\n /** Test seam for the client-run `terminal` method; production spawns it on the real TTY. */\n runTerminalAuth?: (runtime: RuntimeDef, method: AuthMethod) => Promise<number>\n /** Test seams for the loopback-paste fallback: reading a line, and replaying the pasted URL.\n * An aborted `signal` must release a question already waiting on stdin, answering empty. */\n readLine?: (question: string, signal?: AbortSignal) => Promise<string>\n deliverLoopback?: (url: string) => Promise<void>\n /** How long to let an agent-run login settle before offering the paste fallback. */\n pasteAfterMs?: number\n /** Skip the login-state sweep and list every installed runtime in one group. */\n skipProbe?: boolean\n /** Test seams for the grouped picker. */\n probeRuntimes?: typeof probeAllRuntimes\n pick?: (model: PickerModel, io: PickerIo, prompt: string) => Promise<string | undefined>\n io?: PickerIo\n}\n\nfunction isTerminalMethod(method: AuthMethod): method is AuthMethodTerminal & { type: 'terminal' } {\n return 'type' in method && method.type === 'terminal'\n}\n\n/** Row detail for one login method: what it is, and who runs it. */\nfunction hintFor(method: AuthMethod): string {\n const kind = isTerminalMethod(method) ? 'in a terminal' : 'handled by the runtime'\n return `${method.description?.trim() || method.name} (${kind})`\n}\n\n/** Ask one line. An abort resolves it empty and closes the interface: a login that settles while\n * the operator is being prompted must not stay parked on stdin waiting for a keypress. */\nasync function readLine(question: string, signal?: AbortSignal): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n let onAbort: (() => void) | undefined\n try {\n return await new Promise<string>((resolve) => {\n if (signal?.aborted) return resolve('')\n onAbort = () => resolve('')\n signal?.addEventListener('abort', onAbort, { once: true })\n rl.question(question, resolve)\n })\n } finally {\n if (onAbort) signal?.removeEventListener('abort', onAbort)\n rl.close()\n }\n}\n\n/** Re-launch the agent program interactively on the operator's own terminal. */\nfunction spawnTerminalAuth(runtime: RuntimeDef, method: AuthMethod): Promise<number> {\n const extra = isTerminalMethod(method) ? { args: method.args, env: method.env } : {}\n const args = [...runtime.args, ...(extra.args ?? [])]\n const env = {\n ...process.env,\n ...Object.fromEntries(runtime.env.map((entry) => [entry.name, entry.value])),\n ...(extra.env ?? {})\n }\n return new Promise((resolve, reject) => {\n const child = spawn(runtime.command, args, { stdio: 'inherit', env })\n child.on('error', reject)\n child.on('exit', (code) => resolve(code ?? 1))\n })\n}\n\n/**\n * List the installed runtimes at once, then annotate each with whether it is logged in FOR THIS\n * OPERATOR as the verdicts arrive.\n *\n * The order is fixed the moment the list appears and never changes: the sweep launches every\n * runtime and answers over tens of seconds, so a verdict lands as a status on its own row rather\n * than moving it. A selection made before any verdict is honoured immediately.\n *\n * The status is a real probe, not a guess: nothing persists it (the daemon's `authRequired` lives\n * in its process, and its local store caches only model catalogs), and every on-disk heuristic\n * misreads a runtime that authenticates from an env var. The sweep runs the way this command logs\n * in — host HOME, unsandboxed — so \"logged in\" answers the question actually being asked.\n */\nasync function chooseRuntime(\n catalog: ResolvedRuntimeCatalog,\n root: string,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<string | undefined> {\n const ids = Object.keys(catalog.entries).sort()\n if (ids.length === 0) throw new Error('no runtimes are installed on this host')\n const io = opts.io ?? { input: process.stdin, output: process.stdout }\n const pick = opts.pick ?? pickRow\n const rowFor = (id: string, hint?: string): PickerRow => ({\n id,\n ...(catalog.entries[id]?.name ? { name: catalog.entries[id]!.name } : {}),\n ...(hint ? { hint } : {})\n })\n\n if (opts.skipProbe) {\n return pick(fixedRows(ids.map((id) => rowFor(id))), io, 'Select a runtime to log in')\n }\n\n const results = new Map<string, RuntimeProbeResult>()\n const listeners = new Set<() => void>()\n const statusFor = (id: string): string => {\n const result = results.get(id)\n if (!result) return 'checking…'\n if (result.ok) {\n const models = result.models.length > 0 ? `${result.models.length} model(s)` : 'no models offered'\n return `logged in — ${result.probedVersion ? `${models}, ${result.probedVersion}` : models}`\n }\n if (result.authRequired) return 'not logged in'\n return `not logged in — ${result.error ? result.error.slice(0, 60) : 'probe failed'}`\n }\n const model: PickerModel = {\n rows: () => ids.map((id) => rowFor(id, statusFor(id))),\n subscribe: (listener) => {\n listeners.add(listener)\n return () => listeners.delete(listener)\n }\n }\n\n // Aborted the moment a runtime is chosen: nothing new is launched and every probe in flight\n // ends at once (runtime-prober races the signal), which is what makes the teardown below cheap\n // to wait for. The sweep is never awaited BEFORE a choice — that delay is what this list exists\n // to avoid.\n const sweep = new AbortController()\n const probe = opts.probeRuntimes ?? probeAllRuntimes\n const running = probe(Object.fromEntries(ids.map((id) => [id, catalog.entries[id]!.runtime])), {\n hostFactory: defaultProbeHostFactory({}),\n hostEnv: process.env,\n signal: sweep.signal,\n // The store owns an archive runtime's binary; probe what a login would actually launch.\n resolveRuntime: async (id, runtime) => {\n const entry = catalog.entries[id]\n const archive = entry ? parseArchiveLaunch(id, entry) : undefined\n if (!archive) return runtime\n return storedArchiveRuntimeDef(runtime, await new ArchiveStore({ root }).ensure(archive))\n },\n onResult: (result) => {\n results.set(result.runtime, result)\n for (const listener of listeners) listener()\n }\n })\n running.catch((err) => out.write(`login check failed: ${(err as Error).message}\\n`))\n\n try {\n return await pick(model, io, 'Select a runtime to log in')\n } finally {\n // Cancelled AND awaited: these probes are children of THIS process, and the CLI action exits\n // as soon as runAuth resolves, so a teardown nobody waited for leaves them running after the\n // command is gone. The abort ends each in-flight probe at once rather than at its deadline,\n // so waiting for it costs the operator nothing measurable.\n sweep.abort()\n await running.catch(() => undefined)\n }\n}\n\n// Long enough for a runtime to notice stdin EOF and exit on its own (Antigravity's ACP server\n// takes ~620ms), short enough that a wedged one still gets signalled promptly.\nconst EOF_GRACE_MS = 2500\n\n/** A loopback redirect the operator may replay locally: http(s) to 127.0.0.1/localhost, with a port. */\nfunction loopbackRedirect(value: string): URL | undefined {\n let url: URL\n try {\n url = new URL(value.trim())\n } catch {\n return undefined\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined\n if (url.hostname !== '127.0.0.1' && url.hostname !== 'localhost' && url.hostname !== '[::1]') return undefined\n if (url.username || url.password) return undefined\n return url\n}\n\n/**\n * Offer to finish a loopback OAuth login without a port forward.\n *\n * Google retired the copy/paste (OOB) flow in January 2023 and pointed desktop clients at the\n * loopback IP flow instead, so a runtime like Antigravity binds an HTTP server to 127.0.0.1 on the\n * DAEMON host and waits for the browser to be redirected there. On a headless host the browser\n * cannot reach it — but the redirect still happens, and the full `?code=…&state=…` URL is sitting\n * in the address bar of the tab that failed to load. Replaying that URL from this process, which\n * does run on the daemon host, hands the code to the waiting listener.\n *\n * Resolves as soon as the login settles; the prompt is only offered while it is still pending, so a\n * login completed through a port forward (or one that needed no browser at all) never sees it.\n */\nasync function offerLoopbackPaste(login: Promise<void>, opts: RunAuthOpts, out: NodeJS.WritableStream): Promise<void> {\n const ask = opts.readLine ?? readLine\n const deliver =\n opts.deliverLoopback ??\n (async (url: string) => {\n const res = await fetch(url, { redirect: 'manual', signal: AbortSignal.timeout(15_000) })\n // Any answer means the listener took the request; its body is a browser page, not our business.\n if (res.status >= 500) throw new Error(`the local listener answered HTTP ${res.status}`)\n })\n\n // The prompt is racing the login itself, so it gets a signal rather than a flag: a resolved\n // login has to close the readline question, which no amount of polling `settled` can do.\n let settled = false\n const done = new AbortController()\n const finish = (): void => {\n settled = true\n done.abort()\n }\n void login.then(finish, finish)\n await Promise.race([login.catch(() => undefined), new Promise((r) => setTimeout(r, opts.pasteAfterMs ?? 3000))])\n if (settled) return\n\n out.write('\\nIf the browser could not reach the redirect (this host is headless, no port forward),\\n')\n out.write('copy the URL of the tab that failed to load and paste it here — it carries the code.\\n')\n while (!settled) {\n const answer = (await ask('\\nRedirect URL (Enter to keep waiting): ', done.signal)).trim()\n if (settled || answer === '') return\n const url = loopbackRedirect(answer)\n if (!url) {\n out.write('That is not a loopback redirect URL (expected http://127.0.0.1:<port>/…). Ignored.\\n')\n continue\n }\n try {\n await deliver(url.toString())\n out.write('Delivered to the local listener; waiting for the runtime to finish…\\n')\n return\n } catch (err) {\n out.write(`Could not reach the local listener: ${(err as Error).message}\\n`)\n }\n }\n}\n\n/** Split a typed multi-select answer into the values the schema will be checked against. */\nfunction splitValues(line: string): string[] {\n return line\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value !== '')\n}\n\n/** The most times one field is re-asked before it is left unanswered — a typo deserves another\n * go, an operator who cannot satisfy the schema deserves to be let out of the loop. */\nconst FIELD_ATTEMPTS = 3\n\n/**\n * Ask one reduced field on the terminal, or return undefined when it was left unanswered.\n *\n * The pickable kinds are chosen from the options the AGENT offered, so a typo cannot invent a\n * value it never asked for; text, number and multi-select are typed and re-asked while the\n * field's own schema refuses them ({@link fieldAccepts} — the same gate the answer is checked\n * against, applied here so the refusal is explainable rather than a late blanket decline).\n */\nasync function askField(\n target: ElicitTarget,\n label: string,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<string | number | string[] | undefined> {\n if (target.kind === 'enum' || target.kind === 'boolean') {\n const io = opts.io ?? { input: process.stdin, output: process.stdout }\n const rows = target.options.map((option) => ({ id: option.value, name: option.label }))\n return await (opts.pick ?? pickRow)(fixedRows(rows), io, label)\n }\n\n const ask = opts.readLine ?? readLine\n if (target.kind === 'multi-enum') {\n out.write(`\\n${label} — one or more of: ${target.options.map((option) => option.value).join(', ')}\\n`)\n } else {\n out.write(`\\n${label}\\n`)\n }\n const prompt = target.kind === 'multi-enum' ? 'Values (comma-separated, empty to skip): ' : 'Value (empty to skip): '\n for (let attempt = 0; attempt < FIELD_ATTEMPTS; attempt++) {\n const line = (await ask(prompt)).trim()\n if (line === '') return undefined\n const value = target.kind === 'multi-enum' ? splitValues(line) : target.kind === 'number' ? Number(line) : line\n if (fieldAccepts(target, value)) return value\n out.write(`That is not a value ${target.propName} accepts.\\n`)\n }\n return undefined\n}\n\n/**\n * Answer a form elicitation with the properties the agent's own `requestedSchema` asked for.\n *\n * The reduction is the shared one — {@link elicitForm} over {@link CLI_ELICIT_SURFACE} — so this\n * terminal answers under the schema's own property names and types, and a form carrying a\n * required field it cannot render is declined whole rather than half-answered. An accept keyed\n * on anything else (a fixed `{type,text}`, say) is an answer the runtime never asked for: a\n * request for `projectId` would come back without one and the login would fail on it.\n */\nasync function answerAuthForm(\n params: CreateElicitationRequest,\n opts: RunAuthOpts,\n out: NodeJS.WritableStream\n): Promise<CreateElicitationResponse | undefined> {\n const form = elicitForm(params, CLI_ELICIT_SURFACE)\n if (!form) {\n out.write('\\nThe runtime asked for input this terminal cannot render whole — declining.\\n')\n return undefined\n }\n const message = (params as { message?: unknown }).message\n if (typeof message === 'string' && message.trim()) out.write(`\\n${message.trim()}\\n`)\n\n const answer: Record<string, string | number | string[]> = {}\n for (const target of form) {\n const value = await askField(target, elicitFieldLabel(params, target.propName), opts, out)\n if (value !== undefined) answer[target.propName] = value\n }\n // Nothing typed is a decline, not an empty accept: the spec has agents handle `decline`, and\n // an empty accept would report \"answered\" for a question the operator walked away from.\n if (Object.keys(answer).length === 0) return undefined\n if (!elicitFormAccepts(form, elicitRequiredProps(params), answer)) {\n out.write('\\nDeclined — the runtime needs every required field answered.\\n')\n return undefined\n }\n return { action: 'accept', content: elicitFormContent(form, answer) } as CreateElicitationResponse\n}\n\nexport async function runAuth(opts: RunAuthOpts): Promise<void> {\n const out = opts.out ?? process.stdout\n const root = resolveRoot(opts.root)\n const cfg = loadConfig({ root: opts.root, configPath: opts.configPath, optional: true })\n\n const resolved = opts.resolveCatalog\n ? await opts.resolveCatalog()\n : await resolveRuntimeCatalog(cfg, root, {\n ...(opts.runtimeId ? { neededRuntimes: [opts.runtimeId] } : {}),\n mode: 'cache-first'\n })\n const catalog = opts.installed ? opts.installed(resolved) : installedRuntimeCatalog(resolved)\n\n const runtimeId = opts.runtimeId ?? (await chooseRuntime(catalog, root, opts, out))\n if (!runtimeId) return\n\n const entry = catalog.entries[runtimeId]\n if (!entry) {\n const ids = Object.keys(catalog.entries).sort().join(', ') || '(none)'\n throw new Error(`runtime \"${runtimeId}\" is not installed on this host. Available: ${ids}`)\n }\n\n // Same store the daemon launches from: a vendor-archive runtime is not launchable until it is\n // extracted, and a login against a different binary than the sessions run would be a lie.\n const archive = parseArchiveLaunch(runtimeId, entry)\n const runtime = archive\n ? storedArchiveRuntimeDef(\n entry.runtime,\n await new ArchiveStore({\n root,\n log: { info: (message) => out.write(`${message}\\n`), warn: (message) => out.write(`${message}\\n`) }\n }).ensure(archive)\n )\n : entry.runtime\n\n const hostOptions: ConstructorParameters<typeof AcpHost>[1] = {\n onUpdate: () => {},\n runtimeId: runtimeId,\n isolateAccountApps: cfg.security.isolateAccountApps,\n authTerminalCapable: true,\n // The agent's own flow speaks through these two channels, and its stderr — which stays\n // unsuppressed here, because a runtime that prints a consent link has nowhere else to put it.\n onAuthElicit: async (params: CreateElicitationRequest): Promise<CreateElicitationResponse | undefined> => {\n const url = (params as { url?: unknown }).url\n if (typeof url === 'string') {\n out.write(`\\nOpen this URL to continue signing in:\\n\\n ${url}\\n\\n`)\n out.write('Waiting for the runtime to confirm…\\n')\n return { action: 'accept' } as CreateElicitationResponse\n }\n return await answerAuthForm(params, opts, out)\n }\n }\n const host = opts.hostFactory ? opts.hostFactory(runtime, hostOptions) : new AcpHost(runtime, hostOptions)\n\n const onSigint = (): void => {\n void host.stop(5000, EOF_GRACE_MS).finally(() => process.exit(130))\n }\n process.once('SIGINT', onSigint)\n try {\n out.write(`Starting ${runtimeId}…\\n`)\n await host.start()\n const methods = host.authMethods()\n if (methods.length === 0) {\n out.write(`${runtimeId} advertises no login methods — it either needs none or reads a credential from env.\\n`)\n return\n }\n\n let method = opts.methodId ? methods.find((m) => m.id === opts.methodId) : undefined\n if (opts.methodId && !method) {\n throw new Error(\n `\"${opts.methodId}\" is not offered by ${runtimeId}. Offered: ${methods.map((m) => m.id).join(', ')}`\n )\n }\n if (!method) {\n if (methods.length === 1) method = methods[0]!\n else {\n // The same arrow-key list the runtime was chosen from: a login is no place to make someone\n // retype an identifier they can already see.\n const rows = methods.map((entry) => ({ id: entry.id, name: entry.name, hint: hintFor(entry) }))\n const answer = await (opts.pick ?? pickRow)(\n fixedRows(rows),\n opts.io ?? { input: process.stdin, output: process.stdout },\n `How do you want to log in to ${runtimeId}?`\n )\n if (!answer) return\n method = methods.find((m) => m.id === answer)\n if (!method) throw new Error(`\"${answer}\" is not one of the offered methods`)\n }\n }\n out.write(`Using ${method.id} — ${method.name}\\n`)\n\n if (isTerminalMethod(method)) {\n // The client owns this one: hand the operator's terminal to the agent program itself.\n await host.stop(5000, EOF_GRACE_MS)\n const code = await (opts.runTerminalAuth ?? spawnTerminalAuth)(runtime, method)\n if (code !== 0) throw new Error(`interactive login exited with code ${code}`)\n } else {\n const login = host.authenticate(method.id)\n await offerLoopbackPaste(login, opts, out)\n await login\n }\n\n out.write(`\\n✓ ${runtimeId} is logged in on this host.\\n`)\n out.write('Sessions pick the credential up on their next start — the daemon needs no restart.\\n')\n } finally {\n process.removeListener('SIGINT', onSigint)\n // Graceful: a runtime that exits on stdin EOF then prints nothing. Some (Antigravity's ACP\n // server) install a signal handler that dumps a full stack trace over the operator's terminal\n // on SIGTERM, which reads like a crash right after a login that in fact succeeded.\n await host.stop(5000, EOF_GRACE_MS).catch(() => undefined)\n }\n}\n"],"mappings":"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"}