beecork 1.7.1 → 2.0.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 (253) hide show
  1. package/README.md +52 -111
  2. package/dist/index.js +1394 -581
  3. package/package.json +26 -54
  4. package/dist/capabilities/index.d.ts +0 -3
  5. package/dist/capabilities/index.js +0 -2
  6. package/dist/capabilities/manager.d.ts +0 -13
  7. package/dist/capabilities/manager.js +0 -115
  8. package/dist/capabilities/packs.d.ts +0 -2
  9. package/dist/capabilities/packs.js +0 -54
  10. package/dist/capabilities/types.d.ts +0 -21
  11. package/dist/capabilities/types.js +0 -1
  12. package/dist/channels/admin.d.ts +0 -10
  13. package/dist/channels/admin.js +0 -20
  14. package/dist/channels/command-handler.d.ts +0 -19
  15. package/dist/channels/command-handler.js +0 -235
  16. package/dist/channels/discord.d.ts +0 -17
  17. package/dist/channels/discord.js +0 -266
  18. package/dist/channels/index.d.ts +0 -7
  19. package/dist/channels/index.js +0 -6
  20. package/dist/channels/loader.d.ts +0 -7
  21. package/dist/channels/loader.js +0 -87
  22. package/dist/channels/pipeline.d.ts +0 -50
  23. package/dist/channels/pipeline.js +0 -92
  24. package/dist/channels/registry.d.ts +0 -36
  25. package/dist/channels/registry.js +0 -80
  26. package/dist/channels/send-helpers.d.ts +0 -19
  27. package/dist/channels/send-helpers.js +0 -21
  28. package/dist/channels/telegram.d.ts +0 -47
  29. package/dist/channels/telegram.js +0 -649
  30. package/dist/channels/types.d.ts +0 -41
  31. package/dist/channels/types.js +0 -1
  32. package/dist/channels/voice-state.d.ts +0 -29
  33. package/dist/channels/voice-state.js +0 -45
  34. package/dist/channels/webhook.d.ts +0 -16
  35. package/dist/channels/webhook.js +0 -222
  36. package/dist/channels/whatsapp.d.ts +0 -28
  37. package/dist/channels/whatsapp.js +0 -323
  38. package/dist/cli/capabilities.d.ts +0 -3
  39. package/dist/cli/capabilities.js +0 -72
  40. package/dist/cli/channel.d.ts +0 -3
  41. package/dist/cli/channel.js +0 -202
  42. package/dist/cli/commands.d.ts +0 -15
  43. package/dist/cli/commands.js +0 -279
  44. package/dist/cli/doctor.d.ts +0 -1
  45. package/dist/cli/doctor.js +0 -208
  46. package/dist/cli/handoff.d.ts +0 -8
  47. package/dist/cli/handoff.js +0 -33
  48. package/dist/cli/helpers.d.ts +0 -2
  49. package/dist/cli/helpers.js +0 -21
  50. package/dist/cli/mcp.d.ts +0 -3
  51. package/dist/cli/mcp.js +0 -47
  52. package/dist/cli/media.d.ts +0 -2
  53. package/dist/cli/media.js +0 -125
  54. package/dist/cli/setup.d.ts +0 -1
  55. package/dist/cli/setup.js +0 -239
  56. package/dist/cli/store.d.ts +0 -3
  57. package/dist/cli/store.js +0 -108
  58. package/dist/config.d.ts +0 -11
  59. package/dist/config.js +0 -115
  60. package/dist/cron/scheduler.d.ts +0 -22
  61. package/dist/cron/scheduler.js +0 -220
  62. package/dist/cron/store.d.ts +0 -12
  63. package/dist/cron/store.js +0 -83
  64. package/dist/daemon.d.ts +0 -1
  65. package/dist/daemon.js +0 -345
  66. package/dist/dashboard/html.d.ts +0 -1
  67. package/dist/dashboard/html.js +0 -849
  68. package/dist/dashboard/routes.d.ts +0 -17
  69. package/dist/dashboard/routes.js +0 -623
  70. package/dist/dashboard/server.d.ts +0 -1
  71. package/dist/dashboard/server.js +0 -104
  72. package/dist/db/connection.d.ts +0 -29
  73. package/dist/db/connection.js +0 -37
  74. package/dist/db/index.d.ts +0 -14
  75. package/dist/db/index.js +0 -127
  76. package/dist/db/migrations.d.ts +0 -2
  77. package/dist/db/migrations.js +0 -384
  78. package/dist/delegation/manager.d.ts +0 -18
  79. package/dist/delegation/manager.js +0 -89
  80. package/dist/index.d.ts +0 -2
  81. package/dist/knowledge/index.d.ts +0 -2
  82. package/dist/knowledge/index.js +0 -1
  83. package/dist/knowledge/manager.d.ts +0 -17
  84. package/dist/knowledge/manager.js +0 -160
  85. package/dist/knowledge/types.d.ts +0 -7
  86. package/dist/knowledge/types.js +0 -1
  87. package/dist/machines/forwarder.d.ts +0 -7
  88. package/dist/machines/forwarder.js +0 -35
  89. package/dist/machines/index.d.ts +0 -1
  90. package/dist/machines/index.js +0 -1
  91. package/dist/machines/registry.d.ts +0 -15
  92. package/dist/machines/registry.js +0 -46
  93. package/dist/mcp/handlers.d.ts +0 -37
  94. package/dist/mcp/handlers.js +0 -520
  95. package/dist/mcp/server.d.ts +0 -2
  96. package/dist/mcp/server.js +0 -86
  97. package/dist/mcp/tool-definitions.d.ts +0 -1225
  98. package/dist/mcp/tool-definitions.js +0 -412
  99. package/dist/mcp/validate.d.ts +0 -23
  100. package/dist/mcp/validate.js +0 -65
  101. package/dist/media/factory.d.ts +0 -6
  102. package/dist/media/factory.js +0 -36
  103. package/dist/media/generators/dall-e.d.ts +0 -10
  104. package/dist/media/generators/dall-e.js +0 -41
  105. package/dist/media/generators/elevenlabs-music.d.ts +0 -9
  106. package/dist/media/generators/elevenlabs-music.js +0 -34
  107. package/dist/media/generators/elevenlabs-sfx.d.ts +0 -9
  108. package/dist/media/generators/elevenlabs-sfx.js +0 -33
  109. package/dist/media/generators/kling.d.ts +0 -9
  110. package/dist/media/generators/kling.js +0 -47
  111. package/dist/media/generators/lyria.d.ts +0 -10
  112. package/dist/media/generators/lyria.js +0 -41
  113. package/dist/media/generators/nano-banana.d.ts +0 -10
  114. package/dist/media/generators/nano-banana.js +0 -45
  115. package/dist/media/generators/poll-util.d.ts +0 -12
  116. package/dist/media/generators/poll-util.js +0 -22
  117. package/dist/media/generators/recraft.d.ts +0 -9
  118. package/dist/media/generators/recraft.js +0 -52
  119. package/dist/media/generators/runway.d.ts +0 -9
  120. package/dist/media/generators/runway.js +0 -49
  121. package/dist/media/generators/stable-diffusion.d.ts +0 -9
  122. package/dist/media/generators/stable-diffusion.js +0 -35
  123. package/dist/media/generators/veo.d.ts +0 -9
  124. package/dist/media/generators/veo.js +0 -32
  125. package/dist/media/index.d.ts +0 -6
  126. package/dist/media/index.js +0 -8
  127. package/dist/media/loader.d.ts +0 -8
  128. package/dist/media/loader.js +0 -46
  129. package/dist/media/store.d.ts +0 -17
  130. package/dist/media/store.js +0 -69
  131. package/dist/media/types.d.ts +0 -43
  132. package/dist/media/types.js +0 -1
  133. package/dist/memory/extractor.d.ts +0 -5
  134. package/dist/memory/extractor.js +0 -157
  135. package/dist/notifications/index.d.ts +0 -4
  136. package/dist/notifications/index.js +0 -21
  137. package/dist/notifications/ntfy.d.ts +0 -9
  138. package/dist/notifications/ntfy.js +0 -25
  139. package/dist/notifications/pushover.d.ts +0 -9
  140. package/dist/notifications/pushover.js +0 -26
  141. package/dist/notifications/types.d.ts +0 -5
  142. package/dist/notifications/types.js +0 -1
  143. package/dist/notifications/webhook-provider.d.ts +0 -9
  144. package/dist/notifications/webhook-provider.js +0 -24
  145. package/dist/observability/analytics.d.ts +0 -30
  146. package/dist/observability/analytics.js +0 -118
  147. package/dist/pipe/anthropic-client.d.ts +0 -9
  148. package/dist/pipe/anthropic-client.js +0 -50
  149. package/dist/pipe/brain.d.ts +0 -16
  150. package/dist/pipe/brain.js +0 -89
  151. package/dist/pipe/memory-store.d.ts +0 -8
  152. package/dist/pipe/memory-store.js +0 -39
  153. package/dist/pipe/project-scanner.d.ts +0 -6
  154. package/dist/pipe/project-scanner.js +0 -26
  155. package/dist/pipe/types.d.ts +0 -34
  156. package/dist/pipe/types.js +0 -1
  157. package/dist/projects/index.d.ts +0 -4
  158. package/dist/projects/index.js +0 -2
  159. package/dist/projects/manager.d.ts +0 -13
  160. package/dist/projects/manager.js +0 -166
  161. package/dist/projects/router.d.ts +0 -17
  162. package/dist/projects/router.js +0 -246
  163. package/dist/projects/types.d.ts +0 -19
  164. package/dist/projects/types.js +0 -1
  165. package/dist/service/install.d.ts +0 -4
  166. package/dist/service/install.js +0 -146
  167. package/dist/service/templates.d.ts +0 -4
  168. package/dist/service/templates.js +0 -52
  169. package/dist/service/windows.d.ts +0 -8
  170. package/dist/service/windows.js +0 -59
  171. package/dist/session/budget-guard.d.ts +0 -20
  172. package/dist/session/budget-guard.js +0 -31
  173. package/dist/session/circuit-breaker.d.ts +0 -19
  174. package/dist/session/circuit-breaker.js +0 -91
  175. package/dist/session/context-compactor.d.ts +0 -32
  176. package/dist/session/context-compactor.js +0 -45
  177. package/dist/session/context-monitor.d.ts +0 -15
  178. package/dist/session/context-monitor.js +0 -44
  179. package/dist/session/handoff.d.ts +0 -21
  180. package/dist/session/handoff.js +0 -50
  181. package/dist/session/manager.d.ts +0 -60
  182. package/dist/session/manager.js +0 -416
  183. package/dist/session/memory-store.d.ts +0 -29
  184. package/dist/session/memory-store.js +0 -45
  185. package/dist/session/message-queue.d.ts +0 -28
  186. package/dist/session/message-queue.js +0 -52
  187. package/dist/session/pending-dispatcher.d.ts +0 -31
  188. package/dist/session/pending-dispatcher.js +0 -120
  189. package/dist/session/pending-store.d.ts +0 -60
  190. package/dist/session/pending-store.js +0 -118
  191. package/dist/session/stale-session.d.ts +0 -31
  192. package/dist/session/stale-session.js +0 -45
  193. package/dist/session/subprocess.d.ts +0 -32
  194. package/dist/session/subprocess.js +0 -230
  195. package/dist/session/tab-store.d.ts +0 -28
  196. package/dist/session/tab-store.js +0 -78
  197. package/dist/session/tool-classifier.d.ts +0 -4
  198. package/dist/session/tool-classifier.js +0 -56
  199. package/dist/tasks/scheduler.d.ts +0 -45
  200. package/dist/tasks/scheduler.js +0 -329
  201. package/dist/tasks/store.d.ts +0 -11
  202. package/dist/tasks/store.js +0 -103
  203. package/dist/timeline/index.d.ts +0 -3
  204. package/dist/timeline/index.js +0 -2
  205. package/dist/timeline/logger.d.ts +0 -8
  206. package/dist/timeline/logger.js +0 -11
  207. package/dist/timeline/query.d.ts +0 -11
  208. package/dist/timeline/query.js +0 -67
  209. package/dist/timeline/types.d.ts +0 -12
  210. package/dist/timeline/types.js +0 -1
  211. package/dist/types.d.ts +0 -225
  212. package/dist/types.js +0 -3
  213. package/dist/users/index.d.ts +0 -2
  214. package/dist/users/index.js +0 -1
  215. package/dist/users/service.d.ts +0 -17
  216. package/dist/users/service.js +0 -46
  217. package/dist/util/auto-heal.d.ts +0 -43
  218. package/dist/util/auto-heal.js +0 -107
  219. package/dist/util/install-info.d.ts +0 -37
  220. package/dist/util/install-info.js +0 -80
  221. package/dist/util/logger.d.ts +0 -18
  222. package/dist/util/logger.js +0 -118
  223. package/dist/util/paths.d.ts +0 -13
  224. package/dist/util/paths.js +0 -55
  225. package/dist/util/platform.d.ts +0 -2
  226. package/dist/util/platform.js +0 -11
  227. package/dist/util/progress.d.ts +0 -34
  228. package/dist/util/progress.js +0 -133
  229. package/dist/util/rate-limiter.d.ts +0 -14
  230. package/dist/util/rate-limiter.js +0 -50
  231. package/dist/util/retry.d.ts +0 -2
  232. package/dist/util/retry.js +0 -18
  233. package/dist/util/text.d.ts +0 -32
  234. package/dist/util/text.js +0 -101
  235. package/dist/version.d.ts +0 -1
  236. package/dist/version.js +0 -4
  237. package/dist/voice/index.d.ts +0 -17
  238. package/dist/voice/index.js +0 -42
  239. package/dist/voice/stt.d.ts +0 -16
  240. package/dist/voice/stt.js +0 -57
  241. package/dist/voice/tts.d.ts +0 -23
  242. package/dist/voice/tts.js +0 -84
  243. package/dist/watchers/evaluator.d.ts +0 -5
  244. package/dist/watchers/evaluator.js +0 -45
  245. package/dist/watchers/index.d.ts +0 -4
  246. package/dist/watchers/index.js +0 -3
  247. package/dist/watchers/scheduler.d.ts +0 -20
  248. package/dist/watchers/scheduler.js +0 -183
  249. package/dist/watchers/store.d.ts +0 -10
  250. package/dist/watchers/store.js +0 -56
  251. package/dist/watchers/types.d.ts +0 -15
  252. package/dist/watchers/types.js +0 -1
  253. package/scripts/postinstall.mjs +0 -50
@@ -1,323 +0,0 @@
1
- /*
2
- * WhatsApp integration via @whiskeysockets/baileys.
3
- *
4
- * baileys is a peer-optional dependency loaded by dynamic import, and its
5
- * runtime types are intentionally loose (the lib uses heavy union/index
6
- * types that don't survive serialization across the dynamic-import boundary).
7
- * Trying to type every variant of Baileys' message/connection shapes would
8
- * either pull baileys into the static graph (bloating non-WhatsApp installs)
9
- * or require maintaining a parallel shim. We accept `any` at this trust
10
- * boundary; runtime validation lives in the descriptors table inside
11
- * messages.upsert.
12
- */
13
- /* eslint-disable @typescript-eslint/no-explicit-any */
14
- import fs from 'node:fs';
15
- import { logger } from '../util/logger.js';
16
- import { saveMedia, isOversized } from '../media/store.js';
17
- import { sendChunkedResponse } from './send-helpers.js';
18
- import { inboundLimiter } from '../util/rate-limiter.js';
19
- import { processInboundMessage } from './pipeline.js';
20
- import { isChannelAdmin } from './admin.js';
21
- import { VoiceState } from './voice-state.js';
22
- const WHATSAPP_MAX_LENGTH = 8192;
23
- export class WhatsAppChannel {
24
- id = 'whatsapp';
25
- name = 'WhatsApp';
26
- maxMessageLength = WHATSAPP_MAX_LENGTH;
27
- sock = null;
28
- ctx;
29
- allowedNumbers;
30
- reconnectAttempts = 0;
31
- maxReconnectAttempts = 10;
32
- backoffDelays = [1000, 5000, 15000, 30000, 60000];
33
- voice = new VoiceState('whatsapp');
34
- constructor(ctx) {
35
- this.ctx = ctx;
36
- this.allowedNumbers = new Set(ctx.config.whatsapp?.allowedNumbers ?? []);
37
- }
38
- /**
39
- * Schedule the next reconnect with exponential backoff. Unlike the previous
40
- * inline setTimeout, this path retries when `start()` itself rejects (auth
41
- * failure, baileys init throw, etc.) instead of going permanently silent
42
- * after a single failed attempt.
43
- */
44
- scheduleReconnect() {
45
- this.reconnectAttempts++;
46
- if (this.reconnectAttempts > this.maxReconnectAttempts) {
47
- logger.error(`WhatsApp reconnect failed after ${this.maxReconnectAttempts} attempts, giving up`);
48
- this.ctx
49
- .notifyCallback?.('⚠️ WhatsApp disconnected after 10 reconnection attempts. Restart daemon to reconnect.')
50
- .catch((err) => logger.error('Failed to send WhatsApp disconnect notification:', err));
51
- return;
52
- }
53
- const delayIdx = Math.min(this.reconnectAttempts - 1, this.backoffDelays.length - 1);
54
- const delay = this.backoffDelays[delayIdx];
55
- logger.warn(`WhatsApp connection closed, reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
56
- setTimeout(() => {
57
- this.start().catch((err) => {
58
- logger.error('WhatsApp reconnect attempt failed:', err);
59
- // Recurse via scheduleReconnect so backoff keeps escalating instead of
60
- // silently dropping the reconnect chain after one failed start().
61
- this.scheduleReconnect();
62
- });
63
- }, delay);
64
- }
65
- async start() {
66
- // Initialize voice providers (STT + TTS)
67
- this.voice.init(this.ctx.config);
68
- try {
69
- const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, downloadMediaMessage, fetchLatestBaileysVersion, } = await import('@whiskeysockets/baileys');
70
- const { getWhatsappSessionPath } = await import('../util/paths.js');
71
- // Use the centralized path helper — the previous fallback hard-coded
72
- // process.env.HOME which bypassed BEECORK_HOME for tests/isolation.
73
- const sessionPath = this.ctx.config.whatsapp?.sessionPath ?? getWhatsappSessionPath();
74
- fs.mkdirSync(sessionPath, { recursive: true, mode: 0o700 });
75
- const { state, saveCreds } = await useMultiFileAuthState(sessionPath);
76
- const { version } = await fetchLatestBaileysVersion().catch(() => ({ version: undefined }));
77
- const pino = (await import('pino')).default;
78
- this.sock = makeWASocket({
79
- auth: state,
80
- version,
81
- logger: pino({ level: 'silent' }),
82
- });
83
- const sock = this.sock;
84
- sock.ev.on('creds.update', saveCreds);
85
- sock.ev.on('connection.update', async (update) => {
86
- const { connection, lastDisconnect, qr } = update;
87
- if (qr) {
88
- try {
89
- const qrcodeTerminal = await import('qrcode-terminal');
90
- (qrcodeTerminal.default || qrcodeTerminal).generate(qr, { small: true });
91
- logger.info('WhatsApp QR code displayed — scan with your phone');
92
- }
93
- catch {
94
- logger.warn('WhatsApp QR code available but could not render. Install qrcode-terminal.');
95
- }
96
- }
97
- if (connection === 'close') {
98
- const reason = lastDisconnect?.error?.output?.statusCode;
99
- if (reason !== DisconnectReason.loggedOut) {
100
- this.scheduleReconnect();
101
- }
102
- else {
103
- logger.error('WhatsApp logged out. Please re-scan QR code.');
104
- }
105
- }
106
- else if (connection === 'open') {
107
- this.reconnectAttempts = 0;
108
- logger.info('WhatsApp connected');
109
- }
110
- });
111
- sock.ev.on('messages.upsert', async (m) => {
112
- const msg = m.messages[0];
113
- if (!msg?.message || msg.key.fromMe)
114
- return;
115
- const sender = msg.key.remoteJid;
116
- if (!sender || !this.isAllowed(sender))
117
- return;
118
- // Rate limit check
119
- if (!inboundLimiter.check(this.id)) {
120
- await sock
121
- .sendMessage(sender, {
122
- text: "I'm receiving too many messages right now. Please wait a moment.",
123
- })
124
- .catch(() => { });
125
- return;
126
- }
127
- const text = msg.message.conversation ||
128
- msg.message.extendedTextMessage?.text ||
129
- msg.message.imageMessage?.caption ||
130
- msg.message.videoMessage?.caption ||
131
- '';
132
- const descriptors = [
133
- {
134
- key: 'imageMessage',
135
- build: (m, buf) => ({
136
- type: 'image',
137
- mimeType: m.imageMessage.mimetype || 'image/jpeg',
138
- filePath: saveMedia(buf, 'jpg'),
139
- }),
140
- },
141
- {
142
- key: 'audioMessage',
143
- build: (m, buf) => {
144
- const ext = m.audioMessage.ptt ? 'ogg' : 'mp3';
145
- return {
146
- type: m.audioMessage.ptt ? 'voice' : 'audio',
147
- mimeType: m.audioMessage.mimetype || 'audio/ogg',
148
- filePath: saveMedia(buf, ext),
149
- duration: m.audioMessage.seconds ?? undefined,
150
- };
151
- },
152
- },
153
- {
154
- key: 'documentMessage',
155
- build: (m, buf) => {
156
- const ext = m.documentMessage.fileName?.split('.').pop() || 'bin';
157
- return {
158
- type: 'document',
159
- mimeType: m.documentMessage.mimetype || 'application/octet-stream',
160
- filePath: saveMedia(buf, ext, m.documentMessage.fileName ?? undefined),
161
- fileName: m.documentMessage.fileName ?? undefined,
162
- };
163
- },
164
- },
165
- {
166
- key: 'videoMessage',
167
- build: (m, buf) => ({
168
- type: 'video',
169
- mimeType: m.videoMessage.mimetype || 'video/mp4',
170
- filePath: saveMedia(buf, 'mp4'),
171
- duration: m.videoMessage.seconds ?? undefined,
172
- }),
173
- },
174
- ];
175
- const waDownloadTasks = [];
176
- for (const d of descriptors) {
177
- if (!msg.message[d.key])
178
- continue;
179
- waDownloadTasks.push(downloadMediaMessage(msg, 'buffer', {})
180
- .then((buffer) => {
181
- if (!buffer || isOversized(buffer.length))
182
- return null;
183
- try {
184
- return d.build(msg.message, buffer);
185
- }
186
- catch {
187
- return null;
188
- }
189
- })
190
- .catch(() => null));
191
- }
192
- const waResults = await Promise.allSettled(waDownloadTasks);
193
- const media = waResults
194
- .filter((r) => r.status === 'fulfilled' && r.value !== null)
195
- .map((r) => r.value);
196
- // Transcribe voice messages if STT is configured
197
- await this.voice.transcribe(media);
198
- if (!text && media.length === 0)
199
- return;
200
- try {
201
- const waUserId = sender.replace('@s.whatsapp.net', '');
202
- // Shared command handler (covers /tabs, /stop, /projects, /project, /newproject, /close, /fresh, etc.)
203
- if (text.startsWith('/')) {
204
- const { handleSharedCommand } = await import('./command-handler.js');
205
- const cmdResult = await handleSharedCommand({
206
- userId: waUserId,
207
- text,
208
- isAdmin: isChannelAdmin(this.allowedNumbers, waUserId, this.ctx.config.whatsapp?.adminNumber),
209
- channelId: 'whatsapp',
210
- }, this.ctx.tabManager);
211
- if (cmdResult.handled) {
212
- if (cmdResult.response)
213
- await sock.sendMessage(sender, { text: cmdResult.response });
214
- return;
215
- }
216
- }
217
- await sock.sendPresenceUpdate('composing', sender).catch(() => { });
218
- // Shared message pipeline
219
- const pipelineResult = await processInboundMessage({
220
- text,
221
- media,
222
- channelId: 'whatsapp',
223
- tabManager: this.ctx.tabManager,
224
- voiceReplyMode: this.ctx.config.voice?.replyMode,
225
- ttsProvider: this.voice.tts,
226
- userId: waUserId,
227
- sendProgress: (msg) => {
228
- sock.sendMessage(sender, { text: msg }).catch(() => { });
229
- },
230
- });
231
- await sock.sendPresenceUpdate('paused', sender).catch(() => { });
232
- // Empty result means no prompt and no media
233
- if (!pipelineResult.responseText)
234
- return;
235
- // Send voice reply if TTS generated audio
236
- if (pipelineResult.audioPath) {
237
- await sock.sendMessage(sender, {
238
- audio: { url: pipelineResult.audioPath },
239
- mimetype: 'audio/ogg; codecs=opus',
240
- ptt: true,
241
- });
242
- if (pipelineResult.voiceOnly)
243
- return;
244
- }
245
- await this.sendResponse(sender, pipelineResult.responseText, pipelineResult.tabName);
246
- }
247
- catch (err) {
248
- logger.error('WhatsApp message handler error:', err);
249
- await sock
250
- .sendMessage(sender, {
251
- text: 'Something went wrong processing your message. Check daemon logs for details.',
252
- })
253
- .catch((sendErr) => logger.error('WhatsApp: failed to send fallback error message:', sendErr));
254
- }
255
- });
256
- }
257
- catch (err) {
258
- logger.error('Failed to start WhatsApp client:', err);
259
- throw err;
260
- }
261
- }
262
- stop() {
263
- const sock = this.sock;
264
- if (sock) {
265
- sock.end(undefined);
266
- this.sock = null;
267
- }
268
- logger.info('WhatsApp client stopped');
269
- }
270
- async sendMessage(peerId, text, _options) {
271
- const sock = this.sock;
272
- if (!sock)
273
- return;
274
- await sendChunkedResponse({
275
- text,
276
- maxLength: WHATSAPP_MAX_LENGTH,
277
- retryLabel: 'whatsapp-send',
278
- sendChunk: (chunk) => sock.sendMessage(peerId, { text: chunk }),
279
- });
280
- }
281
- async sendNotification(message, _urgent) {
282
- const sock = this.sock;
283
- if (!sock)
284
- return;
285
- for (const number of this.allowedNumbers) {
286
- try {
287
- await sock.sendMessage(`${number}@s.whatsapp.net`, { text: message });
288
- }
289
- catch (err) {
290
- logger.error(`Failed to send WhatsApp notification to ${number}:`, err);
291
- }
292
- }
293
- }
294
- async setTyping(peerId, active) {
295
- const sock = this.sock;
296
- if (!sock)
297
- return;
298
- const status = active ? 'composing' : 'paused';
299
- await sock.sendPresenceUpdate(status, peerId).catch(() => { });
300
- }
301
- // ─── Private ───
302
- async sendResponse(jid, text, tabName) {
303
- const sock = this.sock;
304
- try {
305
- await sendChunkedResponse({
306
- text,
307
- tabName,
308
- maxLength: WHATSAPP_MAX_LENGTH,
309
- retryLabel: 'whatsapp-send',
310
- sendChunk: (chunk) => sock.sendMessage(jid, { text: chunk }),
311
- });
312
- }
313
- catch (err) {
314
- logger.error(`WhatsApp delivery failed for ${jid}:`, err);
315
- }
316
- }
317
- isAllowed(jid) {
318
- if (this.allowedNumbers.size === 0)
319
- return false;
320
- const number = jid.replace('@s.whatsapp.net', '');
321
- return this.allowedNumbers.has(number);
322
- }
323
- }
@@ -1,3 +0,0 @@
1
- export declare function enableCapability(packId: string): Promise<void>;
2
- export declare function listCapabilities(): Promise<void>;
3
- export declare function disableCapability(packId: string): Promise<void>;
@@ -1,72 +0,0 @@
1
- import readline from 'node:readline';
2
- function ask(rl, question, defaultValue) {
3
- const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
4
- return new Promise((r) => rl.question(prompt, (a) => r(a.trim() || defaultValue || '')));
5
- }
6
- export async function enableCapability(packId) {
7
- const { getAvailablePacks, isEnabled, enablePack } = await import('../capabilities/index.js');
8
- const packs = getAvailablePacks();
9
- const pack = packs.find((p) => p.id === packId);
10
- if (!pack) {
11
- console.log(`Unknown capability: "${packId}"`);
12
- console.log('Available: ' + packs.map((p) => p.id).join(', '));
13
- return;
14
- }
15
- if (isEnabled(packId)) {
16
- console.log(`${pack.name} is already enabled. Re-configuring...`);
17
- }
18
- console.log(`\n${pack.name}`);
19
- console.log(` ${pack.description}\n`);
20
- let apiKey;
21
- if (pack.requiresApiKey) {
22
- if (pack.setupUrl) {
23
- console.log(` Setup guide: ${pack.setupUrl}\n`);
24
- }
25
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
26
- apiKey = await ask(rl, ` ${pack.apiKeyHint || 'API key'}`);
27
- rl.close();
28
- if (!apiKey) {
29
- console.log(' No API key provided. Cancelled.');
30
- return;
31
- }
32
- }
33
- enablePack(packId, apiKey);
34
- console.log(`\n✓ ${pack.name} enabled.`);
35
- console.log(' Restart daemon to activate: beecork stop && beecork start\n');
36
- }
37
- export async function listCapabilities() {
38
- const { getAvailablePacks, isEnabled } = await import('../capabilities/index.js');
39
- const packs = getAvailablePacks();
40
- console.log('\nCapabilities:\n');
41
- const categories = ['productivity', 'development', 'data', 'web'];
42
- const categoryNames = {
43
- productivity: 'Productivity',
44
- development: 'Development',
45
- data: 'Data',
46
- web: 'Web',
47
- };
48
- for (const category of categories) {
49
- const categoryPacks = packs.filter((p) => p.category === category);
50
- if (categoryPacks.length === 0)
51
- continue;
52
- console.log(` ${categoryNames[category]}:`);
53
- for (const pack of categoryPacks) {
54
- const status = isEnabled(pack.id) ? '✓' : '○';
55
- const keyNeeded = pack.requiresApiKey ? ' (needs API key)' : '';
56
- console.log(` ${status} ${pack.id} — ${pack.name}${keyNeeded}`);
57
- }
58
- console.log('');
59
- }
60
- console.log(' Enable: beecork enable <name>');
61
- console.log(' Example: beecork enable github\n');
62
- }
63
- export async function disableCapability(packId) {
64
- const { disablePack, isEnabled } = await import('../capabilities/index.js');
65
- if (!isEnabled(packId)) {
66
- console.log(`${packId} is not enabled.`);
67
- return;
68
- }
69
- disablePack(packId);
70
- console.log(`\n✓ ${packId} disabled.`);
71
- console.log(' Restart daemon to apply: beecork stop && beecork start\n');
72
- }
@@ -1,3 +0,0 @@
1
- export declare function channelInstall(packageName: string): void;
2
- export declare function channelCreate(name: string): void;
3
- export declare function channelList(): void;
@@ -1,202 +0,0 @@
1
- import { execFileSync } from 'node:child_process';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- const CHANNEL_PREFIX = 'beecork-channel-';
5
- const SAFE_NPM_PACKAGE = /^[@a-zA-Z0-9_/.-]+$/;
6
- export function channelInstall(packageName) {
7
- // Normalize name
8
- const fullName = packageName.startsWith(CHANNEL_PREFIX)
9
- ? packageName
10
- : `${CHANNEL_PREFIX}${packageName}`;
11
- if (!SAFE_NPM_PACKAGE.test(fullName)) {
12
- console.error(`Invalid package name: ${fullName}`);
13
- process.exit(1);
14
- }
15
- console.log(`Installing channel: ${fullName}...`);
16
- try {
17
- execFileSync('npm', ['install', '-g', fullName], { stdio: 'inherit' });
18
- console.log(`\nChannel "${fullName}" installed.`);
19
- console.log('Restart the daemon to activate: beecork stop && beecork start');
20
- }
21
- catch {
22
- console.error(`Failed to install ${fullName}. Check the package name and try again.`);
23
- process.exit(1);
24
- }
25
- }
26
- export function channelCreate(name) {
27
- const pkgName = `${CHANNEL_PREFIX}${name}`;
28
- const dir = pkgName;
29
- if (fs.existsSync(dir)) {
30
- console.error(`Directory "${dir}" already exists.`);
31
- process.exit(1);
32
- }
33
- fs.mkdirSync(dir, { recursive: true });
34
- fs.mkdirSync(path.join(dir, 'src'), { recursive: true });
35
- // package.json
36
- fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
37
- name: pkgName,
38
- version: '0.1.0',
39
- description: `Beecork channel: ${name}`,
40
- main: 'dist/index.js',
41
- type: 'module',
42
- scripts: {
43
- build: 'tsc',
44
- dev: 'tsc --watch',
45
- },
46
- keywords: ['beecork', 'beecork-channel', name],
47
- peerDependencies: {
48
- beecork: '>=0.4.0',
49
- },
50
- devDependencies: {
51
- typescript: '^5.7.0',
52
- '@types/node': '^22.0.0',
53
- },
54
- }, null, 2) + '\n');
55
- // tsconfig.json
56
- fs.writeFileSync(path.join(dir, 'tsconfig.json'), JSON.stringify({
57
- compilerOptions: {
58
- target: 'ES2022',
59
- module: 'NodeNext',
60
- moduleResolution: 'NodeNext',
61
- outDir: 'dist',
62
- rootDir: 'src',
63
- strict: true,
64
- esModuleInterop: true,
65
- declaration: true,
66
- },
67
- include: ['src'],
68
- }, null, 2) + '\n');
69
- // Main source file
70
- const className = name.charAt(0).toUpperCase() + name.slice(1);
71
- fs.writeFileSync(path.join(dir, 'src', 'index.ts'), `// ${pkgName} — Beecork channel implementation
72
- // See: https://github.com/beecork/beecork for Channel interface docs
73
-
74
- // Import the Channel interface type from beecork
75
- // Note: beecork is a peer dependency
76
- interface Channel {
77
- readonly id: string;
78
- readonly name: string;
79
- readonly maxMessageLength: number;
80
- readonly supportsStreaming: boolean;
81
- readonly supportsMedia: boolean;
82
- start(): Promise<void>;
83
- stop(): void;
84
- sendMessage(peerId: string, text: string): Promise<void>;
85
- sendNotification(message: string, urgent?: boolean): Promise<void>;
86
- setTyping(peerId: string, active: boolean): Promise<void>;
87
- onMessage(handler: (msg: any) => Promise<void>): void;
88
- }
89
-
90
- interface ChannelContext {
91
- config: any;
92
- tabManager: any;
93
- }
94
-
95
- export default class ${className}Channel implements Channel {
96
- readonly id = '${name}';
97
- readonly name = '${className}';
98
- readonly maxMessageLength = 4096;
99
- readonly supportsStreaming = false;
100
- readonly supportsMedia = false;
101
-
102
- private ctx: ChannelContext;
103
- private handler: ((msg: any) => Promise<void>) | null = null;
104
-
105
- constructor(ctx: ChannelContext) {
106
- this.ctx = ctx;
107
- }
108
-
109
- async start(): Promise<void> {
110
- // TODO: Connect to your service, start polling/websocket
111
- console.log(\`${name} channel started\`);
112
- }
113
-
114
- stop(): void {
115
- // TODO: Disconnect, cleanup
116
- console.log(\`${name} channel stopped\`);
117
- }
118
-
119
- onMessage(handler: (msg: any) => Promise<void>): void {
120
- this.handler = handler;
121
- }
122
-
123
- async sendMessage(peerId: string, text: string): Promise<void> {
124
- // TODO: Send a message to the user
125
- }
126
-
127
- async sendNotification(message: string, urgent?: boolean): Promise<void> {
128
- // TODO: Send a notification to all configured users
129
- }
130
-
131
- async setTyping(peerId: string, active: boolean): Promise<void> {
132
- // TODO: Show typing indicator
133
- }
134
- }
135
- `);
136
- // README
137
- fs.writeFileSync(path.join(dir, 'README.md'), `# ${pkgName}
138
-
139
- A Beecork channel plugin for ${name}.
140
-
141
- ## Installation
142
-
143
- \`\`\`bash
144
- beecork channel install ${name}
145
- # or: npm install -g ${pkgName}
146
- \`\`\`
147
-
148
- ## Configuration
149
-
150
- Add to your \`~/.beecork/config.json\`:
151
-
152
- \`\`\`json
153
- {
154
- "${name}": {
155
- "enabled": true
156
- }
157
- }
158
- \`\`\`
159
-
160
- ## Development
161
-
162
- \`\`\`bash
163
- npm install
164
- npm run build
165
- \`\`\`
166
-
167
- ## Publishing
168
-
169
- \`\`\`bash
170
- npm publish
171
- \`\`\`
172
- `);
173
- console.log(`\nChannel scaffold created: ${dir}/`);
174
- console.log(`\nNext steps:`);
175
- console.log(` cd ${dir}`);
176
- console.log(` npm install`);
177
- console.log(` # Edit src/index.ts to implement your channel`);
178
- console.log(` npm run build`);
179
- console.log(` npm publish`);
180
- }
181
- export function channelList() {
182
- try {
183
- const output = execFileSync('npm', ['list', '-g', '--depth=0'], {
184
- encoding: 'utf-8',
185
- stdio: ['pipe', 'pipe', 'pipe'],
186
- });
187
- const lines = output.split('\n').filter((line) => line.includes(CHANNEL_PREFIX));
188
- if (lines.length === 0) {
189
- console.log('No community channels installed.');
190
- console.log(`Install one: beecork channel install <name>`);
191
- return;
192
- }
193
- console.log(`\n${lines.length} community channel(s):\n`);
194
- for (const line of lines) {
195
- console.log(` ${line.trim()}`);
196
- }
197
- console.log('');
198
- }
199
- catch {
200
- console.log('No community channels installed.');
201
- }
202
- }
@@ -1,15 +0,0 @@
1
- export declare function startDaemon(): Promise<void>;
2
- export declare function stopDaemon(): Promise<void>;
3
- export declare function showStatus(): Promise<void>;
4
- export declare function listTabs(): Promise<void>;
5
- export declare function tailLogs(tabName?: string): Promise<void>;
6
- export declare function listCrons(): Promise<void>;
7
- export declare function deleteCron(id: string): Promise<void>;
8
- export declare function listWatchers(): Promise<void>;
9
- export declare function deleteWatcher(id: string): Promise<void>;
10
- export declare function listMemories(): Promise<void>;
11
- export declare function deleteMemory(id: string): Promise<void>;
12
- export declare function updateBeecork(options: {
13
- check?: boolean;
14
- }): Promise<void>;
15
- export declare function sendMessage(message: string): Promise<void>;