Fixes #1124. ## The defect `src/index.ts` awaited `resolveSettings` at module scope with nothing around it: ```ts const policy = await resolveSettings({ settingSources: [] }); for (const [key, value] of Object.entries(policy.effective.env ?? {})) { process.env[key] = value; } ``` That is a top-level `await` in an ESM entry point, so a rejection aborts module evaluation and the process exits before serving any ACP traffic. The client only sees a process that exited 1 with no protocol messages. Two neighbours make this the only call that can do it, and both are still true on \`main\`: - `SettingsManager.loadAllSettings` (`src/settings.ts:105-113`) wraps the same SDK call in `try`/`catch` and falls back to `{}`. - The `process.on("unhandledRejection", ...)` handler is registered at \`src/index.ts:62\`, after this await, so it does not cover it. Reading the managed tier is best-effort by nature — on a host with no MDM and no managed policy the result is empty and the agent behaves identically — so a transient `EINTR`/`EMFILE`/`EAGAIN` while reading it should leave the agent running with no policy env rather than stop it from starting. ## The change The guard lives in a new `src/managed-policy.ts` rather than inline, for one reason: `src/index.ts` is an ESM entry point with top-level side effects, so nothing in it can be imported by a test. Extracting the tier read makes the failure path testable, which is what the regression test below exercises. `applyManagedPolicyEnv` mirrors `loadAllSettings`: it takes the SDK call through a parameter defaulting to `resolveSettings` and a target env defaulting to `process.env`, reports the failure on stderr, and returns without applying anything. `src/index.ts` becomes: ```ts await applyManagedPolicyEnv(); ``` `console.error` is correct here: this runs before stdout is redirected, so the ACP stream stays clean. ## Verification Four tests in `src/tests/managed-policy.test.ts` cover the applied case, an empty tier, a tier with no `env` table, and the failure path — the last one asserts the promise **resolves** rather than rejects, with the target env untouched, which is the property the entry point depends on. ``` before after tests 17 failed | 1366 passed 17 failed | 1370 passed ``` The 17 failures are pre-existing in this checkout and untouched by this change; the four added tests account for the difference. `eslint src --ext .ts`, `tsc`, and `prettier --check` (with the repository's `.prettierrc.json`) are clean on the three files. ## Note I have not established whether those 17 pre-existing failures are host-specific or real, so I am not claiming anything about them or changing anything for them.
ACP adapter for the Claude Agent SDK
Use Claude Agent SDK from ACP-compatible clients!
This tool implements an ACP agent by using the official Claude Agent SDK, supporting:
- Context @-mentions
- Images
- Tool calls (with permission requests)
- Following
- Edit review
- TODO lists
- Nested subagent transcripts
- Interactive (and background) terminals
- Custom Slash commands
- Client MCP servers
- Session-scoped long-running goals through the provider-neutral goal extension
- Structured errors, recovery, and warnings through the opt-in session failure extension
- Concrete model and effort defaults through the opt-in recommended config value extension
- Tool permission presentation, editable choices, and durable effects through the permission extension
Learn more about the Agent Client Protocol.
To try changes that have landed on main but are not released yet, install from the
preview channel — every push to main publishes one. See
docs/RELEASES.md.
npm install @agentclientprotocol/claude-agent-acp@preview
Subagent sessions
Subagents are exposed only after bilateral capability negotiation. Until the released ACP SDKs
preserve the draft clientCapabilities.subagents field, a supporting client may advertise
nativeSubagentSessions in _meta.jetbrains.air.capabilities; the adapter mirrors the capability
in its initialize response. The canonical field remains supported and takes precedence once it is
available. Without either client signal, Agent/Task lifecycle keeps its legacy ordinary ACP
tool-call representation and child interactions stay on the root session. Clients that use the
historical _meta["subagent-transcript"] capability or forwardSubagentText session option retain
the flattened child transcript behavior.
Contribution Policy
This project does not require a Contributor License Agreement (CLA). Instead, contributions are accepted under the following terms:
By contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. You affirm that you have the legal right to submit your work, that you are not including code you do not have rights to, and that you understand contributions are made without requiring a Contributor License Agreement (CLA).