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,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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')}</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;