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,164 @@
|
|
|
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.IMessageAdapter = void 0;
|
|
11
|
+
// core/channels/imessage.ts — iMessage channel adapter via BlueBubbles.
|
|
12
|
+
//
|
|
13
|
+
// BlueBubbles is a Mac app that exposes iMessage via REST + WebSocket.
|
|
14
|
+
// A Mac running the BlueBubbles server is REQUIRED — iMessage is an
|
|
15
|
+
// Apple-exclusive service.
|
|
16
|
+
//
|
|
17
|
+
// Setup (one-time, on a Mac):
|
|
18
|
+
// 1. Install BlueBubbles from https://bluebubbles.app
|
|
19
|
+
// 2. Open BlueBubbles, set a server password, note the URL/port
|
|
20
|
+
// 3. Set BLUEBUBBLES_URL and BLUEBUBBLES_PASSWORD in Aiden's .env
|
|
21
|
+
//
|
|
22
|
+
// Config (env vars):
|
|
23
|
+
// BLUEBUBBLES_URL — e.g. http://192.168.1.5:1234
|
|
24
|
+
// BLUEBUBBLES_PASSWORD — set in BlueBubbles server settings
|
|
25
|
+
// BLUEBUBBLES_ALLOWED_NUMBERS — optional comma-separated allowlist
|
|
26
|
+
const axios_1 = __importDefault(require("axios"));
|
|
27
|
+
const ws_1 = require("ws");
|
|
28
|
+
const gateway_1 = require("../gateway");
|
|
29
|
+
class IMessageAdapter {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.name = 'imessage';
|
|
32
|
+
this.healthy = false;
|
|
33
|
+
this.ws = null;
|
|
34
|
+
this.reconnectTimer = null;
|
|
35
|
+
this.baseUrl = (process.env.BLUEBUBBLES_URL ?? '').replace(/\/$/, '');
|
|
36
|
+
this.password = process.env.BLUEBUBBLES_PASSWORD ?? '';
|
|
37
|
+
const raw = process.env.BLUEBUBBLES_ALLOWED_NUMBERS ?? '';
|
|
38
|
+
this.allowedNumbers = raw ? new Set(raw.split(',').map(s => s.trim()).filter(Boolean)) : new Set();
|
|
39
|
+
}
|
|
40
|
+
// ── Lifecycle ──────────────────────────────────────────────
|
|
41
|
+
async start() {
|
|
42
|
+
if (!this.baseUrl || !this.password) {
|
|
43
|
+
console.log('[iMessage] Disabled — set BLUEBUBBLES_URL and BLUEBUBBLES_PASSWORD to enable');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Verify BlueBubbles is reachable
|
|
47
|
+
const reachable = await this.checkHealth();
|
|
48
|
+
if (!reachable) {
|
|
49
|
+
console.log(`[iMessage] Disabled — BlueBubbles server not reachable at ${this.baseUrl}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.healthy = true;
|
|
53
|
+
console.log(`[iMessage] Connected to BlueBubbles at ${this.baseUrl}`);
|
|
54
|
+
// Register outbound delivery
|
|
55
|
+
gateway_1.gateway.registerChannel('imessage', async (msg) => {
|
|
56
|
+
await this.send(msg.channelId, msg.text);
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
// Connect WebSocket for real-time inbound messages
|
|
60
|
+
this.connectWebSocket();
|
|
61
|
+
}
|
|
62
|
+
async stop() {
|
|
63
|
+
this.healthy = false;
|
|
64
|
+
if (this.reconnectTimer) {
|
|
65
|
+
clearTimeout(this.reconnectTimer);
|
|
66
|
+
this.reconnectTimer = null;
|
|
67
|
+
}
|
|
68
|
+
if (this.ws) {
|
|
69
|
+
this.ws.close();
|
|
70
|
+
this.ws = null;
|
|
71
|
+
}
|
|
72
|
+
gateway_1.gateway.unregisterChannel('imessage');
|
|
73
|
+
console.log('[iMessage] Disconnected');
|
|
74
|
+
}
|
|
75
|
+
async send(target, message) {
|
|
76
|
+
if (!this.healthy)
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
await axios_1.default.post(`${this.baseUrl}/api/v1/message/text`, { chatGuid: target, message, tempGuid: `aiden-${Date.now()}` }, {
|
|
80
|
+
params: { password: this.password },
|
|
81
|
+
timeout: 10000,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
console.error('[iMessage] send error:', e.message);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
isHealthy() { return this.healthy; }
|
|
89
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
90
|
+
async checkHealth() {
|
|
91
|
+
try {
|
|
92
|
+
await axios_1.default.get(`${this.baseUrl}/api/v1/ping`, {
|
|
93
|
+
params: { password: this.password },
|
|
94
|
+
timeout: 3000,
|
|
95
|
+
});
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
connectWebSocket() {
|
|
103
|
+
if (!this.healthy)
|
|
104
|
+
return;
|
|
105
|
+
const wsUrl = this.baseUrl.replace(/^http/, 'ws');
|
|
106
|
+
this.ws = new ws_1.WebSocket(`${wsUrl}?password=${encodeURIComponent(this.password)}`);
|
|
107
|
+
this.ws.on('open', () => {
|
|
108
|
+
console.log('[iMessage] WebSocket connected');
|
|
109
|
+
});
|
|
110
|
+
this.ws.on('message', async (raw) => {
|
|
111
|
+
try {
|
|
112
|
+
const event = JSON.parse(raw.toString());
|
|
113
|
+
if (event.type !== 'new-message')
|
|
114
|
+
return;
|
|
115
|
+
const msg = event.data;
|
|
116
|
+
// Only handle inbound (not self-sent) chat messages
|
|
117
|
+
if (!msg || msg.isFromMe)
|
|
118
|
+
return;
|
|
119
|
+
if (msg.attributedBody === null && !msg.text)
|
|
120
|
+
return;
|
|
121
|
+
const text = msg.text ?? '';
|
|
122
|
+
const chatId = msg.chats?.[0]?.guid ?? '';
|
|
123
|
+
const sender = msg.handle?.address ?? '';
|
|
124
|
+
if (!this.isAllowed(sender))
|
|
125
|
+
return;
|
|
126
|
+
const response = await this.processMessage(chatId || sender, sender, text);
|
|
127
|
+
await this.send(chatId || sender, response);
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
console.error('[iMessage] message parse error:', e.message);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
this.ws.on('error', (e) => {
|
|
134
|
+
console.error('[iMessage] WebSocket error:', e.message);
|
|
135
|
+
});
|
|
136
|
+
this.ws.on('close', () => {
|
|
137
|
+
if (this.healthy) {
|
|
138
|
+
// Reconnect after 5 seconds
|
|
139
|
+
this.reconnectTimer = setTimeout(() => this.connectWebSocket(), 5000);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
isAllowed(number) {
|
|
144
|
+
if (this.allowedNumbers.size === 0)
|
|
145
|
+
return true;
|
|
146
|
+
return this.allowedNumbers.has(number);
|
|
147
|
+
}
|
|
148
|
+
async processMessage(channelId, userId, text) {
|
|
149
|
+
try {
|
|
150
|
+
return await gateway_1.gateway.routeMessage({
|
|
151
|
+
channel: 'imessage',
|
|
152
|
+
channelId,
|
|
153
|
+
userId,
|
|
154
|
+
text,
|
|
155
|
+
timestamp: Date.now(),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
console.error('[iMessage] routeMessage error:', e.message);
|
|
160
|
+
return '❌ Something went wrong. Try again.';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.IMessageAdapter = IMessageAdapter;
|
|
@@ -0,0 +1,96 @@
|
|
|
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.channelManager = exports.ChannelManager = void 0;
|
|
8
|
+
// ── ChannelManager ─────────────────────────────────────────
|
|
9
|
+
class ChannelManager {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.adapters = new Map();
|
|
12
|
+
this.lastActivity = new Map();
|
|
13
|
+
}
|
|
14
|
+
/** Register an adapter — must be called before startAll() */
|
|
15
|
+
register(adapter) {
|
|
16
|
+
this.adapters.set(adapter.name, adapter);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Start all registered adapters.
|
|
20
|
+
* Each adapter self-checks its credentials and reports 'started' or 'disabled'.
|
|
21
|
+
* Adapters that throw are marked 'failed' — startup continues for others.
|
|
22
|
+
*/
|
|
23
|
+
async startAll() {
|
|
24
|
+
const results = [];
|
|
25
|
+
for (const [name, adapter] of this.adapters) {
|
|
26
|
+
try {
|
|
27
|
+
await adapter.start();
|
|
28
|
+
const status = adapter.isHealthy() ? 'started' : 'disabled';
|
|
29
|
+
results.push({ name, status });
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(`[ChannelManager] ${name} failed to start:`, error.message);
|
|
33
|
+
results.push({ name, status: 'failed', error: String(error.message) });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Summary line
|
|
37
|
+
const summary = results
|
|
38
|
+
.map(r => {
|
|
39
|
+
if (r.status === 'started')
|
|
40
|
+
return `${r.name} ✓`;
|
|
41
|
+
if (r.status === 'disabled')
|
|
42
|
+
return `${r.name} (disabled)`;
|
|
43
|
+
return `${r.name} ✗ ${r.error ?? ''}`;
|
|
44
|
+
})
|
|
45
|
+
.join(' | ');
|
|
46
|
+
if (results.length > 0)
|
|
47
|
+
console.log(`[Channels] ${summary}`);
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
/** Gracefully stop all adapters — called on SIGTERM / shutdown */
|
|
51
|
+
async stopAll() {
|
|
52
|
+
for (const [, adapter] of this.adapters) {
|
|
53
|
+
try {
|
|
54
|
+
await adapter.stop();
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.error(`[ChannelManager] Error stopping ${adapter.name}:`, e.message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Current health status for all registered adapters */
|
|
62
|
+
getStatus() {
|
|
63
|
+
return Array.from(this.adapters.values()).map(adapter => ({
|
|
64
|
+
name: adapter.name,
|
|
65
|
+
healthy: adapter.isHealthy(),
|
|
66
|
+
lastActivity: this.lastActivity.get(adapter.name),
|
|
67
|
+
lastMessageTimestamp: this.lastActivity.get(adapter.name),
|
|
68
|
+
configValid: adapter.isHealthy(),
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
/** Record an activity timestamp for a channel (called by gateway hooks, etc.) */
|
|
72
|
+
recordActivity(name) {
|
|
73
|
+
this.lastActivity.set(name, Date.now());
|
|
74
|
+
}
|
|
75
|
+
/** Restart a specific adapter by name */
|
|
76
|
+
async restart(name) {
|
|
77
|
+
const adapter = this.adapters.get(name);
|
|
78
|
+
if (!adapter)
|
|
79
|
+
return { name, status: 'failed', error: `Unknown channel: ${name}` };
|
|
80
|
+
try {
|
|
81
|
+
await adapter.stop();
|
|
82
|
+
await adapter.start();
|
|
83
|
+
return { name, status: adapter.isHealthy() ? 'started' : 'disabled' };
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return { name, status: 'failed', error: String(error.message) };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Get a single adapter by name */
|
|
90
|
+
get(name) {
|
|
91
|
+
return this.adapters.get(name);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.ChannelManager = ChannelManager;
|
|
95
|
+
/** Singleton instance — import this in server.ts and cli handlers */
|
|
96
|
+
exports.channelManager = new ChannelManager();
|
|
@@ -0,0 +1,140 @@
|
|
|
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.SignalAdapter = void 0;
|
|
11
|
+
// core/channels/signal.ts — Signal channel adapter.
|
|
12
|
+
//
|
|
13
|
+
// Uses signal-cli-rest-api — a standalone REST wrapper around the
|
|
14
|
+
// official signal-cli Java tool. Users run it separately:
|
|
15
|
+
// https://github.com/bbernhard/signal-cli-rest-api
|
|
16
|
+
//
|
|
17
|
+
// Setup (one-time, outside Aiden):
|
|
18
|
+
// docker run -p 8080:8080 -v ~/.local/share/signal-cli:/home/.local/share/signal-cli \
|
|
19
|
+
// bbernhard/signal-cli-rest-api
|
|
20
|
+
// # then register your number at http://localhost:8080/v1/register/<number>
|
|
21
|
+
//
|
|
22
|
+
// Config (env vars):
|
|
23
|
+
// SIGNAL_CLI_URL — REST API base URL (default: http://localhost:8080)
|
|
24
|
+
// SIGNAL_PHONE_NUMBER — your registered Signal number (+15551234567)
|
|
25
|
+
// SIGNAL_ALLOWED_NUMBERS — optional comma-separated allowlist
|
|
26
|
+
const axios_1 = __importDefault(require("axios"));
|
|
27
|
+
const gateway_1 = require("../gateway");
|
|
28
|
+
class SignalAdapter {
|
|
29
|
+
constructor() {
|
|
30
|
+
this.name = 'signal';
|
|
31
|
+
this.healthy = false;
|
|
32
|
+
this.pollTimer = null;
|
|
33
|
+
this.lastReceived = 0;
|
|
34
|
+
this.baseUrl = (process.env.SIGNAL_CLI_URL ?? 'http://localhost:8080').replace(/\/$/, '');
|
|
35
|
+
this.myNumber = process.env.SIGNAL_PHONE_NUMBER ?? '';
|
|
36
|
+
const raw = process.env.SIGNAL_ALLOWED_NUMBERS ?? '';
|
|
37
|
+
this.allowedNumbers = raw ? new Set(raw.split(',').map(s => s.trim()).filter(Boolean)) : new Set();
|
|
38
|
+
}
|
|
39
|
+
// ── Lifecycle ──────────────────────────────────────────────
|
|
40
|
+
async start() {
|
|
41
|
+
if (!this.myNumber) {
|
|
42
|
+
console.log('[Signal] Disabled — set SIGNAL_PHONE_NUMBER to enable');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Verify signal-cli is reachable
|
|
46
|
+
const reachable = await this.checkHealth();
|
|
47
|
+
if (!reachable) {
|
|
48
|
+
console.log(`[Signal] Disabled — signal-cli-rest-api not reachable at ${this.baseUrl}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.healthy = true;
|
|
52
|
+
this.lastReceived = Date.now();
|
|
53
|
+
console.log(`[Signal] Connected — polling ${this.baseUrl}`);
|
|
54
|
+
// Register outbound delivery
|
|
55
|
+
gateway_1.gateway.registerChannel('signal', async (msg) => {
|
|
56
|
+
await this.send(msg.channelId, msg.text);
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
// Poll for new messages every 2 seconds
|
|
60
|
+
this.pollTimer = setInterval(() => this.poll(), 2000);
|
|
61
|
+
}
|
|
62
|
+
async stop() {
|
|
63
|
+
this.healthy = false;
|
|
64
|
+
if (this.pollTimer) {
|
|
65
|
+
clearInterval(this.pollTimer);
|
|
66
|
+
this.pollTimer = null;
|
|
67
|
+
}
|
|
68
|
+
gateway_1.gateway.unregisterChannel('signal');
|
|
69
|
+
console.log('[Signal] Disconnected');
|
|
70
|
+
}
|
|
71
|
+
async send(target, message) {
|
|
72
|
+
if (!this.healthy)
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
await axios_1.default.post(`${this.baseUrl}/v2/send`, { message, number: this.myNumber, recipients: [target] }, { timeout: 10000 });
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error('[Signal] send error:', e.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
isHealthy() { return this.healthy; }
|
|
82
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
83
|
+
async checkHealth() {
|
|
84
|
+
try {
|
|
85
|
+
await axios_1.default.get(`${this.baseUrl}/v1/health`, { timeout: 3000 });
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async poll() {
|
|
93
|
+
if (!this.healthy)
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
const res = await axios_1.default.get(`${this.baseUrl}/v1/receive/${encodeURIComponent(this.myNumber)}`, { timeout: 5000 });
|
|
97
|
+
const messages = Array.isArray(res.data) ? res.data : [];
|
|
98
|
+
for (const item of messages) {
|
|
99
|
+
const envelope = item.envelope;
|
|
100
|
+
if (!envelope)
|
|
101
|
+
continue;
|
|
102
|
+
const dm = envelope.dataMessage;
|
|
103
|
+
if (!dm?.message)
|
|
104
|
+
continue;
|
|
105
|
+
const sender = envelope.source ?? envelope.sourceNumber ?? '';
|
|
106
|
+
if (!this.isAllowed(sender))
|
|
107
|
+
continue;
|
|
108
|
+
const response = await this.processMessage(sender, sender, dm.message);
|
|
109
|
+
await this.send(sender, response);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
// Don't spam logs on transient poll errors
|
|
114
|
+
if (this.healthy) {
|
|
115
|
+
console.error('[Signal] poll error:', e.message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
isAllowed(number) {
|
|
120
|
+
if (this.allowedNumbers.size === 0)
|
|
121
|
+
return true;
|
|
122
|
+
return this.allowedNumbers.has(number);
|
|
123
|
+
}
|
|
124
|
+
async processMessage(channelId, userId, text) {
|
|
125
|
+
try {
|
|
126
|
+
return await gateway_1.gateway.routeMessage({
|
|
127
|
+
channel: 'signal',
|
|
128
|
+
channelId,
|
|
129
|
+
userId,
|
|
130
|
+
text,
|
|
131
|
+
timestamp: Date.now(),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
console.error('[Signal] routeMessage error:', e.message);
|
|
136
|
+
return '❌ Something went wrong. Try again.';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.SignalAdapter = SignalAdapter;
|
|
@@ -0,0 +1,139 @@
|
|
|
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.SlackAdapter = void 0;
|
|
8
|
+
// core/channels/slack.ts — Slack channel adapter.
|
|
9
|
+
//
|
|
10
|
+
// Config (env vars):
|
|
11
|
+
// SLACK_BOT_TOKEN — required (xoxb-…); adapter stays disabled if absent
|
|
12
|
+
// SLACK_SIGNING_SECRET — required; used for request signature verification
|
|
13
|
+
// SLACK_APP_TOKEN — optional (xapp-…); enables Socket Mode (preferred for local dev)
|
|
14
|
+
// SLACK_ALLOWED_CHANNELS — optional comma-separated channel IDs
|
|
15
|
+
//
|
|
16
|
+
// Modes:
|
|
17
|
+
// Socket mode — if SLACK_APP_TOKEN set; no public URL required (ideal for local dev)
|
|
18
|
+
// HTTP mode — if no SLACK_APP_TOKEN; listens on port 3001
|
|
19
|
+
//
|
|
20
|
+
// Features:
|
|
21
|
+
// - Responds to direct messages and app_mention events
|
|
22
|
+
// - /aiden slash command
|
|
23
|
+
// - Thread replies (replies in same thread as trigger)
|
|
24
|
+
// - Allowlist enforcement
|
|
25
|
+
// - Ignores bot messages
|
|
26
|
+
// - Signature verification via SLACK_SIGNING_SECRET
|
|
27
|
+
// - Graceful degradation: missing creds → disabled, no crash
|
|
28
|
+
const bolt_1 = require("@slack/bolt");
|
|
29
|
+
const gateway_1 = require("../gateway");
|
|
30
|
+
class SlackAdapter {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.name = 'slack';
|
|
33
|
+
this.app = null;
|
|
34
|
+
this.healthy = false;
|
|
35
|
+
this.botToken = process.env.SLACK_BOT_TOKEN ?? '';
|
|
36
|
+
this.signingSecret = process.env.SLACK_SIGNING_SECRET ?? '';
|
|
37
|
+
this.appToken = process.env.SLACK_APP_TOKEN ?? '';
|
|
38
|
+
const rawChannels = process.env.SLACK_ALLOWED_CHANNELS ?? '';
|
|
39
|
+
this.allowedChannels = rawChannels
|
|
40
|
+
? new Set(rawChannels.split(',').map(s => s.trim()).filter(Boolean))
|
|
41
|
+
: new Set();
|
|
42
|
+
}
|
|
43
|
+
// ── Lifecycle ──────────────────────────────────────────────
|
|
44
|
+
async start() {
|
|
45
|
+
if (!this.botToken || !this.signingSecret) {
|
|
46
|
+
console.log('[Slack] Disabled — set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET to enable');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const useSocketMode = !!this.appToken;
|
|
50
|
+
this.app = new bolt_1.App({
|
|
51
|
+
token: this.botToken,
|
|
52
|
+
signingSecret: this.signingSecret,
|
|
53
|
+
...(useSocketMode
|
|
54
|
+
? { socketMode: true, appToken: this.appToken }
|
|
55
|
+
: {}),
|
|
56
|
+
logLevel: bolt_1.LogLevel.WARN,
|
|
57
|
+
});
|
|
58
|
+
// ── Direct messages ─────────────────────────────────────
|
|
59
|
+
this.app.message(async ({ message, say }) => {
|
|
60
|
+
const msg = message;
|
|
61
|
+
if (msg.bot_id || msg.subtype)
|
|
62
|
+
return; // ignore bots & system messages
|
|
63
|
+
if (this.allowedChannels.size > 0 && !this.allowedChannels.has(msg.channel))
|
|
64
|
+
return;
|
|
65
|
+
const response = await this.processMessage(msg.channel, msg.user ?? 'unknown', msg.text ?? '');
|
|
66
|
+
await say({ text: response, thread_ts: msg.ts }).catch((e) => console.error('[Slack] say error:', e.message));
|
|
67
|
+
});
|
|
68
|
+
// ── App mentions (@Aiden) ────────────────────────────────
|
|
69
|
+
this.app.event('app_mention', async ({ event, say }) => {
|
|
70
|
+
if (this.allowedChannels.size > 0 && !this.allowedChannels.has(event.channel))
|
|
71
|
+
return;
|
|
72
|
+
// Strip the @mention prefix from the message
|
|
73
|
+
const text = (event.text ?? '').replace(/<@[^>]+>/g, '').trim();
|
|
74
|
+
const response = await this.processMessage(event.channel, event.user, text);
|
|
75
|
+
await say({ text: response, thread_ts: event.ts }).catch((e) => console.error('[Slack] mention reply error:', e.message));
|
|
76
|
+
});
|
|
77
|
+
// ── Slash command /aiden ─────────────────────────────────
|
|
78
|
+
this.app.command('/aiden', async ({ command, ack, say }) => {
|
|
79
|
+
await ack();
|
|
80
|
+
if (this.allowedChannels.size > 0 && !this.allowedChannels.has(command.channel_id)) {
|
|
81
|
+
await say('⚠️ This channel is not authorized for Aiden.');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const response = await this.processMessage(command.channel_id, command.user_id, command.text);
|
|
85
|
+
await say(response).catch((e) => console.error('[Slack] slash reply error:', e.message));
|
|
86
|
+
});
|
|
87
|
+
// Register outbound delivery so gateway.deliver() and broadcast() work
|
|
88
|
+
gateway_1.gateway.registerChannel('slack', async (msg) => {
|
|
89
|
+
try {
|
|
90
|
+
await this.app.client.chat.postMessage({ channel: msg.channelId, text: msg.text });
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
console.error('[Slack] Delivery error:', e.message);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const port = useSocketMode ? undefined : 3001;
|
|
99
|
+
try {
|
|
100
|
+
await this.app.start(port);
|
|
101
|
+
this.healthy = true;
|
|
102
|
+
console.log(`[Slack] Connected (${useSocketMode ? 'socket mode' : `HTTP mode port ${port}`})`);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
console.error('[Slack] Start failed:', e.message);
|
|
106
|
+
this.healthy = false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async stop() {
|
|
110
|
+
this.healthy = false;
|
|
111
|
+
if (this.app) {
|
|
112
|
+
gateway_1.gateway.unregisterChannel('slack');
|
|
113
|
+
await this.app.stop().catch(() => { });
|
|
114
|
+
this.app = null;
|
|
115
|
+
}
|
|
116
|
+
console.log('[Slack] Disconnected');
|
|
117
|
+
}
|
|
118
|
+
async send(channelId, message) {
|
|
119
|
+
await this.app?.client.chat.postMessage({ channel: channelId, text: message }).catch((e) => console.error('[Slack] send error:', e.message));
|
|
120
|
+
}
|
|
121
|
+
isHealthy() { return this.healthy; }
|
|
122
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
123
|
+
async processMessage(channelId, userId, text) {
|
|
124
|
+
try {
|
|
125
|
+
return await gateway_1.gateway.routeMessage({
|
|
126
|
+
channel: 'slack',
|
|
127
|
+
channelId,
|
|
128
|
+
userId,
|
|
129
|
+
text,
|
|
130
|
+
timestamp: Date.now(),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
console.error('[Slack] routeMessage error:', e.message);
|
|
135
|
+
return '❌ Something went wrong. Try again.';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.SlackAdapter = SlackAdapter;
|
|
@@ -0,0 +1,144 @@
|
|
|
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.TwilioAdapter = void 0;
|
|
8
|
+
// core/channels/twilio.ts — SMS channel adapter via Twilio.
|
|
9
|
+
//
|
|
10
|
+
// Inbound SMS requires a publicly reachable webhook URL pointing to
|
|
11
|
+
// POST /api/channels/sms/inbound
|
|
12
|
+
// Use ngrok or similar for local dev: ngrok http 4200
|
|
13
|
+
// Then set WEBHOOK_URL=https://<your-ngrok-id>.ngrok.io
|
|
14
|
+
//
|
|
15
|
+
// Config (env vars):
|
|
16
|
+
// TWILIO_ACCOUNT_SID — required
|
|
17
|
+
// TWILIO_AUTH_TOKEN — required
|
|
18
|
+
// TWILIO_PHONE_NUMBER — your Twilio-owned number (+15551234567)
|
|
19
|
+
// TWILIO_ALLOWED_NUMBERS — optional comma-separated inbound allowlist
|
|
20
|
+
// WEBHOOK_URL — base URL for inbound webhook registration
|
|
21
|
+
const gateway_1 = require("../gateway");
|
|
22
|
+
// SMS max segment length per GSM spec
|
|
23
|
+
const SMS_CHUNK_SIZE = 160;
|
|
24
|
+
/** Split a message into ≤160-character segments */
|
|
25
|
+
function chunkSms(text) {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
let remaining = text;
|
|
28
|
+
while (remaining.length > 0) {
|
|
29
|
+
chunks.push(remaining.substring(0, SMS_CHUNK_SIZE));
|
|
30
|
+
remaining = remaining.substring(SMS_CHUNK_SIZE);
|
|
31
|
+
}
|
|
32
|
+
return chunks;
|
|
33
|
+
}
|
|
34
|
+
class TwilioAdapter {
|
|
35
|
+
constructor(app) {
|
|
36
|
+
this.name = 'sms';
|
|
37
|
+
this.twilioClient = null;
|
|
38
|
+
this.healthy = false;
|
|
39
|
+
this.app = null;
|
|
40
|
+
this.accountSid = process.env.TWILIO_ACCOUNT_SID ?? '';
|
|
41
|
+
this.authToken = process.env.TWILIO_AUTH_TOKEN ?? '';
|
|
42
|
+
this.fromNumber = process.env.TWILIO_PHONE_NUMBER ?? '';
|
|
43
|
+
const raw = process.env.TWILIO_ALLOWED_NUMBERS ?? '';
|
|
44
|
+
this.allowedNumbers = raw ? new Set(raw.split(',').map(s => s.trim()).filter(Boolean)) : new Set();
|
|
45
|
+
this.webhookUrl = process.env.WEBHOOK_URL ?? '';
|
|
46
|
+
this.app = app ?? null;
|
|
47
|
+
}
|
|
48
|
+
// ── Lifecycle ──────────────────────────────────────────────
|
|
49
|
+
async start() {
|
|
50
|
+
if (!this.accountSid || !this.authToken || !this.fromNumber) {
|
|
51
|
+
console.log('[SMS] Disabled — set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE_NUMBER to enable');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let twilio;
|
|
55
|
+
try {
|
|
56
|
+
twilio = require('twilio');
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.log('[SMS] Disabled — twilio package not available:', e.message);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.twilioClient = twilio(this.accountSid, this.authToken);
|
|
63
|
+
// Register outbound delivery
|
|
64
|
+
gateway_1.gateway.registerChannel('sms', async (msg) => {
|
|
65
|
+
await this.send(msg.channelId, msg.text);
|
|
66
|
+
return true;
|
|
67
|
+
});
|
|
68
|
+
// Register inbound webhook handler on the express app
|
|
69
|
+
if (this.app) {
|
|
70
|
+
this.app.post('/api/channels/sms/inbound', async (req, res) => {
|
|
71
|
+
res.set('Content-Type', 'text/xml');
|
|
72
|
+
const from = req.body?.From ?? '';
|
|
73
|
+
const body = req.body?.Body ?? '';
|
|
74
|
+
if (!this.isAllowed(from)) {
|
|
75
|
+
res.send('<?xml version="1.0" encoding="UTF-8"?><Response></Response>');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const response = await this.processMessage(from, from, body);
|
|
79
|
+
// Reply via TwiML (Twilio Markup Language) — Twilio sends this as SMS
|
|
80
|
+
const twiml = [
|
|
81
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
82
|
+
'<Response>',
|
|
83
|
+
...chunkSms(response).map(chunk => ` <Message>${chunk.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}</Message>`),
|
|
84
|
+
'</Response>',
|
|
85
|
+
].join('\n');
|
|
86
|
+
res.send(twiml);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (!this.webhookUrl) {
|
|
90
|
+
console.log('[SMS] Outbound ready — inbound SMS requires public webhook URL (set WEBHOOK_URL env or use ngrok)');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(`[SMS] Ready — inbound webhook: ${this.webhookUrl}/api/channels/sms/inbound`);
|
|
94
|
+
}
|
|
95
|
+
this.healthy = true;
|
|
96
|
+
}
|
|
97
|
+
async stop() {
|
|
98
|
+
this.healthy = false;
|
|
99
|
+
gateway_1.gateway.unregisterChannel('sms');
|
|
100
|
+
this.twilioClient = null;
|
|
101
|
+
console.log('[SMS] Disconnected');
|
|
102
|
+
}
|
|
103
|
+
async send(target, message) {
|
|
104
|
+
if (!this.twilioClient || !this.healthy)
|
|
105
|
+
return;
|
|
106
|
+
const chunks = chunkSms(message);
|
|
107
|
+
for (const chunk of chunks) {
|
|
108
|
+
try {
|
|
109
|
+
await this.twilioClient.messages.create({
|
|
110
|
+
body: chunk,
|
|
111
|
+
from: this.fromNumber,
|
|
112
|
+
to: target,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
console.error('[SMS] send error:', e.message);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
isHealthy() { return this.healthy; }
|
|
122
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
123
|
+
isAllowed(number) {
|
|
124
|
+
if (this.allowedNumbers.size === 0)
|
|
125
|
+
return true;
|
|
126
|
+
return this.allowedNumbers.has(number);
|
|
127
|
+
}
|
|
128
|
+
async processMessage(channelId, userId, text) {
|
|
129
|
+
try {
|
|
130
|
+
return await gateway_1.gateway.routeMessage({
|
|
131
|
+
channel: 'sms',
|
|
132
|
+
channelId,
|
|
133
|
+
userId,
|
|
134
|
+
text,
|
|
135
|
+
timestamp: Date.now(),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
console.error('[SMS] routeMessage error:', e.message);
|
|
140
|
+
return 'Something went wrong. Try again.';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.TwilioAdapter = TwilioAdapter;
|