pi-acp 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.js +1415 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/acp/agent.ts","../src/acp/session.ts","../src/pi-rpc/process.ts","../src/acp/session-store.ts","../src/acp/paths.ts","../src/acp/translate/pi-tools.ts","../src/acp/slash-commands.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts"],"sourcesContent":["import { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'\nimport { PiAcpAgent } from './acp/agent.js'\n\n\nconst input = new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n process.stdout.write(chunk, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n})\n\nconst output = new ReadableStream<Uint8Array>({\n start(controller) {\n process.stdin.on('data', (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)))\n process.stdin.on('end', () => controller.close())\n process.stdin.on('error', err => controller.error(err))\n }\n})\n\nconst stream = ndJsonStream(input, output)\n\nnew AgentSideConnection(conn => new PiAcpAgent(conn), stream)\n\nprocess.stdin.resume()\nprocess.on('SIGINT', () => process.exit(0))\nprocess.on('SIGTERM', () => process.exit(0))\n","import {\n RequestError,\n type Agent as ACPAgent,\n type AgentSideConnection,\n type AuthenticateRequest,\n type CancelNotification,\n type InitializeRequest,\n type InitializeResponse,\n type LoadSessionRequest,\n type LoadSessionResponse,\n type ModelInfo,\n type NewSessionRequest,\n type PromptRequest,\n type PromptResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type StopReason\n} from '@agentclientprotocol/sdk'\nimport { SessionManager } from './session.js'\nimport { SessionStore } from './session-store.js'\nimport { PiRpcProcess } from '../pi-rpc/process.js'\nimport { normalizePiAssistantText, normalizePiMessageText } from './translate/pi-messages.js'\nimport { promptToPiMessage } from './translate/prompt.js'\nimport { loadSlashCommands, parseCommandArgs, toAvailableCommands } from './slash-commands.js'\nimport { isAbsolute } from 'node:path'\nimport { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\nimport { join, dirname } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\ntype ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'\n\nfunction builtinAvailableCommands(): AvailableCommand[] {\n return [\n {\n name: 'compact',\n description: 'Manually compact the session context',\n input: { hint: 'optional custom instructions' }\n },\n {\n name: 'autocompact',\n description: 'Toggle automatic context compaction',\n input: { hint: 'on|off|toggle' }\n },\n {\n name: 'export',\n description: 'Export session to an HTML file in the session cwd'\n },\n {\n name: 'session',\n description: 'Show session stats (messages, tokens, cost, session file)'\n },\n {\n name: 'queue',\n description: 'Set pi message queue mode (all | one-at-a-time(recommended))',\n input: { hint: 'all | one-at-a-time' }\n },\n {\n name: 'changelog',\n description: 'Show pi changelog'\n }\n ]\n}\n\nfunction mergeCommands(a: AvailableCommand[], b: AvailableCommand[]): AvailableCommand[] {\n // Preserve order, de-dupe by name (first wins).\n const out: AvailableCommand[] = []\n const seen = new Set<string>()\n\n for (const c of [...a, ...b]) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n out.push(c)\n }\n\n return out\n}\nimport { fileURLToPath } from 'node:url'\n\nconst pkg = readNearestPackageJson(import.meta.url)\n\nexport class PiAcpAgent implements ACPAgent {\n private readonly conn: AgentSideConnection\n private readonly sessions = new SessionManager()\n private readonly store = new SessionStore()\n\n constructor(conn: AgentSideConnection) {\n this.conn = conn\n }\n\n async initialize(params: InitializeRequest): Promise<InitializeResponse> {\n // We currently only support ACP protocol version 1.\n const supportedVersion = 1\n const requested = params.protocolVersion\n\n return {\n protocolVersion: requested === supportedVersion ? requested : supportedVersion,\n agentInfo: {\n name: pkg.name ?? 'pi-acp',\n title: 'pi ACP adapter',\n version: pkg.version ?? '0.0.0'\n },\n authMethods: [],\n agentCapabilities: {\n loadSession: true,\n mcpCapabilities: { http: false, sse: false },\n promptCapabilities: {\n image: true,\n audio: false,\n embeddedContext: false\n },\n sessionCapabilities: {}\n }\n }\n }\n\n async newSession(params: NewSessionRequest) {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n // Pi doesn't support mcpServers, but we accept and store.\n const session = await this.sessions.create({\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n fileCommands\n })\n\n const models = await getModelState(session.proc)\n const thinking = await getThinkingState(session.proc)\n\n const response = {\n sessionId: session.sessionId,\n models,\n modes: thinking,\n _meta: {}\n }\n\n // Advertise slash commands (ACP: available_commands_update)\n // Important: some clients (e.g. Zed) will ignore notifications for an unknown sessionId.\n // So we must send this *after* the session/new response has been delivered.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async authenticate(_params: AuthenticateRequest) {\n // MVP: no auth.\n return\n }\n\n async prompt(params: PromptRequest): Promise<PromptResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const { message, attachments } = promptToPiMessage(params.prompt)\n\n // Built-in ACP slash command handling (headless-friendly subset).\n // Note: file-based slash commands are expanded inside session.prompt().\n if (attachments.length === 0 && message.trimStart().startsWith('/')) {\n const trimmed = message.trim()\n const space = trimmed.indexOf(' ')\n const cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space)\n const argsString = space === -1 ? '' : trimmed.slice(space + 1)\n const args = parseCommandArgs(argsString)\n\n if (cmd === 'compact') {\n const customInstructions = args.join(' ').trim() || undefined\n const res = await session.proc.compact(customInstructions)\n\n const r: any = res && typeof res === 'object' ? (res as any) : null\n const tokensBefore = typeof r?.tokensBefore === 'number' ? r.tokensBefore : null\n const summary = typeof r?.summary === 'string' ? r.summary : null\n\n const headerLines = [\n `Compaction completed.${customInstructions ? ' (custom instructions applied)' : ''}`,\n tokensBefore !== null ? `Tokens before: ${tokensBefore}` : null\n ].filter(Boolean)\n\n const text = headerLines.join('\\n') + (summary ? `\\n\\n${summary}` : '')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'session') {\n const stats = (await session.proc.getSessionStats()) as any\n\n const lines: string[] = []\n if (stats?.sessionId) lines.push(`Session: ${stats.sessionId}`)\n if (stats?.sessionFile) lines.push(`Session file: ${stats.sessionFile}`)\n if (typeof stats?.totalMessages === 'number') lines.push(`Messages: ${stats.totalMessages}`)\n\n if (typeof stats?.cost === 'number') lines.push(`Cost: ${stats.cost}`)\n\n const t = stats?.tokens\n if (t && typeof t === 'object') {\n const parts: string[] = []\n if (typeof t.input === 'number') parts.push(`in ${t.input}`)\n if (typeof t.output === 'number') parts.push(`out ${t.output}`)\n if (typeof t.cacheRead === 'number') parts.push(`cache read ${t.cacheRead}`)\n if (typeof t.cacheWrite === 'number') parts.push(`cache write ${t.cacheWrite}`)\n if (typeof t.total === 'number') parts.push(`total ${t.total}`)\n if (parts.length) lines.push(`Tokens: ${parts.join(', ')}`)\n }\n\n // Fallback if stats shape changes.\n const text = lines.length ? lines.join('\\n') : `Session stats:\\n${JSON.stringify(stats, null, 2)}`\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'queue') {\n const modeRaw = String(args[0] ?? '').toLowerCase()\n const state = (await session.proc.getState()) as any\n const current = String(state?.queueMode ?? '')\n\n // If no arg, just report current.\n if (!modeRaw) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Queue mode: ${current || 'unknown'}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (modeRaw !== 'all' && modeRaw !== 'one-at-a-time') {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Usage: /queue all | /queue one-at-a-time'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n await session.proc.setQueueMode(modeRaw as 'all' | 'one-at-a-time')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Queue mode set to: ${modeRaw}` }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'changelog') {\n // Read pi's installed CHANGELOG.md. Adapter-side, no model call.\n const findChangelog = (): string | null => {\n // 1) Locate the installed pi package by resolving the `pi` executable.\n // On Node installs, `pi` typically resolves to .../@mariozechner/pi-coding-agent/dist/cli.js\n try {\n const whichCmd = process.platform === 'win32' ? 'where' : 'which'\n const which = spawnSync(whichCmd, ['pi'], { encoding: 'utf-8' })\n const piPath = String(which.stdout ?? '')\n .split(/\\r?\\n/)[0]\n ?.trim()\n\n if (piPath) {\n const resolved = realpathSync(piPath)\n const pkgRoot = dirname(dirname(resolved))\n const p = join(pkgRoot, 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n // 2) Fallback: ask npm where global modules live.\n try {\n const npmRoot = spawnSync('npm', ['root', '-g'], { encoding: 'utf-8' })\n const root = String(npmRoot.stdout ?? '').trim()\n if (root) {\n const p = join(root, '@mariozechner', 'pi-coding-agent', 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n return null\n }\n\n const changelogPath = findChangelog()\n if (!changelogPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: \"Changelog not found (couldn't locate pi installation).\" }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n let text = ''\n try {\n text = readFileSync(changelogPath, 'utf-8')\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Failed to read changelog: ${String(e?.message ?? e)}` }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n // Keep it reasonably sized in chat.\n const maxChars = 20_000\n if (text.length > maxChars) text = text.slice(0, maxChars) + '\\n\\n...(truncated)...'\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'export') {\n // For now we always export into the session cwd and do not accept a user-provided path.\n // IMPORTANT: pi's export_html reads the session JSONL file. If it doesn't exist yet\n // (no messages) or is empty, pi throws and RPC mode emits an uncorrelated parse error\n // (no id), which would otherwise hang our request. So we guard here.\n const state = (await session.proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n const messageCount = typeof state?.messageCount === 'number' ? state.messageCount : 0\n\n if (!sessionFile || messageCount === 0 || !existsSync(sessionFile)) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (no session messages). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n try {\n const raw = readFileSync(sessionFile, 'utf-8')\n if (raw.trim().length === 0) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (empty session file). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n } catch {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: \"Couldn't read session file for export. Try sending a prompt first.\"\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, '_')\n const outputPath = join(session.cwd, `pi-session-${safeSessionId}.html`)\n\n let resultPath = ''\n try {\n const result = await session.proc.exportHtml(outputPath)\n resultPath = result.path\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Export failed: ${String(e?.message ?? e)}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (!resultPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Export failed: no output path returned by pi.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const uri = `file://${resultPath}`\n\n // Emit a short prefix + a resource link. Many clients concatenate chunks into a single\n // assistant message, so this avoids the \"link + duplicate plain text\" look.\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Session exported: '\n }\n }\n })\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'resource_link',\n name: `pi-session-${safeSessionId}.html`,\n uri,\n mimeType: 'text/html',\n title: 'Session exported'\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'autocompact') {\n const mode = (args[0] ?? 'toggle').toLowerCase()\n let enabled: boolean | null = null\n if (mode === 'on' || mode === 'true' || mode === 'enable' || mode === 'enabled') enabled = true\n else if (mode === 'off' || mode === 'false' || mode === 'disable' || mode === 'disabled') enabled = false\n\n if (enabled === null) {\n // toggle: read current state and invert.\n const state = (await session.proc.getState()) as any\n const current = Boolean(state?.autoCompactionEnabled)\n enabled = !current\n }\n\n await session.proc.setAutoCompaction(enabled)\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Auto-compaction ${enabled ? 'enabled' : 'disabled'}.`\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n }\n\n const result = await session.prompt(message, attachments)\n\n // ACP StopReason does not include \"error\"; if pi fails we map to end_turn for now,\n // unless we know this was a cancellation.\n const stopReason: StopReason =\n result === 'error' ? (session.wasCancelRequested() ? 'cancelled' : 'end_turn') : result\n\n return { stopReason }\n }\n\n async cancel(params: CancelNotification): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n await session.cancel()\n }\n\n async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n // MVP: ignore mcpServers.\n const stored = this.store.get(params.sessionId)\n if (!stored) {\n throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`)\n }\n\n // Spawn pi and point it directly at the stored session file.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd,\n sessionPath: stored.sessionFile\n })\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n const session = this.sessions.getOrCreate(params.sessionId, {\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n proc,\n fileCommands\n })\n\n // (Optional) ensure mapping stays fresh.\n this.store.upsert({\n sessionId: params.sessionId,\n cwd: params.cwd,\n sessionFile: stored.sessionFile\n })\n\n // Replay full conversation history.\n const data = (await proc.getMessages()) as any\n const messages = Array.isArray(data?.messages) ? data.messages : []\n\n for (const m of messages) {\n const role = String(m?.role ?? '')\n\n if (role === 'user') {\n const text = normalizePiMessageText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'user_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n\n if (role === 'assistant') {\n const text = normalizePiAssistantText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n }\n\n const models = await getModelState(proc)\n const thinking = await getThinkingState(proc)\n\n const response = {\n models,\n modes: thinking,\n _meta: {}\n }\n\n // Advertise slash commands after the response so the client knows the session exists.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async unstable_setSessionModel(params: { sessionId: string; modelId: string }): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n\n // Accept either:\n // - \"provider/model\" (preferred, matches how we advertise)\n // - \"model\" (fallback, we try to resolve via available models)\n let provider: string | null = null\n let modelId: string | null = null\n\n if (params.modelId.includes('/')) {\n const [p, ...rest] = params.modelId.split('/')\n provider = p\n modelId = rest.join('/')\n } else {\n modelId = params.modelId\n }\n\n if (!provider) {\n const data = (await session.proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n const found = models.find(m => String(m?.id) === modelId)\n if (found) {\n provider = String(found.provider)\n modelId = String(found.id)\n }\n }\n\n if (!provider || !modelId) {\n throw RequestError.invalidParams(`Unknown modelId: ${params.modelId}`)\n }\n\n await session.proc.setModel(provider, modelId)\n }\n\n async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const mode = String(params.modeId)\n if (!isThinkingLevel(mode)) {\n throw RequestError.invalidParams(`Unknown modeId: ${mode}`)\n }\n\n await session.proc.setThinkingLevel(mode)\n\n // Let the client know the current mode changed (keeps the dropdown in sync).\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'current_mode_update',\n currentModeId: mode\n }\n })\n\n return {}\n }\n}\n\nfunction isThinkingLevel(x: string): x is ThinkingLevel {\n return x === 'off' || x === 'minimal' || x === 'low' || x === 'medium' || x === 'high' || x === 'xhigh'\n}\n\nasync function getThinkingState(proc: PiRpcProcess): Promise<{\n availableModes: Array<{\n id: string\n name: string\n description?: string | null\n }>\n currentModeId: string\n}> {\n // Ask pi for current thinking level.\n let current: ThinkingLevel = 'medium'\n try {\n const state = (await proc.getState()) as any\n const tl = typeof state?.thinkingLevel === 'string' ? state.thinkingLevel : null\n if (tl && isThinkingLevel(tl)) current = tl\n } catch {\n // ignore\n }\n\n const available: ThinkingLevel[] = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh']\n\n return {\n currentModeId: current,\n availableModes: available.map(id => ({\n id,\n name: `Thinking: ${id}`,\n description: null\n }))\n }\n}\n\nasync function getModelState(proc: PiRpcProcess): Promise<{\n availableModels: ModelInfo[]\n currentModelId: string\n} | null> {\n // Ask pi for available models.\n let availableModels: ModelInfo[] = []\n try {\n const data = (await proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n availableModels = models\n .map(m => {\n const provider = String(m?.provider ?? '').trim()\n const id = String(m?.id ?? '').trim()\n if (!provider || !id) return null\n\n const name = String(m?.name ?? id)\n return {\n modelId: `${provider}/${id}`,\n name: `${provider}/${name}`,\n description: null\n } satisfies ModelInfo\n })\n .filter(Boolean) as ModelInfo[]\n } catch {\n // ignore\n }\n\n // Ask pi what model is currently active.\n let currentModelId: string | null = null\n try {\n const state = (await proc.getState()) as any\n const model = state?.model\n if (model && typeof model === 'object') {\n const provider = String((model as any).provider ?? '').trim()\n const id = String((model as any).id ?? '').trim()\n if (provider && id) currentModelId = `${provider}/${id}`\n }\n } catch {\n // ignore\n }\n\n if (!availableModels.length && !currentModelId) return null\n\n // Fallback if current model is unknown: use first in list.\n if (!currentModelId) currentModelId = availableModels[0]?.modelId ?? 'default'\n\n return {\n availableModels,\n currentModelId\n }\n}\n\nfunction readNearestPackageJson(metaUrl: string): {\n name?: string\n version?: string\n} {\n try {\n let dir = dirname(fileURLToPath(metaUrl))\n\n // Walk upwards a few levels to find the nearest package.json\n for (let i = 0; i < 6; i++) {\n const p = join(dir, 'package.json')\n if (existsSync(p)) {\n const json = JSON.parse(readFileSync(p, 'utf-8')) as any\n return { name: json?.name, version: json?.version }\n }\n dir = dirname(dir)\n }\n } catch {\n // ignore\n }\n return { name: 'pi-acp', version: '0.0.0' }\n}\n","import type {\n AgentSideConnection,\n ContentBlock,\n McpServer,\n SessionUpdate,\n ToolCallContent,\n ToolKind\n} from '@agentclientprotocol/sdk'\nimport { RequestError } from '@agentclientprotocol/sdk'\nimport { readFileSync } from 'node:fs'\nimport { isAbsolute, resolve as resolvePath } from 'node:path'\nimport { PiRpcProcess, type PiRpcEvent } from '../pi-rpc/process.js'\nimport { SessionStore } from './session-store.js'\nimport { toolResultToText } from './translate/pi-tools.js'\nimport { expandSlashCommand, type FileSlashCommand } from './slash-commands.js'\n\ntype SessionCreateParams = {\n cwd: string\n mcpServers: McpServer[]\n conn: AgentSideConnection\n fileCommands?: import('./slash-commands.js').FileSlashCommand[]\n}\n\nexport type StopReason = 'end_turn' | 'cancelled' | 'error'\n\ntype PendingTurn = {\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\ntype QueuedTurn = {\n message: string\n attachments: unknown[]\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\nexport class SessionManager {\n private sessions = new Map<string, PiAcpSession>()\n private readonly store = new SessionStore()\n\n /** Get a registered session if it exists (no throw). */\n maybeGet(sessionId: string): PiAcpSession | undefined {\n return this.sessions.get(sessionId)\n }\n\n async create(params: SessionCreateParams): Promise<PiAcpSession> {\n // Let pi manage session persistence in its default location (~/.pi/agent/sessions/...)\n // so sessions are visible to the regular `pi` CLI.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd\n })\n\n const state = (await proc.getState()) as any\n const sessionId = typeof state?.sessionId === 'string' ? state.sessionId : crypto.randomUUID()\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n\n if (sessionFile) {\n this.store.upsert({ sessionId, cwd: params.cwd, sessionFile })\n }\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n\n get(sessionId: string): PiAcpSession {\n const s = this.sessions.get(sessionId)\n if (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`)\n return s\n }\n\n /**\n * Used by session/load: create a session object bound to an existing sessionId/proc\n * if it isn't already registered.\n */\n getOrCreate(sessionId: string, params: SessionCreateParams & { proc: PiRpcProcess }): PiAcpSession {\n const existing = this.sessions.get(sessionId)\n if (existing) return existing\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc: params.proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n}\n\nexport class PiAcpSession {\n readonly sessionId: string\n readonly cwd: string\n readonly mcpServers: McpServer[]\n\n readonly proc: PiRpcProcess\n private readonly conn: AgentSideConnection\n private readonly fileCommands: FileSlashCommand[]\n\n // Used to map abort semantics to ACP stopReason.\n // Applies to the currently running turn.\n private cancelRequested = false\n\n // Current in-flight turn (if any). Additional prompts are queued.\n private pendingTurn: PendingTurn | null = null\n private readonly turnQueue: QueuedTurn[] = []\n // Track tool call statuses and ensure they are monotonic (pending -> in_progress -> completed).\n // Some pi events can arrive out of order (e.g. late toolcall_* deltas after execution starts),\n // and clients may hide progress if we ever downgrade back to `pending`.\n private currentToolCalls = new Map<string, 'pending' | 'in_progress'>()\n\n // pi can emit multiple `turn_end` events for a single user prompt (e.g. after tool_use).\n // The overall agent loop completes when `agent_end` is emitted.\n private inAgentLoop = false\n\n // For ACP diff support: capture file contents before edits, then emit ToolCallContent {type:\"diff\"}.\n // This is due to pi sending diff as a string as opposed to ACP expected diff format.\n // Compatible format may need to be implemented in pi in the future.\n private editSnapshots = new Map<string, { path: string; oldText: string }>()\n\n // Ensure `session/update` notifications are sent in order and can be awaited\n // before completing a `session/prompt` request.\n private lastEmit: Promise<void> = Promise.resolve()\n\n constructor(opts: {\n sessionId: string\n cwd: string\n mcpServers: McpServer[]\n proc: PiRpcProcess\n conn: AgentSideConnection\n fileCommands?: FileSlashCommand[]\n }) {\n this.sessionId = opts.sessionId\n this.cwd = opts.cwd\n this.mcpServers = opts.mcpServers\n this.proc = opts.proc\n this.conn = opts.conn\n this.fileCommands = opts.fileCommands ?? []\n\n this.proc.onEvent(ev => this.handlePiEvent(ev))\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<StopReason> {\n // pi RPC mode disables slash command expansion, so we do it here.\n const expandedMessage = expandSlashCommand(message, this.fileCommands)\n\n const turnPromise = new Promise<StopReason>((resolve, reject) => {\n const queued: QueuedTurn = { message: expandedMessage, attachments, resolve, reject }\n\n // If a turn is already running, enqueue.\n if (this.pendingTurn) {\n this.turnQueue.push(queued)\n\n // Best-effort: notify client that a prompt was queued.\n // This doesn't work in Zed yet, needs to be revisited\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Queued message (position ${this.turnQueue.length}).`\n }\n })\n\n // Also publish queue depth via session info metadata.\n // This also not visible in the client\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n return\n }\n\n // No turn is running; start immediately.\n this.startTurn(queued)\n })\n\n return turnPromise\n }\n\n async cancel(): Promise<void> {\n // Cancel current and clear any queued prompts.\n this.cancelRequested = true\n\n if (this.turnQueue.length) {\n const queued = this.turnQueue.splice(0, this.turnQueue.length)\n for (const t of queued) t.resolve('cancelled')\n\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: 'Cleared queued prompts.' }\n })\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: Boolean(this.pendingTurn) } }\n })\n }\n\n // Abort the currently running turn (if any). If nothing is running, this is a no-op.\n await this.proc.abort()\n }\n\n wasCancelRequested(): boolean {\n return this.cancelRequested\n }\n\n private emit(update: SessionUpdate): void {\n // Serialize update delivery.\n this.lastEmit = this.lastEmit\n .then(() =>\n this.conn.sessionUpdate({\n sessionId: this.sessionId,\n update\n })\n )\n .catch(() => {\n // Ignore notification errors (client may have gone away). We still want\n // prompt completion.\n })\n }\n\n private async flushEmits(): Promise<void> {\n await this.lastEmit\n }\n\n private startTurn(t: QueuedTurn): void {\n this.cancelRequested = false\n this.inAgentLoop = false\n\n this.pendingTurn = { resolve: t.resolve, reject: t.reject }\n\n // Publish queue depth (0 because we're starting the turn now).\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n // Kick off pi, but completion is determined by pi events, not the RPC response.\n // Important: pi may emit multiple `turn_end` events (e.g. when the model requests tools).\n // The full prompt is finished when we see `agent_end`.\n this.proc.prompt(t.message, t.attachments).catch(err => {\n // If the subprocess errors before we get an `agent_end`, treat as error unless cancelled.\n // Also ensure we flush any already-enqueued updates first.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'error'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // If the prompt failed, do not automatically proceed—pi may be unhealthy.\n // But we still clear the queueDepth metadata.\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: false } }\n })\n })\n void err\n })\n }\n\n private handlePiEvent(ev: PiRpcEvent) {\n const type = String((ev as any).type ?? '')\n\n switch (type) {\n case 'message_update': {\n const ame = (ev as any).assistantMessageEvent\n\n // Stream assistant text.\n if (ame?.type === 'text_delta' && typeof ame.delta === 'string') {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: ame.delta } satisfies ContentBlock\n })\n break\n }\n\n // Surface tool calls ASAP so clients (e.g. Zed) can show a tool-in-use/loading UI\n // while the model is still streaming tool call args.\n if (ame?.type === 'toolcall_start' || ame?.type === 'toolcall_delta' || ame?.type === 'toolcall_end') {\n const toolCall =\n // pi sometimes includes the tool call directly on the event\n (ame as any)?.toolCall ??\n // ...and always includes it in the partial assistant message at contentIndex\n (ame as any)?.partial?.content?.[(ame as any)?.contentIndex ?? 0]\n\n const toolCallId = String((toolCall as any)?.id ?? '')\n const toolName = String((toolCall as any)?.name ?? 'tool')\n\n if (toolCallId) {\n const rawInput =\n (toolCall as any)?.arguments && typeof (toolCall as any).arguments === 'object'\n ? (toolCall as any).arguments\n : (() => {\n const s = String((toolCall as any)?.partialArgs ?? '')\n if (!s) return undefined\n try {\n return JSON.parse(s)\n } catch {\n return { partialArgs: s }\n }\n })()\n\n const existingStatus = this.currentToolCalls.get(toolCallId)\n // IMPORTANT: never downgrade status (e.g. if we already marked in_progress via tool_execution_start).\n const status = existingStatus ?? 'pending'\n\n if (!existingStatus) {\n this.currentToolCalls.set(toolCallId, 'pending')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status,\n rawInput\n })\n } else {\n // Best-effort: keep rawInput updated while args are streaming.\n // Keep the existing status (pending or in_progress).\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status,\n rawInput\n })\n }\n }\n\n break\n }\n\n // (MVP) ignore other delta types (thinking, etc.) for now.\n break\n }\n\n case 'tool_execution_start': {\n const toolCallId = String((ev as any).toolCallId ?? crypto.randomUUID())\n const toolName = String((ev as any).toolName ?? 'tool')\n const args = (ev as any).args\n\n // Capture pre-edit file contents so we can emit a structured ACP diff on completion.\n if (toolName === 'edit') {\n const p = typeof args?.path === 'string' ? args.path : undefined\n if (p) {\n try {\n const abs = isAbsolute(p) ? p : resolvePath(this.cwd, p)\n const oldText = readFileSync(abs, 'utf8')\n this.editSnapshots.set(toolCallId, { path: p, oldText })\n } catch {\n // Ignore snapshot failures; we'll fall back to plain text output.\n }\n }\n }\n\n // If we already surfaced the tool call while the model streamed it, just transition.\n if (!this.currentToolCalls.has(toolCallId)) {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status: 'in_progress',\n rawInput: args\n })\n } else {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n rawInput: args\n })\n }\n\n break\n }\n\n case 'tool_execution_update': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const partial = (ev as any).partialResult\n const text = toolResultToText(partial)\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n content: text\n ? ([{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[])\n : undefined,\n rawOutput: partial\n })\n break\n }\n\n case 'tool_execution_end': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const result = (ev as any).result\n const isError = Boolean((ev as any).isError)\n const text = toolResultToText(result)\n\n // If this was an edit and we captured a snapshot, emit a structured ACP diff.\n // This enables clients like Zed to render an actual diff UI.\n const snapshot = this.editSnapshots.get(toolCallId)\n let content: ToolCallContent[] | undefined\n\n if (!isError && snapshot) {\n try {\n const abs = isAbsolute(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path)\n const newText = readFileSync(abs, 'utf8')\n if (newText !== snapshot.oldText) {\n content = [\n {\n type: 'diff',\n path: snapshot.path,\n oldText: snapshot.oldText,\n newText\n },\n ...(text ? ([{ type: 'content', content: { type: 'text', text } }] as ToolCallContent[]) : [])\n ]\n }\n } catch {\n // ignore; fall back to text only\n }\n }\n\n // Fallback: just text content.\n if (!content && text) {\n content = [{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[]\n }\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: isError ? 'failed' : 'completed',\n content,\n rawOutput: result\n })\n\n this.currentToolCalls.delete(toolCallId)\n this.editSnapshots.delete(toolCallId)\n break\n }\n\n case 'agent_start': {\n this.inAgentLoop = true\n break\n }\n\n case 'turn_end': {\n // pi uses `turn_end` for sub-steps (e.g. tool_use) and will often start another turn.\n // Do NOT resolve the ACP `session/prompt` here; wait for `agent_end`.\n break\n }\n\n case 'agent_end': {\n // Ensure all updates derived from pi events are delivered before we resolve\n // the ACP `session/prompt` request.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'end_turn'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // Start next queued prompt, if any.\n const next = this.turnQueue.shift()\n if (next) {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Starting queued message. (${this.turnQueue.length} remaining)` }\n })\n this.startTurn(next)\n } else {\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: false } }\n })\n }\n })\n break\n }\n\n default:\n break\n }\n }\n}\n\nfunction toToolKind(toolName: string): ToolKind {\n switch (toolName) {\n case 'read':\n return 'read'\n case 'write':\n case 'edit':\n return 'edit'\n case 'bash':\n // Many ACP clients render `execute` tool calls only via the terminal APIs.\n // Since this adapter lets pi execute locally (no client terminal delegation),\n // we report bash as `other` so clients show inline text output blocks.\n return 'other'\n default:\n return 'other'\n }\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport * as readline from 'node:readline'\n\ntype PiRpcCommand =\n | { type: 'prompt'; id?: string; message: string; attachments?: unknown[] }\n | { type: 'abort'; id?: string }\n | { type: 'get_state'; id?: string }\n // Model\n | { type: 'get_available_models'; id?: string }\n | { type: 'set_model'; id?: string; provider: string; modelId: string }\n // Thinking\n | { type: 'set_thinking_level'; id?: string; level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' }\n // Queue Mode\n | { type: 'set_queue_mode'; id?: string; mode: 'all' | 'one-at-a-time' }\n // Compaction\n | { type: 'compact'; id?: string; customInstructions?: string }\n | { type: 'set_auto_compaction'; id?: string; enabled: boolean }\n // Session\n | { type: 'get_session_stats'; id?: string }\n | { type: 'export_html'; id?: string; outputPath?: string }\n | { type: 'switch_session'; id?: string; sessionPath: string }\n // Messages\n | { type: 'get_messages'; id?: string }\n\ntype PiRpcResponse = {\n type: 'response'\n id?: string\n command: string\n success: boolean\n data?: unknown\n error?: string\n}\n\nexport type PiRpcEvent = Record<string, unknown>\n\ntype SpawnParams = {\n cwd: string\n /** Optional override for `pi` executable name/path */\n piCommand?: string\n /** If set, pi will persist the session to this exact file (via `--session <path>`). */\n sessionPath?: string\n}\n\nexport class PiRpcProcess {\n private readonly child: ChildProcessWithoutNullStreams\n private readonly pending = new Map<string, { resolve: (v: PiRpcResponse) => void; reject: (e: unknown) => void }>()\n private eventHandlers: Array<(ev: PiRpcEvent) => void> = []\n\n private constructor(child: ChildProcessWithoutNullStreams) {\n this.child = child\n\n const rl = readline.createInterface({ input: child.stdout })\n rl.on('line', line => {\n if (!line.trim()) return\n let msg: any\n try {\n msg = JSON.parse(line)\n } catch {\n // ignore malformed lines for now\n return\n }\n\n if (msg?.type === 'response') {\n const id = typeof msg.id === 'string' ? msg.id : undefined\n if (id) {\n const pending = this.pending.get(id)\n if (pending) {\n this.pending.delete(id)\n pending.resolve(msg as PiRpcResponse)\n return\n }\n }\n }\n\n for (const h of this.eventHandlers) h(msg as PiRpcEvent)\n })\n\n child.on('exit', (code, signal) => {\n const err = new Error(`pi process exited (code=${code}, signal=${signal})`)\n for (const [, p] of this.pending) p.reject(err)\n this.pending.clear()\n })\n }\n\n static async spawn(params: SpawnParams): Promise<PiRpcProcess> {\n const cmd = params.piCommand ?? 'pi'\n\n const args = ['--mode', 'rpc']\n if (params.sessionPath) args.push('--session', params.sessionPath)\n\n const child = spawn(cmd, args, {\n cwd: params.cwd,\n stdio: 'pipe',\n env: process.env\n })\n\n child.stderr.on('data', () => {\n // leave stderr untouched; ACP clients may capture it.\n })\n\n const proc = new PiRpcProcess(child)\n\n // Best-effort handshake.\n // Important: pi may emit a get_state response pointing at a sessionFile in a directory\n // that is created lazily. Create the parent dir up-front to avoid later parse errors\n // when we call commands like export_html.\n try {\n const state = (await proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n if (sessionFile) {\n const { mkdirSync } = await import('node:fs')\n const { dirname } = await import('node:path')\n mkdirSync(dirname(sessionFile), { recursive: true })\n }\n } catch {\n // ignore for now\n }\n\n return proc\n }\n\n onEvent(handler: (ev: PiRpcEvent) => void): () => void {\n this.eventHandlers.push(handler)\n return () => {\n this.eventHandlers = this.eventHandlers.filter(h => h !== handler)\n }\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<void> {\n const res = await this.request({ type: 'prompt', message, attachments })\n if (!res.success) throw new Error(`pi prompt failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async abort(): Promise<void> {\n const res = await this.request({ type: 'abort' })\n if (!res.success) throw new Error(`pi abort failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getState(): Promise<unknown> {\n const res = await this.request({ type: 'get_state' })\n if (!res.success) throw new Error(`pi get_state failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async getAvailableModels(): Promise<unknown> {\n const res = await this.request({ type: 'get_available_models' })\n if (!res.success) throw new Error(`pi get_available_models failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setModel(provider: string, modelId: string): Promise<unknown> {\n const res = await this.request({ type: 'set_model', provider, modelId })\n if (!res.success) throw new Error(`pi set_model failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setThinkingLevel(level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'): Promise<void> {\n const res = await this.request({ type: 'set_thinking_level', level })\n if (!res.success) throw new Error(`pi set_thinking_level failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async setQueueMode(mode: 'all' | 'one-at-a-time'): Promise<void> {\n const res = await this.request({ type: 'set_queue_mode', mode })\n if (!res.success) throw new Error(`pi set_queue_mode failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async compact(customInstructions?: string): Promise<unknown> {\n const res = await this.request({ type: 'compact', customInstructions })\n if (!res.success) throw new Error(`pi compact failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setAutoCompaction(enabled: boolean): Promise<void> {\n const res = await this.request({ type: 'set_auto_compaction', enabled })\n if (!res.success) throw new Error(`pi set_auto_compaction failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getSessionStats(): Promise<unknown> {\n const res = await this.request({ type: 'get_session_stats' })\n if (!res.success) throw new Error(`pi get_session_stats failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async exportHtml(outputPath?: string): Promise<{ path: string }> {\n const res = await this.request({ type: 'export_html', outputPath })\n if (!res.success) throw new Error(`pi export_html failed: ${res.error ?? JSON.stringify(res.data)}`)\n const data: any = res.data\n return { path: String(data?.path ?? '') }\n }\n\n async switchSession(sessionPath: string): Promise<void> {\n const res = await this.request({ type: 'switch_session', sessionPath })\n if (!res.success) throw new Error(`pi switch_session failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getMessages(): Promise<unknown> {\n const res = await this.request({ type: 'get_messages' })\n if (!res.success) throw new Error(`pi get_messages failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n private request(cmd: PiRpcCommand): Promise<PiRpcResponse> {\n const id = crypto.randomUUID()\n const withId = { ...cmd, id }\n\n const line = JSON.stringify(withId) + '\\n'\n\n return new Promise<PiRpcResponse>((resolve, reject) => {\n this.pending.set(id, { resolve, reject })\n this.child.stdin.write(line, err => {\n if (err) {\n this.pending.delete(id)\n reject(err)\n }\n })\n })\n }\n}\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { getPiAcpSessionMapPath } from './paths.js'\n\nexport type StoredSession = {\n sessionId: string\n cwd: string\n sessionFile: string\n updatedAt: string\n}\n\ntype SessionMapFile = {\n version: 1\n sessions: Record<string, StoredSession>\n}\n\nfunction ensureParentDir(path: string) {\n mkdirSync(dirname(path), { recursive: true })\n}\n\nfunction loadFile(path: string): SessionMapFile {\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as SessionMapFile\n if (parsed?.version !== 1 || typeof parsed.sessions !== 'object' || !parsed.sessions) {\n return { version: 1, sessions: {} }\n }\n return parsed\n } catch {\n return { version: 1, sessions: {} }\n }\n}\n\nfunction saveFile(path: string, data: SessionMapFile): void {\n ensureParentDir(path)\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n', 'utf-8')\n}\n\nexport class SessionStore {\n private readonly path: string\n\n constructor(path = getPiAcpSessionMapPath()) {\n this.path = path\n }\n\n get(sessionId: string): StoredSession | null {\n const db = loadFile(this.path)\n return db.sessions[sessionId] ?? null\n }\n\n upsert(entry: { sessionId: string; cwd: string; sessionFile: string }): void {\n const db = loadFile(this.path)\n db.sessions[entry.sessionId] = {\n sessionId: entry.sessionId,\n cwd: entry.cwd,\n sessionFile: entry.sessionFile,\n updatedAt: new Date().toISOString()\n }\n saveFile(this.path, db)\n }\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n/**\n * Storage owned by the ACP adapter.\n *\n * We intentionally keep this separate from pi's own ~/.pi/agent/* directory.\n */\nexport function getPiAcpDir(): string {\n return join(homedir(), '.pi', 'pi-acp')\n}\n\nexport function getPiAcpSessionMapPath(): string {\n return join(getPiAcpDir(), 'session-map.json')\n}\n","export function toolResultToText(result: unknown): string {\n if (!result) return ''\n\n // pi tool results generally look like: { content: [{type:\"text\", text:\"...\"}], details: {...} }\n const content = (result as any).content\n if (Array.isArray(content)) {\n const texts = content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n if (texts.length) return texts.join('')\n }\n\n const details = (result as any)?.details\n\n // Some pi tools return a unified diff in `details.diff`.\n const diff = details?.diff\n if (typeof diff === 'string' && diff.trim()) {\n return diff\n }\n\n // The bash tool frequently returns stdout/stderr in `details` rather than content blocks.\n const stdout =\n (typeof details?.stdout === 'string' ? details.stdout : undefined) ??\n (typeof (result as any)?.stdout === 'string' ? (result as any).stdout : undefined) ??\n (typeof details?.output === 'string' ? details.output : undefined) ??\n (typeof (result as any)?.output === 'string' ? (result as any).output : undefined)\n\n const stderr =\n (typeof details?.stderr === 'string' ? details.stderr : undefined) ??\n (typeof (result as any)?.stderr === 'string' ? (result as any).stderr : undefined)\n\n const exitCode =\n (typeof details?.exitCode === 'number' ? details.exitCode : undefined) ??\n (typeof (result as any)?.exitCode === 'number' ? (result as any).exitCode : undefined) ??\n (typeof details?.code === 'number' ? details.code : undefined) ??\n (typeof (result as any)?.code === 'number' ? (result as any).code : undefined)\n\n if ((typeof stdout === 'string' && stdout.trim()) || (typeof stderr === 'string' && stderr.trim())) {\n const parts: string[] = []\n if (typeof stdout === 'string' && stdout.trim()) parts.push(stdout)\n if (typeof stderr === 'string' && stderr.trim()) parts.push(`stderr:\\n${stderr}`)\n if (typeof exitCode === 'number') parts.push(`exit code: ${exitCode}`)\n return parts.join('\\n\\n').trimEnd()\n }\n\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, resolve } from 'node:path'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\n\n/**\n * File-based slash command (mirrors pi-coding-agent semantics).\n */\nexport type FileSlashCommand = {\n name: string\n description: string\n content: string\n source: string // e.g. \"(user)\", \"(project)\", \"(project:frontend)\"\n}\n\nfunction parseFrontmatter(content: string): {\n frontmatter: Record<string, string>\n content: string\n} {\n const frontmatter: Record<string, string> = {}\n\n if (!content.startsWith('---')) return { frontmatter, content }\n\n const endIndex = content.indexOf('\\n---', 3)\n if (endIndex === -1) return { frontmatter, content }\n\n const frontmatterBlock = content.slice(4, endIndex)\n const remaining = content.slice(endIndex + 4).trim()\n\n for (const line of frontmatterBlock.split('\\n')) {\n const match = line.match(/^(\\w+):\\s*(.*)$/)\n if (match) frontmatter[match[1]] = match[2].trim()\n }\n\n return { frontmatter, content: remaining }\n}\n\nfunction loadCommandsFromDir(dir: string, source: 'user' | 'project', subdir = ''): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n if (!existsSync(dir)) return commands\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n\n if (entry.isDirectory()) {\n const newSubdir = subdir ? `${subdir}:${entry.name}` : entry.name\n commands.push(...loadCommandsFromDir(fullPath, source, newSubdir))\n continue\n }\n\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue\n\n try {\n const rawContent = readFileSync(fullPath, 'utf-8')\n const { frontmatter, content } = parseFrontmatter(rawContent)\n\n const name = entry.name.slice(0, -3)\n\n const sourceStr =\n source === 'user' ? (subdir ? `(user:${subdir})` : '(user)') : subdir ? `(project:${subdir})` : '(project)'\n\n let description = frontmatter.description || ''\n if (!description) {\n const firstLine = content.split('\\n').find(l => l.trim())\n if (firstLine) {\n description = firstLine.slice(0, 60)\n if (firstLine.length > 60) description += '...'\n }\n }\n\n description = description ? `${description} ${sourceStr}` : sourceStr\n\n commands.push({\n name,\n description,\n content,\n source: sourceStr\n })\n } catch {\n // Silently skip unreadable files.\n }\n }\n } catch {\n // Silently skip unreadable dirs.\n }\n\n return commands\n}\n\n/**\n * Load slash commands from:\n * - user: ~/.pi/agent/commands/**\\/*.md\n * - project: <cwd>/.pi/commands/**\\/*.md\n */\nexport function loadSlashCommands(cwd: string): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n\n const userDir = join(homedir(), '.pi', 'agent', 'commands')\n const projectDir = resolve(cwd, '.pi', 'commands')\n\n // Match pi ordering: user first, then project.\n commands.push(...loadCommandsFromDir(userDir, 'user'))\n commands.push(...loadCommandsFromDir(projectDir, 'project'))\n\n return commands\n}\n\n/**\n * Convert file-based commands to ACP AvailableCommand objects.\n * De-dupes by name (first wins).\n */\nexport function toAvailableCommands(fileCommands: FileSlashCommand[]): AvailableCommand[] {\n const seen = new Set<string>()\n const out: AvailableCommand[] = []\n\n for (const c of fileCommands) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n\n out.push({\n name: c.name,\n description: c.description\n // input: omitted for now (pi commands don't specify this)\n })\n }\n\n return out\n}\n\n/**\n * Parse command args (bash-style quotes).\n */\nexport function parseCommandArgs(argsString: string): string[] {\n const args: string[] = []\n let current = ''\n let inQuote: string | null = null\n\n for (let i = 0; i < argsString.length; i++) {\n const ch = argsString[i]\n\n if (inQuote) {\n if (ch === inQuote) inQuote = null\n else current += ch\n continue\n }\n\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch\n } else if (ch === ' ' || ch === '\\t') {\n if (current) {\n args.push(current)\n current = ''\n }\n } else {\n current += ch\n }\n }\n\n if (current) args.push(current)\n return args\n}\n\n/**\n * Substitute $1, $2, ... and $@.\n */\nexport function substituteArgs(content: string, args: string[]): string {\n let result = content\n\n result = result.replace(/\\$@/g, args.join(' '))\n result = result.replace(/\\$(\\d+)/g, (_m, num) => {\n const idx = Number.parseInt(String(num), 10) - 1\n return args[idx] ?? ''\n })\n\n return result\n}\n\n/**\n * Expand a leading /command using the loaded file commands.\n * Returns original text if it's not a known slash command.\n */\nexport function expandSlashCommand(text: string, fileCommands: FileSlashCommand[]): string {\n if (!text.startsWith('/')) return text\n\n const spaceIndex = text.indexOf(' ')\n const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex)\n const argsString = spaceIndex === -1 ? '' : text.slice(spaceIndex + 1)\n\n const cmd = fileCommands.find(c => c.name === commandName)\n if (!cmd) return text\n\n const args = parseCommandArgs(argsString)\n return substituteArgs(cmd.content, args)\n}\n","export function normalizePiMessageText(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n\nexport function normalizePiAssistantText(content: unknown): string {\n // Assistant content is typically an array of blocks; only replay text blocks for MVP.\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n","import type { ContentBlock } from '@agentclientprotocol/sdk'\n\nexport type PiAttachment = {\n id: string\n type: 'image' | 'document'\n fileName: string\n mimeType: string\n size: number\n content: string\n extractedText?: string\n preview?: string\n}\n\nexport function guessFileNameFromMime(mimeType: string): string {\n const ext =\n mimeType === 'image/png' ? 'png' : mimeType === 'image/jpeg' ? 'jpg' : mimeType === 'image/webp' ? 'webp' : 'bin'\n return `attachment.${ext}`\n}\n\nexport function promptToPiMessage(blocks: ContentBlock[]): {\n message: string\n attachments: PiAttachment[]\n} {\n let message = ''\n const attachments: PiAttachment[] = []\n\n for (const b of blocks) {\n switch (b.type) {\n case 'text':\n message += b.text\n break\n\n case 'resource_link':\n // A lightweight, human-readable hint for the LLM.\n message += `\\n[Context] ${b.uri}`\n break\n\n case 'image': {\n const id = b.uri ?? crypto.randomUUID()\n // pi expects base64 without data-url prefix.\n const size = Buffer.byteLength(b.data, 'base64')\n attachments.push({\n id,\n type: 'image',\n fileName: guessFileNameFromMime(b.mimeType),\n mimeType: b.mimeType,\n size,\n content: b.data\n })\n break\n }\n\n case 'resource': {\n // Clients should not send this if embeddedContext=false, but be resilient.\n const r: any = (b as any).resource\n const uri = typeof r?.uri === 'string' ? r.uri : '(unknown)'\n\n if (typeof r?.text === 'string') {\n // TextResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'text/plain'\n message += `\\n[Embedded Context] ${uri} (${mime})\\n${r.text}`\n } else if (typeof r?.blob === 'string') {\n // BlobResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'application/octet-stream'\n const bytes = Buffer.byteLength(r.blob, 'base64')\n message += `\\n[Embedded Context] ${uri} (${mime}, ${bytes} bytes)`\n } else {\n message += `\\n[Embedded Context] ${uri}`\n }\n break\n }\n\n case 'audio': {\n // Not supported by pi. Provide a marker so we don't silently drop context.\n const bytes = Buffer.byteLength(b.data, 'base64')\n message += `\\n[Audio] (${b.mimeType}, ${bytes} bytes) not supported by pi-acp`\n break\n }\n\n default:\n // Ignore unknown block types for now.\n break\n }\n }\n\n return { message, attachments }\n}\n"],"mappings":"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","names":["RequestError","readFileSync","mkdirSync","dirname","resolve","readFileSync","homedir","join","resolve","readFileSync","isAbsolute","existsSync","readFileSync","join","dirname","RequestError","result","resolve"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-acp",
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "ACP adapter for pi coding agent",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"pi-acp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "tsx src/index.ts",
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"lint": "eslint .",
|
|
20
|
+
"test": "node --import tsx --test test/**/*.test.ts",
|
|
21
|
+
"smoke": "node scripts/smoke-acp.mjs"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@agentclientprotocol/sdk": "^0.12.0",
|
|
25
|
+
"zod": "^3.25.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@eslint/js": "^9.17.0",
|
|
29
|
+
"@types/node": "^22.0.0",
|
|
30
|
+
"eslint": "^9.17.0",
|
|
31
|
+
"globals": "^15.14.0",
|
|
32
|
+
"tsup": "^8.0.0",
|
|
33
|
+
"tsx": "^4.0.0",
|
|
34
|
+
"typescript": "^5.6.0",
|
|
35
|
+
"typescript-eslint": "^8.18.0"
|
|
36
|
+
}
|
|
37
|
+
}
|