@posthog/agent 2.0.0 → 2.0.2
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/LICENSE +1 -1
- package/README.md +221 -219
- package/dist/adapters/claude/conversion/tool-use-to-acp.d.ts +21 -0
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +547 -0
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -0
- package/dist/adapters/claude/permissions/permission-options.d.ts +13 -0
- package/dist/adapters/claude/permissions/permission-options.js +117 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -0
- package/dist/adapters/claude/questions/utils.d.ts +132 -0
- package/dist/adapters/claude/questions/utils.js +63 -0
- package/dist/adapters/claude/questions/utils.js.map +1 -0
- package/dist/adapters/claude/tools.d.ts +18 -0
- package/dist/adapters/claude/tools.js +95 -0
- package/dist/adapters/claude/tools.js.map +1 -0
- package/dist/agent-DBQY1BfC.d.ts +123 -0
- package/dist/agent.d.ts +5 -0
- package/dist/agent.js +3656 -0
- package/dist/agent.js.map +1 -0
- package/dist/claude-cli/cli.js +3695 -2746
- package/dist/claude-cli/vendor/ripgrep/COPYING +3 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-darwin/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-linux/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-darwin/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-linux/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-win32/ripgrep.node +0 -0
- package/dist/gateway-models.d.ts +24 -0
- package/dist/gateway-models.js +93 -0
- package/dist/gateway-models.js.map +1 -0
- package/dist/index.d.ts +170 -1157
- package/dist/index.js +9373 -5135
- package/dist/index.js.map +1 -1
- package/dist/logger-DDBiMOOD.d.ts +24 -0
- package/dist/posthog-api.d.ts +40 -0
- package/dist/posthog-api.js +175 -0
- package/dist/posthog-api.js.map +1 -0
- package/dist/server/agent-server.d.ts +41 -0
- package/dist/server/agent-server.js +10503 -0
- package/dist/server/agent-server.js.map +1 -0
- package/dist/server/bin.d.ts +1 -0
- package/dist/server/bin.js +10558 -0
- package/dist/server/bin.js.map +1 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +65 -13
- package/src/acp-extensions.ts +98 -16
- package/src/adapters/acp-connection.ts +494 -0
- package/src/adapters/base-acp-agent.ts +150 -0
- package/src/adapters/claude/claude-agent.ts +596 -0
- package/src/adapters/claude/conversion/acp-to-sdk.ts +102 -0
- package/src/adapters/claude/conversion/sdk-to-acp.ts +571 -0
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +618 -0
- package/src/adapters/claude/hooks.ts +64 -0
- package/src/adapters/claude/mcp/tool-metadata.ts +102 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +433 -0
- package/src/adapters/claude/permissions/permission-options.ts +103 -0
- package/src/adapters/claude/plan/utils.ts +56 -0
- package/src/adapters/claude/questions/utils.ts +92 -0
- package/src/adapters/claude/session/commands.ts +38 -0
- package/src/adapters/claude/session/mcp-config.ts +37 -0
- package/src/adapters/claude/session/models.ts +12 -0
- package/src/adapters/claude/session/options.ts +236 -0
- package/src/adapters/claude/tool-meta.ts +143 -0
- package/src/adapters/claude/tools.ts +53 -688
- package/src/adapters/claude/types.ts +61 -0
- package/src/adapters/codex/spawn.ts +130 -0
- package/src/agent.ts +96 -587
- package/src/execution-mode.ts +43 -0
- package/src/gateway-models.ts +135 -0
- package/src/index.ts +79 -0
- package/src/otel-log-writer.test.ts +105 -0
- package/src/otel-log-writer.ts +94 -0
- package/src/posthog-api.ts +75 -235
- package/src/resume.ts +115 -0
- package/src/sagas/apply-snapshot-saga.test.ts +690 -0
- package/src/sagas/apply-snapshot-saga.ts +88 -0
- package/src/sagas/capture-tree-saga.test.ts +892 -0
- package/src/sagas/capture-tree-saga.ts +141 -0
- package/src/sagas/resume-saga.test.ts +558 -0
- package/src/sagas/resume-saga.ts +332 -0
- package/src/sagas/test-fixtures.ts +250 -0
- package/src/server/agent-server.test.ts +220 -0
- package/src/server/agent-server.ts +748 -0
- package/src/server/bin.ts +88 -0
- package/src/server/jwt.ts +65 -0
- package/src/server/schemas.ts +47 -0
- package/src/server/types.ts +13 -0
- package/src/server/utils/retry.test.ts +122 -0
- package/src/server/utils/retry.ts +61 -0
- package/src/server/utils/sse-parser.test.ts +93 -0
- package/src/server/utils/sse-parser.ts +46 -0
- package/src/session-log-writer.test.ts +140 -0
- package/src/session-log-writer.ts +137 -0
- package/src/test/assertions.ts +114 -0
- package/src/test/controllers/sse-controller.ts +107 -0
- package/src/test/fixtures/api.ts +111 -0
- package/src/test/fixtures/config.ts +33 -0
- package/src/test/fixtures/notifications.ts +92 -0
- package/src/test/mocks/claude-sdk.ts +251 -0
- package/src/test/mocks/msw-handlers.ts +48 -0
- package/src/test/setup.ts +114 -0
- package/src/test/wait.ts +41 -0
- package/src/tree-tracker.ts +173 -0
- package/src/types.ts +54 -137
- package/src/utils/acp-content.ts +58 -0
- package/src/utils/async-mutex.test.ts +104 -0
- package/src/utils/async-mutex.ts +31 -0
- package/src/utils/common.ts +15 -0
- package/src/utils/gateway.ts +9 -6
- package/src/utils/logger.ts +0 -30
- package/src/utils/streams.ts +220 -0
- package/CLAUDE.md +0 -331
- package/src/adapters/claude/claude.ts +0 -1947
- package/src/adapters/claude/mcp-server.ts +0 -810
- package/src/adapters/claude/utils.ts +0 -267
- package/src/adapters/connection.ts +0 -95
- package/src/file-manager.ts +0 -273
- package/src/git-manager.ts +0 -577
- package/src/schemas.ts +0 -241
- package/src/session-store.ts +0 -259
- package/src/task-manager.ts +0 -163
- package/src/todo-manager.ts +0 -180
- package/src/tools/registry.ts +0 -134
- package/src/tools/types.ts +0 -133
- package/src/utils/tapped-stream.ts +0 -60
- package/src/worktree-manager.ts +0 -974
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
|
+
import { type SetupServerApi, setupServer } from "msw/node";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { createTestRepo, type TestRepo } from "../test/fixtures/api.js";
|
|
5
|
+
import { createPostHogHandlers } from "../test/mocks/msw-handlers.js";
|
|
6
|
+
import { AgentServer } from "./agent-server.js";
|
|
7
|
+
import { type JwtPayload, SANDBOX_CONNECTION_AUDIENCE } from "./jwt.js";
|
|
8
|
+
|
|
9
|
+
function createTestJwt(
|
|
10
|
+
payload: JwtPayload,
|
|
11
|
+
privateKey: string,
|
|
12
|
+
expiresInSeconds = 3600,
|
|
13
|
+
): string {
|
|
14
|
+
return jwt.sign(
|
|
15
|
+
{ ...payload, aud: SANDBOX_CONNECTION_AUDIENCE },
|
|
16
|
+
privateKey,
|
|
17
|
+
{
|
|
18
|
+
algorithm: "RS256",
|
|
19
|
+
expiresIn: expiresInSeconds,
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Test RSA key pair (2048-bit, for testing only)
|
|
25
|
+
const TEST_PRIVATE_KEY = `-----BEGIN PRIVATE KEY-----
|
|
26
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqh94SYMFsvG4C
|
|
27
|
+
Co9BSGjtPr2/OxzuNGr41O4+AMkDQRd9pKO49DhTA4VzwnOvrH8y4eI9N8OQne7B
|
|
28
|
+
wpdoouSn4DoDAS/b3SUfij/RoFUSyZiTQoWz0H6o2Vuufiz0Hf+BzlZEVnhSQ1ru
|
|
29
|
+
vqSf+4l8cWgeMXaFXgdD5kQ8GjvR5uqKxvO2Env1hMJRKeOOEGgCep/0c6SkMUTX
|
|
30
|
+
SeC+VjypVg9+8yPxtIpOQ7XKv+7e/PA0ilqehRQh4fo9BAWjUW1+HnbtsjJAjjfv
|
|
31
|
+
ngzIjpajuQVyMi7G79v8OvijhLMJjJBh3TdbVIfi+RkVj/H94UUfKWRfJA0eLykA
|
|
32
|
+
VvTiFf0nAgMBAAECggEABkLBQWFW2IXBNAm/IEGEF408uH2l/I/mqSTaBUq1EwKq
|
|
33
|
+
U17RRg8y77hg2CHBP9fNf3i7NuIltNcaeA6vRwpOK1MXiVv/QJHLO2fP41Mx4jIC
|
|
34
|
+
gi/c7NtsfiprQaG5pnykhP0SnXlndd65bzUkpOasmWdXnbK5VL8ZV40uliInJafE
|
|
35
|
+
1Eo9qSYCJxHmivU/4AbiBgygOAo1QIiuuUHcx0YGknLrBaMQETuvWJGE3lxVQ30/
|
|
36
|
+
EuRyA3r6BwN2T0z47PZBzvCpg/C1KeoYuKSMwMyEXfl+a8NclqdROkVaenmZpvVH
|
|
37
|
+
0lAvFDuPrBSDmU4XJbKCEfwfHjRkiWAFaTrKntGQtQKBgQD/ILoK4U9DkJoKTYvY
|
|
38
|
+
9lX7dg6wNO8jGLHNufU8tHhU+QnBMH3hBXrAtIKQ1sGs+D5rq/O7o0Balmct9vwb
|
|
39
|
+
CQZ1EpPfa83Thsv6Skd7lWK0JF7g2vVk8kT4nY/eqkgZUWgkfdMp+OMg2drYiIE8
|
|
40
|
+
u+sRPTCdq4Tv5miRg0OToX2H/QKBgQDrVR2GXm6ZUyFbCy8A0kttXP1YyXqDVq7p
|
|
41
|
+
L4kqyUq43hmbjzIRM4YDN3EvgZvVf6eub6L/3HfKvWD/OvEhHovTvHb9jkwZ3FO+
|
|
42
|
+
YQllB/ccAWJs/Dw5jLAsX9O+eIe4lfwROib3vYLnDTAmrXD5VL35R5F0MsdRoxk5
|
|
43
|
+
lTCq1sYI8wKBgGA9ZjDIgXAJUjJkwkZb1l9/T1clALiKjjf+2AXIRkQ3lXhs5G9H
|
|
44
|
+
8+BRt5cPjAvFsTZIrS6xDIufhNiP/NXt96OeGG4FaqVKihOmhYSW+57cwXWs4zjr
|
|
45
|
+
Mx1dwnHKZlw2m0R4unlwy60OwUFBbQ8ODER6gqZXl1Qv5G5Px+Qe3Q25AoGAUl+s
|
|
46
|
+
wgfz9r9egZvcjBEQTeuq0pVTyP1ipET7YnqrKSK1G/p3sAW09xNFDzfy8DyK2UhC
|
|
47
|
+
agUl+VVoym47UTh8AVWK4R4aDUNOHOmifDbZjHf/l96CxjI0yJOSbq2J9FarsOwG
|
|
48
|
+
D9nKJE49eIxlayD6jnM6us27bxwEDF/odSRQlXkCgYEAxn9l/5kewWkeEA0Afe1c
|
|
49
|
+
Uf+mepHBLw1Pbg5GJYIZPC6e5+wRNvtFjM5J6h5LVhyb7AjKeLBTeohoBKEfUyUO
|
|
50
|
+
rl/ql9qDIh5lJFn3uNh7+r7tmG21Zl2pyh+O8GljjZ25mYhdiwl0uqzVZaINe2Wa
|
|
51
|
+
vbMnD1ZQKgL8LHgb02cbTsc=
|
|
52
|
+
-----END PRIVATE KEY-----`;
|
|
53
|
+
|
|
54
|
+
const TEST_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
55
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6ofeEmDBbLxuAgqPQUho
|
|
56
|
+
7T69vzsc7jRq+NTuPgDJA0EXfaSjuPQ4UwOFc8Jzr6x/MuHiPTfDkJ3uwcKXaKLk
|
|
57
|
+
p+A6AwEv290lH4o/0aBVEsmYk0KFs9B+qNlbrn4s9B3/gc5WRFZ4UkNa7r6kn/uJ
|
|
58
|
+
fHFoHjF2hV4HQ+ZEPBo70ebqisbzthJ79YTCUSnjjhBoAnqf9HOkpDFE10ngvlY8
|
|
59
|
+
qVYPfvMj8bSKTkO1yr/u3vzwNIpanoUUIeH6PQQFo1Ftfh527bIyQI43754MyI6W
|
|
60
|
+
o7kFcjIuxu/b/Dr4o4SzCYyQYd03W1SH4vkZFY/x/eFFHylkXyQNHi8pAFb04hX9
|
|
61
|
+
JwIDAQAB
|
|
62
|
+
-----END PUBLIC KEY-----`;
|
|
63
|
+
|
|
64
|
+
describe("AgentServer HTTP Mode", () => {
|
|
65
|
+
let repo: TestRepo;
|
|
66
|
+
let server: AgentServer;
|
|
67
|
+
let mswServer: SetupServerApi;
|
|
68
|
+
let appendLogCalls: unknown[][];
|
|
69
|
+
const port = 3099;
|
|
70
|
+
|
|
71
|
+
beforeEach(async () => {
|
|
72
|
+
repo = await createTestRepo("agent-server-http");
|
|
73
|
+
appendLogCalls = [];
|
|
74
|
+
mswServer = setupServer(
|
|
75
|
+
...createPostHogHandlers({
|
|
76
|
+
baseUrl: "http://localhost:8000",
|
|
77
|
+
onAppendLog: (entries) => appendLogCalls.push(entries),
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
mswServer.listen({ onUnhandledRequest: "bypass" });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
afterEach(async () => {
|
|
84
|
+
if (server) {
|
|
85
|
+
await server.stop();
|
|
86
|
+
}
|
|
87
|
+
mswServer.close();
|
|
88
|
+
await repo.cleanup();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const createServer = () => {
|
|
92
|
+
server = new AgentServer({
|
|
93
|
+
port,
|
|
94
|
+
jwtPublicKey: TEST_PUBLIC_KEY,
|
|
95
|
+
repositoryPath: repo.path,
|
|
96
|
+
apiUrl: "http://localhost:8000",
|
|
97
|
+
apiKey: "test-api-key",
|
|
98
|
+
projectId: 1,
|
|
99
|
+
mode: "interactive",
|
|
100
|
+
taskId: "test-task-id",
|
|
101
|
+
runId: "test-run-id",
|
|
102
|
+
});
|
|
103
|
+
return server;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const createToken = (overrides = {}) => {
|
|
107
|
+
return createTestJwt(
|
|
108
|
+
{
|
|
109
|
+
run_id: "test-run-id",
|
|
110
|
+
task_id: "test-task-id",
|
|
111
|
+
team_id: 1,
|
|
112
|
+
user_id: 1,
|
|
113
|
+
distinct_id: "test-distinct-id",
|
|
114
|
+
mode: "interactive",
|
|
115
|
+
...overrides,
|
|
116
|
+
},
|
|
117
|
+
TEST_PRIVATE_KEY,
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
describe("GET /health", () => {
|
|
122
|
+
it("returns ok status with active session", async () => {
|
|
123
|
+
await createServer().start();
|
|
124
|
+
|
|
125
|
+
const response = await fetch(`http://localhost:${port}/health`);
|
|
126
|
+
const body = await response.json();
|
|
127
|
+
|
|
128
|
+
expect(response.status).toBe(200);
|
|
129
|
+
expect(body).toEqual({ status: "ok", hasSession: true });
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("GET /events", () => {
|
|
134
|
+
it("returns 401 without authorization header", async () => {
|
|
135
|
+
await createServer().start();
|
|
136
|
+
|
|
137
|
+
const response = await fetch(`http://localhost:${port}/events`);
|
|
138
|
+
const body = await response.json();
|
|
139
|
+
|
|
140
|
+
expect(response.status).toBe(401);
|
|
141
|
+
expect(body.error).toBe("Missing authorization header");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("returns 401 with invalid token", async () => {
|
|
145
|
+
await createServer().start();
|
|
146
|
+
|
|
147
|
+
const response = await fetch(`http://localhost:${port}/events`, {
|
|
148
|
+
headers: { Authorization: "Bearer invalid-token" },
|
|
149
|
+
});
|
|
150
|
+
const body = await response.json();
|
|
151
|
+
|
|
152
|
+
expect(response.status).toBe(401);
|
|
153
|
+
expect(body.code).toBe("invalid_signature");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("accepts valid JWT and returns SSE stream", async () => {
|
|
157
|
+
await createServer().start();
|
|
158
|
+
const token = createToken();
|
|
159
|
+
|
|
160
|
+
const response = await fetch(`http://localhost:${port}/events`, {
|
|
161
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(response.status).toBe(200);
|
|
165
|
+
expect(response.headers.get("content-type")).toBe("text/event-stream");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("POST /command", () => {
|
|
170
|
+
it("returns 401 without authorization", async () => {
|
|
171
|
+
await createServer().start();
|
|
172
|
+
|
|
173
|
+
const response = await fetch(`http://localhost:${port}/command`, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
headers: { "Content-Type": "application/json" },
|
|
176
|
+
body: JSON.stringify({
|
|
177
|
+
jsonrpc: "2.0",
|
|
178
|
+
method: "user_message",
|
|
179
|
+
params: { content: "test" },
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(response.status).toBe(401);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("returns 400 when run_id does not match active session", async () => {
|
|
187
|
+
await createServer().start();
|
|
188
|
+
const token = createToken({ run_id: "different-run-id" });
|
|
189
|
+
|
|
190
|
+
const response = await fetch(`http://localhost:${port}/command`, {
|
|
191
|
+
method: "POST",
|
|
192
|
+
headers: {
|
|
193
|
+
Authorization: `Bearer ${token}`,
|
|
194
|
+
"Content-Type": "application/json",
|
|
195
|
+
},
|
|
196
|
+
body: JSON.stringify({
|
|
197
|
+
jsonrpc: "2.0",
|
|
198
|
+
method: "user_message",
|
|
199
|
+
params: { content: "test" },
|
|
200
|
+
}),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
expect(response.status).toBe(400);
|
|
204
|
+
const body = await response.json();
|
|
205
|
+
expect(body.error).toBe("No active session for this run");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("404 handling", () => {
|
|
210
|
+
it("returns 404 for unknown routes", async () => {
|
|
211
|
+
await createServer().start();
|
|
212
|
+
|
|
213
|
+
const response = await fetch(`http://localhost:${port}/unknown`);
|
|
214
|
+
const body = await response.json();
|
|
215
|
+
|
|
216
|
+
expect(response.status).toBe(404);
|
|
217
|
+
expect(body.error).toBe("Not found");
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|