@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.
Files changed (131) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +221 -219
  3. package/dist/adapters/claude/conversion/tool-use-to-acp.d.ts +21 -0
  4. package/dist/adapters/claude/conversion/tool-use-to-acp.js +547 -0
  5. package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -0
  6. package/dist/adapters/claude/permissions/permission-options.d.ts +13 -0
  7. package/dist/adapters/claude/permissions/permission-options.js +117 -0
  8. package/dist/adapters/claude/permissions/permission-options.js.map +1 -0
  9. package/dist/adapters/claude/questions/utils.d.ts +132 -0
  10. package/dist/adapters/claude/questions/utils.js +63 -0
  11. package/dist/adapters/claude/questions/utils.js.map +1 -0
  12. package/dist/adapters/claude/tools.d.ts +18 -0
  13. package/dist/adapters/claude/tools.js +95 -0
  14. package/dist/adapters/claude/tools.js.map +1 -0
  15. package/dist/agent-DBQY1BfC.d.ts +123 -0
  16. package/dist/agent.d.ts +5 -0
  17. package/dist/agent.js +3656 -0
  18. package/dist/agent.js.map +1 -0
  19. package/dist/claude-cli/cli.js +3695 -2746
  20. package/dist/claude-cli/vendor/ripgrep/COPYING +3 -0
  21. package/dist/claude-cli/vendor/ripgrep/arm64-darwin/rg +0 -0
  22. package/dist/claude-cli/vendor/ripgrep/arm64-darwin/ripgrep.node +0 -0
  23. package/dist/claude-cli/vendor/ripgrep/arm64-linux/rg +0 -0
  24. package/dist/claude-cli/vendor/ripgrep/arm64-linux/ripgrep.node +0 -0
  25. package/dist/claude-cli/vendor/ripgrep/x64-darwin/rg +0 -0
  26. package/dist/claude-cli/vendor/ripgrep/x64-darwin/ripgrep.node +0 -0
  27. package/dist/claude-cli/vendor/ripgrep/x64-linux/rg +0 -0
  28. package/dist/claude-cli/vendor/ripgrep/x64-linux/ripgrep.node +0 -0
  29. package/dist/claude-cli/vendor/ripgrep/x64-win32/rg.exe +0 -0
  30. package/dist/claude-cli/vendor/ripgrep/x64-win32/ripgrep.node +0 -0
  31. package/dist/gateway-models.d.ts +24 -0
  32. package/dist/gateway-models.js +93 -0
  33. package/dist/gateway-models.js.map +1 -0
  34. package/dist/index.d.ts +170 -1157
  35. package/dist/index.js +9373 -5135
  36. package/dist/index.js.map +1 -1
  37. package/dist/logger-DDBiMOOD.d.ts +24 -0
  38. package/dist/posthog-api.d.ts +40 -0
  39. package/dist/posthog-api.js +175 -0
  40. package/dist/posthog-api.js.map +1 -0
  41. package/dist/server/agent-server.d.ts +41 -0
  42. package/dist/server/agent-server.js +10503 -0
  43. package/dist/server/agent-server.js.map +1 -0
  44. package/dist/server/bin.d.ts +1 -0
  45. package/dist/server/bin.js +10558 -0
  46. package/dist/server/bin.js.map +1 -0
  47. package/dist/types.d.ts +129 -0
  48. package/dist/types.js +1 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +65 -13
  51. package/src/acp-extensions.ts +98 -16
  52. package/src/adapters/acp-connection.ts +494 -0
  53. package/src/adapters/base-acp-agent.ts +150 -0
  54. package/src/adapters/claude/claude-agent.ts +596 -0
  55. package/src/adapters/claude/conversion/acp-to-sdk.ts +102 -0
  56. package/src/adapters/claude/conversion/sdk-to-acp.ts +571 -0
  57. package/src/adapters/claude/conversion/tool-use-to-acp.ts +618 -0
  58. package/src/adapters/claude/hooks.ts +64 -0
  59. package/src/adapters/claude/mcp/tool-metadata.ts +102 -0
  60. package/src/adapters/claude/permissions/permission-handlers.ts +433 -0
  61. package/src/adapters/claude/permissions/permission-options.ts +103 -0
  62. package/src/adapters/claude/plan/utils.ts +56 -0
  63. package/src/adapters/claude/questions/utils.ts +92 -0
  64. package/src/adapters/claude/session/commands.ts +38 -0
  65. package/src/adapters/claude/session/mcp-config.ts +37 -0
  66. package/src/adapters/claude/session/models.ts +12 -0
  67. package/src/adapters/claude/session/options.ts +236 -0
  68. package/src/adapters/claude/tool-meta.ts +143 -0
  69. package/src/adapters/claude/tools.ts +53 -688
  70. package/src/adapters/claude/types.ts +61 -0
  71. package/src/adapters/codex/spawn.ts +130 -0
  72. package/src/agent.ts +96 -587
  73. package/src/execution-mode.ts +43 -0
  74. package/src/gateway-models.ts +135 -0
  75. package/src/index.ts +79 -0
  76. package/src/otel-log-writer.test.ts +105 -0
  77. package/src/otel-log-writer.ts +94 -0
  78. package/src/posthog-api.ts +75 -235
  79. package/src/resume.ts +115 -0
  80. package/src/sagas/apply-snapshot-saga.test.ts +690 -0
  81. package/src/sagas/apply-snapshot-saga.ts +88 -0
  82. package/src/sagas/capture-tree-saga.test.ts +892 -0
  83. package/src/sagas/capture-tree-saga.ts +141 -0
  84. package/src/sagas/resume-saga.test.ts +558 -0
  85. package/src/sagas/resume-saga.ts +332 -0
  86. package/src/sagas/test-fixtures.ts +250 -0
  87. package/src/server/agent-server.test.ts +220 -0
  88. package/src/server/agent-server.ts +748 -0
  89. package/src/server/bin.ts +88 -0
  90. package/src/server/jwt.ts +65 -0
  91. package/src/server/schemas.ts +47 -0
  92. package/src/server/types.ts +13 -0
  93. package/src/server/utils/retry.test.ts +122 -0
  94. package/src/server/utils/retry.ts +61 -0
  95. package/src/server/utils/sse-parser.test.ts +93 -0
  96. package/src/server/utils/sse-parser.ts +46 -0
  97. package/src/session-log-writer.test.ts +140 -0
  98. package/src/session-log-writer.ts +137 -0
  99. package/src/test/assertions.ts +114 -0
  100. package/src/test/controllers/sse-controller.ts +107 -0
  101. package/src/test/fixtures/api.ts +111 -0
  102. package/src/test/fixtures/config.ts +33 -0
  103. package/src/test/fixtures/notifications.ts +92 -0
  104. package/src/test/mocks/claude-sdk.ts +251 -0
  105. package/src/test/mocks/msw-handlers.ts +48 -0
  106. package/src/test/setup.ts +114 -0
  107. package/src/test/wait.ts +41 -0
  108. package/src/tree-tracker.ts +173 -0
  109. package/src/types.ts +54 -137
  110. package/src/utils/acp-content.ts +58 -0
  111. package/src/utils/async-mutex.test.ts +104 -0
  112. package/src/utils/async-mutex.ts +31 -0
  113. package/src/utils/common.ts +15 -0
  114. package/src/utils/gateway.ts +9 -6
  115. package/src/utils/logger.ts +0 -30
  116. package/src/utils/streams.ts +220 -0
  117. package/CLAUDE.md +0 -331
  118. package/src/adapters/claude/claude.ts +0 -1947
  119. package/src/adapters/claude/mcp-server.ts +0 -810
  120. package/src/adapters/claude/utils.ts +0 -267
  121. package/src/adapters/connection.ts +0 -95
  122. package/src/file-manager.ts +0 -273
  123. package/src/git-manager.ts +0 -577
  124. package/src/schemas.ts +0 -241
  125. package/src/session-store.ts +0 -259
  126. package/src/task-manager.ts +0 -163
  127. package/src/todo-manager.ts +0 -180
  128. package/src/tools/registry.ts +0 -134
  129. package/src/tools/types.ts +0 -133
  130. package/src/utils/tapped-stream.ts +0 -60
  131. 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
+ });