opensentinel 2.1.1

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/bot-KJ26BG56.js +15 -0
  4. package/dist/bot-KJ26BG56.js.map +1 -0
  5. package/dist/charts-MMXM6BWW.js +241 -0
  6. package/dist/charts-MMXM6BWW.js.map +1 -0
  7. package/dist/chunk-4LVWXUNC.js +1079 -0
  8. package/dist/chunk-4LVWXUNC.js.map +1 -0
  9. package/dist/chunk-4TG2IG5K.js +5249 -0
  10. package/dist/chunk-4TG2IG5K.js.map +1 -0
  11. package/dist/chunk-6DRDKB45.js +251 -0
  12. package/dist/chunk-6DRDKB45.js.map +1 -0
  13. package/dist/chunk-6SNHU3CY.js +123 -0
  14. package/dist/chunk-6SNHU3CY.js.map +1 -0
  15. package/dist/chunk-CI6Q63MM.js +1613 -0
  16. package/dist/chunk-CI6Q63MM.js.map +1 -0
  17. package/dist/chunk-CQ4JURG7.js +57 -0
  18. package/dist/chunk-CQ4JURG7.js.map +1 -0
  19. package/dist/chunk-F6QUZQGI.js +51 -0
  20. package/dist/chunk-F6QUZQGI.js.map +1 -0
  21. package/dist/chunk-GK3E2I7A.js +216 -0
  22. package/dist/chunk-GK3E2I7A.js.map +1 -0
  23. package/dist/chunk-GUBEEYDW.js +211 -0
  24. package/dist/chunk-GUBEEYDW.js.map +1 -0
  25. package/dist/chunk-GVJVEWHI.js +29 -0
  26. package/dist/chunk-GVJVEWHI.js.map +1 -0
  27. package/dist/chunk-HH2HBTQM.js +806 -0
  28. package/dist/chunk-HH2HBTQM.js.map +1 -0
  29. package/dist/chunk-JXUP2X7V.js +129 -0
  30. package/dist/chunk-JXUP2X7V.js.map +1 -0
  31. package/dist/chunk-KHNYJY2Z.js +178 -0
  32. package/dist/chunk-KHNYJY2Z.js.map +1 -0
  33. package/dist/chunk-L3F43VPB.js +652 -0
  34. package/dist/chunk-L3F43VPB.js.map +1 -0
  35. package/dist/chunk-L3PDU3XN.js +803 -0
  36. package/dist/chunk-L3PDU3XN.js.map +1 -0
  37. package/dist/chunk-NSBPE2FW.js +17 -0
  38. package/dist/chunk-NSBPE2FW.js.map +1 -0
  39. package/dist/cli.d.ts +1 -0
  40. package/dist/cli.js +52 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/commands/setup.d.ts +9 -0
  43. package/dist/commands/setup.js +374 -0
  44. package/dist/commands/setup.js.map +1 -0
  45. package/dist/commands/start.d.ts +8 -0
  46. package/dist/commands/start.js +27 -0
  47. package/dist/commands/start.js.map +1 -0
  48. package/dist/commands/status.d.ts +8 -0
  49. package/dist/commands/status.js +57 -0
  50. package/dist/commands/status.js.map +1 -0
  51. package/dist/commands/stop.d.ts +8 -0
  52. package/dist/commands/stop.js +37 -0
  53. package/dist/commands/stop.js.map +1 -0
  54. package/dist/commands/utils.d.ts +50 -0
  55. package/dist/commands/utils.js +36 -0
  56. package/dist/commands/utils.js.map +1 -0
  57. package/dist/discord-ZOJFTVTB.js +49 -0
  58. package/dist/discord-ZOJFTVTB.js.map +1 -0
  59. package/dist/imessage-JFRB6EJ7.js +14 -0
  60. package/dist/imessage-JFRB6EJ7.js.map +1 -0
  61. package/dist/lib.d.ts +855 -0
  62. package/dist/lib.js +274 -0
  63. package/dist/lib.js.map +1 -0
  64. package/dist/mcp-LS7Q3Z5W.js +30 -0
  65. package/dist/mcp-LS7Q3Z5W.js.map +1 -0
  66. package/dist/scheduler-EZ7CZMCS.js +42 -0
  67. package/dist/scheduler-EZ7CZMCS.js.map +1 -0
  68. package/dist/signal-T3MCSULM.js +14 -0
  69. package/dist/signal-T3MCSULM.js.map +1 -0
  70. package/dist/slack-N2M4FHAJ.js +54 -0
  71. package/dist/slack-N2M4FHAJ.js.map +1 -0
  72. package/dist/src-K7GASHRH.js +430 -0
  73. package/dist/src-K7GASHRH.js.map +1 -0
  74. package/dist/tools-24GZHYRF.js +16 -0
  75. package/dist/tools-24GZHYRF.js.map +1 -0
  76. package/dist/whatsapp-VCRUPAO5.js +14 -0
  77. package/dist/whatsapp-VCRUPAO5.js.map +1 -0
  78. package/drizzle/0000_chilly_shinobi_shaw.sql +75 -0
  79. package/drizzle/0001_freezing_shape.sql +274 -0
  80. package/drizzle/meta/0000_snapshot.json +529 -0
  81. package/drizzle/meta/0001_snapshot.json +2576 -0
  82. package/drizzle/meta/_journal.json +20 -0
  83. package/package.json +98 -0
@@ -0,0 +1,216 @@
1
+ import {
2
+ chatWithTools
3
+ } from "./chunk-CI6Q63MM.js";
4
+
5
+ // src/inputs/imessage/index.ts
6
+ var iMessageBot = class {
7
+ config;
8
+ conversations = /* @__PURE__ */ new Map();
9
+ isRunning = false;
10
+ pollTimer = null;
11
+ lastMessageTime = Date.now();
12
+ processedGuids = /* @__PURE__ */ new Set();
13
+ constructor(config) {
14
+ this.config = {
15
+ pollInterval: config.pollInterval || 5e3,
16
+ ...config
17
+ };
18
+ }
19
+ async start() {
20
+ if (this.isRunning) return;
21
+ if (process.platform !== "darwin" && this.config.mode === "applescript") {
22
+ throw new Error("AppleScript mode only works on macOS");
23
+ }
24
+ this.isRunning = true;
25
+ this.lastMessageTime = Date.now();
26
+ console.log(`[iMessage] Starting in ${this.config.mode} mode...`);
27
+ if (this.config.mode === "bluebubbles") {
28
+ await this.startBlueBubbles();
29
+ } else {
30
+ await this.startAppleScript();
31
+ }
32
+ }
33
+ // ============================================
34
+ // BLUEBUBBLES MODE
35
+ // ============================================
36
+ async startBlueBubbles() {
37
+ if (!this.config.serverUrl || !this.config.password) {
38
+ throw new Error("BlueBubbles requires serverUrl and password");
39
+ }
40
+ const response = await fetch(`${this.config.serverUrl}/api/v1/server/info`, {
41
+ headers: { Authorization: `Bearer ${this.config.password}` }
42
+ });
43
+ if (!response.ok) {
44
+ throw new Error("Failed to connect to BlueBubbles server");
45
+ }
46
+ console.log("[iMessage] Connected to BlueBubbles server");
47
+ this.pollTimer = setInterval(
48
+ () => this.pollBlueBubbles(),
49
+ this.config.pollInterval
50
+ );
51
+ }
52
+ async pollBlueBubbles() {
53
+ if (!this.config.serverUrl) return;
54
+ try {
55
+ const response = await fetch(
56
+ `${this.config.serverUrl}/api/v1/message?after=${this.lastMessageTime}&limit=50`,
57
+ {
58
+ headers: { Authorization: `Bearer ${this.config.password}` }
59
+ }
60
+ );
61
+ if (!response.ok) return;
62
+ const data = await response.json();
63
+ const messages = data.data;
64
+ for (const msg of messages) {
65
+ if (this.processedGuids.has(msg.guid) || msg.isFromMe) continue;
66
+ this.processedGuids.add(msg.guid);
67
+ await this.handleMessage(msg.handle.address, msg.text);
68
+ if (msg.dateCreated > this.lastMessageTime) {
69
+ this.lastMessageTime = msg.dateCreated;
70
+ }
71
+ }
72
+ if (this.processedGuids.size > 1e3) {
73
+ const arr = Array.from(this.processedGuids);
74
+ this.processedGuids = new Set(arr.slice(-500));
75
+ }
76
+ } catch (error) {
77
+ console.error("[iMessage] Error polling BlueBubbles:", error);
78
+ }
79
+ }
80
+ async sendBlueBubbles(to, text) {
81
+ if (!this.config.serverUrl) {
82
+ throw new Error("BlueBubbles not configured");
83
+ }
84
+ const response = await fetch(
85
+ `${this.config.serverUrl}/api/v1/message/text`,
86
+ {
87
+ method: "POST",
88
+ headers: {
89
+ Authorization: `Bearer ${this.config.password}`,
90
+ "Content-Type": "application/json"
91
+ },
92
+ body: JSON.stringify({
93
+ chatGuid: `iMessage;-;${to}`,
94
+ message: text
95
+ })
96
+ }
97
+ );
98
+ if (!response.ok) {
99
+ throw new Error(`Failed to send message: ${response.status}`);
100
+ }
101
+ }
102
+ // ============================================
103
+ // APPLESCRIPT MODE (macOS only)
104
+ // ============================================
105
+ async startAppleScript() {
106
+ console.log("[iMessage] Using AppleScript mode (macOS)");
107
+ this.pollTimer = setInterval(
108
+ () => this.pollAppleScript(),
109
+ this.config.pollInterval
110
+ );
111
+ }
112
+ async pollAppleScript() {
113
+ try {
114
+ const script = `
115
+ tell application "Messages"
116
+ set recentChats to chats
117
+ set output to ""
118
+ repeat with aChat in recentChats
119
+ set lastMsg to last item of messages of aChat
120
+ if (date sent of lastMsg) > (current date) - ${this.config.pollInterval / 1e3} then
121
+ if sender of lastMsg is not equal to me then
122
+ set senderNum to handle of sender of lastMsg
123
+ set msgText to content of lastMsg
124
+ set output to output & senderNum & "|||" & msgText & "\\n"
125
+ end if
126
+ end if
127
+ end repeat
128
+ return output
129
+ end tell
130
+ `;
131
+ const result = await this.runAppleScript(script);
132
+ if (!result.trim()) return;
133
+ const lines = result.trim().split("\n");
134
+ for (const line of lines) {
135
+ const [sender, text] = line.split("|||");
136
+ if (sender && text) {
137
+ await this.handleMessage(sender, text);
138
+ }
139
+ }
140
+ } catch (error) {
141
+ }
142
+ }
143
+ async runAppleScript(script) {
144
+ const { execFile } = await import("child_process");
145
+ const { promisify } = await import("util");
146
+ const execFileAsync = promisify(execFile);
147
+ const { stdout } = await execFileAsync("osascript", ["-e", script]);
148
+ return stdout;
149
+ }
150
+ async sendAppleScript(to, text) {
151
+ const escapedText = text.replace(/"/g, '\\"').replace(/\n/g, "\\n");
152
+ const script = `
153
+ tell application "Messages"
154
+ set targetService to 1st account whose service type = iMessage
155
+ set targetBuddy to participant "${to}" of targetService
156
+ send "${escapedText}" to targetBuddy
157
+ end tell
158
+ `;
159
+ await this.runAppleScript(script);
160
+ }
161
+ // ============================================
162
+ // MESSAGE HANDLING
163
+ // ============================================
164
+ async handleMessage(sender, text) {
165
+ if (!text.trim()) return;
166
+ if (this.config.allowedNumbers && this.config.allowedNumbers.length > 0 && !this.config.allowedNumbers.includes(sender)) {
167
+ console.log(`[iMessage] Ignoring message from unauthorized: ${sender}`);
168
+ return;
169
+ }
170
+ console.log(`[iMessage] Message from ${sender}: ${text.slice(0, 50)}...`);
171
+ let context = this.conversations.get(sender);
172
+ if (!context) {
173
+ context = { messages: [], lastActivity: /* @__PURE__ */ new Date() };
174
+ this.conversations.set(sender, context);
175
+ }
176
+ context.messages.push({ role: "user", content: text });
177
+ context.lastActivity = /* @__PURE__ */ new Date();
178
+ if (context.messages.length > 10) {
179
+ context.messages = context.messages.slice(-10);
180
+ }
181
+ try {
182
+ const response = await chatWithTools(context.messages, sender);
183
+ context.messages.push({ role: "assistant", content: response.content });
184
+ await this.sendMessage(sender, response.content);
185
+ console.log(`[iMessage] Replied to ${sender}`);
186
+ } catch (error) {
187
+ console.error("[iMessage] Error processing message:", error);
188
+ await this.sendMessage(sender, "Sorry, I encountered an error processing your request.");
189
+ }
190
+ }
191
+ async sendMessage(to, text) {
192
+ if (this.config.mode === "bluebubbles") {
193
+ await this.sendBlueBubbles(to, text);
194
+ } else {
195
+ await this.sendAppleScript(to, text);
196
+ }
197
+ }
198
+ async stop() {
199
+ this.isRunning = false;
200
+ if (this.pollTimer) {
201
+ clearInterval(this.pollTimer);
202
+ this.pollTimer = null;
203
+ }
204
+ console.log("[iMessage] Disconnected");
205
+ }
206
+ get running() {
207
+ return this.isRunning;
208
+ }
209
+ };
210
+ var imessage_default = iMessageBot;
211
+
212
+ export {
213
+ iMessageBot,
214
+ imessage_default
215
+ };
216
+ //# sourceMappingURL=chunk-GK3E2I7A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inputs/imessage/index.ts"],"sourcesContent":["/**\n * iMessage Integration\n * Connects OpenSentinel to iMessage (macOS only)\n *\n * Supports two modes:\n * 1. BlueBubbles - Requires BlueBubbles Server running on Mac\n * 2. AppleScript - Direct macOS integration (requires Full Disk Access)\n *\n * BlueBubbles: https://bluebubbles.app/\n */\n\nimport { chatWithTools } from \"../../core/brain\";\nimport type { Message } from \"../../core/brain\";\n\ninterface iMessageConfig {\n mode: \"bluebubbles\" | \"applescript\";\n // BlueBubbles settings\n serverUrl?: string;\n password?: string;\n // Common settings\n allowedNumbers?: string[];\n pollInterval?: number;\n}\n\ninterface BlueBubblesMessage {\n guid: string;\n text: string;\n handle: {\n address: string;\n };\n isFromMe: boolean;\n dateCreated: number;\n}\n\ninterface ConversationContext {\n messages: Message[];\n lastActivity: Date;\n}\n\nexport class iMessageBot {\n private config: iMessageConfig;\n private conversations: Map<string, ConversationContext> = new Map();\n private isRunning = false;\n private pollTimer: Timer | null = null;\n private lastMessageTime: number = Date.now();\n private processedGuids: Set<string> = new Set();\n\n constructor(config: iMessageConfig) {\n this.config = {\n pollInterval: config.pollInterval || 5000,\n ...config,\n };\n }\n\n async start(): Promise<void> {\n if (this.isRunning) return;\n\n // Check platform\n if (process.platform !== \"darwin\" && this.config.mode === \"applescript\") {\n throw new Error(\"AppleScript mode only works on macOS\");\n }\n\n this.isRunning = true;\n this.lastMessageTime = Date.now();\n\n console.log(`[iMessage] Starting in ${this.config.mode} mode...`);\n\n if (this.config.mode === \"bluebubbles\") {\n await this.startBlueBubbles();\n } else {\n await this.startAppleScript();\n }\n }\n\n // ============================================\n // BLUEBUBBLES MODE\n // ============================================\n\n private async startBlueBubbles(): Promise<void> {\n if (!this.config.serverUrl || !this.config.password) {\n throw new Error(\"BlueBubbles requires serverUrl and password\");\n }\n\n // Verify connection\n const response = await fetch(`${this.config.serverUrl}/api/v1/server/info`, {\n headers: { Authorization: `Bearer ${this.config.password}` },\n });\n\n if (!response.ok) {\n throw new Error(\"Failed to connect to BlueBubbles server\");\n }\n\n console.log(\"[iMessage] Connected to BlueBubbles server\");\n\n // Start polling for new messages\n this.pollTimer = setInterval(\n () => this.pollBlueBubbles(),\n this.config.pollInterval\n );\n }\n\n private async pollBlueBubbles(): Promise<void> {\n if (!this.config.serverUrl) return;\n\n try {\n const response = await fetch(\n `${this.config.serverUrl}/api/v1/message?after=${this.lastMessageTime}&limit=50`,\n {\n headers: { Authorization: `Bearer ${this.config.password}` },\n }\n );\n\n if (!response.ok) return;\n\n const data = await response.json();\n const messages = data.data as BlueBubblesMessage[];\n\n for (const msg of messages) {\n // Skip if already processed or from us\n if (this.processedGuids.has(msg.guid) || msg.isFromMe) continue;\n\n this.processedGuids.add(msg.guid);\n await this.handleMessage(msg.handle.address, msg.text);\n\n // Update last message time\n if (msg.dateCreated > this.lastMessageTime) {\n this.lastMessageTime = msg.dateCreated;\n }\n }\n\n // Cleanup old GUIDs (keep last 1000)\n if (this.processedGuids.size > 1000) {\n const arr = Array.from(this.processedGuids);\n this.processedGuids = new Set(arr.slice(-500));\n }\n } catch (error) {\n console.error(\"[iMessage] Error polling BlueBubbles:\", error);\n }\n }\n\n private async sendBlueBubbles(to: string, text: string): Promise<void> {\n if (!this.config.serverUrl) {\n throw new Error(\"BlueBubbles not configured\");\n }\n\n const response = await fetch(\n `${this.config.serverUrl}/api/v1/message/text`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.config.password}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chatGuid: `iMessage;-;${to}`,\n message: text,\n }),\n }\n );\n\n if (!response.ok) {\n throw new Error(`Failed to send message: ${response.status}`);\n }\n }\n\n // ============================================\n // APPLESCRIPT MODE (macOS only)\n // ============================================\n\n private async startAppleScript(): Promise<void> {\n console.log(\"[iMessage] Using AppleScript mode (macOS)\");\n\n // Start polling Messages.app database\n this.pollTimer = setInterval(\n () => this.pollAppleScript(),\n this.config.pollInterval\n );\n }\n\n private async pollAppleScript(): Promise<void> {\n try {\n // Query Messages database for new messages\n const script = `\n tell application \"Messages\"\n set recentChats to chats\n set output to \"\"\n repeat with aChat in recentChats\n set lastMsg to last item of messages of aChat\n if (date sent of lastMsg) > (current date) - ${this.config.pollInterval! / 1000} then\n if sender of lastMsg is not equal to me then\n set senderNum to handle of sender of lastMsg\n set msgText to content of lastMsg\n set output to output & senderNum & \"|||\" & msgText & \"\\\\n\"\n end if\n end if\n end repeat\n return output\n end tell\n `;\n\n const result = await this.runAppleScript(script);\n if (!result.trim()) return;\n\n const lines = result.trim().split(\"\\n\");\n for (const line of lines) {\n const [sender, text] = line.split(\"|||\");\n if (sender && text) {\n await this.handleMessage(sender, text);\n }\n }\n } catch (error) {\n // AppleScript errors are common, don't spam logs\n }\n }\n\n private async runAppleScript(script: string): Promise<string> {\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execFileAsync = promisify(execFile);\n\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n return stdout;\n }\n\n private async sendAppleScript(to: string, text: string): Promise<void> {\n const escapedText = text.replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\");\n\n const script = `\n tell application \"Messages\"\n set targetService to 1st account whose service type = iMessage\n set targetBuddy to participant \"${to}\" of targetService\n send \"${escapedText}\" to targetBuddy\n end tell\n `;\n\n await this.runAppleScript(script);\n }\n\n // ============================================\n // MESSAGE HANDLING\n // ============================================\n\n private async handleMessage(sender: string, text: string): Promise<void> {\n if (!text.trim()) return;\n\n // Check if sender is allowed\n if (\n this.config.allowedNumbers &&\n this.config.allowedNumbers.length > 0 &&\n !this.config.allowedNumbers.includes(sender)\n ) {\n console.log(`[iMessage] Ignoring message from unauthorized: ${sender}`);\n return;\n }\n\n console.log(`[iMessage] Message from ${sender}: ${text.slice(0, 50)}...`);\n\n // Get or create conversation context\n let context = this.conversations.get(sender);\n if (!context) {\n context = { messages: [], lastActivity: new Date() };\n this.conversations.set(sender, context);\n }\n\n // Add user message to context\n context.messages.push({ role: \"user\", content: text });\n context.lastActivity = new Date();\n\n // Keep only last 10 messages\n if (context.messages.length > 10) {\n context.messages = context.messages.slice(-10);\n }\n\n try {\n // Get AI response\n const response = await chatWithTools(context.messages, sender);\n\n // Add assistant response to context\n context.messages.push({ role: \"assistant\", content: response.content });\n\n // Send response\n await this.sendMessage(sender, response.content);\n\n console.log(`[iMessage] Replied to ${sender}`);\n } catch (error) {\n console.error(\"[iMessage] Error processing message:\", error);\n await this.sendMessage(sender, \"Sorry, I encountered an error processing your request.\");\n }\n }\n\n async sendMessage(to: string, text: string): Promise<void> {\n if (this.config.mode === \"bluebubbles\") {\n await this.sendBlueBubbles(to, text);\n } else {\n await this.sendAppleScript(to, text);\n }\n }\n\n async stop(): Promise<void> {\n this.isRunning = false;\n\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n\n console.log(\"[iMessage] Disconnected\");\n }\n\n get running(): boolean {\n return this.isRunning;\n }\n}\n\nexport default iMessageBot;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,211 @@
1
+ // src/commands/utils.ts
2
+ import { createInterface } from "readline";
3
+ import { exec as execCb } from "child_process";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+ import { existsSync, mkdirSync, readFileSync } from "fs";
7
+ var colors = {
8
+ reset: "\x1B[0m",
9
+ bold: "\x1B[1m",
10
+ dim: "\x1B[2m",
11
+ green: "\x1B[32m",
12
+ cyan: "\x1B[36m",
13
+ yellow: "\x1B[33m",
14
+ red: "\x1B[31m",
15
+ magenta: "\x1B[35m"
16
+ };
17
+ async function prompt(question) {
18
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
19
+ return new Promise((resolve) => {
20
+ rl.question(question, (answer) => {
21
+ rl.close();
22
+ resolve(answer.trim());
23
+ });
24
+ });
25
+ }
26
+ async function confirm(question, defaultYes = true) {
27
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
28
+ const answer = await prompt(`${question} ${hint} `);
29
+ if (answer === "") return defaultYes;
30
+ return answer.toLowerCase().startsWith("y");
31
+ }
32
+ async function promptSecret(question) {
33
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
34
+ if (process.stdin.isTTY) {
35
+ process.stdin.setRawMode?.(false);
36
+ }
37
+ return new Promise((resolve) => {
38
+ rl.question(question, (answer) => {
39
+ rl.close();
40
+ resolve(answer.trim());
41
+ });
42
+ });
43
+ }
44
+ async function exec(cmd, opts) {
45
+ return new Promise((resolve, reject) => {
46
+ const child = execCb(cmd, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
47
+ const exitCode = error?.code ?? 0;
48
+ const result = { stdout: stdout.toString(), stderr: stderr.toString(), exitCode: typeof exitCode === "number" ? exitCode : 1 };
49
+ if (error && opts?.throws !== false) {
50
+ reject(Object.assign(error, result));
51
+ } else {
52
+ resolve(result);
53
+ }
54
+ });
55
+ if (opts?.input) {
56
+ child.stdin?.write(opts.input);
57
+ child.stdin?.end();
58
+ }
59
+ });
60
+ }
61
+ async function which(binary) {
62
+ try {
63
+ const result = await exec(`which ${binary}`, { throws: false });
64
+ return result.stdout.trim() || null;
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+ function detectPlatform() {
70
+ const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "other";
71
+ let distro = "unknown";
72
+ let packageManager = "unknown";
73
+ if (os === "linux") {
74
+ try {
75
+ const osRelease = readFileSync("/etc/os-release", "utf-8");
76
+ const idMatch = osRelease.match(/^ID=(.+)$/m);
77
+ const idLikeMatch = osRelease.match(/^ID_LIKE=(.+)$/m);
78
+ distro = idMatch?.[1]?.replace(/"/g, "") || "unknown";
79
+ const idLike = idLikeMatch?.[1]?.replace(/"/g, "") || "";
80
+ if (distro === "ubuntu" || distro === "debian" || idLike.includes("debian")) {
81
+ packageManager = "apt";
82
+ } else if (distro === "fedora" || idLike.includes("fedora") || idLike.includes("rhel")) {
83
+ packageManager = "dnf";
84
+ } else if (distro === "arch" || idLike.includes("arch")) {
85
+ packageManager = "pacman";
86
+ }
87
+ } catch {
88
+ }
89
+ } else if (os === "darwin") {
90
+ packageManager = "brew";
91
+ distro = "macos";
92
+ }
93
+ return { os, distro, packageManager };
94
+ }
95
+ function getConfigDir() {
96
+ const dir = process.env.OPENSENTINEL_HOME || join(homedir(), ".opensentinel");
97
+ if (!existsSync(dir)) {
98
+ mkdirSync(dir, { recursive: true });
99
+ }
100
+ return dir;
101
+ }
102
+ function getPackageRoot() {
103
+ let dir = import.meta.dirname || __dirname;
104
+ for (let i = 0; i < 5; i++) {
105
+ if (existsSync(join(dir, "package.json"))) {
106
+ return dir;
107
+ }
108
+ dir = join(dir, "..");
109
+ }
110
+ return process.cwd();
111
+ }
112
+ function getMigrationsDir() {
113
+ return join(getPackageRoot(), "drizzle");
114
+ }
115
+ async function checkPort(port) {
116
+ try {
117
+ const result = await exec(`ss -tlnp 2>/dev/null | grep :${port} || netstat -tlnp 2>/dev/null | grep :${port}`, { throws: false });
118
+ return result.stdout.trim().length > 0;
119
+ } catch {
120
+ return false;
121
+ }
122
+ }
123
+ async function checkPostgres() {
124
+ const installed = !!await which("psql");
125
+ let running = false;
126
+ let port = 5432;
127
+ if (installed) {
128
+ const result = await exec("pg_isready -q 2>/dev/null", { throws: false });
129
+ running = result.exitCode === 0;
130
+ }
131
+ if (!running) {
132
+ const port5445 = await checkPort(5445);
133
+ if (port5445) {
134
+ running = true;
135
+ port = 5445;
136
+ }
137
+ }
138
+ return { installed, running, port };
139
+ }
140
+ async function checkRedis() {
141
+ const installed = !!await which("redis-cli");
142
+ let running = false;
143
+ let port = 6379;
144
+ if (installed) {
145
+ const result = await exec("redis-cli ping 2>/dev/null", { throws: false });
146
+ running = result.stdout.trim() === "PONG";
147
+ }
148
+ if (!running) {
149
+ for (const p of [6384, 6380]) {
150
+ const result = await exec(`redis-cli -p ${p} ping 2>/dev/null`, { throws: false });
151
+ if (result.stdout.trim() === "PONG") {
152
+ running = true;
153
+ port = p;
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ return { installed, running, port };
159
+ }
160
+ function printBanner() {
161
+ console.log(`
162
+ ${colors.cyan}${colors.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
163
+ \u2551 OPENSENTINEL v2.0.0 \u2551
164
+ \u2551 Your Personal AI Assistant \u2551
165
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${colors.reset}
166
+ `);
167
+ }
168
+ function loadEnvFile() {
169
+ const candidates = [
170
+ process.env.OPENSENTINEL_HOME && join(process.env.OPENSENTINEL_HOME, ".env"),
171
+ join(homedir(), ".opensentinel", ".env"),
172
+ join(process.cwd(), ".env")
173
+ ].filter(Boolean);
174
+ for (const candidate of candidates) {
175
+ if (existsSync(candidate)) {
176
+ const content = readFileSync(candidate, "utf-8");
177
+ for (const line of content.split("\n")) {
178
+ const trimmed = line.trim();
179
+ if (!trimmed || trimmed.startsWith("#")) continue;
180
+ const eqIndex = trimmed.indexOf("=");
181
+ if (eqIndex === -1) continue;
182
+ const key = trimmed.slice(0, eqIndex).trim();
183
+ const value = trimmed.slice(eqIndex + 1).trim();
184
+ if (!process.env[key]) {
185
+ process.env[key] = value;
186
+ }
187
+ }
188
+ return candidate;
189
+ }
190
+ }
191
+ return null;
192
+ }
193
+
194
+ export {
195
+ colors,
196
+ prompt,
197
+ confirm,
198
+ promptSecret,
199
+ exec,
200
+ which,
201
+ detectPlatform,
202
+ getConfigDir,
203
+ getPackageRoot,
204
+ getMigrationsDir,
205
+ checkPort,
206
+ checkPostgres,
207
+ checkRedis,
208
+ printBanner,
209
+ loadEnvFile
210
+ };
211
+ //# sourceMappingURL=chunk-GUBEEYDW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/utils.ts"],"sourcesContent":["/**\n * Shared CLI utilities for OpenSentinel commands.\n */\n\nimport { createInterface } from \"node:readline\";\nimport { exec as execCb } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\n\n// ── Colors (ANSI escape codes) ───────────────────────────────────────────────\n\nexport const colors = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n cyan: \"\\x1b[36m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n magenta: \"\\x1b[35m\",\n};\n\n// ── Interactive prompts ──────────────────────────────────────────────────────\n\nexport async function prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport async function confirm(question: string, defaultYes = true): Promise<boolean> {\n const hint = defaultYes ? \"[Y/n]\" : \"[y/N]\";\n const answer = await prompt(`${question} ${hint} `);\n if (answer === \"\") return defaultYes;\n return answer.toLowerCase().startsWith(\"y\");\n}\n\nexport async function promptSecret(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n // Disable echo for secret input\n if (process.stdin.isTTY) {\n process.stdin.setRawMode?.(false);\n }\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\n// ── Shell execution ──────────────────────────────────────────────────────────\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nexport async function exec(cmd: string, opts?: { throws?: boolean; input?: string }): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const child = execCb(cmd, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {\n const exitCode = error?.code ?? 0;\n const result = { stdout: stdout.toString(), stderr: stderr.toString(), exitCode: typeof exitCode === \"number\" ? exitCode : 1 };\n if (error && opts?.throws !== false) {\n reject(Object.assign(error, result));\n } else {\n resolve(result);\n }\n });\n if (opts?.input) {\n child.stdin?.write(opts.input);\n child.stdin?.end();\n }\n });\n}\n\nexport async function which(binary: string): Promise<string | null> {\n try {\n const result = await exec(`which ${binary}`, { throws: false });\n return result.stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\n// ── Platform detection ───────────────────────────────────────────────────────\n\nexport interface Platform {\n os: \"linux\" | \"darwin\" | \"other\";\n distro: string;\n packageManager: \"apt\" | \"brew\" | \"dnf\" | \"pacman\" | \"unknown\";\n}\n\nexport function detectPlatform(): Platform {\n const os = process.platform === \"linux\" ? \"linux\"\n : process.platform === \"darwin\" ? \"darwin\"\n : \"other\" as const;\n\n let distro = \"unknown\";\n let packageManager: Platform[\"packageManager\"] = \"unknown\";\n\n if (os === \"linux\") {\n try {\n const osRelease = readFileSync(\"/etc/os-release\", \"utf-8\");\n const idMatch = osRelease.match(/^ID=(.+)$/m);\n const idLikeMatch = osRelease.match(/^ID_LIKE=(.+)$/m);\n distro = idMatch?.[1]?.replace(/\"/g, \"\") || \"unknown\";\n const idLike = idLikeMatch?.[1]?.replace(/\"/g, \"\") || \"\";\n\n if (distro === \"ubuntu\" || distro === \"debian\" || idLike.includes(\"debian\")) {\n packageManager = \"apt\";\n } else if (distro === \"fedora\" || idLike.includes(\"fedora\") || idLike.includes(\"rhel\")) {\n packageManager = \"dnf\";\n } else if (distro === \"arch\" || idLike.includes(\"arch\")) {\n packageManager = \"pacman\";\n }\n } catch {}\n } else if (os === \"darwin\") {\n packageManager = \"brew\";\n distro = \"macos\";\n }\n\n return { os, distro, packageManager };\n}\n\n// ── Config directory ─────────────────────────────────────────────────────────\n\nexport function getConfigDir(): string {\n const dir = process.env.OPENSENTINEL_HOME || join(homedir(), \".opensentinel\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dir;\n}\n\nexport function getPackageRoot(): string {\n // When running from source: import.meta.dirname is src/commands/\n // When installed globally: import.meta.dirname is dist/commands/ or dist/\n // Go up to find package.json\n let dir = import.meta.dirname || __dirname;\n for (let i = 0; i < 5; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = join(dir, \"..\");\n }\n return process.cwd();\n}\n\nexport function getMigrationsDir(): string {\n return join(getPackageRoot(), \"drizzle\");\n}\n\n// ── Port and service checks ──────────────────────────────────────────────────\n\nexport async function checkPort(port: number): Promise<boolean> {\n try {\n const result = await exec(`ss -tlnp 2>/dev/null | grep :${port} || netstat -tlnp 2>/dev/null | grep :${port}`, { throws: false });\n return result.stdout.trim().length > 0;\n } catch {\n return false;\n }\n}\n\nexport async function checkPostgres(): Promise<{ installed: boolean; running: boolean; port: number }> {\n const installed = !!(await which(\"psql\"));\n let running = false;\n let port = 5432;\n\n if (installed) {\n const result = await exec(\"pg_isready -q 2>/dev/null\", { throws: false });\n running = result.exitCode === 0;\n }\n\n // Also check if running on non-standard port\n if (!running) {\n const port5445 = await checkPort(5445);\n if (port5445) {\n running = true;\n port = 5445;\n }\n }\n\n return { installed, running, port };\n}\n\nexport async function checkRedis(): Promise<{ installed: boolean; running: boolean; port: number }> {\n const installed = !!(await which(\"redis-cli\"));\n let running = false;\n let port = 6379;\n\n if (installed) {\n const result = await exec(\"redis-cli ping 2>/dev/null\", { throws: false });\n running = result.stdout.trim() === \"PONG\";\n }\n\n // Check alternate ports\n if (!running) {\n for (const p of [6384, 6380]) {\n const result = await exec(`redis-cli -p ${p} ping 2>/dev/null`, { throws: false });\n if (result.stdout.trim() === \"PONG\") {\n running = true;\n port = p;\n break;\n }\n }\n }\n\n return { installed, running, port };\n}\n\n// ── Banner ───────────────────────────────────────────────────────────────────\n\nexport function printBanner() {\n console.log(`\n${colors.cyan}${colors.bold}╔══════════════════════════════════════════╗\n║ OPENSENTINEL v2.0.0 ║\n║ Your Personal AI Assistant ║\n╚══════════════════════════════════════════╝${colors.reset}\n`);\n}\n\n// ── .env file loading ────────────────────────────────────────────────────────\n\nexport function loadEnvFile(): string | null {\n const candidates = [\n process.env.OPENSENTINEL_HOME && join(process.env.OPENSENTINEL_HOME, \".env\"),\n join(homedir(), \".opensentinel\", \".env\"),\n join(process.cwd(), \".env\"),\n ].filter(Boolean) as string[];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n const content = readFileSync(candidate, \"utf-8\");\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n const value = trimmed.slice(eqIndex + 1).trim();\n // Don't override existing env vars\n if (!process.env[key]) {\n process.env[key] = value;\n }\n }\n return candidate;\n }\n }\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ import {
2
+ env
3
+ } from "./chunk-4TG2IG5K.js";
4
+
5
+ // src/outputs/stt.ts
6
+ import OpenAI from "openai";
7
+ var openai = new OpenAI({
8
+ apiKey: env.OPENAI_API_KEY
9
+ });
10
+ async function transcribeAudio(audioBuffer, language) {
11
+ try {
12
+ const uint8Array = new Uint8Array(audioBuffer);
13
+ const file = new File([uint8Array], "audio.ogg", { type: "audio/ogg" });
14
+ const response = await openai.audio.transcriptions.create({
15
+ file,
16
+ model: "whisper-1",
17
+ language: language || "en"
18
+ });
19
+ return response.text;
20
+ } catch (error) {
21
+ console.error("Error transcribing audio:", error);
22
+ return null;
23
+ }
24
+ }
25
+
26
+ export {
27
+ transcribeAudio
28
+ };
29
+ //# sourceMappingURL=chunk-GVJVEWHI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/outputs/stt.ts"],"sourcesContent":["import OpenAI from \"openai\";\nimport { env } from \"../config/env\";\n\nconst openai = new OpenAI({\n apiKey: env.OPENAI_API_KEY,\n});\n\nexport async function transcribeAudio(\n audioBuffer: Buffer,\n language?: string\n): Promise<string | null> {\n try {\n // Create a File object from the buffer (convert to Uint8Array for compatibility)\n const uint8Array = new Uint8Array(audioBuffer);\n const file = new File([uint8Array], \"audio.ogg\", { type: \"audio/ogg\" });\n\n const response = await openai.audio.transcriptions.create({\n file,\n model: \"whisper-1\",\n language: language || \"en\",\n });\n\n return response.text;\n } catch (error) {\n console.error(\"Error transcribing audio:\", error);\n return null;\n }\n}\n"],"mappings":";;;;;AAAA,OAAO,YAAY;AAGnB,IAAM,SAAS,IAAI,OAAO;AAAA,EACxB,QAAQ,IAAI;AACd,CAAC;AAED,eAAsB,gBACpB,aACA,UACwB;AACxB,MAAI;AAEF,UAAM,aAAa,IAAI,WAAW,WAAW;AAC7C,UAAM,OAAO,IAAI,KAAK,CAAC,UAAU,GAAG,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtE,UAAM,WAAW,MAAM,OAAO,MAAM,eAAe,OAAO;AAAA,MACxD;AAAA,MACA,OAAO;AAAA,MACP,UAAU,YAAY;AAAA,IACxB,CAAC;AAED,WAAO,SAAS;AAAA,EAClB,SAAS,OAAO;AACd,YAAQ,MAAM,6BAA6B,KAAK;AAChD,WAAO;AAAA,EACT;AACF;","names":[]}