codeep 1.2.19 → 1.2.20
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 +34 -0
- package/dist/acp/protocol.d.ts +54 -0
- package/dist/acp/protocol.js +3 -0
- package/dist/acp/server.d.ts +1 -0
- package/dist/acp/server.js +81 -0
- package/dist/acp/session.d.ts +15 -0
- package/dist/acp/session.js +61 -0
- package/dist/acp/transport.d.ts +13 -0
- package/dist/acp/transport.js +41 -0
- package/dist/renderer/main.js +7 -0
- package/dist/utils/agent.d.ts +4 -2
- package/dist/utils/agentChat.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -764,3 +764,37 @@ Contributions are welcome! Please open an issue or submit a pull request on [Git
|
|
|
764
764
|
## Support
|
|
765
765
|
|
|
766
766
|
- **Issues**: [GitHub Issues](https://github.com/VladoIvankovic/Codeep/issues)
|
|
767
|
+
|
|
768
|
+
## Zed Editor Integration (ACP)
|
|
769
|
+
|
|
770
|
+
Codeep supports the [Agent Client Protocol (ACP)](https://agentclientprotocol.com), letting you use it as an AI coding agent directly inside [Zed](https://zed.dev).
|
|
771
|
+
|
|
772
|
+
### Setup
|
|
773
|
+
|
|
774
|
+
1. Install Codeep globally:
|
|
775
|
+
|
|
776
|
+
```bash
|
|
777
|
+
npm install -g codeep
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
2. Add to your Zed `settings.json`:
|
|
781
|
+
|
|
782
|
+
```json
|
|
783
|
+
{
|
|
784
|
+
"agent_servers": {
|
|
785
|
+
"Codeep": {
|
|
786
|
+
"type": "custom",
|
|
787
|
+
"command": "codeep",
|
|
788
|
+
"args": ["acp"]
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
3. Make sure your API key is set in the environment Zed uses:
|
|
795
|
+
|
|
796
|
+
```bash
|
|
797
|
+
export DEEPSEEK_API_KEY=your_key # or whichever provider
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
4. Open Zed's AI panel and select **Codeep** as the agent.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface JsonRpcRequest {
|
|
2
|
+
jsonrpc: '2.0';
|
|
3
|
+
id: number | string;
|
|
4
|
+
method: string;
|
|
5
|
+
params?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface JsonRpcResponse {
|
|
8
|
+
jsonrpc: '2.0';
|
|
9
|
+
id: number | string;
|
|
10
|
+
result?: unknown;
|
|
11
|
+
error?: {
|
|
12
|
+
code: number;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface JsonRpcNotification {
|
|
17
|
+
jsonrpc: '2.0';
|
|
18
|
+
method: string;
|
|
19
|
+
params?: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface InitializeParams {
|
|
22
|
+
capabilities?: Record<string, unknown>;
|
|
23
|
+
workspaceFolders?: {
|
|
24
|
+
uri: string;
|
|
25
|
+
name: string;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
export interface InitializeResult {
|
|
29
|
+
capabilities: {
|
|
30
|
+
streaming?: boolean;
|
|
31
|
+
fileEditing?: boolean;
|
|
32
|
+
};
|
|
33
|
+
serverInfo: {
|
|
34
|
+
name: string;
|
|
35
|
+
version: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface AgentRunParams {
|
|
39
|
+
prompt: string;
|
|
40
|
+
workspaceRoot?: string;
|
|
41
|
+
conversationId?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface AgentStreamParams {
|
|
44
|
+
conversationId: string;
|
|
45
|
+
text: string;
|
|
46
|
+
done?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ApplyEditParams {
|
|
49
|
+
changes: {
|
|
50
|
+
uri: string;
|
|
51
|
+
newText: string;
|
|
52
|
+
}[];
|
|
53
|
+
}
|
|
54
|
+
export type AcpMessage = JsonRpcRequest | JsonRpcResponse | JsonRpcNotification;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function startAcpServer(): Promise<void>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/acp/server.ts
|
|
2
|
+
// Codeep ACP adapter — started via `codeep acp` CLI subcommand
|
|
3
|
+
import { StdioTransport } from './transport.js';
|
|
4
|
+
import { runAgentSession } from './session.js';
|
|
5
|
+
export function startAcpServer() {
|
|
6
|
+
const transport = new StdioTransport();
|
|
7
|
+
const activeSessions = new Map();
|
|
8
|
+
transport.start((msg) => {
|
|
9
|
+
switch (msg.method) {
|
|
10
|
+
case 'initialize':
|
|
11
|
+
handleInitialize(msg);
|
|
12
|
+
break;
|
|
13
|
+
case 'initialized':
|
|
14
|
+
// no-op acknowledgment
|
|
15
|
+
break;
|
|
16
|
+
case 'agent/run':
|
|
17
|
+
handleAgentRun(msg);
|
|
18
|
+
break;
|
|
19
|
+
case 'agent/cancel':
|
|
20
|
+
handleAgentCancel(msg);
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
transport.error(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
function handleInitialize(msg) {
|
|
27
|
+
const _params = msg.params;
|
|
28
|
+
const result = {
|
|
29
|
+
capabilities: {
|
|
30
|
+
streaming: true,
|
|
31
|
+
fileEditing: true,
|
|
32
|
+
},
|
|
33
|
+
serverInfo: {
|
|
34
|
+
name: 'codeep',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
transport.respond(msg.id, result);
|
|
39
|
+
}
|
|
40
|
+
function handleAgentRun(msg) {
|
|
41
|
+
const params = msg.params;
|
|
42
|
+
const conversationId = params.conversationId ?? String(msg.id);
|
|
43
|
+
const abortController = new AbortController();
|
|
44
|
+
activeSessions.set(conversationId, abortController);
|
|
45
|
+
runAgentSession({
|
|
46
|
+
prompt: params.prompt,
|
|
47
|
+
workspaceRoot: params.workspaceRoot ?? process.cwd(),
|
|
48
|
+
conversationId,
|
|
49
|
+
abortSignal: abortController.signal,
|
|
50
|
+
onChunk: (text) => {
|
|
51
|
+
transport.notify('agent/stream', { conversationId, text });
|
|
52
|
+
},
|
|
53
|
+
onFileEdit: (uri, newText) => {
|
|
54
|
+
transport.notify('workspace/applyEdit', {
|
|
55
|
+
changes: [{ uri, newText }],
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
}).then(() => {
|
|
59
|
+
transport.respond(msg.id, { done: true });
|
|
60
|
+
}).catch((err) => {
|
|
61
|
+
if (err.name === 'AbortError') {
|
|
62
|
+
transport.respond(msg.id, { cancelled: true });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
transport.error(msg.id, -32000, err.message);
|
|
66
|
+
}
|
|
67
|
+
}).finally(() => {
|
|
68
|
+
activeSessions.delete(conversationId);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function handleAgentCancel(msg) {
|
|
72
|
+
const { conversationId } = msg.params;
|
|
73
|
+
activeSessions.get(conversationId)?.abort();
|
|
74
|
+
activeSessions.delete(conversationId);
|
|
75
|
+
transport.respond(msg.id, { cancelled: true });
|
|
76
|
+
}
|
|
77
|
+
// Keep process alive until stdin closes (Zed terminates us)
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
process.stdin.on('end', resolve);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AgentSessionOptions {
|
|
2
|
+
prompt: string;
|
|
3
|
+
workspaceRoot: string;
|
|
4
|
+
conversationId: string;
|
|
5
|
+
abortSignal: AbortSignal;
|
|
6
|
+
onChunk: (text: string) => void;
|
|
7
|
+
onFileEdit: (uri: string, newText: string) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Run a single agent session driven by ACP parameters.
|
|
11
|
+
*
|
|
12
|
+
* onFileEdit is reserved for future use (v1 emits everything via onChunk).
|
|
13
|
+
*/
|
|
14
|
+
export declare function runAgentSession(opts: AgentSessionOptions): Promise<void>;
|
|
15
|
+
export declare function pathToUri(absolutePath: string): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// acp/session.ts
|
|
2
|
+
// Bridges ACP parameters to the Codeep agent loop.
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
import { runAgent } from '../utils/agent.js';
|
|
5
|
+
import { getProjectContext } from '../utils/project.js';
|
|
6
|
+
/**
|
|
7
|
+
* Build a ProjectContext from a workspace root directory.
|
|
8
|
+
* Falls back to a minimal synthetic context if scanning fails.
|
|
9
|
+
*/
|
|
10
|
+
function buildProjectContext(workspaceRoot) {
|
|
11
|
+
const ctx = getProjectContext(workspaceRoot);
|
|
12
|
+
if (ctx) {
|
|
13
|
+
return ctx;
|
|
14
|
+
}
|
|
15
|
+
// Minimal fallback so runAgent never receives null
|
|
16
|
+
return {
|
|
17
|
+
root: workspaceRoot,
|
|
18
|
+
name: workspaceRoot.split('/').pop() ?? 'workspace',
|
|
19
|
+
type: 'Unknown',
|
|
20
|
+
structure: '',
|
|
21
|
+
keyFiles: [],
|
|
22
|
+
fileCount: 0,
|
|
23
|
+
summary: `Workspace at ${workspaceRoot}`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Run a single agent session driven by ACP parameters.
|
|
28
|
+
*
|
|
29
|
+
* onFileEdit is reserved for future use (v1 emits everything via onChunk).
|
|
30
|
+
*/
|
|
31
|
+
export async function runAgentSession(opts) {
|
|
32
|
+
const projectContext = buildProjectContext(opts.workspaceRoot);
|
|
33
|
+
const result = await runAgent(opts.prompt, projectContext, {
|
|
34
|
+
abortSignal: opts.abortSignal,
|
|
35
|
+
// Stream iteration status and thinking text back to the caller via onChunk
|
|
36
|
+
onIteration: (_iteration, message) => {
|
|
37
|
+
opts.onChunk(message + '\n');
|
|
38
|
+
},
|
|
39
|
+
onThinking: (text) => {
|
|
40
|
+
opts.onChunk(text);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
// Emit the final response text if present
|
|
44
|
+
if (result.finalResponse) {
|
|
45
|
+
opts.onChunk(result.finalResponse);
|
|
46
|
+
}
|
|
47
|
+
// Surface errors as thrown exceptions so index.ts can handle them correctly
|
|
48
|
+
if (!result.success && !result.aborted) {
|
|
49
|
+
throw new Error(result.error ?? 'Agent run failed without a specific error message');
|
|
50
|
+
}
|
|
51
|
+
if (result.aborted) {
|
|
52
|
+
const abortError = new Error('Agent session was cancelled');
|
|
53
|
+
abortError.name = 'AbortError';
|
|
54
|
+
throw abortError;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Utility: convert an absolute file-system path to a file:// URI string.
|
|
58
|
+
// Exported for use by callers that need to construct applyEdit URIs.
|
|
59
|
+
export function pathToUri(absolutePath) {
|
|
60
|
+
return pathToFileURL(absolutePath).href;
|
|
61
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JsonRpcRequest, JsonRpcResponse, JsonRpcNotification } from './protocol.js';
|
|
2
|
+
type MessageHandler = (msg: JsonRpcRequest) => void;
|
|
3
|
+
export declare class StdioTransport {
|
|
4
|
+
private buffer;
|
|
5
|
+
private handler;
|
|
6
|
+
start(handler: MessageHandler): void;
|
|
7
|
+
private onData;
|
|
8
|
+
send(msg: JsonRpcResponse | JsonRpcNotification): void;
|
|
9
|
+
respond(id: number | string, result: unknown): void;
|
|
10
|
+
error(id: number | string, code: number, message: string): void;
|
|
11
|
+
notify(method: string, params: unknown): void;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// acp/transport.ts
|
|
2
|
+
// Newline-delimited JSON-RPC over stdio
|
|
3
|
+
export class StdioTransport {
|
|
4
|
+
buffer = '';
|
|
5
|
+
handler = null;
|
|
6
|
+
start(handler) {
|
|
7
|
+
this.handler = handler;
|
|
8
|
+
process.stdin.setEncoding('utf8');
|
|
9
|
+
process.stdin.on('data', (chunk) => this.onData(chunk));
|
|
10
|
+
process.stdin.on('end', () => process.exit(0));
|
|
11
|
+
}
|
|
12
|
+
onData(chunk) {
|
|
13
|
+
this.buffer += chunk;
|
|
14
|
+
const lines = this.buffer.split('\n');
|
|
15
|
+
this.buffer = lines.pop() ?? '';
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed)
|
|
19
|
+
continue;
|
|
20
|
+
try {
|
|
21
|
+
const msg = JSON.parse(trimmed);
|
|
22
|
+
this.handler?.(msg);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// ignore malformed messages
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
send(msg) {
|
|
30
|
+
process.stdout.write(JSON.stringify(msg) + '\n');
|
|
31
|
+
}
|
|
32
|
+
respond(id, result) {
|
|
33
|
+
this.send({ jsonrpc: '2.0', id, result });
|
|
34
|
+
}
|
|
35
|
+
error(id, code, message) {
|
|
36
|
+
this.send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
37
|
+
}
|
|
38
|
+
notify(method, params) {
|
|
39
|
+
this.send({ jsonrpc: '2.0', method, params });
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/renderer/main.js
CHANGED
|
@@ -321,6 +321,7 @@ Codeep - AI-powered coding assistant TUI
|
|
|
321
321
|
|
|
322
322
|
Usage:
|
|
323
323
|
codeep Start interactive chat
|
|
324
|
+
codeep acp Start ACP server (for Zed editor integration)
|
|
324
325
|
codeep --version Show version
|
|
325
326
|
codeep --help Show this help
|
|
326
327
|
|
|
@@ -332,6 +333,12 @@ Commands (in chat):
|
|
|
332
333
|
`);
|
|
333
334
|
process.exit(0);
|
|
334
335
|
}
|
|
336
|
+
// ACP server mode — started by Zed via Agent Client Protocol
|
|
337
|
+
if (args[0] === 'acp') {
|
|
338
|
+
const { startAcpServer } = await import('../acp/server.js');
|
|
339
|
+
await startAcpServer();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
335
342
|
await loadAllApiKeys();
|
|
336
343
|
let apiKey = await loadApiKey();
|
|
337
344
|
if (!apiKey) {
|
package/dist/utils/agent.d.ts
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* Private chat/stream logic lives in agentChat.ts and agentStream.ts.
|
|
5
5
|
*/
|
|
6
6
|
import { ProjectContext } from './project';
|
|
7
|
-
import { loadProjectRules, formatChatHistoryForAgent
|
|
8
|
-
|
|
7
|
+
import { loadProjectRules, formatChatHistoryForAgent } from './agentChat';
|
|
8
|
+
import type { AgentChatResponse } from './agentChat';
|
|
9
|
+
export { loadProjectRules, formatChatHistoryForAgent };
|
|
10
|
+
export type { AgentChatResponse };
|
|
9
11
|
import { ToolCall, ToolResult, ActionLog } from './tools';
|
|
10
12
|
import { undoLastAction, undoAllActions, getCurrentSession, getRecentSessions, formatSession, ActionSession } from './history';
|
|
11
13
|
import { VerifyResult } from './verify';
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { ProjectContext } from './project';
|
|
15
15
|
import { Message } from '../config/index';
|
|
16
|
-
import { AgentChatResponse } from './agentStream';
|
|
17
|
-
export { AgentChatResponse };
|
|
16
|
+
import type { AgentChatResponse } from './agentStream';
|
|
17
|
+
export type { AgentChatResponse };
|
|
18
18
|
/**
|
|
19
19
|
* Custom error class for timeout
|
|
20
20
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.20",
|
|
4
4
|
"description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|