# Windsurf ACP Connector

This directory contains the ACP client connector that manages the connection
lifecycle between the Windsurf IDE and the chisel agent.

## ACP Custom Capabilities Audit

The chisel agent defines `cognition.ai/`-prefixed custom capabilities that are
negotiated during the `initialize` handshake. A comprehensive audit of these
capabilities is maintained at:

> **[`devin-webapp/apps/chisel/cognition-acp/CAPABILITIES_AUDIT.md`](https://github.com/usacognition/devin-webapp/blob/main/apps/chisel/cognition-acp/CAPABILITIES_AUDIT.md)**

When modifying the `initialize` request in `windsurfAcpConnector.ts` — in
particular the `clientCapabilities` or `clientCapabilities._meta` fields — you
**must** update the audit table.

Currently, `WindsurfAcpConnector.initialize()` sends:

- `clientInfo: { name: MetadataProvider.ideName, version: ideVersion }` — standard ACP client identification; sends `"windsurf"`, `"windsurf-next"`, or `"windsurf-insiders"` so the agent can attribute analytics to the host IDE
- `clientCapabilities.elicitation: { form: {} }` — standard ACP elicitation support
- `clientCapabilities.fs: { readTextFile: true, writeTextFile: true }` — standard ACP file access support
- `clientCapabilities._meta`:
  - `cognition.ai/subagentSupport: true`
  - `cognition.ai/multiRootWorkspace: true`
  - `cognition.ai/partialContent: true` — enables partial form data in elicitation decline `_meta`
  - `cognition.ai/messageGrouping: true` — enables streaming tool call previews and `clientMessageId`-based chunk regrouping
  - `cognition.ai/refTagsRaw: true` — opts out of server-side `<ref_file>` / `<ref_snippet>` / `<code_snippet>` → `resource_link` conversion. Windsurf keeps the raw tags because it does its own richer client-side ref-tag rendering (`cci:` URIs with line-range selection). Default (absent / false) means the agent converts the tags (consumer lands in a follow-up PR).
  - `cognition.ai/groupedSessionConfigOptions: true` — opts in to receiving model config options organized into `SessionConfigSelectGroup` entries (grouped by model family) instead of a flat list
  - `cognition.ai/windsurfConfigBridge: true` — opts in to receiving Windsurf-specific config options that use `_windsurf_*` categories (`_windsurf_ignore_files`, `_windsurf_max_turn_requests`). Without this, the agent omits these options to avoid "Unknown" dropdowns in clients that don't recognize custom categories.
  - `cognition.ai/revert: true` — mutual opt-in for the revert-to-step extension methods (`cognition.ai/revert/{listSteps,preview,execute,forkFromStep}`). The agent only advertises the matching agent capability when this is sent. Callers gate UI on `supportsRevert(agentCapabilities)` from `@exa/windsurf-acp`.
  - `cognition.ai/mcp: true` — mutual opt-in for the MCP marketplace extension methods (`cognition.ai/mcp/{listServers,toggleServer,toggleTool}`). The agent only advertises the matching agent capability when this is sent. Callers gate UI on `supportsMcpManagement(agentCapabilities)` from `@exa/windsurf-acp`.
  - `cognition.ai/editorContext: true` — declares that Windsurf supplies implicit editor state (open documents and cursor position via `_cognition.ai/document/*` lifecycle notifications). The agent combines this with `requestDiagnostics` to decide whether to include the `## IDE Metadata` system-prompt section, which tells the model how to treat the `<additional_metadata>` blocks that editor state and diagnostics are injected in. The flag does not gate the injection itself, only the prompt guidance.
  - `cognition.ai/requestDiagnostics: BackgroundLintManager.getInstance().enabled` — gated on the `CASCADE_AUTO_FIX_LINTS` feature flag. When the flag is off, this is `false` and the agent never registers a diagnostics handler (zero round-trips). When `true`, the connector calls `BackgroundLintManager.watchForLints()` _before_ dispatching each `fs/write_text_file` request so the lint snapshot captures pre-edit state — matching Cortex's invariant that the watch window encompasses the edit. At `Stop` boundaries, the agent pulls lint diagnostics via the `_cognition.ai/request_diagnostics` extension method, which calls `consumeCollectedLints()` to return lints accumulated during the watch windows and mark them as returned. Early-return paths (no active editor, unsupported language, auto-fix disabled) call `finalizeActiveWatch()` instead, which cleans up the watch without consuming — collected lints remain available for the next valid pull.
  - `terminal_output: true` — opt-in for receiving `terminal_info`, `terminal_output`, and `terminal_exit` metadata on `tool_call` / `tool_call_update` events. Third-party ACP agents (codex-acp, claude-agent-acp) gate sending this terminal metadata on this capability. The accumulated `terminal_output.data` is rendered inline in `ExecuteToolCall` when no content blocks are present.
  - `cognition.ai/lazyEditorFiles: true` — tells the Devin Cloud ACP proxy that this client can lazy-fetch editor-file diff blobs via `_cognition.ai/resource/load` instead of requiring them inline. When the proxy sees this, it skips eager S3 blob fetching for `multi_edit_result` / `skill_pr_suggestion` events and emits empty-text `diff` blocks with `cognition.ai/contentsKey` / `cognition.ai/prevContentsKey` in `_meta`. The chat client's `acpResourceCache` resolves the blobs on demand.
  - `cognition.ai/toolCallQuestions: true` — opts in to receiving Devin Cloud question events as `ToolCallStart`/`ToolCallProgress` (matching the Chisel `ask_user_question` format) instead of `AgentMessageChunk`/`UserMessageChunk`. Without this, the Devin Cloud proxy falls back to the legacy plain-message format.

Standard ACP `terminal` capability is omitted intentionally because Windsurf
handles terminals through its own extension APIs.
