@causyne/agent 1.10.13 → 1.10.18

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 (76) hide show
  1. package/docs/ARCHITECTURE.md +118 -17
  2. package/docs/SECURITY_REVIEW.md +13 -1
  3. package/docs/THIRD_PARTY_NOTICES.md +46 -10
  4. package/package.json +10 -4
  5. package/src/agentLoop.js +123 -21
  6. package/src/agentProfiles.js +135 -0
  7. package/src/agentProfiles.ts +143 -0
  8. package/src/approvalGrants.js +17 -35
  9. package/src/approvalGrants.ts +54 -0
  10. package/src/auditLog.d.ts +3 -0
  11. package/src/browser/browserRuntime.js +88 -0
  12. package/src/browser/browserRuntime.ts +107 -0
  13. package/src/browser/causyneBrowser.js +495 -0
  14. package/src/browser/causyneBrowser.ts +594 -0
  15. package/src/browser/searchProviders.js +156 -0
  16. package/src/browser/searchProviders.ts +156 -0
  17. package/src/browser/snapshotWindow.js +28 -0
  18. package/src/browser/snapshotWindow.ts +40 -0
  19. package/src/browser/urlPolicy.js +89 -0
  20. package/src/browser/urlPolicy.ts +89 -0
  21. package/src/checkpoints.js +19 -6
  22. package/src/cliMode.js +13 -1
  23. package/src/commands.js +37 -8
  24. package/src/config.d.ts +2 -0
  25. package/src/decisionPolicy.js +68 -0
  26. package/src/decisionPolicy.ts +106 -0
  27. package/src/hooks.js +121 -107
  28. package/src/hooks.ts +193 -0
  29. package/src/implementationPlan.js +50 -0
  30. package/src/implementationPlan.ts +59 -0
  31. package/src/mcp/mcpClient.js +520 -132
  32. package/src/mcp/mcpClient.ts +584 -0
  33. package/src/mcp/mcpRegistry.js +399 -185
  34. package/src/mcp/mcpRegistry.ts +451 -0
  35. package/src/planCache.js +473 -450
  36. package/src/planCache.ts +840 -0
  37. package/src/plugins/pluginManager.js +40 -5
  38. package/src/plugins/pluginSkills.js +84 -0
  39. package/src/plugins/pluginSkills.ts +106 -0
  40. package/src/provisioning/capabilityProvisioner.d.ts +10 -0
  41. package/src/provisioning/capabilityProvisioner.js +5 -0
  42. package/src/provisioning/capabilityTools.js +2 -1
  43. package/src/sandbox.js +32 -2
  44. package/src/sessionJournal.js +471 -0
  45. package/src/sessionJournal.ts +496 -0
  46. package/src/sessionStore.js +3 -279
  47. package/src/skillsManager.js +18 -0
  48. package/src/subagentJournal.js +215 -0
  49. package/src/subagentJournal.ts +254 -0
  50. package/src/taskShape.js +179 -198
  51. package/src/taskShape.ts +259 -0
  52. package/src/toolPacks.js +7 -5
  53. package/src/tools/browserAutomator.js +45 -241
  54. package/src/tools/browserAutomator.ts +57 -0
  55. package/src/tools/manageLocalAiDependencies.js +1 -1
  56. package/src/tools/registry.js +4 -3
  57. package/src/tools/requestDecision.js +87 -0
  58. package/src/tools/requestDecision.ts +107 -0
  59. package/src/tools/subagentOrchestrator.js +73 -12
  60. package/src/tools/updatePlan.js +37 -84
  61. package/src/tools/updatePlan.ts +48 -0
  62. package/src/tools/webFetch.js +183 -68
  63. package/src/tools/webFetch.ts +185 -0
  64. package/src/tools/webSearch.js +50 -75
  65. package/src/tools/webSearch.ts +56 -0
  66. package/src/tui/ask.js +41 -1
  67. package/src/tui/chatRenderer.js +28 -0
  68. package/src/tui/dialogs.js +91 -0
  69. package/src/tui/prompt.js +32 -3
  70. package/src/tui/toolDisplay.js +0 -1
  71. package/src/types/contracts.js +8 -0
  72. package/src/types/contracts.ts +263 -0
  73. package/src/utils/paths.d.ts +3 -0
  74. package/src/version.d.ts +1 -0
  75. package/src/mcp/jsonRpc.js +0 -165
  76. package/src/tools/todoWrite.js +0 -75
@@ -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
- }
@@ -1,75 +0,0 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
-
4
- export const todoWrite = {
5
- schema: {
6
- name: 'TodoWrite',
7
- description: 'Dynamic Context Injector: Create and manage structured tasks. Forces atomic, granular steps instead of vague goals.',
8
- parameters: {
9
- type: 'object',
10
- properties: {
11
- todos: {
12
- type: 'array',
13
- description: 'The updated todo list (JSON state)',
14
- items: {
15
- type: 'object',
16
- properties: {
17
- id: { type: 'string' },
18
- content: { type: 'string', minLength: 5, description: 'Must be an atomic, actionable step.' },
19
- status: {
20
- type: 'string',
21
- enum: ['pending', 'in_progress', 'completed']
22
- }
23
- },
24
- required: ['id', 'content', 'status'],
25
- additionalProperties: false
26
- }
27
- }
28
- },
29
- required: ['todos'],
30
- additionalProperties: false
31
- }
32
- },
33
- async execute(args) {
34
- try {
35
- const todoPath = path.join(process.cwd(), '.causyne_todos.json');
36
- const mdPath = path.join(process.cwd(), 'AGI_PLAN.md');
37
-
38
- // Phase 2 AGI Upgrade: Atomic Validation
39
- for (const task of args.todos) {
40
- const words = task.content.split(' ').length;
41
- if (words < 2) {
42
- return { success: false, error: `Task [${task.id}] is too vague ("${task.content}"). Rewrite it into an atomic, actionable step (e.g., "Scaffold React Navbar").` };
43
- }
44
- }
45
-
46
- // Save JSON state
47
- await fs.writeFile(todoPath, JSON.stringify(args.todos, null, 2), 'utf8');
48
-
49
- // Render to MD for user visibility
50
- let mdContent = '# AGI Execution Plan\n\n';
51
- for (const t of args.todos) {
52
- let box = '[ ]';
53
- if (t.status === 'in_progress') box = '[/]';
54
- if (t.status === 'completed') box = '[x]';
55
- mdContent += `- ${box} ${t.id}: ${t.content}\n`;
56
- }
57
- await fs.writeFile(mdPath, mdContent, 'utf8');
58
-
59
- // Phase 2 AGI Upgrade: Memory Hook (Signaling back to AgentLoop context window)
60
- const inProgress = args.todos.filter(t => t.status === 'in_progress');
61
- const completed = args.todos.filter(t => t.status === 'completed');
62
-
63
- if (inProgress.length > 1) {
64
- return { success: true, output: `[Memory Hook] Saved. WARNING: You have ${inProgress.length} tasks in_progress. Only ONE task may be in progress at a time.` };
65
- }
66
-
67
- return {
68
- success: true,
69
- output: `[Memory Hook] Tasks synchronized. ${completed.length} completed, ${inProgress.length} active. Focus locked on: ${inProgress[0]?.content || 'None'}`
70
- };
71
- } catch (e) {
72
- return { success: false, error: e.message };
73
- }
74
- }
75
- };