@victor-software-house/pi-acp 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-CjPR14E_.mjs","names":["resolvePath","SessionManager","isTextBlock","parseYaml","DEFAULT_TIMEOUT_MS","SessionManager","pkgJson.version","pkgJson.name","PiSessionManager","pkgJson.version"],"sources":["../src/daemon/session-registry.ts","../src/daemon/context.ts","../src/daemon/control.ts","../src/daemon/idle.ts","../src/acp/acp-bash-operations.ts","../src/acp/acp-read-operations.ts","../src/acp/auth.ts","../src/acp/auth-required.ts","../src/acp/client-capabilities.ts","../src/acp/ext-methods.ts","../src/acp/model-alias.ts","../src/acp/pi-settings.ts","../src/acp/translate/tool-content.ts","../src/acp/unreachable.ts","../src/acp/session.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts","../src/resources/diagnostics.ts","../src/resources/sources/local.ts","../src/resources/loader.ts","../src/resources/manifest.schema.ts","../src/resources/manifest.ts","../src/resources/modes.ts","../src/resources/sources/http.ts","../src/resources/sources/ssh.ts","../package.json","../src/acp/agent.ts","../src/runtime/serve.ts","../src/daemon/index.ts"],"sourcesContent":["/**\n * Daemon-level session registry. Maps sessionId -> live AgentSession plus\n * ownership refcount so that closing a session from one client does NOT\n * dispose the underlying pi runtime if another client also holds it.\n */\n\nimport type { AgentSession } from \"@earendil-works/pi-coding-agent\";\n\nexport interface SessionEntry {\n\tsessionId: string;\n\tpiSession: AgentSession;\n\townerConnectionId: string;\n\talsoHeldBy: Set<string>;\n\tcwd: string;\n\tsessionFile: string | undefined;\n\tupdatedAt: Date;\n}\n\nexport interface SessionRegistry {\n\tregister(entry: NewSessionEntry): void;\n\tattach(sessionId: string, connectionId: string): SessionEntry | undefined;\n\trelease(sessionId: string, connectionId: string): ReleaseResult;\n\tget(sessionId: string): SessionEntry | undefined;\n\tlistAll(): SessionEntry[];\n\tlistOwnedBy(connectionId: string): SessionEntry[];\n}\n\nexport interface NewSessionEntry {\n\tsessionId: string;\n\tpiSession: AgentSession;\n\townerConnectionId: string;\n\tcwd: string;\n\tsessionFile: string | undefined;\n}\n\nexport type ReleaseResult =\n\t| { kind: \"disposed\"; entry: SessionEntry }\n\t| { kind: \"still-held\"; entry: SessionEntry }\n\t| { kind: \"unknown\" };\n\nexport function createSessionRegistry(): SessionRegistry {\n\tconst map = new Map<string, SessionEntry>();\n\n\treturn {\n\t\tregister(input) {\n\t\t\tconst entry: SessionEntry = {\n\t\t\t\tsessionId: input.sessionId,\n\t\t\t\tpiSession: input.piSession,\n\t\t\t\townerConnectionId: input.ownerConnectionId,\n\t\t\t\talsoHeldBy: new Set<string>(),\n\t\t\t\tcwd: input.cwd,\n\t\t\t\tsessionFile: input.sessionFile,\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t};\n\t\t\tmap.set(input.sessionId, entry);\n\t\t},\n\n\t\tattach(sessionId, connectionId) {\n\t\t\tconst entry = map.get(sessionId);\n\t\t\tif (entry === undefined) return undefined;\n\t\t\tif (entry.ownerConnectionId !== connectionId) {\n\t\t\t\tentry.alsoHeldBy.add(connectionId);\n\t\t\t\tentry.updatedAt = new Date();\n\t\t\t}\n\t\t\treturn entry;\n\t\t},\n\n\t\trelease(sessionId, connectionId) {\n\t\t\tconst entry = map.get(sessionId);\n\t\t\tif (entry === undefined) return { kind: \"unknown\" };\n\n\t\t\tif (entry.alsoHeldBy.delete(connectionId)) {\n\t\t\t\tentry.updatedAt = new Date();\n\t\t\t\tif (entry.ownerConnectionId === connectionId && entry.alsoHeldBy.size === 0) {\n\t\t\t\t\tmap.delete(sessionId);\n\t\t\t\t\treturn { kind: \"disposed\", entry };\n\t\t\t\t}\n\t\t\t\treturn { kind: \"still-held\", entry };\n\t\t\t}\n\n\t\t\tif (entry.ownerConnectionId === connectionId) {\n\t\t\t\tif (entry.alsoHeldBy.size > 0) {\n\t\t\t\t\t// Hand ownership to one of the still-holders so the entry\n\t\t\t\t\t// keeps a coherent owner record. Pick first by iteration.\n\t\t\t\t\tconst next = entry.alsoHeldBy.values().next().value;\n\t\t\t\t\tif (next !== undefined) {\n\t\t\t\t\t\tentry.alsoHeldBy.delete(next);\n\t\t\t\t\t\tentry.ownerConnectionId = next;\n\t\t\t\t\t\tentry.updatedAt = new Date();\n\t\t\t\t\t\treturn { kind: \"still-held\", entry };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tmap.delete(sessionId);\n\t\t\t\treturn { kind: \"disposed\", entry };\n\t\t\t}\n\n\t\t\treturn { kind: \"still-held\", entry };\n\t\t},\n\n\t\tget(sessionId) {\n\t\t\treturn map.get(sessionId);\n\t\t},\n\n\t\tlistAll() {\n\t\t\treturn Array.from(map.values());\n\t\t},\n\n\t\tlistOwnedBy(connectionId) {\n\t\t\treturn Array.from(map.values()).filter(\n\t\t\t\t(e) => e.ownerConnectionId === connectionId || e.alsoHeldBy.has(connectionId),\n\t\t\t);\n\t\t},\n\t};\n}\n","/**\n * Daemon-level shared state injected into per-connection PiAcpAgent instances.\n *\n * Phase 1 landed the interface + stub IdleTracker.\n * Phase 2 wires the real SessionRegistry.\n * Phase 3 will replace IdleTracker.\n */\n\nimport { createSessionRegistry, type SessionRegistry } from \"@pi-acp/daemon/session-registry\";\n\nexport interface DaemonContext {\n\t/** Cross-window session registry. PRD-003 FR-5. */\n\tsessionRegistry: SessionRegistry;\n\t/** Idle-shutdown tracker. Stub in Phase 1-2; real in Phase 3. */\n\tidleTracker: IdleTracker;\n}\n\n/** Phase-3 stub. Replaced when idle shutdown lands. */\nexport interface IdleTracker {\n\tbump(delta: 1 | -1): void;\n\tdispose(): void;\n}\n\nexport type { SessionEntry, SessionRegistry } from \"@pi-acp/daemon/session-registry\";\nexport { createSessionRegistry } from \"@pi-acp/daemon/session-registry\";\n\nexport function createNoopIdleTracker(): IdleTracker {\n\treturn {\n\t\tbump() {\n\t\t\t/* phase 3 wires this */\n\t\t},\n\t\tdispose() {\n\t\t\t/* phase 3 wires this */\n\t\t},\n\t};\n}\n\nexport function createDaemonContext(): DaemonContext {\n\treturn {\n\t\tsessionRegistry: createSessionRegistry(),\n\t\tidleTracker: createNoopIdleTracker(),\n\t};\n}\n","/**\n * Daemon control plane: a Hono app served over a separate Unix domain socket\n * (`~/.pi/run/pi-acp-control.sock` by default).\n *\n * Operator clients (`pi-acp --daemon-status`, `pi-acp --daemon-stop`) talk to\n * this surface via HTTP-over-UDS. Keeping it out-of-band from the ACP NDJSON\n * socket means no first-frame peeking, no stream unshift dance — the ACP\n * accept path is pure ACP.\n *\n * Routes:\n * GET /status → { uptimeSeconds, connections, sessions, pid, version }\n * POST /shutdown → triggers graceful shutdown (response sent first)\n * GET /sessions → daemon session registry snapshot\n */\n\nimport type { DaemonContext } from \"@pi-acp/daemon/context\";\nimport { Hono } from \"hono\";\n\nexport interface ControlContext {\n\tctx: DaemonContext;\n\tstartedAt: number;\n\tpid: number;\n\tversion: string;\n\tactiveConnections: () => number;\n\tonShutdown: () => void;\n}\n\nexport function buildControlApp(control: ControlContext): Hono {\n\tconst app = new Hono();\n\n\tapp.get(\"/status\", (c) =>\n\t\tc.json({\n\t\t\tuptimeSeconds: Math.round((Date.now() - control.startedAt) / 1000),\n\t\t\tconnections: control.activeConnections(),\n\t\t\tsessions: control.ctx.sessionRegistry.listAll().length,\n\t\t\tpid: control.pid,\n\t\t\tversion: control.version,\n\t\t}),\n\t);\n\n\tapp.post(\"/shutdown\", (c) => {\n\t\t// Defer one tick so the response flushes before we tear the listener\n\t\t// down — otherwise the operator sees a connection reset instead of 200.\n\t\tsetImmediate(control.onShutdown);\n\t\treturn c.json({ ok: true });\n\t});\n\n\tapp.get(\"/sessions\", (c) =>\n\t\tc.json({\n\t\t\tsessions: control.ctx.sessionRegistry.listAll().map((entry) => ({\n\t\t\t\tsessionId: entry.sessionId,\n\t\t\t\tcwd: entry.cwd,\n\t\t\t\towner: entry.ownerConnectionId,\n\t\t\t\talsoHeldBy: [...entry.alsoHeldBy],\n\t\t\t\tupdatedAt: entry.updatedAt,\n\t\t\t})),\n\t\t}),\n\t);\n\n\treturn app;\n}\n\nexport interface ControlServer {\n\tstop(): void;\n}\n\n/**\n * Bind the control app to a Unix domain socket. Uses Bun.serve's `unix` option.\n */\nexport function serveControl(app: Hono, socketPath: string): ControlServer {\n\tconst server = Bun.serve({\n\t\tunix: socketPath,\n\t\tfetch: app.fetch,\n\t});\n\treturn {\n\t\tstop() {\n\t\t\ttry {\n\t\t\t\tvoid server.stop(true);\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t},\n\t};\n}\n","import type { IdleTracker } from \"@pi-acp/daemon/context\";\n\nconst DEFAULT_IDLE_SECONDS = 600;\n\nexport function createIdleTracker(opts: { idleMs: number; onIdle: () => void }): IdleTracker {\n\tlet active = 0;\n\tlet timer: ReturnType<typeof setTimeout> | null = null;\n\n\tconst startTimer = (): void => {\n\t\tif (timer !== null) return;\n\t\ttimer = setTimeout(opts.onIdle, opts.idleMs);\n\t\ttimer.unref?.();\n\t};\n\n\tconst stopTimer = (): void => {\n\t\tif (timer === null) return;\n\t\tclearTimeout(timer);\n\t\ttimer = null;\n\t};\n\n\t// Cold start: no connections yet. Arm the timer so an unused daemon\n\t// shuts itself down even if the spawning client never connected.\n\tstartTimer();\n\n\treturn {\n\t\tbump(delta: 1 | -1) {\n\t\t\tactive = Math.max(0, active + delta);\n\t\t\tif (active === 0) startTimer();\n\t\t\telse stopTimer();\n\t\t},\n\t\tdispose() {\n\t\t\tstopTimer();\n\t\t},\n\t};\n}\n\nexport function resolveIdleMs(): number {\n\tconst raw = process.env[\"PI_ACP_DAEMON_IDLE_SECONDS\"];\n\tif (raw === undefined || raw === \"\") return DEFAULT_IDLE_SECONDS * 1000;\n\tconst n = Number.parseInt(raw, 10);\n\tif (!Number.isFinite(n) || n <= 0) return DEFAULT_IDLE_SECONDS * 1000;\n\treturn n * 1000;\n}\n","/**\n * PRD-002 §FR-6.5 — ACP terminal delegation for pi's `bash` tool.\n *\n * Companion to acp-read-operations.ts. When the client advertises\n * `clientCapabilities.terminal === true`, pi-acp overrides pi's built-in\n * `bash` with an ACP-routed implementation. Commands run on the CLIENT'S\n * machine via `terminal/*` lifecycle, so Zed Remote workflows execute\n * `bash` on the remote workspace where the user actually edits — matching\n * the FR-6 `read` delegation behavior so the full read/bash pair is\n * coherent.\n *\n * Pi exposes `BashOperations.exec(command, cwd, { onData, signal, timeout, env })`\n * with a streaming `onData(Buffer)` callback. ACP's TerminalHandle exposes\n * `currentOutput()` returning a snapshot string. We bridge by polling\n * `currentOutput()` while `waitForExit()` is pending and computing\n * length-prefix deltas, then emitting `onData(Buffer.from(delta, \"utf8\"))`.\n *\n * Command + args: pi passes a single shell-string `command`. We wrap as\n * `command: \"/bin/sh\", args: [\"-c\", command]` to preserve shell semantics\n * (pipes, redirects, expansion). Zed's terminal implementation accepts\n * this verbatim — same pattern Codex and Claude ACP use.\n *\n * Cancellation: pi's options.signal is honored by calling `terminal.kill()`\n * then awaiting release. The poll loop also self-aborts on signal.\n *\n * SessionId binding: same late-ref pattern as acp-read-operations — the\n * id ref is mutated by PiAcpAgent right after createAgentSession returns,\n * before any tool turn can run.\n */\n\nimport type { AgentSideConnection } from \"@agentclientprotocol/sdk\";\nimport type { BashOperations } from \"@earendil-works/pi-coding-agent\";\n\nexport interface AcpBashOperationsDeps {\n\tconn: AgentSideConnection;\n\tgetSessionId: () => string;\n}\n\nconst POLL_INTERVAL_MS = 100;\nconst SHELL_PATH = \"/bin/sh\";\n\nexport function createAcpBashOperations(deps: AcpBashOperationsDeps): BashOperations {\n\tconst { conn, getSessionId } = deps;\n\n\treturn {\n\t\tasync exec(command, cwd, options) {\n\t\t\tconst sessionId = getSessionId();\n\t\t\tif (sessionId === \"\") {\n\t\t\t\tthrow new Error(\"pi-acp acp-bash: sessionId not yet bound\");\n\t\t\t}\n\n\t\t\tconst env =\n\t\t\t\toptions.env !== undefined\n\t\t\t\t\t? Object.entries(options.env)\n\t\t\t\t\t\t\t.filter(([, v]) => v !== undefined)\n\t\t\t\t\t\t\t.map(([name, value]) => ({ name, value: String(value) }))\n\t\t\t\t\t: [];\n\n\t\t\tconst createParams: Parameters<AgentSideConnection[\"createTerminal\"]>[0] = {\n\t\t\t\tsessionId,\n\t\t\t\tcommand: SHELL_PATH,\n\t\t\t\targs: [\"-c\", command],\n\t\t\t\tcwd,\n\t\t\t\tenv,\n\t\t\t};\n\n\t\t\tconst terminal = await conn.createTerminal(createParams);\n\n\t\t\tlet lastOutputLen = 0;\n\t\t\tlet cancelled = false;\n\t\t\tconst abortHandler = (): void => {\n\t\t\t\tcancelled = true;\n\t\t\t\tvoid terminal.kill().catch(() => {});\n\t\t\t};\n\t\t\toptions.signal?.addEventListener(\"abort\", abortHandler);\n\n\t\t\t// Background poll for incremental stdout. Diffs against the\n\t\t\t// previous full snapshot length and pushes the new tail through\n\t\t\t// onData. ACP's terminal contract guarantees output only grows\n\t\t\t// (it can be truncated from the START on byte-limit overflow,\n\t\t\t// but we don't pass outputByteLimit so that's not in play).\n\t\t\tconst pollLoop = async (): Promise<void> => {\n\t\t\t\twhile (!cancelled) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst snap = await terminal.currentOutput();\n\t\t\t\t\t\tif (snap.output.length > lastOutputLen) {\n\t\t\t\t\t\t\tconst delta = snap.output.slice(lastOutputLen);\n\t\t\t\t\t\t\tlastOutputLen = snap.output.length;\n\t\t\t\t\t\t\toptions.onData(Buffer.from(delta, \"utf8\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (snap.exitStatus !== null && snap.exitStatus !== undefined) return;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Terminal already released or transport blip — exit loop;\n\t\t\t\t\t\t// waitForExit will surface the real outcome.\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tawait new Promise<void>((r) => setTimeout(r, POLL_INTERVAL_MS));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst timeoutPromise =\n\t\t\t\toptions.timeout !== undefined && options.timeout > 0\n\t\t\t\t\t? new Promise<{ timedOut: true }>((resolve) =>\n\t\t\t\t\t\t\tsetTimeout(() => resolve({ timedOut: true }), options.timeout),\n\t\t\t\t\t\t)\n\t\t\t\t\t: null;\n\n\t\t\ttry {\n\t\t\t\tconst pollPromise = pollLoop();\n\t\t\t\tconst exitPromise = terminal.waitForExit();\n\t\t\t\tconst winner =\n\t\t\t\t\ttimeoutPromise !== null\n\t\t\t\t\t\t? await Promise.race([exitPromise, timeoutPromise])\n\t\t\t\t\t\t: await exitPromise;\n\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\tif (\"timedOut\" in winner) {\n\t\t\t\t\tawait terminal.kill().catch(() => {});\n\t\t\t\t\tconst final = await terminal.waitForExit();\n\t\t\t\t\texitCode = final.exitCode ?? null;\n\t\t\t\t} else {\n\t\t\t\t\texitCode = winner.exitCode ?? null;\n\t\t\t\t}\n\n\t\t\t\t// Drain any final output the poll loop may have missed.\n\t\t\t\tcancelled = true;\n\t\t\t\tawait pollPromise;\n\t\t\t\ttry {\n\t\t\t\t\tconst final = await terminal.currentOutput();\n\t\t\t\t\tif (final.output.length > lastOutputLen) {\n\t\t\t\t\t\tconst delta = final.output.slice(lastOutputLen);\n\t\t\t\t\t\toptions.onData(Buffer.from(delta, \"utf8\"));\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t/* best-effort */\n\t\t\t\t}\n\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\toptions.signal?.removeEventListener(\"abort\", abortHandler);\n\t\t\t\ttry {\n\t\t\t\t\tawait terminal.release();\n\t\t\t\t} catch {\n\t\t\t\t\t/* best-effort — terminal may already be released */\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * PRD-002 §FR-6 — ACP-FS delegation for the `read` tool.\n *\n * Pi exposes a `ReadOperations` seam on its built-in read tool\n * (`createReadToolDefinition(cwd, { operations })`). When an ACP client\n * advertises `clientCapabilities.fs.readTextFile`, pi-acp swaps the\n * default node-fs operations for ACP-routed ones so `read` lands on the\n * client's filesystem (which Zed Remote forwards to the remote machine).\n *\n * The sessionId is captured via a getter callback because for newSession /\n * forkSession the id is generated *inside* `createAgentSession`, after\n * `customTools` (which embed these operations) have already been built.\n * The ref is mutated by the agent immediately after session creation and\n * before the model can invoke any tool, so by the time `readFile` runs\n * the getter returns the canonical sessionId.\n *\n * Mandatory skill: `pi-tool-progressive-disclosure` — the override keeps\n * the same tool name + argument schema as pi's built-in so the model is\n * unaware of the indirection.\n */\n\nimport type { AgentSideConnection } from \"@agentclientprotocol/sdk\";\nimport type { ReadOperations } from \"@earendil-works/pi-coding-agent\";\n\nexport interface AcpReadOperationsDeps {\n\tconn: AgentSideConnection;\n\t/**\n\t * Lazy sessionId provider. Called per-operation. Returning an empty\n\t * string causes the tool to throw — the model never sees a stale id.\n\t */\n\tgetSessionId: () => string;\n}\n\nexport function createAcpReadOperations(deps: AcpReadOperationsDeps): ReadOperations {\n\tconst { conn, getSessionId } = deps;\n\n\treturn {\n\t\tasync readFile(absolutePath: string): Promise<Buffer> {\n\t\t\tconst sessionId = getSessionId();\n\t\t\tif (sessionId === \"\") {\n\t\t\t\tthrow new Error(\"pi-acp acp-fs read: sessionId not yet bound\");\n\t\t\t}\n\t\t\tconst response = await conn.readTextFile({ sessionId, path: absolutePath });\n\t\t\treturn Buffer.from(response.content, \"utf8\");\n\t\t},\n\t\tasync access(absolutePath: string): Promise<void> {\n\t\t\tconst sessionId = getSessionId();\n\t\t\tif (sessionId === \"\") {\n\t\t\t\tthrow new Error(\"pi-acp acp-fs access: sessionId not yet bound\");\n\t\t\t}\n\t\t\t// ACP has no explicit access primitive — a successful read is the\n\t\t\t// only way to confirm readability. Discard the body.\n\t\t\tawait conn.readTextFile({ sessionId, path: absolutePath });\n\t\t},\n\t\t// detectImageMimeType intentionally omitted — ACP fs/read_text_file\n\t\t// returns text content only; image detection would need an out-of-\n\t\t// band probe that ACP doesn't currently expose.\n\t};\n}\n","/**\n * Build ACP AuthMethod descriptors for terminal-based authentication.\n *\n * Supports both the registry-required \"type/args/env\" shape and Zed's\n * _meta[\"terminal-auth\"] extension for the Authenticate banner.\n */\n\nimport type { AuthMethod } from \"@agentclientprotocol/sdk\";\n\nexport const AUTH_METHOD_ID = \"pi_terminal_login\";\n\ninterface AuthMethodOptions {\n\tsupportsTerminalAuthMeta?: boolean;\n}\n\nexport function buildAuthMethods(opts?: AuthMethodOptions): AuthMethod[] {\n\tconst supportsTerminalAuthMeta = opts?.supportsTerminalAuthMeta ?? true;\n\n\tconst method: AuthMethod = {\n\t\tid: AUTH_METHOD_ID,\n\t\tname: \"Launch pi in the terminal\",\n\t\tdescription: \"Start pi in an interactive terminal to configure API keys or login\",\n\t\ttype: \"terminal\",\n\t\targs: [\"--terminal-login\"],\n\t\tenv: {},\n\t};\n\n\tif (supportsTerminalAuthMeta) {\n\t\tconst launch = resolveTerminalLaunchCommand();\n\t\tmethod._meta = {\n\t\t\t\"terminal-auth\": {\n\t\t\t\t...launch,\n\t\t\t\tlabel: \"Launch pi\",\n\t\t\t},\n\t\t};\n\t}\n\n\treturn [method];\n}\n\nfunction resolveTerminalLaunchCommand(): { command: string; args: string[] } {\n\tconst argv0 = process.argv[0] ?? \"node\";\n\tconst argv1 = process.argv[1];\n\n\tif (argv1 !== undefined && argv0.includes(\"node\") && argv1.endsWith(\".js\")) {\n\t\treturn { command: argv0, args: [argv1, \"--terminal-login\"] };\n\t}\n\n\treturn { command: \"pi-acp\", args: [\"--terminal-login\"] };\n}\n","/**\n * Detect common auth/credential errors from pi and surface them as ACP AUTH_REQUIRED.\n */\n\nimport { RequestError } from \"@agentclientprotocol/sdk\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\n\nconst AUTH_ERROR_PATTERNS = [\n\t\"api key\",\n\t\"apikey\",\n\t\"missing key\",\n\t\"no key\",\n\t\"not configured\",\n\t\"unauthorized\",\n\t\"authentication\",\n\t\"permission denied\",\n\t\"forbidden\",\n\t\"401\",\n\t\"403\",\n];\n\nexport function detectAuthError(err: unknown): RequestError | null {\n\tconst text = err instanceof Error ? err.message : String(err ?? \"\");\n\tconst lower = text.toLowerCase();\n\n\tconst isAuthRelated = AUTH_ERROR_PATTERNS.some((p) => lower.includes(p));\n\tif (!isAuthRelated) return null;\n\n\treturn RequestError.authRequired(\n\t\t{ authMethods: buildAuthMethods() },\n\t\t\"Configure an API key or log in with an OAuth provider.\",\n\t);\n}\n","/**\n * Parse and represent client capabilities from the ACP initialize request.\n *\n * Both reference implementations (claude-agent-acp, codex-acp) store and\n * use `clientCapabilities` for feature detection and auth method selection.\n *\n * Reads from:\n * - `_meta.terminal_output` — terminal output rendering\n * - `_meta.terminal-auth` — terminal auth with command metadata\n * - `auth._meta.gateway` — gateway auth (non-standard extension)\n * - `fs.readTextFile` — typed spec-stable surface (PRD-002 §FR-6)\n */\n\nimport type { ClientCapabilities } from \"@agentclientprotocol/sdk\";\n\nexport interface ClientCapabilityFlags {\n\t/** Client supports terminal output metadata (info/output/exit lifecycle). */\n\tterminalOutput: boolean;\n\t/** Client supports terminal-based authentication with command metadata. */\n\tterminalAuth: boolean;\n\t/** Client supports gateway-based authentication. */\n\tgatewayAuth: boolean;\n\t/** Client supports `fs/read_text_file` requests (PRD-002 §FR-6). */\n\tfsReadTextFile: boolean;\n\t/**\n\t * Client supports all `terminal/*` methods (createTerminal, terminalOutput,\n\t * waitForTerminalExit, releaseTerminal, killTerminal). When true, pi-acp\n\t * overrides pi's built-in `bash` tool with an ACP-routed implementation\n\t * so commands run on the CLIENT'S machine (e.g., Zed Remote routes\n\t * terminal/* to the remote, making `bash` land on the remote workspace).\n\t */\n\tterminal: boolean;\n}\n\nexport function parseClientCapabilities(\n\tcaps: ClientCapabilities | undefined | null,\n): ClientCapabilityFlags {\n\t// Single code path: treat null/undefined as an empty capabilities object.\n\t// Each flag's check is the source of truth for both the present and\n\t// absent cases — no parallel default branch to drift out of sync when\n\t// adding a new flag.\n\tconst safe = caps ?? ({} as ClientCapabilities);\n\n\tconst meta = safe._meta;\n\tconst metaIsObject = typeof meta === \"object\" && meta !== null;\n\n\tconst authMeta =\n\t\t\"auth\" in safe && typeof safe.auth === \"object\" && safe.auth !== null && \"_meta\" in safe.auth\n\t\t\t? safe.auth._meta\n\t\t\t: undefined;\n\tconst authMetaIsObject = typeof authMeta === \"object\" && authMeta !== null;\n\n\t// biome-ignore lint/complexity/useLiteralKeys: tsc strict-mode index-signature access\n\treturn {\n\t\tterminalOutput: metaIsObject && meta[\"terminal_output\"] === true,\n\t\tterminalAuth: metaIsObject && meta[\"terminal-auth\"] === true,\n\t\tgatewayAuth: authMetaIsObject && authMeta[\"gateway\"] === true,\n\t\tfsReadTextFile: safe.fs?.readTextFile === true,\n\t\tterminal: safe.terminal === true,\n\t};\n}\n","/**\n * ACP `extMethod` / `extNotification` dispatcher.\n *\n * ACP spec recommends prefixing extension method names with a unique\n * identifier (e.g., a domain name). pi-acp uses the `pi-acp/` prefix for\n * its built-ins; client-defined methods can also be routed here by\n * registering handlers via `register()`.\n *\n * Unknown request methods throw `RequestError.methodNotFound`. Unknown\n * notification methods are silently ignored per JSON-RPC 2.0 semantics —\n * notifications have no response channel, so erroring is meaningless.\n */\n\nimport { RequestError } from \"@agentclientprotocol/sdk\";\n\nexport type ExtMethodRequestHandler = (\n\tparams: Record<string, unknown>,\n) => Promise<Record<string, unknown>> | Record<string, unknown>;\n\nexport type ExtNotificationHandler = (params: Record<string, unknown>) => Promise<void> | void;\n\nexport interface ExtDispatcherDeps {\n\t/** Version string surfaced via `pi-acp/runtime-info`. */\n\tversion: string;\n\t/** Returns the current count of locally-tracked sessions. */\n\tsessionCount: () => number;\n\t/** Process start time in ms epoch, used to compute uptime. */\n\tstartedAt: number;\n}\n\nexport class ExtMethodDispatcher {\n\tprivate readonly requestHandlers = new Map<string, ExtMethodRequestHandler>();\n\tprivate readonly notificationHandlers = new Map<string, ExtNotificationHandler>();\n\n\tconstructor(deps: ExtDispatcherDeps) {\n\t\t// Built-in request handlers under the pi-acp/ namespace.\n\t\tthis.requestHandlers.set(\"pi-acp/ping\", () => ({ ok: true, ts: Date.now() }));\n\t\tthis.requestHandlers.set(\"pi-acp/runtime-info\", () => ({\n\t\t\tversion: deps.version,\n\t\t\tuptimeMs: Date.now() - deps.startedAt,\n\t\t\tsessionCount: deps.sessionCount(),\n\t\t}));\n\t}\n\n\tregister(method: string, handler: ExtMethodRequestHandler): void {\n\t\tthis.requestHandlers.set(method, handler);\n\t}\n\n\tregisterNotification(method: string, handler: ExtNotificationHandler): void {\n\t\tthis.notificationHandlers.set(method, handler);\n\t}\n\n\tasync handleRequest(\n\t\tmethod: string,\n\t\tparams: Record<string, unknown>,\n\t): Promise<Record<string, unknown>> {\n\t\tconst handler = this.requestHandlers.get(method);\n\t\tif (handler === undefined) throw RequestError.methodNotFound(method);\n\t\treturn await handler(params);\n\t}\n\n\tasync handleNotification(method: string, params: Record<string, unknown>): Promise<void> {\n\t\tconst handler = this.notificationHandlers.get(method);\n\t\tif (handler === undefined) return;\n\t\tawait handler(params);\n\t}\n}\n","/**\n * Model alias resolution for user-friendly model names.\n *\n * Lets users type \"opus\", \"sonnet\", \"opus[1m]\" instead of exact\n * \"provider/modelId\" strings. Uses tokenized matching and scoring\n * following the claude-agent-acp pattern.\n */\n\ninterface ModelEntry {\n\tprovider: string;\n\tid: string;\n\tname?: string | undefined;\n}\n\ninterface ResolvedModel {\n\tprovider: string;\n\tid: string;\n}\n\n/**\n * Tokenize a string: split on non-alphanumeric, lowercase, strip \"claude\".\n */\nfunction tokenize(input: string): string[] {\n\treturn input\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((t) => t !== \"\" && t !== \"claude\");\n}\n\n/**\n * Extract a context hint in square brackets, e.g. \"opus[1m]\" -> { base: \"opus\", hint: \"1m\" }.\n */\nfunction extractContextHint(input: string): { base: string; hint: string | null } {\n\tconst match = /^(.+?)\\[([^\\]]+)\\]$/.exec(input);\n\tif (match !== null && match[1] !== undefined && match[2] !== undefined) {\n\t\treturn { base: match[1], hint: match[2] };\n\t}\n\treturn { base: input, hint: null };\n}\n\n/** Check if a string is purely numeric. */\nfunction isNumeric(s: string): boolean {\n\treturn /^\\d+$/.test(s);\n}\n\n/**\n * Score how well a model matches the given preference tokens.\n *\n * Returns a score >= 0 (higher is better), or -1 for no match.\n * Requires at least one non-numeric token to match to avoid false positives\n * from bare version numbers (e.g. \"4\" matching model version suffixes).\n */\nfunction scoreModel(model: ModelEntry, prefTokens: string[], hint: string | null): number {\n\tconst modelStr = `${model.provider}/${model.id}/${model.name ?? \"\"}`.toLowerCase();\n\tconst modelTokens = tokenize(modelStr);\n\n\tlet matched = 0;\n\tlet hasNonNumericMatch = false;\n\tfor (const pt of prefTokens) {\n\t\tif (modelTokens.some((mt) => mt.includes(pt) || pt.includes(mt))) {\n\t\t\tmatched++;\n\t\t\tif (!isNumeric(pt)) hasNonNumericMatch = true;\n\t\t}\n\t}\n\n\tif (matched === 0) return -1;\n\n\t// Require at least one non-numeric token to match -- prevents \"gpt-4\"\n\t// matching on the bare \"4\" version component.\n\tif (!hasNonNumericMatch) return -1;\n\n\tlet score = matched / prefTokens.length;\n\n\t// Bonus for hint match (e.g. \"1m\" context window hint)\n\tif (hint !== null && modelStr.includes(hint.toLowerCase())) {\n\t\tscore += 0.5;\n\t}\n\n\t// Bonus for exact substring match on model id\n\tconst pref = prefTokens.join(\"\");\n\tif (model.id.toLowerCase().includes(pref)) {\n\t\tscore += 0.25;\n\t}\n\n\treturn score;\n}\n\n/**\n * Resolve a user-friendly model preference to a concrete model.\n *\n * Matching strategy (in order):\n * 1. Exact match on \"provider/id\"\n * 2. Exact match on \"id\" alone\n * 3. Tokenized scored match with optional context hint\n *\n * Returns null if no model matches.\n */\nexport function resolveModelPreference(\n\tmodels: readonly ModelEntry[],\n\tpreference: string,\n): ResolvedModel | null {\n\tconst trimmed = preference.trim();\n\tif (trimmed === \"\") return null;\n\n\t// 1. Exact match on \"provider/id\"\n\tif (trimmed.includes(\"/\")) {\n\t\tconst [p, ...rest] = trimmed.split(\"/\");\n\t\tconst provider = p ?? \"\";\n\t\tconst id = rest.join(\"/\");\n\t\tconst exact = models.find(\n\t\t\t(m) =>\n\t\t\t\tm.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\tm.id.toLowerCase() === id.toLowerCase(),\n\t\t);\n\t\tif (exact !== undefined) return { provider: exact.provider, id: exact.id };\n\t}\n\n\t// 2. Exact match on id alone\n\tconst byId = models.find((m) => m.id.toLowerCase() === trimmed.toLowerCase());\n\tif (byId !== undefined) return { provider: byId.provider, id: byId.id };\n\n\t// 3. Tokenized scored match\n\tconst { base, hint } = extractContextHint(trimmed);\n\tconst prefTokens = tokenize(base);\n\tif (prefTokens.length === 0) return null;\n\n\tlet bestModel: ModelEntry | null = null;\n\tlet bestScore = -1;\n\n\tfor (const model of models) {\n\t\tconst s = scoreModel(model, prefTokens, hint);\n\t\tif (s > bestScore) {\n\t\t\tbestScore = s;\n\t\t\tbestModel = model;\n\t\t}\n\t}\n\n\t// Require at least 50% of preference tokens to match to avoid spurious hits\n\t// (e.g. \"gpt-4\" matching on the \"4\" token alone)\n\tif (bestModel === null || bestScore < 0.5) return null;\n\treturn { provider: bestModel.provider, id: bestModel.id };\n}\n","/**\n * Read pi settings from global and project config files.\n *\n * Settings are merged: project overrides global.\n * Paths follow pi-mono conventions:\n * Global: ~/.pi/agent/settings.json\n * Project: <cwd>/.pi/settings.json\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport * as z from \"zod\";\n\nconst piSettingsSchema = z.object({\n\tenableSkillCommands: z.boolean().optional(),\n\tquietStartup: z.boolean().optional(),\n\tquietStart: z.boolean().optional(),\n\tskills: z\n\t\t.object({\n\t\t\tenableSkillCommands: z.boolean().optional(),\n\t\t})\n\t\t.optional(),\n});\n\ntype PiSettings = z.infer<typeof piSettingsSchema>;\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n\treturn typeof x === \"object\" && x !== null && !Array.isArray(x);\n}\n\nfunction merge(\n\tbase: Record<string, unknown>,\n\toverride: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...base };\n\tfor (const [key, val] of Object.entries(override)) {\n\t\tconst existing = result[key];\n\t\tif (isRecord(existing) && isRecord(val)) {\n\t\t\tresult[key] = merge(existing, val);\n\t\t} else {\n\t\t\tresult[key] = val;\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction readJson(path: string): Record<string, unknown> {\n\ttry {\n\t\tif (!existsSync(path)) return {};\n\t\tconst data: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isRecord(data) ? data : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport function piAgentDir(): string {\n\treturn process.env.PI_CODING_AGENT_DIR !== undefined\n\t\t? resolve(process.env.PI_CODING_AGENT_DIR)\n\t\t: join(homedir(), \".pi\", \"agent\");\n}\n\nfunction resolvedSettings(cwd: string): PiSettings {\n\tconst globalPath = join(piAgentDir(), \"settings.json\");\n\tconst projectPath = resolve(cwd, \".pi\", \"settings.json\");\n\tconst merged = merge(readJson(globalPath), readJson(projectPath));\n\tconst result = piSettingsSchema.safeParse(merged);\n\treturn result.success ? result.data : {};\n}\n\nexport function skillCommandsEnabled(cwd: string): boolean {\n\tconst settings = resolvedSettings(cwd);\n\n\tif (typeof settings.enableSkillCommands === \"boolean\") {\n\t\treturn settings.enableSkillCommands;\n\t}\n\n\tif (typeof settings.skills?.enableSkillCommands === \"boolean\") {\n\t\treturn settings.skills.enableSkillCommands;\n\t}\n\n\treturn true;\n}\n","/**\n * Per-tool content formatting for ACP tool results.\n *\n * Dispatches formatting by tool name following the reference implementation\n * pattern (claude-agent-acp / codex-acp). Each tool type produces\n * `ToolCallContent[]` appropriate for its output shape.\n */\n\nimport type { ToolCallContent } from \"@agentclientprotocol/sdk\";\nimport * as z from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Zod schemas for pi tool result shapes\n// ---------------------------------------------------------------------------\n\nconst textBlockSchema = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n});\n\nconst imageBlockSchema = z.object({\n\ttype: z.literal(\"image\"),\n});\n\nconst contentBlockSchema = z.union([textBlockSchema, imageBlockSchema]);\n\nconst bashDetailsSchema = z.object({\n\tstdout: z.string().optional(),\n\tstderr: z.string().optional(),\n\toutput: z.string().optional(),\n\texitCode: z.number().optional(),\n\tcode: z.number().optional(),\n});\n\nconst bashResultSchema = z.object({\n\tcontent: z.array(z.unknown()).optional(),\n\tdetails: bashDetailsSchema.optional(),\n\tstdout: z.string().optional(),\n\tstderr: z.string().optional(),\n\toutput: z.string().optional(),\n\texitCode: z.number().optional(),\n\tcode: z.number().optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Extraction helpers\n// ---------------------------------------------------------------------------\n\nexport interface BashOutput {\n\toutput: string;\n\texitCode: number | undefined;\n}\n\n/**\n * Extract stdout/stderr and exit code from a pi bash/tmux result.\n */\nexport function extractBashOutput(result: unknown): BashOutput {\n\tif (result === null || result === undefined || typeof result !== \"object\") {\n\t\treturn { output: \"\", exitCode: undefined };\n\t}\n\n\tconst parsed = bashResultSchema.safeParse(result);\n\tif (!parsed.success) {\n\t\treturn { output: \"\", exitCode: undefined };\n\t}\n\n\tconst r = parsed.data;\n\tconst d = r.details;\n\n\t// Try content blocks first\n\tif (r.content !== undefined) {\n\t\tconst texts = r.content\n\t\t\t.map((block) => textBlockSchema.safeParse(block))\n\t\t\t.filter((res) => res.success)\n\t\t\t.map((res) => res.data.text);\n\t\tif (texts.length > 0) {\n\t\t\tconst exitCode = d?.exitCode ?? r.exitCode ?? d?.code ?? r.code;\n\t\t\treturn { output: texts.join(\"\"), exitCode };\n\t\t}\n\t}\n\n\tconst stdout = d?.stdout ?? r.stdout ?? d?.output ?? r.output;\n\tconst stderr = d?.stderr ?? r.stderr;\n\tconst exitCode = d?.exitCode ?? r.exitCode ?? d?.code ?? r.code;\n\n\tconst parts: string[] = [];\n\tif (stdout !== undefined && stdout.trim() !== \"\") parts.push(stdout);\n\tif (stderr !== undefined && stderr.trim() !== \"\") parts.push(stderr);\n\n\treturn { output: parts.join(\"\\n\"), exitCode };\n}\n\n/**\n * Extract text content from a pi tool result (generic).\n */\nexport function extractTextContent(result: unknown): string {\n\tif (result === null || result === undefined || typeof result !== \"object\") return \"\";\n\n\tif (\"content\" in result && Array.isArray(result.content)) {\n\t\tconst texts: string[] = [];\n\t\tfor (const block of result.content) {\n\t\t\tconst parsed = textBlockSchema.safeParse(block);\n\t\t\tif (parsed.success) texts.push(parsed.data.text);\n\t\t}\n\t\tif (texts.length > 0) return texts.join(\"\");\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(result, null, 2);\n\t} catch {\n\t\treturn String(result);\n\t}\n}\n\n/**\n * Extract content blocks from a pi result, preserving type information.\n * Used for read results where images need to be preserved.\n */\nexport function extractContentBlocks(\n\tresult: unknown,\n): Array<{ type: \"text\"; text: string } | { type: \"image\" }> {\n\tif (result === null || result === undefined || typeof result !== \"object\") return [];\n\tif (!(\"content\" in result) || !Array.isArray(result.content)) return [];\n\n\tconst blocks: Array<{ type: \"text\"; text: string } | { type: \"image\" }> = [];\n\tfor (const raw of result.content) {\n\t\tconst parsed = contentBlockSchema.safeParse(raw);\n\t\tif (parsed.success) {\n\t\t\tblocks.push(parsed.data);\n\t\t}\n\t}\n\treturn blocks;\n}\n\n// ---------------------------------------------------------------------------\n// Markdown escaping via dynamic backtick fence wrapping\n// ---------------------------------------------------------------------------\n\n/**\n * Find the longest consecutive backtick sequence in a string.\n */\nfunction longestBacktickRun(text: string): number {\n\tlet max = 0;\n\tlet current = 0;\n\tfor (const ch of text) {\n\t\tif (ch === \"`\") {\n\t\t\tcurrent++;\n\t\t\tif (current > max) max = current;\n\t\t} else {\n\t\t\tcurrent = 0;\n\t\t}\n\t}\n\treturn max;\n}\n\n/**\n * Wrap text in a dynamically-sized backtick fence to prevent markdown rendering.\n *\n * Instead of character-level escaping (which fails on files containing backtick\n * sequences, indented code blocks, blockquotes, and list markers), this wraps\n * the entire text in a backtick fence whose length exceeds any backtick sequence\n * in the content. This approach is simpler and strictly more correct (following\n * the claude-agent-acp pattern).\n */\nexport function markdownEscape(text: string): string {\n\tif (text === \"\") return \"\";\n\n\tconst fenceLen = Math.max(3, longestBacktickRun(text) + 1);\n\tconst fence = \"`\".repeat(fenceLen);\n\n\t// Avoid a trailing double newline before the closing fence\n\tconst body = text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n\treturn `${fence}\\n${body}\\n${fence}`;\n}\n\n// ---------------------------------------------------------------------------\n// Per-tool content formatting\n// ---------------------------------------------------------------------------\n\n/**\n * Format tool output into `ToolCallContent[]` by tool name.\n *\n * Returns the appropriate content shape for each tool type:\n * - bash/tmux: console code fences\n * - read: markdown-escaped text (images preserved)\n * - edit/write: empty (diff handled separately)\n * - lsp: code fences\n * - errors: code fences with failed status\n * - everything else: plain text\n */\nexport function formatToolContent(\n\ttoolName: string,\n\tresult: unknown,\n\tisError: boolean,\n): ToolCallContent[] {\n\t// Error path: wrap any error text in a code fence\n\tif (isError) {\n\t\tconst text = extractTextContent(result);\n\t\tif (text === \"\") return [];\n\t\treturn [{ type: \"content\", content: { type: \"text\", text: `\\`\\`\\`\\n${text}\\n\\`\\`\\`` } }];\n\t}\n\n\tswitch (toolName) {\n\t\tcase \"bash\":\n\t\tcase \"tmux\":\n\t\t\treturn formatBashContent(result);\n\n\t\tcase \"read\":\n\t\t\treturn formatReadContent(result);\n\n\t\tcase \"edit\":\n\t\tcase \"write\":\n\t\t\t// Diff content is handled separately in handleToolEnd.\n\t\t\t// Return empty so the diff path takes precedence.\n\t\t\treturn [];\n\n\t\tcase \"lsp\":\n\t\t\treturn formatLspContent(result);\n\n\t\tdefault:\n\t\t\treturn formatFallbackContent(result);\n\t}\n}\n\nfunction formatBashContent(result: unknown): ToolCallContent[] {\n\tconst { output, exitCode } = extractBashOutput(result);\n\tif (output === \"\" && exitCode === undefined) return [];\n\n\tconst parts: string[] = [];\n\tif (output !== \"\") {\n\t\tparts.push(`\\`\\`\\`console\\n${output}\\n\\`\\`\\``);\n\t}\n\tif (exitCode !== undefined && exitCode !== 0) {\n\t\tparts.push(`exit code: ${exitCode}`);\n\t}\n\n\tconst text = parts.join(\"\\n\\n\");\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text } }];\n}\n\nfunction formatReadContent(result: unknown): ToolCallContent[] {\n\tconst blocks = extractContentBlocks(result);\n\tif (blocks.length === 0) {\n\t\t// Check if the result explicitly has an empty content array\n\t\tif (\n\t\t\ttypeof result === \"object\" &&\n\t\t\tresult !== null &&\n\t\t\t\"content\" in result &&\n\t\t\tArray.isArray(result.content) &&\n\t\t\tresult.content.length === 0\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\t// Fallback to text extraction for results without content blocks\n\t\tconst text = extractTextContent(result);\n\t\tif (text === \"\") return [];\n\t\treturn [{ type: \"content\", content: { type: \"text\", text: markdownEscape(text) } }];\n\t}\n\n\tconst content: ToolCallContent[] = [];\n\tfor (const block of blocks) {\n\t\tif (block.type === \"text\") {\n\t\t\tcontent.push({\n\t\t\t\ttype: \"content\",\n\t\t\t\tcontent: { type: \"text\", text: markdownEscape(block.text) },\n\t\t\t});\n\t\t}\n\t\t// Image blocks are preserved as-is (the ACP client handles rendering)\n\t\t// We skip them here since they need their original structure from the result\n\t}\n\n\t// If we only had image blocks and no text, return empty\n\treturn content;\n}\n\nfunction formatLspContent(result: unknown): ToolCallContent[] {\n\tconst text = extractTextContent(result);\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text: `\\`\\`\\`\\n${text}\\n\\`\\`\\`` } }];\n}\n\nfunction formatFallbackContent(result: unknown): ToolCallContent[] {\n\tconst text = extractTextContent(result);\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text } }];\n}\n\n/**\n * Wrap streaming output text in a console code fence for bash/tmux.\n *\n * Each streaming update is self-contained (full accumulated buffer),\n * following the codex-acp pattern.\n */\nexport function wrapStreamingBashOutput(text: string): string {\n\tif (text === \"\") return \"\";\n\treturn `\\`\\`\\`console\\n${text}\\n\\`\\`\\``;\n}\n","/**\n * Exhaustive switch/case helper.\n *\n * Writes unknown values to stderr instead of silently ignoring them, aiding\n * debugging when the pi SDK adds new event types. Never write to stdout: it\n * carries the ACP NDJSON stream and any other byte poisons the protocol.\n */\nexport function unreachable(value: never, context?: string): void {\n\tconst label = context !== undefined ? `[${context}] ` : \"\";\n\tprocess.stderr.write(`${label}Unhandled value: ${String(value)}\\n`);\n}\n","import { readFileSync } from \"node:fs\";\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\nimport {\n\ttype AgentSideConnection,\n\ttype ContentBlock,\n\ttype McpServer,\n\tRequestError,\n\ttype SessionUpdate,\n\ttype ToolCallContent,\n\ttype ToolCallLocation,\n\ttype ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type { AgentEvent, AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessageEvent, ToolCall } from \"@earendil-works/pi-ai\";\nimport type { AgentSession, AgentSessionEvent } from \"@earendil-works/pi-coding-agent\";\nimport { formatToolContent, wrapStreamingBashOutput } from \"@pi-acp/acp/translate/tool-content\";\nimport { unreachable } from \"@pi-acp/acp/unreachable\";\nimport * as z from \"zod\";\n\nexport type StopReason = \"end_turn\" | \"cancelled\" | \"max_tokens\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findUniqueLineNumber(text: string, needle: string): number | undefined {\n\tif (!needle) return undefined;\n\tconst first = text.indexOf(needle);\n\tif (first < 0) return undefined;\n\tif (text.indexOf(needle, first + needle.length) >= 0) return undefined;\n\n\tlet line = 1;\n\tfor (let i = 0; i < first; i++) {\n\t\tif (text.charCodeAt(i) === 10) line++;\n\t}\n\treturn line;\n}\n\nexport interface ToolArgs {\n\tpath?: string | undefined;\n\toldText?: string | undefined;\n\t[key: string]: unknown;\n}\n\nexport function resolveToolPath(\n\targs: ToolArgs,\n\tcwd: string,\n\tline?: number,\n): ToolCallLocation[] | undefined {\n\tconst p = args.path;\n\tif (p === undefined) return undefined;\n\n\tconst resolved = isAbsolute(p) ? p : resolvePath(cwd, p);\n\treturn [{ path: resolved, ...(typeof line === \"number\" ? { line } : {}) }];\n}\n\nexport function toToolKind(toolName: string): ToolKind {\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn \"read\";\n\t\tcase \"write\":\n\t\tcase \"edit\":\n\t\t\treturn \"edit\";\n\t\tcase \"bash\":\n\t\tcase \"tmux\":\n\t\t\treturn \"execute\";\n\t\tcase \"lsp\":\n\t\t\treturn \"search\";\n\t\tdefault:\n\t\t\treturn \"other\";\n\t}\n}\n\nconst MAX_TITLE_LEN = 80;\n\nfunction truncateTitle(text: string): string {\n\tconst oneLine = text.replace(/\\n/g, \" \").trim();\n\tif (oneLine.length <= MAX_TITLE_LEN) return oneLine;\n\treturn `${oneLine.slice(0, MAX_TITLE_LEN - 1)}…`;\n}\n\nfunction capitalize(s: string): string {\n\tif (s.length === 0) return s;\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/**\n * Build a descriptive tool title from tool name and args.\n *\n * Returns a short human-readable label like \"Read src/index.ts\" or \"Run ls -la\".\n */\nexport function buildToolTitle(toolName: string, args: ToolArgs): string {\n\tconst p = args.path;\n\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn p !== undefined ? `Read ${p}` : \"Read\";\n\t\tcase \"write\":\n\t\t\treturn p !== undefined ? `Write ${p}` : \"Write\";\n\t\tcase \"edit\":\n\t\t\treturn p !== undefined ? `Edit ${p}` : \"Edit\";\n\t\tcase \"bash\": {\n\t\t\tconst command =\n\t\t\t\ttypeof args[\"command\"] === \"string\"\n\t\t\t\t\t? args[\"command\"]\n\t\t\t\t\t: typeof args[\"cmd\"] === \"string\"\n\t\t\t\t\t\t? args[\"cmd\"]\n\t\t\t\t\t\t: undefined;\n\t\t\treturn command !== undefined ? truncateTitle(`Run ${command}`) : \"bash\";\n\t\t}\n\t\tcase \"lsp\": {\n\t\t\tconst action = typeof args[\"action\"] === \"string\" ? args[\"action\"] : undefined;\n\t\t\tconst file = typeof args[\"file\"] === \"string\" ? args[\"file\"] : undefined;\n\t\t\tconst query = typeof args[\"query\"] === \"string\" ? args[\"query\"] : undefined;\n\t\t\tconst line = typeof args[\"line\"] === \"number\" ? args[\"line\"] : undefined;\n\t\t\tif (action !== undefined) {\n\t\t\t\tconst target = file !== undefined ? (line !== undefined ? `${file}:${line}` : file) : query;\n\t\t\t\treturn target !== undefined\n\t\t\t\t\t? truncateTitle(`${capitalize(action)} ${target}`)\n\t\t\t\t\t: capitalize(action);\n\t\t\t}\n\t\t\treturn \"LSP\";\n\t\t}\n\t\tcase \"tmux\": {\n\t\t\tconst action = typeof args[\"action\"] === \"string\" ? args[\"action\"] : undefined;\n\t\t\tconst command = typeof args[\"command\"] === \"string\" ? args[\"command\"] : undefined;\n\t\t\tconst name = typeof args[\"name\"] === \"string\" ? args[\"name\"] : undefined;\n\t\t\tif (action === \"run\" && command !== undefined) return truncateTitle(`Tmux: ${command}`);\n\t\t\tif (action !== undefined && name !== undefined)\n\t\t\t\treturn truncateTitle(`Tmux ${action} ${name}`);\n\t\t\tif (action !== undefined) return `Tmux ${action}`;\n\t\t\treturn \"Tmux\";\n\t\t}\n\t\tcase \"context_tag\": {\n\t\t\tconst name = typeof args[\"name\"] === \"string\" ? args[\"name\"] : undefined;\n\t\t\treturn name !== undefined ? `Tag ${name}` : \"Tag\";\n\t\t}\n\t\tcase \"context_log\":\n\t\t\treturn \"Context log\";\n\t\tcase \"context_checkout\": {\n\t\t\tconst target = typeof args[\"target\"] === \"string\" ? args[\"target\"] : undefined;\n\t\t\treturn target !== undefined ? truncateTitle(`Checkout ${target}`) : \"Checkout\";\n\t\t}\n\t\tcase \"claudemon\":\n\t\t\treturn \"Check quota\";\n\t\tdefault:\n\t\t\treturn toolName;\n\t}\n}\n\n/**\n * Map pi assistant stopReason to ACP StopReason.\n * pi: \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\"\n * ACP: \"end_turn\" | \"cancelled\" | \"max_tokens\" | \"error\"\n */\nfunction mapPiStopReason(piReason: string | null): StopReason {\n\tswitch (piReason) {\n\t\tcase \"stop\":\n\t\tcase \"toolUse\":\n\t\t\treturn \"end_turn\";\n\t\tcase \"length\":\n\t\t\treturn \"max_tokens\";\n\t\tcase \"aborted\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"error\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"end_turn\";\n\t}\n}\n\nfunction extractToolCallFromPartial(ame: AssistantMessageEvent): ToolCall | undefined {\n\tif (!(\"partial\" in ame)) return undefined;\n\tconst content = ame.partial.content;\n\tconst idx = \"contentIndex\" in ame ? ame.contentIndex : 0;\n\tconst block = content[idx];\n\tif (block && \"type\" in block && block.type === \"toolCall\") return block;\n\treturn undefined;\n}\n\nfunction parseToolInput(tc: ToolCall): ToolArgs {\n\treturn tc.arguments;\n}\n\nconst toolArgsSchema = z\n\t.object({\n\t\tpath: z.string().trim().optional(),\n\t\toldText: z.string().trim().optional(),\n\t})\n\t.loose();\n\nexport function toToolArgs(raw: unknown): ToolArgs {\n\tconst result = toolArgsSchema.safeParse(raw);\n\treturn result.success ? result.data : {};\n}\n\n// ---------------------------------------------------------------------------\n// _meta builder helpers\n// ---------------------------------------------------------------------------\n\ntype PiAcpMeta = Record<string, unknown>;\n\n/** Build the `_meta.piAcp` tool name metadata. */\nfunction buildToolMeta(toolName: string, extra?: PiAcpMeta): PiAcpMeta {\n\tconst base: PiAcpMeta = { piAcp: { toolName } };\n\tif (extra !== undefined) {\n\t\treturn { ...base, ...extra };\n\t}\n\treturn base;\n}\n\n// ---------------------------------------------------------------------------\n// Terminal tool classification\n// ---------------------------------------------------------------------------\n\n/** Tools that produce terminal-style output. */\nfunction isTerminalTool(toolName: string): boolean {\n\treturn toolName === \"bash\" || toolName === \"tmux\";\n}\n\n// ---------------------------------------------------------------------------\n// Session manager\n// ---------------------------------------------------------------------------\n\nexport class SessionManager {\n\tprivate sessions = new Map<string, PiAcpSession>();\n\n\tdisposeAll(): void {\n\t\tfor (const id of this.sessions.keys()) this.close(id);\n\t}\n\n\tmaybeGet(sessionId: string): PiAcpSession | undefined {\n\t\treturn this.sessions.get(sessionId);\n\t}\n\n\tclose(sessionId: string): void {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) return;\n\t\ttry {\n\t\t\ts.dispose();\n\t\t} catch {\n\t\t\t// best-effort\n\t\t}\n\t\tthis.sessions.delete(sessionId);\n\t}\n\n\t/**\n\t * Drop this connection's PiAcpSession wrapper without disposing the\n\t * underlying pi runtime. Used when the daemon SessionRegistry reports\n\t * another client still holds the session.\n\t */\n\tdetach(sessionId: string): void {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) return;\n\t\ttry {\n\t\t\ts.unsubscribeOnly();\n\t\t} catch {\n\t\t\t// best-effort — fall back to full dispose if detach is unsupported\n\t\t}\n\t\tthis.sessions.delete(sessionId);\n\t}\n\n\tcloseAllExcept(keepSessionId: string): void {\n\t\tfor (const id of this.sessions.keys()) {\n\t\t\tif (id !== keepSessionId) this.close(id);\n\t\t}\n\t}\n\n\tregister(session: PiAcpSession): void {\n\t\tthis.sessions.set(session.sessionId, session);\n\t}\n\n\tget(sessionId: string): PiAcpSession {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`);\n\t\treturn s;\n\t}\n\n\tsize(): number {\n\t\treturn this.sessions.size;\n\t}\n\n\tvalues(): IterableIterator<PiAcpSession> {\n\t\treturn this.sessions.values();\n\t}\n\n\t/** First registered session, or undefined. Order = insertion order. */\n\tfirst(): PiAcpSession | undefined {\n\t\tconst it = this.sessions.values().next();\n\t\treturn it.done === true ? undefined : it.value;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// ACP session wrapping a pi AgentSession\n// ---------------------------------------------------------------------------\n\nexport interface PiAcpSessionOpts {\n\tsessionId: string;\n\tcwd: string;\n\tmcpServers: McpServer[];\n\tpiSession: AgentSession;\n\tconn: AgentSideConnection;\n\t/** Whether the client supports terminal output metadata. */\n\tsupportsTerminalOutput?: boolean | undefined;\n\t/**\n\t * Best-effort cleanup callbacks run at session dispose. PRD-002 §FR-5\n\t * `none` mode passes a tmpdir rmSync here. Callbacks must not throw\n\t * (the dispose path catches but logs nothing).\n\t */\n\tcleanups?: Array<() => void>;\n\t/**\n\t * PRD-002 §FR-7 diagnostics report. When non-empty, emitted as a\n\t * leading `agent_message_chunk` on the first prompt of this session.\n\t * Discarded after that single emission.\n\t */\n\tdiagnosticsReport?: string | undefined;\n}\n\nexport class PiAcpSession {\n\treadonly sessionId: string;\n\treadonly cwd: string;\n\treadonly mcpServers: McpServer[];\n\treadonly piSession: AgentSession;\n\treadonly supportsTerminalOutput: boolean;\n\n\tprivate readonly conn: AgentSideConnection;\n\n\tprivate cancelRequested = false;\n\tprivate promptRunning = false;\n\tprivate pendingTurn: { resolve: (r: StopReason) => void; reject: (e: unknown) => void } | null =\n\t\tnull;\n\t/** Queued prompts waiting for the active turn to complete. */\n\tprivate pendingMessages: Array<{\n\t\tmessage: string;\n\t\timages: unknown[];\n\t\tresolve: (r: StopReason) => void;\n\t\treject: (e: unknown) => void;\n\t}> = [];\n\n\tprivate currentToolCalls = new Map<string, \"pending\" | \"in_progress\">();\n\t/** Map of toolCallId -> toolName for streaming updates (Phase 5). */\n\tprivate toolCallNames = new Map<string, string>();\n\tprivate editSnapshots = new Map<string, { path: string; oldText: string }>();\n\tprivate lastAssistantStopReason: string | null = null;\n\tprivate lastEmit: Promise<void> = Promise.resolve();\n\tprivate unsubscribe: (() => void) | undefined;\n\tprivate readonly cleanups: Array<() => void>;\n\tprivate pendingDiagnosticsReport: string | null;\n\n\tconstructor(opts: PiAcpSessionOpts) {\n\t\tthis.sessionId = opts.sessionId;\n\t\tthis.cwd = opts.cwd;\n\t\tthis.mcpServers = opts.mcpServers;\n\t\tthis.piSession = opts.piSession;\n\t\tthis.conn = opts.conn;\n\t\tthis.supportsTerminalOutput = opts.supportsTerminalOutput ?? false;\n\t\tthis.cleanups = opts.cleanups ?? [];\n\t\tthis.pendingDiagnosticsReport =\n\t\t\topts.diagnosticsReport !== undefined && opts.diagnosticsReport !== \"\"\n\t\t\t\t? opts.diagnosticsReport\n\t\t\t\t: null;\n\t\tthis.unsubscribe = this.piSession.subscribe((ev: AgentSessionEvent) => this.handlePiEvent(ev));\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribe?.();\n\t\tthis.piSession.dispose();\n\t\tfor (const cleanup of this.cleanups) {\n\t\t\ttry {\n\t\t\t\tcleanup();\n\t\t\t} catch {\n\t\t\t\t// best-effort; FR-5 tmpdir removal is the only registered case\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Drop event subscription without disposing the underlying piSession.\n\t * Used when the daemon registry transfers ownership to another connection\n\t * that still holds this session.\n\t */\n\tunsubscribeOnly(): void {\n\t\tthis.unsubscribe?.();\n\t\tthis.unsubscribe = undefined;\n\t}\n\n\tasync prompt(message: string, images: unknown[] = []): Promise<StopReason> {\n\t\t// If a prompt is already running, queue this one and return a promise\n\t\t// that resolves when it eventually executes.\n\t\tif (this.promptRunning) {\n\t\t\treturn new Promise<StopReason>((resolve, reject) => {\n\t\t\t\tthis.pendingMessages.push({ message, images, resolve, reject });\n\t\t\t});\n\t\t}\n\n\t\treturn this.executePrompt(message, images);\n\t}\n\n\tasync cancel(): Promise<void> {\n\t\tthis.cancelRequested = true;\n\n\t\t// Resolve all queued prompts as cancelled\n\t\tfor (const pending of this.pendingMessages) {\n\t\t\tpending.resolve(\"cancelled\");\n\t\t}\n\t\tthis.pendingMessages = [];\n\n\t\tawait this.piSession.abort();\n\t}\n\n\tprivate executePrompt(message: string, images: unknown[]): Promise<StopReason> {\n\t\tthis.promptRunning = true;\n\n\t\tconst turnPromise = new Promise<StopReason>((resolve, reject) => {\n\t\t\tthis.cancelRequested = false;\n\t\t\tthis.pendingTurn = { resolve, reject };\n\t\t});\n\n\t\tconst imageContents = Array.isArray(images)\n\t\t\t? images.filter(\n\t\t\t\t\t(img): img is { type: \"image\"; data: string; mimeType: string } =>\n\t\t\t\t\t\ttypeof img === \"object\" && img !== null && \"type\" in img && img.type === \"image\",\n\t\t\t\t)\n\t\t\t: [];\n\n\t\t// PRD-002 §FR-7 — emit the once-per-session diagnostics report\n\t\t// before the model produces any output. Drop the reference after\n\t\t// the first prompt so subsequent prompts in the same session don't\n\t\t// repeat it. Fire-and-forget; failure here doesn't block the turn.\n\t\tif (this.pendingDiagnosticsReport !== null) {\n\t\t\tconst report = this.pendingDiagnosticsReport;\n\t\t\tthis.pendingDiagnosticsReport = null;\n\t\t\tvoid this.conn\n\t\t\t\t.sessionUpdate({\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `${report}\\n` },\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.catch(() => {\n\t\t\t\t\t/* best-effort */\n\t\t\t\t});\n\t\t}\n\n\t\tthis.piSession.prompt(message, { images: imageContents }).catch(() => {\n\t\t\tvoid this.flushEmits().finally(() => {\n\t\t\t\tconst reason: StopReason = this.cancelRequested ? \"cancelled\" : \"error\";\n\t\t\t\tthis.pendingTurn?.resolve(reason);\n\t\t\t\tthis.pendingTurn = null;\n\t\t\t});\n\t\t});\n\n\t\treturn turnPromise;\n\t}\n\n\t/**\n\t * Dequeue and execute the next pending prompt, if any.\n\t * Called after a turn completes.\n\t */\n\tprivate dequeueNextPrompt(): void {\n\t\tconst next = this.pendingMessages.shift();\n\t\tif (next === undefined) {\n\t\t\tthis.promptRunning = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.executePrompt(next.message, next.images).then(next.resolve, next.reject);\n\t}\n\n\twasCancelRequested(): boolean {\n\t\treturn this.cancelRequested;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal\n\t// -----------------------------------------------------------------------\n\n\tprivate emit(update: SessionUpdate): void {\n\t\tthis.lastEmit = this.lastEmit\n\t\t\t.then(() => this.conn.sessionUpdate({ sessionId: this.sessionId, update }))\n\t\t\t.catch(() => {});\n\t}\n\n\tprivate async flushEmits(): Promise<void> {\n\t\tawait this.lastEmit;\n\t}\n\n\tprivate handlePiEvent(ev: AgentSessionEvent): void {\n\t\tif (!isAgentEvent(ev)) return;\n\n\t\tswitch (ev.type) {\n\t\t\tcase \"message_update\":\n\t\t\t\tthis.handleMessageUpdate(ev.assistantMessageEvent);\n\t\t\t\tbreak;\n\t\t\tcase \"message_end\":\n\t\t\t\tthis.handleMessageEnd(ev.message);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis.handleToolStart(ev.toolCallId, ev.toolName, toToolArgs(ev.args));\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_update\":\n\t\t\t\tthis.handleToolUpdate(ev.toolCallId, ev.toolName, ev.partialResult);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\":\n\t\t\t\tthis.handleToolEnd(ev.toolCallId, ev.toolName, ev.result, ev.isError);\n\t\t\t\tbreak;\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis.handleAgentEnd();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunreachable(ev, \"handlePiEvent\");\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate handleMessageUpdate(ame: AssistantMessageEvent): void {\n\t\tif (ame.type === \"text_delta\") {\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\tcontent: { type: \"text\", text: ame.delta } satisfies ContentBlock,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (ame.type === \"thinking_delta\") {\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"agent_thought_chunk\",\n\t\t\t\tcontent: { type: \"text\", text: ame.delta } satisfies ContentBlock,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tame.type === \"toolcall_start\" ||\n\t\t\tame.type === \"toolcall_delta\" ||\n\t\t\tame.type === \"toolcall_end\"\n\t\t) {\n\t\t\tconst toolCall = ame.type === \"toolcall_end\" ? ame.toolCall : extractToolCallFromPartial(ame);\n\t\t\tif (!toolCall) return;\n\n\t\t\tconst rawInput = parseToolInput(toolCall);\n\t\t\tconst locations = resolveToolPath(rawInput, this.cwd);\n\t\t\tconst existingStatus = this.currentToolCalls.get(toolCall.id);\n\t\t\tconst status = existingStatus ?? \"pending\";\n\n\t\t\tif (!existingStatus) {\n\t\t\t\tthis.currentToolCalls.set(toolCall.id, \"pending\");\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\ttitle: buildToolTitle(toolCall.name, rawInput),\n\t\t\t\t\tkind: toToolKind(toolCall.name),\n\t\t\t\t\tstatus,\n\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\trawInput,\n\t\t\t\t\t_meta: buildToolMeta(toolCall.name),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\tstatus,\n\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\trawInput,\n\t\t\t\t\t_meta: buildToolMeta(toolCall.name),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleMessageEnd(msg: AgentMessage): void {\n\t\tif (\"role\" in msg && msg.role === \"assistant\") {\n\t\t\tthis.lastAssistantStopReason = msg.stopReason;\n\t\t}\n\t}\n\n\tprivate handleToolStart(toolCallId: string, toolName: string, args: ToolArgs): void {\n\t\t// Track toolName for streaming updates (Phase 5)\n\t\tthis.toolCallNames.set(toolCallId, toolName);\n\n\t\tlet line: number | undefined;\n\n\t\tif ((toolName === \"edit\" || toolName === \"write\") && args.path !== undefined) {\n\t\t\ttry {\n\t\t\t\tconst abs = isAbsolute(args.path) ? args.path : resolvePath(this.cwd, args.path);\n\t\t\t\tlet oldText = \"\";\n\t\t\t\ttry {\n\t\t\t\t\toldText = readFileSync(abs, \"utf8\");\n\t\t\t\t} catch {\n\t\t\t\t\t// File may not exist yet for write -- treat as empty.\n\t\t\t\t}\n\t\t\t\tthis.editSnapshots.set(toolCallId, { path: abs, oldText });\n\t\t\t\tif (toolName === \"edit\") {\n\t\t\t\t\tline = findUniqueLineNumber(oldText, args.oldText ?? \"\");\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// snapshot failure is non-fatal\n\t\t\t}\n\t\t}\n\n\t\tconst locations = resolveToolPath(args, this.cwd, line);\n\n\t\t// Build terminal metadata for bash/tmux when client supports it\n\t\tconst terminalMeta =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? { terminal_info: { terminal_id: toolCallId, cwd: this.cwd } }\n\t\t\t\t: undefined;\n\t\tconst meta = buildToolMeta(toolName, terminalMeta);\n\n\t\t// Build content for terminal-aware clients\n\t\tconst terminalContent: ToolCallContent[] | undefined =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? [{ type: \"terminal\" as const, terminalId: toolCallId }]\n\t\t\t\t: undefined;\n\n\t\tif (!this.currentToolCalls.has(toolCallId)) {\n\t\t\tthis.currentToolCalls.set(toolCallId, \"in_progress\");\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\ttoolCallId,\n\t\t\t\ttitle: buildToolTitle(toolName, args),\n\t\t\t\tkind: toToolKind(toolName),\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t...(terminalContent !== undefined ? { content: terminalContent } : {}),\n\t\t\t\trawInput: args,\n\t\t\t\t_meta: meta,\n\t\t\t});\n\t\t} else {\n\t\t\tthis.currentToolCalls.set(toolCallId, \"in_progress\");\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\ttitle: buildToolTitle(toolName, args),\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t...(terminalContent !== undefined ? { content: terminalContent } : {}),\n\t\t\t\trawInput: args,\n\t\t\t\t_meta: meta,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolUpdate(toolCallId: string, toolName: string, partialResult: unknown): void {\n\t\t// Look up tool name from our map (Phase 5), fall back to event's toolName\n\t\tconst name = this.toolCallNames.get(toolCallId) ?? toolName;\n\n\t\tif (this.supportsTerminalOutput && isTerminalTool(name)) {\n\t\t\t// Terminal-aware path: emit only _meta.terminal_output, no content\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t_meta: buildToolMeta(name, {\n\t\t\t\t\tterminal_output: { terminal_id: toolCallId, data: text },\n\t\t\t\t}),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t} else if (isTerminalTool(name)) {\n\t\t\t// Non-terminal fallback: wrap in console code fence\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tconst wrapped = wrapStreamingBashOutput(text);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\tcontent: wrapped\n\t\t\t\t\t? ([\n\t\t\t\t\t\t\t{ type: \"content\", content: { type: \"text\", text: wrapped } },\n\t\t\t\t\t\t] satisfies ToolCallContent[])\n\t\t\t\t\t: null,\n\t\t\t\t_meta: buildToolMeta(name),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t} else {\n\t\t\t// Other tools: plain text content\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\tcontent: text\n\t\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t\t: null,\n\t\t\t\t_meta: buildToolMeta(name),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolEnd(\n\t\ttoolCallId: string,\n\t\ttoolName: string,\n\t\tresult: unknown,\n\t\tisError: boolean,\n\t): void {\n\t\tconst snapshot = this.editSnapshots.get(toolCallId);\n\t\tlet content: ToolCallContent[] | null = null;\n\n\t\t// Diff path for edit/write\n\t\tif (!isError && snapshot) {\n\t\t\ttry {\n\t\t\t\tconst newText = readFileSync(snapshot.path, \"utf8\");\n\t\t\t\tif (newText !== snapshot.oldText) {\n\t\t\t\t\tconst formatted = formatToolContent(toolName, result, isError);\n\t\t\t\t\tcontent = [\n\t\t\t\t\t\t{ type: \"diff\", path: snapshot.path, oldText: snapshot.oldText, newText },\n\t\t\t\t\t\t...formatted,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall back to formatted content\n\t\t\t}\n\t\t}\n\n\t\t// If no diff content, use formatted tool content\n\t\tif (content === null) {\n\t\t\tconst formatted = formatToolContent(toolName, result, isError);\n\t\t\tcontent = formatted.length > 0 ? formatted : null;\n\t\t}\n\n\t\t// Last resort: if formatToolContent returns empty and no diff, generate plain text\n\t\tif (content === null && !isError && toolName !== \"edit\" && toolName !== \"write\") {\n\t\t\tconst text = extractStreamingText(result);\n\t\t\tif (text) {\n\t\t\t\tcontent = [{ type: \"content\", content: { type: \"text\", text } }];\n\t\t\t}\n\t\t}\n\n\t\t// For terminal tools: emit a separate terminal_output update before terminal_exit.\n\t\t// This ensures Zed renders output before the exit status (following claude-agent-acp).\n\t\tif (this.supportsTerminalOutput && isTerminalTool(toolName)) {\n\t\t\tconst outputText = extractStreamingText(result);\n\t\t\tif (outputText !== \"\") {\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t\t_meta: buildToolMeta(toolName, {\n\t\t\t\t\t\tterminal_output: { terminal_id: toolCallId, data: outputText },\n\t\t\t\t\t}),\n\t\t\t\t\trawOutput: result,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Build terminal exit metadata for bash/tmux\n\t\tconst terminalExitMeta =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? {\n\t\t\t\t\t\tterminal_exit: {\n\t\t\t\t\t\t\tterminal_id: toolCallId,\n\t\t\t\t\t\t\texit_code: extractExitCode(result),\n\t\t\t\t\t\t\tsignal: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\tconst meta = buildToolMeta(toolName, terminalExitMeta);\n\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\ttoolCallId,\n\t\t\tstatus: isError ? \"failed\" : \"completed\",\n\t\t\tcontent,\n\t\t\t_meta: meta,\n\t\t\trawOutput: result,\n\t\t});\n\n\t\tthis.currentToolCalls.delete(toolCallId);\n\t\tthis.editSnapshots.delete(toolCallId);\n\t\tthis.toolCallNames.delete(toolCallId);\n\t}\n\n\tprivate handleAgentEnd(): void {\n\t\tthis.emitUsageUpdate();\n\t\tvoid this.flushEmits().finally(() => {\n\t\t\tconst reason: StopReason = this.cancelRequested\n\t\t\t\t? \"cancelled\"\n\t\t\t\t: mapPiStopReason(this.lastAssistantStopReason);\n\t\t\tthis.lastAssistantStopReason = null;\n\t\t\tthis.pendingTurn?.resolve(reason);\n\t\t\tthis.pendingTurn = null;\n\t\t\tthis.dequeueNextPrompt();\n\t\t});\n\t}\n\n\t/**\n\t * Emit a usage_update notification with current context and cost data.\n\t */\n\tprivate emitUsageUpdate(): void {\n\t\tconst contextUsage = this.piSession.getContextUsage?.();\n\t\tconst stats = this.piSession.getSessionStats();\n\n\t\tconst used = contextUsage?.tokens ?? 0;\n\t\tconst size = contextUsage?.contextWindow ?? 0;\n\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"usage_update\",\n\t\t\tused,\n\t\t\tsize,\n\t\t\tcost: stats.cost > 0 ? { amount: stats.cost, currency: \"USD\" } : null,\n\t\t});\n\t}\n\n\t/**\n\t * Build ACP Usage data from pi session stats for prompt response.\n\t */\n\tgetUsage(): {\n\t\tinputTokens: number;\n\t\toutputTokens: number;\n\t\tcachedReadTokens: number;\n\t\tcachedWriteTokens: number;\n\t} {\n\t\tconst stats = this.piSession.getSessionStats();\n\t\treturn {\n\t\t\tinputTokens: stats.tokens.input,\n\t\t\toutputTokens: stats.tokens.output,\n\t\t\tcachedReadTokens: stats.tokens.cacheRead,\n\t\t\tcachedWriteTokens: stats.tokens.cacheWrite,\n\t\t};\n\t}\n\n\t/**\n\t * Get cumulative session cost.\n\t */\n\tgetCost(): number {\n\t\treturn this.piSession.getSessionStats().cost;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Streaming text extraction (lightweight, no formatting)\n// ---------------------------------------------------------------------------\n\nfunction isTextBlock(v: unknown): v is { type: \"text\"; text: string } {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\t\"type\" in v &&\n\t\tv.type === \"text\" &&\n\t\t\"text\" in v &&\n\t\ttypeof v.text === \"string\"\n\t);\n}\n\nfunction extractStreamingText(result: unknown): string {\n\tif (result === null || result === undefined) return \"\";\n\tif (typeof result === \"string\") return result;\n\tif (typeof result !== \"object\") return String(result);\n\n\t// Content blocks\n\tif (\"content\" in result && Array.isArray(result.content)) {\n\t\tconst texts: string[] = [];\n\t\tfor (const raw of result.content) {\n\t\t\tif (isTextBlock(raw)) {\n\t\t\t\ttexts.push(raw.text);\n\t\t\t}\n\t\t}\n\t\tif (texts.length > 0) return texts.join(\"\");\n\t}\n\n\t// Details fields\n\tif (\"details\" in result) {\n\t\tconst details = result.details;\n\t\tif (typeof details === \"object\" && details !== null) {\n\t\t\tif (\"stdout\" in details && typeof details.stdout === \"string\" && details.stdout.trim() !== \"\")\n\t\t\t\treturn details.stdout;\n\t\t\tif (\"output\" in details && typeof details.output === \"string\" && details.output.trim() !== \"\")\n\t\t\t\treturn details.output;\n\t\t}\n\t}\n\n\t// Top-level output/stdout\n\tif (\"output\" in result && typeof result.output === \"string\" && result.output.trim() !== \"\")\n\t\treturn result.output;\n\tif (\"stdout\" in result && typeof result.stdout === \"string\" && result.stdout.trim() !== \"\")\n\t\treturn result.stdout;\n\n\treturn \"\";\n}\n\nfunction extractExitCode(result: unknown): number | null {\n\tif (result === null || result === undefined || typeof result !== \"object\") return null;\n\n\tif (\"details\" in result) {\n\t\tconst details = result.details;\n\t\tif (typeof details === \"object\" && details !== null) {\n\t\t\tif (\"exitCode\" in details && typeof details.exitCode === \"number\") return details.exitCode;\n\t\t\tif (\"code\" in details && typeof details.code === \"number\") return details.code;\n\t\t}\n\t}\n\n\tif (\"exitCode\" in result && typeof result.exitCode === \"number\") return result.exitCode;\n\tif (\"code\" in result && typeof result.code === \"number\") return result.code;\n\n\treturn null;\n}\n\n/**\n * Type guard to narrow AgentSessionEvent to the AgentEvent subset\n * (the variants we handle). Session-specific events like auto_compaction\n * are ignored.\n */\nfunction isAgentEvent(\n\tev: AgentSessionEvent,\n): ev is Extract<\n\tAgentEvent,\n\t| { type: \"message_update\" }\n\t| { type: \"message_end\" }\n\t| { type: \"tool_execution_start\" }\n\t| { type: \"tool_execution_update\" }\n\t| { type: \"tool_execution_end\" }\n\t| { type: \"agent_end\" }\n> {\n\treturn (\n\t\tev.type === \"message_update\" ||\n\t\tev.type === \"message_end\" ||\n\t\tev.type === \"tool_execution_start\" ||\n\t\tev.type === \"tool_execution_update\" ||\n\t\tev.type === \"tool_execution_end\" ||\n\t\tev.type === \"agent_end\"\n\t);\n}\n","/**\n * Extract plain text from pi message content.\n *\n * Pi messages store content as either a string or an array of typed blocks.\n * These helpers extract the text portions for ACP session replay.\n */\n\ninterface TextBlock {\n\ttype: \"text\";\n\ttext: string;\n}\n\nfunction isTextBlock(block: unknown): block is TextBlock {\n\tif (typeof block !== \"object\" || block === null) return false;\n\treturn (\n\t\t\"type\" in block && block.type === \"text\" && \"text\" in block && typeof block.text === \"string\"\n\t);\n}\n\nexport function extractUserMessageText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter(isTextBlock)\n\t\t.map((b) => b.text)\n\t\t.join(\"\");\n}\n\nexport function extractAssistantText(content: unknown): string {\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter(isTextBlock)\n\t\t.map((b) => b.text)\n\t\t.join(\"\");\n}\n","/**\n * Convert ACP prompt ContentBlocks to a pi-compatible message string and image array.\n */\n\nimport type { ContentBlock } from \"@agentclientprotocol/sdk\";\n\nexport interface PiImage {\n\ttype: \"image\";\n\tmimeType: string;\n\tdata: string;\n}\n\nexport function acpPromptToPiMessage(blocks: ContentBlock[]): {\n\tmessage: string;\n\timages: PiImage[];\n} {\n\tlet message = \"\";\n\tconst images: PiImage[] = [];\n\n\tfor (const block of blocks) {\n\t\tswitch (block.type) {\n\t\t\tcase \"text\":\n\t\t\t\tmessage += block.text;\n\t\t\t\tbreak;\n\n\t\t\tcase \"resource_link\":\n\t\t\t\tmessage += `\\n[Context] ${block.uri}`;\n\t\t\t\tbreak;\n\n\t\t\tcase \"image\":\n\t\t\t\timages.push({\n\t\t\t\t\ttype: \"image\",\n\t\t\t\t\tmimeType: block.mimeType,\n\t\t\t\t\tdata: block.data,\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase \"resource\": {\n\t\t\t\tconst resource = block.resource;\n\t\t\t\tconst uri = resource.uri;\n\t\t\t\tconst mime = resource.mimeType ?? null;\n\n\t\t\t\tif (\"text\" in resource) {\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri} (${mime ?? \"text/plain\"})\\n${resource.text}`;\n\t\t\t\t} else if (\"blob\" in resource) {\n\t\t\t\t\tconst bytes = Buffer.byteLength(resource.blob, \"base64\");\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri} (${mime ?? \"application/octet-stream\"}, ${bytes} bytes)`;\n\t\t\t\t} else {\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri}`;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"audio\": {\n\t\t\t\tconst bytes = Buffer.byteLength(block.data, \"base64\");\n\t\t\t\tmessage += `\\n[Audio] (${block.mimeType}, ${bytes} bytes) not supported`;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn { message, images };\n}\n","/**\n * PRD-002 §FR-7 — opt-in diagnostics surface.\n *\n * When the manifest sets `diagnostics: true`, pi-acp emits a one- or\n * two-paragraph summary at session start (before any model output) listing\n * every resource source and any reload failures. Pure formatting — no\n * side effects on the loader or session state.\n *\n * Surface choice: the agent emits this as an `agent_message_chunk` on the\n * first prompt of the session (chosen per PRD §FR-7 acceptance). It lives\n * at the session boundary, never interleaved with model text.\n */\n\nimport type { ManifestDiagnostic } from \"@pi-acp/resources/manifest\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\n\nexport interface DiagnosticsInput {\n\tsources: ResourceSource[];\n\t/**\n\t * Manifest-level diagnostics (parse failures, unsupported root kinds,\n\t * etc.) collected during `buildResourceLoader`.\n\t */\n\tmanifestDiagnostics: ManifestDiagnostic[];\n}\n\nexport interface DiagnosticsReport {\n\t/**\n\t * Full multi-line summary. Empty string when there's nothing to say\n\t * (no manifest diagnostics + every source contributed zero failures).\n\t */\n\ttext: string;\n\t/** Per-source stat counts, exposed for tests. */\n\tsourceStats: Array<{\n\t\tid: string;\n\t\tkind: ResourceSource[\"kind\"];\n\t\tagentsFiles: number;\n\t\tskills: number;\n\t\tprompts: number;\n\t\tfailures: string[];\n\t}>;\n}\n\nexport function buildDiagnosticsReport(input: DiagnosticsInput): DiagnosticsReport {\n\tconst sourceStats = input.sources.map((source) => {\n\t\tconst skills = source.getSkills();\n\t\tconst prompts = source.getPrompts();\n\t\tconst failures = skills.diagnostics\n\t\t\t.filter((d) => d.type === \"warning\" || d.type === \"error\")\n\t\t\t.map((d) => d.message);\n\t\treturn {\n\t\t\tid: source.id,\n\t\t\tkind: source.kind,\n\t\t\tagentsFiles: source.getAgentsFiles().length,\n\t\t\tskills: skills.skills.length,\n\t\t\tprompts: prompts.prompts.length,\n\t\t\tfailures,\n\t\t};\n\t});\n\n\tconst lines: string[] = [];\n\tif (sourceStats.length > 0) {\n\t\tlines.push(\"[pi-acp] resources active:\");\n\t\tfor (const s of sourceStats) {\n\t\t\tlines.push(\n\t\t\t\t` ${s.id.padEnd(20)} kind=${s.kind} (${s.agentsFiles} AGENTS files, ${s.skills} skills, ${s.prompts} prompts)`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst allFailures: string[] = [];\n\tfor (const s of sourceStats) {\n\t\tfor (const f of s.failures) allFailures.push(` ${s.id.padEnd(20)} ${f}`);\n\t}\n\tfor (const d of input.manifestDiagnostics) {\n\t\tconst where = d.path !== undefined ? ` ${d.path}` : \"\";\n\t\tallFailures.push(` manifest[${d.source}${where}] ${d.message}`);\n\t}\n\tif (allFailures.length > 0) {\n\t\tif (lines.length > 0) lines.push(\"\");\n\t\tlines.push(\"[pi-acp] resource failures:\");\n\t\tlines.push(...allFailures);\n\t}\n\n\treturn { text: lines.join(\"\\n\"), sourceStats };\n}\n","/**\n * LocalBackend: wraps pi's DefaultResourceLoader for one (cwd, agentDir) root.\n * Phase 4 skeleton — manifest support (multiple local roots) lands in Phase 5.\n */\n\nimport {\n\tDefaultResourceLoader,\n\ttype LoadExtensionsResult,\n\ttype PromptTemplate,\n\ttype ResourceDiagnostic,\n\ttype Skill,\n} from \"@earendil-works/pi-coding-agent\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\n\nexport interface LocalBackendOptions {\n\tid?: string;\n\tcwd: string;\n\tagentDir: string;\n}\n\nexport class LocalBackend implements ResourceSource {\n\treadonly id: string;\n\treadonly kind = \"local\" as const;\n\tprivate readonly loader: DefaultResourceLoader;\n\n\tconstructor(opts: LocalBackendOptions) {\n\t\tthis.id = opts.id ?? \"local\";\n\t\tthis.loader = new DefaultResourceLoader({ cwd: opts.cwd, agentDir: opts.agentDir });\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait this.loader.reload();\n\t}\n\n\tgetAgentsFiles(): Array<{ path: string; content: string }> {\n\t\treturn this.loader.getAgentsFiles().agentsFiles;\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn this.loader.getSkills();\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn this.loader.getPrompts();\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\treturn this.loader.getExtensions();\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn this.loader.getSystemPrompt();\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn this.loader.getAppendSystemPrompt();\n\t}\n\n\t/**\n\t * Expose the wrapped DefaultResourceLoader for VirtualResourceLoader's\n\t * extension/theme passthrough. Other backends don't expose this.\n\t */\n\tinner(): DefaultResourceLoader {\n\t\treturn this.loader;\n\t}\n}\n","/**\n * VirtualResourceLoader: implements pi's ResourceLoader interface as a\n * composer over multiple ResourceSource instances.\n *\n * Phase 4 ships the skeleton with a single LocalBackend default — behaviour\n * identical to v0.5's bare `createAgentSession({ cwd })` (which auto-builds a\n * DefaultResourceLoader). The point of going through this layer now is to\n * make Phase 5+ additive: manifest declares additional sources; loader\n * aggregates without changing PiAcpAgent's wire shape.\n */\n\nimport type {\n\tLoadExtensionsResult,\n\tPromptTemplate,\n\tResourceDiagnostic,\n\tResourceLoader,\n\tSkill,\n} from \"@earendil-works/pi-coding-agent\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\nimport { LocalBackend } from \"@pi-acp/resources/sources/local\";\n\n/** Mirrors pi's internal ResourceExtensionPaths (not re-exported from package root). */\ntype ResourceExtensionPaths = Parameters<ResourceLoader[\"extendResources\"]>[0];\n\nexport type MergeStrategy = \"append\" | \"override-by-name\";\n\nexport interface VirtualResourceLoaderOptions {\n\tsources: ResourceSource[];\n\tmergeStrategy?: MergeStrategy;\n\t/**\n\t * One source designated as primary supplies extensions + runtime.\n\t * Defaults to the first local source. Must satisfy the LocalBackend\n\t * interface contract for extensions / themes.\n\t */\n\tprimarySourceId?: string;\n}\n\nexport class VirtualResourceLoader implements ResourceLoader {\n\tprivate readonly sources: ResourceSource[];\n\tprivate readonly mergeStrategy: MergeStrategy;\n\tprivate readonly primary: LocalBackend;\n\n\tconstructor(opts: VirtualResourceLoaderOptions) {\n\t\tif (opts.sources.length === 0) {\n\t\t\tthrow new Error(\"VirtualResourceLoader requires at least one source\");\n\t\t}\n\t\tthis.sources = opts.sources;\n\t\tthis.mergeStrategy = opts.mergeStrategy ?? \"append\";\n\t\tconst primary = resolvePrimary(opts.sources, opts.primarySourceId);\n\t\tthis.primary = primary;\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tawait Promise.all(this.sources.map((s) => s.reload()));\n\t}\n\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content: string }> } {\n\t\tconst seen = new Set<string>();\n\t\tconst merged: Array<{ path: string; content: string }> = [];\n\t\tfor (const source of this.sources) {\n\t\t\tfor (const file of source.getAgentsFiles()) {\n\t\t\t\tif (seen.has(file.path)) continue;\n\t\t\t\tseen.add(file.path);\n\t\t\t\tmerged.push(file);\n\t\t\t}\n\t\t}\n\t\treturn { agentsFiles: merged };\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst merge = createMerger<Skill>(this.mergeStrategy, (s) => s.name);\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tfor (const source of this.sources) {\n\t\t\tconst result = source.getSkills();\n\t\t\tmerge.absorb(result.skills);\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t\treturn { skills: merge.list(), diagnostics };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst merge = createMerger<PromptTemplate>(this.mergeStrategy, (p) => p.name);\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tfor (const source of this.sources) {\n\t\t\tconst result = source.getPrompts();\n\t\t\tmerge.absorb(result.prompts);\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t\treturn { prompts: merge.list(), diagnostics };\n\t}\n\n\tgetThemes(): {\n\t\tthemes: ReturnType<ResourceLoader[\"getThemes\"]>[\"themes\"];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t} {\n\t\treturn this.primary.inner().getThemes();\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\t// Pi's extension runtime is owned by the primary backend's\n\t\t// DefaultResourceLoader. Multi-source extension composition is\n\t\t// out of scope for v0.6.\n\t\treturn this.primary.getExtensions();\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\tfor (const source of this.sources) {\n\t\t\tconst sp = source.getSystemPrompt();\n\t\t\tif (sp !== undefined) return sp;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\tconst merged: string[] = [];\n\t\tfor (const source of this.sources) merged.push(...source.getAppendSystemPrompt());\n\t\treturn merged;\n\t}\n\n\textendResources(paths: ResourceExtensionPaths): void {\n\t\t// Forward to the primary backend's underlying DefaultResourceLoader.\n\t\tthis.primary.inner().extendResources(paths);\n\t}\n\n\t/** Returns the active source list. Useful for diagnostics. */\n\tlistSources(): ResourceSource[] {\n\t\treturn [...this.sources];\n\t}\n}\n\nfunction resolvePrimary(sources: ResourceSource[], preferredId: string | undefined): LocalBackend {\n\tif (preferredId !== undefined) {\n\t\tconst found = sources.find((s) => s.id === preferredId);\n\t\tif (found === undefined) {\n\t\t\tthrow new Error(`VirtualResourceLoader: primarySourceId \"${preferredId}\" not in sources`);\n\t\t}\n\t\tif (!(found instanceof LocalBackend)) {\n\t\t\tthrow new Error(\n\t\t\t\t`VirtualResourceLoader: primary source \"${preferredId}\" must be a LocalBackend`,\n\t\t\t);\n\t\t}\n\t\treturn found;\n\t}\n\tconst firstLocal = sources.find((s): s is LocalBackend => s instanceof LocalBackend);\n\tif (firstLocal === undefined) {\n\t\tthrow new Error(\n\t\t\t\"VirtualResourceLoader: at least one LocalBackend is required (for extensions + themes)\",\n\t\t);\n\t}\n\treturn firstLocal;\n}\n\ninterface Merger<T> {\n\tabsorb(items: T[]): void;\n\tlist(): T[];\n}\n\nfunction createMerger<T>(strategy: MergeStrategy, key: (item: T) => string): Merger<T> {\n\tif (strategy === \"append\") {\n\t\tconst out: T[] = [];\n\t\treturn {\n\t\t\tabsorb(items) {\n\t\t\t\tout.push(...items);\n\t\t\t},\n\t\t\tlist() {\n\t\t\t\treturn out;\n\t\t\t},\n\t\t};\n\t}\n\tconst byKey = new Map<string, T>();\n\treturn {\n\t\tabsorb(items) {\n\t\t\tfor (const item of items) byKey.set(key(item), item);\n\t\t},\n\t\tlist() {\n\t\t\treturn Array.from(byKey.values());\n\t\t},\n\t};\n}\n","/**\n * Zod schema for the `.pi-acp.yaml` resource composition manifest (ADR-0008).\n *\n * Backend kinds: `local`, `ssh`, `http`, `acp-fs`. Phase 5 ships parsing and\n * validation for all four; only `local` is honored by the loader until the\n * remote-backend phases land — unknown kinds parse fine and surface as a\n * diagnostic at load time.\n */\n\nimport * as z from \"zod\";\n\nconst IdSchema = z.string().trim().min(1, \"id is required\");\n\nconst LocalPathsSchema = z\n\t.object({\n\t\tcwd: z.string().trim().optional(),\n\t\tagentDir: z.string().trim().optional(),\n\t})\n\t.strict();\n\nconst RemotePathsSchema = z\n\t.object({\n\t\tskills: z.string().trim().optional(),\n\t\tprompts: z.string().trim().optional(),\n\t\tagentsFiles: z.array(z.string().trim()).optional(),\n\t\textensions: z.string().trim().optional(),\n\t})\n\t.strict();\n\nconst LocalRootSchema = z\n\t.object({\n\t\tid: IdSchema,\n\t\tkind: z.literal(\"local\"),\n\t\tpaths: LocalPathsSchema.default({}),\n\t})\n\t.strict();\n\nconst SshRootSchema = z\n\t.object({\n\t\tid: IdSchema,\n\t\tkind: z.literal(\"ssh\"),\n\t\thost: z.string().trim().min(1),\n\t\tuser: z.string().trim().optional(),\n\t\tpaths: RemotePathsSchema.default({}),\n\t})\n\t.strict();\n\nconst HttpRootSchema = z\n\t.object({\n\t\tid: IdSchema,\n\t\tkind: z.literal(\"http\"),\n\t\tbaseUrl: z.url().refine((u) => u.startsWith(\"https://\"), {\n\t\t\terror: \"baseUrl must use https://\",\n\t\t}),\n\t\tcache: z.object({ ttl: z.int().nonnegative() }).strict().optional(),\n\t\tpaths: RemotePathsSchema.default({}),\n\t})\n\t.strict();\n\nconst AcpFsRootSchema = z\n\t.object({\n\t\tid: IdSchema,\n\t\tkind: z.literal(\"acp-fs\"),\n\t\tpaths: RemotePathsSchema.default({}),\n\t})\n\t.strict();\n\nexport const RootSchema = z.discriminatedUnion(\"kind\", [\n\tLocalRootSchema,\n\tSshRootSchema,\n\tHttpRootSchema,\n\tAcpFsRootSchema,\n]);\n\nexport const AutoImportSchema = z\n\t.object({\n\t\tsource: IdSchema,\n\t\tpaths: z.array(z.string().trim()).min(1),\n\t})\n\t.strict();\n\nexport const ManifestSchema = z\n\t.object({\n\t\tversion: z.literal(1),\n\t\tmode: z.enum([\"local\", \"overlay\", \"none\"]).default(\"local\"),\n\t\troots: z.array(RootSchema).default([]),\n\t\tmergeStrategy: z.enum([\"append\", \"override-by-name\"]).default(\"append\"),\n\t\tautoImport: z.array(AutoImportSchema).optional(),\n\t\tdiagnostics: z.boolean().default(false),\n\t})\n\t.strict();\n\nexport type Manifest = z.infer<typeof ManifestSchema>;\nexport type Root = z.infer<typeof RootSchema>;\nexport type AutoImportEntry = z.infer<typeof AutoImportSchema>;\n\nexport const DEFAULT_MANIFEST: Manifest = {\n\tversion: 1,\n\tmode: \"local\",\n\troots: [],\n\tmergeStrategy: \"append\",\n\tdiagnostics: false,\n};\n","/**\n * Cascade resolver for the `.pi-acp.yaml` resource composition manifest\n * (ADR-0008, PRD-002 §FR-3).\n *\n * Precedence (highest first):\n * 1. ACP session params: `params._meta.piAcp.manifest`\n * — either an inline manifest object or a string path to a YAML file\n * 2. Project-level: `<cwd>/.pi-acp.yaml`\n * 3. User-global: `~/.pi-acp/config.yaml`\n * 4. Synthesized default\n *\n * Parse errors at any layer fall through to the next; the caller never gets\n * an exception. Errors collect into the returned `diagnostics` list so they\n * can be surfaced to the operator.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { DEFAULT_MANIFEST, type Manifest, ManifestSchema } from \"@pi-acp/resources/manifest.schema\";\nimport { parse as parseYaml } from \"yaml\";\n\nexport interface ManifestDiagnostic {\n\tsource: \"session-params\" | \"project\" | \"user-global\" | \"default\";\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface LoadManifestInput {\n\tcwd: string;\n\tsessionParams?: unknown;\n}\n\nexport interface LoadManifestResult {\n\tmanifest: Manifest;\n\tsource: ManifestDiagnostic[\"source\"];\n\tpath?: string;\n\tdiagnostics: ManifestDiagnostic[];\n}\n\nconst USER_MANIFEST_PATH = join(homedir(), \".pi-acp\", \"config.yaml\");\nconst PROJECT_MANIFEST_BASENAME = \".pi-acp.yaml\";\n\nexport async function loadManifest(input: LoadManifestInput): Promise<LoadManifestResult> {\n\tconst diagnostics: ManifestDiagnostic[] = [];\n\n\tconst fromParams = await tryFromSessionParams(input.sessionParams, diagnostics);\n\tif (fromParams !== null) {\n\t\tconst result: LoadManifestResult = {\n\t\t\tmanifest: fromParams.manifest,\n\t\t\tsource: \"session-params\",\n\t\t\tdiagnostics,\n\t\t};\n\t\tif (fromParams.path !== undefined) result.path = fromParams.path;\n\t\treturn result;\n\t}\n\n\tconst projectPath = join(input.cwd, PROJECT_MANIFEST_BASENAME);\n\tconst fromProject = tryFromFile(projectPath, \"project\", diagnostics);\n\tif (fromProject !== null) {\n\t\treturn { manifest: fromProject, source: \"project\", path: projectPath, diagnostics };\n\t}\n\n\tconst fromUser = tryFromFile(USER_MANIFEST_PATH, \"user-global\", diagnostics);\n\tif (fromUser !== null) {\n\t\treturn { manifest: fromUser, source: \"user-global\", path: USER_MANIFEST_PATH, diagnostics };\n\t}\n\n\treturn { manifest: DEFAULT_MANIFEST, source: \"default\", diagnostics };\n}\n\nasync function tryFromSessionParams(\n\tparams: unknown,\n\tdiagnostics: ManifestDiagnostic[],\n): Promise<{ manifest: Manifest; path?: string } | null> {\n\tif (typeof params !== \"object\" || params === null) return null;\n\tconst meta = (params as { _meta?: unknown })._meta;\n\tif (typeof meta !== \"object\" || meta === null) return null;\n\tconst piAcp = (meta as { piAcp?: unknown }).piAcp;\n\tif (typeof piAcp !== \"object\" || piAcp === null) return null;\n\tconst manifestRef = (piAcp as { manifest?: unknown }).manifest;\n\tif (manifestRef === undefined) return null;\n\n\tif (typeof manifestRef === \"string\") {\n\t\tconst parsed = tryFromFile(manifestRef, \"session-params\", diagnostics);\n\t\tif (parsed !== null) return { manifest: parsed, path: manifestRef };\n\t\treturn null;\n\t}\n\n\tconst result = ManifestSchema.safeParse(manifestRef);\n\tif (result.success) return { manifest: result.data };\n\tdiagnostics.push({\n\t\tsource: \"session-params\",\n\t\tmessage: `inline manifest validation failed: ${result.error.message}`,\n\t});\n\treturn null;\n}\n\nfunction tryFromFile(\n\tpath: string,\n\tsource: ManifestDiagnostic[\"source\"],\n\tdiagnostics: ManifestDiagnostic[],\n): Manifest | null {\n\tif (!existsSync(path)) return null;\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(path, \"utf8\");\n\t} catch (err) {\n\t\tdiagnostics.push({\n\t\t\tsource,\n\t\t\tpath,\n\t\t\tmessage: `read failed: ${err instanceof Error ? err.message : String(err)}`,\n\t\t});\n\t\treturn null;\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(raw);\n\t} catch (err) {\n\t\tdiagnostics.push({\n\t\t\tsource,\n\t\t\tpath,\n\t\t\tmessage: `YAML parse failed: ${err instanceof Error ? err.message : String(err)}`,\n\t\t});\n\t\treturn null;\n\t}\n\tconst result = ManifestSchema.safeParse(parsed);\n\tif (result.success) return result.data;\n\tdiagnostics.push({\n\t\tsource,\n\t\tpath,\n\t\tmessage: `schema validation failed: ${result.error.message}`,\n\t});\n\treturn null;\n}\n","/**\n * Cwd-independence modes (PRD-002 §FR-5).\n *\n * | Mode | cwd handling | Tool target |\n * |-----------|--------------------------------------------|---------------|\n * | `local` | ACP params.cwd (must be absolute) | params.cwd |\n * | `overlay` | same as local — manifest aux roots compose | params.cwd |\n * | `none` | substitute ephemeral tmpdir | tmpdir |\n *\n * `local` and `overlay` are functionally identical in the current substrate\n * because `VirtualResourceLoader` always overlays manifest roots on top of\n * the implicit local root. The `overlay` keyword is retained for\n * forward-compatibility and operator clarity (declaring `mode: overlay`\n * documents the intent even if the runtime path is the same).\n *\n * `none` mints `mkdtemp(...)` under the OS tmpdir and returns a cleanup\n * thunk the caller must invoke at session close. The cleanup is\n * best-effort — never throws — so a session dispose path that runs it\n * after the directory has already been removed is safe.\n */\n\nimport { mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { Manifest } from \"@pi-acp/resources/manifest.schema\";\n\nexport type CwdMode = Manifest[\"mode\"];\n\nexport interface ResolveModeInput {\n\tmanifest: Manifest;\n\trequestedCwd: string;\n}\n\nexport interface ResolveModeResult {\n\tmode: CwdMode;\n\t/**\n\t * Effective cwd to thread through pi and ACP session updates. For\n\t * `local` / `overlay` this echoes `requestedCwd`; for `none` it's a\n\t * freshly-minted tmpdir.\n\t */\n\tcwd: string;\n\t/**\n\t * Best-effort cleanup. Always defined to simplify caller wiring; a\n\t * no-op for `local` / `overlay`. Idempotent.\n\t */\n\tcleanup: () => void;\n\t/**\n\t * True when the resolver created an ephemeral directory the caller\n\t * does NOT own. Useful for diagnostics + skipping the absolute-path\n\t * guard in callers that would normally reject a synthetic cwd.\n\t */\n\tephemeral: boolean;\n}\n\nconst TMPDIR_PREFIX = \"pi-acp-session-\";\n\nexport function resolveMode(input: ResolveModeInput): ResolveModeResult {\n\tconst mode = input.manifest.mode;\n\n\tif (mode === \"none\") {\n\t\tconst dir = mkdtempSync(join(tmpdir(), TMPDIR_PREFIX));\n\t\tlet removed = false;\n\t\tconst cleanup = (): void => {\n\t\t\tif (removed) return;\n\t\t\tremoved = true;\n\t\t\ttry {\n\t\t\t\trmSync(dir, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\t// best-effort — fall through silently\n\t\t\t}\n\t\t};\n\t\treturn { mode, cwd: dir, cleanup, ephemeral: true };\n\t}\n\n\t// local + overlay: pass requestedCwd through untouched.\n\treturn {\n\t\tmode,\n\t\tcwd: input.requestedCwd,\n\t\tcleanup: () => {},\n\t\tephemeral: false,\n\t};\n}\n","/**\n * HttpBackend: reads resource files from a remote HTTPS endpoint.\n *\n * Phase 7 scope: AGENTS files via explicit `paths.agentsFiles` list only.\n * Skills, prompts, and extensions emit a \"not yet implemented over http\"\n * diagnostic each — they need either an explicit file manifest or a\n * directory-listing convention that no public CDN ships natively.\n *\n * HTTPS-only at construction (defensive — manifest schema also enforces).\n * Per-URL in-memory TTL cache (default 300 s) survives across reload() calls\n * so repeated session bootstraps within the TTL window skip the network.\n * Per-request timeout via AbortController; default 5_000 ms per PRD-002 §FR-2.\n *\n * No write semantics. No redirect chasing beyond `fetch`'s default behavior\n * (follow). No auth — public URLs only; private resources should be exposed\n * via SSH or a future authed-fetch source.\n */\n\nimport type { PromptTemplate, ResourceDiagnostic, Skill } from \"@earendil-works/pi-coding-agent\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\n\nexport interface HttpBackendPaths {\n\tskills?: string | undefined;\n\tprompts?: string | undefined;\n\tagentsFiles?: string[] | undefined;\n\textensions?: string | undefined;\n}\n\nexport interface HttpBackendOptions {\n\tid: string;\n\tbaseUrl: string;\n\tpaths?: HttpBackendPaths;\n\t/** Cache TTL in seconds. Default 300 per PRD-002 §FR-2. */\n\tcacheTtlSeconds?: number;\n\t/** Per-request timeout in ms. Default 5_000. */\n\ttimeoutMs?: number;\n\t/**\n\t * `fetch` impl override. Tests inject a stub. Defaults to the global\n\t * `fetch` bound to `globalThis`.\n\t */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface UrlCacheEntry {\n\tcontent: string;\n\texpiresAt: number;\n}\n\ninterface AgentsFileCache {\n\tfiles: Array<{ path: string; content: string }>;\n\tdiagnostics: ResourceDiagnostic[];\n}\n\nconst DEFAULT_CACHE_TTL_SECONDS = 300;\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport class HttpBackend implements ResourceSource {\n\treadonly id: string;\n\treadonly kind = \"http\" as const;\n\tprivate readonly baseUrl: string;\n\tprivate readonly paths: HttpBackendPaths;\n\tprivate readonly cacheTtlMs: number;\n\tprivate readonly timeoutMs: number;\n\tprivate readonly fetchImpl: typeof fetch;\n\tprivate readonly urlCache = new Map<string, UrlCacheEntry>();\n\tprivate cache: AgentsFileCache | null = null;\n\n\tconstructor(opts: HttpBackendOptions) {\n\t\tif (!opts.baseUrl.startsWith(\"https://\")) {\n\t\t\tthrow new Error(\n\t\t\t\t`pi-acp http source '${opts.id}': baseUrl must use https:// (got \"${opts.baseUrl}\")`,\n\t\t\t);\n\t\t}\n\t\tthis.id = opts.id;\n\t\tthis.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n\t\tthis.paths = opts.paths ?? {};\n\t\tthis.cacheTtlMs = (opts.cacheTtlSeconds ?? DEFAULT_CACHE_TTL_SECONDS) * 1000;\n\t\tthis.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\t\tthis.fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tfor (const kind of [\"skills\", \"prompts\", \"extensions\"] as const) {\n\t\t\tif (this.paths[kind] !== undefined) {\n\t\t\t\tdiagnostics.push(this.unsupportedDiagnostic(kind));\n\t\t\t}\n\t\t}\n\t\tconst list = this.paths.agentsFiles ?? [];\n\t\tconst files: Array<{ path: string; content: string }> = [];\n\t\tif (list.length > 0) {\n\t\t\tconst results = await Promise.all(\n\t\t\t\tlist.map((path) =>\n\t\t\t\t\tthis.fetchPath(path).then(\n\t\t\t\t\t\t(content) => ({ path, content, error: null as string | null }),\n\t\t\t\t\t\t(err: unknown) => ({\n\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\tcontent: null as string | null,\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t\tfor (const r of results) {\n\t\t\t\tif (r.content !== null) {\n\t\t\t\t\tfiles.push({ path: this.qualifyPath(r.path), content: r.content });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `pi-acp http source '${this.id}' (${this.baseUrl}): agentsFile '${r.path}' unreadable — ${r.error ?? \"(unknown)\"}`,\n\t\t\t\t\tpath: r.path,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.cache = { files, diagnostics };\n\t}\n\n\tgetAgentsFiles(): Array<{ path: string; content: string }> {\n\t\treturn this.cache?.files ?? [];\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { skills: [], diagnostics: this.cache?.diagnostics ?? [] };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: [], diagnostics: [] };\n\t}\n\n\t// `getExtensions` omitted — VirtualResourceLoader routes extensions\n\t// through the primary LocalBackend. Unsupported `paths.extensions`\n\t// surfaces as a diagnostic via reload() + getSkills().\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn [];\n\t}\n\n\tprivate qualifyPath(path: string): string {\n\t\treturn `${this.baseUrl}/${path.replace(/^\\/+/, \"\")}`;\n\t}\n\n\tprivate unsupportedDiagnostic(kind: \"skills\" | \"prompts\" | \"extensions\"): ResourceDiagnostic {\n\t\treturn {\n\t\t\ttype: \"warning\",\n\t\t\tmessage: `pi-acp http source '${this.id}' (${this.baseUrl}): ${kind} discovery over HTTP not yet implemented — declare individual files via paths.agentsFiles for now, or omit paths.${kind}.`,\n\t\t};\n\t}\n\n\tprivate async fetchPath(path: string): Promise<string> {\n\t\tconst url = this.qualifyPath(path);\n\t\tconst now = Date.now();\n\t\tconst cached = this.urlCache.get(url);\n\t\tif (cached !== undefined && cached.expiresAt > now) {\n\t\t\treturn cached.content;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tconst timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this.fetchImpl(url, { signal: controller.signal });\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && err.name === \"AbortError\") {\n\t\t\t\tthrow new Error(`fetch timed out after ${this.timeoutMs}ms`);\n\t\t\t}\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`HTTP ${response.status} ${response.statusText || \"\"}`.trim());\n\t\t}\n\t\tconst content = await response.text();\n\t\tthis.urlCache.set(url, { content, expiresAt: now + this.cacheTtlMs });\n\t\treturn content;\n\t}\n}\n","/**\n * SshBackend: reads resource files from a remote host via the system `ssh`\n * command. Honors the operator's `~/.ssh/config` (ProxyJump, ControlMaster,\n * agent forwarding) by design — we shell out to the real `ssh` binary\n * rather than re-implementing SFTP. PRD-002 §FR-2.\n *\n * Phase 6 scope: AGENTS files via explicit `paths.agentsFiles` list only.\n * Skills, prompts, and extensions emit a single \"not yet implemented over\n * ssh\" diagnostic each — they need either remote directory enumeration (no\n * `fs/listDir` analogue on the wire today) or an explicit file manifest,\n * both deferred to future phases.\n *\n * Timeout: pure ssh-protocol options — `-o ConnectTimeout=N` caps the TCP\n * + handshake phase; `-o ServerAliveInterval=2 -o ServerAliveCountMax=N`\n * caps post-auth silence on a stalled remote. ssh self-terminates without\n * any caller-side wrapper. Bun Shell `$` interpolations are auto-escaped;\n * `ShellPromise` has no `.timeout()` primitive (verified at runtime\n * against bun 1.3.14 — only `cwd/env/quiet/nothrow/throws/text/json/\n * lines/arrayBuffer/bytes/blob/run/then`), but ssh's own options cover\n * the 99% of real-world stall modes. See the `bun-shell` skill.\n */\n\nimport type { PromptTemplate, ResourceDiagnostic, Skill } from \"@earendil-works/pi-coding-agent\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\nimport { $ } from \"bun\";\n\nexport interface SshBackendPaths {\n\tskills?: string | undefined;\n\tprompts?: string | undefined;\n\tagentsFiles?: string[] | undefined;\n\textensions?: string | undefined;\n}\n\nexport interface SshBackendOptions {\n\tid: string;\n\thost: string;\n\tuser?: string;\n\tpaths?: SshBackendPaths;\n\t/** Per-operation timeout. Default 5_000ms per PRD-002 §FR-2. */\n\ttimeoutMs?: number;\n\t/**\n\t * ssh binary path. Defaults to `\"ssh\"` (resolved via PATH). Tests\n\t * inject an absolute-path shim because Bun.spawn's PATH lookup does\n\t * not honor runtime `process.env.PATH` mutations.\n\t */\n\tsshCommand?: string;\n}\n\ninterface AgentsFileCache {\n\tfiles: Array<{ path: string; content: string }>;\n\tdiagnostics: ResourceDiagnostic[];\n}\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport class SshBackend implements ResourceSource {\n\treadonly id: string;\n\treadonly kind = \"ssh\" as const;\n\tprivate readonly host: string;\n\tprivate readonly user: string | undefined;\n\tprivate readonly paths: SshBackendPaths;\n\tprivate readonly timeoutMs: number;\n\tprivate readonly sshCommand: string;\n\tprivate cache: AgentsFileCache | null = null;\n\n\tconstructor(opts: SshBackendOptions) {\n\t\tthis.id = opts.id;\n\t\tthis.host = opts.host;\n\t\tthis.user = opts.user;\n\t\tthis.paths = opts.paths ?? {};\n\t\tthis.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\t\tthis.sshCommand = opts.sshCommand ?? \"ssh\";\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tfor (const kind of [\"skills\", \"prompts\", \"extensions\"] as const) {\n\t\t\tif (this.paths[kind] !== undefined) {\n\t\t\t\tdiagnostics.push(this.unsupportedDiagnostic(kind));\n\t\t\t}\n\t\t}\n\t\tconst list = this.paths.agentsFiles ?? [];\n\t\tconst files: Array<{ path: string; content: string }> = [];\n\t\tif (list.length > 0) {\n\t\t\tconst results = await Promise.all(\n\t\t\t\tlist.map((path) =>\n\t\t\t\t\tthis.cat(path).then(\n\t\t\t\t\t\t(content) => ({ path, content, error: null as string | null }),\n\t\t\t\t\t\t(err: unknown) => ({\n\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\tcontent: null as string | null,\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t\tfor (const r of results) {\n\t\t\t\tif (r.content !== null) {\n\t\t\t\t\tfiles.push({ path: this.qualifyPath(r.path), content: r.content });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"warning\",\n\t\t\t\t\tmessage: `pi-acp ssh source '${this.id}' (${this.target()}): agentsFile '${r.path}' unreadable — ${r.error ?? \"(unknown)\"}`,\n\t\t\t\t\tpath: r.path,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.cache = { files, diagnostics };\n\t}\n\n\tgetAgentsFiles(): Array<{ path: string; content: string }> {\n\t\treturn this.cache?.files ?? [];\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\t// Backend-level diagnostics (agentsFile failures, unsupported manifest\n\t\t// keys) surface here so they reach the operator through\n\t\t// VirtualResourceLoader's existing diagnostic aggregation path. Skills\n\t\t// over SSH are not implemented; the diagnostic for `paths.skills` is\n\t\t// already in this list when applicable.\n\t\treturn { skills: [], diagnostics: this.cache?.diagnostics ?? [] };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: [], diagnostics: [] };\n\t}\n\n\t// `getExtensions` intentionally omitted — VirtualResourceLoader routes\n\t// extensions through the primary LocalBackend. Unsupported `paths.extensions`\n\t// surfaces as a diagnostic via `reload()` + `getSkills()`.\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn [];\n\t}\n\n\tprivate target(): string {\n\t\treturn this.user !== undefined && this.user.length > 0\n\t\t\t? `${this.user}@${this.host}`\n\t\t\t: this.host;\n\t}\n\n\tprivate qualifyPath(path: string): string {\n\t\treturn `ssh://${this.target()}/${path.replace(/^\\//, \"\")}`;\n\t}\n\n\tprivate unsupportedDiagnostic(kind: \"skills\" | \"prompts\" | \"extensions\"): ResourceDiagnostic {\n\t\treturn {\n\t\t\ttype: \"warning\",\n\t\t\tmessage: `pi-acp ssh source '${this.id}' (${this.target()}): ${kind} discovery over SSH not yet implemented — declare individual files via paths.agentsFiles for now, or omit paths.${kind}.`,\n\t\t};\n\t}\n\n\tprivate async cat(path: string): Promise<string> {\n\t\tconst seconds = Math.max(1, Math.ceil(this.timeoutMs / 1000));\n\t\tconst aliveCount = Math.max(1, Math.floor(seconds / 2));\n\t\tconst result =\n\t\t\tawait $`${this.sshCommand} -o BatchMode=yes -o ConnectTimeout=${seconds} -o ServerAliveInterval=2 -o ServerAliveCountMax=${aliveCount} ${this.target()} -- cat ${path}`\n\t\t\t\t.quiet()\n\t\t\t\t.nothrow();\n\t\tif (result.exitCode !== 0) {\n\t\t\tconst stderr = result.stderr.toString().trim();\n\t\t\tthrow new Error(`ssh exited ${result.exitCode}: ${stderr || \"(no stderr)\"}`);\n\t\t}\n\t\treturn result.stdout.toString();\n\t}\n}\n","","import { randomUUID } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\nimport {\n\ttype Agent as ACPAgent,\n\ttype AgentSideConnection,\n\ttype AuthenticateRequest,\n\ttype AvailableCommand,\n\ttype CancelNotification,\n\ttype CloseSessionRequest,\n\ttype CloseSessionResponse,\n\ttype ForkSessionRequest,\n\ttype ForkSessionResponse,\n\ttype InitializeRequest,\n\ttype InitializeResponse,\n\ttype ListSessionsRequest,\n\ttype ListSessionsResponse,\n\ttype LoadSessionRequest,\n\ttype LoadSessionResponse,\n\ttype ModelInfo,\n\ttype NewSessionRequest,\n\ttype PromptRequest,\n\ttype PromptResponse,\n\tRequestError,\n\ttype ResumeSessionRequest,\n\ttype ResumeSessionResponse,\n\ttype SessionConfigOption,\n\ttype SessionInfo,\n\ttype SessionModelState,\n\ttype SessionModeState,\n\ttype SetSessionConfigOptionRequest,\n\ttype SetSessionConfigOptionResponse,\n\ttype SetSessionModelRequest,\n\ttype SetSessionModelResponse,\n\ttype SetSessionModeRequest,\n\ttype SetSessionModeResponse,\n\ttype StopReason,\n} from \"@agentclientprotocol/sdk\";\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, ToolResultMessage, UserMessage } from \"@earendil-works/pi-ai\";\nimport {\n\ttype AgentSession,\n\ttype CreateAgentSessionResult,\n\tcreateAgentSession,\n\tcreateBashToolDefinition,\n\tcreateReadToolDefinition,\n\tgetAgentDir,\n\tSessionManager as PiSessionManager,\n\ttype ToolDefinition,\n} from \"@earendil-works/pi-coding-agent\";\nimport { createAcpBashOperations } from \"@pi-acp/acp/acp-bash-operations\";\nimport { createAcpReadOperations } from \"@pi-acp/acp/acp-read-operations\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\nimport { detectAuthError } from \"@pi-acp/acp/auth-required\";\nimport {\n\ttype ClientCapabilityFlags,\n\tparseClientCapabilities,\n} from \"@pi-acp/acp/client-capabilities\";\nimport { ExtMethodDispatcher } from \"@pi-acp/acp/ext-methods\";\nimport { resolveModelPreference } from \"@pi-acp/acp/model-alias\";\nimport { skillCommandsEnabled } from \"@pi-acp/acp/pi-settings\";\nimport {\n\tbuildToolTitle,\n\tPiAcpSession,\n\tresolveToolPath,\n\tSessionManager,\n\ttype ToolArgs,\n\ttoToolArgs,\n\ttoToolKind,\n} from \"@pi-acp/acp/session\";\nimport { extractUserMessageText } from \"@pi-acp/acp/translate/pi-messages\";\nimport { acpPromptToPiMessage } from \"@pi-acp/acp/translate/prompt\";\nimport { formatToolContent } from \"@pi-acp/acp/translate/tool-content\";\nimport { piChangelogPath } from \"@pi-acp/pi-package\";\nimport { buildDiagnosticsReport } from \"@pi-acp/resources/diagnostics\";\nimport { VirtualResourceLoader } from \"@pi-acp/resources/loader\";\nimport { loadManifest, type ManifestDiagnostic } from \"@pi-acp/resources/manifest\";\nimport { type ResolveModeResult, resolveMode } from \"@pi-acp/resources/modes\";\nimport type { ResourceSource } from \"@pi-acp/resources/sources/base\";\nimport { HttpBackend } from \"@pi-acp/resources/sources/http\";\nimport { LocalBackend } from \"@pi-acp/resources/sources/local\";\nimport { SshBackend } from \"@pi-acp/resources/sources/ssh\";\n\nimport pkgJson from \"../../package.json\" with { type: \"json\" };\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Builtin ACP slash commands handled directly by the adapter. */\nconst BUILTIN_COMMANDS: readonly AvailableCommand[] = [\n\t{\n\t\tname: \"compact\",\n\t\tdescription: \"Manually compact the session context\",\n\t\tinput: { hint: \"optional custom instructions\" },\n\t},\n\t{\n\t\tname: \"autocompact\",\n\t\tdescription: \"Toggle automatic context compaction\",\n\t\tinput: { hint: \"on|off|toggle\" },\n\t},\n\t{ name: \"export\", description: \"Export session to an HTML file in the session cwd\" },\n\t{ name: \"session\", description: \"Show session stats (messages, tokens, cost, session file)\" },\n\t{ name: \"name\", description: \"Set session display name\", input: { hint: \"<name>\" } },\n\t{\n\t\tname: \"steering\",\n\t\tdescription: \"Get/set pi steering message delivery mode\",\n\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t},\n\t{\n\t\tname: \"follow-up\",\n\t\tdescription: \"Get/set pi follow-up message delivery mode\",\n\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t},\n\t{ name: \"changelog\", description: \"Show pi changelog\" },\n] as const;\n\n/**\n * Deduplicate commands by name. First occurrence wins.\n */\nfunction deduplicateCommands(commands: AvailableCommand[]): AvailableCommand[] {\n\tconst seen = new Set<string>();\n\tconst out: AvailableCommand[] = [];\n\tfor (const c of commands) {\n\t\tif (seen.has(c.name)) continue;\n\t\tseen.add(c.name);\n\t\tout.push(c);\n\t}\n\treturn out;\n}\n\nfunction parseArgs(input: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet quote: string | null = null;\n\n\tfor (const ch of input) {\n\t\tif (quote !== null) {\n\t\t\tif (ch === quote) quote = null;\n\t\t\telse current += ch;\n\t\t} else if (ch === '\"' || ch === \"'\") {\n\t\t\tquote = ch;\n\t\t} else if (ch === \" \" || ch === \"\\t\") {\n\t\t\tif (current !== \"\") {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += ch;\n\t\t}\n\t}\n\n\tif (current !== \"\") args.push(current);\n\treturn args;\n}\n\nconst SESSION_TITLE_MAX = 100;\n\nfunction truncateSessionTitle(text: string): string | null {\n\tconst trimmed = text.trim();\n\tif (trimmed === \"\") return null;\n\tconst oneLine = trimmed.replace(/\\n/g, \" \");\n\tif (oneLine.length <= SESSION_TITLE_MAX) return oneLine;\n\treturn `${oneLine.slice(0, SESSION_TITLE_MAX - 1)}…`;\n}\n\nexport class PiAcpAgent implements ACPAgent {\n\tprivate readonly conn: AgentSideConnection;\n\tprivate readonly sessions = new SessionManager();\n\t/** Cache of sessionId → file path, populated by listSessions and newSession. */\n\tprivate readonly sessionPaths = new Map<string, string>();\n\t/** Parsed client capability flags from initialize(). */\n\tprivate clientCapabilities: ClientCapabilityFlags = {\n\t\tterminalOutput: false,\n\t\tterminalAuth: false,\n\t\tgatewayAuth: false,\n\t\tfsReadTextFile: false,\n\t\tterminal: false,\n\t};\n\n\tprivate readonly daemonContext: import(\"@pi-acp/daemon/context\").DaemonContext | undefined;\n\t/** Unique ID for this ACP connection. Used as the ownership key in the daemon SessionRegistry. */\n\tprivate readonly connectionId = randomUUID();\n\tprivate readonly extMethods: ExtMethodDispatcher;\n\tprivate readonly startedAt = Date.now();\n\n\tdispose(): void {\n\t\t// On connection close, release every session this connection owned or\n\t\t// resumed from the daemon registry. Sessions another client still holds\n\t\t// stay live; sessions only this connection held get disposed by release().\n\t\tif (this.daemonContext !== undefined) {\n\t\t\tconst registry = this.daemonContext.sessionRegistry;\n\t\t\tfor (const entry of registry.listOwnedBy(this.connectionId)) {\n\t\t\t\tconst result = registry.release(entry.sessionId, this.connectionId);\n\t\t\t\tif (result.kind === \"disposed\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tentry.piSession.dispose();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* best-effort */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.sessions.disposeAll();\n\t}\n\n\tconstructor(\n\t\tconn: AgentSideConnection,\n\t\tdaemonContext?: import(\"@pi-acp/daemon/context\").DaemonContext,\n\t) {\n\t\tthis.conn = conn;\n\t\tthis.daemonContext = daemonContext;\n\t\tthis.extMethods = new ExtMethodDispatcher({\n\t\t\tversion: pkgJson.version,\n\t\t\tstartedAt: this.startedAt,\n\t\t\tsessionCount: () => this.sessions.size(),\n\t\t});\n\t}\n\n\tasync extMethod(\n\t\tmethod: string,\n\t\tparams: Record<string, unknown>,\n\t): Promise<Record<string, unknown>> {\n\t\treturn this.extMethods.handleRequest(method, params);\n\t}\n\n\tasync extNotification(method: string, params: Record<string, unknown>): Promise<void> {\n\t\tawait this.extMethods.handleNotification(method, params);\n\t}\n\n\tprivate registerWithDaemon(input: {\n\t\tsessionId: string;\n\t\tpiSession: AgentSession;\n\t\tcwd: string;\n\t\tsessionFile: string | undefined;\n\t}): void {\n\t\tif (this.daemonContext === undefined) return;\n\t\tthis.daemonContext.sessionRegistry.register({\n\t\t\tsessionId: input.sessionId,\n\t\t\tpiSession: input.piSession,\n\t\t\townerConnectionId: this.connectionId,\n\t\t\tcwd: input.cwd,\n\t\t\tsessionFile: input.sessionFile,\n\t\t});\n\t}\n\n\tprivate releaseFromDaemon(sessionId: string): { disposed: boolean } {\n\t\tif (this.daemonContext === undefined) return { disposed: true };\n\t\tconst result = this.daemonContext.sessionRegistry.release(sessionId, this.connectionId);\n\t\treturn { disposed: result.kind === \"disposed\" };\n\t}\n\n\t/**\n\t * Build a VirtualResourceLoader for a new pi session. Reads the\n\t * `.pi-acp.yaml` manifest cascade (ACP params > project > user-global >\n\t * default), turns each declared root into a ResourceSource, and ensures at\n\t * least one LocalBackend is present for the extension / theme passthrough.\n\t *\n\t * Phase 5 materializes `kind: \"local\"`. Phase 6 adds `kind: \"ssh\"`.\n\t * Phase 7 adds `kind: \"http\"`. `acp-fs` still parses fine but surfaces as\n\t * a diagnostic until its backend lands in a subsequent phase.\n\t */\n\tprivate async buildResourceLoader(\n\t\tcwd: string,\n\t\tsessionParams?: unknown,\n\t\topts?: { resolveCwdMode?: boolean },\n\t): Promise<{\n\t\tloader: VirtualResourceLoader;\n\t\tmodeResult: ResolveModeResult;\n\t\tdiagnosticsEnabled: boolean;\n\t\tmanifestDiagnostics: ManifestDiagnostic[];\n\t}> {\n\t\tconst loaded = await loadManifest({ cwd, sessionParams });\n\t\t// Mode resolution mints a tmpdir for `mode: none`. Load/resume/fork\n\t\t// paths pin cwd from the session file, so mode is irrelevant on those\n\t\t// paths — passing { resolveCwdMode: false } avoids the leaked\n\t\t// tmpdir + the cwd-mismatch (manifest tmpdir vs session-file cwd).\n\t\tconst shouldResolveMode = opts?.resolveCwdMode !== false;\n\t\tconst modeResult: ResolveModeResult = shouldResolveMode\n\t\t\t? resolveMode({ manifest: loaded.manifest, requestedCwd: cwd })\n\t\t\t: { mode: loaded.manifest.mode, cwd, cleanup: () => {}, ephemeral: false };\n\t\tconst effectiveCwd = modeResult.cwd;\n\t\tconst diagnostics: ManifestDiagnostic[] = [...loaded.diagnostics];\n\t\tconst sources: ResourceSource[] = [];\n\n\t\tfor (const root of loaded.manifest.roots) {\n\t\t\tif (root.kind === \"local\") {\n\t\t\t\tsources.push(\n\t\t\t\t\tnew LocalBackend({\n\t\t\t\t\t\tid: root.id,\n\t\t\t\t\t\tcwd: root.paths.cwd ?? effectiveCwd,\n\t\t\t\t\t\tagentDir: root.paths.agentDir ?? getAgentDir(),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (root.kind === \"ssh\") {\n\t\t\t\tconst sshOpts: ConstructorParameters<typeof SshBackend>[0] = {\n\t\t\t\t\tid: root.id,\n\t\t\t\t\thost: root.host,\n\t\t\t\t\tpaths: root.paths,\n\t\t\t\t};\n\t\t\t\tif (root.user !== undefined) sshOpts.user = root.user;\n\t\t\t\tsources.push(new SshBackend(sshOpts));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (root.kind === \"http\") {\n\t\t\t\tconst httpOpts: ConstructorParameters<typeof HttpBackend>[0] = {\n\t\t\t\t\tid: root.id,\n\t\t\t\t\tbaseUrl: root.baseUrl,\n\t\t\t\t\tpaths: root.paths,\n\t\t\t\t};\n\t\t\t\tif (root.cache !== undefined) httpOpts.cacheTtlSeconds = root.cache.ttl;\n\t\t\t\tsources.push(new HttpBackend(httpOpts));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst diag: ManifestDiagnostic = {\n\t\t\t\tsource: loaded.source,\n\t\t\t\tmessage: `root \"${root.id}\" kind=\"${root.kind}\" not yet supported in this build (skipped)`,\n\t\t\t};\n\t\t\tif (loaded.path !== undefined) diag.path = loaded.path;\n\t\t\tdiagnostics.push(diag);\n\t\t}\n\n\t\t// VirtualResourceLoader needs at least one LocalBackend for extensions\n\t\t// + themes. Synthesize one from the effective cwd if the manifest\n\t\t// didn't already declare one. In `none` mode the effective cwd is the\n\t\t// ephemeral tmpdir, so the synthesized backend sees a clean root.\n\t\tif (!sources.some((s) => s.kind === \"local\")) {\n\t\t\tsources.unshift(new LocalBackend({ cwd: effectiveCwd, agentDir: getAgentDir() }));\n\t\t}\n\n\t\tconst loader = new VirtualResourceLoader({\n\t\t\tsources,\n\t\t\tmergeStrategy: loaded.manifest.mergeStrategy,\n\t\t});\n\t\tawait loader.reload();\n\n\t\t// Phase 11 will surface these via session/update. Until then, log\n\t\t// them to stderr under the daemon-debug flag so a malformed manifest\n\t\t// doesn't fail silently.\n\t\t// biome-ignore lint/complexity/useLiteralKeys: env var keys need bracket access for tsc strict mode\n\t\tif (diagnostics.length > 0 && process.env[\"PI_ACP_DAEMON_DEBUG\"] === \"1\") {\n\t\t\tfor (const d of diagnostics) {\n\t\t\t\tconst where = d.path !== undefined ? ` ${d.path}` : \"\";\n\t\t\t\tprocess.stderr.write(`pi-acp manifest [${d.source}${where}]: ${d.message}\\n`);\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tloader,\n\t\t\tmodeResult,\n\t\t\tdiagnosticsEnabled: loaded.manifest.diagnostics === true,\n\t\t\tmanifestDiagnostics: diagnostics,\n\t\t};\n\t}\n\n\t/**\n\t * PRD-002 §FR-6 + §FR-6.5 — tool overrides for ACP-FS read + ACP terminal bash.\n\t *\n\t * For each tool we override, the allowlist MUST include the original\n\t * tool name so pi's customTool registration loop (which filters by\n\t * name) can register the override; the override then shadows the\n\t * builtin via the tool-definition `Map.set` path inside AgentSession\n\t * (verified against pi source — agent-session.js:1811).\n\t *\n\t * SessionId binding is late: pi mints the id inside `createAgentSession`\n\t * (after `customTools` is built), so we share a single mutable ref\n\t * across all overrides. The caller mutates `sessionIdRef.current`\n\t * right after createAgentSession returns, before any model turn — the\n\t * tools aren't invoked until prompt-time, so the late binding is safe.\n\t *\n\t * Returns `null` when neither capability is advertised; callers skip\n\t * the overlay and pi's built-in tools handle everything locally.\n\t */\n\tprivate buildAcpToolOverlay(cwd: string): {\n\t\tsessionIdRef: { current: string };\n\t\ttools: string[];\n\t\tcustomTools: ToolDefinition[];\n\t} | null {\n\t\tconst wantRead = this.clientCapabilities.fsReadTextFile;\n\t\tconst wantBash = this.clientCapabilities.terminal;\n\t\tif (!wantRead && !wantBash) return null;\n\n\t\tconst sessionIdRef = { current: \"\" };\n\t\tconst customTools: ToolDefinition[] = [];\n\n\t\tif (wantRead) {\n\t\t\tconst operations = createAcpReadOperations({\n\t\t\t\tconn: this.conn,\n\t\t\t\tgetSessionId: () => sessionIdRef.current,\n\t\t\t});\n\t\t\t// Variance: `createReadToolDefinition` returns a narrowly-typed\n\t\t\t// ToolDefinition; `customTools[]` expects the wide form. Pi's\n\t\t\t// runtime treats every customTool through the unknown-args path,\n\t\t\t// so widening is safe. TS's exactOptionalPropertyTypes flags it\n\t\t\t// because `renderCall.args` is contravariant.\n\t\t\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion\n\t\t\tconst readToolDef = createReadToolDefinition(cwd, {\n\t\t\t\toperations,\n\t\t\t}) as unknown as ToolDefinition;\n\t\t\tcustomTools.push(readToolDef);\n\t\t}\n\n\t\tif (wantBash) {\n\t\t\tconst operations = createAcpBashOperations({\n\t\t\t\tconn: this.conn,\n\t\t\t\tgetSessionId: () => sessionIdRef.current,\n\t\t\t});\n\t\t\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion\n\t\t\tconst bashToolDef = createBashToolDefinition(cwd, {\n\t\t\t\toperations,\n\t\t\t}) as unknown as ToolDefinition;\n\t\t\tcustomTools.push(bashToolDef);\n\t\t}\n\n\t\treturn {\n\t\t\tsessionIdRef,\n\t\t\ttools: [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\"],\n\t\t\tcustomTools,\n\t\t};\n\t}\n\n\tasync initialize(params: InitializeRequest): Promise<InitializeResponse> {\n\t\tconst supportedVersion = 1;\n\t\tconst requested = params.protocolVersion;\n\n\t\tthis.clientCapabilities = parseClientCapabilities(params.clientCapabilities);\n\n\t\treturn {\n\t\t\tprotocolVersion: requested === supportedVersion ? requested : supportedVersion,\n\t\t\tagentInfo: {\n\t\t\t\tname: pkgJson.name,\n\t\t\t\ttitle: \"pi ACP adapter\",\n\t\t\t\tversion: pkgJson.version,\n\t\t\t},\n\t\t\tauthMethods: buildAuthMethods({\n\t\t\t\tsupportsTerminalAuthMeta: this.clientCapabilities.terminalAuth,\n\t\t\t}),\n\t\t\tagentCapabilities: {\n\t\t\t\tloadSession: true,\n\t\t\t\tmcpCapabilities: { http: false, sse: false },\n\t\t\t\tpromptCapabilities: {\n\t\t\t\t\timage: true,\n\t\t\t\t\taudio: false,\n\t\t\t\t\tembeddedContext: true,\n\t\t\t\t},\n\t\t\t\tsessionCapabilities: {\n\t\t\t\t\tlist: {},\n\t\t\t\t\tclose: {},\n\t\t\t\t\tresume: {},\n\t\t\t\t\tfork: {},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync newSession(params: NewSessionRequest) {\n\t\t// In `local` / `overlay` modes the cwd must be absolute and exist on\n\t\t// disk. In `none` mode we synthesize a tmpdir and ignore params.cwd\n\t\t// for tool targeting, but the manifest still cascades from\n\t\t// params.cwd's project-root .pi-acp.yaml so a passed-in cwd is not\n\t\t// useless — we just don't run pi against it.\n\t\tconst builtResources = await this.buildResourceLoader(params.cwd, params).catch(\n\t\t\t(e: unknown) => {\n\t\t\t\tconst authErr = detectAuthError(e);\n\t\t\t\tif (authErr !== null) throw authErr;\n\t\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\t\tthrow RequestError.internalError({}, `Failed to load pi-acp manifest: ${msg}`);\n\t\t\t},\n\t\t);\n\t\tconst {\n\t\t\tloader: resourceLoader,\n\t\t\tmodeResult,\n\t\t\tdiagnosticsEnabled,\n\t\t\tmanifestDiagnostics,\n\t\t} = builtResources;\n\t\tconst effectiveCwd = modeResult.cwd;\n\n\t\tif (modeResult.mode !== \"none\" && !isAbsolute(params.cwd)) {\n\t\t\tmodeResult.cleanup();\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tconst diagnosticsReport = diagnosticsEnabled\n\t\t\t? buildDiagnosticsReport({\n\t\t\t\t\tsources: resourceLoader.listSources(),\n\t\t\t\t\tmanifestDiagnostics,\n\t\t\t\t}).text\n\t\t\t: \"\";\n\n\t\tconst acpToolOverlay = this.buildAcpToolOverlay(effectiveCwd);\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: effectiveCwd,\n\t\t\t\tresourceLoader,\n\t\t\t\t...(acpToolOverlay\n\t\t\t\t\t? { tools: acpToolOverlay.tools, customTools: acpToolOverlay.customTools }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tmodeResult.cleanup();\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to create pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\t\tif (acpToolOverlay !== null) {\n\t\t\tacpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();\n\t\t}\n\n\t\tconst availableModels = piSession.modelRegistry.getAvailable();\n\t\tif (availableModels.length === 0) {\n\t\t\tpiSession.dispose();\n\t\t\tmodeResult.cleanup();\n\t\t\tthrow RequestError.authRequired(\n\t\t\t\t{ authMethods: buildAuthMethods() },\n\t\t\t\t\"Configure an API key or log in with an OAuth provider.\",\n\t\t\t);\n\t\t}\n\n\t\tconst sessionId = piSession.sessionManager.getSessionId();\n\t\tconst sessionFile = piSession.sessionManager.getSessionFile();\n\t\tif (sessionFile !== undefined) {\n\t\t\tthis.sessionPaths.set(sessionId, sessionFile);\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId,\n\t\t\tcwd: effectiveCwd,\n\t\t\tmcpServers: params.mcpServers,\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t\tcleanups: modeResult.ephemeral ? [modeResult.cleanup] : [],\n\t\t\t...(diagnosticsReport !== \"\" ? { diagnosticsReport } : {}),\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({ sessionId, piSession, cwd: params.cwd, sessionFile });\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\treturn {\n\t\t\tsessionId: session.sessionId,\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync authenticate(_params: AuthenticateRequest) {\n\t\treturn {};\n\t}\n\n\tasync prompt(params: PromptRequest): Promise<PromptResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst { message, images } = acpPromptToPiMessage(params.prompt);\n\n\t\tif (images.length === 0 && message.trimStart().startsWith(\"/\")) {\n\t\t\tconst trimmed = message.trim();\n\t\t\tconst space = trimmed.indexOf(\" \");\n\t\t\tconst cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space);\n\t\t\tconst argsString = space === -1 ? \"\" : trimmed.slice(space + 1);\n\t\t\tconst args = parseArgs(argsString);\n\n\t\t\tconst handled = await this.handleBuiltinCommand(session, cmd, args);\n\t\t\tif (handled) return handled;\n\t\t}\n\n\t\tconst result = await session.prompt(message, images);\n\n\t\tconst stopReason: StopReason = result === \"error\" ? \"end_turn\" : result;\n\t\tconst usage = session.getUsage();\n\t\tconst cost = session.getCost();\n\n\t\treturn {\n\t\t\tstopReason,\n\t\t\tusage: {\n\t\t\t\tinputTokens: usage.inputTokens,\n\t\t\t\toutputTokens: usage.outputTokens,\n\t\t\t\tcachedReadTokens: usage.cachedReadTokens,\n\t\t\t\tcachedWriteTokens: usage.cachedWriteTokens,\n\t\t\t\ttotalTokens: usage.inputTokens + usage.outputTokens,\n\t\t\t},\n\t\t\t_meta: cost > 0 ? { cost: { amount: cost, currency: \"USD\" } } : {},\n\t\t};\n\t}\n\n\tasync cancel(params: CancelNotification): Promise<void> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tawait session.cancel();\n\t}\n\n\t/**\n\t * Resolve a session ID to a file path.\n\t * Checks the local cache first (populated by listSessions/newSession),\n\t * falls back to a full listAll() scan on cache miss.\n\t */\n\tprivate async resolveSessionFile(sessionId: string): Promise<string | null> {\n\t\tconst cached = this.sessionPaths.get(sessionId);\n\t\tif (cached !== undefined) return cached;\n\n\t\tconst all = await PiSessionManager.listAll();\n\t\tfor (const s of all) {\n\t\t\tthis.sessionPaths.set(s.id, s.path);\n\t\t}\n\n\t\treturn this.sessionPaths.get(sessionId) ?? null;\n\t}\n\n\t/**\n\t * Replay persisted session messages as ACP session updates.\n\t *\n\t * Iterates through the message history, emitting structured updates for each\n\t * content block type: text, thinking, tool calls, and tool results. A map of\n\t * tool call IDs to their invocation data (from assistant messages) is built\n\t * to enrich subsequent tool result updates with rawInput and locations.\n\t */\n\tprivate async replaySessionHistory(\n\t\tsession: PiAcpSession,\n\t\tmessages: AgentMessage[],\n\t): Promise<void> {\n\t\tconst toolCallMap = new Map<string, { name: string; args: ToolArgs }>();\n\n\t\tfor (const m of messages) {\n\t\t\tif (!(\"role\" in m)) continue;\n\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst text = extractUserMessageText((m satisfies UserMessage).content);\n\t\t\t\tif (text) {\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: { sessionUpdate: \"user_message_chunk\", content: { type: \"text\", text } },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (m.role === \"assistant\") {\n\t\t\t\tconst am = m satisfies AssistantMessage;\n\t\t\t\tfor (const block of am.content) {\n\t\t\t\t\tif (block.type === \"text\" && block.text) {\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\t\t\tcontent: { type: \"text\", text: block.text },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (block.type === \"thinking\" && block.thinking) {\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"agent_thought_chunk\",\n\t\t\t\t\t\t\t\tcontent: { type: \"text\", text: block.thinking },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t\tconst args = toToolArgs(block.arguments);\n\t\t\t\t\t\ttoolCallMap.set(block.id, { name: block.name, args });\n\t\t\t\t\t\tconst locations = resolveToolPath(args, session.cwd);\n\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\t\t\t\ttoolCallId: block.id,\n\t\t\t\t\t\t\t\ttitle: buildToolTitle(block.name, args),\n\t\t\t\t\t\t\t\tkind: toToolKind(block.name),\n\t\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\t\trawInput: args,\n\t\t\t\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\t\t\t\t_meta: { piAcp: { toolName: block.name } },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst tr = m satisfies ToolResultMessage;\n\t\t\t\tconst toolName = tr.toolName;\n\t\t\t\tconst toolCallId = tr.toolCallId;\n\t\t\t\tconst isError = tr.isError;\n\n\t\t\t\t// Enrich from the preceding assistant tool call if available.\n\t\t\t\tconst invocation = toolCallMap.get(toolCallId);\n\t\t\t\tconst args = invocation?.args;\n\t\t\t\tconst locations = args !== undefined ? resolveToolPath(args, session.cwd) : undefined;\n\n\t\t\t\t// If no tool_call was emitted from the assistant message (e.g. older\n\t\t\t\t// session format without structured assistant content), emit one now.\n\t\t\t\tif (invocation === undefined) {\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\ttitle: buildToolTitle(toolName, {}),\n\t\t\t\t\t\t\tkind: toToolKind(toolName),\n\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\trawInput: null,\n\t\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t\t\t_meta: { piAcp: { toolName } },\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst content = formatToolContent(toolName, m, isError);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\tstatus: isError ? \"failed\" : \"completed\",\n\t\t\t\t\t\tcontent: content.length > 0 ? content : null,\n\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\t\t_meta: { piAcp: { toolName } },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tasync listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse> {\n\t\tconst cwd = params.cwd;\n\n\t\tconst raw =\n\t\t\tcwd !== undefined && cwd !== null\n\t\t\t\t? await PiSessionManager.list(cwd)\n\t\t\t\t: await PiSessionManager.listAll();\n\n\t\tfor (const s of raw) {\n\t\t\tthis.sessionPaths.set(s.id, s.path);\n\t\t}\n\n\t\tconst sessions = raw.map((s) => ({\n\t\t\tid: s.id,\n\t\t\tcwd: s.cwd,\n\t\t\tname: s.name,\n\t\t\tfirstMessage: s.firstMessage,\n\t\t\tmodified: s.modified,\n\t\t\tmessageCount: s.messageCount,\n\t\t}));\n\n\t\tif (params.cursor !== undefined && params.cursor !== null) {\n\t\t\tconst parsed = Number.parseInt(params.cursor, 10);\n\t\t\tif (!Number.isFinite(parsed) || parsed < 0) {\n\t\t\t\tthrow RequestError.invalidParams(`Invalid cursor: ${params.cursor}`);\n\t\t\t}\n\t\t}\n\n\t\tconst start =\n\t\t\tparams.cursor !== undefined && params.cursor !== null\n\t\t\t\t? Number.parseInt(params.cursor, 10)\n\t\t\t\t: 0;\n\n\t\tconst PAGE_SIZE = 50;\n\t\tconst page = sessions.slice(start, start + PAGE_SIZE);\n\n\t\tconst liveSessions =\n\t\t\tthis.daemonContext !== undefined ? this.daemonContext.sessionRegistry.listAll() : [];\n\t\tconst liveById = new Map(liveSessions.map((e) => [e.sessionId, e]));\n\n\t\tconst acpSessions: SessionInfo[] = page.map((s) => {\n\t\t\tconst live = liveById.get(s.id);\n\t\t\tconst isOwnedByThisConnection =\n\t\t\t\tlive !== undefined &&\n\t\t\t\t(live.ownerConnectionId === this.connectionId || live.alsoHeldBy.has(this.connectionId));\n\t\t\treturn {\n\t\t\t\tsessionId: s.id,\n\t\t\t\tcwd: s.cwd,\n\t\t\t\ttitle:\n\t\t\t\t\t(s.name !== undefined && s.name !== \"\" ? s.name : null) ??\n\t\t\t\t\ttruncateSessionTitle(s.firstMessage) ??\n\t\t\t\t\tnull,\n\t\t\t\tupdatedAt: s.modified.toISOString(),\n\t\t\t\t...(live !== undefined\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t_meta: {\n\t\t\t\t\t\t\t\tpiAcp: {\n\t\t\t\t\t\t\t\t\tlive: true,\n\t\t\t\t\t\t\t\t\townedByThisConnection: isOwnedByThisConnection,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t});\n\n\t\t// Surface daemon-live sessions that are NOT on disk yet (e.g., newSession\n\t\t// called but not yet persisted by pi). Insert at the front so the most\n\t\t// recently-active live ones bubble up.\n\t\tconst seen = new Set(page.map((s) => s.id));\n\t\tconst liveOnly = liveSessions\n\t\t\t.filter((e) => !seen.has(e.sessionId))\n\t\t\t.map<SessionInfo>((e) => ({\n\t\t\t\tsessionId: e.sessionId,\n\t\t\t\tcwd: e.cwd,\n\t\t\t\ttitle: null,\n\t\t\t\tupdatedAt: e.updatedAt.toISOString(),\n\t\t\t\t_meta: {\n\t\t\t\t\tpiAcp: {\n\t\t\t\t\t\tlive: true,\n\t\t\t\t\t\townedByThisConnection:\n\t\t\t\t\t\t\te.ownerConnectionId === this.connectionId || e.alsoHeldBy.has(this.connectionId),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}));\n\n\t\tconst merged = [...liveOnly, ...acpSessions];\n\t\tconst nextCursor = start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null;\n\n\t\treturn { sessions: merged, nextCursor, _meta: {} };\n\t}\n\n\tasync loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tthis.sessions.close(params.sessionId);\n\n\t\tconst sessionFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sessionFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tconst acpToolOverlay = this.buildAcpToolOverlay(params.cwd);\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.open(sessionFile);\n\t\t\tconst { loader: resourceLoader } = await this.buildResourceLoader(params.cwd, params, {\n\t\t\t\tresolveCwdMode: false,\n\t\t\t});\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t\tresourceLoader,\n\t\t\t\t...(acpToolOverlay\n\t\t\t\t\t? { tools: acpToolOverlay.tools, customTools: acpToolOverlay.customTools }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to load pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\t\tif (acpToolOverlay !== null) {\n\t\t\tacpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: params.sessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers,\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: params.sessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile,\n\t\t});\n\n\t\tawait this.replaySessionHistory(session, piSession.messages);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\treturn {\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {\n\t\tconst local = this.sessions.maybeGet(params.sessionId);\n\t\t// Check daemon registry too: another client may have created the session\n\t\t// and this connection only resumed it; the local PiAcpSession wrapper\n\t\t// existed but the underlying piSession is shared.\n\t\tconst inRegistry = this.daemonContext?.sessionRegistry.get(params.sessionId);\n\t\tif (local === undefined && inRegistry === undefined) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\t// Release from registry first to decide whether to dispose pi runtime.\n\t\tconst release = this.releaseFromDaemon(params.sessionId);\n\t\tif (release.disposed) {\n\t\t\t// Last holder — full close including pi dispose via SessionManager.\n\t\t\tthis.sessions.close(params.sessionId);\n\t\t} else if (local !== undefined) {\n\t\t\t// Other clients still hold the session. Drop only this connection's\n\t\t\t// PiAcpSession wrapper (which holds our own event subscription).\n\t\t\t// SessionManager.detach removes the entry without disposing the\n\t\t\t// underlying piSession.\n\t\t\tthis.sessions.detach(params.sessionId);\n\t\t}\n\t\treturn {};\n\t}\n\n\tasync resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\t// If the session is already live in THIS connection, reuse it.\n\t\tconst existing = this.sessions.maybeGet(params.sessionId);\n\t\tif (existing !== undefined) {\n\t\t\tconst modes = buildThinkingModes(existing.piSession);\n\t\t\tconst models = buildModelState(existing.piSession);\n\t\t\treturn {\n\t\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\t\tmodes,\n\t\t\t\tmodels,\n\t\t\t};\n\t\t}\n\n\t\t// If another connection in the same daemon already holds the session,\n\t\t// attach to it and create a local PiAcpSession wrapping the shared\n\t\t// piSession with this connection's own event subscription + conn.\n\t\tif (this.daemonContext !== undefined) {\n\t\t\tconst registry = this.daemonContext.sessionRegistry;\n\t\t\tconst attached = registry.attach(params.sessionId, this.connectionId);\n\t\t\tif (attached !== undefined) {\n\t\t\t\tconst session = new PiAcpSession({\n\t\t\t\t\tsessionId: params.sessionId,\n\t\t\t\t\tcwd: params.cwd,\n\t\t\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\t\t\tpiSession: attached.piSession,\n\t\t\t\t\tconn: this.conn,\n\t\t\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t\t\t});\n\t\t\t\tthis.sessions.register(session);\n\t\t\t\tif (attached.sessionFile !== undefined) {\n\t\t\t\t\tthis.sessionPaths.set(params.sessionId, attached.sessionFile);\n\t\t\t\t}\n\t\t\t\tconst modes = buildThinkingModes(attached.piSession);\n\t\t\t\tconst models = buildModelState(attached.piSession);\n\t\t\t\treturn {\n\t\t\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\t\t\tmodes,\n\t\t\t\t\tmodels,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, load from disk (same path as loadSession but without replay).\n\t\tconst sessionFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sessionFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tconst acpToolOverlay = this.buildAcpToolOverlay(params.cwd);\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.open(sessionFile);\n\t\t\tconst { loader: resourceLoader } = await this.buildResourceLoader(params.cwd, params, {\n\t\t\t\tresolveCwdMode: false,\n\t\t\t});\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t\tresourceLoader,\n\t\t\t\t...(acpToolOverlay\n\t\t\t\t\t? { tools: acpToolOverlay.tools, customTools: acpToolOverlay.customTools }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to resume pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\t\tif (acpToolOverlay !== null) {\n\t\t\tacpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: params.sessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.sessionPaths.set(params.sessionId, sessionFile);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: params.sessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile,\n\t\t});\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\treturn {\n\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tconst sourceFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sourceFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tconst acpToolOverlay = this.buildAcpToolOverlay(params.cwd);\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.forkFrom(sourceFile, params.cwd);\n\t\t\tconst { loader: resourceLoader } = await this.buildResourceLoader(params.cwd, params, {\n\t\t\t\tresolveCwdMode: false,\n\t\t\t});\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t\tresourceLoader,\n\t\t\t\t...(acpToolOverlay\n\t\t\t\t\t? { tools: acpToolOverlay.tools, customTools: acpToolOverlay.customTools }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to fork pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\n\t\tconst newSessionId = piSession.sessionManager.getSessionId();\n\t\tif (acpToolOverlay !== null) {\n\t\t\tacpToolOverlay.sessionIdRef.current = newSessionId;\n\t\t}\n\t\tconst newSessionFile = piSession.sessionManager.getSessionFile();\n\t\tif (newSessionFile !== undefined) {\n\t\t\tthis.sessionPaths.set(newSessionId, newSessionFile);\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: newSessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: newSessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile: newSessionFile,\n\t\t});\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\treturn {\n\t\t\tsessionId: newSessionId,\n\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst mode = String(params.modeId);\n\t\tif (!isThinkingLevel(mode)) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modeId: ${mode}`);\n\t\t}\n\n\t\tsession.piSession.setThinkingLevel(mode);\n\n\t\tvoid this.conn.sessionUpdate({\n\t\t\tsessionId: session.sessionId,\n\t\t\tupdate: { sessionUpdate: \"current_mode_update\", currentModeId: mode },\n\t\t});\n\n\t\tthis.emitConfigOptionUpdate(session);\n\n\t\treturn {};\n\t}\n\n\tasync unstable_setSessionModel(\n\t\tparams: SetSessionModelRequest,\n\t): Promise<SetSessionModelResponse | void> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\n\t\tconst resolved = resolveModelPreference(available, params.modelId);\n\t\tif (resolved === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tconst model = available.find((m) => m.provider === resolved.provider && m.id === resolved.id);\n\t\tif (!model) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tawait session.piSession.setModel(model);\n\t\tthis.emitConfigOptionUpdate(session);\n\t}\n\n\tasync setSessionConfigOption(\n\t\tparams: SetSessionConfigOptionRequest,\n\t): Promise<SetSessionConfigOptionResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst configId = String(params.configId);\n\t\tconst value = String(params.value);\n\n\t\tif (configId === \"model\") {\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst resolved = resolveModelPreference(available, value);\n\t\t\tif (resolved === null) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tconst model = available.find((m) => m.provider === resolved.provider && m.id === resolved.id);\n\t\t\tif (!model) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tawait session.piSession.setModel(model);\n\t\t} else if (configId === \"thought_level\") {\n\t\t\tif (!isThinkingLevel(value)) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown thinking level: ${value}`);\n\t\t\t}\n\t\t\tsession.piSession.setThinkingLevel(value);\n\t\t} else {\n\t\t\tthrow RequestError.invalidParams(`Unknown config option: ${configId}`);\n\t\t}\n\n\t\tconst modes = buildThinkingModes(session.piSession);\n\t\tconst models = buildModelState(session.piSession);\n\t\treturn { configOptions: buildConfigOptions(modes, models) };\n\t}\n\n\tprivate emitConfigOptionUpdate(session: PiAcpSession): void {\n\t\tconst modes = buildThinkingModes(session.piSession);\n\t\tconst models = buildModelState(session.piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tvoid this.conn.sessionUpdate({\n\t\t\tsessionId: session.sessionId,\n\t\t\tupdate: {\n\t\t\t\tsessionUpdate: \"config_option_update\",\n\t\t\t\tconfigOptions,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async handleBuiltinCommand(\n\t\tsession: PiAcpSession,\n\t\tcmd: string,\n\t\targs: string[],\n\t): Promise<PromptResponse | null> {\n\t\tconst piSession = session.piSession;\n\n\t\tif (cmd === \"compact\") {\n\t\t\tconst customInstructions = args.join(\" \").trim() || undefined;\n\t\t\tconst res = await piSession.compact(customInstructions);\n\n\t\t\tconst headerLines = [\n\t\t\t\t`Compaction completed.${customInstructions !== undefined && customInstructions !== \"\" ? \" (custom instructions applied)\" : \"\"}`,\n\t\t\t\ttypeof res?.tokensBefore === \"number\" ? `Tokens before: ${res.tokensBefore}` : null,\n\t\t\t].filter(Boolean);\n\n\t\t\tconst text = headerLines.join(\"\\n\") + (res?.summary ? `\\n\\n${res.summary}` : \"\");\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"session\") {\n\t\t\tconst stats = piSession.getSessionStats();\n\t\t\tconst lines: string[] = [];\n\t\t\tif (stats.sessionId !== undefined && stats.sessionId !== \"\")\n\t\t\t\tlines.push(`Session: ${stats.sessionId}`);\n\t\t\tif (stats.sessionFile !== undefined && stats.sessionFile !== \"\")\n\t\t\t\tlines.push(`Session file: ${stats.sessionFile}`);\n\t\t\tlines.push(`Messages: ${stats.totalMessages}`);\n\t\t\tlines.push(`Cost: ${stats.cost}`);\n\t\t\tconst t = stats.tokens;\n\t\t\tconst parts: string[] = [];\n\t\t\tif (t.input) parts.push(`in ${t.input}`);\n\t\t\tif (t.output) parts.push(`out ${t.output}`);\n\t\t\tif (t.cacheRead) parts.push(`cache read ${t.cacheRead}`);\n\t\t\tif (t.cacheWrite) parts.push(`cache write ${t.cacheWrite}`);\n\t\t\tif (t.total) parts.push(`total ${t.total}`);\n\t\t\tif (parts.length > 0) lines.push(`Tokens: ${parts.join(\", \")}`);\n\n\t\t\tconst text = lines.join(\"\\n\");\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"name\") {\n\t\t\tconst name = args.join(\" \").trim();\n\t\t\tif (!name) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /name <name>\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tpiSession.setSessionName(name);\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"session_info_update\",\n\t\t\t\t\ttitle: name,\n\t\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Session name set: ${name}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"steering\") {\n\t\t\tconst modeRaw = String(args[0] ?? \"\").toLowerCase();\n\t\t\tif (!modeRaw) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Steering mode: ${piSession.steeringMode}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tif (modeRaw !== \"all\" && modeRaw !== \"one-at-a-time\") {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /steering all | /steering one-at-a-time\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tpiSession.setSteeringMode(modeRaw);\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Steering mode set to: ${modeRaw}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"follow-up\") {\n\t\t\tconst modeRaw = String(args[0] ?? \"\").toLowerCase();\n\t\t\tif (!modeRaw) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Follow-up mode: ${piSession.followUpMode}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tif (modeRaw !== \"all\" && modeRaw !== \"one-at-a-time\") {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /follow-up all | /follow-up one-at-a-time\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tpiSession.setFollowUpMode(modeRaw);\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Follow-up mode set to: ${modeRaw}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"autocompact\") {\n\t\t\tconst mode = (args[0] ?? \"toggle\").toLowerCase();\n\t\t\tlet enabled: boolean | null = null;\n\t\t\tif (mode === \"on\" || mode === \"true\" || mode === \"enable\") enabled = true;\n\t\t\telse if (mode === \"off\" || mode === \"false\" || mode === \"disable\") enabled = false;\n\n\t\t\tif (enabled === null) {\n\t\t\t\tenabled = !piSession.autoCompactionEnabled;\n\t\t\t}\n\n\t\t\tpiSession.setAutoCompactionEnabled(enabled);\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Auto-compaction ${enabled ? \"enabled\" : \"disabled\"}.` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"changelog\") {\n\t\t\tconst changelogPath = findChangelog();\n\t\t\tif (changelogPath === null) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Changelog not found.\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tlet text = \"\";\n\t\t\ttry {\n\t\t\t\ttext = readFileSync(changelogPath, \"utf-8\");\n\t\t\t} catch (e: unknown) {\n\t\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Failed to read changelog: ${msg}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tconst maxChars = 20_000;\n\t\t\tif (text.length > maxChars) text = `${text.slice(0, maxChars)}\\n\\n...(truncated)...`;\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"export\") {\n\t\t\tconst messageCount = piSession.messages.length;\n\t\t\tif (messageCount === 0) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Nothing to export yet. Send a prompt first.\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\t\t\tconst outputPath = join(session.cwd, `pi-session-${safeSessionId}.html`);\n\t\t\t\tconst resultPath = await piSession.exportToHtml(outputPath);\n\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Session exported: \" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\ttype: \"resource_link\",\n\t\t\t\t\t\t\tname: `pi-session-${safeSessionId}.html`,\n\t\t\t\t\t\t\turi: `file://${resultPath}`,\n\t\t\t\t\t\t\tmimeType: \"text/html\",\n\t\t\t\t\t\t\ttitle: \"Session exported\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (e: unknown) {\n\t\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Export failed: ${msg}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\nfunction isThinkingLevel(x: string): x is ThinkingLevel {\n\treturn (\n\t\tx === \"off\" || x === \"minimal\" || x === \"low\" || x === \"medium\" || x === \"high\" || x === \"xhigh\"\n\t);\n}\n\nfunction buildThinkingModes(piSession: AgentSession): {\n\tavailableModes: Array<{ id: string; name: string; description?: string | null }>;\n\tcurrentModeId: string;\n} {\n\tconst levels = piSession.getAvailableThinkingLevels();\n\treturn {\n\t\tcurrentModeId: piSession.thinkingLevel,\n\t\tavailableModes: levels.map((id) => ({\n\t\t\tid,\n\t\t\tname: `Thinking: ${id}`,\n\t\t\tdescription: null,\n\t\t})),\n\t};\n}\n\nfunction buildModelState(piSession: AgentSession): SessionModelState {\n\tconst available = piSession.modelRegistry.getAvailable();\n\tconst current = piSession.model;\n\n\tconst availableModels: ModelInfo[] = available.map((m) => ({\n\t\tmodelId: `${m.provider}/${m.id}`,\n\t\tname: `${m.provider}/${m.name ?? m.id}`,\n\t\tdescription: null,\n\t}));\n\n\tlet currentModelId = \"default\";\n\tif (current !== undefined) {\n\t\tcurrentModelId = `${current.provider}/${current.id}`;\n\t} else if (availableModels.length > 0 && availableModels[0] !== undefined) {\n\t\tcurrentModelId = availableModels[0].modelId;\n\t}\n\n\treturn { availableModels, currentModelId };\n}\n\nfunction buildConfigOptions(\n\tmodes: SessionModeState,\n\tmodels: SessionModelState,\n): SessionConfigOption[] {\n\treturn [\n\t\t{\n\t\t\tid: \"model\",\n\t\t\tname: \"Model\",\n\t\t\tdescription: \"AI model to use\",\n\t\t\tcategory: \"model\",\n\t\t\ttype: \"select\" as const,\n\t\t\tcurrentValue: models.currentModelId,\n\t\t\toptions: models.availableModels.map((m) => ({\n\t\t\t\tvalue: m.modelId,\n\t\t\t\tname: m.name,\n\t\t\t\tdescription: m.description ?? null,\n\t\t\t})),\n\t\t},\n\t\t{\n\t\t\tid: \"thought_level\",\n\t\t\tname: \"Thinking Level\",\n\t\t\tdescription: \"Reasoning depth for models that support it\",\n\t\t\tcategory: \"thought_level\",\n\t\t\ttype: \"select\" as const,\n\t\t\tcurrentValue: modes.currentModeId,\n\t\t\toptions: modes.availableModes.map((m) => ({\n\t\t\t\tvalue: m.id,\n\t\t\t\tname: m.name,\n\t\t\t\tdescription: m.description ?? null,\n\t\t\t})),\n\t\t},\n\t];\n}\n\nfunction buildCommandList(\n\tpiSession: AgentSession,\n\tenableSkillCommands: boolean,\n): AvailableCommand[] {\n\tconst commands: AvailableCommand[] = [];\n\n\tfor (const template of piSession.promptTemplates) {\n\t\tcommands.push({\n\t\t\tname: template.name,\n\t\t\tdescription: template.description ?? `(prompt)`,\n\t\t});\n\t}\n\n\tif (enableSkillCommands) {\n\t\tconst skills = piSession.resourceLoader.getSkills();\n\t\tfor (const skill of skills.skills) {\n\t\t\tcommands.push({\n\t\t\t\tname: `skill:${skill.name}`,\n\t\t\t\tdescription: skill.description ?? `(skill)`,\n\t\t\t});\n\t\t}\n\t}\n\n\tfor (const cmd of piSession.extensionRunner.getRegisteredCommands()) {\n\t\tcommands.push({\n\t\t\tname: cmd.name,\n\t\t\tdescription: cmd.description ?? \"(extension)\",\n\t\t});\n\t}\n\n\treturn commands;\n}\n\nfunction findChangelog(): string | null {\n\ttry {\n\t\tconst p = piChangelogPath();\n\t\tif (existsSync(p)) return p;\n\t} catch {}\n\treturn null;\n}\n","/**\n * ACP-over-stream wiring for the daemon's per-connection accept path.\n *\n * Owns nothing global. Returns the constructed AgentSideConnection plus a\n * shutdown helper. Caller decides what process / signal handlers to attach.\n */\n\nimport type { Duplex } from \"node:stream\";\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\";\nimport { PiAcpAgent } from \"@pi-acp/acp/agent\";\nimport type { DaemonContext } from \"@pi-acp/daemon/context\";\n\nexport interface ServeOptions {\n\t/** Reads from the client. */\n\tinput: Duplex;\n\t/** Writes to the client. */\n\toutput: Duplex;\n\tdaemonContext: DaemonContext;\n}\n\nexport interface ServeHandle {\n\tconnection: AgentSideConnection;\n\t/** Best-effort dispose of the PiAcpAgent. */\n\tdispose: () => void;\n}\n\nexport function serveAcp(opts: ServeOptions): ServeHandle {\n\t// Build the NDJSON framing layer. `input` is the client-bound stream we\n\t// read FROM (client → agent). `output` is the stream we write TO\n\t// (agent → client). ndJsonStream(writable, readable): first arg is where\n\t// the agent writes responses, second is where it reads requests.\n\tconst stream = ndJsonStream(toWebWritable(opts.output), toWebReadable(opts.input));\n\tconst connection = new AgentSideConnection(\n\t\t(conn) => new PiAcpAgent(conn, opts.daemonContext),\n\t\tstream,\n\t);\n\treturn {\n\t\tconnection,\n\t\tdispose() {\n\t\t\ttry {\n\t\t\t\tconst inner = readUnknownProp(connection, \"agent\");\n\t\t\t\tconst dispose = readUnknownProp(inner, \"dispose\");\n\t\t\t\tif (typeof dispose === \"function\") {\n\t\t\t\t\tReflect.apply(dispose, inner, []);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction readUnknownProp(target: unknown, key: string): unknown {\n\tif (typeof target !== \"object\" || target === null) return undefined;\n\treturn Reflect.get(target, key);\n}\n\nfunction toWebReadable(src: Duplex): ReadableStream<Uint8Array> {\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tsrc.on(\"data\", (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));\n\t\t\tsrc.on(\"end\", () => {\n\t\t\t\ttry {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t/* already closed */\n\t\t\t\t}\n\t\t\t});\n\t\t\tsrc.on(\"error\", (err) => {\n\t\t\t\ttry {\n\t\t\t\t\tcontroller.error(err);\n\t\t\t\t} catch {\n\t\t\t\t\t/* already terminated */\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t});\n}\n\nfunction toWebWritable(dst: Duplex): WritableStream<Uint8Array> {\n\treturn new WritableStream<Uint8Array>({\n\t\twrite(chunk) {\n\t\t\treturn new Promise<void>((resolve) => {\n\t\t\t\tif (dst.destroyed || !dst.writable) {\n\t\t\t\t\tresolve();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tdst.write(chunk, () => resolve());\n\t\t\t\t} catch {\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t});\n}\n","/**\n * Daemon entry point. Invoked when pi-acp is launched with `--daemon`.\n *\n * Lifecycle:\n * 1. Acquire per-UID lockfile (refuses if another daemon alive).\n * 2. Remove stale socket files left by a dead prior daemon.\n * 3. Construct DaemonContext shared singletons.\n * 4. Bind ACP socket (raw NDJSON via node:net).\n * 5. Bind control socket (HTTP via Bun.serve + Hono).\n * 6. SIGINT/SIGTERM/idle-timeout trigger graceful shutdown.\n */\n\nimport { createServer, type Server, type Socket } from \"node:net\";\nimport { createDaemonContext, type DaemonContext } from \"@pi-acp/daemon/context\";\nimport {\n\tbuildControlApp,\n\ttype ControlContext,\n\ttype ControlServer,\n\tserveControl,\n} from \"@pi-acp/daemon/control\";\nimport { createIdleTracker, resolveIdleMs } from \"@pi-acp/daemon/idle\";\nimport {\n\tacquireLock,\n\tcontrolSocketPath,\n\tensureSocketParentDir,\n\treleaseLock,\n\tremoveStaleSocketIfAny,\n\tsocketPath,\n} from \"@pi-acp/daemon/socket\";\nimport { type ServeHandle, serveAcp } from \"@pi-acp/runtime/serve\";\n\nimport pkgJson from \"../../package.json\" with { type: \"json\" };\n\ninterface Connection {\n\tsocket: Socket;\n\thandle: ServeHandle;\n}\n\nexport async function runDaemon(): Promise<void> {\n\tconst lockResult = acquireLock();\n\tif (!lockResult.ok) {\n\t\tprocess.stderr.write(\n\t\t\t`pi-acp daemon: already running (pid ${lockResult.heldByPid ?? \"unknown\"})\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tensureSocketParentDir();\n\tremoveStaleSocketIfAny();\n\n\tconst connections = new Set<Connection>();\n\tlet shuttingDown = false;\n\tconst startedAt = Date.now();\n\n\tconst shutdown = (): void => {\n\t\tif (shuttingDown) return;\n\t\tshuttingDown = true;\n\t\tserver.close();\n\t\tcontrolServer.stop();\n\t\tfor (const entry of connections) {\n\t\t\ttry {\n\t\t\t\tentry.handle.dispose();\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tentry.socket.destroy();\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t}\n\t\tconnections.clear();\n\t\tctx.idleTracker.dispose();\n\t\tremoveStaleSocketIfAny();\n\t\treleaseLock();\n\t\tprocess.exit(0);\n\t};\n\n\tconst ctx: DaemonContext = createDaemonContext();\n\tctx.idleTracker = createIdleTracker({ idleMs: resolveIdleMs(), onIdle: shutdown });\n\n\tconst controlCtx: ControlContext = {\n\t\tctx,\n\t\tstartedAt,\n\t\tpid: process.pid,\n\t\tversion: pkgJson.version,\n\t\tactiveConnections: () => connections.size,\n\t\tonShutdown: shutdown,\n\t};\n\n\tconst server: Server = createServer((socket) => {\n\t\tif (shuttingDown) {\n\t\t\tsocket.destroy();\n\t\t\treturn;\n\t\t}\n\t\tonAccept(socket);\n\t});\n\n\tconst onAccept = (socket: Socket): void => {\n\t\tconst handle = serveAcp({\n\t\t\tinput: socket,\n\t\t\toutput: socket,\n\t\t\tdaemonContext: ctx,\n\t\t});\n\t\tconst entry: Connection = { socket, handle };\n\t\tconnections.add(entry);\n\t\tctx.idleTracker.bump(1);\n\n\t\tconst cleanup = (): void => {\n\t\t\tif (!connections.delete(entry)) return;\n\t\t\ttry {\n\t\t\t\thandle.dispose();\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t\tctx.idleTracker.bump(-1);\n\t\t};\n\n\t\tsocket.on(\"close\", cleanup);\n\t\tsocket.on(\"error\", cleanup);\n\t};\n\n\tserver.on(\"error\", (err) => {\n\t\tprocess.stderr.write(`pi-acp daemon: server error: ${err.message}\\n`);\n\t});\n\n\tawait new Promise<void>((resolve, reject) => {\n\t\tconst path = socketPath();\n\t\tserver.listen(path, () => resolve());\n\t\tserver.once(\"error\", reject);\n\t});\n\n\tconst controlServer: ControlServer = serveControl(\n\t\tbuildControlApp(controlCtx),\n\t\tcontrolSocketPath(),\n\t);\n\n\t// biome-ignore lint/complexity/useLiteralKeys: env var keys need bracket access for tsc strict mode\n\tif (process.env[\"PI_ACP_DAEMON_DEBUG\"] === \"1\") {\n\t\tprocess.stderr.write(\n\t\t\t`pi-acp daemon: acp=${socketPath()} control=${controlSocketPath()} pid=${process.pid}\\n`,\n\t\t);\n\t}\n\n\tprocess.on(\"SIGINT\", () => {\n\t\tshutdown();\n\t});\n\tprocess.on(\"SIGTERM\", () => {\n\t\tshutdown();\n\t});\n}\n"],"mappings":"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"}
|