@causyne/agent 1.10.12 → 1.10.17

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 (68) hide show
  1. package/LICENSE +1 -1
  2. package/docs/ARCHITECTURE.md +136 -7
  3. package/docs/SECURITY_REVIEW.md +13 -1
  4. package/docs/THIRD_PARTY_NOTICES.md +43 -10
  5. package/package.json +11 -4
  6. package/src/agentLoop.js +161 -93
  7. package/src/agentProfiles.js +135 -0
  8. package/src/agentProfiles.ts +143 -0
  9. package/src/approvalGrants.js +17 -35
  10. package/src/approvalGrants.ts +54 -0
  11. package/src/auditLog.d.ts +3 -0
  12. package/src/benchmarks/planCache.js +159 -0
  13. package/src/browser/camofoxRuntime.js +93 -0
  14. package/src/browser/camofoxRuntime.ts +112 -0
  15. package/src/browser/causyneBrowser.js +495 -0
  16. package/src/browser/causyneBrowser.ts +594 -0
  17. package/src/browser/searchProviders.js +156 -0
  18. package/src/browser/searchProviders.ts +156 -0
  19. package/src/browser/snapshotWindow.js +28 -0
  20. package/src/browser/snapshotWindow.ts +40 -0
  21. package/src/browser/urlPolicy.js +89 -0
  22. package/src/browser/urlPolicy.ts +89 -0
  23. package/src/checkpoints.js +19 -6
  24. package/src/commands.js +120 -8
  25. package/src/config.d.ts +2 -0
  26. package/src/cortex/autoCondenser.js +1 -1
  27. package/src/hooks.js +150 -0
  28. package/src/hooks.ts +193 -0
  29. package/src/mcp/mcpClient.js +520 -132
  30. package/src/mcp/mcpClient.ts +584 -0
  31. package/src/mcp/mcpRegistry.js +399 -185
  32. package/src/mcp/mcpRegistry.ts +451 -0
  33. package/src/planCache.js +529 -225
  34. package/src/planCache.ts +840 -0
  35. package/src/plugins/pluginManager.js +460 -0
  36. package/src/plugins/pluginRunner.js +50 -0
  37. package/src/plugins/pluginSkills.js +84 -0
  38. package/src/plugins/pluginSkills.ts +106 -0
  39. package/src/provisioning/capabilityProvisioner.d.ts +10 -0
  40. package/src/provisioning/capabilityProvisioner.js +5 -0
  41. package/src/provisioning/capabilityTools.js +2 -1
  42. package/src/sandbox.js +53 -2
  43. package/src/sessionJournal.js +471 -0
  44. package/src/sessionJournal.ts +496 -0
  45. package/src/sessionStore.js +3 -279
  46. package/src/skillsManager.js +18 -0
  47. package/src/subagentJournal.js +215 -0
  48. package/src/subagentJournal.ts +254 -0
  49. package/src/taskShape.js +179 -198
  50. package/src/taskShape.ts +259 -0
  51. package/src/toolPacks.js +6 -3
  52. package/src/tools/browserAutomator.js +45 -241
  53. package/src/tools/browserAutomator.ts +57 -0
  54. package/src/tools/deferredMcpSearch.js +2 -2
  55. package/src/tools/manageLocalAiDependencies.js +1 -1
  56. package/src/tools/pluginManager.js +61 -0
  57. package/src/tools/registry.js +47 -53
  58. package/src/tools/subagentOrchestrator.js +73 -12
  59. package/src/tools/toolForge.js +47 -95
  60. package/src/tools/webFetch.js +183 -68
  61. package/src/tools/webFetch.ts +185 -0
  62. package/src/tools/webSearch.js +50 -75
  63. package/src/tools/webSearch.ts +56 -0
  64. package/src/types/contracts.js +8 -0
  65. package/src/types/contracts.ts +263 -0
  66. package/src/utils/paths.d.ts +3 -0
  67. package/src/version.d.ts +1 -0
  68. package/src/mcp/jsonRpc.js +0 -165
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Shared compile-time contracts for the incremental TypeScript migration.
3
+ *
4
+ * This module deliberately exports types only. Runtime data entering from a
5
+ * model, MCP server, plugin, config file, subprocess, or filesystem still has
6
+ * to be validated before it is treated as one of these shapes.
7
+ */
8
+
9
+ export type JsonPrimitive = string | number | boolean | null;
10
+ export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
11
+ export type JsonObject = { [key: string]: JsonValue };
12
+
13
+ export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
14
+
15
+ export interface TextContentBlock {
16
+ type: 'text';
17
+ text: string;
18
+ }
19
+
20
+ export interface ImageContentBlock {
21
+ type: 'image_url';
22
+ image_url: {
23
+ url: string;
24
+ detail?: 'auto' | 'low' | 'high';
25
+ };
26
+ }
27
+
28
+ export interface AudioContentBlock {
29
+ type: 'input_audio';
30
+ input_audio: {
31
+ data: string;
32
+ format: string;
33
+ };
34
+ }
35
+
36
+ export type MessageContent = string | Array<TextContentBlock | ImageContentBlock | AudioContentBlock | JsonObject>;
37
+
38
+ export interface AgentMessage {
39
+ role: MessageRole;
40
+ content: MessageContent;
41
+ name?: string;
42
+ tool_call_id?: string;
43
+ cacheAnchor?: string;
44
+ spillPath?: string;
45
+ }
46
+
47
+ export interface TokenUsage {
48
+ promptTokens: number;
49
+ completionTokens: number;
50
+ totalTokens?: number;
51
+ }
52
+
53
+ export interface ProviderResponse {
54
+ content: string;
55
+ usage: TokenUsage;
56
+ reasoning?: string;
57
+ toolCalls?: ToolCall[];
58
+ }
59
+
60
+ export interface ProviderChatOptions {
61
+ temperature?: number;
62
+ maxTokens?: number;
63
+ jsonMode?: boolean;
64
+ tools?: ToolSchema[];
65
+ signal?: AbortSignal;
66
+ }
67
+
68
+ export interface JsonSchema {
69
+ type?: string | string[];
70
+ description?: string;
71
+ properties?: Record<string, JsonSchema>;
72
+ required?: string[];
73
+ items?: JsonSchema;
74
+ enum?: JsonPrimitive[];
75
+ additionalProperties?: boolean | JsonSchema;
76
+ }
77
+
78
+ export interface ToolSchema {
79
+ name: string;
80
+ description: string;
81
+ parameters: JsonSchema;
82
+ }
83
+
84
+ export interface ToolCall {
85
+ id?: string;
86
+ name: string;
87
+ arguments: JsonObject;
88
+ }
89
+
90
+ export interface ToolExecutionContext {
91
+ workspace: string;
92
+ signal?: AbortSignal;
93
+ taskId?: string;
94
+ sessionId?: string;
95
+ }
96
+
97
+ export interface ToolSuccess<T extends JsonValue = JsonValue> {
98
+ success: true;
99
+ result: T;
100
+ metadata?: JsonObject;
101
+ }
102
+
103
+ export interface ToolFailure {
104
+ success: false;
105
+ error: string;
106
+ code?: string;
107
+ metadata?: JsonObject;
108
+ }
109
+
110
+ export type ToolResult<T extends JsonValue = JsonValue> = ToolSuccess<T> | ToolFailure;
111
+
112
+ export interface ToolModule<TArguments extends JsonObject = JsonObject, TResult extends JsonValue = JsonValue> {
113
+ schema: ToolSchema;
114
+ execute(arguments_: TArguments, context?: ToolExecutionContext): Promise<ToolResult<TResult>> | ToolResult<TResult>;
115
+ }
116
+
117
+ export type RiskLevel = 'safe' | 'moderate' | 'dangerous' | 'extreme' | 'forbidden';
118
+
119
+ export interface SandboxDecision {
120
+ allowed: boolean;
121
+ risk: RiskLevel;
122
+ reason?: string;
123
+ }
124
+
125
+ export type ApprovalChoice = 'deny' | 'allow_once' | 'allow_always';
126
+
127
+ export interface ApprovalDecision {
128
+ choice: ApprovalChoice;
129
+ toolName: string;
130
+ reason?: string;
131
+ }
132
+
133
+ export type HookEvent = 'PreToolUse' | 'PostToolUse';
134
+
135
+ export interface HookRule {
136
+ event: HookEvent;
137
+ command: string[];
138
+ name?: string;
139
+ tool?: string;
140
+ tools?: string[];
141
+ timeoutMs?: number;
142
+ enabled?: boolean;
143
+ }
144
+
145
+ export interface HookDecision {
146
+ denied: boolean;
147
+ messages: string[];
148
+ reason?: string;
149
+ }
150
+
151
+ export type PlanFailureClass =
152
+ | 'not_found'
153
+ | 'permission'
154
+ | 'timeout'
155
+ | 'network'
156
+ | 'rate_limited'
157
+ | 'invalid_args'
158
+ | 'syntax'
159
+ | 'exit_nonzero'
160
+ | 'failed';
161
+
162
+ export interface PlanStep {
163
+ tool: string;
164
+ note: string;
165
+ ok: boolean;
166
+ why?: PlanFailureClass;
167
+ }
168
+
169
+ export interface PlanTemplate {
170
+ id: string;
171
+ archetype: string;
172
+ keywords: string[];
173
+ steps: PlanStep[];
174
+ uses: number;
175
+ wins: number;
176
+ createdAt: number;
177
+ updatedAt: number;
178
+ }
179
+
180
+ export interface PlanMatch {
181
+ template: PlanTemplate;
182
+ similarity: number;
183
+ matchType: 'exact' | 'fuzzy';
184
+ telemetry: {
185
+ keywordCount: number;
186
+ lookupMs: number;
187
+ };
188
+ }
189
+
190
+ export type PluginCapability = 'workspace:read' | 'workspace:write' | 'network' | 'subprocess';
191
+
192
+ export interface PluginToolManifest {
193
+ name: string;
194
+ description: string;
195
+ parameters: JsonSchema;
196
+ entry: string;
197
+ export?: string;
198
+ capabilities?: PluginCapability[];
199
+ timeoutMs?: number;
200
+ }
201
+
202
+ export interface PluginSkillManifest {
203
+ id: string;
204
+ name?: string;
205
+ description: string;
206
+ file: string;
207
+ }
208
+
209
+ export interface PluginManifest {
210
+ schemaVersion: 1;
211
+ name: string;
212
+ version: string;
213
+ description: string;
214
+ capabilities?: PluginCapability[];
215
+ tools?: PluginToolManifest[];
216
+ skills?: PluginSkillManifest[];
217
+ }
218
+
219
+ export interface AgentProfileManifest {
220
+ schemaVersion: 1;
221
+ name: string;
222
+ description: string;
223
+ instructions: string;
224
+ toolScope: string[];
225
+ maxSteps?: number;
226
+ maxTokens?: number;
227
+ }
228
+
229
+ export interface TaskPhase {
230
+ name: string;
231
+ tools: string[];
232
+ note: string;
233
+ }
234
+
235
+ export interface TaskPackScore {
236
+ name: string;
237
+ score: number;
238
+ }
239
+
240
+ export type TaskConfidence = 'low' | 'medium' | 'high';
241
+
242
+ export interface WorkspaceContext {
243
+ framework?: string;
244
+ projectType?: string;
245
+ designSystem?: string;
246
+ keyFiles?: string[];
247
+ }
248
+
249
+ export interface TaskShape {
250
+ archetype: string;
251
+ archetypeLabel: string;
252
+ packs: TaskPackScore[];
253
+ phases: TaskPhase[];
254
+ confidence: TaskConfidence;
255
+ }
256
+
257
+ export type AgentEvent =
258
+ | { type: 'model.started'; provider: string; model: string }
259
+ | { type: 'model.delta'; text: string }
260
+ | { type: 'tool.requested'; call: ToolCall }
261
+ | { type: 'tool.completed'; callId?: string; result: ToolResult }
262
+ | { type: 'approval.required'; toolName: string; risk: RiskLevel; reason?: string }
263
+ | { type: 'session.notice'; message: string };
@@ -0,0 +1,3 @@
1
+ /** Runtime declarations for the retained JavaScript path boundary. */
2
+ export function resolveUserPath(input: string): string;
3
+ export function causyneHome(): string;
@@ -0,0 +1 @@
1
+ export function getPackageVersion(): string;
@@ -1,165 +0,0 @@
1
-
2
-
3
- import { spawn } from 'child_process';
4
-
5
- const DEFAULT_TIMEOUT_MS = 30000;
6
-
7
- /**
8
- * A JSON-RPC channel over a child process's stdin/stdout.
9
- *
10
- * MCP frames stdio traffic as newline-delimited JSON. stderr is deliberately
11
- * NOT parsed — servers use it for human-readable logging, and treating it as
12
- * protocol is how a chatty server becomes a hang.
13
- */
14
- export class StdioChannel {
15
- constructor({ command, args = [], env = {}, cwd }) {
16
- this.command = command;
17
- this.args = args;
18
- this.env = env;
19
- this.cwd = cwd;
20
- this.child = null;
21
- this.buffer = '';
22
- this.pending = new Map();
23
- this.nextId = 1;
24
- this.notificationHandler = null;
25
- this.stderrTail = [];
26
- }
27
-
28
- async open() {
29
- this.child = spawn(this.command, this.args, {
30
- cwd: this.cwd || process.cwd(),
31
- env: { ...process.env, ...this.env },
32
- stdio: ['pipe', 'pipe', 'pipe']
33
- });
34
-
35
- this.child.stdout.setEncoding('utf-8');
36
- this.child.stdout.on('data', chunk => this.#ingest(chunk));
37
-
38
- // Kept only so a failure can be explained. Bounded, because a server that
39
-
40
- this.child.stderr.setEncoding('utf-8');
41
- this.child.stderr.on('data', chunk => {
42
- this.stderrTail.push(String(chunk));
43
- if (this.stderrTail.length > 20) this.stderrTail.shift();
44
- });
45
-
46
- this.child.on('exit', code => this.#failAll(new Error(`server exited (code ${code})${this.lastError()}`)));
47
- this.child.on('error', err => this.#failAll(err));
48
-
49
- // Surface a command that does not exist as an error rather than a timeout.
50
- await new Promise((resolve, reject) => {
51
- const onError = (err) => reject(err);
52
- this.child.once('error', onError);
53
- setTimeout(() => { this.child.removeListener('error', onError); resolve(); }, 150);
54
- });
55
- }
56
-
57
- lastError() {
58
- const tail = this.stderrTail.join('').trim();
59
- return tail ? `: ${tail.slice(-400)}` : '';
60
- }
61
-
62
- #ingest(chunk) {
63
- this.buffer += chunk;
64
- let newline;
65
- while ((newline = this.buffer.indexOf('\n')) !== -1) {
66
- const line = this.buffer.slice(0, newline).trim();
67
- this.buffer = this.buffer.slice(newline + 1);
68
- if (!line) continue;
69
- let frame;
70
- try { frame = JSON.parse(line); } catch (e) { continue; }
71
- this.#dispatch(frame);
72
- }
73
- }
74
-
75
- #dispatch(frame) {
76
- if (frame.id !== undefined && this.pending.has(frame.id)) {
77
- const { resolve, reject, timer } = this.pending.get(frame.id);
78
- this.pending.delete(frame.id);
79
- clearTimeout(timer);
80
- if (frame.error) reject(new Error(frame.error.message || 'JSON-RPC error'));
81
- else resolve(frame.result);
82
- return;
83
- }
84
- if (frame.method && this.notificationHandler) {
85
- try { this.notificationHandler(frame); } catch (e) {}
86
- }
87
- }
88
-
89
- #failAll(error) {
90
- for (const [, { reject, timer }] of this.pending) {
91
- clearTimeout(timer);
92
- reject(error);
93
- }
94
- this.pending.clear();
95
- }
96
-
97
- send(method, params, timeoutMs = DEFAULT_TIMEOUT_MS) {
98
- if (!this.child || this.child.killed) return Promise.reject(new Error('channel is closed'));
99
- const id = this.nextId++;
100
- const frame = { jsonrpc: '2.0', id, method, params: params ?? {} };
101
-
102
- return new Promise((resolve, reject) => {
103
- const timer = setTimeout(() => {
104
- this.pending.delete(id);
105
- reject(new Error(`${method} timed out after ${timeoutMs} ms`));
106
- }, timeoutMs);
107
- this.pending.set(id, { resolve, reject, timer });
108
- try {
109
- this.child.stdin.write(JSON.stringify(frame) + '\n');
110
- } catch (e) {
111
- clearTimeout(timer);
112
- this.pending.delete(id);
113
- reject(e);
114
- }
115
- });
116
- }
117
-
118
- notify(method, params) {
119
- if (!this.child || this.child.killed) return;
120
- try {
121
- this.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method, params: params ?? {} }) + '\n');
122
- } catch (e) {}
123
- }
124
-
125
- close() {
126
- this.#failAll(new Error('channel closed'));
127
- try { if (this.child) this.child.kill('SIGTERM'); } catch (e) {}
128
- this.child = null;
129
- }
130
- }
131
-
132
- /** A JSON-RPC channel over HTTP POST. One request, one response, no session. */
133
- export class HttpChannel {
134
- constructor({ url, headers = {} }) {
135
- this.url = url;
136
- this.headers = headers;
137
- this.nextId = 1;
138
- this.notificationHandler = null;
139
- }
140
-
141
- async open() {
142
- // Nothing to open. Validate the URL now so a typo fails at connect time
143
- // rather than on the first tool call.
144
- const parsed = new URL(this.url);
145
- if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
146
- throw new Error(`unsupported transport protocol: ${parsed.protocol}`);
147
- }
148
- }
149
-
150
- async send(method, params, timeoutMs = DEFAULT_TIMEOUT_MS) {
151
- const response = await fetch(this.url, {
152
- method: 'POST',
153
- headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', ...this.headers },
154
- body: JSON.stringify({ jsonrpc: '2.0', id: this.nextId++, method, params: params ?? {} }),
155
- signal: AbortSignal.timeout(timeoutMs)
156
- });
157
- if (!response.ok) throw new Error(`HTTP ${response.status} from ${this.url}`);
158
- const frame = await response.json();
159
- if (frame.error) throw new Error(frame.error.message || 'JSON-RPC error');
160
- return frame.result;
161
- }
162
-
163
- notify() { /* HTTP transport has no notification channel */ }
164
- close() { /* nothing to close */ }
165
- }