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.
- package/LICENSE +661 -0
- package/README.md +465 -0
- package/config/devos.config.json +186 -0
- package/config/hardware.json +9 -0
- package/config/model-selection.json +7 -0
- package/config/setup-complete.json +20 -0
- package/dist/api/routes/computerUse.js +112 -0
- package/dist/api/server.js +6870 -0
- package/dist/bin/npx-init.js +71 -0
- package/dist/coordination/commandGate.js +115 -0
- package/dist/coordination/livePulse.js +127 -0
- package/dist/core/agentLoop.js +2718 -0
- package/dist/core/agentShield.js +231 -0
- package/dist/core/aidenIdentity.js +215 -0
- package/dist/core/aidenPersonality.js +166 -0
- package/dist/core/aidenSdk.js +374 -0
- package/dist/core/asyncTasks.js +82 -0
- package/dist/core/auditTrail.js +61 -0
- package/dist/core/auxiliaryClient.js +114 -0
- package/dist/core/bgLLM.js +108 -0
- package/dist/core/bm25.js +68 -0
- package/dist/core/callbackSystem.js +64 -0
- package/dist/core/channels/adapter.js +6 -0
- package/dist/core/channels/discord.js +173 -0
- package/dist/core/channels/email.js +253 -0
- package/dist/core/channels/imessage.js +164 -0
- package/dist/core/channels/manager.js +96 -0
- package/dist/core/channels/signal.js +140 -0
- package/dist/core/channels/slack.js +139 -0
- package/dist/core/channels/twilio.js +144 -0
- package/dist/core/channels/webhook.js +186 -0
- package/dist/core/channels/whatsapp.js +185 -0
- package/dist/core/clarifyBus.js +75 -0
- package/dist/core/codeInterpreter.js +82 -0
- package/dist/core/computerControl.js +439 -0
- package/dist/core/conversationMemory.js +334 -0
- package/dist/core/costTracker.js +221 -0
- package/dist/core/cronManager.js +217 -0
- package/dist/core/deepKB.js +77 -0
- package/dist/core/doctor.js +279 -0
- package/dist/core/dreamEngine.js +334 -0
- package/dist/core/entityGraph.js +169 -0
- package/dist/core/eventBus.js +16 -0
- package/dist/core/evolutionAnalyzer.js +153 -0
- package/dist/core/executionLoop.js +309 -0
- package/dist/core/executor.js +224 -0
- package/dist/core/failureAnalyzer.js +166 -0
- package/dist/core/fastPathExpansion.js +82 -0
- package/dist/core/faultEngine.js +106 -0
- package/dist/core/featureGates.js +70 -0
- package/dist/core/fileIngestion.js +113 -0
- package/dist/core/gateway.js +97 -0
- package/dist/core/goalTracker.js +75 -0
- package/dist/core/growthEngine.js +168 -0
- package/dist/core/hardwareDetector.js +98 -0
- package/dist/core/hooks.js +45 -0
- package/dist/core/httpKeepalive.js +46 -0
- package/dist/core/hybridSearch.js +101 -0
- package/dist/core/importers.js +164 -0
- package/dist/core/instinctSystem.js +223 -0
- package/dist/core/knowledgeBase.js +351 -0
- package/dist/core/learningMemory.js +121 -0
- package/dist/core/lessonsBrowser.js +125 -0
- package/dist/core/licenseManager.js +399 -0
- package/dist/core/logBuffer.js +85 -0
- package/dist/core/machineId.js +87 -0
- package/dist/core/mcpClient.js +442 -0
- package/dist/core/memoryDistiller.js +165 -0
- package/dist/core/memoryExtractor.js +212 -0
- package/dist/core/memoryIds.js +213 -0
- package/dist/core/memoryPreamble.js +113 -0
- package/dist/core/memoryQuery.js +136 -0
- package/dist/core/memoryRecall.js +140 -0
- package/dist/core/memoryStrategy.js +201 -0
- package/dist/core/messageValidator.js +85 -0
- package/dist/core/modelDiscovery.js +108 -0
- package/dist/core/modelRouter.js +118 -0
- package/dist/core/morningBriefing.js +203 -0
- package/dist/core/multiGoalValidator.js +51 -0
- package/dist/core/parallelExecutor.js +43 -0
- package/dist/core/passiveSkillObserver.js +204 -0
- package/dist/core/paths.js +57 -0
- package/dist/core/patternDetector.js +83 -0
- package/dist/core/planResponseRepair.js +64 -0
- package/dist/core/planTool.js +111 -0
- package/dist/core/playwrightBridge.js +356 -0
- package/dist/core/pluginSystem.js +121 -0
- package/dist/core/privateMode.js +85 -0
- package/dist/core/reactLoop.js +156 -0
- package/dist/core/recipeEngine.js +166 -0
- package/dist/core/responseCache.js +128 -0
- package/dist/core/runSandbox.js +132 -0
- package/dist/core/sandboxRunner.js +200 -0
- package/dist/core/scheduler.js +543 -0
- package/dist/core/secretScanner.js +49 -0
- package/dist/core/semanticMemory.js +223 -0
- package/dist/core/sessionMemory.js +259 -0
- package/dist/core/sessionRouter.js +91 -0
- package/dist/core/sessionSearch.js +163 -0
- package/dist/core/setupWizard.js +225 -0
- package/dist/core/skillImporter.js +303 -0
- package/dist/core/skillLibrary.js +144 -0
- package/dist/core/skillLoader.js +471 -0
- package/dist/core/skillTeacher.js +352 -0
- package/dist/core/skillValidator.js +210 -0
- package/dist/core/skillWriter.js +384 -0
- package/dist/core/slashAsTool.js +226 -0
- package/dist/core/spawnManager.js +197 -0
- package/dist/core/statusVerbs.js +43 -0
- package/dist/core/swarmManager.js +109 -0
- package/dist/core/taskQueue.js +119 -0
- package/dist/core/taskRecovery.js +128 -0
- package/dist/core/taskState.js +168 -0
- package/dist/core/telegramBot.js +152 -0
- package/dist/core/todoManager.js +70 -0
- package/dist/core/toolNameRepair.js +71 -0
- package/dist/core/toolRegistry.js +2730 -0
- package/dist/core/tools/calendarTool.js +98 -0
- package/dist/core/tools/companyFilingsTool.js +98 -0
- package/dist/core/tools/gmailTool.js +87 -0
- package/dist/core/tools/marketDataTool.js +135 -0
- package/dist/core/tools/socialResearchTool.js +121 -0
- package/dist/core/truthCheck.js +57 -0
- package/dist/core/updateChecker.js +74 -0
- package/dist/core/userCognitionProfile.js +238 -0
- package/dist/core/userProfile.js +341 -0
- package/dist/core/version.js +5 -0
- package/dist/core/visionAnalyze.js +161 -0
- package/dist/core/voice/audio.js +187 -0
- package/dist/core/voice/stt.js +226 -0
- package/dist/core/voice/tts.js +310 -0
- package/dist/core/voiceInput.js +118 -0
- package/dist/core/voiceOutput.js +130 -0
- package/dist/core/webSearch.js +326 -0
- package/dist/core/workflowTracker.js +72 -0
- package/dist/core/workspaceMemory.js +54 -0
- package/dist/core/youtubeTranscript.js +224 -0
- package/dist/integrations/computerUse/apiRegistry.js +113 -0
- package/dist/integrations/computerUse/screenAgent.js +203 -0
- package/dist/integrations/computerUse/visionLoop.js +296 -0
- package/dist/memory/memoryLayers.js +143 -0
- package/dist/providers/boa.js +93 -0
- package/dist/providers/cerebras.js +70 -0
- package/dist/providers/custom.js +89 -0
- package/dist/providers/gemini.js +82 -0
- package/dist/providers/groq.js +92 -0
- package/dist/providers/index.js +149 -0
- package/dist/providers/nvidia.js +70 -0
- package/dist/providers/ollama.js +99 -0
- package/dist/providers/openrouter.js +74 -0
- package/dist/providers/router.js +497 -0
- package/dist/providers/types.js +6 -0
- package/dist/security/browserVault.js +129 -0
- package/dist/security/dataGuard.js +89 -0
- package/dist/tools/eonetTool.js +72 -0
- package/dist/types/computerUse.js +2 -0
- package/dist/types/executor.js +2 -0
- package/dist-bundle/cli.js +357859 -0
- 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
|
+
}
|