aiden-runtime 3.16.0

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 (159) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +465 -0
  3. package/config/devos.config.json +186 -0
  4. package/config/hardware.json +9 -0
  5. package/config/model-selection.json +7 -0
  6. package/config/setup-complete.json +20 -0
  7. package/dist/api/routes/computerUse.js +112 -0
  8. package/dist/api/server.js +6870 -0
  9. package/dist/bin/npx-init.js +71 -0
  10. package/dist/coordination/commandGate.js +115 -0
  11. package/dist/coordination/livePulse.js +127 -0
  12. package/dist/core/agentLoop.js +2718 -0
  13. package/dist/core/agentShield.js +231 -0
  14. package/dist/core/aidenIdentity.js +215 -0
  15. package/dist/core/aidenPersonality.js +166 -0
  16. package/dist/core/aidenSdk.js +374 -0
  17. package/dist/core/asyncTasks.js +82 -0
  18. package/dist/core/auditTrail.js +61 -0
  19. package/dist/core/auxiliaryClient.js +114 -0
  20. package/dist/core/bgLLM.js +108 -0
  21. package/dist/core/bm25.js +68 -0
  22. package/dist/core/callbackSystem.js +64 -0
  23. package/dist/core/channels/adapter.js +6 -0
  24. package/dist/core/channels/discord.js +173 -0
  25. package/dist/core/channels/email.js +253 -0
  26. package/dist/core/channels/imessage.js +164 -0
  27. package/dist/core/channels/manager.js +96 -0
  28. package/dist/core/channels/signal.js +140 -0
  29. package/dist/core/channels/slack.js +139 -0
  30. package/dist/core/channels/twilio.js +144 -0
  31. package/dist/core/channels/webhook.js +186 -0
  32. package/dist/core/channels/whatsapp.js +185 -0
  33. package/dist/core/clarifyBus.js +75 -0
  34. package/dist/core/codeInterpreter.js +82 -0
  35. package/dist/core/computerControl.js +439 -0
  36. package/dist/core/conversationMemory.js +334 -0
  37. package/dist/core/costTracker.js +221 -0
  38. package/dist/core/cronManager.js +217 -0
  39. package/dist/core/deepKB.js +77 -0
  40. package/dist/core/doctor.js +279 -0
  41. package/dist/core/dreamEngine.js +334 -0
  42. package/dist/core/entityGraph.js +169 -0
  43. package/dist/core/eventBus.js +16 -0
  44. package/dist/core/evolutionAnalyzer.js +153 -0
  45. package/dist/core/executionLoop.js +309 -0
  46. package/dist/core/executor.js +224 -0
  47. package/dist/core/failureAnalyzer.js +166 -0
  48. package/dist/core/fastPathExpansion.js +82 -0
  49. package/dist/core/faultEngine.js +106 -0
  50. package/dist/core/featureGates.js +70 -0
  51. package/dist/core/fileIngestion.js +113 -0
  52. package/dist/core/gateway.js +97 -0
  53. package/dist/core/goalTracker.js +75 -0
  54. package/dist/core/growthEngine.js +168 -0
  55. package/dist/core/hardwareDetector.js +98 -0
  56. package/dist/core/hooks.js +45 -0
  57. package/dist/core/httpKeepalive.js +46 -0
  58. package/dist/core/hybridSearch.js +101 -0
  59. package/dist/core/importers.js +164 -0
  60. package/dist/core/instinctSystem.js +223 -0
  61. package/dist/core/knowledgeBase.js +351 -0
  62. package/dist/core/learningMemory.js +121 -0
  63. package/dist/core/lessonsBrowser.js +125 -0
  64. package/dist/core/licenseManager.js +399 -0
  65. package/dist/core/logBuffer.js +85 -0
  66. package/dist/core/machineId.js +87 -0
  67. package/dist/core/mcpClient.js +442 -0
  68. package/dist/core/memoryDistiller.js +165 -0
  69. package/dist/core/memoryExtractor.js +212 -0
  70. package/dist/core/memoryIds.js +213 -0
  71. package/dist/core/memoryPreamble.js +113 -0
  72. package/dist/core/memoryQuery.js +136 -0
  73. package/dist/core/memoryRecall.js +140 -0
  74. package/dist/core/memoryStrategy.js +201 -0
  75. package/dist/core/messageValidator.js +85 -0
  76. package/dist/core/modelDiscovery.js +108 -0
  77. package/dist/core/modelRouter.js +118 -0
  78. package/dist/core/morningBriefing.js +203 -0
  79. package/dist/core/multiGoalValidator.js +51 -0
  80. package/dist/core/parallelExecutor.js +43 -0
  81. package/dist/core/passiveSkillObserver.js +204 -0
  82. package/dist/core/paths.js +57 -0
  83. package/dist/core/patternDetector.js +83 -0
  84. package/dist/core/planResponseRepair.js +64 -0
  85. package/dist/core/planTool.js +111 -0
  86. package/dist/core/playwrightBridge.js +356 -0
  87. package/dist/core/pluginSystem.js +121 -0
  88. package/dist/core/privateMode.js +85 -0
  89. package/dist/core/reactLoop.js +156 -0
  90. package/dist/core/recipeEngine.js +166 -0
  91. package/dist/core/responseCache.js +128 -0
  92. package/dist/core/runSandbox.js +132 -0
  93. package/dist/core/sandboxRunner.js +200 -0
  94. package/dist/core/scheduler.js +543 -0
  95. package/dist/core/secretScanner.js +49 -0
  96. package/dist/core/semanticMemory.js +223 -0
  97. package/dist/core/sessionMemory.js +259 -0
  98. package/dist/core/sessionRouter.js +91 -0
  99. package/dist/core/sessionSearch.js +163 -0
  100. package/dist/core/setupWizard.js +225 -0
  101. package/dist/core/skillImporter.js +303 -0
  102. package/dist/core/skillLibrary.js +144 -0
  103. package/dist/core/skillLoader.js +471 -0
  104. package/dist/core/skillTeacher.js +352 -0
  105. package/dist/core/skillValidator.js +210 -0
  106. package/dist/core/skillWriter.js +384 -0
  107. package/dist/core/slashAsTool.js +226 -0
  108. package/dist/core/spawnManager.js +197 -0
  109. package/dist/core/statusVerbs.js +43 -0
  110. package/dist/core/swarmManager.js +109 -0
  111. package/dist/core/taskQueue.js +119 -0
  112. package/dist/core/taskRecovery.js +128 -0
  113. package/dist/core/taskState.js +168 -0
  114. package/dist/core/telegramBot.js +152 -0
  115. package/dist/core/todoManager.js +70 -0
  116. package/dist/core/toolNameRepair.js +71 -0
  117. package/dist/core/toolRegistry.js +2730 -0
  118. package/dist/core/tools/calendarTool.js +98 -0
  119. package/dist/core/tools/companyFilingsTool.js +98 -0
  120. package/dist/core/tools/gmailTool.js +87 -0
  121. package/dist/core/tools/marketDataTool.js +135 -0
  122. package/dist/core/tools/socialResearchTool.js +121 -0
  123. package/dist/core/truthCheck.js +57 -0
  124. package/dist/core/updateChecker.js +74 -0
  125. package/dist/core/userCognitionProfile.js +238 -0
  126. package/dist/core/userProfile.js +341 -0
  127. package/dist/core/version.js +5 -0
  128. package/dist/core/visionAnalyze.js +161 -0
  129. package/dist/core/voice/audio.js +187 -0
  130. package/dist/core/voice/stt.js +226 -0
  131. package/dist/core/voice/tts.js +310 -0
  132. package/dist/core/voiceInput.js +118 -0
  133. package/dist/core/voiceOutput.js +130 -0
  134. package/dist/core/webSearch.js +326 -0
  135. package/dist/core/workflowTracker.js +72 -0
  136. package/dist/core/workspaceMemory.js +54 -0
  137. package/dist/core/youtubeTranscript.js +224 -0
  138. package/dist/integrations/computerUse/apiRegistry.js +113 -0
  139. package/dist/integrations/computerUse/screenAgent.js +203 -0
  140. package/dist/integrations/computerUse/visionLoop.js +296 -0
  141. package/dist/memory/memoryLayers.js +143 -0
  142. package/dist/providers/boa.js +93 -0
  143. package/dist/providers/cerebras.js +70 -0
  144. package/dist/providers/custom.js +89 -0
  145. package/dist/providers/gemini.js +82 -0
  146. package/dist/providers/groq.js +92 -0
  147. package/dist/providers/index.js +149 -0
  148. package/dist/providers/nvidia.js +70 -0
  149. package/dist/providers/ollama.js +99 -0
  150. package/dist/providers/openrouter.js +74 -0
  151. package/dist/providers/router.js +497 -0
  152. package/dist/providers/types.js +6 -0
  153. package/dist/security/browserVault.js +129 -0
  154. package/dist/security/dataGuard.js +89 -0
  155. package/dist/tools/eonetTool.js +72 -0
  156. package/dist/types/computerUse.js +2 -0
  157. package/dist/types/executor.js +2 -0
  158. package/dist-bundle/cli.js +357859 -0
  159. package/package.json +256 -0
@@ -0,0 +1,442 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.mcpClient = exports.MCPClient = void 0;
11
+ exports.connectMcpServer = connectMcpServer;
12
+ exports.disconnectMcpServer = disconnectMcpServer;
13
+ exports.listMcpServers = listMcpServers;
14
+ exports.listMcpTools = listMcpTools;
15
+ exports.callMcpTool = callMcpTool;
16
+ // core/mcpClient.ts — MCP (Model Context Protocol) client.
17
+ // Supports both stdio and HTTP MCP servers using JSON-RPC 2.0.
18
+ // Protocol version: 2024-11-05 (MCP spec 1.x)
19
+ //
20
+ // JSON-RPC methods used:
21
+ // "initialize" — capability handshake on connect
22
+ // "tools/list" — discover available tools
23
+ // "tools/call" — invoke a tool with arguments
24
+ const fs_1 = __importDefault(require("fs"));
25
+ const path_1 = __importDefault(require("path"));
26
+ const child_process_1 = require("child_process");
27
+ const version_1 = require("./version");
28
+ // ── Paths ──────────────────────────────────────────────────────
29
+ const LEGACY_CONFIG_PATH = path_1.default.join(process.cwd(), 'config', 'mcp-servers.json');
30
+ const MCP_CONFIG_PATH = path_1.default.join(process.cwd(), 'workspace', 'config', 'mcp.json');
31
+ // ── McpManager — new native client (Phase 1) ──────────────────
32
+ class McpManager {
33
+ constructor() {
34
+ this.configs = new Map();
35
+ this.stdioConns = new Map();
36
+ this.toolCache = new Map();
37
+ }
38
+ // ── Connect ──────────────────────────────────────────────
39
+ async connect(config) {
40
+ this.configs.set(config.name, config);
41
+ if (config.transport === 'stdio') {
42
+ await this._connectStdio(config);
43
+ }
44
+ else {
45
+ await this._connectHttp(config);
46
+ }
47
+ }
48
+ // ── Disconnect ───────────────────────────────────────────
49
+ async disconnect(serverName) {
50
+ const conn = this.stdioConns.get(serverName);
51
+ if (conn) {
52
+ if (conn.retryTimer)
53
+ clearTimeout(conn.retryTimer);
54
+ conn.proc.kill();
55
+ this.stdioConns.delete(serverName);
56
+ }
57
+ this.toolCache.delete(serverName);
58
+ console.log(`[McpManager] Disconnected: ${serverName}`);
59
+ }
60
+ // ── List ─────────────────────────────────────────────────
61
+ servers() {
62
+ return Array.from(this.configs.keys());
63
+ }
64
+ tools() {
65
+ return Array.from(this.toolCache.values()).flat();
66
+ }
67
+ // ── Call tool ────────────────────────────────────────────
68
+ async call(toolName, args) {
69
+ // toolName format: 'serverName:originalName'
70
+ const colonIdx = toolName.indexOf(':');
71
+ if (colonIdx === -1)
72
+ throw new Error(`Invalid MCP tool name: "${toolName}" (expected "server:tool")`);
73
+ const serverName = toolName.slice(0, colonIdx);
74
+ const origName = toolName.slice(colonIdx + 1);
75
+ const config = this.configs.get(serverName);
76
+ if (!config)
77
+ throw new Error(`MCP server not configured: "${serverName}"`);
78
+ if (config.transport === 'stdio') {
79
+ return this._callStdio(serverName, origName, args);
80
+ }
81
+ else {
82
+ return this._callHttp(config, origName, args);
83
+ }
84
+ }
85
+ // ── Load workspace/config/mcp.json ───────────────────────
86
+ async loadConfig() {
87
+ try {
88
+ if (!fs_1.default.existsSync(MCP_CONFIG_PATH))
89
+ return;
90
+ const raw = JSON.parse(fs_1.default.readFileSync(MCP_CONFIG_PATH, 'utf-8'));
91
+ const servers = raw.servers ?? [];
92
+ for (const srv of servers) {
93
+ try {
94
+ // Expand $ENV_VAR references in env values
95
+ const env = {};
96
+ for (const [k, v] of Object.entries(srv.env ?? {})) {
97
+ env[k] = v.startsWith('$')
98
+ ? (process.env[v.slice(1)] ?? '')
99
+ : v;
100
+ }
101
+ await this.connect({ ...srv, env });
102
+ console.log(`[McpManager] Connected server from config: ${srv.name}`);
103
+ }
104
+ catch (e) {
105
+ console.warn(`[McpManager] Failed to connect "${srv.name}": ${e.message}`);
106
+ }
107
+ }
108
+ }
109
+ catch (e) {
110
+ if (!String(e.message).includes('ENOENT')) {
111
+ console.warn(`[McpManager] Failed to load config: ${e.message}`);
112
+ }
113
+ }
114
+ }
115
+ // ── Stdio transport ──────────────────────────────────────
116
+ async _connectStdio(config) {
117
+ const [cmd, ...rest] = (config.command ?? 'npx').split(' ');
118
+ const args = [...rest, ...(config.args ?? [])];
119
+ const env = { ...process.env, ...(config.env ?? {}) };
120
+ const proc = (0, child_process_1.spawn)(cmd, args, {
121
+ stdio: ['pipe', 'pipe', 'pipe'],
122
+ env,
123
+ shell: false,
124
+ });
125
+ const conn = {
126
+ proc,
127
+ buffer: '',
128
+ pending: new Map(),
129
+ nextId: 1,
130
+ config,
131
+ retryCount: 0,
132
+ };
133
+ this.stdioConns.set(config.name, conn);
134
+ proc.stdout.on('data', (chunk) => {
135
+ conn.buffer += chunk.toString();
136
+ // Process newline-delimited JSON messages
137
+ const lines = conn.buffer.split('\n');
138
+ conn.buffer = lines.pop() ?? '';
139
+ for (const line of lines) {
140
+ const trimmed = line.trim();
141
+ if (!trimmed)
142
+ continue;
143
+ try {
144
+ const msg = JSON.parse(trimmed);
145
+ if (msg.id != null && conn.pending.has(msg.id)) {
146
+ const { resolve, reject } = conn.pending.get(msg.id);
147
+ conn.pending.delete(msg.id);
148
+ if (msg.error)
149
+ reject(new Error(`MCP error ${msg.error.code}: ${msg.error.message}`));
150
+ else
151
+ resolve(msg.result);
152
+ }
153
+ }
154
+ catch { }
155
+ }
156
+ });
157
+ proc.on('exit', () => {
158
+ this._scheduleReconnect(config, conn);
159
+ });
160
+ proc.stderr.on('data', (chunk) => {
161
+ // Suppress stderr noise — MCP servers write startup logs here
162
+ });
163
+ // Handshake: send "initialize"
164
+ try {
165
+ await this._rpcStdio(conn, 'initialize', {
166
+ protocolVersion: '2024-11-05',
167
+ capabilities: {},
168
+ clientInfo: { name: 'aiden', version: version_1.VERSION },
169
+ });
170
+ // Discover tools
171
+ const result = await this._rpcStdio(conn, 'tools/list', {});
172
+ const raw = result?.tools ?? [];
173
+ const tools = raw.map((t) => ({
174
+ name: `${config.name}:${t.name}`,
175
+ description: String(t.description || t.name),
176
+ inputSchema: t.inputSchema ?? {},
177
+ serverName: config.name,
178
+ originalName: t.name,
179
+ }));
180
+ this.toolCache.set(config.name, tools);
181
+ conn.retryCount = 0;
182
+ console.log(`[McpManager] stdio/${config.name}: ${tools.length} tool(s) discovered`);
183
+ }
184
+ catch (e) {
185
+ console.warn(`[McpManager] stdio/${config.name} handshake failed: ${e.message}`);
186
+ }
187
+ }
188
+ async _rpcStdio(conn, method, params) {
189
+ return new Promise((resolve, reject) => {
190
+ const id = conn.nextId++;
191
+ const msg = JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n';
192
+ conn.pending.set(id, { resolve, reject });
193
+ const timer = setTimeout(() => {
194
+ conn.pending.delete(id);
195
+ reject(new Error(`RPC timeout: ${method}`));
196
+ }, 15000);
197
+ conn.proc.stdin.write(msg, () => clearTimeout(timer));
198
+ });
199
+ }
200
+ async _callStdio(serverName, toolName, args) {
201
+ const conn = this.stdioConns.get(serverName);
202
+ if (!conn)
203
+ throw new Error(`MCP server "${serverName}" not connected`);
204
+ const result = await this._rpcStdio(conn, 'tools/call', { name: toolName, arguments: args });
205
+ const content = result?.content ?? [];
206
+ return content.map((c) => (typeof c.text === 'string' ? c.text : JSON.stringify(c))).join('\n');
207
+ }
208
+ _scheduleReconnect(config, conn) {
209
+ if (conn.retryCount >= 5) {
210
+ console.warn(`[McpManager] stdio/${config.name}: giving up after 5 retries`);
211
+ return;
212
+ }
213
+ const delayMs = Math.min(1000 * Math.pow(2, conn.retryCount), 30000);
214
+ conn.retryCount++;
215
+ conn.retryTimer = setTimeout(() => {
216
+ console.log(`[McpManager] Reconnecting ${config.name} (attempt ${conn.retryCount})…`);
217
+ this.stdioConns.delete(config.name);
218
+ this._connectStdio(config).catch(() => { });
219
+ }, delayMs);
220
+ }
221
+ // ── HTTP transport ───────────────────────────────────────
222
+ async _connectHttp(config) {
223
+ if (!config.url)
224
+ throw new Error(`HTTP MCP server "${config.name}" has no url`);
225
+ try {
226
+ // send "initialize"
227
+ await this._rpcHttp(config.url, 'initialize', {
228
+ protocolVersion: '2024-11-05',
229
+ capabilities: {},
230
+ clientInfo: { name: 'aiden', version: version_1.VERSION },
231
+ });
232
+ // discover tools via "tools/list"
233
+ const result = await this._rpcHttp(config.url, 'tools/list', {});
234
+ const raw = result?.tools ?? [];
235
+ const tools = raw.map((t) => ({
236
+ name: `${config.name}:${t.name}`,
237
+ description: String(t.description || t.name),
238
+ inputSchema: t.inputSchema ?? {},
239
+ serverName: config.name,
240
+ originalName: t.name,
241
+ }));
242
+ this.toolCache.set(config.name, tools);
243
+ console.log(`[McpManager] http/${config.name}: ${tools.length} tool(s) discovered`);
244
+ }
245
+ catch (e) {
246
+ console.warn(`[McpManager] http/${config.name} handshake failed: ${e.message}`);
247
+ }
248
+ }
249
+ async _rpcHttp(url, method, params) {
250
+ let rpcUrl = url.replace(/\/$/, '');
251
+ // Some servers expect /rpc; others accept POST to root
252
+ const r = await fetch(rpcUrl, {
253
+ method: 'POST',
254
+ headers: { 'Content-Type': 'application/json' },
255
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }),
256
+ signal: AbortSignal.timeout(15000),
257
+ });
258
+ if (!r.ok)
259
+ throw new Error(`HTTP ${r.status}`);
260
+ const data = await r.json();
261
+ if (data?.error)
262
+ throw new Error(`MCP error ${data.error.code}: ${data.error.message}`);
263
+ return data?.result;
264
+ }
265
+ async _callHttp(config, toolName, args) {
266
+ const result = await this._rpcHttp(config.url, 'tools/call', { name: toolName, arguments: args });
267
+ const content = result?.content ?? [];
268
+ return content.map((c) => (typeof c.text === 'string' ? c.text : JSON.stringify(c))).join('\n');
269
+ }
270
+ }
271
+ // ── Singleton McpManager ──────────────────────────────────────
272
+ const mcpManager = new McpManager();
273
+ // Load config in background on startup (no-throw)
274
+ setImmediate(() => mcpManager.loadConfig().catch(() => { }));
275
+ // ── Named function exports (Phase 1 API) ──────────────────────
276
+ async function connectMcpServer(config) {
277
+ return mcpManager.connect(config);
278
+ }
279
+ async function disconnectMcpServer(serverName) {
280
+ return mcpManager.disconnect(serverName);
281
+ }
282
+ function listMcpServers() {
283
+ return mcpManager.servers();
284
+ }
285
+ function listMcpTools() {
286
+ return mcpManager.tools();
287
+ }
288
+ async function callMcpTool(toolName, args) {
289
+ return mcpManager.call(toolName, args);
290
+ }
291
+ // ══════════════════════════════════════════════════════════════
292
+ // Legacy MCPClient class — kept intact for backward compat
293
+ // Used by: agentLoop.ts, api/server.ts, toolRegistry.ts
294
+ // ══════════════════════════════════════════════════════════════
295
+ class MCPClient {
296
+ constructor() {
297
+ this.servers = [];
298
+ this.toolCache = new Map();
299
+ this.load();
300
+ }
301
+ // ── Server management ──────────────────────────────────────
302
+ addServer(name, url, description = '') {
303
+ this.servers = this.servers.filter(s => s.name !== name);
304
+ const server = {
305
+ name,
306
+ url: url.replace(/\/$/, ''),
307
+ enabled: true,
308
+ description,
309
+ addedAt: Date.now(),
310
+ };
311
+ this.servers.push(server);
312
+ this.save();
313
+ console.log(`[MCP] Server added: ${name} → ${server.url}`);
314
+ return server;
315
+ }
316
+ removeServer(name) {
317
+ this.servers = this.servers.filter(s => s.name !== name);
318
+ this.toolCache.delete(name);
319
+ this.save();
320
+ console.log(`[MCP] Server removed: ${name}`);
321
+ }
322
+ toggleServer(name, enabled) {
323
+ const s = this.servers.find(s => s.name === name);
324
+ if (!s)
325
+ return false;
326
+ s.enabled = enabled;
327
+ if (!enabled)
328
+ this.toolCache.delete(name);
329
+ this.save();
330
+ return true;
331
+ }
332
+ listServers() {
333
+ return this.servers;
334
+ }
335
+ // ── Tool discovery ─────────────────────────────────────────
336
+ async discoverTools(serverName) {
337
+ const server = this.servers.find(s => s.name === serverName);
338
+ if (!server || !server.enabled)
339
+ return [];
340
+ try {
341
+ const r = await fetch(`${server.url}/tools/list`, {
342
+ method: 'POST',
343
+ headers: { 'Content-Type': 'application/json' },
344
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }),
345
+ signal: AbortSignal.timeout(8000),
346
+ });
347
+ if (!r.ok) {
348
+ console.warn(`[MCP] discoverTools ${serverName}: HTTP ${r.status}`);
349
+ return [];
350
+ }
351
+ const data = await r.json();
352
+ const rawTools = data?.result?.tools ?? [];
353
+ const tools = rawTools.map((t) => ({
354
+ name: `mcp_${serverName}_${t.name}`,
355
+ description: String(t.description || t.name),
356
+ inputSchema: t.inputSchema ?? {},
357
+ serverName,
358
+ }));
359
+ this.toolCache.set(serverName, tools);
360
+ console.log(`[MCP] Discovered ${tools.length} tool(s) from ${serverName}`);
361
+ return tools;
362
+ }
363
+ catch (e) {
364
+ console.warn(`[MCP] discoverTools ${serverName}: ${e.message}`);
365
+ return [];
366
+ }
367
+ }
368
+ async discoverAllServers() {
369
+ const results = await Promise.allSettled(this.servers.filter(s => s.enabled).map(s => this.discoverTools(s.name)));
370
+ return results.flatMap(r => r.status === 'fulfilled' ? r.value : []);
371
+ }
372
+ // ── Tool execution ─────────────────────────────────────────
373
+ async callTool(serverName, toolName, input) {
374
+ const server = this.servers.find(s => s.name === serverName);
375
+ if (!server)
376
+ return { success: false, output: `MCP server "${serverName}" not found` };
377
+ if (!server.enabled)
378
+ return { success: false, output: `MCP server "${serverName}" is disabled` };
379
+ try {
380
+ const r = await fetch(`${server.url}/tools/call`, {
381
+ method: 'POST',
382
+ headers: { 'Content-Type': 'application/json' },
383
+ body: JSON.stringify({
384
+ jsonrpc: '2.0', id: 1, method: 'tools/call',
385
+ params: { name: toolName, arguments: input },
386
+ }),
387
+ signal: AbortSignal.timeout(30000),
388
+ });
389
+ if (!r.ok)
390
+ return { success: false, output: `MCP call failed: HTTP ${r.status}` };
391
+ const data = await r.json();
392
+ const content = data?.result?.content ?? [];
393
+ const output = content
394
+ .map((c) => (typeof c.text === 'string' ? c.text : JSON.stringify(c)))
395
+ .join('\n').trim();
396
+ if (data?.error) {
397
+ return { success: false, output: `MCP error ${data.error.code ?? ''}: ${data.error.message ?? JSON.stringify(data.error)}` };
398
+ }
399
+ return { success: true, output: output || '(empty response)' };
400
+ }
401
+ catch (e) {
402
+ return { success: false, output: `MCP error: ${e.message}` };
403
+ }
404
+ }
405
+ // ── Cache accessors ────────────────────────────────────────
406
+ getAllCachedTools() {
407
+ return Array.from(this.toolCache.values()).flat();
408
+ }
409
+ getCachedToolsForServer(serverName) {
410
+ return this.toolCache.get(serverName) ?? [];
411
+ }
412
+ // ── Persistence ────────────────────────────────────────────
413
+ load() {
414
+ try {
415
+ const p = fs_1.default.existsSync(MCP_CONFIG_PATH) ? MCP_CONFIG_PATH : LEGACY_CONFIG_PATH;
416
+ if (!fs_1.default.existsSync(p))
417
+ return;
418
+ const raw = fs_1.default.readFileSync(p, 'utf-8');
419
+ // Legacy format: plain array of MCPServer
420
+ // New format: { servers: [...] }
421
+ const parsed = JSON.parse(raw);
422
+ this.servers = Array.isArray(parsed) ? parsed : (parsed.servers ?? []);
423
+ setImmediate(() => this.discoverAllServers().catch(() => { }));
424
+ }
425
+ catch (e) {
426
+ console.warn(`[MCP] Failed to load config: ${e.message}`);
427
+ this.servers = [];
428
+ }
429
+ }
430
+ save() {
431
+ try {
432
+ fs_1.default.mkdirSync(path_1.default.dirname(LEGACY_CONFIG_PATH), { recursive: true });
433
+ fs_1.default.writeFileSync(LEGACY_CONFIG_PATH, JSON.stringify(this.servers, null, 2));
434
+ }
435
+ catch (e) {
436
+ console.warn(`[MCP] Failed to save config: ${e.message}`);
437
+ }
438
+ }
439
+ }
440
+ exports.MCPClient = MCPClient;
441
+ // ── Legacy singleton (backward compat) ────────────────────────
442
+ exports.mcpClient = new MCPClient();
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.distillSession = distillSession;
44
+ exports.distillAllActiveSessions = distillAllActiveSessions;
45
+ // core/memoryDistiller.ts — Session-end memory distillation (N+27).
46
+ // After a session ends (exit, idle, or SSE close), distils the full
47
+ // conversation into 5-15 compact facts via LLM and persists them
48
+ // into semantic memory. Next session they surface via BM25 search
49
+ // without re-loading any conversation history.
50
+ const fs_1 = __importDefault(require("fs"));
51
+ const path_1 = __importDefault(require("path"));
52
+ const conversationMemory_1 = require("./conversationMemory");
53
+ const semanticMemory_1 = require("./semanticMemory");
54
+ const agentLoop_1 = require("./agentLoop");
55
+ const router_1 = require("../providers/router");
56
+ // ── Constants ─────────────────────────────────────────────────
57
+ const DISTILL_PROMPT = `You are a memory distillation system. You will be given a conversation transcript.
58
+ Extract 5 to 15 concise, self-contained facts that would be useful to know in a future session.
59
+ Focus on:
60
+ - Files created, modified, or deleted (include full paths)
61
+ - Decisions made and the reasons behind them
62
+ - Problems solved and the approach that worked
63
+ - User preferences observed (style, tools, workflows)
64
+ - Important entities: repos, APIs, services, credentials locations
65
+ - Tasks completed and their outcomes
66
+
67
+ Output ONLY a plain list, one fact per line, each starting with "- ".
68
+ No headings, no explanations, no blank lines between facts.
69
+ Facts must be self-contained (understandable without the conversation).
70
+ Maximum 15 facts. Minimum 5 facts if the conversation has meaningful content.`;
71
+ const MAX_TRANSCRIPT_CHARS = 32000; // ~8k tokens
72
+ const DISTILL_MARKER_PATH = path_1.default.join(process.cwd(), 'workspace', 'distilled_sessions.json');
73
+ // ── distillSession ────────────────────────────────────────────
74
+ // Main entry point. Reads exchanges for the given sessionId,
75
+ // calls LLM to extract facts, persists to semantic memory.
76
+ // Never throws — all errors are logged and swallowed.
77
+ async function distillSession(sessionId, timeoutMs = 15000) {
78
+ try {
79
+ // Load the correct session
80
+ conversationMemory_1.conversationMemory.setSession(sessionId);
81
+ const exchanges = conversationMemory_1.conversationMemory.state?.exchanges;
82
+ if (!exchanges || exchanges.length < 3) {
83
+ return { factsExtracted: 0, facts: [], skipped: 'too few exchanges' };
84
+ }
85
+ // Check if already distilled
86
+ if (isAlreadyDistilled(sessionId)) {
87
+ return { factsExtracted: 0, facts: [], skipped: 'already distilled' };
88
+ }
89
+ // Build transcript
90
+ let transcript = '';
91
+ for (const ex of exchanges) {
92
+ const turn = `User: ${ex.userMessage}\nAssistant: ${ex.aiReply}\n\n`;
93
+ if (transcript.length + turn.length > MAX_TRANSCRIPT_CHARS)
94
+ break;
95
+ transcript += turn;
96
+ }
97
+ if (!transcript.trim()) {
98
+ return { factsExtracted: 0, facts: [], skipped: 'empty transcript' };
99
+ }
100
+ // Call LLM with timeout
101
+ const tier = (0, router_1.getModelForTask)('planner');
102
+ const prompt = `${DISTILL_PROMPT}\n\n---TRANSCRIPT---\n${transcript}`;
103
+ const raw = await Promise.race([
104
+ (0, agentLoop_1.callLLM)(prompt, tier.apiKey, tier.model, tier.providerName),
105
+ new Promise((_, reject) => setTimeout(() => reject(new Error('distill timeout')), timeoutMs)),
106
+ ]);
107
+ // Parse bullet lines
108
+ const facts = (raw || '')
109
+ .split('\n')
110
+ .map(l => l.replace(/^[-*•]\s*/, '').trim())
111
+ .filter(l => l.length > 10)
112
+ .slice(0, 15);
113
+ if (facts.length === 0) {
114
+ return { factsExtracted: 0, facts: [], skipped: 'no facts parsed' };
115
+ }
116
+ // Persist each fact to semantic memory
117
+ for (const fact of facts) {
118
+ semanticMemory_1.semanticMemory.add(fact, 'fact', ['distilled', sessionId]);
119
+ }
120
+ // N+33: update structured Honcho user profile from distilled facts (non-blocking)
121
+ Promise.resolve().then(() => __importStar(require('./userProfile'))).then(({ updateProfile }) => updateProfile(facts)).catch(() => { });
122
+ // Mark session as distilled
123
+ markDistilled(sessionId);
124
+ console.log(`[MemoryDistiller] Distilled ${facts.length} facts from session ${sessionId}`);
125
+ return { factsExtracted: facts.length, facts };
126
+ }
127
+ catch (err) {
128
+ console.warn('[MemoryDistiller] distillSession failed (non-fatal):', err?.message);
129
+ return { factsExtracted: 0, facts: [], skipped: err?.message ?? 'unknown error' };
130
+ }
131
+ }
132
+ // ── distillAllActiveSessions ──────────────────────────────────
133
+ // Distils every known session — used on SIGINT/SIGTERM so no
134
+ // session is lost when the server shuts down.
135
+ async function distillAllActiveSessions(timeoutMs = 8000) {
136
+ try {
137
+ const sessions = conversationMemory_1.conversationMemory.getSessions();
138
+ await Promise.allSettled(sessions.map(sid => distillSession(sid, timeoutMs)));
139
+ }
140
+ catch (err) {
141
+ console.warn('[MemoryDistiller] distillAllActiveSessions failed:', err?.message);
142
+ }
143
+ }
144
+ // ── Distilled-session tracking ────────────────────────────────
145
+ function loadDistilledSet() {
146
+ try {
147
+ if (fs_1.default.existsSync(DISTILL_MARKER_PATH)) {
148
+ return new Set(JSON.parse(fs_1.default.readFileSync(DISTILL_MARKER_PATH, 'utf-8')));
149
+ }
150
+ }
151
+ catch { }
152
+ return new Set();
153
+ }
154
+ function isAlreadyDistilled(sessionId) {
155
+ return loadDistilledSet().has(sessionId);
156
+ }
157
+ function markDistilled(sessionId) {
158
+ try {
159
+ const set = loadDistilledSet();
160
+ set.add(sessionId);
161
+ fs_1.default.mkdirSync(path_1.default.dirname(DISTILL_MARKER_PATH), { recursive: true });
162
+ fs_1.default.writeFileSync(DISTILL_MARKER_PATH, JSON.stringify([...set], null, 2) + '\n', 'utf-8');
163
+ }
164
+ catch { }
165
+ }