@zed-industries/claude-code-acp
Advanced tools
| import { Agent, AgentSideConnection, AuthenticateRequest, CancelNotification, ClientCapabilities, ForkSessionRequest, ForkSessionResponse, InitializeRequest, InitializeResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, ReadTextFileRequest, ReadTextFileResponse, ResumeSessionRequest, ResumeSessionResponse, SessionNotification, SetSessionModelRequest, SetSessionModelResponse, SetSessionModeRequest, SetSessionModeResponse, TerminalHandle, TerminalOutputResponse, WriteTextFileRequest, WriteTextFileResponse } from "@agentclientprotocol/sdk"; | ||
| import { SettingsManager } from "./settings.js"; | ||
| import { CanUseTool, Options, PermissionMode, Query, SDKPartialAssistantMessage, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk"; | ||
| import { Pushable } from "./utils.js"; | ||
| import { ContentBlockParam } from "@anthropic-ai/sdk/resources"; | ||
| import { BetaContentBlock, BetaRawContentBlockDelta } from "@anthropic-ai/sdk/resources/beta.mjs"; | ||
| export declare const CLAUDE_CONFIG_DIR: string; | ||
| /** | ||
| * Logger interface for customizing logging output | ||
| */ | ||
| export interface Logger { | ||
| log: (...args: any[]) => void; | ||
| error: (...args: any[]) => void; | ||
| } | ||
| type Session = { | ||
| query: Query; | ||
| input: Pushable<SDKUserMessage>; | ||
| cancelled: boolean; | ||
| permissionMode: PermissionMode; | ||
| settingsManager: SettingsManager; | ||
| }; | ||
| type BackgroundTerminal = { | ||
| handle: TerminalHandle; | ||
| status: "started"; | ||
| lastOutput: TerminalOutputResponse | null; | ||
| } | { | ||
| status: "aborted" | "exited" | "killed" | "timedOut"; | ||
| pendingOutput: TerminalOutputResponse; | ||
| }; | ||
| /** | ||
| * Extra metadata that can be given to Claude Code when creating a new session. | ||
| */ | ||
| export type NewSessionMeta = { | ||
| claudeCode?: { | ||
| /** | ||
| * Options forwarded to Claude Code when starting a new session. | ||
| * Those parameters will be ignored and managed by ACP: | ||
| * - cwd | ||
| * - includePartialMessages | ||
| * - allowDangerouslySkipPermissions | ||
| * - permissionMode | ||
| * - canUseTool | ||
| * - executable | ||
| * Those parameters will be used and updated to work with ACP: | ||
| * - hooks (merged with ACP's hooks) | ||
| * - mcpServers (merged with ACP's mcpServers) | ||
| */ | ||
| options?: Options; | ||
| }; | ||
| }; | ||
| /** | ||
| * Extra metadata that the agent provides for each tool_call / tool_update update. | ||
| */ | ||
| export type ToolUpdateMeta = { | ||
| claudeCode?: { | ||
| toolName: string; | ||
| toolResponse?: unknown; | ||
| }; | ||
| }; | ||
| type ToolUseCache = { | ||
| [key: string]: { | ||
| type: "tool_use" | "server_tool_use" | "mcp_tool_use"; | ||
| id: string; | ||
| name: string; | ||
| input: any; | ||
| }; | ||
| }; | ||
| export declare class ClaudeAcpAgent implements Agent { | ||
| sessions: { | ||
| [key: string]: Session; | ||
| }; | ||
| client: AgentSideConnection; | ||
| toolUseCache: ToolUseCache; | ||
| backgroundTerminals: { | ||
| [key: string]: BackgroundTerminal; | ||
| }; | ||
| clientCapabilities?: ClientCapabilities; | ||
| logger: Logger; | ||
| constructor(client: AgentSideConnection, logger?: Logger); | ||
| initialize(request: InitializeRequest): Promise<InitializeResponse>; | ||
| newSession(params: NewSessionRequest): Promise<NewSessionResponse>; | ||
| unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse>; | ||
| unstable_resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse>; | ||
| authenticate(_params: AuthenticateRequest): Promise<void>; | ||
| prompt(params: PromptRequest): Promise<PromptResponse>; | ||
| cancel(params: CancelNotification): Promise<void>; | ||
| unstable_setSessionModel(params: SetSessionModelRequest): Promise<SetSessionModelResponse | void>; | ||
| setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse>; | ||
| readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>; | ||
| writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>; | ||
| canUseTool(sessionId: string): CanUseTool; | ||
| private createSession; | ||
| } | ||
| export declare function promptToClaude(prompt: PromptRequest): SDKUserMessage; | ||
| /** | ||
| * Convert an SDKAssistantMessage (Claude) to a SessionNotification (ACP). | ||
| * Only handles text, image, and thinking chunks for now. | ||
| */ | ||
| export declare function toAcpNotifications(content: string | ContentBlockParam[] | BetaContentBlock[] | BetaRawContentBlockDelta[], role: "assistant" | "user", sessionId: string, toolUseCache: ToolUseCache, client: AgentSideConnection, logger: Logger): SessionNotification[]; | ||
| export declare function streamEventToAcpNotifications(message: SDKPartialAssistantMessage, sessionId: string, toolUseCache: ToolUseCache, client: AgentSideConnection, logger: Logger): SessionNotification[]; | ||
| export declare function runAcp(): void; | ||
| export {}; | ||
| //# sourceMappingURL=acp-agent.d.ts.map |
| {"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"} |
| #!/usr/bin/env node | ||
| export {}; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""} |
| export { ClaudeAcpAgent, runAcp, toAcpNotifications, streamEventToAcpNotifications, type ToolUpdateMeta, type NewSessionMeta, } from "./acp-agent.js"; | ||
| export { loadManagedSettings, applyEnvironmentSettings, nodeToWebReadable, nodeToWebWritable, Pushable, unreachable, } from "./utils.js"; | ||
| export { createMcpServer } from "./mcp-server.js"; | ||
| export { toolInfoFromToolUse, planEntries, toolUpdateFromToolResult, createPreToolUseHook, acpToolNames as toolNames, } from "./tools.js"; | ||
| export { SettingsManager, type ClaudeCodeSettings, type PermissionSettings, type PermissionDecision, type PermissionCheckResult, type SettingsManagerOptions, } from "./settings.js"; | ||
| export type { ClaudePlanEntry } from "./tools.js"; | ||
| //# sourceMappingURL=lib.d.ts.map |
| {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EACd,MAAM,EACN,kBAAkB,EAClB,6BAA6B,EAC7B,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,EACR,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,wBAAwB,EACxB,oBAAoB,EACpB,YAAY,IAAI,SAAS,GAC1B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"} |
| import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | ||
| import { ClaudeAcpAgent } from "./acp-agent.js"; | ||
| import { ClientCapabilities } from "@agentclientprotocol/sdk"; | ||
| export declare const SYSTEM_REMINDER = "\n\n<system-reminder>\nWhenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.\n</system-reminder>"; | ||
| export declare function createMcpServer(agent: ClaudeAcpAgent, sessionId: string, clientCapabilities: ClientCapabilities | undefined): McpServer; | ||
| /** | ||
| * Replace text in a file and calculate the line numbers where the edits occurred. | ||
| * | ||
| * @param fileContent - The full file content | ||
| * @param edits - Array of edit operations to apply sequentially | ||
| * @returns the new content and the line numbers where replacements occurred in the final content | ||
| */ | ||
| export declare function replaceAndCalculateLocation(fileContent: string, edits: Array<{ | ||
| oldText: string; | ||
| newText: string; | ||
| replaceAll?: boolean; | ||
| }>): { | ||
| newContent: string; | ||
| lineNumbers: number[]; | ||
| }; | ||
| //# sourceMappingURL=mcp-server.d.ts.map |
| {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,OAAO,EAAqB,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EACL,kBAAkB,EAGnB,MAAM,0BAA0B,CAAC;AAQlC,eAAO,MAAM,eAAe,iSAIT,CAAC;AA2BpB,wBAAgB,eAAe,CAC7B,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,GACjD,SAAS,CA2nBX;AA+DD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,KAAK,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC,GACD;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAyF/C"} |
| /** | ||
| * Permission rule format examples: | ||
| * - "Read" - matches all Read tool calls | ||
| * - "Read(./.env)" - matches specific path | ||
| * - "Read(./.env.*)" - glob pattern | ||
| * - "Read(./secrets/**)" - recursive glob | ||
| * - "Bash(npm run lint)" - exact command prefix | ||
| * - "Bash(npm run:*)" - command prefix with wildcard | ||
| * | ||
| * Docs: https://code.claude.com/docs/en/iam#tool-specific-permission-rules | ||
| */ | ||
| export interface PermissionSettings { | ||
| allow?: string[]; | ||
| deny?: string[]; | ||
| ask?: string[]; | ||
| additionalDirectories?: string[]; | ||
| defaultMode?: string; | ||
| } | ||
| export interface ClaudeCodeSettings { | ||
| permissions?: PermissionSettings; | ||
| env?: Record<string, string>; | ||
| } | ||
| export type PermissionDecision = "allow" | "deny" | "ask"; | ||
| export interface PermissionCheckResult { | ||
| decision: PermissionDecision; | ||
| rule?: string; | ||
| source?: "allow" | "deny" | "ask"; | ||
| } | ||
| /** | ||
| * Gets the enterprise settings path based on the current platform | ||
| */ | ||
| export declare function getManagedSettingsPath(): string; | ||
| export interface SettingsManagerOptions { | ||
| onChange?: () => void; | ||
| logger?: { | ||
| log: (...args: any[]) => void; | ||
| error: (...args: any[]) => void; | ||
| }; | ||
| } | ||
| /** | ||
| * Manages Claude Code settings from multiple sources with proper precedence. | ||
| * | ||
| * Settings are loaded from (in order of increasing precedence): | ||
| * 1. User settings (~/.claude/settings.json) | ||
| * 2. Project settings (<cwd>/.claude/settings.json) | ||
| * 3. Local project settings (<cwd>/.claude/settings.local.json) | ||
| * 4. Enterprise managed settings (platform-specific path) | ||
| * | ||
| * The manager watches all settings files for changes and automatically reloads. | ||
| */ | ||
| export declare class SettingsManager { | ||
| private cwd; | ||
| private userSettings; | ||
| private projectSettings; | ||
| private localSettings; | ||
| private enterpriseSettings; | ||
| private mergedSettings; | ||
| private watchers; | ||
| private onChange?; | ||
| private logger; | ||
| private initialized; | ||
| private debounceTimer; | ||
| constructor(cwd: string, options?: SettingsManagerOptions); | ||
| /** | ||
| * Initialize the settings manager by loading all settings and setting up file watchers | ||
| */ | ||
| initialize(): Promise<void>; | ||
| /** | ||
| * Returns the path to the user settings file | ||
| */ | ||
| private getUserSettingsPath; | ||
| /** | ||
| * Returns the path to the project settings file | ||
| */ | ||
| private getProjectSettingsPath; | ||
| /** | ||
| * Returns the path to the local project settings file | ||
| */ | ||
| private getLocalSettingsPath; | ||
| /** | ||
| * Loads settings from all sources | ||
| */ | ||
| private loadAllSettings; | ||
| /** | ||
| * Merges all settings sources with proper precedence. | ||
| * For permissions, rules from all sources are combined. | ||
| * Deny rules always take precedence during permission checks. | ||
| */ | ||
| private mergeSettings; | ||
| /** | ||
| * Sets up file watchers for all settings files | ||
| */ | ||
| private setupWatchers; | ||
| /** | ||
| * Handles settings file changes with debouncing to avoid rapid reloads | ||
| */ | ||
| private handleSettingsChange; | ||
| /** | ||
| * Checks if a tool invocation is allowed based on the loaded settings. | ||
| * | ||
| * @param toolName - The tool name (can be ACP-prefixed like mcp__acp__Read or plain like Read) | ||
| * @param toolInput - The tool input object | ||
| * @returns The permission decision and matching rule info | ||
| */ | ||
| checkPermission(toolName: string, toolInput: unknown): PermissionCheckResult; | ||
| /** | ||
| * Returns the current merged settings | ||
| */ | ||
| getSettings(): ClaudeCodeSettings; | ||
| /** | ||
| * Returns the current working directory | ||
| */ | ||
| getCwd(): string; | ||
| /** | ||
| * Updates the working directory and reloads project-specific settings | ||
| */ | ||
| setCwd(cwd: string): Promise<void>; | ||
| /** | ||
| * Disposes of file watchers and cleans up resources | ||
| */ | ||
| dispose(): void; | ||
| } | ||
| //# sourceMappingURL=settings.d.ts.map |
| {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;CACnC;AAuLD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAW/C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAC7E;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,MAAM,CAAqE;IACnF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAA8C;gBAEvD,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAMzD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;YACW,eAAe;IAgB7B;;;;OAIG;IACH,OAAO,CAAC,aAAa;IA8CrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAgB5B;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,qBAAqB;IAuC5E;;OAEG;IACH,WAAW,IAAI,kBAAkB;IAIjC;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"} |
| export {}; | ||
| //# sourceMappingURL=acp-agent.test.d.ts.map |
| {"version":3,"file":"acp-agent.test.d.ts","sourceRoot":"","sources":["../../src/tests/acp-agent.test.ts"],"names":[],"mappings":""} |
| export {}; | ||
| //# sourceMappingURL=extract-lines.test.d.ts.map |
| {"version":3,"file":"extract-lines.test.d.ts","sourceRoot":"","sources":["../../src/tests/extract-lines.test.ts"],"names":[],"mappings":""} |
| export {}; | ||
| //# sourceMappingURL=replace-and-calculate-location.test.d.ts.map |
| {"version":3,"file":"replace-and-calculate-location.test.d.ts","sourceRoot":"","sources":["../../src/tests/replace-and-calculate-location.test.ts"],"names":[],"mappings":""} |
| export {}; | ||
| //# sourceMappingURL=settings.test.d.ts.map |
| {"version":3,"file":"settings.test.d.ts","sourceRoot":"","sources":["../../src/tests/settings.test.ts"],"names":[],"mappings":""} |
| export {}; | ||
| //# sourceMappingURL=typescript-declarations.test.d.ts.map |
| {"version":3,"file":"typescript-declarations.test.d.ts","sourceRoot":"","sources":["../../src/tests/typescript-declarations.test.ts"],"names":[],"mappings":""} |
| import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from "vitest"; | ||
| import * as fs from "node:fs"; | ||
| import * as path from "node:path"; | ||
| import * as os from "node:os"; | ||
| import { spawnSync } from "child_process"; | ||
| describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("TypeScript declaration files integration", () => { | ||
| let tempDir; | ||
| let tarballPath; | ||
| const projectRoot = path.resolve(__dirname, "../.."); | ||
| // Base configuration templates | ||
| const basePackageJson = { | ||
| name: "ts-declaration-test", | ||
| version: "1.0.0", | ||
| type: "module", | ||
| dependencies: {}, | ||
| devDependencies: { | ||
| typescript: "5.9.3", | ||
| "@types/node": "25.0.3", | ||
| }, | ||
| }; | ||
| const baseTsConfig = { | ||
| compilerOptions: { | ||
| target: "ES2020", | ||
| module: "NodeNext", | ||
| moduleResolution: "NodeNext", | ||
| lib: ["ES2020"], | ||
| strict: true, | ||
| esModuleInterop: true, | ||
| skipLibCheck: true, // Skip checking dependency internals, focus on our types | ||
| noEmit: true, | ||
| declaration: false, | ||
| }, | ||
| include: ["*.ts"], | ||
| }; | ||
| // Build and pack the package once for all tests | ||
| beforeAll(async () => { | ||
| // Step 1: Clean dist folder to ensure fresh build | ||
| const distPath = path.join(projectRoot, "dist"); | ||
| await fs.promises.rm(distPath, { recursive: true, force: true }); | ||
| console.log("Cleaned dist folder"); | ||
| console.log("Building package..."); | ||
| // Step 2: Build the package | ||
| const buildResult = spawnSync("npm", ["run", "build"], { | ||
| cwd: projectRoot, | ||
| stdio: "pipe", | ||
| encoding: "utf-8", | ||
| }); | ||
| if (buildResult.status !== 0) { | ||
| throw new Error(`Build failed: ${buildResult.stderr || buildResult.stdout}`); | ||
| } | ||
| console.log("Packing package..."); | ||
| // Step 3: Pack to create tarball | ||
| const packResult = spawnSync("npm", ["pack", "--pack-destination", os.tmpdir()], { | ||
| cwd: projectRoot, | ||
| stdio: "pipe", | ||
| encoding: "utf-8", | ||
| }); | ||
| if (packResult.status !== 0) { | ||
| throw new Error(`Pack failed: ${packResult.stderr || packResult.stdout}`); | ||
| } | ||
| // Get the tarball filename from stdout (npm pack outputs the filename) | ||
| const tarballName = packResult.stdout.trim().split("\n").pop(); | ||
| if (!tarballName) { | ||
| throw new Error("Failed to get tarball name from npm pack output"); | ||
| } | ||
| tarballPath = path.join(os.tmpdir(), tarballName); | ||
| console.log(`Tarball created at: ${tarballPath}`); | ||
| }, 60000); // 60 second timeout for build | ||
| // Clean up the tarball after all tests | ||
| afterAll(async () => { | ||
| if (tarballPath && fs.existsSync(tarballPath)) { | ||
| await fs.promises.unlink(tarballPath); | ||
| console.log("Cleaned up tarball"); | ||
| } | ||
| }); | ||
| // Create fresh temp directory for each test | ||
| beforeEach(async () => { | ||
| tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "ts-declaration-test-")); | ||
| }); | ||
| // Clean up temp directory after each test | ||
| afterEach(async () => { | ||
| if (tempDir) { | ||
| await fs.promises.rm(tempDir, { recursive: true, force: true }); | ||
| } | ||
| }); | ||
| // Helper function to set up a test TypeScript project | ||
| async function setupTestProject(packageJson = basePackageJson, tsconfig = baseTsConfig) { | ||
| // Write package.json | ||
| await fs.promises.writeFile(path.join(tempDir, "package.json"), JSON.stringify(packageJson, null, 2)); | ||
| // Write tsconfig.json | ||
| await fs.promises.writeFile(path.join(tempDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2)); | ||
| // Install all dependencies (TypeScript, @types/node, and the tarball) | ||
| console.log(`Installing dependencies in ${tempDir}...`); | ||
| const installResult = spawnSync("npm", ["install", tarballPath], { | ||
| cwd: tempDir, | ||
| stdio: "pipe", | ||
| encoding: "utf-8", | ||
| timeout: 60000, // 60 second timeout | ||
| }); | ||
| if (installResult.status !== 0) { | ||
| throw new Error(`npm install failed: ${installResult.stderr || installResult.stdout}`); | ||
| } | ||
| } | ||
| // Helper function to run TypeScript type checking | ||
| function runTypeCheck(srcDir = tempDir) { | ||
| const result = spawnSync("npx", ["tsc", "--noEmit"], { | ||
| cwd: srcDir, | ||
| stdio: "pipe", | ||
| encoding: "utf-8", | ||
| timeout: 30000, // 30 second timeout | ||
| }); | ||
| return { | ||
| success: result.status === 0, | ||
| output: result.stdout + result.stderr, | ||
| }; | ||
| } | ||
| // Helper function to write a test TypeScript file | ||
| async function writeTestFile(filename, content) { | ||
| await fs.promises.writeFile(path.join(tempDir, filename), content); | ||
| } | ||
| // Test 1: Main exports import verification | ||
| it("should successfully type-check main exports", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-main-exports.ts", ` | ||
| import { | ||
| ClaudeAcpAgent, | ||
| runAcp, | ||
| toAcpNotifications, | ||
| streamEventToAcpNotifications, | ||
| SettingsManager, | ||
| createMcpServer, | ||
| loadManagedSettings, | ||
| applyEnvironmentSettings, | ||
| nodeToWebReadable, | ||
| nodeToWebWritable, | ||
| Pushable, | ||
| unreachable, | ||
| toolInfoFromToolUse, | ||
| planEntries, | ||
| toolUpdateFromToolResult, | ||
| createPreToolUseHook, | ||
| toolNames, | ||
| } from "@zed-industries/claude-code-acp"; | ||
| // Type-only imports | ||
| import type { | ||
| ToolUpdateMeta, | ||
| NewSessionMeta, | ||
| ClaudeCodeSettings, | ||
| PermissionSettings, | ||
| PermissionDecision, | ||
| PermissionCheckResult, | ||
| SettingsManagerOptions, | ||
| ClaudePlanEntry, | ||
| } from "@zed-industries/claude-code-acp"; | ||
| // Verify exports exist and have expected types | ||
| const _runAcp: typeof runAcp = runAcp; | ||
| const _createMcpServer: typeof createMcpServer = createMcpServer; | ||
| const _toolNames: typeof toolNames = toolNames; | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 2: Deep imports verification (backwards compatibility) | ||
| it("should successfully type-check deep imports", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-deep-imports.ts", ` | ||
| // Deep import from dist/tools.js | ||
| import { | ||
| acpToolNames, | ||
| EDIT_TOOL_NAMES, | ||
| ACP_TOOL_NAME_PREFIX, | ||
| toolInfoFromToolUse, | ||
| planEntries, | ||
| } from "@zed-industries/claude-code-acp/dist/tools.js"; | ||
| // Deep import from dist/settings.js | ||
| import { | ||
| SettingsManager, | ||
| getManagedSettingsPath, | ||
| } from "@zed-industries/claude-code-acp/dist/settings.js"; | ||
| // Deep import from dist/utils.js | ||
| import { | ||
| Pushable, | ||
| nodeToWebReadable, | ||
| nodeToWebWritable, | ||
| loadManagedSettings, | ||
| } from "@zed-industries/claude-code-acp/dist/utils.js"; | ||
| // Verify types work | ||
| const prefix: string = ACP_TOOL_NAME_PREFIX; | ||
| const editTools: readonly string[] = EDIT_TOOL_NAMES; | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 3: SettingsManager type shape verification | ||
| it("should verify SettingsManager has correct type shape", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-settings-manager.ts", ` | ||
| import { | ||
| SettingsManager, | ||
| ClaudeCodeSettings, | ||
| PermissionCheckResult, | ||
| SettingsManagerOptions | ||
| } from "@zed-industries/claude-code-acp"; | ||
| // Test constructor signature | ||
| const options: SettingsManagerOptions = { | ||
| onChange: () => {}, | ||
| logger: { log: console.log, error: console.error }, | ||
| }; | ||
| declare const cwd: string; | ||
| const manager = new SettingsManager(cwd, options); | ||
| // Test method signatures | ||
| async function testMethods() { | ||
| // initialize returns Promise<void> | ||
| await manager.initialize(); | ||
| // checkPermission returns PermissionCheckResult | ||
| const result: PermissionCheckResult = manager.checkPermission( | ||
| "mcp__acp__Read", | ||
| { file_path: "/some/path" } | ||
| ); | ||
| // Verify decision type | ||
| const decision: "allow" | "deny" | "ask" = result.decision; | ||
| const rule: string | undefined = result.rule; | ||
| const source: "allow" | "deny" | "ask" | undefined = result.source; | ||
| // getSettings returns ClaudeCodeSettings | ||
| const settings: ClaudeCodeSettings = manager.getSettings(); | ||
| // getCwd returns string | ||
| const currentCwd: string = manager.getCwd(); | ||
| // setCwd returns Promise<void> | ||
| await manager.setCwd("/new/path"); | ||
| // dispose returns void | ||
| manager.dispose(); | ||
| } | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 4: ClaudeAcpAgent instantiation and type verification | ||
| it("should verify ClaudeAcpAgent has correct type shape", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-claude-acp-agent.ts", ` | ||
| import { ClaudeAcpAgent } from "@zed-industries/claude-code-acp"; | ||
| import type { AgentSideConnection } from "@agentclientprotocol/sdk"; | ||
| // ClaudeAcpAgent should be a class that can be instantiated | ||
| declare const mockConnection: AgentSideConnection; | ||
| declare const mockLogger: { log: (...args: any[]) => void; error: (...args: any[]) => void }; | ||
| // Test constructor - accepts AgentSideConnection and optional logger | ||
| const agent = new ClaudeAcpAgent(mockConnection, mockLogger); | ||
| // Verify it has sessions property | ||
| const sessions: Record<string, any> = agent.sessions; | ||
| // Verify it has client property | ||
| const client: AgentSideConnection = agent.client; | ||
| // Verify it has logger property | ||
| const logger = agent.logger; | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 5: Type-only exports work correctly | ||
| it("should verify type-only exports are usable", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-type-exports.ts", ` | ||
| import type { | ||
| ClaudeCodeSettings, | ||
| PermissionSettings, | ||
| PermissionDecision, | ||
| PermissionCheckResult, | ||
| SettingsManagerOptions, | ||
| ClaudePlanEntry, | ||
| ToolUpdateMeta, | ||
| NewSessionMeta, | ||
| } from "@zed-industries/claude-code-acp"; | ||
| // Test ClaudeCodeSettings shape | ||
| const settings: ClaudeCodeSettings = { | ||
| permissions: { | ||
| allow: ["Read"], | ||
| deny: ["Read(./.env)"], | ||
| ask: ["Bash"], | ||
| additionalDirectories: ["/extra"], | ||
| defaultMode: "default", | ||
| }, | ||
| env: { | ||
| API_KEY: "secret", | ||
| }, | ||
| }; | ||
| // Test PermissionSettings shape | ||
| const perms: PermissionSettings = { | ||
| allow: ["Read"], | ||
| deny: ["Write"], | ||
| }; | ||
| // Test PermissionDecision | ||
| const decisions: PermissionDecision[] = ["allow", "deny", "ask"]; | ||
| // Test ClaudePlanEntry shape | ||
| const planEntry: ClaudePlanEntry = { | ||
| content: "Do something", | ||
| status: "pending", | ||
| activeForm: "Doing something", | ||
| }; | ||
| // Test valid status values | ||
| const validStatuses: ClaudePlanEntry["status"][] = [ | ||
| "pending", | ||
| "in_progress", | ||
| "completed", | ||
| ]; | ||
| // Test ToolUpdateMeta shape | ||
| const toolMeta: ToolUpdateMeta = { | ||
| claudeCode: { | ||
| toolName: "Read", | ||
| toolResponse: { success: true }, | ||
| }, | ||
| }; | ||
| // Test NewSessionMeta shape | ||
| const sessionMeta: NewSessionMeta = { | ||
| claudeCode: { | ||
| options: {}, | ||
| }, | ||
| }; | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 6: Function signatures verification | ||
| it("should verify function signatures are correct", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-function-signatures.ts", ` | ||
| import { | ||
| runAcp, | ||
| createMcpServer, | ||
| toolInfoFromToolUse, | ||
| planEntries, | ||
| createPreToolUseHook, | ||
| loadManagedSettings, | ||
| applyEnvironmentSettings, | ||
| SettingsManager, | ||
| } from "@zed-industries/claude-code-acp"; | ||
| import type { ClaudeCodeSettings } from "@zed-industries/claude-code-acp"; | ||
| // runAcp should be a function with no parameters that returns void | ||
| const runAcpType: () => void = runAcp; | ||
| // toolInfoFromToolUse should accept any and return object with title and kind | ||
| const info = toolInfoFromToolUse({ name: "Read", input: {} }); | ||
| const title: string = info.title; | ||
| const kind: string = info.kind; | ||
| // planEntries should accept todos array and return array | ||
| const entries = planEntries({ | ||
| todos: [ | ||
| { content: "test", status: "pending", activeForm: "testing" } | ||
| ] | ||
| }); | ||
| // entries should be an array | ||
| const entriesArray: any[] = entries; | ||
| // createPreToolUseHook should accept SettingsManager and optional logger | ||
| declare const settingsManager: SettingsManager; | ||
| const hook = createPreToolUseHook(settingsManager, console); | ||
| // loadManagedSettings should return ClaudeCodeSettings | null | ||
| const managedSettings: ClaudeCodeSettings | null = loadManagedSettings(); | ||
| // applyEnvironmentSettings should accept ClaudeCodeSettings and return void | ||
| const applyResult: void = applyEnvironmentSettings({ permissions: {} }); | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 7: Pushable generic class verification | ||
| it("should verify Pushable class works correctly", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-pushable.ts", ` | ||
| import { Pushable } from "@zed-industries/claude-code-acp"; | ||
| // Pushable should be a generic class | ||
| const pushable = new Pushable<string>(); | ||
| // Should have push method | ||
| pushable.push("test"); | ||
| // Should have end method | ||
| pushable.end(); | ||
| // Should implement AsyncIterable | ||
| async function consume() { | ||
| for await (const item of pushable) { | ||
| const str: string = item; | ||
| } | ||
| } | ||
| // Generic type parameter should work | ||
| const numPushable = new Pushable<number>(); | ||
| numPushable.push(42); | ||
| interface MyType { id: number; name: string; } | ||
| const customPushable = new Pushable<MyType>(); | ||
| customPushable.push({ id: 1, name: "test" }); | ||
| `); | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| console.error("TypeScript errors:", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| // Test 8: Verify incorrect types fail | ||
| it("should fail type-check with incorrect types", async () => { | ||
| await setupTestProject(); | ||
| await writeTestFile("test-invalid-types.ts", ` | ||
| import { SettingsManager, ClaudeCodeSettings } from "@zed-industries/claude-code-acp"; | ||
| // This should fail - SettingsManager constructor requires string cwd | ||
| // @ts-expect-error - Testing that wrong argument type fails | ||
| const badManager = new SettingsManager(123); | ||
| // This should fail - ClaudeCodeSettings permissions must be an object | ||
| const badSettings: ClaudeCodeSettings = { | ||
| // @ts-expect-error - Testing that wrong type fails | ||
| permissions: "not-an-object", | ||
| }; | ||
| `); | ||
| // This test should PASS because we expect tsc to catch these errors | ||
| // with @ts-expect-error directives | ||
| const result = runTypeCheck(); | ||
| if (!result.success) { | ||
| // If it fails, it means @ts-expect-error didn't catch the error | ||
| // which could mean the types are too permissive | ||
| console.error("TypeScript errors (expected @ts-expect-error to catch):", result.output); | ||
| } | ||
| expect(result.success).toBe(true); | ||
| }, 120000); | ||
| }); |
| import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk"; | ||
| import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources"; | ||
| export declare const ACP_TOOL_NAME_PREFIX = "mcp__acp__"; | ||
| export declare const acpToolNames: { | ||
| read: string; | ||
| edit: string; | ||
| write: string; | ||
| bash: string; | ||
| killShell: string; | ||
| bashOutput: string; | ||
| }; | ||
| export declare const EDIT_TOOL_NAMES: string[]; | ||
| import { BetaBashCodeExecutionToolResultBlockParam, BetaCodeExecutionToolResultBlockParam, BetaRequestMCPToolResultBlockParam, BetaTextEditorCodeExecutionToolResultBlockParam, BetaToolSearchToolResultBlockParam, BetaWebFetchToolResultBlockParam, BetaWebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources/beta.mjs"; | ||
| import { HookCallback } from "@anthropic-ai/claude-agent-sdk"; | ||
| import { Logger } from "./acp-agent.js"; | ||
| import { SettingsManager } from "./settings.js"; | ||
| interface ToolInfo { | ||
| title: string; | ||
| kind: ToolKind; | ||
| content: ToolCallContent[]; | ||
| locations?: ToolCallLocation[]; | ||
| } | ||
| interface ToolUpdate { | ||
| title?: string; | ||
| content?: ToolCallContent[]; | ||
| locations?: ToolCallLocation[]; | ||
| } | ||
| export declare function toolInfoFromToolUse(toolUse: any): ToolInfo; | ||
| export declare function toolUpdateFromToolResult(toolResult: ToolResultBlockParam | BetaWebSearchToolResultBlockParam | BetaWebFetchToolResultBlockParam | WebSearchToolResultBlockParam | BetaCodeExecutionToolResultBlockParam | BetaBashCodeExecutionToolResultBlockParam | BetaTextEditorCodeExecutionToolResultBlockParam | BetaRequestMCPToolResultBlockParam | BetaToolSearchToolResultBlockParam, toolUse: any | undefined): ToolUpdate; | ||
| export type ClaudePlanEntry = { | ||
| content: string; | ||
| status: "pending" | "in_progress" | "completed"; | ||
| activeForm: string; | ||
| }; | ||
| export declare function planEntries(input: { | ||
| todos: ClaudePlanEntry[]; | ||
| }): PlanEntry[]; | ||
| export declare function markdownEscape(text: string): string; | ||
| export declare const registerHookCallback: (toolUseID: string, { onPostToolUseHook, }: { | ||
| onPostToolUseHook?: (toolUseID: string, toolInput: unknown, toolResponse: unknown) => Promise<void>; | ||
| }) => void; | ||
| export declare const createPostToolUseHook: (logger?: Logger) => HookCallback; | ||
| /** | ||
| * Creates a PreToolUse hook that checks permissions using the SettingsManager. | ||
| * This runs before the SDK's built-in permission rules, allowing us to enforce | ||
| * our own permission settings for ACP-prefixed tools. | ||
| */ | ||
| export declare const createPreToolUseHook: (settingsManager: SettingsManager, logger?: Logger) => HookCallback; | ||
| export {}; | ||
| //# sourceMappingURL=tools.d.ts.map |
| {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGlG,OAAO,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAWlG,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,YAAY;;;;;;;CAOxB,CAAC;AAEF,eAAO,MAAM,eAAe,UAA0C,CAAC;AAEvE,OAAO,EACL,yCAAyC,EACzC,qCAAqC,EACrC,kCAAkC,EAClC,+CAA+C,EAC/C,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,CA+V1D;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EACN,oBAAoB,GACpB,iCAAiC,GACjC,gCAAgC,GAChC,6BAA6B,GAC7B,qCAAqC,GACrC,yCAAyC,GACzC,+CAA+C,GAC/C,kCAAkC,GAClC,kCAAkC,EACtC,OAAO,EAAE,GAAG,GAAG,SAAS,GACvB,UAAU,CA4HZ;AAmCD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,SAAS,EAAE,CAM5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAcD,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,wBAEG;IACD,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,SAKF,CAAC;AAGF,eAAO,MAAM,qBAAqB,GAC/B,SAAQ,MAAgB,KAAG,YAa3B,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC9B,iBAAiB,eAAe,EAAE,SAAQ,MAAgB,KAAG,YA2C7D,CAAC"} |
| import { Readable, Writable } from "node:stream"; | ||
| import { WritableStream, ReadableStream } from "node:stream/web"; | ||
| import { Logger } from "./acp-agent.js"; | ||
| import { ClaudeCodeSettings } from "./settings.js"; | ||
| export declare class Pushable<T> implements AsyncIterable<T> { | ||
| private queue; | ||
| private resolvers; | ||
| private done; | ||
| push(item: T): void; | ||
| end(): void; | ||
| [Symbol.asyncIterator](): AsyncIterator<T>; | ||
| } | ||
| export declare function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array>; | ||
| export declare function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array>; | ||
| export declare function unreachable(value: never, logger?: Logger): void; | ||
| export declare function sleep(time: number): Promise<void>; | ||
| export declare function loadManagedSettings(): ClaudeCodeSettings | null; | ||
| export declare function applyEnvironmentSettings(settings: ClaudeCodeSettings): void; | ||
| export interface ExtractLinesResult { | ||
| content: string; | ||
| wasLimited: boolean; | ||
| linesRead: number; | ||
| } | ||
| /** | ||
| * Extracts lines from file content with byte limit enforcement. | ||
| * | ||
| * @param fullContent - The complete file content | ||
| * @param maxContentLength - Maximum number of UTF-16 Code Units to return | ||
| * @returns Object containing extracted content and metadata | ||
| */ | ||
| export declare function extractLinesWithByteLimit(fullContent: string, maxContentLength: number): ExtractLinesResult; | ||
| //# sourceMappingURL=utils.d.ts.map |
| {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAA0B,MAAM,eAAe,CAAC;AAG3E,qBAAa,QAAQ,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,IAAI,CAAS;IAErB,IAAI,CAAC,IAAI,EAAE,CAAC;IASZ,GAAG;IAQH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;CAgB3C;AAGD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAclF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAUlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAgB,QAQjE;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,GAAG,IAAI,CAM/D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAM3E;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,CA8CpB"} |
+15
-2
@@ -455,2 +455,6 @@ import { AgentSideConnection, ndJsonStream, RequestError, } from "@agentclientprotocol/sdk"; | ||
| } | ||
| // Configure thinking tokens from environment variable | ||
| const maxThinkingTokens = process.env.MAX_THINKING_TOKENS | ||
| ? parseInt(process.env.MAX_THINKING_TOKENS, 10) | ||
| : undefined; | ||
| const options = { | ||
@@ -460,2 +464,3 @@ systemPrompt, | ||
| stderr: (err) => this.logger.error(err), | ||
| ...(maxThinkingTokens !== undefined && { maxThinkingTokens }), | ||
| ...userProvidedOptions, | ||
@@ -478,2 +483,3 @@ // Override certain fields that must be controlled by ACP | ||
| }), | ||
| tools: { type: "preset", preset: "claude_code" }, | ||
| hooks: { | ||
@@ -497,3 +503,4 @@ ...userProvidedOptions?.hooks, | ||
| const allowedTools = []; | ||
| const disallowedTools = []; | ||
| // Disable this for now, not a great way to expose this over ACP at the moment (in progress work so we can revisit) | ||
| const disallowedTools = ["AskUserQuestion"]; | ||
| // Check if built-in tools should be disabled | ||
@@ -620,3 +627,9 @@ const disableBuiltInTools = params._meta?.disableBuiltInTools === true; | ||
| .map((command) => { | ||
| const input = command.argumentHint ? { hint: command.argumentHint } : null; | ||
| const input = command.argumentHint | ||
| ? { | ||
| hint: Array.isArray(command.argumentHint) | ||
| ? command.argumentHint.join(" ") | ||
| : command.argumentHint, | ||
| } | ||
| : null; | ||
| let name = command.name; | ||
@@ -623,0 +636,0 @@ if (command.name.endsWith(" (MCP)")) { |
+214
-158
@@ -67,2 +67,16 @@ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { | ||
| const defaults = { maxFileSize: 50000, linesToRead: 2000 }; | ||
| function formatErrorMessage(error) { | ||
| if (error instanceof Error) { | ||
| return error.message; | ||
| } | ||
| if (typeof error === "string") { | ||
| return error; | ||
| } | ||
| try { | ||
| return JSON.stringify(error); | ||
| } | ||
| catch { | ||
| return String(error); | ||
| } | ||
| } | ||
| const unqualifiedToolNames = { | ||
@@ -190,4 +204,4 @@ read: "Read", | ||
| } | ||
| else { | ||
| readInfo += `Read lines ${input.offset}-${result.linesRead}. `; | ||
| else if (input.offset && input.offset > 1) { | ||
| readInfo += `Read lines ${input.offset}-${input.offset + result.linesRead}.`; | ||
| } | ||
@@ -210,6 +224,7 @@ if (result.wasLimited) { | ||
| return { | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Reading file failed: " + error.message, | ||
| text: "Reading file failed: " + formatErrorMessage(error), | ||
| }, | ||
@@ -268,6 +283,7 @@ ], | ||
| return { | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Writing file failed: " + error.message, | ||
| text: "Writing file failed: " + formatErrorMessage(error), | ||
| }, | ||
@@ -350,6 +366,7 @@ ], | ||
| return { | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Editing file failed: " + (error?.message ?? String(error)), | ||
| text: "Editing file failed: " + formatErrorMessage(error), | ||
| }, | ||
@@ -389,110 +406,123 @@ ], | ||
| }, async (input, extra) => { | ||
| const env_1 = { stack: [], error: void 0, hasError: false }; | ||
| try { | ||
| const session = agent.sessions[sessionId]; | ||
| if (!session) { | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "The user has left the building", | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| const toolCallId = extra._meta?.["claudecode/toolUseId"]; | ||
| if (typeof toolCallId !== "string") { | ||
| throw new Error("No tool call ID found"); | ||
| } | ||
| if (!agent.clientCapabilities?.terminal || !agent.client.createTerminal) { | ||
| throw new Error("unreachable"); | ||
| } | ||
| const handle = await agent.client.createTerminal({ | ||
| command: input.command, | ||
| env: [{ name: "CLAUDECODE", value: "1" }], | ||
| sessionId, | ||
| outputByteLimit: 32000, | ||
| }); | ||
| await agent.client.sessionUpdate({ | ||
| sessionId, | ||
| update: { | ||
| sessionUpdate: "tool_call_update", | ||
| toolCallId, | ||
| status: "in_progress", | ||
| title: input.description, | ||
| content: [{ type: "terminal", terminalId: handle.id }], | ||
| }, | ||
| }); | ||
| const abortPromise = new Promise((resolve) => { | ||
| if (extra.signal.aborted) { | ||
| resolve(null); | ||
| const env_1 = { stack: [], error: void 0, hasError: false }; | ||
| try { | ||
| const session = agent.sessions[sessionId]; | ||
| if (!session) { | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "The user has left the building", | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| else { | ||
| extra.signal.addEventListener("abort", () => { | ||
| const toolCallId = extra._meta?.["claudecode/toolUseId"]; | ||
| if (typeof toolCallId !== "string") { | ||
| throw new Error("No tool call ID found"); | ||
| } | ||
| if (!agent.clientCapabilities?.terminal || !agent.client.createTerminal) { | ||
| throw new Error("unreachable"); | ||
| } | ||
| const handle = await agent.client.createTerminal({ | ||
| command: input.command, | ||
| env: [{ name: "CLAUDECODE", value: "1" }], | ||
| sessionId, | ||
| outputByteLimit: 32000, | ||
| }); | ||
| await agent.client.sessionUpdate({ | ||
| sessionId, | ||
| update: { | ||
| sessionUpdate: "tool_call_update", | ||
| toolCallId, | ||
| status: "in_progress", | ||
| title: input.description, | ||
| content: [{ type: "terminal", terminalId: handle.id }], | ||
| }, | ||
| }); | ||
| const abortPromise = new Promise((resolve) => { | ||
| if (extra.signal.aborted) { | ||
| resolve(null); | ||
| }); | ||
| } | ||
| }); | ||
| const statusPromise = Promise.race([ | ||
| handle.waitForExit().then((exitStatus) => ({ status: "exited", exitStatus })), | ||
| abortPromise.then(() => ({ status: "aborted", exitStatus: null })), | ||
| sleep(input.timeout ?? 2 * 60 * 1000).then(async () => { | ||
| if (agent.backgroundTerminals[handle.id]?.status === "started") { | ||
| await handle.kill(); | ||
| } | ||
| return { status: "timedOut", exitStatus: null }; | ||
| }), | ||
| ]); | ||
| if (input.run_in_background) { | ||
| agent.backgroundTerminals[handle.id] = { | ||
| handle, | ||
| lastOutput: null, | ||
| status: "started", | ||
| }; | ||
| statusPromise.then(async ({ status, exitStatus }) => { | ||
| const bgTerm = agent.backgroundTerminals[handle.id]; | ||
| if (bgTerm.status !== "started") { | ||
| return; | ||
| else { | ||
| extra.signal.addEventListener("abort", () => { | ||
| resolve(null); | ||
| }); | ||
| } | ||
| const currentOutput = await handle.currentOutput(); | ||
| }); | ||
| const statusPromise = Promise.race([ | ||
| handle.waitForExit().then((exitStatus) => ({ status: "exited", exitStatus })), | ||
| abortPromise.then(() => ({ status: "aborted", exitStatus: null })), | ||
| sleep(input.timeout ?? 2 * 60 * 1000).then(async () => { | ||
| if (agent.backgroundTerminals[handle.id]?.status === "started") { | ||
| await handle.kill(); | ||
| } | ||
| return { status: "timedOut", exitStatus: null }; | ||
| }), | ||
| ]); | ||
| if (input.run_in_background) { | ||
| agent.backgroundTerminals[handle.id] = { | ||
| status, | ||
| pendingOutput: { | ||
| ...currentOutput, | ||
| output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output), | ||
| exitStatus: exitStatus ?? currentOutput.exitStatus, | ||
| }, | ||
| handle, | ||
| lastOutput: null, | ||
| status: "started", | ||
| }; | ||
| return handle.release(); | ||
| }); | ||
| statusPromise.then(async ({ status, exitStatus }) => { | ||
| const bgTerm = agent.backgroundTerminals[handle.id]; | ||
| if (bgTerm.status !== "started") { | ||
| return; | ||
| } | ||
| const currentOutput = await handle.currentOutput(); | ||
| agent.backgroundTerminals[handle.id] = { | ||
| status, | ||
| pendingOutput: { | ||
| ...currentOutput, | ||
| output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output), | ||
| exitStatus: exitStatus ?? currentOutput.exitStatus, | ||
| }, | ||
| }; | ||
| return handle.release(); | ||
| }); | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: `Command started in background with id: ${handle.id}`, | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| const terminal = __addDisposableResource(env_1, handle, true); | ||
| const { status } = await statusPromise; | ||
| if (status === "aborted") { | ||
| return { | ||
| content: [{ type: "text", text: "Tool cancelled by user" }], | ||
| }; | ||
| } | ||
| const output = await terminal.currentOutput(); | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: `Command started in background with id: ${handle.id}`, | ||
| }, | ||
| ], | ||
| content: [{ type: "text", text: toolCommandOutput(status, output) }], | ||
| }; | ||
| } | ||
| const terminal = __addDisposableResource(env_1, handle, true); | ||
| const { status } = await statusPromise; | ||
| if (status === "aborted") { | ||
| return { | ||
| content: [{ type: "text", text: "Tool cancelled by user" }], | ||
| }; | ||
| catch (e_1) { | ||
| env_1.error = e_1; | ||
| env_1.hasError = true; | ||
| } | ||
| const output = await terminal.currentOutput(); | ||
| finally { | ||
| const result_1 = __disposeResources(env_1); | ||
| if (result_1) | ||
| await result_1; | ||
| } | ||
| } | ||
| catch (error) { | ||
| return { | ||
| content: [{ type: "text", text: toolCommandOutput(status, output) }], | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Running bash command failed: " + formatErrorMessage(error), | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| catch (e_1) { | ||
| env_1.error = e_1; | ||
| env_1.hasError = true; | ||
| } | ||
| finally { | ||
| const result_1 = __disposeResources(env_1); | ||
| if (result_1) | ||
| await result_1; | ||
| } | ||
| }); | ||
@@ -514,18 +544,41 @@ server.registerTool(unqualifiedToolNames.bashOutput, { | ||
| }, async (input) => { | ||
| const bgTerm = agent.backgroundTerminals[input.bash_id]; | ||
| if (!bgTerm) { | ||
| throw new Error(`Unknown shell ${input.bash_id}`); | ||
| try { | ||
| const bgTerm = agent.backgroundTerminals[input.bash_id]; | ||
| if (!bgTerm) { | ||
| throw new Error(`Unknown shell ${input.bash_id}`); | ||
| } | ||
| if (bgTerm.status === "started") { | ||
| const newOutput = await bgTerm.handle.currentOutput(); | ||
| const strippedOutput = stripCommonPrefix(bgTerm.lastOutput?.output ?? "", newOutput.output); | ||
| bgTerm.lastOutput = newOutput; | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: toolCommandOutput(bgTerm.status, { | ||
| ...newOutput, | ||
| output: strippedOutput, | ||
| }), | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| else { | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: toolCommandOutput(bgTerm.status, bgTerm.pendingOutput), | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| } | ||
| if (bgTerm.status === "started") { | ||
| const newOutput = await bgTerm.handle.currentOutput(); | ||
| const strippedOutput = stripCommonPrefix(bgTerm.lastOutput?.output ?? "", newOutput.output); | ||
| bgTerm.lastOutput = newOutput; | ||
| catch (error) { | ||
| return { | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: toolCommandOutput(bgTerm.status, { | ||
| ...newOutput, | ||
| output: strippedOutput, | ||
| }), | ||
| text: "Retrieving bash output failed: " + formatErrorMessage(error), | ||
| }, | ||
@@ -535,12 +588,2 @@ ], | ||
| } | ||
| else { | ||
| return { | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: toolCommandOutput(bgTerm.status, bgTerm.pendingOutput), | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| }); | ||
@@ -561,43 +604,56 @@ server.registerTool(unqualifiedToolNames.killShell, { | ||
| }, async (input) => { | ||
| const bgTerm = agent.backgroundTerminals[input.shell_id]; | ||
| if (!bgTerm) { | ||
| throw new Error(`Unknown shell ${input.shell_id}`); | ||
| } | ||
| switch (bgTerm.status) { | ||
| case "started": { | ||
| await bgTerm.handle.kill(); | ||
| const currentOutput = await bgTerm.handle.currentOutput(); | ||
| agent.backgroundTerminals[bgTerm.handle.id] = { | ||
| status: "killed", | ||
| pendingOutput: { | ||
| ...currentOutput, | ||
| output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output), | ||
| }, | ||
| }; | ||
| await bgTerm.handle.release(); | ||
| return { | ||
| content: [{ type: "text", text: "Command killed successfully." }], | ||
| }; | ||
| try { | ||
| const bgTerm = agent.backgroundTerminals[input.shell_id]; | ||
| if (!bgTerm) { | ||
| throw new Error(`Unknown shell ${input.shell_id}`); | ||
| } | ||
| case "aborted": | ||
| return { | ||
| content: [{ type: "text", text: "Command aborted by user." }], | ||
| }; | ||
| case "exited": | ||
| return { | ||
| content: [{ type: "text", text: "Command had already exited." }], | ||
| }; | ||
| case "killed": | ||
| return { | ||
| content: [{ type: "text", text: "Command was already killed." }], | ||
| }; | ||
| case "timedOut": | ||
| return { | ||
| content: [{ type: "text", text: "Command killed by timeout." }], | ||
| }; | ||
| default: { | ||
| unreachable(bgTerm); | ||
| throw new Error("Unexpected background terminal status"); | ||
| switch (bgTerm.status) { | ||
| case "started": { | ||
| await bgTerm.handle.kill(); | ||
| const currentOutput = await bgTerm.handle.currentOutput(); | ||
| agent.backgroundTerminals[bgTerm.handle.id] = { | ||
| status: "killed", | ||
| pendingOutput: { | ||
| ...currentOutput, | ||
| output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output), | ||
| }, | ||
| }; | ||
| await bgTerm.handle.release(); | ||
| return { | ||
| content: [{ type: "text", text: "Command killed successfully." }], | ||
| }; | ||
| } | ||
| case "aborted": | ||
| return { | ||
| content: [{ type: "text", text: "Command aborted by user." }], | ||
| }; | ||
| case "exited": | ||
| return { | ||
| content: [{ type: "text", text: "Command had already exited." }], | ||
| }; | ||
| case "killed": | ||
| return { | ||
| content: [{ type: "text", text: "Command was already killed." }], | ||
| }; | ||
| case "timedOut": | ||
| return { | ||
| content: [{ type: "text", text: "Command killed by timeout." }], | ||
| }; | ||
| default: { | ||
| unreachable(bgTerm); | ||
| throw new Error("Unexpected background terminal status"); | ||
| } | ||
| } | ||
| } | ||
| catch (error) { | ||
| return { | ||
| isError: true, | ||
| content: [ | ||
| { | ||
| type: "text", | ||
| text: "Killing shell failed: " + formatErrorMessage(error), | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| }); | ||
@@ -604,0 +660,0 @@ } |
+12
-4
@@ -6,5 +6,6 @@ { | ||
| }, | ||
| "version": "0.13.0", | ||
| "version": "0.13.1", | ||
| "description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)", | ||
| "main": "dist/lib.js", | ||
| "types": "dist/lib.d.ts", | ||
| "bin": { | ||
@@ -14,2 +15,9 @@ "claude-code-acp": "./dist/index.js" | ||
| "type": "module", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/lib.d.ts", | ||
| "import": "./dist/lib.js" | ||
| }, | ||
| "./*": "./*" | ||
| }, | ||
| "files": [ | ||
@@ -57,3 +65,3 @@ "dist/", | ||
| "@agentclientprotocol/sdk": "0.13.0", | ||
| "@anthropic-ai/claude-agent-sdk": "0.2.6", | ||
| "@anthropic-ai/claude-agent-sdk": "0.2.7", | ||
| "@modelcontextprotocol/sdk": "1.25.2", | ||
@@ -65,3 +73,3 @@ "diff": "8.0.3", | ||
| "@anthropic-ai/sdk": "0.71.2", | ||
| "@types/node": "25.0.7", | ||
| "@types/node": "25.0.8", | ||
| "@typescript-eslint/eslint-plugin": "8.53.0", | ||
@@ -72,3 +80,3 @@ "@typescript-eslint/parser": "8.53.0", | ||
| "globals": "17.0.0", | ||
| "prettier": "3.7.4", | ||
| "prettier": "3.8.0", | ||
| "ts-node": "10.9.2", | ||
@@ -75,0 +83,0 @@ "typescript": "5.9.3", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
237971
22.57%39
178.57%5182
19.46%23
35.29%4
33.33%+ Added
- Removed