@probelabs/probe 0.6.0-rc100

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 (115) hide show
  1. package/README.md +583 -0
  2. package/bin/.gitkeep +0 -0
  3. package/bin/probe +158 -0
  4. package/bin/probe-binary +0 -0
  5. package/build/agent/ProbeAgent.d.ts +199 -0
  6. package/build/agent/ProbeAgent.js +1486 -0
  7. package/build/agent/acp/README.md +347 -0
  8. package/build/agent/acp/connection.js +237 -0
  9. package/build/agent/acp/connection.test.js +311 -0
  10. package/build/agent/acp/examples/simple-client.js +212 -0
  11. package/build/agent/acp/examples/tool-lifecycle.js +230 -0
  12. package/build/agent/acp/final-test.js +173 -0
  13. package/build/agent/acp/index.js +5 -0
  14. package/build/agent/acp/integration.test.js +385 -0
  15. package/build/agent/acp/manual-test.js +410 -0
  16. package/build/agent/acp/protocol-test.js +190 -0
  17. package/build/agent/acp/server.js +448 -0
  18. package/build/agent/acp/server.test.js +371 -0
  19. package/build/agent/acp/test-runner.js +216 -0
  20. package/build/agent/acp/test-utils/README.md +315 -0
  21. package/build/agent/acp/test-utils/acp-tester.js +484 -0
  22. package/build/agent/acp/test-utils/mock-acp-client.js +434 -0
  23. package/build/agent/acp/tools.js +368 -0
  24. package/build/agent/acp/tools.test.js +334 -0
  25. package/build/agent/acp/types.js +218 -0
  26. package/build/agent/acp/types.test.js +327 -0
  27. package/build/agent/appTracer.js +360 -0
  28. package/build/agent/fileSpanExporter.js +169 -0
  29. package/build/agent/index.js +7426 -0
  30. package/build/agent/mcp/client.js +338 -0
  31. package/build/agent/mcp/config.js +313 -0
  32. package/build/agent/mcp/index.js +64 -0
  33. package/build/agent/mcp/xmlBridge.js +371 -0
  34. package/build/agent/mockProvider.js +53 -0
  35. package/build/agent/probeTool.js +257 -0
  36. package/build/agent/schemaUtils.js +1726 -0
  37. package/build/agent/simpleTelemetry.js +267 -0
  38. package/build/agent/telemetry.js +225 -0
  39. package/build/agent/tokenCounter.js +395 -0
  40. package/build/agent/tools.js +163 -0
  41. package/build/cli.js +49 -0
  42. package/build/delegate.js +267 -0
  43. package/build/directory-resolver.js +237 -0
  44. package/build/downloader.js +750 -0
  45. package/build/extract.js +149 -0
  46. package/build/index.js +70 -0
  47. package/build/mcp/index.js +514 -0
  48. package/build/mcp/index.ts +608 -0
  49. package/build/query.js +116 -0
  50. package/build/search.js +247 -0
  51. package/build/tools/common.js +410 -0
  52. package/build/tools/index.js +40 -0
  53. package/build/tools/langchain.js +88 -0
  54. package/build/tools/system-message.js +121 -0
  55. package/build/tools/vercel.js +271 -0
  56. package/build/utils/file-lister.js +193 -0
  57. package/build/utils.js +128 -0
  58. package/cjs/agent/ProbeAgent.cjs +5829 -0
  59. package/cjs/index.cjs +6217 -0
  60. package/cjs/package.json +3 -0
  61. package/index.d.ts +401 -0
  62. package/package.json +114 -0
  63. package/scripts/postinstall.js +172 -0
  64. package/src/agent/ProbeAgent.d.ts +199 -0
  65. package/src/agent/ProbeAgent.js +1486 -0
  66. package/src/agent/acp/README.md +347 -0
  67. package/src/agent/acp/connection.js +237 -0
  68. package/src/agent/acp/connection.test.js +311 -0
  69. package/src/agent/acp/examples/simple-client.js +212 -0
  70. package/src/agent/acp/examples/tool-lifecycle.js +230 -0
  71. package/src/agent/acp/final-test.js +173 -0
  72. package/src/agent/acp/index.js +5 -0
  73. package/src/agent/acp/integration.test.js +385 -0
  74. package/src/agent/acp/manual-test.js +410 -0
  75. package/src/agent/acp/protocol-test.js +190 -0
  76. package/src/agent/acp/server.js +448 -0
  77. package/src/agent/acp/server.test.js +371 -0
  78. package/src/agent/acp/test-runner.js +216 -0
  79. package/src/agent/acp/test-utils/README.md +315 -0
  80. package/src/agent/acp/test-utils/acp-tester.js +484 -0
  81. package/src/agent/acp/test-utils/mock-acp-client.js +434 -0
  82. package/src/agent/acp/tools.js +368 -0
  83. package/src/agent/acp/tools.test.js +334 -0
  84. package/src/agent/acp/types.js +218 -0
  85. package/src/agent/acp/types.test.js +327 -0
  86. package/src/agent/appTracer.js +360 -0
  87. package/src/agent/fileSpanExporter.js +169 -0
  88. package/src/agent/index.js +813 -0
  89. package/src/agent/mcp/client.js +338 -0
  90. package/src/agent/mcp/config.js +313 -0
  91. package/src/agent/mcp/index.js +64 -0
  92. package/src/agent/mcp/xmlBridge.js +371 -0
  93. package/src/agent/mockProvider.js +53 -0
  94. package/src/agent/probeTool.js +257 -0
  95. package/src/agent/schemaUtils.js +1726 -0
  96. package/src/agent/simpleTelemetry.js +267 -0
  97. package/src/agent/telemetry.js +225 -0
  98. package/src/agent/tokenCounter.js +395 -0
  99. package/src/agent/tools.js +163 -0
  100. package/src/cli.js +49 -0
  101. package/src/delegate.js +267 -0
  102. package/src/directory-resolver.js +237 -0
  103. package/src/downloader.js +750 -0
  104. package/src/extract.js +149 -0
  105. package/src/index.js +70 -0
  106. package/src/mcp/index.ts +608 -0
  107. package/src/query.js +116 -0
  108. package/src/search.js +247 -0
  109. package/src/tools/common.js +410 -0
  110. package/src/tools/index.js +40 -0
  111. package/src/tools/langchain.js +88 -0
  112. package/src/tools/system-message.js +121 -0
  113. package/src/tools/vercel.js +271 -0
  114. package/src/utils/file-lister.js +193 -0
  115. package/src/utils.js +128 -0
@@ -0,0 +1,385 @@
1
+ // Integration tests for ACP implementation
2
+ import { jest } from '@jest/globals';
3
+ import { EventEmitter } from 'events';
4
+ import { ACPServer } from './server.js';
5
+ import { ACPConnection } from './connection.js';
6
+ import { ACP_PROTOCOL_VERSION, RequestMethod } from './types.js';
7
+
8
+ // Mock manually handled below
9
+
10
+ // Mock streams for testing
11
+ class MockStream extends EventEmitter {
12
+ constructor() {
13
+ super();
14
+ this.encoding = null;
15
+ this.writtenData = [];
16
+ }
17
+
18
+ setEncoding(encoding) {
19
+ this.encoding = encoding;
20
+ }
21
+
22
+ write(data) {
23
+ this.writtenData.push(data);
24
+ return true;
25
+ }
26
+ }
27
+
28
+ describe('ACP Integration', () => {
29
+ let server, clientInput, clientOutput, serverInput, serverOutput;
30
+ let mockProbeAgent;
31
+
32
+ beforeEach(async () => {
33
+ // Setup mock streams - simulate client/server communication
34
+ clientInput = new MockStream(); // Client receives from server
35
+ clientOutput = new MockStream(); // Client sends to server
36
+ serverInput = new MockStream(); // Server receives from client
37
+ serverOutput = new MockStream(); // Server sends to client
38
+
39
+ // Connect the streams
40
+ clientOutput.pipe = jest.fn();
41
+ serverOutput.pipe = jest.fn();
42
+
43
+ // Mock ProbeAgent
44
+ const { ProbeAgent } = await import('../ProbeAgent.js');
45
+ mockProbeAgent = {
46
+ answer: jest.fn().mockResolvedValue('Test AI response'),
47
+ cancel: jest.fn(),
48
+ sessionId: 'test-session'
49
+ };
50
+ ProbeAgent.mockImplementation(() => mockProbeAgent);
51
+
52
+ // Create server with mock streams
53
+ server = new ACPServer({ debug: false });
54
+ server.connection = new ACPConnection(serverInput, serverOutput);
55
+ });
56
+
57
+ afterEach(() => {
58
+ if (server.connection) {
59
+ server.connection.close();
60
+ }
61
+ });
62
+
63
+ describe('full protocol flow', () => {
64
+ test('should handle complete initialization flow', async () => {
65
+ // Start server
66
+ server.connection.start();
67
+
68
+ // Simulate client initialization request
69
+ const initRequest = {
70
+ jsonrpc: '2.0',
71
+ method: RequestMethod.INITIALIZE,
72
+ params: { protocolVersion: ACP_PROTOCOL_VERSION },
73
+ id: 1
74
+ };
75
+
76
+ // Simulate receiving the request
77
+ serverInput.emit('data', JSON.stringify(initRequest) + '\n');
78
+
79
+ // Wait for async processing
80
+ await new Promise(resolve => setTimeout(resolve, 10));
81
+
82
+ // Check that server sent response
83
+ expect(serverOutput.writtenData).toHaveLength(1);
84
+ const response = JSON.parse(serverOutput.writtenData[0]);
85
+
86
+ expect(response).toEqual({
87
+ jsonrpc: '2.0',
88
+ id: 1,
89
+ result: {
90
+ protocolVersion: ACP_PROTOCOL_VERSION,
91
+ serverInfo: {
92
+ name: 'probe-agent-acp',
93
+ version: '1.0.0',
94
+ description: 'Probe AI agent with code search capabilities'
95
+ },
96
+ capabilities: server.capabilities
97
+ }
98
+ });
99
+
100
+ expect(server.initialized).toBe(true);
101
+ });
102
+
103
+ test('should handle session creation and prompt flow', async () => {
104
+ server.connection.start();
105
+ server.initialized = true; // Skip initialization for this test
106
+
107
+ // 1. Create new session
108
+ const newSessionRequest = {
109
+ jsonrpc: '2.0',
110
+ method: RequestMethod.NEW_SESSION,
111
+ params: {},
112
+ id: 2
113
+ };
114
+
115
+ serverInput.emit('data', JSON.stringify(newSessionRequest) + '\n');
116
+ await new Promise(resolve => setTimeout(resolve, 10));
117
+
118
+ expect(serverOutput.writtenData).toHaveLength(1);
119
+ const sessionResponse = JSON.parse(serverOutput.writtenData[0]);
120
+ expect(sessionResponse.result.sessionId).toBeDefined();
121
+ const sessionId = sessionResponse.result.sessionId;
122
+
123
+ // Clear previous data
124
+ serverOutput.writtenData = [];
125
+
126
+ // 2. Send prompt request
127
+ const promptRequest = {
128
+ jsonrpc: '2.0',
129
+ method: RequestMethod.PROMPT,
130
+ params: {
131
+ sessionId,
132
+ message: 'How does authentication work in this codebase?'
133
+ },
134
+ id: 3
135
+ };
136
+
137
+ serverInput.emit('data', JSON.stringify(promptRequest) + '\n');
138
+ await new Promise(resolve => setTimeout(resolve, 50)); // Give more time for AI processing
139
+
140
+ // Check that AI was called
141
+ expect(mockProbeAgent.answer).toHaveBeenCalledWith('How does authentication work in this codebase?');
142
+
143
+ // Check response
144
+ expect(serverOutput.writtenData).toHaveLength(1);
145
+ const promptResponse = JSON.parse(serverOutput.writtenData[0]);
146
+
147
+ expect(promptResponse).toEqual({
148
+ jsonrpc: '2.0',
149
+ id: 3,
150
+ result: {
151
+ content: [{ type: 'text', text: 'Test AI response' }],
152
+ sessionId,
153
+ timestamp: expect.any(String)
154
+ }
155
+ });
156
+
157
+ // Check that session history was updated
158
+ const session = server.sessions.get(sessionId);
159
+ expect(session.history).toHaveLength(2);
160
+ expect(session.history[0].role).toBe('user');
161
+ expect(session.history[1].role).toBe('assistant');
162
+ });
163
+
164
+ test('should handle errors gracefully', async () => {
165
+ server.connection.start();
166
+
167
+ // Send invalid method
168
+ const invalidRequest = {
169
+ jsonrpc: '2.0',
170
+ method: 'invalidMethod',
171
+ params: {},
172
+ id: 4
173
+ };
174
+
175
+ serverInput.emit('data', JSON.stringify(invalidRequest) + '\n');
176
+ await new Promise(resolve => setTimeout(resolve, 10));
177
+
178
+ expect(serverOutput.writtenData).toHaveLength(1);
179
+ const errorResponse = JSON.parse(serverOutput.writtenData[0]);
180
+
181
+ expect(errorResponse).toEqual({
182
+ jsonrpc: '2.0',
183
+ id: 4,
184
+ error: {
185
+ code: -32601,
186
+ message: 'Unknown method: invalidMethod'
187
+ }
188
+ });
189
+ });
190
+
191
+ test('should handle session mode changes with notifications', async () => {
192
+ server.connection.start();
193
+ server.initialized = true;
194
+
195
+ // Create session
196
+ const newSessionRequest = {
197
+ jsonrpc: '2.0',
198
+ method: RequestMethod.NEW_SESSION,
199
+ params: {},
200
+ id: 5
201
+ };
202
+
203
+ serverInput.emit('data', JSON.stringify(newSessionRequest) + '\n');
204
+ await new Promise(resolve => setTimeout(resolve, 10));
205
+
206
+ const sessionResponse = JSON.parse(serverOutput.writtenData[0]);
207
+ const sessionId = sessionResponse.result.sessionId;
208
+
209
+ // Clear previous data
210
+ serverOutput.writtenData = [];
211
+
212
+ // Set session mode
213
+ const setModeRequest = {
214
+ jsonrpc: '2.0',
215
+ method: RequestMethod.SET_SESSION_MODE,
216
+ params: {
217
+ sessionId,
218
+ mode: 'planning'
219
+ },
220
+ id: 6
221
+ };
222
+
223
+ serverInput.emit('data', JSON.stringify(setModeRequest) + '\n');
224
+ await new Promise(resolve => setTimeout(resolve, 10));
225
+
226
+ // Should have both response and notification
227
+ expect(serverOutput.writtenData).toHaveLength(2);
228
+
229
+ // Check response
230
+ const modeResponse = JSON.parse(serverOutput.writtenData[0]);
231
+ expect(modeResponse).toEqual({
232
+ jsonrpc: '2.0',
233
+ id: 6,
234
+ result: { success: true }
235
+ });
236
+
237
+ // Check notification
238
+ const notification = JSON.parse(serverOutput.writtenData[1]);
239
+ expect(notification).toEqual({
240
+ jsonrpc: '2.0',
241
+ method: 'sessionUpdated',
242
+ params: {
243
+ sessionId,
244
+ mode: 'planning'
245
+ }
246
+ });
247
+ });
248
+
249
+ test('should handle cancellation', async () => {
250
+ server.connection.start();
251
+ server.initialized = true;
252
+
253
+ // Create session and trigger agent creation
254
+ const newSessionRequest = {
255
+ jsonrpc: '2.0',
256
+ method: RequestMethod.NEW_SESSION,
257
+ params: {},
258
+ id: 7
259
+ };
260
+
261
+ serverInput.emit('data', JSON.stringify(newSessionRequest) + '\n');
262
+ await new Promise(resolve => setTimeout(resolve, 10));
263
+
264
+ const sessionResponse = JSON.parse(serverOutput.writtenData[0]);
265
+ const sessionId = sessionResponse.result.sessionId;
266
+
267
+ // Send a prompt to create the agent
268
+ const promptRequest = {
269
+ jsonrpc: '2.0',
270
+ method: RequestMethod.PROMPT,
271
+ params: {
272
+ sessionId,
273
+ message: 'Test question'
274
+ },
275
+ id: 8
276
+ };
277
+
278
+ serverInput.emit('data', JSON.stringify(promptRequest) + '\n');
279
+ await new Promise(resolve => setTimeout(resolve, 10));
280
+
281
+ // Clear previous data
282
+ serverOutput.writtenData = [];
283
+
284
+ // Send cancel request
285
+ const cancelRequest = {
286
+ jsonrpc: '2.0',
287
+ method: RequestMethod.CANCEL,
288
+ params: { sessionId },
289
+ id: 9
290
+ };
291
+
292
+ serverInput.emit('data', JSON.stringify(cancelRequest) + '\n');
293
+ await new Promise(resolve => setTimeout(resolve, 10));
294
+
295
+ // Check that cancel was called on agent
296
+ expect(mockProbeAgent.cancel).toHaveBeenCalled();
297
+
298
+ // Check response
299
+ expect(serverOutput.writtenData).toHaveLength(1);
300
+ const cancelResponse = JSON.parse(serverOutput.writtenData[0]);
301
+ expect(cancelResponse).toEqual({
302
+ jsonrpc: '2.0',
303
+ id: 9,
304
+ result: { success: true }
305
+ });
306
+ });
307
+ });
308
+
309
+ describe('error handling', () => {
310
+ beforeEach(() => {
311
+ server.connection.start();
312
+ });
313
+
314
+ test('should handle malformed JSON', async () => {
315
+ serverInput.emit('data', 'malformed json\n');
316
+ await new Promise(resolve => setTimeout(resolve, 10));
317
+
318
+ expect(serverOutput.writtenData).toHaveLength(1);
319
+ const errorResponse = JSON.parse(serverOutput.writtenData[0]);
320
+ expect(errorResponse.error.code).toBe(-32700); // Parse error
321
+ });
322
+
323
+ test('should handle invalid JSON-RPC format', async () => {
324
+ const invalidMessage = { jsonrpc: '1.0', method: 'test' };
325
+ serverInput.emit('data', JSON.stringify(invalidMessage) + '\n');
326
+ await new Promise(resolve => setTimeout(resolve, 10));
327
+
328
+ expect(serverOutput.writtenData).toHaveLength(1);
329
+ const errorResponse = JSON.parse(serverOutput.writtenData[0]);
330
+ expect(errorResponse.error.code).toBe(-32600); // Invalid request
331
+ });
332
+
333
+ test('should handle AI errors in prompt processing', async () => {
334
+ server.initialized = true;
335
+
336
+ // Mock AI to throw error
337
+ mockProbeAgent.answer.mockRejectedValue(new Error('AI service unavailable'));
338
+
339
+ // Create session
340
+ await server.handleNewSession({ sessionId: 'test-session' });
341
+
342
+ const promptRequest = {
343
+ jsonrpc: '2.0',
344
+ method: RequestMethod.PROMPT,
345
+ params: {
346
+ sessionId: 'test-session',
347
+ message: 'Test question'
348
+ },
349
+ id: 10
350
+ };
351
+
352
+ serverInput.emit('data', JSON.stringify(promptRequest) + '\n');
353
+ await new Promise(resolve => setTimeout(resolve, 10));
354
+
355
+ expect(serverOutput.writtenData).toHaveLength(1);
356
+ const response = JSON.parse(serverOutput.writtenData[0]);
357
+
358
+ expect(response.result.content[0].text).toBe('Error: AI service unavailable');
359
+ expect(response.result.error).toBe(true);
360
+ });
361
+ });
362
+
363
+ describe('connection management', () => {
364
+ test('should clean up on disconnect', async () => {
365
+ server.connection.start();
366
+ server.initialized = true;
367
+
368
+ // Create some sessions
369
+ await server.handleNewSession({ sessionId: 'session1' });
370
+ await server.handleNewSession({ sessionId: 'session2' });
371
+ await server.handlePrompt({ sessionId: 'session1', message: 'test' });
372
+ await server.handlePrompt({ sessionId: 'session2', message: 'test' });
373
+
374
+ expect(server.sessions.size).toBe(2);
375
+
376
+ // Simulate disconnect
377
+ serverInput.emit('end');
378
+ await new Promise(resolve => setTimeout(resolve, 10));
379
+
380
+ // All sessions should be cleaned up
381
+ expect(server.sessions.size).toBe(0);
382
+ expect(mockProbeAgent.cancel).toHaveBeenCalledTimes(2);
383
+ });
384
+ });
385
+ });