@probelabs/probe 0.6.0-rc331 → 0.6.0-rc334

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 (45) hide show
  1. package/bin/binaries/{probe-v0.6.0-rc331-aarch64-apple-darwin.tar.gz → probe-v0.6.0-rc334-aarch64-apple-darwin.tar.gz} +0 -0
  2. package/bin/binaries/{probe-v0.6.0-rc331-aarch64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc334-aarch64-unknown-linux-musl.tar.gz} +0 -0
  3. package/bin/binaries/{probe-v0.6.0-rc331-x86_64-apple-darwin.tar.gz → probe-v0.6.0-rc334-x86_64-apple-darwin.tar.gz} +0 -0
  4. package/bin/binaries/{probe-v0.6.0-rc331-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc334-x86_64-pc-windows-msvc.zip} +0 -0
  5. package/bin/binaries/{probe-v0.6.0-rc331-x86_64-unknown-linux-musl.tar.gz → probe-v0.6.0-rc334-x86_64-unknown-linux-musl.tar.gz} +0 -0
  6. package/build/agent/ProbeAgent.d.ts +105 -4
  7. package/build/agent/ProbeAgent.js +209 -12
  8. package/build/agent/bashExecutor.js +36 -101
  9. package/build/agent/engines/codex.js +367 -88
  10. package/build/agent/engines/governed-answer-failure.js +152 -0
  11. package/build/agent/engines/governed-codex-profile.js +198 -0
  12. package/build/agent/governance/acknowledgedJsonlChannel.js +328 -0
  13. package/build/agent/governance/atomicTerminalReceipt.js +188 -0
  14. package/build/agent/governance/index.d.ts +130 -0
  15. package/build/agent/governance/index.js +8 -0
  16. package/build/agent/mcp/built-in-server.js +152 -53
  17. package/build/agent/mcp/index.d.ts +65 -0
  18. package/build/agent/mcp/index.js +6 -1
  19. package/build/agent/probeTool.js +1 -1
  20. package/build/agent/processSupervisor.js +351 -0
  21. package/build/agent/tools.js +14 -8
  22. package/build/index.js +2 -0
  23. package/build/utils/provider.js +9 -3
  24. package/cjs/agent/ProbeAgent.cjs +13463 -12187
  25. package/cjs/index.cjs +75974 -74139
  26. package/index.d.ts +149 -4
  27. package/package.json +6 -2
  28. package/src/agent/ProbeAgent.d.ts +105 -4
  29. package/src/agent/ProbeAgent.js +209 -12
  30. package/src/agent/bashExecutor.js +36 -101
  31. package/src/agent/engines/codex.js +367 -88
  32. package/src/agent/engines/governed-answer-failure.js +152 -0
  33. package/src/agent/engines/governed-codex-profile.js +198 -0
  34. package/src/agent/governance/acknowledgedJsonlChannel.js +328 -0
  35. package/src/agent/governance/atomicTerminalReceipt.js +188 -0
  36. package/src/agent/governance/index.d.ts +130 -0
  37. package/src/agent/governance/index.js +8 -0
  38. package/src/agent/mcp/built-in-server.js +152 -53
  39. package/src/agent/mcp/index.d.ts +65 -0
  40. package/src/agent/mcp/index.js +6 -1
  41. package/src/agent/probeTool.js +1 -1
  42. package/src/agent/processSupervisor.js +351 -0
  43. package/src/agent/tools.js +14 -8
  44. package/src/index.js +2 -0
  45. package/src/utils/provider.js +9 -3
@@ -5,16 +5,101 @@
5
5
 
6
6
  import { createServer } from 'http';
7
7
  import { EventEmitter } from 'events';
8
- import { randomUUID } from 'crypto';
8
+ import { createHash, randomUUID } from 'crypto';
9
9
  import { Server as MCPServer } from '@modelcontextprotocol/sdk/server/index.js';
10
10
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
11
11
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
12
+ import { asSchema } from 'ai';
13
+ import { searchSchema, extractSchema, listFilesSchema } from '../../tools/common.js';
12
14
  import {
13
15
  CallToolRequestSchema,
14
16
  ListToolsRequestSchema,
15
17
  isInitializeRequest
16
18
  } from '@modelcontextprotocol/sdk/types.js';
17
19
 
20
+ function descriptor(description, schema) {
21
+ const canonical = asSchema(schema);
22
+ return Object.freeze({ description, inputSchema: canonical.jsonSchema, validate: canonical.validate });
23
+ }
24
+
25
+ const TOOL_DESCRIPTORS = Object.freeze({
26
+ search: descriptor('Search for code patterns using semantic search', searchSchema),
27
+ extract: descriptor('Extract code from files or symbols', extractSchema),
28
+ listFiles: descriptor('List files in a directory', listFilesSchema)
29
+ });
30
+
31
+ const ARGUMENT_DOMAIN = Buffer.from('reqproof.probe.tool-arguments/v1', 'utf8');
32
+ const GOVERNED_CODEX_PROFILE_V2 = 'probe.governed-codex-profile/v2';
33
+ const GOVERNED_CALL_LIMIT = 256;
34
+
35
+ function ownData(value, arrays, stack = new Set()) {
36
+ if (value === null || typeof value !== 'object') return;
37
+ if (stack.has(value)) throw new TypeError('cycle');
38
+ stack.add(value);
39
+ const proto = Object.getPrototypeOf(value);
40
+ const isArray = Array.isArray(value);
41
+ if (isArray ? proto !== Array.prototype : proto !== Object.prototype && proto !== null) throw new TypeError('prototype');
42
+ const descriptors = Object.getOwnPropertyDescriptors(value);
43
+ const keys = Reflect.ownKeys(descriptors);
44
+ if (keys.some(key => typeof key === 'symbol')) throw new TypeError('symbol');
45
+ if (isArray) {
46
+ if (!arrays) throw new TypeError('array');
47
+ if (keys.some(key => key !== 'length' && (!/^(0|[1-9]\d*)$/.test(key) || Number(key) >= value.length))) throw new TypeError('array key');
48
+ for (let i = 0; i < value.length; i++) if (!Object.prototype.hasOwnProperty.call(descriptors, i)) throw new TypeError('array hole');
49
+ }
50
+ for (const key of keys) {
51
+ if (isArray && key === 'length') continue;
52
+ const property = descriptors[key];
53
+ if (!property.enumerable || !Object.prototype.hasOwnProperty.call(property, 'value') || key === 'toJSON') throw new TypeError('property');
54
+ ownData(property.value, arrays, stack);
55
+ }
56
+ stack.delete(value);
57
+ }
58
+
59
+ function canonicalJSON(value, stack = new Set()) {
60
+ if (value === null || typeof value === 'boolean' || typeof value === 'string') return JSON.stringify(value);
61
+ if (typeof value === 'number') { if (!Number.isFinite(value)) throw new TypeError('number'); return Object.is(value, -0) ? '0' : JSON.stringify(value); }
62
+ if (typeof value !== 'object' || stack.has(value)) throw new TypeError('value');
63
+ ownData(value, true); stack.add(value);
64
+ let encoded;
65
+ if (Array.isArray(value)) encoded = `[${value.map(item => canonicalJSON(item, stack)).join(',')}]`;
66
+ else encoded = `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${canonicalJSON(value[key], stack)}`).join(',')}}`;
67
+ stack.delete(value); return encoded;
68
+ }
69
+
70
+ function argumentDigest(value) {
71
+ const payload = Buffer.from(canonicalJSON(value), 'utf8');
72
+ const length = bytes => { const out = Buffer.alloc(8); out.writeBigUInt64BE(BigInt(bytes.length)); return out; };
73
+ return `sha256:${createHash('sha256').update(length(ARGUMENT_DOMAIN)).update(ARGUMENT_DOMAIN).update(length(payload)).update(payload).digest('hex')}`;
74
+ }
75
+
76
+ async function validateToolArguments(name, args) {
77
+ const contract = TOOL_DESCRIPTORS[name];
78
+ if (!contract) return { value: args };
79
+ try { if (!args || Array.isArray(args) || typeof args !== 'object') throw new TypeError(); ownData(args, false); }
80
+ catch { throw new TypeError('TOOL_ARGUMENT_CONTAINER_INVALID'); }
81
+ try {
82
+ for (const key of Object.keys(args)) if (!Object.prototype.hasOwnProperty.call(contract.inputSchema.properties, key)) throw new TypeError();
83
+ const validated = await contract.validate(args);
84
+ if (!validated.success) throw new TypeError();
85
+ return { value: validated.value, digest: argumentDigest(validated.value) };
86
+ } catch { throw new TypeError('TOOL_ARGUMENT_VALIDATION_FAILED'); }
87
+ }
88
+
89
+ function emitToolCall(agent, event) {
90
+ agent.events?.emit('toolCall', Object.freeze(event));
91
+ }
92
+
93
+ function abortable(promise, signal) {
94
+ if (!signal) return promise;
95
+ if (signal.aborted) return Promise.reject(new Error('Tool execution cancelled'));
96
+ return new Promise((resolve, reject) => {
97
+ const aborted = () => reject(new Error('Tool execution cancelled'));
98
+ signal.addEventListener('abort', aborted, { once: true });
99
+ promise.then(value => { signal.removeEventListener('abort', aborted); resolve(value); }, error => { signal.removeEventListener('abort', aborted); reject(error); });
100
+ });
101
+ }
102
+
18
103
  /**
19
104
  * Simple in-memory event store for resumability
20
105
  */
@@ -85,6 +170,10 @@ export class BuiltInMCPServer extends EventEmitter {
85
170
  this.streamableTransports = new Map(); // Map of sessionId -> StreamableHTTPServerTransport
86
171
  this.connections = new Set();
87
172
  this.debug = options.debug || false;
173
+ this.governedCallAccounting = options.governedProfileVersion === GOVERNED_CODEX_PROFILE_V2;
174
+ this.governedCallsAdmitted = 0;
175
+ this.governedCallsClosed = 0;
176
+ this.governedCallOverflow = false;
88
177
  }
89
178
 
90
179
  /**
@@ -586,40 +675,7 @@ export class BuiltInMCPServer extends EventEmitter {
586
675
 
587
676
  // Get tools from agent
588
677
  if (this.agent && this.agent.allowedTools) {
589
- const toolDefs = {
590
- search: {
591
- description: 'Search for code patterns using semantic search',
592
- inputSchema: {
593
- type: 'object',
594
- properties: {
595
- query: { type: 'string', description: 'Search query' },
596
- path: { type: 'string', description: 'Directory to search', default: '.' },
597
- maxResults: { type: 'integer', default: 10 }
598
- },
599
- required: ['query']
600
- }
601
- },
602
- extract: {
603
- description: 'Extract code from specific file location',
604
- inputSchema: {
605
- type: 'object',
606
- properties: {
607
- path: { type: 'string', description: 'File path with optional line number' }
608
- },
609
- required: ['path']
610
- }
611
- },
612
- listFiles: {
613
- description: 'List files in a directory',
614
- inputSchema: {
615
- type: 'object',
616
- properties: {
617
- path: { type: 'string', description: 'Directory path' },
618
- pattern: { type: 'string', description: 'File pattern' }
619
- },
620
- required: ['path']
621
- }
622
- },
678
+ const toolDefs = { ...TOOL_DESCRIPTORS,
623
679
  searchFiles: {
624
680
  description: 'Search for files by name pattern',
625
681
  inputSchema: {
@@ -662,7 +718,7 @@ export class BuiltInMCPServer extends EventEmitter {
662
718
  * Handle tool execution
663
719
  */
664
720
  async handleCallTool(params) {
665
- const { name, arguments: args } = params;
721
+ const { name, arguments: rawArgs } = params;
666
722
 
667
723
  // Extract tool name from MCP format
668
724
  const toolName = name.replace('mcp__probe__', '');
@@ -678,27 +734,70 @@ export class BuiltInMCPServer extends EventEmitter {
678
734
  throw new Error(`Tool ${name} not found`);
679
735
  }
680
736
 
681
- try {
682
- // Execute tool directly (no spawning!)
683
- const result = await tool.execute(args);
737
+ let governedCallAdmitted = false;
738
+ if (this.governedCallAccounting) {
739
+ if (this.governedCallsAdmitted >= GOVERNED_CALL_LIMIT) {
740
+ this.governedCallOverflow = true;
741
+ throw new Error('Governed tool call limit exceeded');
742
+ }
743
+ this.governedCallsAdmitted++;
744
+ governedCallAdmitted = true;
745
+ }
684
746
 
685
- return {
686
- content: [{
687
- type: 'text',
688
- text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
689
- }]
690
- };
691
- } catch (error) {
692
- return {
693
- content: [{
694
- type: 'text',
695
- text: `Error executing ${name}: ${error.message}`
696
- }],
697
- isError: true
747
+ try {
748
+ const id = randomUUID();
749
+ const startTime = Date.now();
750
+ let validated;
751
+ try { validated = await validateToolArguments(toolName, rawArgs); } catch (error) {
752
+ const rejectedEvent = { id, name: toolName, sessionId: this.agent.sessionId, startTime, argumentsDigest: null };
753
+ try { emitToolCall(this.agent, { ...rejectedEvent, status: 'in_progress' }); } catch { /* Rejection remains authoritative. */ }
754
+ const endTime = Date.now();
755
+ try { emitToolCall(this.agent, { ...rejectedEvent, status: 'failed', endTime, duration: endTime - startTime }); }
756
+ catch { /* Rejection remains authoritative. */ }
757
+ return { content: [{ type: 'text', text: `Error executing ${name}: ${error.message}` }], isError: true };
758
+ }
759
+ const { value: args, digest: argumentsDigest } = validated;
760
+
761
+ const baseEvent = { id, name: toolName, sessionId: this.agent.sessionId, startTime, ...(argumentsDigest && { argumentsDigest }) };
762
+ const fail = error => {
763
+ const endTime = Date.now();
764
+ try { emitToolCall(this.agent, { ...baseEvent, status: 'failed', error: 'TOOL_EXECUTION_FAILED', endTime, duration: endTime - startTime }); }
765
+ catch (listenerError) { error = listenerError; }
766
+ return { content: [{ type: 'text', text: `Error executing ${name}: ${error.message}` }], isError: true };
698
767
  };
768
+
769
+ try { emitToolCall(this.agent, { ...baseEvent, status: 'in_progress' }); }
770
+ catch (error) { return fail(error); }
771
+
772
+ try {
773
+ // Execute tool directly (no spawning!)
774
+ const signal = this.agent.abortSignal;
775
+ const execution = Promise.resolve().then(() => tool.execute({ ...args, sessionId: this.agent.sessionId, workingDirectory: this.agent.workspaceRoot || this.agent.cwd || process.cwd(), abortSignal: signal }));
776
+ const result = await abortable(execution, signal);
777
+
778
+ const endTime = Date.now();
779
+ try { emitToolCall(this.agent, { ...baseEvent, status: 'completed', endTime, duration: endTime - startTime }); }
780
+ catch { /* Execution already succeeded; observer failure is non-authoritative. */ }
781
+
782
+ return {
783
+ content: [{
784
+ type: 'text',
785
+ text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
786
+ }]
787
+ };
788
+ } catch (error) {
789
+ return fail(error);
790
+ }
791
+ } finally {
792
+ if (governedCallAdmitted) this.governedCallsClosed++;
699
793
  }
700
794
  }
701
795
 
796
+ getGovernedCallEvidence() {
797
+ return Object.freeze({ admitted: this.governedCallsAdmitted, closed: this.governedCallsClosed,
798
+ overflow: this.governedCallOverflow });
799
+ }
800
+
702
801
  /**
703
802
  * Get the number of available tools
704
803
  */
@@ -787,4 +886,4 @@ export class BuiltInMCPServer extends EventEmitter {
787
886
  // rpc: `http://${this.host}:${this.port}/rpc`
788
887
  };
789
888
  }
790
- }
889
+ }
@@ -0,0 +1,65 @@
1
+ import type { ProbeAgent } from '../ProbeAgent.js';
2
+
3
+ export type MCPRecord = Record<string, unknown>;
4
+ export interface BuiltInMCPServerOptions { port?: number; host?: string; debug?: boolean;
5
+ governedProfileVersion?: 'probe.governed-codex-profile/v2'; }
6
+ export interface GovernedCallEvidence { admitted: number; closed: number; overflow: boolean; }
7
+ export interface MCPToolDefinition { name: string; description: string; inputSchema: MCPRecord; }
8
+ export interface MCPToolResult { content: Array<{ type: string; text: string }>; isError?: boolean; }
9
+
10
+ export class BuiltInMCPServer {
11
+ constructor(agent: ProbeAgent, options?: BuiltInMCPServerOptions);
12
+ start(): Promise<{ host: string; port: number }>;
13
+ stop(): Promise<void>;
14
+ handleListTools(): Promise<{ tools: MCPToolDefinition[] }>;
15
+ handleCallTool(params: { name: string; arguments?: MCPRecord }): Promise<MCPToolResult>;
16
+ getGovernedCallEvidence(): Readonly<GovernedCallEvidence>;
17
+ getToolCount(): number;
18
+ getConfig(): { transport: 'http'; url: string };
19
+ }
20
+
21
+ export class MCPClientManager {
22
+ constructor(options?: MCPRecord);
23
+ initialize(config?: MCPRecord | null): Promise<MCPRecord>;
24
+ connectToServer(config: MCPRecord): Promise<unknown>;
25
+ callTool(toolName: string, args?: MCPRecord): Promise<unknown>;
26
+ callGracefulStopAll(): Promise<unknown[]>;
27
+ getTools(): Record<string, unknown>;
28
+ getVercelTools(): Record<string, unknown>;
29
+ disconnect(): Promise<void>;
30
+ }
31
+
32
+ export function createMCPManager(options?: MCPRecord): Promise<MCPClientManager>;
33
+ export function createTransport(serverConfig: MCPRecord): unknown;
34
+ export function loadMCPConfiguration(): MCPRecord;
35
+ export function loadMCPConfigurationFromPath(configPath: string): MCPRecord;
36
+ export function parseEnabledServers(config: MCPRecord): MCPRecord[];
37
+ export function createSampleConfig(): MCPRecord;
38
+ export function saveConfig(config: MCPRecord, path: string): void;
39
+
40
+ export class MCPXmlBridge {
41
+ constructor(options?: MCPRecord);
42
+ initialize(config?: MCPRecord | MCPRecord[] | null): Promise<void>;
43
+ getVercelTools(filterToolNames?: string[] | null): Record<string, unknown>;
44
+ getToolNames(): string[];
45
+ isMcpTool(toolName: string): boolean;
46
+ callGracefulStopAll(): Promise<unknown[]>;
47
+ cleanup(): Promise<void>;
48
+ }
49
+
50
+ export function mcpToolToDescription(name: string, tool: MCPRecord): string;
51
+
52
+ declare const MCP: {
53
+ MCPClientManager: typeof MCPClientManager;
54
+ createMCPManager: typeof createMCPManager;
55
+ createTransport: typeof createTransport;
56
+ loadMCPConfiguration: typeof loadMCPConfiguration;
57
+ loadMCPConfigurationFromPath: typeof loadMCPConfigurationFromPath;
58
+ parseEnabledServers: typeof parseEnabledServers;
59
+ createSampleConfig: typeof createSampleConfig;
60
+ saveConfig: typeof saveConfig;
61
+ MCPXmlBridge: typeof MCPXmlBridge;
62
+ mcpToolToDescription: typeof mcpToolToDescription;
63
+ BuiltInMCPServer: typeof BuiltInMCPServer;
64
+ };
65
+ export default MCP;
@@ -20,6 +20,7 @@ export {
20
20
  MCPXmlBridge,
21
21
  mcpToolToDescription
22
22
  } from './xmlBridge.js';
23
+ export { BuiltInMCPServer } from './built-in-server.js';
23
24
 
24
25
  // Import for default export
25
26
  import { MCPClientManager, createMCPManager, createTransport } from './client.js';
@@ -34,6 +35,7 @@ import {
34
35
  MCPXmlBridge,
35
36
  mcpToolToDescription
36
37
  } from './xmlBridge.js';
38
+ import { BuiltInMCPServer } from './built-in-server.js';
37
39
 
38
40
  // Default export for convenience
39
41
  export default {
@@ -51,5 +53,8 @@ export default {
51
53
 
52
54
  // MCP Bridge
53
55
  MCPXmlBridge,
54
- mcpToolToDescription
56
+ mcpToolToDescription,
57
+
58
+ // Built-in server
59
+ BuiltInMCPServer
55
60
  };
@@ -1,5 +1,5 @@
1
1
  // Simplified tool wrapper for probe agent (based on examples/chat/probeTool.js)
2
- import { listFilesByLevel } from '../index.js';
2
+ import { listFilesByLevel } from '../utils/file-lister.js';
3
3
  import { exec } from 'child_process';
4
4
  import { promisify } from 'util';
5
5
  import { randomUUID } from 'crypto';