amp-acp 0.3.7 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/{src → dist}/index.js +2 -6
- package/dist/index.js.map +1 -0
- package/dist/mcp-config.d.ts +12 -0
- package/dist/mcp-config.d.ts.map +1 -0
- package/dist/mcp-config.js +30 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/run-acp.d.ts +2 -0
- package/dist/run-acp.d.ts.map +1 -0
- package/dist/run-acp.js +10 -0
- package/dist/run-acp.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +178 -0
- package/dist/server.js.map +1 -0
- package/dist/to-acp.d.ts +41 -0
- package/dist/to-acp.d.ts.map +1 -0
- package/dist/to-acp.js +93 -0
- package/dist/to-acp.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +28 -0
- package/dist/utils.js.map +1 -0
- package/package.json +16 -6
- package/AGENTS.md +0 -22
- package/img/screenshot.png +0 -0
- package/src/run-acp.js +0 -10
- package/src/server.js +0 -208
- package/src/to-acp.js +0 -91
- package/src/utils.js +0 -27
package/README.md
CHANGED
|
@@ -52,6 +52,81 @@ That's it! The SDK handles authentication and Amp integration automatically.
|
|
|
52
52
|
- Renders Amp messages and interactions natively in Zed
|
|
53
53
|
- Tool permissions are handled by Amp (no additional configuration needed)
|
|
54
54
|
- Supports conversation continuity across multiple prompts
|
|
55
|
+
- **MCP servers configured in Zed are automatically passed through to Amp**
|
|
56
|
+
|
|
57
|
+
## MCP Configuration Passthrough
|
|
58
|
+
|
|
59
|
+
The adapter supports passing [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers configured in Zed through to Amp. This allows you to use the same MCP tools in both Zed's native AI and Amp.
|
|
60
|
+
|
|
61
|
+
This implementation is compatible with how other ACP agents like [Claude Code](https://github.com/zed-industries/claude-code-acp) and [Codex](https://github.com/zed-industries/codex-acp) handle MCP servers. See [Zed's MCP documentation](https://zed.dev/docs/ai/mcp) for more details.
|
|
62
|
+
|
|
63
|
+
### Supported MCP Server Types
|
|
64
|
+
|
|
65
|
+
| Type | Description | Example |
|
|
66
|
+
|------|-------------|---------|
|
|
67
|
+
| **stdio** | Local command-line MCP servers | `@playwright/mcp`, `@modelcontextprotocol/server-filesystem` |
|
|
68
|
+
| **HTTP** | Remote HTTP MCP servers | `https://mcp.exa.ai/mcp`, `https://mcp.semgrep.ai/mcp` |
|
|
69
|
+
| **SSE** | Remote Server-Sent Events MCP servers | `https://mcp.monday.com/sse` |
|
|
70
|
+
|
|
71
|
+
### Example: Using Exa Search with Amp
|
|
72
|
+
|
|
73
|
+
[Exa](https://exa.ai) provides a powerful web search MCP server. Add both the agent server and context servers to your Zed `settings.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"agent_servers": {
|
|
78
|
+
"Amp": {
|
|
79
|
+
"command": "npx",
|
|
80
|
+
"args": ["-y", "amp-acp"]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"context_servers": {
|
|
84
|
+
"exa": {
|
|
85
|
+
"url": "https://mcp.exa.ai/mcp"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Example: Multiple MCP Servers
|
|
92
|
+
|
|
93
|
+
You can configure multiple MCP servers to extend Amp's capabilities:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"agent_servers": {
|
|
98
|
+
"Amp": {
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "amp-acp"]
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"context_servers": {
|
|
104
|
+
"playwright": {
|
|
105
|
+
"command": "npx",
|
|
106
|
+
"args": ["-y", "@playwright/mcp@latest", "--headless"]
|
|
107
|
+
},
|
|
108
|
+
"filesystem": {
|
|
109
|
+
"command": "npx",
|
|
110
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed"]
|
|
111
|
+
},
|
|
112
|
+
"github": {
|
|
113
|
+
"command": "npx",
|
|
114
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
115
|
+
"env": {
|
|
116
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN": "your-token"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### How MCP Passthrough Works
|
|
124
|
+
|
|
125
|
+
1. When you configure `context_servers` in Zed's `settings.json`, Zed passes them to the ACP agent via the `mcpServers` parameter in the `session/new` request
|
|
126
|
+
2. The amp-acp adapter converts the MCP server configurations from ACP format to Amp SDK format
|
|
127
|
+
3. Amp connects to the MCP servers and makes their tools available during the session
|
|
128
|
+
|
|
129
|
+
For more details, see [docs/mcp-passthrough.md](docs/mcp-passthrough.md).
|
|
55
130
|
|
|
56
131
|
## Troubleshooting
|
|
57
132
|
|
|
@@ -60,3 +135,6 @@ That's it! The SDK handles authentication and Amp integration automatically.
|
|
|
60
135
|
**Connection issues**: Restart Zed and try again. The adapter creates a fresh connection each time.
|
|
61
136
|
|
|
62
137
|
**Tool execution problems**: Check Zed's output panel for detailed error messages from the Amp SDK.
|
|
138
|
+
|
|
139
|
+
**MCP server not connecting**: Ensure the MCP server command is correct and any required environment variables are set. Check Zed's logs for connection errors.
|
|
140
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/{src → dist}/index.js
RENAMED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// stdout is reserved for ACP stream. Redirect logs to stderr.
|
|
3
2
|
console.log = console.error;
|
|
4
3
|
console.info = console.error;
|
|
5
4
|
console.warn = console.error;
|
|
6
5
|
console.debug = console.error;
|
|
7
|
-
|
|
8
6
|
import { runAcp } from './run-acp.js';
|
|
9
|
-
|
|
10
7
|
runAcp();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
process.stdin.resume();
|
|
8
|
+
process.stdin.resume();
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC;AAC5B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;AAC7B,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;AAC7B,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,EAAE,CAAC;AAET,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { McpServer } from '@agentclientprotocol/sdk';
|
|
2
|
+
interface AmpMcpServerConfig {
|
|
3
|
+
command?: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
env?: Record<string, string>;
|
|
6
|
+
url?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export type AmpMcpConfig = Record<string, AmpMcpServerConfig>;
|
|
10
|
+
export declare function convertAcpMcpServersToAmpConfig(mcpServers: McpServer[] | undefined | null): AmpMcpConfig;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=mcp-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.d.ts","sourceRoot":"","sources":["../src/mcp-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAE9D,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,YAAY,CA6BxG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function convertAcpMcpServersToAmpConfig(mcpServers) {
|
|
2
|
+
const mcpConfig = {};
|
|
3
|
+
if (!Array.isArray(mcpServers)) {
|
|
4
|
+
return mcpConfig;
|
|
5
|
+
}
|
|
6
|
+
for (const server of mcpServers) {
|
|
7
|
+
if ('type' in server && (server.type === 'http' || server.type === 'sse')) {
|
|
8
|
+
const headers = {};
|
|
9
|
+
for (const h of server.headers) {
|
|
10
|
+
headers[h.name] = h.value;
|
|
11
|
+
}
|
|
12
|
+
mcpConfig[server.name] = {
|
|
13
|
+
url: server.url,
|
|
14
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const env = server.env.length > 0
|
|
19
|
+
? Object.fromEntries(server.env.map((e) => [e.name, e.value]))
|
|
20
|
+
: undefined;
|
|
21
|
+
mcpConfig[server.name] = {
|
|
22
|
+
command: server.command,
|
|
23
|
+
args: server.args,
|
|
24
|
+
env,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return mcpConfig;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../src/mcp-config.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,+BAA+B,CAAC,UAA0C;IACxF,MAAM,SAAS,GAAiB,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QAChC,IAAI,MAAM,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAC1E,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC/B,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAC5B,CAAC;YACD,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;gBACvB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;aAC/D,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;gBAC/B,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC9D,CAAC,CAAC,SAAS,CAAC;YACd,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG;aACJ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-acp.d.ts","sourceRoot":"","sources":["../src/run-acp.ts"],"names":[],"mappings":"AAIA,wBAAgB,MAAM,IAAI,IAAI,CAQ7B"}
|
package/dist/run-acp.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
2
|
+
import { nodeToWebWritable, nodeToWebReadable } from './utils.js';
|
|
3
|
+
import { AmpAcpAgent } from './server.js';
|
|
4
|
+
export function runAcp() {
|
|
5
|
+
const input = nodeToWebWritable(process.stdout);
|
|
6
|
+
const output = nodeToWebReadable(process.stdin);
|
|
7
|
+
const stream = ndJsonStream(input, output);
|
|
8
|
+
new AgentSideConnection((client) => new AmpAcpAgent(client), stream);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=run-acp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-acp.js","sourceRoot":"","sources":["../src/run-acp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,UAAU,MAAM;IACpB,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,YAAY,CACzB,KAA8C,EAC9C,MAA+C,CAChD,CAAC;IACF,IAAI,mBAAmB,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACvE,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type AgentSideConnection, type Agent, type InitializeRequest, type InitializeResponse, type NewSessionRequest, type NewSessionResponse, type PromptRequest, type PromptResponse, type AuthenticateRequest, type AuthenticateResponse, type CancelNotification, type SetSessionModeRequest, type SetSessionModeResponse, type SetSessionModelRequest, type SetSessionModelResponse, type ReadTextFileRequest, type ReadTextFileResponse, type WriteTextFileRequest, type WriteTextFileResponse } from '@agentclientprotocol/sdk';
|
|
2
|
+
import { type AmpMcpConfig } from './mcp-config.js';
|
|
3
|
+
interface SessionState {
|
|
4
|
+
threadId: string | null;
|
|
5
|
+
controller: AbortController | null;
|
|
6
|
+
cancelled: boolean;
|
|
7
|
+
active: boolean;
|
|
8
|
+
mode: string;
|
|
9
|
+
mcpConfig: AmpMcpConfig;
|
|
10
|
+
cwd: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class AmpAcpAgent implements Agent {
|
|
13
|
+
private client;
|
|
14
|
+
sessions: Map<string, SessionState>;
|
|
15
|
+
private clientCapabilities?;
|
|
16
|
+
constructor(client: AgentSideConnection);
|
|
17
|
+
initialize(request: InitializeRequest): Promise<InitializeResponse>;
|
|
18
|
+
newSession(params: NewSessionRequest): Promise<NewSessionResponse>;
|
|
19
|
+
authenticate(_params: AuthenticateRequest): Promise<AuthenticateResponse>;
|
|
20
|
+
prompt(params: PromptRequest): Promise<PromptResponse>;
|
|
21
|
+
cancel(params: CancelNotification): Promise<void>;
|
|
22
|
+
setSessionModel(_params: SetSessionModelRequest): Promise<SetSessionModelResponse>;
|
|
23
|
+
setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse>;
|
|
24
|
+
readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;
|
|
25
|
+
writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,KAAK,EACV,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE3B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAmC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGrF,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,YAAY,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,WAAY,YAAW,KAAK;IACvC,OAAO,CAAC,MAAM,CAAsB;IACpC,QAAQ,4BAAmC;IAC3C,OAAO,CAAC,kBAAkB,CAAC,CAAqB;gBAEpC,MAAM,EAAE,mBAAmB;IAIjC,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAYnE,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAgDlE,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAIzE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IA+FtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAElF,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAO9E,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IACxE,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAClF"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { RequestError, } from '@agentclientprotocol/sdk';
|
|
2
|
+
import { execute } from '@sourcegraph/amp-sdk';
|
|
3
|
+
import { convertAcpMcpServersToAmpConfig } from './mcp-config.js';
|
|
4
|
+
import { toAcpNotifications } from './to-acp.js';
|
|
5
|
+
export class AmpAcpAgent {
|
|
6
|
+
client;
|
|
7
|
+
sessions = new Map();
|
|
8
|
+
clientCapabilities;
|
|
9
|
+
constructor(client) {
|
|
10
|
+
this.client = client;
|
|
11
|
+
}
|
|
12
|
+
async initialize(request) {
|
|
13
|
+
this.clientCapabilities = request.clientCapabilities;
|
|
14
|
+
return {
|
|
15
|
+
protocolVersion: 1,
|
|
16
|
+
agentCapabilities: {
|
|
17
|
+
promptCapabilities: { image: true, embeddedContext: true },
|
|
18
|
+
mcpCapabilities: { http: true, sse: true },
|
|
19
|
+
},
|
|
20
|
+
authMethods: [],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async newSession(params) {
|
|
24
|
+
const sessionId = `S-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
25
|
+
const mcpConfig = convertAcpMcpServersToAmpConfig(params.mcpServers);
|
|
26
|
+
this.sessions.set(sessionId, {
|
|
27
|
+
threadId: null,
|
|
28
|
+
controller: null,
|
|
29
|
+
cancelled: false,
|
|
30
|
+
active: false,
|
|
31
|
+
mode: 'default',
|
|
32
|
+
mcpConfig,
|
|
33
|
+
cwd: params.cwd || process.cwd(),
|
|
34
|
+
});
|
|
35
|
+
const result = {
|
|
36
|
+
sessionId,
|
|
37
|
+
modes: {
|
|
38
|
+
currentModeId: 'default',
|
|
39
|
+
availableModes: [
|
|
40
|
+
{ id: 'default', name: 'Default', description: 'Prompts for permission on first use of each tool' },
|
|
41
|
+
{ id: 'bypass', name: 'Bypass', description: 'Skips all permission prompts' },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
setImmediate(async () => {
|
|
46
|
+
try {
|
|
47
|
+
await this.client.sessionUpdate({
|
|
48
|
+
sessionId,
|
|
49
|
+
update: {
|
|
50
|
+
sessionUpdate: 'available_commands_update',
|
|
51
|
+
availableCommands: [
|
|
52
|
+
{
|
|
53
|
+
name: 'init',
|
|
54
|
+
description: 'Generate an AGENTS.md file for the project',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
console.error('[acp] failed to send available_commands_update', e);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
async authenticate(_params) {
|
|
67
|
+
throw RequestError.authRequired();
|
|
68
|
+
}
|
|
69
|
+
async prompt(params) {
|
|
70
|
+
const s = this.sessions.get(params.sessionId);
|
|
71
|
+
if (!s)
|
|
72
|
+
throw new Error('Session not found');
|
|
73
|
+
s.cancelled = false;
|
|
74
|
+
s.active = true;
|
|
75
|
+
let textInput = '';
|
|
76
|
+
for (const chunk of params.prompt) {
|
|
77
|
+
switch (chunk.type) {
|
|
78
|
+
case 'text':
|
|
79
|
+
if (chunk.text.trim() === '/init') {
|
|
80
|
+
textInput += `Please analyze this codebase and create an AGENTS.md file containing:
|
|
81
|
+
1. Build/lint/test commands - especially for running a single test
|
|
82
|
+
2. Architecture and codebase structure information, including important subprojects, internal APIs, databases, etc.
|
|
83
|
+
3. Code style guidelines, including imports, conventions, formatting, types, naming conventions, error handling, etc.
|
|
84
|
+
|
|
85
|
+
The file you create will be given to agentic coding tools (such as yourself) that operate in this repository. Make it about 20 lines long.
|
|
86
|
+
|
|
87
|
+
If there are Cursor rules (in .cursor/rules/ or .cursorrules), Claude rules (CLAUDE.md), Windsurf rules (.windsurfrules), Cline rules (.clinerules), Goose rules (.goosehints), or Copilot rules (in .github/copilot-instructions.md), make sure to include them. Also, first check if there is an existing AGENTS.md or AGENT.md file, and if so, update it instead of overwriting it.`;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
textInput += chunk.text;
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
case 'resource_link':
|
|
94
|
+
textInput += `\n${chunk.uri}\n`;
|
|
95
|
+
break;
|
|
96
|
+
case 'resource':
|
|
97
|
+
if ('text' in chunk.resource) {
|
|
98
|
+
textInput += `\n<context ref="${chunk.resource.uri}">\n${chunk.resource.text}\n</context>\n`;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case 'image':
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const options = {
|
|
108
|
+
cwd: s.cwd,
|
|
109
|
+
};
|
|
110
|
+
if (s.mode === 'bypass') {
|
|
111
|
+
options.dangerouslyAllowAll = true;
|
|
112
|
+
}
|
|
113
|
+
if (Object.keys(s.mcpConfig).length > 0) {
|
|
114
|
+
options.mcpConfig = s.mcpConfig;
|
|
115
|
+
}
|
|
116
|
+
if (s.threadId) {
|
|
117
|
+
options.continue = s.threadId;
|
|
118
|
+
}
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
s.controller = controller;
|
|
121
|
+
try {
|
|
122
|
+
for await (const message of execute({ prompt: textInput, options, signal: controller.signal })) {
|
|
123
|
+
if (!s.threadId && message.session_id) {
|
|
124
|
+
s.threadId = message.session_id;
|
|
125
|
+
}
|
|
126
|
+
if (message.type === 'assistant') {
|
|
127
|
+
for (const n of toAcpNotifications(message, params.sessionId)) {
|
|
128
|
+
try {
|
|
129
|
+
await this.client.sessionUpdate(n);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
console.error('[acp] sessionUpdate failed', e);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (message.type === 'result' && message.is_error) {
|
|
137
|
+
await this.client.sessionUpdate({
|
|
138
|
+
sessionId: params.sessionId,
|
|
139
|
+
update: { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: `Error: ${message.error}` } },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { stopReason: s.cancelled ? 'cancelled' : 'end_turn' };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
if (s.cancelled || (err instanceof Error && (err.name === 'AbortError' || err.message.includes('aborted')))) {
|
|
147
|
+
return { stopReason: 'cancelled' };
|
|
148
|
+
}
|
|
149
|
+
console.error('[amp] Execution error:', err);
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
s.active = false;
|
|
154
|
+
s.cancelled = false;
|
|
155
|
+
s.controller = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async cancel(params) {
|
|
159
|
+
const s = this.sessions.get(params.sessionId);
|
|
160
|
+
if (!s)
|
|
161
|
+
return;
|
|
162
|
+
if (s.active && s.controller) {
|
|
163
|
+
s.cancelled = true;
|
|
164
|
+
s.controller.abort();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async setSessionModel(_params) { return {}; }
|
|
168
|
+
async setSessionMode(params) {
|
|
169
|
+
const s = this.sessions.get(params.sessionId);
|
|
170
|
+
if (!s)
|
|
171
|
+
throw new Error('Session not found');
|
|
172
|
+
s.mode = params.modeId;
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
async readTextFile(params) { return this.client.readTextFile(params); }
|
|
176
|
+
async writeTextFile(params) { return this.client.writeTextFile(params); }
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/to-acp.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SessionNotification } from '@agentclientprotocol/sdk';
|
|
2
|
+
interface AmpContentText {
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
interface AmpContentImage {
|
|
7
|
+
type: 'image';
|
|
8
|
+
source?: {
|
|
9
|
+
type: 'base64' | 'url';
|
|
10
|
+
data?: string;
|
|
11
|
+
media_type?: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface AmpContentThinking {
|
|
16
|
+
type: 'thinking';
|
|
17
|
+
thinking: string;
|
|
18
|
+
}
|
|
19
|
+
interface AmpContentToolUse {
|
|
20
|
+
type: 'tool_use';
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
input: unknown;
|
|
24
|
+
}
|
|
25
|
+
interface AmpContentToolResult {
|
|
26
|
+
type: 'tool_result';
|
|
27
|
+
tool_use_id: string;
|
|
28
|
+
content: string | AmpContentText[];
|
|
29
|
+
is_error: boolean;
|
|
30
|
+
}
|
|
31
|
+
type AmpContentBlock = AmpContentText | AmpContentImage | AmpContentThinking | AmpContentToolUse | AmpContentToolResult;
|
|
32
|
+
interface AmpMessage {
|
|
33
|
+
type: string;
|
|
34
|
+
message?: {
|
|
35
|
+
content: string | AmpContentBlock[];
|
|
36
|
+
};
|
|
37
|
+
session_id?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function toAcpNotifications(message: AmpMessage, sessionId: string): SessionNotification[];
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=to-acp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-acp.d.ts","sourceRoot":"","sources":["../src/to-acp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAiC,MAAM,0BAA0B,CAAC;AAEnG,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,UAAU,kBAAkB;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,UAAU,oBAAoB;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IACnC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,eAAe,GAAG,cAAc,GAAG,eAAe,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;AAExH,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;KACrC,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAkEhG"}
|
package/dist/to-acp.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export function toAcpNotifications(message, sessionId) {
|
|
2
|
+
const content = message.message?.content;
|
|
3
|
+
if (typeof content === 'string') {
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
sessionId,
|
|
7
|
+
update: {
|
|
8
|
+
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
9
|
+
content: { type: 'text', text: content },
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
const output = [];
|
|
15
|
+
if (!Array.isArray(content))
|
|
16
|
+
return output;
|
|
17
|
+
for (const chunk of content) {
|
|
18
|
+
let update = null;
|
|
19
|
+
switch (chunk.type) {
|
|
20
|
+
case 'text':
|
|
21
|
+
update = {
|
|
22
|
+
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
23
|
+
content: { type: 'text', text: chunk.text },
|
|
24
|
+
};
|
|
25
|
+
break;
|
|
26
|
+
case 'image':
|
|
27
|
+
update = {
|
|
28
|
+
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
29
|
+
content: {
|
|
30
|
+
type: 'image',
|
|
31
|
+
data: chunk.source?.type === 'base64' ? (chunk.source.data ?? '') : '',
|
|
32
|
+
mimeType: chunk.source?.type === 'base64' ? (chunk.source.media_type ?? '') : '',
|
|
33
|
+
uri: chunk.source?.type === 'url' ? chunk.source.url : undefined,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
break;
|
|
37
|
+
case 'thinking':
|
|
38
|
+
update = {
|
|
39
|
+
sessionUpdate: 'agent_thought_chunk',
|
|
40
|
+
content: { type: 'text', text: chunk.thinking },
|
|
41
|
+
};
|
|
42
|
+
break;
|
|
43
|
+
case 'tool_use':
|
|
44
|
+
update = {
|
|
45
|
+
toolCallId: chunk.id,
|
|
46
|
+
sessionUpdate: 'tool_call',
|
|
47
|
+
rawInput: safeJson(chunk.input),
|
|
48
|
+
status: 'pending',
|
|
49
|
+
title: chunk.name || 'Tool',
|
|
50
|
+
kind: 'other',
|
|
51
|
+
content: [],
|
|
52
|
+
};
|
|
53
|
+
break;
|
|
54
|
+
case 'tool_result':
|
|
55
|
+
update = {
|
|
56
|
+
toolCallId: chunk.tool_use_id,
|
|
57
|
+
sessionUpdate: 'tool_call_update',
|
|
58
|
+
status: chunk.is_error ? 'failed' : 'completed',
|
|
59
|
+
content: toAcpContentArray(chunk.content, chunk.is_error),
|
|
60
|
+
};
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
if (update)
|
|
66
|
+
output.push({ sessionId, update });
|
|
67
|
+
}
|
|
68
|
+
return output;
|
|
69
|
+
}
|
|
70
|
+
function toAcpContentArray(content, isError = false) {
|
|
71
|
+
if (Array.isArray(content) && content.length > 0) {
|
|
72
|
+
return content.map((c) => ({
|
|
73
|
+
type: 'content',
|
|
74
|
+
content: { type: 'text', text: isError ? wrapCode(c.text) : c.text },
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
if (typeof content === 'string' && content.length > 0) {
|
|
78
|
+
return [{ type: 'content', content: { type: 'text', text: isError ? wrapCode(content) : content } }];
|
|
79
|
+
}
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
function wrapCode(t) {
|
|
83
|
+
return '```\n' + t + '\n```';
|
|
84
|
+
}
|
|
85
|
+
function safeJson(x) {
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(JSON.stringify(x));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=to-acp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-acp.js","sourceRoot":"","sources":["../src/to-acp.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { WritableStream, ReadableStream } from 'node:stream/web';
|
|
2
|
+
import type { Writable, Readable } from 'node:stream';
|
|
3
|
+
export declare function nodeToWebWritable(nodeStream: Writable): WritableStream<Uint8Array>;
|
|
4
|
+
export declare function nodeToWebReadable(nodeStream: Readable): ReadableStream<Uint8Array>;
|
|
5
|
+
export declare function unreachable(x: never): never;
|
|
6
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAUlF;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAQlF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAE3C"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { WritableStream, ReadableStream } from 'node:stream/web';
|
|
2
|
+
export function nodeToWebWritable(nodeStream) {
|
|
3
|
+
return new WritableStream({
|
|
4
|
+
write(chunk) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
nodeStream.write(Buffer.from(chunk), (err) => {
|
|
7
|
+
if (err)
|
|
8
|
+
reject(err);
|
|
9
|
+
else
|
|
10
|
+
resolve();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function nodeToWebReadable(nodeStream) {
|
|
17
|
+
return new ReadableStream({
|
|
18
|
+
start(controller) {
|
|
19
|
+
nodeStream.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk)));
|
|
20
|
+
nodeStream.on('end', () => controller.close());
|
|
21
|
+
nodeStream.on('error', (err) => controller.error(err));
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export function unreachable(x) {
|
|
26
|
+
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjE,MAAM,UAAU,iBAAiB,CAAC,UAAoB;IACpD,OAAO,IAAI,cAAc,CAAC;QACxB,KAAK,CAAC,KAAiB;YACrB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;oBAC3C,IAAI,GAAG;wBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;wBAAM,OAAO,EAAE,CAAC;gBACvC,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,UAAoB;IACpD,OAAO,IAAI,cAAc,CAAC;QACxB,KAAK,CAAC,UAAU;YACd,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACpF,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAQ;IAClC,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amp-acp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
6
8
|
"bin": {
|
|
7
|
-
"amp-acp": "
|
|
9
|
+
"amp-acp": "dist/index.js"
|
|
8
10
|
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
9
14
|
"description": "ACP adapter that bridges Amp Code to Agent Client Protocol (Zed external agent)",
|
|
10
15
|
"license": "Apache-2.0",
|
|
11
16
|
"repository": {
|
|
@@ -13,13 +18,18 @@
|
|
|
13
18
|
"url": "https://github.com/tao12345666333/amp-acp"
|
|
14
19
|
},
|
|
15
20
|
"scripts": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"start": "node dist/index.js",
|
|
23
|
+
"lint": "tsc --noEmit",
|
|
24
|
+
"test": "tsc -p tsconfig.test.json --outDir dist-test && node --test dist-test/mcp-config.test.js dist-test/mcp-integration.test.js"
|
|
19
25
|
},
|
|
20
26
|
"dependencies": {
|
|
21
27
|
"@agentclientprotocol/sdk": "0.4.8",
|
|
22
28
|
"@sourcegraph/amp": "^0.0.1765685598-g5365e6",
|
|
23
29
|
"@sourcegraph/amp-sdk": "^0.1.0-20251214200908-g3251f72"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.2.1",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
24
34
|
}
|
|
25
|
-
}
|
|
35
|
+
}
|
package/AGENTS.md
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
## Commands
|
|
4
|
-
- `npm start` or `node src/index.js` — Run the ACP adapter
|
|
5
|
-
- `npm run lint` — Lint (currently a no-op)
|
|
6
|
-
- `npm test` — Test (currently a no-op)
|
|
7
|
-
|
|
8
|
-
## Architecture
|
|
9
|
-
This is an ACP (Agent Client Protocol) adapter that bridges Amp Code to ACP-compatible clients like Zed.
|
|
10
|
-
|
|
11
|
-
- `src/index.js` — Entry point, redirects console to stderr (stdout reserved for ACP stream)
|
|
12
|
-
- `src/run-acp.js` — Sets up ACP connection using stdin/stdout JSON streams
|
|
13
|
-
- `src/server.js` — `AmpAcpAgent` class: handles sessions, prompts, MCP config, and calls `@sourcegraph/amp-sdk`
|
|
14
|
-
- `src/to-acp.js` — Converts Amp stream events to ACP `sessionUpdate` notifications
|
|
15
|
-
- `src/utils.js` — Node-to-Web stream converters
|
|
16
|
-
|
|
17
|
-
## Code Style
|
|
18
|
-
- ES modules (`"type": "module"` in package.json), use `.js` extension in imports
|
|
19
|
-
- No TypeScript; plain JavaScript with JSDoc if needed
|
|
20
|
-
- Use `console.error` for logging (stdout is for ACP protocol only)
|
|
21
|
-
- Error handling: throw `RequestError` from `@agentclientprotocol/sdk` for protocol errors
|
|
22
|
-
- Naming: camelCase for variables/functions, PascalCase for classes
|
package/img/screenshot.png
DELETED
|
Binary file
|
package/src/run-acp.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
2
|
-
import { nodeToWebReadable, nodeToWebWritable } from './utils.js';
|
|
3
|
-
import { AmpAcpAgent } from './server.js';
|
|
4
|
-
|
|
5
|
-
export function runAcp() {
|
|
6
|
-
const input = nodeToWebWritable(process.stdout);
|
|
7
|
-
const output = nodeToWebReadable(process.stdin);
|
|
8
|
-
const stream = ndJsonStream(input, output);
|
|
9
|
-
new AgentSideConnection((client) => new AmpAcpAgent(client), stream);
|
|
10
|
-
}
|
package/src/server.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { RequestError } from '@agentclientprotocol/sdk';
|
|
2
|
-
import { execute } from '@sourcegraph/amp-sdk';
|
|
3
|
-
import { toAcpNotifications } from './to-acp.js';
|
|
4
|
-
|
|
5
|
-
export class AmpAcpAgent {
|
|
6
|
-
constructor(client) {
|
|
7
|
-
this.client = client;
|
|
8
|
-
this.sessions = new Map();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async initialize(request) {
|
|
12
|
-
this.clientCapabilities = request.clientCapabilities;
|
|
13
|
-
return {
|
|
14
|
-
protocolVersion: 1,
|
|
15
|
-
agentCapabilities: {
|
|
16
|
-
promptCapabilities: { image: true, embeddedContext: true },
|
|
17
|
-
mcpCapabilities: { http: true, sse: true },
|
|
18
|
-
},
|
|
19
|
-
authMethods: [],
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async newSession(params) {
|
|
24
|
-
const sessionId = `S-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
25
|
-
|
|
26
|
-
// Convert ACP mcpServers to Amp SDK mcpConfig format
|
|
27
|
-
const mcpConfig = {};
|
|
28
|
-
if (Array.isArray(params.mcpServers)) {
|
|
29
|
-
for (const server of params.mcpServers) {
|
|
30
|
-
if ('type' in server && (server.type === 'http' || server.type === 'sse')) {
|
|
31
|
-
// HTTP/SSE type - Amp SDK may not support this directly
|
|
32
|
-
// Skip for now or handle if SDK supports it
|
|
33
|
-
} else {
|
|
34
|
-
// stdio type
|
|
35
|
-
mcpConfig[server.name] = {
|
|
36
|
-
command: server.command,
|
|
37
|
-
args: server.args,
|
|
38
|
-
env: server.env ? Object.fromEntries(server.env.map((e) => [e.name, e.value])) : undefined,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.sessions.set(sessionId, {
|
|
45
|
-
threadId: null,
|
|
46
|
-
controller: null,
|
|
47
|
-
cancelled: false,
|
|
48
|
-
active: false,
|
|
49
|
-
mode: 'default',
|
|
50
|
-
mcpConfig,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const result = {
|
|
54
|
-
sessionId,
|
|
55
|
-
modes: {
|
|
56
|
-
currentModeId: 'default',
|
|
57
|
-
availableModes: [
|
|
58
|
-
{ id: 'default', name: 'Default', description: 'Prompts for permission on first use of each tool' },
|
|
59
|
-
{ id: 'bypass', name: 'Bypass', description: 'Skips all permission prompts' },
|
|
60
|
-
],
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
setImmediate(async () => {
|
|
65
|
-
try {
|
|
66
|
-
await this.client.sessionUpdate({
|
|
67
|
-
sessionId,
|
|
68
|
-
update: {
|
|
69
|
-
sessionUpdate: 'available_commands_update',
|
|
70
|
-
availableCommands: [
|
|
71
|
-
{
|
|
72
|
-
name: 'init',
|
|
73
|
-
description: 'Generate an AGENTS.md file for the project',
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
} catch (e) {
|
|
79
|
-
console.error('[acp] failed to send available_commands_update', e);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async authenticate(_params) {
|
|
87
|
-
throw RequestError.authRequired();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async prompt(params) {
|
|
91
|
-
const s = this.sessions.get(params.sessionId);
|
|
92
|
-
if (!s) throw new Error('Session not found');
|
|
93
|
-
s.cancelled = false;
|
|
94
|
-
s.active = true;
|
|
95
|
-
|
|
96
|
-
// Build plain-text input for Amp from ACP prompt chunks
|
|
97
|
-
let textInput = '';
|
|
98
|
-
for (const chunk of params.prompt) {
|
|
99
|
-
switch (chunk.type) {
|
|
100
|
-
case 'text':
|
|
101
|
-
if (chunk.text.trim() === '/init') {
|
|
102
|
-
textInput += `Please analyze this codebase and create an AGENTS.md file containing:
|
|
103
|
-
1. Build/lint/test commands - especially for running a single test
|
|
104
|
-
2. Architecture and codebase structure information, including important subprojects, internal APIs, databases, etc.
|
|
105
|
-
3. Code style guidelines, including imports, conventions, formatting, types, naming conventions, error handling, etc.
|
|
106
|
-
|
|
107
|
-
The file you create will be given to agentic coding tools (such as yourself) that operate in this repository. Make it about 20 lines long.
|
|
108
|
-
|
|
109
|
-
If there are Cursor rules (in .cursor/rules/ or .cursorrules), Claude rules (CLAUDE.md), Windsurf rules (.windsurfrules), Cline rules (.clinerules), Goose rules (.goosehints), or Copilot rules (in .github/copilot-instructions.md), make sure to include them. Also, first check if there is an existing AGENTS.md or AGENT.md file, and if so, update it instead of overwriting it.`;
|
|
110
|
-
} else {
|
|
111
|
-
textInput += chunk.text;
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
case 'resource_link':
|
|
115
|
-
textInput += `\n${chunk.uri}\n`;
|
|
116
|
-
break;
|
|
117
|
-
case 'resource':
|
|
118
|
-
if ('text' in chunk.resource) {
|
|
119
|
-
textInput += `\n<context ref="${chunk.resource.uri}">\n${chunk.resource.text}\n</context>\n`;
|
|
120
|
-
}
|
|
121
|
-
break;
|
|
122
|
-
case 'image':
|
|
123
|
-
// Images not supported by Amp SDK yet via simple prompt string; ignore for now
|
|
124
|
-
break;
|
|
125
|
-
default:
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const options = {
|
|
131
|
-
cwd: params.cwd || process.cwd(),
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
if (s.mode === 'bypass') {
|
|
135
|
-
options.dangerouslyAllowAll = true;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (Object.keys(s.mcpConfig).length > 0) {
|
|
139
|
-
options.mcpConfig = s.mcpConfig;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (s.threadId) {
|
|
143
|
-
options.continue = s.threadId;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const controller = new AbortController();
|
|
147
|
-
s.controller = controller;
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
for await (const message of execute({ prompt: textInput, options, signal: controller.signal })) {
|
|
151
|
-
if (!s.threadId && message.session_id) {
|
|
152
|
-
s.threadId = message.session_id;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (message.type === 'assistant') {
|
|
156
|
-
for (const n of toAcpNotifications(message, params.sessionId)) {
|
|
157
|
-
try {
|
|
158
|
-
await this.client.sessionUpdate(n);
|
|
159
|
-
} catch (e) {
|
|
160
|
-
console.error('[acp] sessionUpdate failed', e);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (message.type === 'result' && message.is_error) {
|
|
166
|
-
await this.client.sessionUpdate({
|
|
167
|
-
sessionId: params.sessionId,
|
|
168
|
-
update: { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: `Error: ${message.error}` } },
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return { stopReason: s.cancelled ? 'cancelled' : 'end_turn' };
|
|
174
|
-
} catch (err) {
|
|
175
|
-
if (s.cancelled || (err.name === 'AbortError') || err.message.includes('aborted')) {
|
|
176
|
-
return { stopReason: 'cancelled' };
|
|
177
|
-
}
|
|
178
|
-
console.error('[amp] Execution error:', err);
|
|
179
|
-
throw err;
|
|
180
|
-
} finally {
|
|
181
|
-
s.active = false;
|
|
182
|
-
s.cancelled = false;
|
|
183
|
-
s.controller = null;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async cancel(params) {
|
|
188
|
-
const s = this.sessions.get(params.sessionId);
|
|
189
|
-
if (!s) return {};
|
|
190
|
-
if (s.active && s.controller) {
|
|
191
|
-
s.cancelled = true;
|
|
192
|
-
s.controller.abort();
|
|
193
|
-
}
|
|
194
|
-
return {};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async setSessionModel(_params) { return {}; }
|
|
198
|
-
|
|
199
|
-
async setSessionMode(params) {
|
|
200
|
-
const s = this.sessions.get(params.sessionId);
|
|
201
|
-
if (!s) throw new Error('Session not found');
|
|
202
|
-
s.mode = params.modeId;
|
|
203
|
-
return {};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async readTextFile(params) { return this.client.readTextFile(params); }
|
|
207
|
-
async writeTextFile(params) { return this.client.writeTextFile(params); }
|
|
208
|
-
}
|
package/src/to-acp.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// Minimal conversion from Amp stream JSON events (Claude Code compatible)
|
|
2
|
-
// into ACP sessionUpdate notifications. Based on zed-industries/claude-code-acp.
|
|
3
|
-
|
|
4
|
-
export function toAcpNotifications(message, sessionId) {
|
|
5
|
-
const content = message.message?.content;
|
|
6
|
-
if (typeof content === 'string') {
|
|
7
|
-
return [
|
|
8
|
-
{
|
|
9
|
-
sessionId,
|
|
10
|
-
update: {
|
|
11
|
-
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
12
|
-
content: { type: 'text', text: content },
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
];
|
|
16
|
-
}
|
|
17
|
-
const output = [];
|
|
18
|
-
if (!Array.isArray(content)) return output;
|
|
19
|
-
for (const chunk of content) {
|
|
20
|
-
let update = null;
|
|
21
|
-
switch (chunk.type) {
|
|
22
|
-
case 'text':
|
|
23
|
-
update = {
|
|
24
|
-
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
25
|
-
content: { type: 'text', text: chunk.text },
|
|
26
|
-
};
|
|
27
|
-
break;
|
|
28
|
-
case 'image':
|
|
29
|
-
update = {
|
|
30
|
-
sessionUpdate: message.type === 'assistant' ? 'agent_message_chunk' : 'user_message_chunk',
|
|
31
|
-
content: {
|
|
32
|
-
type: 'image',
|
|
33
|
-
data: chunk.source?.type === 'base64' ? chunk.source.data : '',
|
|
34
|
-
mimeType: chunk.source?.type === 'base64' ? chunk.source.media_type : '',
|
|
35
|
-
uri: chunk.source?.type === 'url' ? chunk.source.url : undefined,
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
break;
|
|
39
|
-
case 'thinking':
|
|
40
|
-
update = {
|
|
41
|
-
sessionUpdate: 'agent_thought_chunk',
|
|
42
|
-
content: { type: 'text', text: chunk.thinking },
|
|
43
|
-
};
|
|
44
|
-
break;
|
|
45
|
-
case 'tool_use':
|
|
46
|
-
update = {
|
|
47
|
-
toolCallId: chunk.id,
|
|
48
|
-
sessionUpdate: 'tool_call',
|
|
49
|
-
rawInput: safeJson(chunk.input),
|
|
50
|
-
status: 'pending',
|
|
51
|
-
title: chunk.name || 'Tool',
|
|
52
|
-
kind: 'other',
|
|
53
|
-
content: [],
|
|
54
|
-
};
|
|
55
|
-
break;
|
|
56
|
-
case 'tool_result':
|
|
57
|
-
update = {
|
|
58
|
-
toolCallId: chunk.tool_use_id,
|
|
59
|
-
sessionUpdate: 'tool_call_update',
|
|
60
|
-
status: chunk.is_error ? 'failed' : 'completed',
|
|
61
|
-
content: toAcpContentArray(chunk.content, chunk.is_error),
|
|
62
|
-
};
|
|
63
|
-
break;
|
|
64
|
-
default:
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
if (update) output.push({ sessionId, update });
|
|
68
|
-
}
|
|
69
|
-
return output;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function toAcpContentArray(content, isError = false) {
|
|
73
|
-
if (Array.isArray(content) && content.length > 0) {
|
|
74
|
-
return content.map((c) => ({
|
|
75
|
-
type: 'content',
|
|
76
|
-
content: c.type === 'text' ? { type: 'text', text: isError ? wrapCode(c.text) : c.text } : c,
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
if (typeof content === 'string' && content.length > 0) {
|
|
80
|
-
return [{ type: 'content', content: { type: 'text', text: isError ? wrapCode(content) : content } }];
|
|
81
|
-
}
|
|
82
|
-
return [];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function wrapCode(t) {
|
|
86
|
-
return '```\n' + t + '\n```';
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function safeJson(x) {
|
|
90
|
-
try { return JSON.parse(JSON.stringify(x)); } catch { return undefined; }
|
|
91
|
-
}
|
package/src/utils.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { WritableStream, ReadableStream } from 'node:stream/web';
|
|
2
|
-
|
|
3
|
-
export function nodeToWebWritable(nodeStream) {
|
|
4
|
-
return new WritableStream({
|
|
5
|
-
write(chunk) {
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
nodeStream.write(Buffer.from(chunk), (err) => {
|
|
8
|
-
if (err) reject(err); else resolve();
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function nodeToWebReadable(nodeStream) {
|
|
16
|
-
return new ReadableStream({
|
|
17
|
-
start(controller) {
|
|
18
|
-
nodeStream.on('data', (chunk) => controller.enqueue(new Uint8Array(chunk)));
|
|
19
|
-
nodeStream.on('end', () => controller.close());
|
|
20
|
-
nodeStream.on('error', (err) => controller.error(err));
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function unreachable(x) {
|
|
26
|
-
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
27
|
-
}
|