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,543 @@
|
|
|
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.scheduler = exports.Scheduler = void 0;
|
|
44
|
+
exports.naturalToCron = naturalToCron;
|
|
45
|
+
exports.scheduleReminder = scheduleReminder;
|
|
46
|
+
exports.listReminders = listReminders;
|
|
47
|
+
exports.cancelReminder = cancelReminder;
|
|
48
|
+
exports.initReminderScheduler = initReminderScheduler;
|
|
49
|
+
// core/scheduler.ts — Natural-language scheduled task engine.
|
|
50
|
+
// Converts human schedules ("every monday at 9am") to cron expressions,
|
|
51
|
+
// fires tasks against the local /api/chat endpoint, and persists state.
|
|
52
|
+
const fs_1 = __importDefault(require("fs"));
|
|
53
|
+
const path_1 = __importDefault(require("path"));
|
|
54
|
+
const morningBriefing_1 = require("./morningBriefing");
|
|
55
|
+
const dreamEngine_1 = require("./dreamEngine");
|
|
56
|
+
const goalTracker_1 = require("./goalTracker");
|
|
57
|
+
const patternDetector_1 = require("./patternDetector");
|
|
58
|
+
const TASKS_PATH = path_1.default.join(process.cwd(), 'workspace', 'scheduled-tasks.json');
|
|
59
|
+
const HEARTBEAT_PATH = path_1.default.join(process.cwd(), 'workspace', 'HEARTBEAT.md');
|
|
60
|
+
// ── Feature 8: HEARTBEAT.md config loader ─────────────────────
|
|
61
|
+
function loadHeartbeatConfig() {
|
|
62
|
+
const isDebug = (process.env.AIDEN_LOG_LEVEL || 'info') === 'debug';
|
|
63
|
+
try {
|
|
64
|
+
if (!fs_1.default.existsSync(HEARTBEAT_PATH))
|
|
65
|
+
return;
|
|
66
|
+
const content = fs_1.default.readFileSync(HEARTBEAT_PATH, 'utf-8');
|
|
67
|
+
const sections = content.split(/^## /m).slice(1);
|
|
68
|
+
let loaded = 0;
|
|
69
|
+
for (const section of sections) {
|
|
70
|
+
const title = section.split('\n')[0];
|
|
71
|
+
const scheduleMatch = title.match(/\((.+)\)/);
|
|
72
|
+
if (!scheduleMatch)
|
|
73
|
+
continue;
|
|
74
|
+
loaded++;
|
|
75
|
+
if (isDebug) {
|
|
76
|
+
console.log('[Heartbeat] Loaded: ' + title.split('(')[0].trim());
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!isDebug && loaded > 0) {
|
|
80
|
+
console.log('[Heartbeat] Loaded ' + loaded + ' schedule(s) from HEARTBEAT.md');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
console.warn('[Heartbeat] Could not load HEARTBEAT.md: ' + e.message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// ── Natural-language → cron converter ─────────────────────────
|
|
88
|
+
function naturalToCron(schedule) {
|
|
89
|
+
const s = schedule.toLowerCase().trim();
|
|
90
|
+
// ── Time extraction helper ────────────────────────────
|
|
91
|
+
const extractHour = (str) => {
|
|
92
|
+
const m = str.match(/(\d{1,2})(?::(\d{2}))?\s*(am|pm)?/);
|
|
93
|
+
if (!m)
|
|
94
|
+
return null;
|
|
95
|
+
let hour = parseInt(m[1], 10);
|
|
96
|
+
const ampm = m[3];
|
|
97
|
+
if (ampm === 'pm' && hour !== 12)
|
|
98
|
+
hour += 12;
|
|
99
|
+
if (ampm === 'am' && hour === 12)
|
|
100
|
+
hour = 0;
|
|
101
|
+
return hour;
|
|
102
|
+
};
|
|
103
|
+
const extractMinute = (str) => {
|
|
104
|
+
const m = str.match(/\d{1,2}:(\d{2})/);
|
|
105
|
+
return m ? parseInt(m[1], 10) : 0;
|
|
106
|
+
};
|
|
107
|
+
// ── Every N minutes ───────────────────────────────────
|
|
108
|
+
const everyMin = s.match(/every\s+(\d+)\s*min/);
|
|
109
|
+
if (everyMin)
|
|
110
|
+
return `*/${everyMin[1]} * * * *`;
|
|
111
|
+
// ── Every hour ────────────────────────────────────────
|
|
112
|
+
if (/every\s+hour/.test(s))
|
|
113
|
+
return '0 * * * *';
|
|
114
|
+
// ── Every 30 minutes ─────────────────────────────────
|
|
115
|
+
if (/every\s+30/.test(s))
|
|
116
|
+
return '*/30 * * * *';
|
|
117
|
+
// ── Daily / every day ────────────────────────────────
|
|
118
|
+
if (/every\s+day|daily/.test(s)) {
|
|
119
|
+
const h = extractHour(s) ?? 8;
|
|
120
|
+
const m = extractMinute(s);
|
|
121
|
+
return `${m} ${h} * * *`;
|
|
122
|
+
}
|
|
123
|
+
// ── Weekdays ─────────────────────────────────────────
|
|
124
|
+
const DAY_MAP = {
|
|
125
|
+
sunday: 0, monday: 1, tuesday: 2, wednesday: 3,
|
|
126
|
+
thursday: 4, friday: 5, saturday: 6,
|
|
127
|
+
};
|
|
128
|
+
for (const [dayName, dayNum] of Object.entries(DAY_MAP)) {
|
|
129
|
+
if (s.includes(dayName)) {
|
|
130
|
+
const h = extractHour(s) ?? 9;
|
|
131
|
+
const m = extractMinute(s);
|
|
132
|
+
return `${m} ${h} * * ${dayNum}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ── Weekdays (Mon–Fri) ────────────────────────────────
|
|
136
|
+
if (/weekday/.test(s)) {
|
|
137
|
+
const h = extractHour(s) ?? 9;
|
|
138
|
+
const m = extractMinute(s);
|
|
139
|
+
return `${m} ${h} * * 1-5`;
|
|
140
|
+
}
|
|
141
|
+
// ── Weekly ───────────────────────────────────────────
|
|
142
|
+
if (/weekly|every\s+week/.test(s)) {
|
|
143
|
+
const h = extractHour(s) ?? 9;
|
|
144
|
+
return `0 ${h} * * 1`; // Monday by default
|
|
145
|
+
}
|
|
146
|
+
// ── Monthly ──────────────────────────────────────────
|
|
147
|
+
if (/monthly|every\s+month/.test(s)) {
|
|
148
|
+
const h = extractHour(s) ?? 9;
|
|
149
|
+
return `0 ${h} 1 * *`; // 1st of month
|
|
150
|
+
}
|
|
151
|
+
// ── Fallback: 9am daily ───────────────────────────────
|
|
152
|
+
return '0 9 * * *';
|
|
153
|
+
}
|
|
154
|
+
// ── Cron match checker ─────────────────────────────────────────
|
|
155
|
+
// Parses a cron expression and tests it against the current time.
|
|
156
|
+
function cronMatchesNow(cronExpr) {
|
|
157
|
+
const parts = cronExpr.split(' ');
|
|
158
|
+
if (parts.length < 5)
|
|
159
|
+
return false;
|
|
160
|
+
const [minutePart, hourPart, , , dayOfWeekPart] = parts;
|
|
161
|
+
const now = new Date();
|
|
162
|
+
const matchField = (field, value) => {
|
|
163
|
+
if (field === '*')
|
|
164
|
+
return true;
|
|
165
|
+
if (field.startsWith('*/')) {
|
|
166
|
+
const step = parseInt(field.slice(2), 10);
|
|
167
|
+
return value % step === 0;
|
|
168
|
+
}
|
|
169
|
+
if (field.includes('-')) {
|
|
170
|
+
const [lo, hi] = field.split('-').map(Number);
|
|
171
|
+
return value >= lo && value <= hi;
|
|
172
|
+
}
|
|
173
|
+
return parseInt(field, 10) === value;
|
|
174
|
+
};
|
|
175
|
+
return (matchField(minutePart, now.getMinutes()) &&
|
|
176
|
+
matchField(hourPart, now.getHours()) &&
|
|
177
|
+
matchField(dayOfWeekPart, now.getDay()));
|
|
178
|
+
}
|
|
179
|
+
// ── Scheduler class ────────────────────────────────────────────
|
|
180
|
+
class Scheduler {
|
|
181
|
+
constructor() {
|
|
182
|
+
this.tasks = [];
|
|
183
|
+
this.intervals = new Map();
|
|
184
|
+
this.load();
|
|
185
|
+
this.registerDreamSchedule();
|
|
186
|
+
this.registerHeartbeatSchedule();
|
|
187
|
+
loadHeartbeatConfig();
|
|
188
|
+
}
|
|
189
|
+
// ── Public API ─────────────────────────────────────────
|
|
190
|
+
add(description, schedule, goal) {
|
|
191
|
+
const task = {
|
|
192
|
+
id: `task_${Date.now()}`,
|
|
193
|
+
description,
|
|
194
|
+
schedule,
|
|
195
|
+
cronExpression: naturalToCron(schedule),
|
|
196
|
+
goal,
|
|
197
|
+
enabled: true,
|
|
198
|
+
createdAt: Date.now(),
|
|
199
|
+
};
|
|
200
|
+
this.tasks.push(task);
|
|
201
|
+
this.save();
|
|
202
|
+
this.scheduleTask(task);
|
|
203
|
+
console.log(`[Scheduler] Added: "${description}" (${task.cronExpression})`);
|
|
204
|
+
return task;
|
|
205
|
+
}
|
|
206
|
+
remove(id) {
|
|
207
|
+
const interval = this.intervals.get(id);
|
|
208
|
+
if (interval) {
|
|
209
|
+
clearInterval(interval);
|
|
210
|
+
this.intervals.delete(id);
|
|
211
|
+
}
|
|
212
|
+
const before = this.tasks.length;
|
|
213
|
+
this.tasks = this.tasks.filter(t => t.id !== id);
|
|
214
|
+
this.save();
|
|
215
|
+
return this.tasks.length < before;
|
|
216
|
+
}
|
|
217
|
+
toggle(id, enabled) {
|
|
218
|
+
const task = this.tasks.find(t => t.id === id);
|
|
219
|
+
if (!task)
|
|
220
|
+
return false;
|
|
221
|
+
task.enabled = enabled;
|
|
222
|
+
this.save();
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
list() {
|
|
226
|
+
return this.tasks;
|
|
227
|
+
}
|
|
228
|
+
// ── Dream Engine: check every 6 hours ─────────────────
|
|
229
|
+
registerDreamSchedule() {
|
|
230
|
+
// Run once 30s after startup
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
(0, dreamEngine_1.checkAndRunDream)();
|
|
233
|
+
}, 30000);
|
|
234
|
+
// Then every 6 hours
|
|
235
|
+
setInterval(() => {
|
|
236
|
+
(0, dreamEngine_1.checkAndRunDream)();
|
|
237
|
+
}, 6 * 60 * 60 * 1000);
|
|
238
|
+
console.log('[Scheduler] Dream engine scheduled (every 6h, startup+30s)');
|
|
239
|
+
}
|
|
240
|
+
// ── Feature 16: HEARTBEAT_OK suppression pattern ──────────────
|
|
241
|
+
// Runs every 30 min during active hours (8 AM–11 PM).
|
|
242
|
+
// Uses local Ollama (zero API cost). Silent unless alert found.
|
|
243
|
+
registerHeartbeatSchedule() {
|
|
244
|
+
async function runHeartbeat() {
|
|
245
|
+
const hour = new Date().getHours();
|
|
246
|
+
const ACTIVE_START = 8;
|
|
247
|
+
const ACTIVE_END = 23;
|
|
248
|
+
if (hour < ACTIVE_START || hour >= ACTIVE_END)
|
|
249
|
+
return;
|
|
250
|
+
if (!fs_1.default.existsSync(HEARTBEAT_PATH))
|
|
251
|
+
return;
|
|
252
|
+
const checklist = fs_1.default.readFileSync(HEARTBEAT_PATH, 'utf-8').trim();
|
|
253
|
+
if (!checklist)
|
|
254
|
+
return;
|
|
255
|
+
// Build heartbeat prompt: checklist + active goals + patterns
|
|
256
|
+
let heartbeatPrompt = checklist;
|
|
257
|
+
const goalsSummary = (0, goalTracker_1.getActiveGoalsSummary)();
|
|
258
|
+
if (goalsSummary)
|
|
259
|
+
heartbeatPrompt += '\n\n' + goalsSummary;
|
|
260
|
+
try {
|
|
261
|
+
const patterns = await (0, patternDetector_1.detectPatterns)();
|
|
262
|
+
const patternSummary = (0, patternDetector_1.getPatternSummary)(patterns);
|
|
263
|
+
if (patternSummary)
|
|
264
|
+
heartbeatPrompt += '\n\n' + patternSummary;
|
|
265
|
+
}
|
|
266
|
+
catch { /* pattern detection is non-critical */ }
|
|
267
|
+
console.log('[Heartbeat] Running checks...');
|
|
268
|
+
try {
|
|
269
|
+
const resp = await fetch('http://localhost:11434/api/chat', {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
headers: { 'Content-Type': 'application/json' },
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
model: 'llama3.2:latest',
|
|
274
|
+
stream: false,
|
|
275
|
+
messages: [
|
|
276
|
+
{
|
|
277
|
+
role: 'system',
|
|
278
|
+
content: "You are Aiden running a background heartbeat. Check the items in the list. If NOTHING needs the user's attention, reply ONLY: HEARTBEAT_OK\nIf something IS urgent or interesting, describe it in 1-2 sentences. Do NOT include HEARTBEAT_OK if you have alerts.",
|
|
279
|
+
},
|
|
280
|
+
{ role: 'user', content: heartbeatPrompt },
|
|
281
|
+
],
|
|
282
|
+
}),
|
|
283
|
+
signal: AbortSignal.timeout(30000),
|
|
284
|
+
});
|
|
285
|
+
if (!resp.ok) {
|
|
286
|
+
console.log('[Heartbeat] Ollama unavailable — skipping');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const data = await resp.json();
|
|
290
|
+
const response = (data?.message?.content || '');
|
|
291
|
+
const cleaned = response.replace(/HEARTBEAT_OK/gi, '').trim();
|
|
292
|
+
if (!cleaned || cleaned.length < 10) {
|
|
293
|
+
console.log('[Heartbeat] All clear');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
console.log('[Heartbeat] Alert:', cleaned);
|
|
297
|
+
// Deliver alert via API server (non-blocking)
|
|
298
|
+
fetch('http://localhost:4200/api/chat', {
|
|
299
|
+
method: 'POST',
|
|
300
|
+
headers: { 'Content-Type': 'application/json' },
|
|
301
|
+
body: JSON.stringify({ message: `notify user with desktop alert: ${cleaned}` }),
|
|
302
|
+
signal: AbortSignal.timeout(10000),
|
|
303
|
+
}).catch(() => { });
|
|
304
|
+
}
|
|
305
|
+
catch (e) {
|
|
306
|
+
console.log('[Heartbeat] Check skipped:', e.message);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Run 60s after startup, then every 30 minutes
|
|
310
|
+
setTimeout(() => runHeartbeat(), 60000);
|
|
311
|
+
setInterval(() => runHeartbeat(), 30 * 60 * 1000);
|
|
312
|
+
console.log('[Heartbeat] Scheduled (every 30m, active hours 8 AM–11 PM)');
|
|
313
|
+
}
|
|
314
|
+
// ── Sprint 25: morning briefing registration ────────────
|
|
315
|
+
registerMorningBriefing() {
|
|
316
|
+
const config = (0, morningBriefing_1.loadBriefingConfig)();
|
|
317
|
+
// Always remove any existing briefing task first
|
|
318
|
+
const existing = this.tasks.find(t => t.id === 'morning_briefing');
|
|
319
|
+
if (existing)
|
|
320
|
+
this.remove('morning_briefing');
|
|
321
|
+
if (!config.enabled)
|
|
322
|
+
return;
|
|
323
|
+
const [hourStr, minuteStr] = config.time.split(':');
|
|
324
|
+
const hour = parseInt(hourStr ?? '8', 10);
|
|
325
|
+
const minute = parseInt(minuteStr ?? '0', 10);
|
|
326
|
+
const task = {
|
|
327
|
+
id: 'morning_briefing',
|
|
328
|
+
description: 'Morning briefing',
|
|
329
|
+
schedule: `every day at ${config.time}`,
|
|
330
|
+
cronExpression: `${minute} ${hour} * * *`,
|
|
331
|
+
goal: '__morning_briefing__',
|
|
332
|
+
enabled: true,
|
|
333
|
+
createdAt: Date.now(),
|
|
334
|
+
};
|
|
335
|
+
this.tasks.push(task);
|
|
336
|
+
this.save();
|
|
337
|
+
this.scheduleTask(task);
|
|
338
|
+
console.log(`[Scheduler] Morning briefing registered at ${config.time}`);
|
|
339
|
+
}
|
|
340
|
+
scheduleTask(task) {
|
|
341
|
+
// Poll every minute and fire when cron expression matches current time
|
|
342
|
+
const interval = setInterval(() => {
|
|
343
|
+
if (!task.enabled)
|
|
344
|
+
return;
|
|
345
|
+
if (this.shouldRun(task)) {
|
|
346
|
+
task.lastRun = Date.now();
|
|
347
|
+
this.save();
|
|
348
|
+
const taskWithTimeout = Promise.race([
|
|
349
|
+
this.runTask(task),
|
|
350
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Task timeout after 5 minutes: ${task.description}`)), Scheduler.TASK_TIMEOUT_MS)),
|
|
351
|
+
]);
|
|
352
|
+
taskWithTimeout.catch(e => console.log(`[Security] Task killed: "${task.description}": ${e.message}`));
|
|
353
|
+
}
|
|
354
|
+
}, 60 * 1000);
|
|
355
|
+
this.intervals.set(task.id, interval);
|
|
356
|
+
}
|
|
357
|
+
shouldRun(task) {
|
|
358
|
+
// Must not have run in the last 55 minutes (prevents double-fire within same minute tick)
|
|
359
|
+
const notRunRecently = !task.lastRun || (Date.now() - task.lastRun) > 55 * 60 * 1000;
|
|
360
|
+
return notRunRecently && cronMatchesNow(task.cronExpression);
|
|
361
|
+
}
|
|
362
|
+
async runTask(task) {
|
|
363
|
+
console.log(`[Scheduler] Running task: "${task.description}"`);
|
|
364
|
+
// ── Sprint 25: morning briefing special marker ────────
|
|
365
|
+
if (task.goal === '__morning_briefing__') {
|
|
366
|
+
try {
|
|
367
|
+
const config = (0, morningBriefing_1.loadBriefingConfig)();
|
|
368
|
+
await (0, morningBriefing_1.deliverBriefing)(config);
|
|
369
|
+
console.log(`[Scheduler] Morning briefing delivered`);
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
console.error(`[Scheduler] Morning briefing failed: ${e.message}`);
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
const res = await fetch('http://localhost:4200/api/chat', {
|
|
378
|
+
method: 'POST',
|
|
379
|
+
headers: { 'Content-Type': 'application/json' },
|
|
380
|
+
body: JSON.stringify({ message: task.goal, history: [] }),
|
|
381
|
+
signal: AbortSignal.timeout(120000), // 2-minute cap per scheduled task
|
|
382
|
+
});
|
|
383
|
+
if (res.ok) {
|
|
384
|
+
console.log(`[Scheduler] Task complete: "${task.description}"`);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.warn(`[Scheduler] Task HTTP ${res.status}: "${task.description}"`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (e) {
|
|
391
|
+
console.error(`[Scheduler] Task failed: "${task.description}" — ${e.message}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
load() {
|
|
395
|
+
try {
|
|
396
|
+
if (!fs_1.default.existsSync(TASKS_PATH))
|
|
397
|
+
return;
|
|
398
|
+
const raw = fs_1.default.readFileSync(TASKS_PATH, 'utf-8');
|
|
399
|
+
this.tasks = JSON.parse(raw);
|
|
400
|
+
const enabled = this.tasks.filter(t => t.enabled);
|
|
401
|
+
enabled.forEach(t => this.scheduleTask(t));
|
|
402
|
+
if (enabled.length > 0) {
|
|
403
|
+
console.log(`[Scheduler] Loaded ${this.tasks.length} task(s), ${enabled.length} active`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
catch (e) {
|
|
407
|
+
console.warn(`[Scheduler] Failed to load tasks: ${e.message}`);
|
|
408
|
+
this.tasks = [];
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
save() {
|
|
412
|
+
try {
|
|
413
|
+
fs_1.default.mkdirSync(path_1.default.dirname(TASKS_PATH), { recursive: true });
|
|
414
|
+
fs_1.default.writeFileSync(TASKS_PATH, JSON.stringify(this.tasks, null, 2));
|
|
415
|
+
}
|
|
416
|
+
catch (e) {
|
|
417
|
+
console.warn(`[Scheduler] Failed to save tasks: ${e.message}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
exports.Scheduler = Scheduler;
|
|
422
|
+
// ── Internal ───────────────────────────────────────────
|
|
423
|
+
Scheduler.TASK_TIMEOUT_MS = 5 * 60 * 1000; // 5-minute dead-man switch
|
|
424
|
+
// ── Singleton ──────────────────────────────────────────────────
|
|
425
|
+
exports.scheduler = new Scheduler();
|
|
426
|
+
// ══════════════════════════════════════════════════════════════════
|
|
427
|
+
// ── One-shot / recurring REMINDER scheduler ───────────────────────
|
|
428
|
+
//
|
|
429
|
+
// Separate from the cron-based Scheduler above. Uses setTimeout so
|
|
430
|
+
// reminders fire in seconds, not minutes. Persists to
|
|
431
|
+
// ~/.aiden/scheduled.json and restores on boot via initReminderScheduler().
|
|
432
|
+
// ══════════════════════════════════════════════════════════════════
|
|
433
|
+
const os = __importStar(require("os"));
|
|
434
|
+
const _reminders = new Map();
|
|
435
|
+
const _rtimers = new Map();
|
|
436
|
+
let _rseq = 1;
|
|
437
|
+
const _RDATA_DIR = path_1.default.join(os.homedir(), '.aiden');
|
|
438
|
+
const _RDATA_FILE = path_1.default.join(_RDATA_DIR, 'scheduled.json');
|
|
439
|
+
function _rsave() {
|
|
440
|
+
try {
|
|
441
|
+
if (!fs_1.default.existsSync(_RDATA_DIR))
|
|
442
|
+
fs_1.default.mkdirSync(_RDATA_DIR, { recursive: true });
|
|
443
|
+
fs_1.default.writeFileSync(_RDATA_FILE, JSON.stringify(Array.from(_reminders.values()), null, 2), 'utf8');
|
|
444
|
+
}
|
|
445
|
+
catch { /* silent */ }
|
|
446
|
+
}
|
|
447
|
+
async function _fireReminder(id) {
|
|
448
|
+
const r = _reminders.get(id);
|
|
449
|
+
if (!r)
|
|
450
|
+
return;
|
|
451
|
+
r.firedCount++;
|
|
452
|
+
console.log(`[Reminders] Firing ${id}: ${r.message}`);
|
|
453
|
+
try {
|
|
454
|
+
const { executeTool } = await Promise.resolve().then(() => __importStar(require('./toolRegistry')));
|
|
455
|
+
await executeTool('notify', { message: r.message, title: 'Aiden Reminder' });
|
|
456
|
+
}
|
|
457
|
+
catch (e) {
|
|
458
|
+
console.error(`[Reminders] notify failed for ${id}:`, e.message);
|
|
459
|
+
}
|
|
460
|
+
if (r.recurring && r.intervalMs) {
|
|
461
|
+
r.fireAt = new Date(Date.now() + r.intervalMs).toISOString();
|
|
462
|
+
_rsave();
|
|
463
|
+
_rtimers.set(id, setTimeout(() => _fireReminder(id), r.intervalMs));
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
_reminders.delete(id);
|
|
467
|
+
_rtimers.delete(id);
|
|
468
|
+
_rsave();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Schedule a desktop notification reminder.
|
|
473
|
+
* @param message Text shown in the notification.
|
|
474
|
+
* @param delayMs Milliseconds from now until first fire.
|
|
475
|
+
* @param recurring Optional: 'hourly' | 'daily' | 'weekly'
|
|
476
|
+
*/
|
|
477
|
+
function scheduleReminder(message, delayMs, recurring) {
|
|
478
|
+
const id = `r${_rseq++}`;
|
|
479
|
+
const now = Date.now();
|
|
480
|
+
const intervalMs = recurring === 'hourly' ? 3600000
|
|
481
|
+
: recurring === 'daily' ? 86400000
|
|
482
|
+
: recurring === 'weekly' ? 604800000
|
|
483
|
+
: undefined;
|
|
484
|
+
const reminder = {
|
|
485
|
+
id,
|
|
486
|
+
message,
|
|
487
|
+
fireAt: new Date(now + delayMs).toISOString(),
|
|
488
|
+
recurring,
|
|
489
|
+
intervalMs,
|
|
490
|
+
createdAt: new Date(now).toISOString(),
|
|
491
|
+
firedCount: 0,
|
|
492
|
+
};
|
|
493
|
+
_reminders.set(id, reminder);
|
|
494
|
+
_rsave();
|
|
495
|
+
_rtimers.set(id, setTimeout(() => _fireReminder(id), delayMs));
|
|
496
|
+
const secs = Math.round(delayMs / 1000);
|
|
497
|
+
console.log(`[Reminders] Scheduled ${id} in ${secs}s${recurring ? ` (${recurring})` : ''}`);
|
|
498
|
+
return reminder;
|
|
499
|
+
}
|
|
500
|
+
function listReminders() {
|
|
501
|
+
return Array.from(_reminders.values());
|
|
502
|
+
}
|
|
503
|
+
function cancelReminder(id) {
|
|
504
|
+
const t = _rtimers.get(id);
|
|
505
|
+
if (t !== undefined)
|
|
506
|
+
clearTimeout(t);
|
|
507
|
+
_rtimers.delete(id);
|
|
508
|
+
const existed = _reminders.delete(id);
|
|
509
|
+
if (existed)
|
|
510
|
+
_rsave();
|
|
511
|
+
return existed;
|
|
512
|
+
}
|
|
513
|
+
/** Call once at server boot to restore any persisted reminders. */
|
|
514
|
+
function initReminderScheduler() {
|
|
515
|
+
try {
|
|
516
|
+
if (!fs_1.default.existsSync(_RDATA_FILE)) {
|
|
517
|
+
console.log('[Reminders] No saved reminders');
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const stored = JSON.parse(fs_1.default.readFileSync(_RDATA_FILE, 'utf8'));
|
|
521
|
+
const now = Date.now();
|
|
522
|
+
let loaded = 0;
|
|
523
|
+
for (const r of stored) {
|
|
524
|
+
const num = parseInt(r.id.replace(/^r/, ''), 10);
|
|
525
|
+
if (!isNaN(num) && num >= _rseq)
|
|
526
|
+
_rseq = num + 1;
|
|
527
|
+
// One-shot already fired: skip
|
|
528
|
+
if (!r.recurring && r.firedCount > 0)
|
|
529
|
+
continue;
|
|
530
|
+
const fireAt = new Date(r.fireAt).getTime();
|
|
531
|
+
const delay = Math.max(0, fireAt - now);
|
|
532
|
+
_reminders.set(r.id, r);
|
|
533
|
+
_rtimers.set(r.id, setTimeout(() => _fireReminder(r.id), delay));
|
|
534
|
+
console.log(`[Reminders] Restored ${r.id} — fires in ${Math.round(delay / 1000)}s`);
|
|
535
|
+
loaded++;
|
|
536
|
+
}
|
|
537
|
+
_rsave(); // purge stale one-shots
|
|
538
|
+
console.log(`[Reminders] ${loaded} reminder(s) restored`);
|
|
539
|
+
}
|
|
540
|
+
catch (e) {
|
|
541
|
+
console.error('[Reminders] Init error:', e.message);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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.scanAndRedact = scanAndRedact;
|
|
8
|
+
exports.containsSecret = containsSecret;
|
|
9
|
+
// core/secretScanner.ts — Redact API keys and secrets before persist
|
|
10
|
+
//
|
|
11
|
+
// Scans text for common secret patterns (OpenAI, Groq, Gemini, GitHub,
|
|
12
|
+
// Cerebras, license keys, Bearer tokens, generic key= patterns) and
|
|
13
|
+
// replaces them with [REDACTED] before any data is written to SQLite
|
|
14
|
+
// or the conversation JSON store.
|
|
15
|
+
// ── Patterns ──────────────────────────────────────────────────
|
|
16
|
+
const SECRET_PATTERNS = [
|
|
17
|
+
/sk-[a-zA-Z0-9]{20,}/g, // OpenAI
|
|
18
|
+
/gsk_[a-zA-Z0-9]{20,}/g, // Groq
|
|
19
|
+
/AIza[a-zA-Z0-9_-]{35}/g, // Google/Gemini
|
|
20
|
+
/ghp_[a-zA-Z0-9]{36}/g, // GitHub PAT
|
|
21
|
+
/csk-[a-zA-Z0-9]{20,}/g, // Cerebras
|
|
22
|
+
/[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}/g, // License keys
|
|
23
|
+
/Bearer\s+[a-zA-Z0-9_\-\.]{20,}/g, // Bearer tokens
|
|
24
|
+
/(?:api[_-]?key|apikey|api[_-]?secret|access[_-]?token)["\s:=]+["']?([a-zA-Z0-9_\-]{20,})["']?/gi,
|
|
25
|
+
];
|
|
26
|
+
// ── Public API ─────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Scan text for secrets and replace all matches with [REDACTED].
|
|
29
|
+
* Safe to call on any string before persisting to disk or DB.
|
|
30
|
+
*/
|
|
31
|
+
function scanAndRedact(text) {
|
|
32
|
+
let result = text;
|
|
33
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
34
|
+
// Reset lastIndex for stateful regexes (those with /g)
|
|
35
|
+
pattern.lastIndex = 0;
|
|
36
|
+
result = result.replace(pattern, '[REDACTED]');
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns true if the text contains anything matching a known secret pattern.
|
|
42
|
+
* Use for early-warning logging before calling scanAndRedact().
|
|
43
|
+
*/
|
|
44
|
+
function containsSecret(text) {
|
|
45
|
+
return SECRET_PATTERNS.some(p => {
|
|
46
|
+
p.lastIndex = 0;
|
|
47
|
+
return p.test(text);
|
|
48
|
+
});
|
|
49
|
+
}
|