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,326 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.reliableWebSearch = reliableWebSearch;
8
+ exports.deepResearch = deepResearch;
9
+ exports.checkSearxNG = checkSearxNG;
10
+ // ── Constants ─────────────────────────────────────────────────
11
+ const SEARXNG_URL = process.env.SEARXNG_URL || 'http://localhost:8888';
12
+ const BRAVE_API_KEY = process.env.BRAVE_SEARCH_API_KEY || '';
13
+ const SEARCH_TIMEOUT = 10000;
14
+ const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36';
15
+ // ── METHOD 1: SearxNG ──────────────────────────────────────────
16
+ async function searchViaSearxNG(query) {
17
+ try {
18
+ const url = `${SEARXNG_URL}/search?q=${encodeURIComponent(query)}&format=json&language=en&categories=general`;
19
+ const res = await fetch(url, {
20
+ headers: { 'User-Agent': USER_AGENT, 'Accept': 'application/json' },
21
+ signal: AbortSignal.timeout(SEARCH_TIMEOUT),
22
+ });
23
+ if (!res.ok) {
24
+ console.warn(`[webSearch] SearxNG returned ${res.status}`);
25
+ return null;
26
+ }
27
+ const data = await res.json();
28
+ const results = (data.results || []).slice(0, 10).map((r) => ({
29
+ title: r.title || '',
30
+ url: r.url || '',
31
+ snippet: r.content || '',
32
+ source: 'searxng',
33
+ }));
34
+ if (results.length === 0)
35
+ return null;
36
+ const lines = results.map(r => `**${r.title}**\n${r.snippet}\n${r.url}`);
37
+ const output = `[SearxNG Results for "${query}"]\n\n${lines.join('\n\n')}`;
38
+ console.log(`[webSearch] SearxNG: ${results.length} results`);
39
+ return { success: true, output, method: 'searxng', results };
40
+ }
41
+ catch (e) {
42
+ console.warn(`[webSearch] SearxNG failed: ${e.message}`);
43
+ return null;
44
+ }
45
+ }
46
+ // ── METHOD 2: Brave Search API ────────────────────────────────
47
+ async function searchViaBrave(query) {
48
+ if (!BRAVE_API_KEY)
49
+ return null;
50
+ try {
51
+ const url = `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=10`;
52
+ const res = await fetch(url, {
53
+ headers: {
54
+ 'Accept': 'application/json',
55
+ 'Accept-Encoding': 'gzip',
56
+ 'X-Subscription-Token': BRAVE_API_KEY,
57
+ },
58
+ signal: AbortSignal.timeout(SEARCH_TIMEOUT),
59
+ });
60
+ if (!res.ok) {
61
+ console.warn(`[webSearch] Brave API returned ${res.status}`);
62
+ return null;
63
+ }
64
+ const data = await res.json();
65
+ const webHits = data?.web?.results || [];
66
+ if (webHits.length === 0)
67
+ return null;
68
+ const results = webHits.map(r => ({
69
+ title: r.title || '',
70
+ url: r.url || '',
71
+ snippet: r.description || '',
72
+ source: 'brave',
73
+ }));
74
+ const lines = results.map(r => `**${r.title}**\n${r.snippet}\n${r.url}`);
75
+ const output = `[Brave Search Results for "${query}"]\n\n${lines.join('\n\n')}`;
76
+ console.log(`[webSearch] Brave: ${results.length} results`);
77
+ return { success: true, output, method: 'brave', results };
78
+ }
79
+ catch (e) {
80
+ console.warn(`[webSearch] Brave failed: ${e.message}`);
81
+ return null;
82
+ }
83
+ }
84
+ // ── METHOD 3: DuckDuckGo (Instant API + HTML scrape) ──────────
85
+ async function searchViaDDG(query) {
86
+ const parts = [];
87
+ // DDG Instant Answer API
88
+ try {
89
+ const ddgUrl = `https://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&no_html=1&skip_disambig=1`;
90
+ const ddgRes = await fetch(ddgUrl, {
91
+ headers: { 'User-Agent': USER_AGENT },
92
+ signal: AbortSignal.timeout(8000),
93
+ });
94
+ const ddgData = await ddgRes.json();
95
+ if (ddgData.Answer)
96
+ parts.push(`Answer: ${ddgData.Answer}`);
97
+ if (ddgData.Abstract)
98
+ parts.push(`Summary: ${ddgData.Abstract}`);
99
+ if (ddgData.AbstractText && !ddgData.Abstract)
100
+ parts.push(ddgData.AbstractText);
101
+ if (ddgData.RelatedTopics?.length) {
102
+ const topics = ddgData.RelatedTopics
103
+ .slice(0, 6)
104
+ .map(t => t.Text || t.Result || '')
105
+ .filter(Boolean);
106
+ if (topics.length)
107
+ parts.push(`Related: ${topics.join('. ')}`);
108
+ }
109
+ }
110
+ catch (e) {
111
+ console.warn(`[webSearch] DDG Instant failed: ${e.message}`);
112
+ }
113
+ // DDG HTML scrape — get snippet text + page content
114
+ try {
115
+ const htmlRes = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, {
116
+ headers: { 'User-Agent': USER_AGENT },
117
+ signal: AbortSignal.timeout(10000),
118
+ });
119
+ const html = await htmlRes.text();
120
+ // Extract snippets
121
+ const snippetMatches = [...html.matchAll(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g)];
122
+ const snippets = snippetMatches
123
+ .map(m => m[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim())
124
+ .filter(s => s.length > 30)
125
+ .slice(0, 5);
126
+ if (snippets.length > 0) {
127
+ parts.push(`Search Snippets:\n${snippets.join('\n')}`);
128
+ }
129
+ // Fetch top 2 result pages
130
+ const urlMatches = [...html.matchAll(/uddg=(https?[^&"]+)/g)];
131
+ const urls = urlMatches
132
+ .map(m => decodeURIComponent(m[1]))
133
+ .filter(u => !u.includes('duckduckgo.com') && !u.includes('youtube.com') && u.startsWith('https'))
134
+ .filter((u, i, arr) => arr.indexOf(u) === i)
135
+ .slice(0, 2);
136
+ const pageTexts = await Promise.all(urls.map(async (url) => {
137
+ try {
138
+ const r = await fetch(url, {
139
+ headers: { 'User-Agent': USER_AGENT },
140
+ signal: AbortSignal.timeout(7000),
141
+ });
142
+ if (!r.ok)
143
+ return null;
144
+ const text = await r.text();
145
+ const clean = text
146
+ .replace(/<script[\s\S]*?<\/script>/gi, '')
147
+ .replace(/<style[\s\S]*?<\/style>/gi, '')
148
+ .replace(/<nav[\s\S]*?<\/nav>/gi, '')
149
+ .replace(/<header[\s\S]*?<\/header>/gi, '')
150
+ .replace(/<footer[\s\S]*?<\/footer>/gi, '')
151
+ .replace(/<[^>]+>/g, ' ')
152
+ .replace(/\s+/g, ' ')
153
+ .trim();
154
+ if (clean.length < 200)
155
+ return null;
156
+ return `[${url}]\n${clean.slice(0, 1500)}`;
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }));
162
+ const validPages = pageTexts.filter(Boolean);
163
+ if (validPages.length > 0)
164
+ parts.push(...validPages);
165
+ }
166
+ catch (e) {
167
+ console.warn(`[webSearch] DDG HTML scrape failed: ${e.message}`);
168
+ }
169
+ if (parts.length === 0)
170
+ return null;
171
+ const output = `[DuckDuckGo Results for "${query}"]\n\n${parts.join('\n\n')}`;
172
+ console.log(`[webSearch] DDG: ${parts.length} sections`);
173
+ return { success: true, output, method: 'ddg' };
174
+ }
175
+ // ── METHOD 4: Wikipedia ───────────────────────────────────────
176
+ async function searchViaWikipedia(query) {
177
+ try {
178
+ const searchRes = await fetch(`https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&srlimit=5&format=json&origin=*`, { signal: AbortSignal.timeout(6000) });
179
+ const searchData = await searchRes.json();
180
+ const hits = searchData?.query?.search || [];
181
+ if (hits.length === 0)
182
+ return null;
183
+ const topTitle = hits[0].title;
184
+ const summaryRes = await fetch(`https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(topTitle)}`, { signal: AbortSignal.timeout(6000) });
185
+ if (!summaryRes.ok)
186
+ return null;
187
+ const wiki = await summaryRes.json();
188
+ if (!wiki.extract || wiki.extract.length < 50)
189
+ return null;
190
+ const snippets = hits
191
+ .slice(1, 4)
192
+ .map(h => h.snippet?.replace(/<[^>]+>/g, '') || '')
193
+ .filter(s => s.length > 20);
194
+ const extra = snippets.length > 0 ? `\n\nRelated: ${snippets.join(' | ')}` : '';
195
+ const output = `[Wikipedia: ${wiki.title}]\n${wiki.extract.slice(0, 1500)}${extra}`;
196
+ console.log(`[webSearch] Wikipedia: ${wiki.extract.length} chars for "${wiki.title}"`);
197
+ return { success: true, output, method: 'wikipedia' };
198
+ }
199
+ catch (e) {
200
+ console.warn(`[webSearch] Wikipedia failed: ${e.message}`);
201
+ return null;
202
+ }
203
+ }
204
+ // ── Weather shortcut ──────────────────────────────────────────
205
+ async function fetchWeather(query) {
206
+ const city = query
207
+ .replace(/what(?:'s| is) the weather/gi, '')
208
+ .replace(/\b(weather|forecast|today|current|temperature|rain|snow|sunny|cloudy|humidity|wind|in|for)\b/gi, '')
209
+ .replace(/\s+/g, ' ')
210
+ .trim() || 'auto';
211
+ try {
212
+ const wr = await fetch(`https://wttr.in/${encodeURIComponent(city)}?format=j1`, { signal: AbortSignal.timeout(8000) });
213
+ const data = await wr.json();
214
+ const cc = data.current_condition?.[0];
215
+ const area = data.nearest_area?.[0];
216
+ if (!cc || !area)
217
+ return null;
218
+ const location = [area.areaName?.[0]?.value, area.country?.[0]?.value].filter(Boolean).join(', ');
219
+ const desc = cc.weatherDesc?.[0]?.value || '';
220
+ let out = `Weather for ${location || city}:\n`;
221
+ out += `Condition: ${desc}\n`;
222
+ out += `Temperature: ${cc.temp_C}°C / ${cc.temp_F}°F (feels like ${cc.FeelsLikeC}°C)\n`;
223
+ out += `Humidity: ${cc.humidity}% | Wind: ${cc.windspeedKmph} km/h ${cc.winddir16Point} | Visibility: ${cc.visibility} km | UV: ${cc.uvIndex}\n`;
224
+ const forecasts = (data.weather || []).slice(0, 3);
225
+ if (forecasts.length) {
226
+ out += '\n3-Day Forecast:\n';
227
+ for (const day of forecasts) {
228
+ const mid = day.hourly?.[4]?.weatherDesc?.[0]?.value || '';
229
+ out += ` ${day.date}: High ${day.maxtempC}°C / Low ${day.mintempC}°C${mid ? ' — ' + mid : ''}\n`;
230
+ }
231
+ }
232
+ console.log(`[webSearch] Weather: retrieved for "${city}"`);
233
+ return { success: true, output: out.trim(), method: 'wttr.in' };
234
+ }
235
+ catch (e) {
236
+ console.warn(`[webSearch] Weather failed: ${e.message}`);
237
+ return null;
238
+ }
239
+ }
240
+ // ── Main exported function ────────────────────────────────────
241
+ async function reliableWebSearch(query) {
242
+ if (!query?.trim())
243
+ return { success: false, output: '', error: 'No query provided' };
244
+ console.log(`[webSearch] Query: "${query}"`);
245
+ // Weather shortcut
246
+ if (/weather|temperature|forecast|rain|snow|sunny|cloudy|humidity|wind/i.test(query)) {
247
+ const weather = await fetchWeather(query);
248
+ if (weather)
249
+ return { success: true, output: weather.output };
250
+ }
251
+ // Method 1 — SearxNG
252
+ const searxResult = await searchViaSearxNG(query);
253
+ if (searxResult) {
254
+ console.log(`[webSearch] ✓ SearxNG succeeded`);
255
+ return { success: true, output: searxResult.output.slice(0, 10000) };
256
+ }
257
+ // Method 2 — Brave
258
+ const braveResult = await searchViaBrave(query);
259
+ if (braveResult) {
260
+ console.log(`[webSearch] ✓ Brave succeeded`);
261
+ return { success: true, output: braveResult.output.slice(0, 10000) };
262
+ }
263
+ // Method 3 — DDG
264
+ const ddgResult = await searchViaDDG(query);
265
+ if (ddgResult) {
266
+ console.log(`[webSearch] ✓ DDG succeeded`);
267
+ return { success: true, output: ddgResult.output.slice(0, 10000) };
268
+ }
269
+ // Method 4 — Wikipedia
270
+ const wikiResult = await searchViaWikipedia(query);
271
+ if (wikiResult) {
272
+ console.log(`[webSearch] ✓ Wikipedia fallback`);
273
+ return { success: true, output: wikiResult.output };
274
+ }
275
+ console.warn(`[webSearch] All methods failed for: "${query}"`);
276
+ return {
277
+ success: false,
278
+ output: '',
279
+ error: `Web search failed for "${query}" — all 4 methods exhausted (SearxNG, Brave, DuckDuckGo, Wikipedia). Try starting SearxNG: .\\scripts\\start-searxng.ps1`,
280
+ };
281
+ }
282
+ // ── Deep research — 3-pass synthesis ─────────────────────────
283
+ async function deepResearch(topic) {
284
+ if (!topic?.trim())
285
+ return { success: false, output: '', error: 'No topic provided' };
286
+ console.log(`[deepResearch] Topic: "${topic}"`);
287
+ const parts = [];
288
+ // Pass 1: Broad
289
+ console.log(`[deepResearch] Pass 1: broad`);
290
+ const broad = await reliableWebSearch(topic);
291
+ if (broad.success && broad.output.length > 100) {
292
+ parts.push(`=== PASS 1: BROAD RESEARCH ===\n${broad.output}`);
293
+ }
294
+ // Pass 2: Latest 2026
295
+ const latestQ = `${topic} 2026 latest`;
296
+ console.log(`[deepResearch] Pass 2: latest — "${latestQ}"`);
297
+ const latest = await reliableWebSearch(latestQ);
298
+ if (latest.success && latest.output.length > 100) {
299
+ parts.push(`=== PASS 2: LATEST (2026) ===\n${latest.output}`);
300
+ }
301
+ // Pass 3: Comparison / review
302
+ const compareQ = `best top ${topic} comparison review`;
303
+ console.log(`[deepResearch] Pass 3: comparison — "${compareQ}"`);
304
+ const compare = await reliableWebSearch(compareQ);
305
+ if (compare.success && compare.output.length > 100) {
306
+ parts.push(`=== PASS 3: COMPARISON & REVIEWS ===\n${compare.output}`);
307
+ }
308
+ if (parts.length === 0) {
309
+ return { success: false, output: '', error: `No research results found for: ${topic}` };
310
+ }
311
+ const combined = parts.join('\n\n');
312
+ console.log(`[deepResearch] Complete: ${combined.length} chars across ${parts.length} passes`);
313
+ return { success: true, output: combined.slice(0, 15000) };
314
+ }
315
+ // ── SearxNG health check ──────────────────────────────────────
316
+ async function checkSearxNG() {
317
+ try {
318
+ const res = await fetch(`${SEARXNG_URL}/search?q=test&format=json`, {
319
+ signal: AbortSignal.timeout(3000),
320
+ });
321
+ return res.ok;
322
+ }
323
+ catch {
324
+ return false;
325
+ }
326
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.startWorkflow = startWorkflow;
8
+ exports.addNode = addNode;
9
+ exports.updateNode = updateNode;
10
+ exports.addEdge = addEdge;
11
+ exports.completeWorkflow = completeWorkflow;
12
+ exports.getWorkflow = getWorkflow;
13
+ // core/workflowTracker.ts — Real-time agent orchestration tracker.
14
+ // Emits workflow events onto eventBus so api/server.ts can forward
15
+ // them to the dashboard via the existing /api/stream SSE channel.
16
+ const eventBus_1 = require("./eventBus");
17
+ // ── State ──────────────────────────────────────────────────────
18
+ let currentWorkflow = null;
19
+ // ── Internal emit ──────────────────────────────────────────────
20
+ function emit(type, payload) {
21
+ eventBus_1.eventBus.emit('workflow_event', { type, ...payload });
22
+ }
23
+ // ── Public API ─────────────────────────────────────────────────
24
+ function startWorkflow(goal) {
25
+ const id = `wf_${Date.now()}`;
26
+ currentWorkflow = {
27
+ id, goal, nodes: [], edges: [],
28
+ status: 'active',
29
+ totalCost: 0,
30
+ totalDuration: 0,
31
+ startedAt: Date.now(),
32
+ };
33
+ emit('workflow:start', { workflow: currentWorkflow });
34
+ return id;
35
+ }
36
+ function addNode(node) {
37
+ if (!currentWorkflow)
38
+ return;
39
+ if (currentWorkflow.nodes.some(n => n.id === node.id))
40
+ return;
41
+ currentWorkflow.nodes.push(node);
42
+ emit('workflow:node:add', { node });
43
+ }
44
+ function updateNode(nodeId, update) {
45
+ if (!currentWorkflow)
46
+ return;
47
+ const node = currentWorkflow.nodes.find(n => n.id === nodeId);
48
+ if (!node)
49
+ return;
50
+ Object.assign(node, update);
51
+ if (update.cost)
52
+ currentWorkflow.totalCost += update.cost;
53
+ emit('workflow:node:update', { nodeId, update });
54
+ }
55
+ function addEdge(edge) {
56
+ if (!currentWorkflow)
57
+ return;
58
+ if (currentWorkflow.edges.some(e => e.id === edge.id))
59
+ return;
60
+ currentWorkflow.edges.push(edge);
61
+ emit('workflow:edge', { edge });
62
+ }
63
+ function completeWorkflow(status) {
64
+ if (!currentWorkflow)
65
+ return;
66
+ currentWorkflow.status = status;
67
+ currentWorkflow.totalDuration = Date.now() - (currentWorkflow.startedAt ?? 0);
68
+ emit('workflow:complete', { workflow: currentWorkflow });
69
+ }
70
+ function getWorkflow() {
71
+ return currentWorkflow;
72
+ }
@@ -0,0 +1,54 @@
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.WorkspaceMemory = void 0;
11
+ // core/workspaceMemory.ts — Per-task file workspace.
12
+ // Each task gets an isolated directory for intermediate artifacts.
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ class WorkspaceMemory {
16
+ constructor(taskId) {
17
+ this.taskDir = path_1.default.join(process.cwd(), 'workspace', 'tasks', taskId);
18
+ fs_1.default.mkdirSync(this.taskDir, { recursive: true });
19
+ }
20
+ write(filename, content) {
21
+ const filePath = path_1.default.join(this.taskDir, filename);
22
+ fs_1.default.writeFileSync(filePath, content, 'utf-8');
23
+ return filePath;
24
+ }
25
+ read(filename) {
26
+ const filePath = path_1.default.join(this.taskDir, filename);
27
+ if (!fs_1.default.existsSync(filePath))
28
+ return null;
29
+ return fs_1.default.readFileSync(filePath, 'utf-8');
30
+ }
31
+ append(filename, content) {
32
+ const filePath = path_1.default.join(this.taskDir, filename);
33
+ fs_1.default.appendFileSync(filePath, content + '\n', 'utf-8');
34
+ return filePath;
35
+ }
36
+ exists(filename) {
37
+ return fs_1.default.existsSync(path_1.default.join(this.taskDir, filename));
38
+ }
39
+ getPath(filename) {
40
+ return path_1.default.join(this.taskDir, filename);
41
+ }
42
+ getDir() {
43
+ return this.taskDir;
44
+ }
45
+ list() {
46
+ try {
47
+ return fs_1.default.readdirSync(this.taskDir);
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ }
53
+ }
54
+ exports.WorkspaceMemory = WorkspaceMemory;
@@ -0,0 +1,224 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.extractVideoId = extractVideoId;
41
+ exports.extractYouTubeTranscript = extractYouTubeTranscript;
42
+ // core/youtubeTranscript.ts — Extract transcripts from YouTube
43
+ // videos using the timedtext API (no API key required).
44
+ // Falls back to yt-dlp if the page fetch is blocked, then to a
45
+ // helpful error message asking the user to paste the transcript.
46
+ const child_process_1 = require("child_process");
47
+ const util_1 = require("util");
48
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
49
+ // ── Video ID extraction ────────────────────────────────────────
50
+ function extractVideoId(url) {
51
+ const patterns = [
52
+ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
53
+ /^([a-zA-Z0-9_-]{11})$/,
54
+ ];
55
+ for (const pattern of patterns) {
56
+ const match = url.match(pattern);
57
+ if (match)
58
+ return match[1];
59
+ }
60
+ return null;
61
+ }
62
+ // ── HTML entity decoder ────────────────────────────────────────
63
+ function decodeHtmlEntities(text) {
64
+ return text
65
+ .replace(/&amp;/g, '&')
66
+ .replace(/&lt;/g, '<')
67
+ .replace(/&gt;/g, '>')
68
+ .replace(/&#39;/g, "'")
69
+ .replace(/&quot;/g, '"')
70
+ .replace(/&#x27;/g, "'")
71
+ .replace(/&#x2F;/g, '/')
72
+ .replace(/<[^>]*>/g, ''); // strip any inline tags
73
+ }
74
+ // ── Method 1: YouTube timedtext API (no key needed) ───────────
75
+ async function fetchViaTimedtextApi(videoId) {
76
+ const pageUrl = `https://www.youtube.com/watch?v=${videoId}`;
77
+ const controller = new AbortController();
78
+ const timer = setTimeout(() => controller.abort(), 15000);
79
+ let pageHtml;
80
+ try {
81
+ const resp = await fetch(pageUrl, {
82
+ signal: controller.signal,
83
+ headers: {
84
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
85
+ 'Accept-Language': 'en-US,en;q=0.9',
86
+ },
87
+ });
88
+ pageHtml = await resp.text();
89
+ }
90
+ finally {
91
+ clearTimeout(timer);
92
+ }
93
+ // Extract caption tracks JSON from page source
94
+ const captionMatch = pageHtml.match(/"captionTracks":\[(\{.*?\})\]/);
95
+ if (!captionMatch) {
96
+ console.log('[YouTube] No captions found in page source');
97
+ return null;
98
+ }
99
+ let captionData;
100
+ try {
101
+ captionData = JSON.parse(`[${captionMatch[1]}]`);
102
+ }
103
+ catch {
104
+ console.log('[YouTube] Failed to parse captionTracks JSON');
105
+ return null;
106
+ }
107
+ // Prefer English, fall back to first available track
108
+ const track = captionData.find((t) => t.languageCode === 'en') ||
109
+ captionData.find((t) => t.languageCode?.startsWith('en')) ||
110
+ captionData[0];
111
+ if (!track?.baseUrl)
112
+ return null;
113
+ // Fetch the XML transcript
114
+ const xmlResp = await fetch(track.baseUrl);
115
+ const xml = await xmlResp.text();
116
+ // Parse <text start="…" dur="…">…</text> entries
117
+ const entries = [];
118
+ const regex = /<text start="([\d.]+)" dur="([\d.]+)"[^>]*>([\s\S]*?)<\/text>/g;
119
+ let m;
120
+ while ((m = regex.exec(xml)) !== null) {
121
+ const text = decodeHtmlEntities(m[3]).trim();
122
+ if (text) {
123
+ entries.push({
124
+ start: parseFloat(m[1]),
125
+ duration: parseFloat(m[2]),
126
+ text,
127
+ });
128
+ }
129
+ }
130
+ if (entries.length === 0)
131
+ return null;
132
+ // Extract page title
133
+ const titleMatch = pageHtml.match(/<title>(.*?)<\/title>/);
134
+ const title = titleMatch?.[1]?.replace(/ - YouTube$/, '').trim() || 'YouTube Video';
135
+ const fullText = entries.map(e => e.text).join(' ');
136
+ return { title, transcript: entries, fullText };
137
+ }
138
+ // ── Method 2: yt-dlp fallback ──────────────────────────────────
139
+ async function fetchViaYtDlp(videoId) {
140
+ const url = `https://www.youtube.com/watch?v=${videoId}`;
141
+ // Check if yt-dlp is available
142
+ try {
143
+ await execAsync('yt-dlp --version', { timeout: 5000 });
144
+ }
145
+ catch {
146
+ console.log('[YouTube] yt-dlp not installed — skipping fallback');
147
+ return null;
148
+ }
149
+ console.log('[YouTube] Trying yt-dlp fallback...');
150
+ // --write-auto-sub + --skip-download + --sub-format vtt
151
+ const cmd = `yt-dlp --write-auto-sub --skip-download --sub-lang en --sub-format vtt -o "/tmp/yt_%(id)s" "${url}"`;
152
+ try {
153
+ await execAsync(cmd, { timeout: 60000 });
154
+ }
155
+ catch (e) {
156
+ console.log('[YouTube] yt-dlp failed:', e.message?.slice(0, 80));
157
+ return null;
158
+ }
159
+ // Read the generated VTT file
160
+ const { readFileSync, existsSync } = await Promise.resolve().then(() => __importStar(require('fs')));
161
+ const vttPath = `/tmp/yt_${videoId}.en.vtt`;
162
+ if (!existsSync(vttPath)) {
163
+ console.log('[YouTube] yt-dlp did not produce a VTT file');
164
+ return null;
165
+ }
166
+ const vtt = readFileSync(vttPath, 'utf8');
167
+ // Parse VTT — strip cue headers and HTML tags, collect text lines
168
+ const lines = vtt.split('\n');
169
+ const texts = [];
170
+ const timeRe = /^\d{2}:\d{2}:\d{2}\.\d{3} --> /;
171
+ for (const line of lines) {
172
+ const trimmed = line.trim();
173
+ if (!trimmed || trimmed === 'WEBVTT' || timeRe.test(trimmed))
174
+ continue;
175
+ if (/^NOTE|^STYLE|^REGION/.test(trimmed))
176
+ continue;
177
+ const clean = trimmed.replace(/<[^>]+>/g, '').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
178
+ if (clean)
179
+ texts.push(clean);
180
+ }
181
+ if (texts.length === 0)
182
+ return null;
183
+ // Deduplicate consecutive identical lines (VTT often repeats)
184
+ const deduped = texts.filter((t, i) => i === 0 || t !== texts[i - 1]);
185
+ const fullText = deduped.join(' ');
186
+ return {
187
+ title: `YouTube Video (${videoId})`,
188
+ transcript: deduped.map((text, i) => ({ text, start: i, duration: 1 })),
189
+ fullText,
190
+ };
191
+ }
192
+ // ── Public entry point ─────────────────────────────────────────
193
+ async function extractYouTubeTranscript(url) {
194
+ const videoId = extractVideoId(url);
195
+ if (!videoId) {
196
+ console.log('[YouTube] Could not extract video ID from URL:', url);
197
+ return null;
198
+ }
199
+ console.log(`[YouTube] Extracting transcript for video: ${videoId}`);
200
+ // Try primary method (timedtext API via page fetch)
201
+ try {
202
+ const result = await fetchViaTimedtextApi(videoId);
203
+ if (result) {
204
+ console.log(`[YouTube] Got transcript via timedtext API: ${result.transcript.length} segments`);
205
+ return result;
206
+ }
207
+ }
208
+ catch (err) {
209
+ console.log('[YouTube] timedtext API failed:', err.message?.slice(0, 120));
210
+ }
211
+ // Try yt-dlp fallback
212
+ try {
213
+ const result = await fetchViaYtDlp(videoId);
214
+ if (result) {
215
+ console.log(`[YouTube] Got transcript via yt-dlp: ${result.transcript.length} segments`);
216
+ return result;
217
+ }
218
+ }
219
+ catch (err) {
220
+ console.log('[YouTube] yt-dlp fallback failed:', err.message?.slice(0, 80));
221
+ }
222
+ console.log('[YouTube] All extraction methods failed for:', videoId);
223
+ return null;
224
+ }