droid-acp 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp-agent-Ddz1S3Jm.mjs","names":["process: ChildProcess | null","sessionId: string | null","notificationHandlers: Array<(n: DroidNotification) => void | Promise<void>>","rawEventHandlers: Array<(e: unknown) => void | Promise<void>>","exitHandlers: Array<(code: number | null) => void>","requestHandler: ((method: string, params: unknown) => Promise<PermissionResponse>) | null","initResolve: ((result: InitSessionResult) => void) | null","initReject: ((error: Error) => void) | null","pendingIdleTimer: NodeJS.Timeout | null","process","msg: FactoryRequest","processingChain: Promise<void>","error: unknown","params: Record<string, unknown>","ACP_MODES: AcpModeId[]","ACP_MODE_TO_DROID_AUTONOMY: Record<AcpModeId, DroidAutonomyLevel>","initialMode: AcpModeId","session: Session","textParts: string[]","images: Array<{ type: \"base64\"; data: string; mediaType: string }>","candidates: unknown[]","entries: Array<{\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n priority: \"medium\";\n }>","explicitChoices: Array<{ id: string; title: string }>","looseChoices: Array<{ id: string; title: string }>","id","title","acpOptions: PermissionOption[]","autoDecision: string | null","selectedOption","isExitSpecMode","status","permission: Awaited<ReturnType<AgentSideConnection[\"requestPermission\"]>>"],"sources":["../src/utils.ts","../src/droid-adapter.ts","../src/types.ts","../src/acp-agent.ts"],"sourcesContent":["import { Readable, Writable } from \"node:stream\";\nimport { WritableStream, ReadableStream } from \"node:stream/web\";\n\nexport interface Logger {\n log: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\nexport class Pushable<T> implements AsyncIterable<T> {\n private queue: T[] = [];\n private resolvers: ((value: IteratorResult<T>) => void)[] = [];\n private done = false;\n\n push(item: T) {\n if (this.resolvers.length > 0) {\n const resolve = this.resolvers.shift()!;\n resolve({ value: item, done: false });\n } else {\n this.queue.push(item);\n }\n }\n\n end() {\n this.done = true;\n while (this.resolvers.length > 0) {\n const resolve = this.resolvers.shift()!;\n resolve({ value: undefined as T, done: true });\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n if (this.queue.length > 0) {\n const value = this.queue.shift()!;\n return Promise.resolve({ value, done: false });\n }\n if (this.done) {\n return Promise.resolve({ value: undefined as T, done: true });\n }\n return new Promise<IteratorResult<T>>((resolve) => {\n this.resolvers.push(resolve);\n });\n },\n };\n }\n}\n\nexport function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array> {\n return new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n nodeStream.write(Buffer.from(chunk), (err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n },\n });\n}\n\nexport function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n nodeStream.on(\"data\", (chunk: Buffer) => {\n controller.enqueue(new Uint8Array(chunk));\n });\n nodeStream.on(\"end\", () => controller.close());\n nodeStream.on(\"error\", (err) => controller.error(err));\n },\n });\n}\n\nexport function unreachable(value: never, logger: Logger = console) {\n let valueAsString;\n try {\n valueAsString = JSON.stringify(value);\n } catch {\n valueAsString = value;\n }\n logger.error(`Unexpected case: ${valueAsString}`);\n}\n\nexport function sleep(time: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, time));\n}\n\n/** Check if running on Windows */\nexport const isWindows = process.platform === \"win32\";\n\n/**\n * Find the droid executable path.\n * Uses DROID_EXECUTABLE env var if set, otherwise defaults to \"droid\".\n * On Windows, also checks for \"droid.exe\" if not explicitly set.\n */\nexport function findDroidExecutable(): string {\n if (process.env.DROID_EXECUTABLE) {\n return process.env.DROID_EXECUTABLE;\n }\n // On Windows, the executable might be droid.exe, but shell: true handles this\n return \"droid\";\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport { randomUUID } from \"node:crypto\";\nimport { findDroidExecutable, isWindows, type Logger } from \"./utils.ts\";\nimport type {\n DroidAutonomyLevel,\n DroidNotification,\n FactoryRequest,\n FactoryMessage,\n InitSessionResult,\n PermissionResponse,\n} from \"./types.ts\";\n\nexport interface DroidAdapterOptions {\n cwd: string;\n logger?: Logger;\n}\n\nexport interface DroidAdapter {\n start(): Promise<InitSessionResult>;\n sendMessage(text: string): void;\n sendUserMessage(message: {\n text: string;\n images?: Array<{ type: \"base64\"; data: string; mediaType: string }>;\n }): void;\n setMode(level: DroidAutonomyLevel): void;\n setModel(modelId: string): void;\n onNotification(handler: (notification: DroidNotification) => void | Promise<void>): void;\n onRawEvent(handler: (event: unknown) => void | Promise<void>): void;\n onRequest(handler: (method: string, params: unknown) => Promise<PermissionResponse>): void;\n onExit(handler: (code: number | null) => void): void;\n stop(): Promise<void>;\n isRunning(): boolean;\n getSessionId(): string | null;\n}\n\nexport function createDroidAdapter(options: DroidAdapterOptions): DroidAdapter {\n let process: ChildProcess | null = null;\n let sessionId: string | null = null;\n const machineId = randomUUID();\n const logger = options.logger ?? console;\n\n const notificationHandlers: Array<(n: DroidNotification) => void | Promise<void>> = [];\n const rawEventHandlers: Array<(e: unknown) => void | Promise<void>> = [];\n const exitHandlers: Array<(code: number | null) => void> = [];\n let requestHandler: ((method: string, params: unknown) => Promise<PermissionResponse>) | null =\n null;\n\n let initResolve: ((result: InitSessionResult) => void) | null = null;\n let initReject: ((error: Error) => void) | null = null;\n\n // State for message ordering (handle out-of-order idle notification)\n let isStreamingAssistant = false;\n let pendingIdle = false;\n let pendingIdleTimer: NodeJS.Timeout | null = null;\n\n const send = (method: string, params: Record<string, unknown>) => {\n if (!process?.stdin?.writable) return;\n const msg: FactoryRequest = {\n jsonrpc: \"2.0\",\n factoryApiVersion: \"1.0.0\",\n type: \"request\",\n method,\n params,\n id: randomUUID(),\n };\n process.stdin.write(JSON.stringify(msg) + \"\\n\");\n logger.log(\"Sent:\", method);\n };\n\n const emit = async (n: DroidNotification) => {\n for (const h of notificationHandlers) {\n await h(n);\n }\n };\n\n // Process queue sequentially using promise chain\n let processingChain: Promise<void> = Promise.resolve();\n\n const queueLine = (line: string) => {\n processingChain = processingChain.then(() => handleLine(line));\n };\n\n const handleLine = async (line: string) => {\n try {\n const msg = JSON.parse(line) as FactoryMessage;\n\n // Emit raw event for debugging\n for (const h of rawEventHandlers) {\n await h(msg);\n }\n\n // Handle init response\n if (\n msg.type === \"response\" &&\n \"result\" in msg &&\n msg.result &&\n \"sessionId\" in msg.result &&\n initResolve\n ) {\n const r = msg.result as unknown as InitSessionResult;\n sessionId = r.sessionId;\n initResolve({\n sessionId: r.sessionId,\n session: r.session,\n settings: r.settings,\n availableModels: r.availableModels || [],\n });\n initResolve = null;\n initReject = null;\n return;\n }\n\n // Handle error response\n if (msg.type === \"response\" && \"error\" in msg && msg.error && initReject) {\n initReject(new Error(msg.error.message));\n initResolve = null;\n initReject = null;\n return;\n }\n\n // Handle notifications\n if (msg.type === \"notification\" && msg.method === \"droid.session_notification\") {\n const notification = (msg.params as { notification?: Record<string, unknown> })\n ?.notification;\n if (!notification) return;\n\n const notificationType = notification.type as string;\n\n switch (notificationType) {\n case \"settings_updated\": {\n const settings = notification.settings as Record<string, unknown> | undefined;\n if (settings) {\n await emit({\n type: \"settings_updated\",\n settings: {\n modelId: typeof settings.modelId === \"string\" ? settings.modelId : undefined,\n reasoningEffort:\n typeof settings.reasoningEffort === \"string\"\n ? settings.reasoningEffort\n : undefined,\n autonomyLevel:\n typeof settings.autonomyLevel === \"string\" ? settings.autonomyLevel : undefined,\n specModeModelId:\n typeof settings.specModeModelId === \"string\"\n ? settings.specModeModelId\n : undefined,\n specModeReasoningEffort:\n typeof settings.specModeReasoningEffort === \"string\"\n ? settings.specModeReasoningEffort\n : undefined,\n },\n });\n }\n break;\n }\n\n case \"droid_working_state_changed\": {\n const newState = notification.newState as string;\n await emit({\n type: \"working_state\",\n state: newState as \"idle\" | \"streaming_assistant_message\",\n });\n\n if (newState === \"streaming_assistant_message\") {\n isStreamingAssistant = true;\n pendingIdle = false;\n if (pendingIdleTimer) {\n clearTimeout(pendingIdleTimer);\n pendingIdleTimer = null;\n }\n } else if (newState === \"idle\") {\n // Handle out-of-order idle notification\n // Droid CLI sometimes sends idle before the final assistant message\n if (isStreamingAssistant) {\n pendingIdle = true;\n\n // Droid can also transition through streaming→idle without emitting a final\n // assistant create_message (e.g. after rejecting ExitSpecMode). In that case,\n // ensure we still complete the prompt after a short grace period.\n if (pendingIdleTimer) {\n clearTimeout(pendingIdleTimer);\n }\n pendingIdleTimer = setTimeout(() => {\n if (!pendingIdle) return;\n pendingIdle = false;\n isStreamingAssistant = false;\n pendingIdleTimer = null;\n void emit({ type: \"complete\" });\n }, 250);\n } else {\n await emit({ type: \"complete\" });\n }\n }\n break;\n }\n\n case \"create_message\": {\n const message = notification.message as {\n role: string;\n id: string;\n content?: Array<{\n type: string;\n text?: string;\n id?: string;\n toolUseId?: string;\n tool_use_id?: string;\n tool_call_id?: string;\n callId?: string;\n call_id?: string;\n name?: string;\n toolName?: string;\n tool_name?: string;\n input?: unknown;\n }>;\n };\n if (message) {\n const blocks = Array.isArray(message.content) ? message.content : [];\n\n const textParts = blocks\n .filter((c) => c.type === \"text\" && typeof c.text === \"string\")\n .map((c) => c.text as string);\n\n if (textParts.length > 0) {\n await emit({\n type: \"message\",\n role: message.role as \"user\" | \"assistant\" | \"system\",\n text: textParts.join(\"\"),\n id: message.id,\n });\n }\n\n const toolUses = blocks.filter((c) => c.type === \"tool_use\");\n for (const toolUseContent of toolUses) {\n const id =\n toolUseContent.id ??\n toolUseContent.toolUseId ??\n toolUseContent.tool_use_id ??\n toolUseContent.tool_call_id ??\n toolUseContent.callId ??\n toolUseContent.call_id ??\n randomUUID();\n const name =\n toolUseContent.name ?? toolUseContent.toolName ?? toolUseContent.tool_name;\n await emit({\n type: \"message\",\n role: message.role as \"user\" | \"assistant\" | \"system\",\n id: message.id,\n toolUse: {\n id,\n name: name || \"unknown\",\n input: toolUseContent.input,\n },\n });\n }\n\n // If we were waiting for this assistant message, now complete\n if (message.role === \"assistant\") {\n isStreamingAssistant = false;\n if (pendingIdleTimer) {\n clearTimeout(pendingIdleTimer);\n pendingIdleTimer = null;\n }\n if (pendingIdle) {\n await emit({ type: \"complete\" });\n pendingIdle = false;\n }\n }\n }\n break;\n }\n\n case \"tool_result\": {\n const toolUseIdRaw =\n (notification as Record<string, unknown>).toolUseId ??\n (notification as Record<string, unknown>).tool_use_id ??\n (notification as Record<string, unknown>).tool_call_id ??\n (notification as Record<string, unknown>).callId ??\n (notification as Record<string, unknown>).call_id ??\n (notification as Record<string, unknown>).id;\n const toolUseId = typeof toolUseIdRaw === \"string\" ? toolUseIdRaw : null;\n\n const rawContent =\n (notification as Record<string, unknown>).content ??\n (notification as Record<string, unknown>).value;\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : JSON.stringify(rawContent ?? \"\", null, 2);\n\n const isErrorRaw =\n (notification as Record<string, unknown>).isError ??\n (notification as Record<string, unknown>).is_error;\n const isError = typeof isErrorRaw === \"boolean\" ? isErrorRaw : false;\n\n if (!toolUseId) {\n logger.error(\"Missing tool_use_id/toolUseId for tool_result notification\");\n break;\n }\n await emit({\n type: \"tool_result\",\n toolUseId,\n content,\n isError,\n });\n break;\n }\n\n case \"error\": {\n isStreamingAssistant = false;\n pendingIdle = false;\n const message =\n typeof notification.message === \"string\"\n ? (notification.message as string)\n : JSON.stringify(notification.message ?? \"Unknown error\");\n await emit({ type: \"error\", message });\n break;\n }\n }\n }\n\n // Handle incoming requests (like permissions)\n if (msg.type === \"request\") {\n const requestId = msg.id;\n const method = msg.method;\n const params = msg.params;\n\n if (requestHandler && method === \"droid.request_permission\") {\n try {\n const result = await requestHandler(method, params);\n const response = {\n jsonrpc: \"2.0\" as const,\n factoryApiVersion: \"1.0.0\" as const,\n type: \"response\" as const,\n id: requestId,\n result,\n };\n if (process?.stdin) {\n process.stdin.write(JSON.stringify(response) + \"\\n\");\n }\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : \"Internal error\";\n const response = {\n jsonrpc: \"2.0\" as const,\n factoryApiVersion: \"1.0.0\" as const,\n type: \"response\" as const,\n id: requestId,\n error: {\n code: -32603,\n message: errorMessage,\n },\n };\n if (process?.stdin) {\n process.stdin.write(JSON.stringify(response) + \"\\n\");\n }\n }\n } else if (method === \"droid.request_permission\") {\n // Auto-approve as fallback if no handler\n const response = {\n jsonrpc: \"2.0\" as const,\n factoryApiVersion: \"1.0.0\" as const,\n type: \"response\" as const,\n id: requestId,\n result: { selectedOption: \"proceed_once\" },\n };\n if (process?.stdin) {\n process.stdin.write(JSON.stringify(response) + \"\\n\");\n }\n logger.log(\"Auto-approved permission request (fallback):\", requestId);\n }\n }\n } catch (err) {\n logger.error(\"Parse error:\", (err as Error).message);\n }\n };\n\n return {\n async start(): Promise<InitSessionResult> {\n const executable = findDroidExecutable();\n const args = [\n \"exec\",\n \"--input-format\",\n \"stream-jsonrpc\",\n \"--output-format\",\n \"stream-jsonrpc\",\n \"--cwd\",\n options.cwd,\n ];\n\n logger.log(\"Starting droid:\", executable, args.join(\" \"));\n process = spawn(executable, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: {\n ...globalThis.process.env,\n FORCE_COLOR: \"0\",\n },\n // Windows compatibility\n shell: isWindows,\n windowsHide: true,\n });\n\n if (process.stdout) {\n createInterface({ input: process.stdout }).on(\"line\", queueLine);\n }\n if (process.stderr) {\n createInterface({ input: process.stderr }).on(\"line\", (l) =>\n logger.error(\"[droid stderr]\", l),\n );\n }\n\n process.on(\"error\", (err) => {\n if (initReject) initReject(err);\n });\n process.on(\"exit\", (code) => {\n logger.log(\"Droid exit:\", code);\n process = null;\n exitHandlers.forEach((h) => h(code));\n });\n\n return new Promise((resolve, reject) => {\n initResolve = resolve;\n initReject = reject;\n send(\"droid.initialize_session\", { machineId, cwd: options.cwd });\n\n const initTimeout = parseInt(globalThis.process.env.DROID_INIT_TIMEOUT || \"60000\", 10);\n setTimeout(() => {\n if (initReject) {\n initReject(new Error(\"Droid init timeout\"));\n initResolve = null;\n initReject = null;\n }\n }, initTimeout);\n });\n },\n\n sendMessage(text: string) {\n this.sendUserMessage({ text });\n },\n\n sendUserMessage(message: {\n text: string;\n images?: Array<{ type: \"base64\"; data: string; mediaType: string }>;\n }) {\n if (!sessionId) return;\n const params: Record<string, unknown> = {\n sessionId,\n text: message.text,\n };\n if (Array.isArray(message.images) && message.images.length > 0) {\n params.images = message.images;\n }\n send(\"droid.add_user_message\", params);\n },\n\n setMode(level: DroidAutonomyLevel) {\n if (!sessionId) return;\n send(\"droid.update_session_settings\", {\n sessionId,\n autonomyLevel: level,\n });\n },\n\n setModel(modelId: string) {\n if (!sessionId) return;\n send(\"droid.update_session_settings\", {\n sessionId,\n modelId,\n });\n },\n\n onNotification(handler) {\n notificationHandlers.push(handler);\n },\n\n onRawEvent(handler) {\n rawEventHandlers.push(handler);\n },\n\n onRequest(handler) {\n requestHandler = handler;\n },\n\n onExit(handler) {\n exitHandlers.push(handler);\n },\n\n async stop() {\n if (process) {\n process.stdin?.end();\n process.kill(\"SIGTERM\");\n process = null;\n }\n },\n\n isRunning() {\n return process !== null && !process.killed;\n },\n\n getSessionId() {\n return sessionId;\n },\n };\n}\n","/**\n * Factory API types for stream-jsonrpc protocol\n */\n\n// ACP mode ids exposed to the client (Zed).\nexport type AcpModeId = \"off\" | \"low\" | \"medium\" | \"high\" | \"spec\";\nexport const ACP_MODES: AcpModeId[] = [\"off\", \"low\", \"medium\", \"high\", \"spec\"];\n\n// Droid `autonomyLevel` values (see Factory docs: Settings → autonomyLevel).\nexport type DroidAutonomyLevel =\n | \"normal\"\n | \"spec\"\n | \"auto-low\"\n | \"auto-medium\"\n | \"auto-high\"\n // legacy values (keep for compatibility with older CLIs)\n | \"suggest\"\n | \"full\";\n\nexport interface FactoryRequest {\n jsonrpc: \"2.0\";\n factoryApiVersion: \"1.0.0\";\n type: \"request\";\n method: string;\n params: Record<string, unknown>;\n id: string;\n}\n\nexport interface FactoryResponse {\n jsonrpc: \"2.0\";\n type: \"response\";\n factoryApiVersion: \"1.0.0\";\n id: string;\n result?: Record<string, unknown>;\n error?: {\n code: number;\n message: string;\n };\n}\n\nexport interface FactoryNotification {\n jsonrpc: \"2.0\";\n type: \"notification\";\n factoryApiVersion: \"1.0.0\";\n method: string;\n params: Record<string, unknown>;\n}\n\nexport type FactoryMessage = FactoryRequest | FactoryResponse | FactoryNotification;\n\nexport interface AvailableModel {\n id: string;\n modelId?: string;\n modelProvider: string;\n displayName: string;\n shortDisplayName?: string;\n supportedReasoningEfforts: string[];\n defaultReasoningEffort: string;\n isCustom: boolean;\n noImageSupport?: boolean;\n}\n\nexport interface InitSessionResult {\n sessionId: string;\n session?: { messages: unknown[] };\n settings?: {\n modelId: string;\n reasoningEffort?: string;\n autonomyLevel?: string;\n };\n availableModels: AvailableModel[];\n}\n\nexport type DroidNotification =\n | { type: \"working_state\"; state: \"idle\" | \"streaming_assistant_message\" }\n | {\n type: \"settings_updated\";\n settings: {\n modelId?: string;\n reasoningEffort?: string;\n autonomyLevel?: string;\n specModeModelId?: string;\n specModeReasoningEffort?: string;\n };\n }\n | { type: \"tool_result\"; toolUseId: string; content: string; isError: boolean }\n | {\n type: \"message\";\n role: \"user\" | \"assistant\" | \"system\";\n text?: string;\n id: string;\n toolUse?: { id: string; name: string; input?: unknown };\n }\n | { type: \"error\"; message: string }\n | { type: \"complete\" };\n\nexport interface DroidPermissionOption {\n value: string;\n label: string;\n}\n\nexport interface PermissionRequest {\n toolUses?: Array<{\n toolUse: {\n id: string;\n name: string;\n input?: {\n command?: string;\n riskLevel?: \"low\" | \"medium\" | \"high\";\n [key: string]: unknown;\n };\n };\n confirmationType?: string;\n details?: unknown;\n }>;\n options?: DroidPermissionOption[];\n}\n\nexport interface PermissionResponse {\n selectedOption: string;\n}\n","import {\n type Agent,\n AgentSideConnection,\n type AuthenticateRequest,\n type AuthenticateResponse,\n type AvailableCommand,\n type InitializeRequest,\n type InitializeResponse,\n type NewSessionRequest,\n type NewSessionResponse,\n type PromptRequest,\n type PromptResponse,\n type CancelNotification,\n type SetSessionModelRequest,\n type SetSessionModelResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type PermissionOption,\n ndJsonStream,\n} from \"@agentclientprotocol/sdk\";\nimport { createDroidAdapter, type DroidAdapter } from \"./droid-adapter.ts\";\nimport {\n ACP_MODES,\n type AcpModeId,\n type DroidAutonomyLevel,\n type DroidNotification,\n type DroidPermissionOption,\n type PermissionRequest,\n} from \"./types.ts\";\nimport { type Logger, nodeToWebReadable, nodeToWebWritable } from \"./utils.ts\";\n\nconst packageJson = { name: \"droid-acp\", version: \"0.1.0\" };\n\nfunction normalizeBase64DataUrl(\n data: string,\n fallbackMimeType: string,\n): { mimeType: string; base64: string } {\n const trimmed = data.trim();\n const match = trimmed.match(/^data:([^;,]+);base64,(.*)$/s);\n if (match) {\n const mimeType = match[1]?.trim() || fallbackMimeType;\n const base64 = match[2]?.trim().replace(/\\s+/g, \"\");\n return { mimeType, base64 };\n }\n\n return { mimeType: fallbackMimeType, base64: trimmed.replace(/\\s+/g, \"\") };\n}\n\n// Available slash commands for ACP adapter\n// Note: Only commands that can be implemented via Droid's JSON-RPC API are supported.\n// CLI-only commands (clear, compact, sessions, etc.) don't have API equivalents.\nfunction getAvailableCommands(): AvailableCommand[] {\n return [\n {\n name: \"help\",\n description: \"Show available slash commands\",\n input: null,\n },\n {\n name: \"model\",\n description: \"Show or change the current model\",\n input: { hint: \"[model_id]\" },\n },\n {\n name: \"mode\",\n description: \"Show or change the autonomy mode (off|low|medium|high|spec)\",\n input: { hint: \"[mode]\" },\n },\n {\n name: \"config\",\n description: \"Show current session configuration\",\n input: null,\n },\n {\n name: \"status\",\n description: \"Show current session status\",\n input: null,\n },\n ];\n}\n\ninterface Session {\n id: string;\n droid: DroidAdapter;\n droidSessionId: string;\n model: string;\n mode: AcpModeId;\n cancelled: boolean;\n promptResolve: ((result: PromptResponse) => void) | null;\n activeToolCallIds: Set<string>;\n toolCallStatus: Map<string, \"pending\" | \"in_progress\" | \"completed\" | \"failed\">;\n toolNames: Map<string, string>;\n availableModels: Array<{ id: string; displayName: string }>;\n cwd: string;\n specChoice: string | null;\n specChoicePromptSignature: string | null;\n specPlanDetailsSignature: string | null;\n specPlanDetailsToolCallId: string | null;\n}\n\nconst ACP_MODE_TO_DROID_AUTONOMY: Record<AcpModeId, DroidAutonomyLevel> = {\n off: \"normal\",\n low: \"auto-low\",\n medium: \"auto-medium\",\n high: \"auto-high\",\n spec: \"spec\",\n};\n\nfunction droidAutonomyToAcpModeId(value: string): AcpModeId | null {\n switch (value) {\n case \"normal\":\n return \"off\";\n case \"auto-low\":\n return \"low\";\n case \"auto-medium\":\n return \"medium\";\n case \"auto-high\":\n return \"high\";\n case \"spec\":\n return \"spec\";\n // legacy values\n case \"suggest\":\n return \"low\";\n case \"full\":\n return \"high\";\n default:\n return null;\n }\n}\n\nexport class DroidAcpAgent implements Agent {\n private sessions: Map<string, Session> = new Map();\n private client: AgentSideConnection;\n private logger: Logger;\n\n constructor(client: AgentSideConnection, logger?: Logger) {\n this.client = client;\n this.logger = logger ?? console;\n this.logger.log(\"DroidAcpAgent initialized\");\n }\n\n async initialize(_request: InitializeRequest): Promise<InitializeResponse> {\n this.logger.log(\"initialize\");\n return {\n protocolVersion: 1,\n agentCapabilities: {\n promptCapabilities: { image: true, embeddedContext: true },\n },\n agentInfo: {\n name: packageJson.name,\n title: \"Factory Droid\",\n version: packageJson.version,\n },\n authMethods: [\n {\n id: \"factory-api-key\",\n name: \"Factory API Key\",\n description: \"Set FACTORY_API_KEY environment variable\",\n },\n ],\n };\n }\n\n async authenticate(request: AuthenticateRequest): Promise<AuthenticateResponse> {\n this.logger.log(\"authenticate:\", request.methodId);\n if (request.methodId === \"factory-api-key\") {\n if (!process.env.FACTORY_API_KEY) {\n throw new Error(\"FACTORY_API_KEY environment variable is not set\");\n }\n return {};\n }\n throw new Error(`Unknown auth method: ${request.methodId}`);\n }\n\n async newSession(request: NewSessionRequest): Promise<NewSessionResponse> {\n const cwd = request.cwd || process.cwd();\n this.logger.log(\"newSession:\", cwd);\n\n const droid = createDroidAdapter({ cwd, logger: this.logger });\n const initResult = await droid.start();\n\n const sessionId = initResult.sessionId;\n const initialMode: AcpModeId =\n typeof initResult.settings?.autonomyLevel === \"string\"\n ? (droidAutonomyToAcpModeId(initResult.settings.autonomyLevel) ?? \"off\")\n : \"off\";\n const session: Session = {\n id: sessionId,\n droid,\n droidSessionId: initResult.sessionId,\n model: initResult.settings?.modelId || \"unknown\",\n mode: initialMode,\n cancelled: false,\n promptResolve: null,\n activeToolCallIds: new Set(),\n toolCallStatus: new Map(),\n toolNames: new Map(),\n availableModels: initResult.availableModels,\n cwd,\n specChoice: null,\n specChoicePromptSignature: null,\n specPlanDetailsSignature: null,\n specPlanDetailsToolCallId: null,\n };\n\n // Set up notification handler\n droid.onNotification((n) => this.handleNotification(session, n));\n\n // Forward raw events for debugging (enable with DROID_DEBUG=1)\n if (process.env.DROID_DEBUG) {\n droid.onRawEvent(async (event) => {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: {\n type: \"text\",\n text: `\\n\\`\\`\\`json\\n${JSON.stringify(event, null, 2)}\\n\\`\\`\\`\\n`,\n },\n },\n });\n });\n }\n\n // Handle permission requests\n droid.onRequest(async (method, params) => {\n if (method === \"droid.request_permission\") {\n return this.handlePermission(session, params as PermissionRequest);\n }\n throw new Error(\"Method not supported\");\n });\n\n // Handle droid process exit\n droid.onExit((code) => {\n this.logger.log(\"Droid exited, cleaning up session:\", session.id, \"code:\", code);\n if (session.promptResolve) {\n session.promptResolve({ stopReason: \"end_turn\" });\n session.promptResolve = null;\n }\n this.sessions.delete(session.id);\n });\n\n this.sessions.set(sessionId, session);\n this.logger.log(\"Session created:\", sessionId);\n\n // Send available commands update after session response\n setTimeout(() => {\n void this.client.sessionUpdate({\n sessionId,\n update: {\n sessionUpdate: \"available_commands_update\",\n availableCommands: getAvailableCommands(),\n },\n });\n }, 0);\n\n return {\n sessionId,\n models: {\n availableModels: initResult.availableModels.map((m) => ({\n modelId: m.id,\n name: m.displayName,\n })),\n currentModelId: initResult.settings?.modelId || \"unknown\",\n },\n modes: {\n currentModeId: initialMode,\n availableModes: [\n {\n id: \"spec\",\n name: \"Spec\",\n description: \"Research and plan only - no code changes\",\n },\n {\n id: \"off\",\n name: \"Auto Off\",\n description: \"Read-only mode - safe for reviewing planned changes without execution\",\n },\n {\n id: \"low\",\n name: \"Auto Low\",\n description: \"Low-risk operations - file creation/modification, no system changes\",\n },\n {\n id: \"medium\",\n name: \"Auto Medium\",\n description: \"Development operations - npm install, git commit, build commands\",\n },\n {\n id: \"high\",\n name: \"Auto High\",\n description: \"Production operations - git push, deployments, database migrations\",\n },\n ],\n },\n };\n }\n\n async prompt(request: PromptRequest): Promise<PromptResponse> {\n const session = this.sessions.get(request.sessionId);\n if (!session) throw new Error(`Session not found: ${request.sessionId}`);\n if (session.cancelled) throw new Error(\"Session cancelled\");\n if (session.promptResolve) throw new Error(\"Another prompt is already in progress\");\n\n this.logger.log(\"prompt:\", request.sessionId);\n\n // Convert ACP prompt blocks into Droid user message (text + images).\n const textParts: string[] = [];\n const images: Array<{ type: \"base64\"; data: string; mediaType: string }> = [];\n for (const chunk of request.prompt) {\n switch (chunk.type) {\n case \"text\":\n textParts.push(chunk.text);\n break;\n\n case \"image\": {\n const mimeType = chunk.mimeType || \"application/octet-stream\";\n if (chunk.data) {\n const normalized = normalizeBase64DataUrl(chunk.data, mimeType);\n images.push({\n type: \"base64\",\n data: normalized.base64,\n mediaType: normalized.mimeType,\n });\n } else if (chunk.uri) {\n textParts.push(`(image: ${chunk.uri})`);\n }\n break;\n }\n\n case \"resource\":\n if (\"text\" in chunk.resource) {\n const contextText = `\\n<context ref=\"${chunk.resource.uri}\">\\n${chunk.resource.text}\\n</context>`;\n textParts.push(contextText);\n } else if (\"blob\" in chunk.resource) {\n const mimeType =\n (chunk.resource as { mimeType?: string | null }).mimeType ||\n \"application/octet-stream\";\n const uri = (chunk.resource as { uri?: string }).uri;\n if (mimeType.startsWith(\"image/\")) {\n const data = (chunk.resource as { blob?: unknown }).blob;\n if (typeof data === \"string\" && data.length > 0) {\n const normalized = normalizeBase64DataUrl(data, mimeType);\n images.push({\n type: \"base64\",\n data: normalized.base64,\n mediaType: normalized.mimeType,\n });\n }\n } else {\n const note = uri\n ? `\\n<context ref=\"${uri}\">\\n(binary resource: ${mimeType})\\n</context>`\n : `\\n(binary resource: ${mimeType})`;\n textParts.push(note);\n }\n }\n break;\n case \"resource_link\":\n textParts.push(`@${chunk.uri}`);\n break;\n default:\n break;\n }\n }\n let text = textParts.join(\"\\n\").trim();\n if (text.length === 0 && images.length > 0) {\n text = \"Please see the attached image(s).\";\n }\n\n // Handle slash commands\n if (text.startsWith(\"/\")) {\n const handled = await this.handleSlashCommand(session, text);\n if (handled) {\n return { stopReason: \"end_turn\" };\n }\n }\n\n // Send message and wait for completion\n return new Promise((resolve) => {\n const timeoutId = setTimeout(\n () => {\n if (session.promptResolve) {\n session.promptResolve({ stopReason: \"end_turn\" });\n session.promptResolve = null;\n }\n },\n 5 * 60 * 1000,\n );\n\n session.promptResolve = resolve;\n session.droid.sendUserMessage({\n text,\n images: images.length > 0 ? images : undefined,\n });\n\n // Ensure we don't leak timers if the prompt resolves normally.\n const originalResolve = session.promptResolve;\n session.promptResolve = (result) => {\n clearTimeout(timeoutId);\n originalResolve?.(result);\n };\n });\n }\n\n async cancel(request: CancelNotification): Promise<void> {\n const session = this.sessions.get(request.sessionId);\n if (session) {\n this.logger.log(\"cancel:\", request.sessionId);\n session.cancelled = true;\n if (session.promptResolve) {\n session.promptResolve({ stopReason: \"cancelled\" });\n session.promptResolve = null;\n }\n await session.droid.stop();\n this.sessions.delete(request.sessionId);\n }\n }\n\n async unstable_setSessionModel(\n request: SetSessionModelRequest,\n ): Promise<SetSessionModelResponse | void> {\n const session = this.sessions.get(request.sessionId);\n if (session) {\n this.logger.log(\"setSessionModel:\", request.modelId);\n session.model = request.modelId;\n session.droid.setModel(request.modelId);\n }\n }\n\n async setSessionMode(request: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n const session = this.sessions.get(request.sessionId);\n if (session) {\n this.logger.log(\"setSessionMode:\", request.modeId);\n const modeId = ACP_MODES.includes(request.modeId as AcpModeId)\n ? (request.modeId as AcpModeId)\n : null;\n if (modeId) {\n session.mode = modeId;\n session.droid.setMode(ACP_MODE_TO_DROID_AUTONOMY[modeId]);\n }\n }\n return {};\n }\n\n private async handleSlashCommand(session: Session, text: string): Promise<boolean> {\n const match = text.match(/^\\/(\\S+)(?:\\s+(.*))?$/);\n if (!match) return false;\n\n const [, command, args] = match;\n const trimmedArgs = args?.trim() || \"\";\n\n switch (command.toLowerCase()) {\n case \"help\": {\n const commands = getAvailableCommands();\n const helpText = [\n \"**Available Commands:**\\n\",\n ...commands.map((cmd) => {\n const inputHint = cmd.input && \"hint\" in cmd.input ? ` ${cmd.input.hint}` : \"\";\n return `- \\`/${cmd.name}${inputHint}\\` - ${cmd.description}`;\n }),\n ].join(\"\\n\");\n await this.sendAgentMessage(session, helpText);\n return true;\n }\n\n case \"model\": {\n if (trimmedArgs) {\n // Change model\n const modelId = trimmedArgs;\n const model = session.availableModels.find(\n (m) => m.id === modelId || m.displayName.toLowerCase() === modelId.toLowerCase(),\n );\n if (model) {\n session.model = model.id;\n session.droid.setModel(model.id);\n await this.sendAgentMessage(session, `Model changed to: **${model.displayName}**`);\n } else {\n const available = session.availableModels.map((m) => `- ${m.id} (${m.displayName})`);\n await this.sendAgentMessage(\n session,\n `Model \"${modelId}\" not found.\\n\\n**Available models:**\\n${available.join(\"\\n\")}`,\n );\n }\n } else {\n // Show current model\n const available = session.availableModels.map((m) => {\n const current = m.id === session.model ? \" **(current)**\" : \"\";\n return `- ${m.id} (${m.displayName})${current}`;\n });\n await this.sendAgentMessage(\n session,\n `**Current model:** ${session.model}\\n\\n**Available models:**\\n${available.join(\"\\n\")}`,\n );\n }\n return true;\n }\n\n case \"mode\": {\n const inputMode = trimmedArgs.toLowerCase() as AcpModeId;\n if (trimmedArgs && ACP_MODES.includes(inputMode)) {\n session.mode = inputMode;\n session.droid.setMode(ACP_MODE_TO_DROID_AUTONOMY[inputMode]);\n await this.sendAgentMessage(session, `Autonomy mode changed to: **${inputMode}**`);\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"current_mode_update\",\n currentModeId: inputMode,\n },\n });\n } else {\n const modeList = ACP_MODES.map((m) => {\n const current = m === session.mode ? \" **(current)**\" : \"\";\n return `- ${m}${current}`;\n }).join(\"\\n\");\n await this.sendAgentMessage(\n session,\n `**Current mode:** ${session.mode}\\n\\n**Available modes:**\\n${modeList}`,\n );\n }\n return true;\n }\n\n case \"config\": {\n const config = [\n `**Session Configuration:**`,\n `- Session ID: ${session.id}`,\n `- Working Directory: ${session.cwd}`,\n `- Model: ${session.model}`,\n `- Mode: ${session.mode}`,\n ].join(\"\\n\");\n await this.sendAgentMessage(session, config);\n return true;\n }\n\n case \"status\": {\n const status = [\n `**Session Status:**`,\n `- Active Tool Calls: ${session.activeToolCallIds.size}`,\n `- Droid Running: ${session.droid.isRunning()}`,\n ].join(\"\\n\");\n await this.sendAgentMessage(session, status);\n return true;\n }\n\n default:\n // Unknown command - show error\n await this.sendAgentMessage(\n session,\n `Unknown command: \\`/${command}\\`. Type \\`/help\\` to see available commands.`,\n );\n return true;\n }\n }\n\n private async sendAgentMessage(session: Session, text: string): Promise<void> {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text },\n },\n });\n }\n\n private extractSpecTitleAndPlan(rawInput: unknown): {\n title: string | null;\n plan: string | null;\n } {\n if (!rawInput || typeof rawInput !== \"object\") return { title: null, plan: null };\n\n const obj = rawInput as Record<string, unknown>;\n\n const title =\n typeof obj.title === \"string\"\n ? obj.title\n : typeof obj.specTitle === \"string\"\n ? obj.specTitle\n : typeof obj.name === \"string\"\n ? obj.name\n : null;\n\n const candidates: unknown[] = [\n obj.plan,\n (obj as { planMarkdown?: unknown }).planMarkdown,\n (obj as { markdown?: unknown }).markdown,\n (obj as { content?: unknown }).content,\n (obj as { text?: unknown }).text,\n ];\n\n const toMarkdown = (value: unknown): string | null => {\n if (typeof value === \"string\") return value;\n if (Array.isArray(value)) {\n const parts = value.map((v) => (typeof v === \"string\" ? v : JSON.stringify(v, null, 2)));\n const joined = parts.join(\"\\n\").trim();\n return joined.length > 0 ? joined : null;\n }\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n if (typeof v.markdown === \"string\") return v.markdown;\n if (typeof v.text === \"string\") return v.text;\n const json = JSON.stringify(v, null, 2);\n return json && json !== \"{}\" ? json : null;\n }\n return null;\n };\n\n for (const c of candidates) {\n const plan = toMarkdown(c);\n if (plan) return { title, plan };\n }\n\n return { title, plan: null };\n }\n\n private planEntriesFromMarkdown(planMarkdown: string): Array<{\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n priority: \"medium\";\n }> {\n const entries: Array<{\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n priority: \"medium\";\n }> = [];\n let inCodeFence = false;\n\n for (const rawLine of planMarkdown.split(\"\\n\")) {\n const line = rawLine.trim();\n if (line.startsWith(\"```\")) {\n inCodeFence = !inCodeFence;\n continue;\n }\n if (inCodeFence) continue;\n if (!line) continue;\n\n const checkbox = line.match(/^- \\[([ xX~])\\]\\s+(.*)$/);\n if (checkbox) {\n const [, mark, content] = checkbox;\n const status =\n mark === \"x\" || mark === \"X\"\n ? (\"completed\" as const)\n : mark === \"~\"\n ? (\"in_progress\" as const)\n : (\"pending\" as const);\n entries.push({ content, status, priority: \"medium\" as const });\n continue;\n }\n\n const bullet = line.match(/^[-*]\\s+(.*)$/);\n if (bullet) {\n entries.push({\n content: bullet[1],\n status: \"pending\",\n priority: \"medium\",\n });\n continue;\n }\n\n const numbered = line.match(/^\\d+\\.\\s+(.*)$/);\n if (numbered) {\n entries.push({\n content: numbered[1],\n status: \"pending\",\n priority: \"medium\",\n });\n continue;\n }\n }\n\n return entries.filter((e) => e.content.length > 0);\n }\n\n private extractPlanChoices(planMarkdown: string): Array<{ id: string; title: string }> {\n const explicitChoices: Array<{ id: string; title: string }> = [];\n const looseChoices: Array<{ id: string; title: string }> = [];\n const seenExplicit = new Set<string>();\n const seenLoose = new Set<string>();\n\n for (const rawLine of planMarkdown.split(\"\\n\")) {\n const line = rawLine.trim();\n if (!line) continue;\n\n const stripped = line\n .replace(/^>\\s+/, \"\")\n .replace(/^#+\\s*/, \"\")\n .replace(/^[-*]\\s+/, \"\")\n .trim()\n .replace(/^[*_`]+/, \"\")\n .trim();\n\n const explicit = stripped.match(/^(?:Option|方案)\\s*([A-Z])\\s*[::–—.)-]\\s*(.+)$/i);\n if (explicit) {\n const id = explicit[1].toUpperCase();\n if (seenExplicit.has(id)) continue;\n seenExplicit.add(id);\n\n const title = explicit[2].trim();\n explicitChoices.push({ id, title });\n continue;\n }\n\n // Looser fallback: allow \"A: ...\" / \"B) ...\" style lines (only if we find multiple).\n const loose = stripped.match(/^([A-F])\\s*[::–—.)-]\\s*(.+)$/);\n if (!loose) continue;\n\n const id = loose[1].toUpperCase();\n if (seenLoose.has(id)) continue;\n seenLoose.add(id);\n\n const title = loose[2].trim();\n looseChoices.push({ id, title });\n }\n\n if (explicitChoices.length > 0) return explicitChoices;\n if (looseChoices.length >= 2) return looseChoices;\n return [];\n }\n\n private handlePermission(\n session: Session,\n params: PermissionRequest,\n ): Promise<{ selectedOption: string }> {\n const toolUse = params.toolUses?.[0]?.toolUse;\n if (!toolUse) {\n return Promise.resolve({ selectedOption: \"proceed_once\" });\n }\n\n const toolCallId = toolUse.id;\n const toolName = toolUse.name;\n const rawInput = toolUse.input;\n const spec = toolName === \"ExitSpecMode\" ? this.extractSpecTitleAndPlan(rawInput) : null;\n const command =\n typeof rawInput?.command === \"string\"\n ? rawInput.command\n : toolName === \"ExitSpecMode\" && typeof spec?.title === \"string\"\n ? spec.title\n : JSON.stringify(rawInput);\n const commandSummary = command.length > 200 ? command.slice(0, 200) + \"…\" : command;\n const isReadOnlyTool =\n toolName === \"Read\" || toolName === \"Grep\" || toolName === \"Glob\" || toolName === \"LS\";\n const riskLevelRaw = (rawInput as { riskLevel?: unknown } | null | undefined)?.riskLevel;\n const riskLevel =\n riskLevelRaw === \"low\" || riskLevelRaw === \"medium\" || riskLevelRaw === \"high\"\n ? riskLevelRaw\n : isReadOnlyTool\n ? \"low\"\n : \"medium\";\n\n this.logger.log(\n \"Permission request for tool:\",\n toolCallId,\n \"risk:\",\n riskLevel,\n \"mode:\",\n session.mode,\n );\n\n const toolCallTitle =\n toolName === \"ExitSpecMode\"\n ? spec?.title\n ? `Exit spec mode: ${spec.title}`\n : \"Exit spec mode\"\n : `Running ${toolName} (${riskLevel}): ${commandSummary}`;\n const toolCallKind = toolName === \"ExitSpecMode\" ? (\"switch_mode\" as const) : undefined;\n const toolCallContent =\n toolName === \"ExitSpecMode\" && spec?.plan\n ? [\n {\n type: \"content\" as const,\n content: { type: \"text\" as const, text: spec.plan },\n },\n ]\n : undefined;\n\n // Emit tool_call (pending), de-duping if the tool call was already created from a tool_use block.\n const alreadyTracked = session.activeToolCallIds.has(toolCallId);\n session.activeToolCallIds.add(toolCallId);\n session.toolNames.set(toolCallId, toolName);\n session.toolCallStatus.set(toolCallId, \"pending\");\n\n if (alreadyTracked) {\n void this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId,\n title: toolCallTitle,\n status: \"pending\",\n kind: toolCallKind,\n content: toolCallContent,\n rawInput,\n },\n });\n } else {\n void this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call\",\n toolCallId,\n title: toolCallTitle,\n status: \"pending\",\n kind: toolCallKind,\n content: toolCallContent,\n rawInput,\n },\n });\n }\n\n return this.decidePermission(session, {\n toolCallId,\n toolName,\n command: commandSummary,\n riskLevel,\n rawInput,\n droidOptions: this.extractDroidPermissionOptions(params),\n });\n }\n\n private extractDroidPermissionOptions(params: PermissionRequest): DroidPermissionOption[] | null {\n const candidates: unknown[] = [];\n\n const maybePush = (value: unknown) => {\n if (Array.isArray(value)) candidates.push(value);\n };\n\n maybePush((params as unknown as { options?: unknown }).options);\n\n const toolUses = (params as unknown as { toolUses?: unknown }).toolUses;\n if (Array.isArray(toolUses)) {\n for (const toolUse of toolUses) {\n if (!toolUse || typeof toolUse !== \"object\") continue;\n const tu = toolUse as Record<string, unknown>;\n maybePush(tu.options);\n const details = tu.details;\n if (details && typeof details === \"object\") {\n maybePush((details as Record<string, unknown>).options);\n }\n }\n }\n\n for (const candidate of candidates) {\n const normalized = (candidate as unknown[])\n .map((opt) => opt as { value?: unknown; label?: unknown })\n .map((opt) => ({\n value: typeof opt.value === \"string\" ? opt.value : null,\n label: typeof opt.label === \"string\" ? opt.label : null,\n }))\n .filter((opt): opt is { value: string; label: string } => !!opt.value && !!opt.label)\n .map((opt) => ({ value: opt.value, label: opt.label }));\n\n if (normalized.length > 0) return normalized;\n }\n\n return null;\n }\n\n private mapExitSpecModeSelection(optionId: string): {\n nextMode: AcpModeId | null;\n droidSelectedOption: string;\n } {\n // Preferred: optionId equals ACP mode id.\n switch (optionId) {\n case \"off\":\n return { nextMode: \"off\", droidSelectedOption: \"proceed_once\" };\n case \"low\":\n return { nextMode: \"low\", droidSelectedOption: \"proceed_auto_run_low\" };\n case \"medium\":\n return { nextMode: \"medium\", droidSelectedOption: \"proceed_auto_run_medium\" };\n case \"high\":\n return { nextMode: \"high\", droidSelectedOption: \"proceed_auto_run_high\" };\n case \"spec\":\n return { nextMode: \"spec\", droidSelectedOption: \"cancel\" };\n default:\n break;\n }\n\n // Back-compat: accept Droid option ids directly (or other clients returning them).\n switch (optionId) {\n case \"proceed_once\":\n return { nextMode: \"off\", droidSelectedOption: \"proceed_once\" };\n case \"proceed_auto_run_low\":\n return { nextMode: \"low\", droidSelectedOption: \"proceed_auto_run_low\" };\n case \"proceed_auto_run_medium\":\n return { nextMode: \"medium\", droidSelectedOption: \"proceed_auto_run_medium\" };\n case \"proceed_auto_run_high\":\n return { nextMode: \"high\", droidSelectedOption: \"proceed_auto_run_high\" };\n case \"cancel\":\n return { nextMode: \"spec\", droidSelectedOption: \"cancel\" };\n default:\n return { nextMode: null, droidSelectedOption: optionId };\n }\n }\n\n private specApprovalOptions(droidOptions: DroidPermissionOption[] | null): PermissionOption[] {\n const has = (value: string): boolean => droidOptions?.some((o) => o.value === value) === true;\n\n const candidates: Array<{\n modeId: AcpModeId;\n droidValue: string;\n name: string;\n kind: PermissionOption[\"kind\"];\n }> = [\n {\n modeId: \"off\",\n droidValue: \"proceed_once\",\n name: \"Proceed (manual approvals)\",\n kind: \"allow_once\",\n },\n {\n modeId: \"low\",\n droidValue: \"proceed_auto_run_low\",\n name: \"Proceed (Auto Low)\",\n kind: \"allow_once\",\n },\n {\n modeId: \"medium\",\n droidValue: \"proceed_auto_run_medium\",\n name: \"Proceed (Auto Medium)\",\n kind: \"allow_once\",\n },\n {\n modeId: \"high\",\n droidValue: \"proceed_auto_run_high\",\n name: \"Proceed (Auto High)\",\n kind: \"allow_once\",\n },\n {\n modeId: \"spec\",\n droidValue: \"cancel\",\n name: \"No, keep iterating (stay in Spec)\",\n kind: \"reject_once\",\n },\n ];\n\n const options = candidates\n .filter((c) => !droidOptions || has(c.droidValue))\n .map((c) => ({ optionId: c.modeId, name: c.name, kind: c.kind }));\n\n if (options.length > 0) return options;\n\n // Fallback: expose raw Droid options if we can't match.\n return (\n droidOptions?.map((o) => ({\n optionId: o.value,\n name: o.label,\n kind: \"allow_once\" as const,\n })) ?? [\n { optionId: \"off\", name: \"Proceed (manual approvals)\", kind: \"allow_once\" },\n { optionId: \"spec\", name: \"No, keep iterating (stay in Spec)\", kind: \"reject_once\" },\n ]\n );\n }\n\n private async decidePermission(\n session: Session,\n params: {\n toolCallId: string;\n toolName: string;\n command: string;\n riskLevel: \"low\" | \"medium\" | \"high\";\n rawInput: unknown;\n droidOptions: DroidPermissionOption[] | null;\n },\n ): Promise<{ selectedOption: string }> {\n if (session.cancelled) {\n session.toolCallStatus.set(params.toolCallId, \"completed\");\n session.activeToolCallIds.delete(params.toolCallId);\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status: \"completed\",\n },\n });\n return { selectedOption: \"cancel\" };\n }\n\n const permissionKindFromOptionValue = (value: string): PermissionOption[\"kind\"] => {\n switch (value) {\n case \"proceed_once\":\n case \"proceed_edit\":\n return \"allow_once\";\n case \"proceed_auto_run_low\":\n case \"proceed_auto_run_medium\":\n case \"proceed_auto_run_high\":\n case \"proceed_auto_run\":\n case \"proceed_always\":\n return \"allow_always\";\n case \"cancel\":\n return \"reject_once\";\n default:\n return \"allow_once\";\n }\n };\n\n const toAcpPermissionOption = (opt: DroidPermissionOption): PermissionOption => {\n const value = opt.value;\n let name = opt.label;\n switch (value) {\n case \"proceed_once\":\n name = \"Allow once\";\n break;\n case \"proceed_always\": {\n const labelLower = opt.label.toLowerCase();\n if (labelLower.includes(\"low\")) {\n name = \"Allow & auto-run low risk commands\";\n break;\n }\n if (labelLower.includes(\"medium\")) {\n name = \"Allow & auto-run medium risk commands\";\n break;\n }\n if (labelLower.includes(\"high\")) {\n name = \"Allow & auto-run high risk commands\";\n break;\n }\n name = \"Allow always\";\n break;\n }\n case \"proceed_auto_run_low\":\n name = \"Proceed & auto-run (low risk)\";\n break;\n case \"proceed_auto_run_medium\":\n name = \"Proceed & auto-run (medium risk)\";\n break;\n case \"proceed_auto_run_high\":\n name = \"Proceed & auto-run (high risk)\";\n break;\n default:\n break;\n }\n return {\n optionId: value,\n name,\n kind: permissionKindFromOptionValue(value),\n };\n };\n\n const droidOptions = params.droidOptions?.length ? params.droidOptions : null;\n const acpOptions: PermissionOption[] =\n params.toolName === \"ExitSpecMode\"\n ? this.specApprovalOptions(droidOptions)\n : droidOptions\n ? droidOptions.map(toAcpPermissionOption)\n : [\n { optionId: \"proceed_once\", name: \"Allow once\", kind: \"allow_once\" },\n { optionId: \"cancel\", name: \"Reject\", kind: \"reject_once\" },\n ];\n\n const spec = this.extractSpecTitleAndPlan(params.rawInput);\n const planTitle = spec.title;\n const planMarkdown = spec.plan;\n\n if (params.toolName === \"ExitSpecMode\" && planMarkdown) {\n const signature = `${planTitle ?? \"\"}\\n${planMarkdown}`;\n if (session.specChoicePromptSignature !== signature) {\n session.specChoicePromptSignature = signature;\n session.specChoice = null;\n }\n\n if (session.specPlanDetailsSignature !== signature) {\n session.specPlanDetailsSignature = signature;\n session.specPlanDetailsToolCallId = `${params.toolCallId}:plan_details`;\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call\",\n toolCallId: session.specPlanDetailsToolCallId,\n title: planTitle ? `Plan details: ${planTitle}` : \"Plan details\",\n kind: \"think\",\n status: \"completed\",\n content: [\n {\n type: \"content\",\n content: { type: \"text\", text: planMarkdown },\n },\n ],\n },\n });\n }\n\n if (session.specChoice === null) {\n const choices = this.extractPlanChoices(planMarkdown);\n if (choices.length > 0) {\n const detailsHint = session.specPlanDetailsToolCallId\n ? `Expand **${session.specPlanDetailsToolCallId}** to view the full plan details.`\n : \"Expand the Plan details tool call to view the full plan details.\";\n const choicePrompt = [\n planTitle ? `**${planTitle}**` : \"**Choose an implementation option**\",\n \"\",\n detailsHint,\n \"Choose one to continue iterating in spec mode.\",\n ...choices.map((c) => `- Option ${c.id}: ${c.title}`),\n ]\n .filter((p) => p.length > 0)\n .join(\"\\n\");\n\n const response = await this.client.requestPermission({\n sessionId: session.id,\n toolCall: {\n toolCallId: `${params.toolCallId}:choose_plan`,\n title: planTitle ? `Choose plan: ${planTitle}` : \"Choose plan option\",\n status: \"pending\",\n kind: \"think\",\n rawInput: { choices },\n content: [\n {\n type: \"content\",\n content: { type: \"text\", text: choicePrompt },\n },\n ],\n },\n options: [\n ...choices.map((c) => ({\n optionId: `choose_plan:${c.id}`,\n name: `Choose Option ${c.id}`,\n kind: \"allow_once\" as const,\n })),\n { optionId: \"choose_plan:skip\", name: \"Skip\", kind: \"reject_once\" as const },\n ],\n });\n\n const outcome =\n response.outcome.outcome === \"selected\"\n ? response.outcome.optionId\n : \"choose_plan:skip\";\n const match = outcome.match(/^choose_plan:([A-Z])$/);\n if (match) {\n const choiceId = match[1];\n session.specChoice = choiceId;\n\n // Close the temporary \"choose plan\" permission prompt tool call.\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: `${params.toolCallId}:choose_plan`,\n status: \"completed\",\n },\n });\n\n // Close the original ExitSpecMode tool call since we're explicitly staying in spec mode.\n session.toolCallStatus.set(params.toolCallId, \"completed\");\n session.activeToolCallIds.delete(params.toolCallId);\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status: \"completed\",\n content: [\n {\n type: \"content\",\n content: {\n type: \"text\",\n text: `Continuing in spec mode with Option ${choiceId}.`,\n },\n },\n ],\n },\n });\n\n await this.sendAgentMessage(\n session,\n `Selected **Option ${choiceId}**. Continuing in spec mode.`,\n );\n setTimeout(() => {\n session.droid.sendMessage(\n `我选择方案 ${choiceId}。请基于该方案继续完善计划/关键改动点,并在准备好执行时再提示退出 spec。`,\n );\n }, 0);\n return { selectedOption: \"cancel\" };\n }\n\n session.specChoice = \"skip\";\n }\n }\n }\n\n if (params.toolName === \"ExitSpecMode\" && planMarkdown) {\n const entries = this.planEntriesFromMarkdown(planMarkdown);\n\n if (entries.length > 0) {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"plan\",\n entries,\n },\n });\n } else if (planMarkdown.trim().length > 0) {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"plan\",\n entries: [\n {\n content: planMarkdown.trim(),\n status: \"pending\",\n priority: \"medium\",\n },\n ],\n },\n });\n }\n }\n\n // Decide whether to auto-approve, auto-reject, or ask the client UI.\n let autoDecision: string | null = null;\n if (params.toolName === \"ExitSpecMode\") {\n // Exiting spec triggers execution; always ask the user which mode to proceed with.\n autoDecision = null;\n this.logger.log(\"Prompting (ExitSpecMode)\");\n } else if (session.mode === \"high\") {\n autoDecision = \"proceed_always\";\n this.logger.log(\"Auto-approved (high mode)\");\n } else if (session.mode === \"medium\") {\n autoDecision = params.riskLevel === \"high\" ? null : \"proceed_once\";\n this.logger.log(\n autoDecision ? \"Auto-approved (medium mode, low/med risk)\" : \"Prompting (medium mode)\",\n );\n } else if (session.mode === \"low\") {\n autoDecision = params.riskLevel === \"low\" ? \"proceed_once\" : null;\n this.logger.log(autoDecision ? \"Auto-approved (low mode, low risk)\" : \"Prompting (low mode)\");\n } else if (session.mode === \"spec\") {\n // Spec mode: allow low-risk operations (read/search) without prompting.\n if (params.riskLevel === \"low\") {\n autoDecision = \"proceed_once\";\n this.logger.log(\"Auto-approved (spec mode, low risk)\");\n } else {\n autoDecision = \"cancel\";\n this.logger.log(\"Auto-rejected (spec mode, medium/high risk)\");\n }\n } else {\n // off mode: ask the user (no auto-approval)\n autoDecision = null;\n this.logger.log(\"Prompting (off mode)\");\n }\n\n if (autoDecision) {\n const selectedOption =\n droidOptions?.some((o) => o.value === autoDecision) === true\n ? autoDecision\n : autoDecision === \"cancel\"\n ? \"cancel\"\n : droidOptions\n ? (droidOptions?.find((o) => permissionKindFromOptionValue(o.value) === \"allow_once\")\n ?.value ??\n droidOptions?.find((o) => o.value !== \"cancel\")?.value ??\n \"proceed_once\")\n : autoDecision;\n\n const isExitSpecMode = params.toolName === \"ExitSpecMode\";\n const status =\n selectedOption === \"cancel\" || isExitSpecMode\n ? (\"completed\" as const)\n : (\"in_progress\" as const);\n\n session.toolCallStatus.set(params.toolCallId, status);\n if (status === \"completed\") {\n session.activeToolCallIds.delete(params.toolCallId);\n }\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status,\n content:\n selectedOption === \"cancel\"\n ? [\n {\n type: \"content\",\n content: {\n type: \"text\",\n text: `Permission denied for \\`${params.toolName}\\` (${params.riskLevel}).`,\n },\n },\n ]\n : undefined,\n },\n });\n return { selectedOption };\n }\n\n let permission: Awaited<ReturnType<AgentSideConnection[\"requestPermission\"]>>;\n try {\n const title =\n params.toolName === \"ExitSpecMode\"\n ? planTitle\n ? `Exit spec mode: ${planTitle}`\n : \"Exit spec mode\"\n : `Running ${params.toolName} (${params.riskLevel}): ${params.command}`;\n\n permission = await this.client.requestPermission({\n sessionId: session.id,\n toolCall: {\n toolCallId: params.toolCallId,\n title,\n rawInput: params.rawInput,\n },\n options: acpOptions,\n });\n } catch (error) {\n this.logger.error(\"requestPermission failed:\", error);\n session.toolCallStatus.set(params.toolCallId, \"completed\");\n session.activeToolCallIds.delete(params.toolCallId);\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status: \"completed\",\n content: [\n {\n type: \"content\",\n content: {\n type: \"text\",\n text: `Permission request failed for \\`${params.toolName}\\`. Cancelling the operation.`,\n },\n },\n ],\n },\n });\n return { selectedOption: \"cancel\" };\n }\n\n let selectedOption = \"cancel\";\n if (permission.outcome.outcome === \"selected\") {\n selectedOption = permission.outcome.optionId;\n } else {\n selectedOption = \"cancel\";\n }\n\n if (params.toolName === \"ExitSpecMode\") {\n const mapped = this.mapExitSpecModeSelection(selectedOption);\n selectedOption = mapped.droidSelectedOption;\n\n if (mapped.nextMode) {\n session.mode = mapped.nextMode;\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"current_mode_update\",\n currentModeId: mapped.nextMode,\n },\n });\n }\n }\n\n const isExitSpecMode = params.toolName === \"ExitSpecMode\";\n const status =\n selectedOption === \"cancel\" || isExitSpecMode\n ? (\"completed\" as const)\n : (\"in_progress\" as const);\n\n session.toolCallStatus.set(params.toolCallId, status);\n if (status === \"completed\") {\n session.activeToolCallIds.delete(params.toolCallId);\n }\n\n // Close ExitSpecMode prompts explicitly so the UI doesn't leave them hanging.\n if (isExitSpecMode) {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status,\n content:\n selectedOption === \"cancel\"\n ? [\n {\n type: \"content\",\n content: { type: \"text\", text: \"Staying in Spec mode.\" },\n },\n ]\n : undefined,\n },\n });\n } else if (selectedOption !== \"cancel\") {\n // If the user explicitly rejected the permission prompt, the Client will already\n // reflect that in the UI (e.g. \"Rejected\"). Avoid overwriting it with a \"completed\" status.\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: params.toolCallId,\n status,\n },\n });\n }\n\n return { selectedOption };\n }\n\n private async handleNotification(session: Session, n: DroidNotification): Promise<void> {\n this.logger.log(\"notification:\", n.type);\n\n switch (n.type) {\n case \"settings_updated\": {\n const autonomyLevel =\n typeof n.settings.autonomyLevel === \"string\"\n ? droidAutonomyToAcpModeId(n.settings.autonomyLevel)\n : null;\n\n if (autonomyLevel && autonomyLevel !== session.mode) {\n session.mode = autonomyLevel;\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"current_mode_update\",\n currentModeId: autonomyLevel,\n },\n });\n }\n\n if (typeof n.settings.modelId === \"string\") {\n session.model = n.settings.modelId;\n }\n break;\n }\n\n case \"message\":\n if (n.role === \"assistant\") {\n // Handle tool use in message\n if (n.toolUse) {\n if (n.toolUse.name === \"TodoWrite\") {\n const todos = (n.toolUse.input as { todos?: unknown })?.todos;\n if (Array.isArray(todos)) {\n const toStatus = (status: unknown): \"pending\" | \"in_progress\" | \"completed\" => {\n switch (status) {\n case \"pending\":\n case \"in_progress\":\n case \"completed\":\n return status;\n default:\n return \"pending\";\n }\n };\n\n const entries = todos\n .map((t) => {\n const todo = t as { content?: unknown; status?: unknown };\n return {\n content: typeof todo.content === \"string\" ? todo.content : \"\",\n status: toStatus(todo.status),\n priority: \"medium\" as const,\n };\n })\n .filter((e) => e.content.length > 0);\n\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"plan\",\n entries,\n },\n });\n }\n break;\n }\n\n const toolCallId = n.toolUse.id;\n const isExitSpecMode = n.toolUse.name === \"ExitSpecMode\";\n const existingStatus = session.toolCallStatus.get(toolCallId);\n if (existingStatus !== \"completed\" && existingStatus !== \"failed\") {\n if (!session.activeToolCallIds.has(toolCallId)) {\n session.activeToolCallIds.add(toolCallId);\n session.toolNames.set(toolCallId, n.toolUse.name);\n\n const initialStatus = isExitSpecMode ? \"pending\" : \"in_progress\";\n session.toolCallStatus.set(toolCallId, initialStatus);\n\n const spec = isExitSpecMode ? this.extractSpecTitleAndPlan(n.toolUse.input) : null;\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call\",\n toolCallId: toolCallId,\n title: isExitSpecMode\n ? spec?.title\n ? `Exit spec mode: ${spec.title}`\n : \"Exit spec mode\"\n : `Running ${n.toolUse.name}`,\n kind: isExitSpecMode ? (\"switch_mode\" as const) : undefined,\n status: initialStatus,\n rawInput: n.toolUse.input,\n content:\n isExitSpecMode && spec?.plan\n ? [{ type: \"content\", content: { type: \"text\", text: spec.plan } }]\n : undefined,\n },\n });\n } else {\n const status = session.toolCallStatus.get(toolCallId);\n if (status !== \"completed\" && status !== \"failed\" && status !== \"pending\") {\n session.toolCallStatus.set(toolCallId, \"in_progress\");\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: toolCallId,\n status: \"in_progress\",\n },\n });\n }\n }\n }\n }\n\n // Handle text content\n if (n.text) {\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text: n.text },\n },\n });\n }\n }\n break;\n\n case \"tool_result\":\n if (!session.activeToolCallIds.has(n.toolUseId)) {\n session.activeToolCallIds.add(n.toolUseId);\n const name = session.toolNames.get(n.toolUseId) ?? \"Tool\";\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call\",\n toolCallId: n.toolUseId,\n title: `Running ${name}`,\n status: \"in_progress\",\n },\n });\n }\n\n const finalStatus = n.isError ? (\"failed\" as const) : (\"completed\" as const);\n\n // Send the tool response content + completion status\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"tool_call_update\",\n toolCallId: n.toolUseId,\n content: [\n {\n type: \"content\",\n content: {\n type: \"text\",\n text: n.content,\n },\n },\n ],\n rawOutput: n.content,\n status: finalStatus,\n },\n });\n\n session.toolCallStatus.set(n.toolUseId, finalStatus);\n session.activeToolCallIds.delete(n.toolUseId);\n break;\n\n case \"error\":\n await this.client.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text: `Error: ${n.message}` },\n },\n });\n if (session.promptResolve) {\n session.promptResolve({ stopReason: \"end_turn\" });\n session.promptResolve = null;\n }\n break;\n\n case \"complete\":\n if (session.promptResolve) {\n session.promptResolve({ stopReason: \"end_turn\" });\n session.promptResolve = null;\n }\n break;\n }\n }\n\n async cleanup(): Promise<void> {\n for (const [, session] of this.sessions) {\n await session.droid.stop();\n }\n this.sessions.clear();\n }\n}\n\nexport function runAcp(): void {\n const input = nodeToWebWritable(process.stdout);\n const output = nodeToWebReadable(process.stdin);\n\n const stream = ndJsonStream(input, output);\n new AgentSideConnection((client) => new DroidAcpAgent(client), stream);\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.mjs ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import { n as runAcp, o as findDroidExecutable, s as isWindows } from "./acp-agent-Ddz1S3Jm.mjs";
3
+ import { spawn } from "node:child_process";
4
+
5
+ //#region src/index.ts
6
+ console.log = console.error;
7
+ console.info = console.error;
8
+ console.warn = console.error;
9
+ console.debug = console.error;
10
+ process.on("unhandledRejection", (reason, promise) => {
11
+ console.error("Unhandled Rejection at:", promise, "reason:", reason);
12
+ });
13
+ /**
14
+ * Run droid with native ACP mode (--output-format acp).
15
+ * Note: Native ACP mode does NOT support custom models due to a bug in droid.
16
+ */
17
+ function runNativeAcp() {
18
+ const executable = findDroidExecutable();
19
+ const args = [
20
+ "exec",
21
+ "--output-format",
22
+ "acp",
23
+ "--cwd",
24
+ process.cwd()
25
+ ];
26
+ console.error(`[droid-acp] Starting droid with native ACP: ${executable} ${args.join(" ")}`);
27
+ console.error("[droid-acp] WARNING: Native ACP mode does not support custom models!");
28
+ const droid = spawn(executable, args, {
29
+ stdio: [
30
+ "pipe",
31
+ "pipe",
32
+ "pipe"
33
+ ],
34
+ env: {
35
+ ...process.env,
36
+ FORCE_COLOR: "0"
37
+ },
38
+ shell: isWindows,
39
+ windowsHide: true
40
+ });
41
+ process.stdin.pipe(droid.stdin);
42
+ droid.stdout.pipe(process.stdout);
43
+ droid.stderr.on("data", (data) => {
44
+ console.error(`[droid stderr] ${data.toString().trim()}`);
45
+ });
46
+ droid.on("error", (err) => {
47
+ console.error("[droid-acp] Failed to start droid:", err.message);
48
+ process.exit(1);
49
+ });
50
+ droid.on("exit", (code, signal) => {
51
+ console.error(`[droid-acp] Droid exited with code ${code}, signal ${signal}`);
52
+ process.exit(code ?? 0);
53
+ });
54
+ process.on("SIGTERM", () => droid.kill());
55
+ process.on("SIGINT", () => droid.kill());
56
+ if (isWindows) process.on("SIGHUP", () => droid.kill());
57
+ }
58
+ if (process.argv.includes("--acp")) runNativeAcp();
59
+ else runAcp();
60
+ process.stdin.resume();
61
+
62
+ //#endregion
63
+ export { };
64
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nconsole.log = console.error;\nconsole.info = console.error;\nconsole.warn = console.error;\nconsole.debug = console.error;\n\nprocess.on(\"unhandledRejection\", (reason, promise) => {\n console.error(\"Unhandled Rejection at:\", promise, \"reason:\", reason);\n});\n\nimport { spawn } from \"node:child_process\";\nimport { runAcp } from \"./acp-agent.ts\";\nimport { findDroidExecutable, isWindows } from \"./utils.ts\";\n\n/**\n * Run droid with native ACP mode (--output-format acp).\n * Note: Native ACP mode does NOT support custom models due to a bug in droid.\n */\nfunction runNativeAcp(): void {\n const executable = findDroidExecutable();\n const cwd = process.cwd();\n const args = [\"exec\", \"--output-format\", \"acp\", \"--cwd\", cwd];\n\n console.error(`[droid-acp] Starting droid with native ACP: ${executable} ${args.join(\" \")}`);\n console.error(\"[droid-acp] WARNING: Native ACP mode does not support custom models!\");\n\n const droid = spawn(executable, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env, FORCE_COLOR: \"0\" },\n // Windows requires shell: true for proper command execution\n shell: isWindows,\n // Windows-specific: hide the console window\n windowsHide: true,\n });\n\n process.stdin.pipe(droid.stdin);\n droid.stdout.pipe(process.stdout);\n droid.stderr.on(\"data\", (data: Buffer) => {\n console.error(`[droid stderr] ${data.toString().trim()}`);\n });\n\n droid.on(\"error\", (err) => {\n console.error(\"[droid-acp] Failed to start droid:\", err.message);\n process.exit(1);\n });\n\n droid.on(\"exit\", (code, signal) => {\n console.error(`[droid-acp] Droid exited with code ${code}, signal ${signal}`);\n process.exit(code ?? 0);\n });\n\n // Signal handling (works on Unix, limited on Windows)\n process.on(\"SIGTERM\", () => droid.kill());\n process.on(\"SIGINT\", () => droid.kill());\n if (isWindows) {\n process.on(\"SIGHUP\", () => droid.kill());\n }\n}\n\n// Parse command line arguments\nconst useNativeAcp = process.argv.includes(\"--acp\");\n\nif (useNativeAcp) {\n // Native ACP mode: direct pipe to droid (no custom model support)\n runNativeAcp();\n} else {\n // Default: stream-jsonrpc mode with custom adapter (supports custom models)\n runAcp();\n}\n\nprocess.stdin.resume();\n"],"mappings":";;;;;AAEA,QAAQ,MAAM,QAAQ;AACtB,QAAQ,OAAO,QAAQ;AACvB,QAAQ,OAAO,QAAQ;AACvB,QAAQ,QAAQ,QAAQ;AAExB,QAAQ,GAAG,uBAAuB,QAAQ,YAAY;AACpD,SAAQ,MAAM,2BAA2B,SAAS,WAAW,OAAO;EACpE;;;;;AAUF,SAAS,eAAqB;CAC5B,MAAM,aAAa,qBAAqB;CAExC,MAAM,OAAO;EAAC;EAAQ;EAAmB;EAAO;EADpC,QAAQ,KAAK;EACoC;AAE7D,SAAQ,MAAM,+CAA+C,WAAW,GAAG,KAAK,KAAK,IAAI,GAAG;AAC5F,SAAQ,MAAM,uEAAuE;CAErF,MAAM,QAAQ,MAAM,YAAY,MAAM;EACpC,OAAO;GAAC;GAAQ;GAAQ;GAAO;EAC/B,KAAK;GAAE,GAAG,QAAQ;GAAK,aAAa;GAAK;EAEzC,OAAO;EAEP,aAAa;EACd,CAAC;AAEF,SAAQ,MAAM,KAAK,MAAM,MAAM;AAC/B,OAAM,OAAO,KAAK,QAAQ,OAAO;AACjC,OAAM,OAAO,GAAG,SAAS,SAAiB;AACxC,UAAQ,MAAM,kBAAkB,KAAK,UAAU,CAAC,MAAM,GAAG;GACzD;AAEF,OAAM,GAAG,UAAU,QAAQ;AACzB,UAAQ,MAAM,sCAAsC,IAAI,QAAQ;AAChE,UAAQ,KAAK,EAAE;GACf;AAEF,OAAM,GAAG,SAAS,MAAM,WAAW;AACjC,UAAQ,MAAM,sCAAsC,KAAK,WAAW,SAAS;AAC7E,UAAQ,KAAK,QAAQ,EAAE;GACvB;AAGF,SAAQ,GAAG,iBAAiB,MAAM,MAAM,CAAC;AACzC,SAAQ,GAAG,gBAAgB,MAAM,MAAM,CAAC;AACxC,KAAI,UACF,SAAQ,GAAG,gBAAgB,MAAM,MAAM,CAAC;;AAO5C,IAFqB,QAAQ,KAAK,SAAS,QAAQ,CAIjD,eAAc;IAGd,SAAQ;AAGV,QAAQ,MAAM,QAAQ"}
package/dist/lib.d.mts ADDED
@@ -0,0 +1,177 @@
1
+ import { Agent, AgentSideConnection, AuthenticateRequest, AuthenticateResponse, CancelNotification, InitializeRequest, InitializeResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, SetSessionModeRequest, SetSessionModeResponse, SetSessionModelRequest, SetSessionModelResponse } from "@agentclientprotocol/sdk";
2
+ import { ReadableStream, WritableStream } from "node:stream/web";
3
+
4
+ //#region src/utils.d.ts
5
+ interface Logger {
6
+ log: (...args: unknown[]) => void;
7
+ error: (...args: unknown[]) => void;
8
+ }
9
+ declare class Pushable<T> implements AsyncIterable<T> {
10
+ private queue;
11
+ private resolvers;
12
+ private done;
13
+ push(item: T): void;
14
+ end(): void;
15
+ [Symbol.asyncIterator](): AsyncIterator<T>;
16
+ }
17
+ /** Check if running on Windows */
18
+ declare const isWindows: boolean;
19
+ /**
20
+ * Find the droid executable path.
21
+ * Uses DROID_EXECUTABLE env var if set, otherwise defaults to "droid".
22
+ * On Windows, also checks for "droid.exe" if not explicitly set.
23
+ */
24
+ declare function findDroidExecutable(): string;
25
+ //#endregion
26
+ //#region src/acp-agent.d.ts
27
+ declare class DroidAcpAgent implements Agent {
28
+ private sessions;
29
+ private client;
30
+ private logger;
31
+ constructor(client: AgentSideConnection, logger?: Logger);
32
+ initialize(_request: InitializeRequest): Promise<InitializeResponse>;
33
+ authenticate(request: AuthenticateRequest): Promise<AuthenticateResponse>;
34
+ newSession(request: NewSessionRequest): Promise<NewSessionResponse>;
35
+ prompt(request: PromptRequest): Promise<PromptResponse>;
36
+ cancel(request: CancelNotification): Promise<void>;
37
+ unstable_setSessionModel(request: SetSessionModelRequest): Promise<SetSessionModelResponse | void>;
38
+ setSessionMode(request: SetSessionModeRequest): Promise<SetSessionModeResponse>;
39
+ private handleSlashCommand;
40
+ private sendAgentMessage;
41
+ private extractSpecTitleAndPlan;
42
+ private planEntriesFromMarkdown;
43
+ private extractPlanChoices;
44
+ private handlePermission;
45
+ private extractDroidPermissionOptions;
46
+ private mapExitSpecModeSelection;
47
+ private specApprovalOptions;
48
+ private decidePermission;
49
+ private handleNotification;
50
+ cleanup(): Promise<void>;
51
+ }
52
+ declare function runAcp(): void;
53
+ //#endregion
54
+ //#region src/types.d.ts
55
+ /**
56
+ * Factory API types for stream-jsonrpc protocol
57
+ */
58
+ type AcpModeId = "off" | "low" | "medium" | "high" | "spec";
59
+ declare const ACP_MODES: AcpModeId[];
60
+ type DroidAutonomyLevel = "normal" | "spec" | "auto-low" | "auto-medium" | "auto-high" | "suggest" | "full";
61
+ interface FactoryRequest {
62
+ jsonrpc: "2.0";
63
+ factoryApiVersion: "1.0.0";
64
+ type: "request";
65
+ method: string;
66
+ params: Record<string, unknown>;
67
+ id: string;
68
+ }
69
+ interface FactoryResponse {
70
+ jsonrpc: "2.0";
71
+ type: "response";
72
+ factoryApiVersion: "1.0.0";
73
+ id: string;
74
+ result?: Record<string, unknown>;
75
+ error?: {
76
+ code: number;
77
+ message: string;
78
+ };
79
+ }
80
+ interface FactoryNotification {
81
+ jsonrpc: "2.0";
82
+ type: "notification";
83
+ factoryApiVersion: "1.0.0";
84
+ method: string;
85
+ params: Record<string, unknown>;
86
+ }
87
+ type FactoryMessage = FactoryRequest | FactoryResponse | FactoryNotification;
88
+ interface AvailableModel {
89
+ id: string;
90
+ modelId?: string;
91
+ modelProvider: string;
92
+ displayName: string;
93
+ shortDisplayName?: string;
94
+ supportedReasoningEfforts: string[];
95
+ defaultReasoningEffort: string;
96
+ isCustom: boolean;
97
+ noImageSupport?: boolean;
98
+ }
99
+ interface InitSessionResult {
100
+ sessionId: string;
101
+ session?: {
102
+ messages: unknown[];
103
+ };
104
+ settings?: {
105
+ modelId: string;
106
+ reasoningEffort?: string;
107
+ autonomyLevel?: string;
108
+ };
109
+ availableModels: AvailableModel[];
110
+ }
111
+ type DroidNotification = {
112
+ type: "working_state";
113
+ state: "idle" | "streaming_assistant_message";
114
+ } | {
115
+ type: "settings_updated";
116
+ settings: {
117
+ modelId?: string;
118
+ reasoningEffort?: string;
119
+ autonomyLevel?: string;
120
+ specModeModelId?: string;
121
+ specModeReasoningEffort?: string;
122
+ };
123
+ } | {
124
+ type: "tool_result";
125
+ toolUseId: string;
126
+ content: string;
127
+ isError: boolean;
128
+ } | {
129
+ type: "message";
130
+ role: "user" | "assistant" | "system";
131
+ text?: string;
132
+ id: string;
133
+ toolUse?: {
134
+ id: string;
135
+ name: string;
136
+ input?: unknown;
137
+ };
138
+ } | {
139
+ type: "error";
140
+ message: string;
141
+ } | {
142
+ type: "complete";
143
+ };
144
+ interface PermissionResponse {
145
+ selectedOption: string;
146
+ }
147
+ //#endregion
148
+ //#region src/droid-adapter.d.ts
149
+ interface DroidAdapterOptions {
150
+ cwd: string;
151
+ logger?: Logger;
152
+ }
153
+ interface DroidAdapter {
154
+ start(): Promise<InitSessionResult>;
155
+ sendMessage(text: string): void;
156
+ sendUserMessage(message: {
157
+ text: string;
158
+ images?: Array<{
159
+ type: "base64";
160
+ data: string;
161
+ mediaType: string;
162
+ }>;
163
+ }): void;
164
+ setMode(level: DroidAutonomyLevel): void;
165
+ setModel(modelId: string): void;
166
+ onNotification(handler: (notification: DroidNotification) => void | Promise<void>): void;
167
+ onRawEvent(handler: (event: unknown) => void | Promise<void>): void;
168
+ onRequest(handler: (method: string, params: unknown) => Promise<PermissionResponse>): void;
169
+ onExit(handler: (code: number | null) => void): void;
170
+ stop(): Promise<void>;
171
+ isRunning(): boolean;
172
+ getSessionId(): string | null;
173
+ }
174
+ declare function createDroidAdapter(options: DroidAdapterOptions): DroidAdapter;
175
+ //#endregion
176
+ export { ACP_MODES, type AcpModeId, type AvailableModel, DroidAcpAgent, type DroidAdapter, type DroidAdapterOptions, type DroidAutonomyLevel, type DroidNotification, type FactoryMessage, type FactoryNotification, type FactoryRequest, type FactoryResponse, type InitSessionResult, type Logger, Pushable, createDroidAdapter, findDroidExecutable, isWindows, runAcp };
177
+ //# sourceMappingURL=lib.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.d.mts","names":[],"sources":["../src/utils.ts","../src/acp-agent.ts","../src/types.ts","../src/droid-adapter.ts"],"sourcesContent":[],"mappings":";;;;UAGiB,MAAA;;EAAA,KAAA,EAAA,CAAA,GAAM,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA;AAKvB;AAAkD,cAArC,QAAqC,CAAA,CAAA,CAAA,YAAd,aAAc,CAAA,CAAA,CAAA,CAAA;EAKrC,QAAA,KAAA;EAiB6B,QAAA,SAAA;EAAd,QAAA,IAAA;EAAzB,IAAO,CAAA,IAAA,EAjBG,CAiBH,CAAA,EAAA,IAAA;EAtB0B,GAAA,CAAA,CAAA,EAAA,IAAA;EAAa,CAsB9C,MAAA,CAAO,aAAA,GAtBuC,EAsBrB,aAtBqB,CAsBP,CAtBO,CAAA;AAmFjD;ACuCA;AAKsB,cD5CT,SC4CS,EAAA,OAAA;;;;;;AA4BsC,iBDjE5C,mBAAA,CAAA,CCiE4C,EAAA,MAAA;;;cAjC/C,aAAA,YAAyB;;ED/HrB,QAAA,MAAM;EAKV,QAAA,MAAQ;EAA6B,WAAA,CAAA,MAAA,EC+H5B,mBD/H4B,EAAA,MAAA,CAAA,EC+HE,MD/HF;EAKrC,UAAA,CAAA,QAAA,ECgIgB,iBDhIhB,CAAA,ECgIoC,ODhIpC,CCgI4C,kBDhI5C,CAAA;EAiB6B,YAAA,CAAA,OAAA,ECqIZ,mBDrIY,CAAA,ECqIU,ODrIV,CCqIkB,oBDrIlB,CAAA;EAAd,UAAA,CAAA,OAAA,ECgJA,iBDhJA,CAAA,ECgJoB,ODhJpB,CCgJ4B,kBDhJ5B,CAAA;EAAzB,MAAO,CAAA,OAAA,EC4Qc,aD5Qd,CAAA,EC4Q8B,OD5Q9B,CC4QsC,cD5QtC,CAAA;EAtB0B,MAAA,CAAA,OAAA,EC4YZ,kBD5YY,CAAA,EC4YS,OD5YT,CAAA,IAAA,CAAA;EAAa,wBAAA,CAAA,OAAA,EC2ZpC,sBD3ZoC,CAAA,EC4Z5C,OD5Z4C,CC4ZpC,uBD5ZoC,GAAA,IAAA,CAAA;EAmFpC,cAAwC,CAAA,OAAA,ECkVrB,qBDlVqB,CAAA,ECkVG,ODlVH,CCkVW,sBDlVX,CAAA;EAOrC,QAAA,kBAAmB;;;;ECgCtB,QAAA,kBAAc;EAKL,QAAA,gBAAA;EAA8B,QAAA,6BAAA;EAMvB,QAAA,wBAAA;EAA4B,QAAA,mBAAA;EAAR,QAAA,gBAAA;EAsBnB,QAAA,kBAAA;EAA8B,OAAA,CAAA,CAAA,EAm5CzC,OAn5CyC,CAAA,IAAA,CAAA;;AAWhC,iBAg5CZ,MAAA,CAAA,CAh5CY,EAAA,IAAA;;;;;;KCzKhB,SAAA;AFFK,cEGJ,SFHU,EEGC,SFHD,EAAA;AAKV,KECD,kBAAA,GFDS,QAAA,GAAA,MAAA,GAAA,UAAA,GAAA,aAAA,GAAA,WAAA,GAAA,SAAA,GAAA,MAAA;AAA6B,UEWjC,cAAA,CFXiC;EAKrC,OAAA,EAAA,KAAA;EAiB6B,iBAAA,EAAA,OAAA;EAAd,IAAA,EAAA,SAAA;EAAzB,MAAO,EAAA,MAAA;EAtB0B,MAAA,EEgB1B,MFhB0B,CAAA,MAAA,EAAA,OAAA,CAAA;EAAa,EAAA,EAAA,MAAA;AAmFjD;AAOgB,UEtEC,eAAA,CFsEkB;;;;ECgCtB,EAAA,EAAA,MAAA;EAKS,MAAA,CAAA,ECtGX,MDsGW,CAAA,MAAA,EAAA,OAAA,CAAA;EAA8B,KAAA,CAAA,EAAA;IAMvB,IAAA,EAAA,MAAA;IAA4B,OAAA,EAAA,MAAA;EAAR,CAAA;;AAsBW,UC3H3C,mBAAA,CD2H2C;EAAR,OAAA,EAAA,KAAA;EAWxB,IAAA,EAAA,cAAA;EAA4B,iBAAA,EAAA,OAAA;EAAR,MAAA,EAAA,MAAA;EA4HxB,MAAA,EC7Pd,MD6Pc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAgB,KC1P5B,cAAA,GAAiB,cD0PW,GC1PM,eD0PN,GC1PwB,mBD0PxB;AA0GhB,UClWP,cAAA,CDkWO;EAAqB,EAAA,EAAA,MAAA;EAehC,OAAA,CAAA,EAAA,MAAA;EACA,aAAA,EAAA,MAAA;EAAR,WAAA,EAAA,MAAA;EAS2B,gBAAA,CAAA,EAAA,MAAA;EAAgC,yBAAA,EAAA,MAAA,EAAA;EAAR,sBAAA,EAAA,MAAA;EAyoCrC,QAAA,EAAA,OAAA;EAp7CmB,cAAA,CAAA,EAAA,OAAA;;AA47CtB,UChgDC,iBAAA,CDggDK;;;;ECzjDV,CAAA;EACC,QAAA,CAAA,EAAA;IAGD,OAAA,EAAA,MAAA;IAUK,eAAc,CAAA,EAAA,MAKrB;IAIO,aAAA,CAAe,EAAA,MAAA;EAYf,CAAA;EAQL,eAAA,EAsBO,cAtBO,EAAA;;AAAoB,KAyBlC,iBAAA,GAzBkC;EAAkB,IAAA,EAAA,eAAA;EAAmB,KAAA,EAAA,MAAA,GAAA,6BAAA;AAEnF,CAAA,GAAiB;EAYA,IAAA,EAAA,kBAAiB;EAWtB,QAAA,EAAA;IA6CK,OAAA,CAAA,EAAA,MAAA;;;;ICzGA,uBAAmB,CAAA,EAAA,MAEzB;EAGM,CAAA;CACE,GAAA;EAAR,IAAA,EAAA,aAAA;EAIE,SAAA,EAAA,MAAA;EAEI,OAAA,EAAA,MAAA;EAEwB,OAAA,EAAA,OAAA;CAA6B,GAAA;EACrB,IAAA,EAAA,SAAA;EACiB,IAAA,EAAA,MAAA,GAAA,WAAA,GAAA,QAAA;EAAR,IAAA,CAAA,EAAA,MAAA;EAEhD,EAAA,EAAA,MAAA;EAAO,OAAA,CAAA,EAAA;IAKD,EAAA,EAAA,MAAA;;;;;;;;;;UDkFC,kBAAA;;;;;UCzGA,mBAAA;;EHVA,MAAA,CAAA,EGYN,MHZY;AAKvB;AAAkD,UGUjC,YAAA,CHViC;EAKrC,KAAA,EAAA,EGMF,OHNE,CGMM,iBHNN,CAAA;EAiB6B,WAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAAd,eAAA,CAAA,OAAA,EAAA;IAAlB,IAAA,EAAA,MAAA;IAtB0B,MAAA,CAAA,EGevB,KHfuB,CAAA;MAAa,IAAA,EAAA,QAAA;MAmFpC,IAAwC,EAAA,MAAA;MAOrC,SAAA,EAAA,MAAmB;;;iBGzElB;EFyGJ,QAAA,CAAA,OAAc,EAAA,MAAA,CAAA,EAAA,IAAA;EAKL,cAAA,CAAA,OAAA,EAAA,CAAA,YAAA,EE5GmB,iBF4GnB,EAAA,GAAA,IAAA,GE5GgD,OF4GhD,CAAA,IAAA,CAAA,CAAA,EAAA,IAAA;EAA8B,UAAA,CAAA,OAAA,EAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,IAAA,GE3GH,OF2GG,CAAA,IAAA,CAAA,CAAA,EAAA,IAAA;EAMvB,SAAA,CAAA,OAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,EAAA,GEhH6B,OFgH7B,CEhHqC,kBFgHrC,CAAA,CAAA,EAAA,IAAA;EAA4B,MAAA,CAAA,OAAA,EAAA,CAAA,IAAA,EAAA,MAAA,GAAA,IAAA,EAAA,GAAA,IAAA,CAAA,EAAA,IAAA;EAAR,IAAA,EAAA,EE9GvC,OF8GuC,CAAA,IAAA,CAAA;EAsBnB,SAAA,EAAA,EAAA,OAAA;EAA8B,YAAA,EAAA,EAAA,MAAA,GAAA,IAAA;;AAWhC,iBE1IZ,kBAAA,CF0IY,OAAA,EE1IgB,mBF0IhB,CAAA,EE1IsC,YF0ItC"}
package/dist/lib.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { a as Pushable, i as createDroidAdapter, n as runAcp, o as findDroidExecutable, r as ACP_MODES, s as isWindows, t as DroidAcpAgent } from "./acp-agent-Ddz1S3Jm.mjs";
2
+
3
+ export { ACP_MODES, DroidAcpAgent, Pushable, createDroidAdapter, findDroidExecutable, isWindows, runAcp };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "droid-acp",
3
+ "version": "0.1.0",
4
+ "description": "ACP adapter for Droid - Factory's AI coding agent",
5
+ "type": "module",
6
+ "main": "dist/lib.mjs",
7
+ "types": "dist/lib.d.mts",
8
+ "bin": {
9
+ "droid-acp": "./dist/index.mjs"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "npx tsdown",
16
+ "dev": "npx tsdown --watch",
17
+ "start": "node dist/index.mjs",
18
+ "lint": "oxlint --type-aware --type-check",
19
+ "lint:fix": "oxlint --fix",
20
+ "format": "oxfmt",
21
+ "format:check": "oxfmt --check",
22
+ "check": "npm run lint && npm run format:check",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "droid",
27
+ "acp",
28
+ "agent",
29
+ "factory",
30
+ "typescript",
31
+ "code"
32
+ ],
33
+ "author": "",
34
+ "license": "Apache-2.0",
35
+ "dependencies": {
36
+ "@agentclientprotocol/sdk": "^0.12.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.19.3",
40
+ "oxfmt": "^0.17.0",
41
+ "oxlint": "^1.32.0",
42
+ "oxlint-tsgolint": "^0.10.0",
43
+ "tsdown": "^0.17.4",
44
+ "typescript": "^5.9.3"
45
+ },
46
+ "engines": {
47
+ "node": ">=22.0.0"
48
+ }
49
+ }