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,217 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ //
7
+ // core/cronManager.ts — Lightweight scheduled task engine.
8
+ //
9
+ // Supports natural-language schedules: "every 5 minutes", "hourly", "daily".
10
+ // Jobs are persisted to ~/.aiden/cron_jobs.json and restored on startup.
11
+ // Uses setInterval — no external cron dependency required.
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.loadJobs = loadJobs;
47
+ exports.parseSchedule = parseSchedule;
48
+ exports.createJob = createJob;
49
+ exports.listJobs = listJobs;
50
+ exports.getJob = getJob;
51
+ exports.pauseJob = pauseJob;
52
+ exports.resumeJob = resumeJob;
53
+ exports.deleteJob = deleteJob;
54
+ exports.triggerJob = triggerJob;
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const os = __importStar(require("os"));
58
+ // ── In-memory registry ────────────────────────────────────────────────────────
59
+ const jobs = new Map();
60
+ const timers = new Map();
61
+ let jobSeq = 1;
62
+ // ── Persistence ───────────────────────────────────────────────────────────────
63
+ const DATA_DIR = path.join(os.homedir(), '.aiden');
64
+ const DATA_FILE = path.join(DATA_DIR, 'cron_jobs.json');
65
+ function save() {
66
+ try {
67
+ if (!fs.existsSync(DATA_DIR))
68
+ fs.mkdirSync(DATA_DIR, { recursive: true });
69
+ fs.writeFileSync(DATA_FILE, JSON.stringify(Array.from(jobs.values()), null, 2), 'utf8');
70
+ }
71
+ catch { /* silent */ }
72
+ }
73
+ function loadJobs() {
74
+ try {
75
+ if (!fs.existsSync(DATA_FILE))
76
+ return;
77
+ const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
78
+ for (const job of data) {
79
+ jobs.set(job.id, job);
80
+ const num = parseInt(job.id, 10);
81
+ if (!isNaN(num) && num >= jobSeq)
82
+ jobSeq = num + 1;
83
+ if (job.enabled)
84
+ _scheduleJob(job);
85
+ }
86
+ }
87
+ catch { /* silent */ }
88
+ }
89
+ // ── Schedule parser ───────────────────────────────────────────────────────────
90
+ // Parses: "every N seconds/minutes/hours/days", "hourly", "daily", numeric ms
91
+ function parseSchedule(schedule) {
92
+ const s = schedule.trim().toLowerCase();
93
+ const match = s.match(/every\s+(\d+)\s+(second|seconds|minute|minutes|hour|hours|day|days)/);
94
+ if (match) {
95
+ const n = parseInt(match[1], 10);
96
+ const unit = match[2].replace(/s$/, '');
97
+ if (unit === 'second')
98
+ return n * 1000;
99
+ if (unit === 'minute')
100
+ return n * 60000;
101
+ if (unit === 'hour')
102
+ return n * 3600000;
103
+ if (unit === 'day')
104
+ return n * 86400000;
105
+ }
106
+ if (s === 'every minute')
107
+ return 60000;
108
+ if (s === 'hourly')
109
+ return 3600000;
110
+ if (s === 'daily')
111
+ return 86400000;
112
+ // Numeric ms fallback
113
+ const ms = parseInt(s, 10);
114
+ if (!isNaN(ms) && ms > 0)
115
+ return ms;
116
+ return 3600000; // default: 1 hour
117
+ }
118
+ // ── Internal scheduler ────────────────────────────────────────────────────────
119
+ function _scheduleJob(job) {
120
+ if (timers.has(job.id))
121
+ return; // already scheduled
122
+ const handle = setInterval(async () => {
123
+ try {
124
+ const { executeTool } = await Promise.resolve().then(() => __importStar(require('./toolRegistry')));
125
+ job.lastRun = new Date().toISOString();
126
+ job.nextRun = new Date(Date.now() + job.intervalMs).toISOString();
127
+ job.runCount++;
128
+ jobs.set(job.id, { ...job });
129
+ save();
130
+ await executeTool('shell_exec', { command: job.action }, 0);
131
+ }
132
+ catch { /* silent — job errors should not crash the process */ }
133
+ }, job.intervalMs);
134
+ // Allow Node.js to exit even if jobs are pending
135
+ if (typeof handle.unref === 'function')
136
+ handle.unref();
137
+ timers.set(job.id, handle);
138
+ }
139
+ // ── Public API ────────────────────────────────────────────────────────────────
140
+ function createJob(description, schedule, action) {
141
+ const intervalMs = parseSchedule(schedule);
142
+ const job = {
143
+ id: String(jobSeq++),
144
+ description,
145
+ schedule,
146
+ intervalMs,
147
+ action,
148
+ enabled: true,
149
+ createdAt: new Date().toISOString(),
150
+ nextRun: new Date(Date.now() + intervalMs).toISOString(),
151
+ runCount: 0,
152
+ };
153
+ jobs.set(job.id, job);
154
+ _scheduleJob(job);
155
+ save();
156
+ return job;
157
+ }
158
+ function listJobs() {
159
+ return Array.from(jobs.values());
160
+ }
161
+ function getJob(id) {
162
+ return jobs.get(id);
163
+ }
164
+ function pauseJob(id) {
165
+ const job = jobs.get(id);
166
+ if (!job)
167
+ return false;
168
+ job.enabled = false;
169
+ const handle = timers.get(id);
170
+ if (handle) {
171
+ clearInterval(handle);
172
+ timers.delete(id);
173
+ }
174
+ jobs.set(id, { ...job });
175
+ save();
176
+ return true;
177
+ }
178
+ function resumeJob(id) {
179
+ const job = jobs.get(id);
180
+ if (!job)
181
+ return false;
182
+ job.enabled = true;
183
+ job.nextRun = new Date(Date.now() + job.intervalMs).toISOString();
184
+ jobs.set(id, { ...job });
185
+ _scheduleJob(job);
186
+ save();
187
+ return true;
188
+ }
189
+ function deleteJob(id) {
190
+ if (!jobs.has(id))
191
+ return false;
192
+ const handle = timers.get(id);
193
+ if (handle) {
194
+ clearInterval(handle);
195
+ timers.delete(id);
196
+ }
197
+ jobs.delete(id);
198
+ save();
199
+ return true;
200
+ }
201
+ async function triggerJob(id) {
202
+ const job = jobs.get(id);
203
+ if (!job)
204
+ return false;
205
+ try {
206
+ const { executeTool } = await Promise.resolve().then(() => __importStar(require('./toolRegistry')));
207
+ job.lastRun = new Date().toISOString();
208
+ job.runCount++;
209
+ jobs.set(id, { ...job });
210
+ save();
211
+ await executeTool('shell_exec', { command: job.action }, 0);
212
+ return true;
213
+ }
214
+ catch {
215
+ return false;
216
+ }
217
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deepKB = exports.DeepKB = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ class DeepKB {
10
+ constructor() {
11
+ this.graph = new Map();
12
+ this.nodes = new Map();
13
+ this.graphPath = path_1.default.join(process.cwd(), 'workspace', 'knowledge', 'deep-graph.json');
14
+ this.load();
15
+ }
16
+ addEntity(id, name, type) {
17
+ this.nodes.set(id, { id, name, type });
18
+ this.save();
19
+ }
20
+ addRelation(fromId, toId, relation, weight = 1.0) {
21
+ if (!this.graph.has(fromId))
22
+ this.graph.set(fromId, []);
23
+ this.graph.get(fromId).push({ fromId, toId, relation, weight });
24
+ this.save();
25
+ }
26
+ // Expand context around a query result — 2 hops max
27
+ expand(startId, depth = 2) {
28
+ const visited = new Set();
29
+ const results = [];
30
+ const dfs = (nodeId, d, rel) => {
31
+ if (d === 0 || visited.has(nodeId))
32
+ return;
33
+ visited.add(nodeId);
34
+ const node = this.nodes.get(nodeId);
35
+ if (node && nodeId !== startId) {
36
+ results.push({ ...node, relation: rel, distance: depth - d + 1 });
37
+ }
38
+ for (const edge of this.graph.get(nodeId) || []) {
39
+ dfs(edge.toId, d - 1, edge.relation);
40
+ }
41
+ };
42
+ dfs(startId, depth, '');
43
+ return results.sort((a, b) => a.distance - b.distance);
44
+ }
45
+ // Auto-extract entities from KB search results and build graph
46
+ ingestFromKBResult(text, sourceId) {
47
+ // Extract capitalized multi-word entities (companies, people, places)
48
+ const entities = text.match(/[A-Z][a-z]+ (?:[A-Z][a-z]+ )*[A-Z][a-z]+|[A-Z]{2,}/g) || [];
49
+ for (const entity of [...new Set(entities)].slice(0, 10)) {
50
+ const entityId = entity.toLowerCase().replace(/\s+/g, '_');
51
+ this.addEntity(entityId, entity, 'extracted');
52
+ this.addRelation(sourceId, entityId, 'mentions', 0.5);
53
+ }
54
+ }
55
+ save() {
56
+ try {
57
+ fs_1.default.mkdirSync(path_1.default.dirname(this.graphPath), { recursive: true });
58
+ fs_1.default.writeFileSync(this.graphPath, JSON.stringify({
59
+ nodes: Object.fromEntries(this.nodes),
60
+ edges: Object.fromEntries(this.graph),
61
+ }, null, 2));
62
+ }
63
+ catch { }
64
+ }
65
+ load() {
66
+ try {
67
+ if (!fs_1.default.existsSync(this.graphPath))
68
+ return;
69
+ const data = JSON.parse(fs_1.default.readFileSync(this.graphPath, 'utf-8'));
70
+ this.nodes = new Map(Object.entries(data.nodes || {}));
71
+ this.graph = new Map(Object.entries(data.edges || {}));
72
+ }
73
+ catch { }
74
+ }
75
+ }
76
+ exports.DeepKB = DeepKB;
77
+ exports.deepKB = new DeepKB();
@@ -0,0 +1,279 @@
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.cleanCorruptedSkills = cleanCorruptedSkills;
11
+ exports.runDoctor = runDoctor;
12
+ // core/doctor.ts — System health checks for DevOS subsystems.
13
+ //
14
+ // Sprint 23: ComputerUse Memory check via MemoryStrategy.
15
+ // Sprint 24: Hardware Detection + First-boot Setup checks.
16
+ //
17
+ // NOTE: This is the sandbox stub. The full implementation (with LLM provider,
18
+ // Docker, database, and tool-registry checks) lives at C:\Users\shiva\DevOS\core\doctor.ts
19
+ // and will be merged on the host machine.
20
+ const fs_1 = __importDefault(require("fs"));
21
+ const path_1 = __importDefault(require("path"));
22
+ const memoryStrategy_1 = require("./memoryStrategy");
23
+ const hardwareDetector_1 = require("./hardwareDetector");
24
+ const setupWizard_1 = require("./setupWizard");
25
+ const evolutionAnalyzer_1 = require("./evolutionAnalyzer");
26
+ const index_1 = require("../providers/index");
27
+ // ── Corrupted skill name patterns ─────────────────────────────
28
+ // Skills with these name patterns are junk auto-generated names
29
+ const CORRUPTED_SKILL_NAMES = [
30
+ 'digital_ledger_app', 'open_batman_com', 'open_esquire_com',
31
+ 'clear_converastion', 'skills_skills', 'which_skill_you',
32
+ 'check_any_those', 'fetch_https_httpbin', 'read_users_shiva',
33
+ 'run_node_console', 'identify_skill_skills', 'open_instagram_com',
34
+ 'open_google_chrome', 'what', 'how_register_trademark',
35
+ 'what_hsn_code', 'what_just_happened', 'give_full_system',
36
+ 'access_uploaded_file', 'provide_data_yesterday',
37
+ ];
38
+ // ── Individual checks ─────────────────────────────────────────
39
+ /**
40
+ * Sprint 23 — ComputerUse Memory check.
41
+ */
42
+ async function checkComputerUseMemory() {
43
+ try {
44
+ const stats = memoryStrategy_1.memoryStrategy.stats();
45
+ const status = stats.total === 0 ? 'warn' : 'ok';
46
+ return {
47
+ name: 'ComputerUse Memory',
48
+ status,
49
+ message: stats.total === 0
50
+ ? 'Memory store is empty — no computer-use sessions recorded yet'
51
+ : `Memory store healthy — ${stats.total} goal(s), avg success rate ${(stats.avgSuccessRate * 100).toFixed(1)}%`,
52
+ detail: {
53
+ totalGoals: stats.total,
54
+ avgSuccessRate: stats.avgSuccessRate,
55
+ topGoals: stats.topGoals,
56
+ },
57
+ };
58
+ }
59
+ catch (err) {
60
+ return {
61
+ name: 'ComputerUse Memory',
62
+ status: 'error',
63
+ message: `Memory store unavailable: ${err?.message ?? 'unknown error'}`,
64
+ };
65
+ }
66
+ }
67
+ // ── Ollama check ──────────────────────────────────────────────
68
+ async function checkOllama() {
69
+ try {
70
+ const ollamaBase = (process.env.OLLAMA_HOST ?? 'http://127.0.0.1:11434').replace(/\/$/, '');
71
+ const r = await fetch(`${ollamaBase}/api/tags`, {
72
+ signal: AbortSignal.timeout(3000),
73
+ });
74
+ if (!r.ok)
75
+ return { name: 'Ollama', status: 'warn', message: `Ollama HTTP ${r.status}` };
76
+ const data = await r.json();
77
+ const all = data.models || [];
78
+ const chatMod = all.filter((m) => !m.name.includes('embed') && !m.name.includes('nomic') && !m.name.includes('mxbai'));
79
+ if (chatMod.length === 0) {
80
+ return { name: 'Ollama', status: 'warn', message: 'Running but no chat models installed', detail: 'Run: ollama pull gemma2:2b' };
81
+ }
82
+ return {
83
+ name: 'Ollama', status: 'ok',
84
+ message: `Running — ${chatMod.length} chat model(s): ${chatMod.map((m) => m.name).join(', ')}`,
85
+ };
86
+ }
87
+ catch {
88
+ return { name: 'Ollama', status: 'warn', message: 'NOT RUNNING — cloud APIs will be used instead', detail: 'Start Ollama for local inference' };
89
+ }
90
+ }
91
+ // ── API keys check ────────────────────────────────────────────
92
+ function checkApiKeys() {
93
+ try {
94
+ const config = (0, index_1.loadConfig)();
95
+ const apis = config.providers?.apis || [];
96
+ const active = apis.filter(a => a.enabled && a.key && a.key.length > 10);
97
+ if (active.length === 0) {
98
+ return { name: 'API Keys', status: 'warn', message: 'NONE configured — add keys in dashboard Settings', detail: 'Go to http://localhost:3000 > Settings > API Keys' };
99
+ }
100
+ const summary = active.map(a => `${a.name}(${a.provider})`).join(', ');
101
+ return { name: 'API Keys', status: 'ok', message: `${active.length} active: ${summary}` };
102
+ }
103
+ catch (e) {
104
+ return { name: 'API Keys', status: 'error', message: `Config load failed: ${e.message}` };
105
+ }
106
+ }
107
+ // ── Port check ────────────────────────────────────────────────
108
+ async function checkPorts() {
109
+ const ports = [4200, 3000, 3001, 11434];
110
+ const labels = { 4200: 'Aiden API', 3000: 'Dashboard', 3001: 'MCP', 11434: 'Ollama' };
111
+ const results = [];
112
+ await Promise.all(ports.map(async (port) => {
113
+ try {
114
+ const ctrl = new AbortController();
115
+ const timer = setTimeout(() => ctrl.abort(), 1500);
116
+ await fetch(`http://localhost:${port}`, { signal: ctrl.signal });
117
+ clearTimeout(timer);
118
+ results.push(`${labels[port]}:${port}(up)`);
119
+ }
120
+ catch (e) {
121
+ if (e.name === 'AbortError') {
122
+ results.push(`${labels[port]}:${port}(up)`); // connected, just no response
123
+ }
124
+ else {
125
+ results.push(`${labels[port]}:${port}(down)`);
126
+ }
127
+ }
128
+ }));
129
+ const down = results.filter(r => r.includes('(down)'));
130
+ return {
131
+ name: 'Ports',
132
+ status: down.length === 0 ? 'ok' : 'warn',
133
+ message: results.join(' | '),
134
+ };
135
+ }
136
+ // ── Skills check ──────────────────────────────────────────────
137
+ function checkSkills() {
138
+ const skillDirs = [
139
+ path_1.default.join(process.cwd(), 'workspace', 'skills', 'learned'),
140
+ path_1.default.join(process.cwd(), 'workspace', 'skills', 'approved'),
141
+ path_1.default.join(process.cwd(), 'skills'),
142
+ ];
143
+ let total = 0;
144
+ let corrupted = 0;
145
+ const corruptedNames = [];
146
+ for (const dir of skillDirs) {
147
+ if (!fs_1.default.existsSync(dir))
148
+ continue;
149
+ try {
150
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
151
+ for (const e of entries) {
152
+ if (!e.isDirectory())
153
+ continue;
154
+ total++;
155
+ if (CORRUPTED_SKILL_NAMES.includes(e.name) || e.name.length < 5 || !e.name.includes('_')) {
156
+ corrupted++;
157
+ corruptedNames.push(e.name);
158
+ }
159
+ }
160
+ }
161
+ catch { }
162
+ }
163
+ if (corrupted > 0) {
164
+ return {
165
+ name: 'Skills', status: 'warn',
166
+ message: `${total} skills, ${corrupted} corrupted — run: devos doctor --clean-skills`,
167
+ detail: `Corrupted: ${corruptedNames.slice(0, 8).join(', ')}${corruptedNames.length > 8 ? '...' : ''}`,
168
+ };
169
+ }
170
+ return { name: 'Skills', status: 'ok', message: `${total} skills loaded, none corrupted` };
171
+ }
172
+ // ── Dashboard check ───────────────────────────────────────────
173
+ function checkDashboard() {
174
+ const pkgPath = path_1.default.join(process.cwd(), 'dashboard-next', 'package.json');
175
+ const distPath = path_1.default.join(process.cwd(), 'dashboard-next', '.next');
176
+ if (!fs_1.default.existsSync(pkgPath)) {
177
+ return { name: 'Dashboard', status: 'error', message: 'MISSING — dashboard-next/ not found' };
178
+ }
179
+ if (!fs_1.default.existsSync(distPath)) {
180
+ return { name: 'Dashboard', status: 'warn', message: 'Found but not built — run: cd dashboard-next && npm run build' };
181
+ }
182
+ return { name: 'Dashboard', status: 'ok', message: 'dashboard-next/ found and built' };
183
+ }
184
+ // ── Scheduler check ───────────────────────────────────────────
185
+ function checkScheduler() {
186
+ try {
187
+ const schedPath = path_1.default.join(process.cwd(), 'workspace', 'scheduled-tasks.json');
188
+ if (!fs_1.default.existsSync(schedPath)) {
189
+ return { name: 'Scheduler', status: 'ok', message: '0 tasks scheduled' };
190
+ }
191
+ const tasks = JSON.parse(fs_1.default.readFileSync(schedPath, 'utf-8'));
192
+ const active = tasks.filter(t => t.enabled !== false).length;
193
+ return { name: 'Scheduler', status: 'ok', message: `${tasks.length} tasks (${active} active)` };
194
+ }
195
+ catch (e) {
196
+ return { name: 'Scheduler', status: 'warn', message: `Could not read tasks: ${e.message}` };
197
+ }
198
+ }
199
+ // ── Clean corrupted skills ─────────────────────────────────────
200
+ function cleanCorruptedSkills() {
201
+ const skillDirs = [
202
+ path_1.default.join(process.cwd(), 'workspace', 'skills', 'learned'),
203
+ path_1.default.join(process.cwd(), 'workspace', 'skills', 'approved'),
204
+ ];
205
+ const deleted = [];
206
+ let kept = 0;
207
+ for (const dir of skillDirs) {
208
+ if (!fs_1.default.existsSync(dir))
209
+ continue;
210
+ try {
211
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
212
+ for (const e of entries) {
213
+ if (!e.isDirectory())
214
+ continue;
215
+ const fullPath = path_1.default.join(dir, e.name);
216
+ const isCorrupted = (CORRUPTED_SKILL_NAMES.includes(e.name) ||
217
+ e.name.length < 5 ||
218
+ (!e.name.includes('_') && e.name !== 'stock_research' && e.name !== 'python_execution'));
219
+ if (isCorrupted) {
220
+ try {
221
+ fs_1.default.rmSync(fullPath, { recursive: true, force: true });
222
+ deleted.push(e.name);
223
+ }
224
+ catch { }
225
+ }
226
+ else {
227
+ kept++;
228
+ }
229
+ }
230
+ }
231
+ catch { }
232
+ }
233
+ return { deleted, kept };
234
+ }
235
+ // ── Doctor runner ─────────────────────────────────────────────
236
+ async function runDoctor() {
237
+ const checks = [];
238
+ // LLM providers
239
+ checks.push(await checkOllama());
240
+ checks.push(checkApiKeys());
241
+ // Network ports
242
+ checks.push(await checkPorts());
243
+ // Sprint 23 — ComputerUse Memory
244
+ checks.push(await checkComputerUseMemory());
245
+ // Sprint 24 — Hardware Detection
246
+ const hw = (0, hardwareDetector_1.detectHardware)();
247
+ checks.push({
248
+ name: 'Hardware Detection',
249
+ status: hw.gpu !== 'Unknown GPU' ? 'ok' : 'warn',
250
+ message: hw.gpu !== 'Unknown GPU'
251
+ ? `GPU detected: ${hw.gpu}`
252
+ : 'GPU not detected - model recommendations may be suboptimal',
253
+ detail: `${hw.gpu} - ${hw.vramGB}GB VRAM - ${hw.ramGB}GB RAM - ${hw.platform}`,
254
+ });
255
+ // Sprint 24 — First-boot Setup
256
+ const setupDone = (0, setupWizard_1.isSetupComplete)();
257
+ checks.push({
258
+ name: 'First-boot Setup',
259
+ status: setupDone ? 'ok' : 'warn',
260
+ message: setupDone ? 'Setup complete' : 'Run: devos setup',
261
+ detail: setupDone ? 'Setup complete' : 'Run: devos setup',
262
+ });
263
+ // Sprint 27 — Self-Evolution Analyzer
264
+ checks.push({
265
+ name: 'Evolution Analyzer',
266
+ status: 'ok',
267
+ message: evolutionAnalyzer_1.evolutionAnalyzer.getSummary(),
268
+ detail: evolutionAnalyzer_1.evolutionAnalyzer.getSummary(),
269
+ });
270
+ // Skills, dashboard, scheduler
271
+ checks.push(checkSkills());
272
+ checks.push(checkDashboard());
273
+ checks.push(checkScheduler());
274
+ return {
275
+ timestamp: new Date().toISOString(),
276
+ checks,
277
+ healthy: checks.every(c => c.status !== 'error'),
278
+ };
279
+ }