whale-code 6.4.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 (319) hide show
  1. package/README.md +95 -0
  2. package/bin/swag-agent.js +9 -0
  3. package/bin/swagmanager-mcp.js +321 -0
  4. package/dist/cli/app.d.ts +26 -0
  5. package/dist/cli/app.js +64 -0
  6. package/dist/cli/chat/AgentSelector.d.ts +14 -0
  7. package/dist/cli/chat/AgentSelector.js +14 -0
  8. package/dist/cli/chat/ChatApp.d.ts +9 -0
  9. package/dist/cli/chat/ChatApp.js +267 -0
  10. package/dist/cli/chat/ChatInput.d.ts +39 -0
  11. package/dist/cli/chat/ChatInput.js +509 -0
  12. package/dist/cli/chat/MarkdownText.d.ts +10 -0
  13. package/dist/cli/chat/MarkdownText.js +20 -0
  14. package/dist/cli/chat/MessageList.d.ts +37 -0
  15. package/dist/cli/chat/MessageList.js +80 -0
  16. package/dist/cli/chat/ModelSelector.d.ts +20 -0
  17. package/dist/cli/chat/ModelSelector.js +73 -0
  18. package/dist/cli/chat/RewindViewer.d.ts +26 -0
  19. package/dist/cli/chat/RewindViewer.js +185 -0
  20. package/dist/cli/chat/StoreSelector.d.ts +14 -0
  21. package/dist/cli/chat/StoreSelector.js +24 -0
  22. package/dist/cli/chat/StreamingText.d.ts +12 -0
  23. package/dist/cli/chat/StreamingText.js +12 -0
  24. package/dist/cli/chat/SubagentPanel.d.ts +45 -0
  25. package/dist/cli/chat/SubagentPanel.js +110 -0
  26. package/dist/cli/chat/TeamPanel.d.ts +21 -0
  27. package/dist/cli/chat/TeamPanel.js +42 -0
  28. package/dist/cli/chat/ToolIndicator.d.ts +25 -0
  29. package/dist/cli/chat/ToolIndicator.js +436 -0
  30. package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
  31. package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
  32. package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
  33. package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
  34. package/dist/cli/commands/config-cmd.d.ts +10 -0
  35. package/dist/cli/commands/config-cmd.js +99 -0
  36. package/dist/cli/commands/doctor.d.ts +14 -0
  37. package/dist/cli/commands/doctor.js +172 -0
  38. package/dist/cli/commands/init.d.ts +16 -0
  39. package/dist/cli/commands/init.js +278 -0
  40. package/dist/cli/commands/mcp.d.ts +12 -0
  41. package/dist/cli/commands/mcp.js +162 -0
  42. package/dist/cli/login/LoginApp.d.ts +7 -0
  43. package/dist/cli/login/LoginApp.js +157 -0
  44. package/dist/cli/print-mode.d.ts +31 -0
  45. package/dist/cli/print-mode.js +202 -0
  46. package/dist/cli/serve-mode.d.ts +37 -0
  47. package/dist/cli/serve-mode.js +636 -0
  48. package/dist/cli/services/agent-definitions.d.ts +25 -0
  49. package/dist/cli/services/agent-definitions.js +91 -0
  50. package/dist/cli/services/agent-events.d.ts +178 -0
  51. package/dist/cli/services/agent-events.js +175 -0
  52. package/dist/cli/services/agent-loop.d.ts +90 -0
  53. package/dist/cli/services/agent-loop.js +762 -0
  54. package/dist/cli/services/agent-worker-base.d.ts +97 -0
  55. package/dist/cli/services/agent-worker-base.js +220 -0
  56. package/dist/cli/services/auth-service.d.ts +30 -0
  57. package/dist/cli/services/auth-service.js +160 -0
  58. package/dist/cli/services/background-processes.d.ts +126 -0
  59. package/dist/cli/services/background-processes.js +318 -0
  60. package/dist/cli/services/browser-auth.d.ts +24 -0
  61. package/dist/cli/services/browser-auth.js +180 -0
  62. package/dist/cli/services/claude-md-loader.d.ts +16 -0
  63. package/dist/cli/services/claude-md-loader.js +58 -0
  64. package/dist/cli/services/config-store.d.ts +47 -0
  65. package/dist/cli/services/config-store.js +79 -0
  66. package/dist/cli/services/debug-log.d.ts +10 -0
  67. package/dist/cli/services/debug-log.js +52 -0
  68. package/dist/cli/services/error-logger.d.ts +58 -0
  69. package/dist/cli/services/error-logger.js +269 -0
  70. package/dist/cli/services/file-history.d.ts +21 -0
  71. package/dist/cli/services/file-history.js +83 -0
  72. package/dist/cli/services/format-server-response.d.ts +16 -0
  73. package/dist/cli/services/format-server-response.js +440 -0
  74. package/dist/cli/services/git-context.d.ts +11 -0
  75. package/dist/cli/services/git-context.js +66 -0
  76. package/dist/cli/services/hooks.d.ts +85 -0
  77. package/dist/cli/services/hooks.js +258 -0
  78. package/dist/cli/services/interactive-tools.d.ts +125 -0
  79. package/dist/cli/services/interactive-tools.js +260 -0
  80. package/dist/cli/services/keybinding-manager.d.ts +52 -0
  81. package/dist/cli/services/keybinding-manager.js +115 -0
  82. package/dist/cli/services/local-tools.d.ts +22 -0
  83. package/dist/cli/services/local-tools.js +697 -0
  84. package/dist/cli/services/lsp-manager.d.ts +18 -0
  85. package/dist/cli/services/lsp-manager.js +717 -0
  86. package/dist/cli/services/mcp-client.d.ts +48 -0
  87. package/dist/cli/services/mcp-client.js +157 -0
  88. package/dist/cli/services/memory-manager.d.ts +16 -0
  89. package/dist/cli/services/memory-manager.js +57 -0
  90. package/dist/cli/services/model-manager.d.ts +18 -0
  91. package/dist/cli/services/model-manager.js +71 -0
  92. package/dist/cli/services/model-router.d.ts +26 -0
  93. package/dist/cli/services/model-router.js +149 -0
  94. package/dist/cli/services/permission-modes.d.ts +13 -0
  95. package/dist/cli/services/permission-modes.js +43 -0
  96. package/dist/cli/services/rewind.d.ts +84 -0
  97. package/dist/cli/services/rewind.js +194 -0
  98. package/dist/cli/services/ripgrep.d.ts +28 -0
  99. package/dist/cli/services/ripgrep.js +138 -0
  100. package/dist/cli/services/sandbox.d.ts +29 -0
  101. package/dist/cli/services/sandbox.js +97 -0
  102. package/dist/cli/services/server-tools.d.ts +61 -0
  103. package/dist/cli/services/server-tools.js +543 -0
  104. package/dist/cli/services/session-persistence.d.ts +23 -0
  105. package/dist/cli/services/session-persistence.js +99 -0
  106. package/dist/cli/services/subagent-worker.d.ts +19 -0
  107. package/dist/cli/services/subagent-worker.js +41 -0
  108. package/dist/cli/services/subagent.d.ts +47 -0
  109. package/dist/cli/services/subagent.js +647 -0
  110. package/dist/cli/services/system-prompt.d.ts +7 -0
  111. package/dist/cli/services/system-prompt.js +198 -0
  112. package/dist/cli/services/team-lead.d.ts +73 -0
  113. package/dist/cli/services/team-lead.js +512 -0
  114. package/dist/cli/services/team-state.d.ts +77 -0
  115. package/dist/cli/services/team-state.js +398 -0
  116. package/dist/cli/services/teammate.d.ts +31 -0
  117. package/dist/cli/services/teammate.js +689 -0
  118. package/dist/cli/services/telemetry.d.ts +61 -0
  119. package/dist/cli/services/telemetry.js +209 -0
  120. package/dist/cli/services/tools/agent-tools.d.ts +14 -0
  121. package/dist/cli/services/tools/agent-tools.js +347 -0
  122. package/dist/cli/services/tools/file-ops.d.ts +15 -0
  123. package/dist/cli/services/tools/file-ops.js +487 -0
  124. package/dist/cli/services/tools/search-tools.d.ts +8 -0
  125. package/dist/cli/services/tools/search-tools.js +186 -0
  126. package/dist/cli/services/tools/shell-exec.d.ts +10 -0
  127. package/dist/cli/services/tools/shell-exec.js +168 -0
  128. package/dist/cli/services/tools/task-manager.d.ts +28 -0
  129. package/dist/cli/services/tools/task-manager.js +209 -0
  130. package/dist/cli/services/tools/web-tools.d.ts +11 -0
  131. package/dist/cli/services/tools/web-tools.js +395 -0
  132. package/dist/cli/setup/SetupApp.d.ts +9 -0
  133. package/dist/cli/setup/SetupApp.js +191 -0
  134. package/dist/cli/shared/MatrixIntro.d.ts +4 -0
  135. package/dist/cli/shared/MatrixIntro.js +83 -0
  136. package/dist/cli/shared/Theme.d.ts +74 -0
  137. package/dist/cli/shared/Theme.js +127 -0
  138. package/dist/cli/shared/WhaleBanner.d.ts +10 -0
  139. package/dist/cli/shared/WhaleBanner.js +12 -0
  140. package/dist/cli/shared/markdown.d.ts +21 -0
  141. package/dist/cli/shared/markdown.js +756 -0
  142. package/dist/cli/status/StatusApp.d.ts +4 -0
  143. package/dist/cli/status/StatusApp.js +105 -0
  144. package/dist/cli/stores/StoreApp.d.ts +7 -0
  145. package/dist/cli/stores/StoreApp.js +81 -0
  146. package/dist/index.d.ts +15 -0
  147. package/dist/index.js +538 -0
  148. package/dist/local-agent/connection.d.ts +48 -0
  149. package/dist/local-agent/connection.js +332 -0
  150. package/dist/local-agent/discovery.d.ts +18 -0
  151. package/dist/local-agent/discovery.js +146 -0
  152. package/dist/local-agent/executor.d.ts +34 -0
  153. package/dist/local-agent/executor.js +241 -0
  154. package/dist/local-agent/index.d.ts +14 -0
  155. package/dist/local-agent/index.js +198 -0
  156. package/dist/node/adapters/base.d.ts +35 -0
  157. package/dist/node/adapters/base.js +10 -0
  158. package/dist/node/adapters/discord.d.ts +29 -0
  159. package/dist/node/adapters/discord.js +299 -0
  160. package/dist/node/adapters/email.d.ts +23 -0
  161. package/dist/node/adapters/email.js +218 -0
  162. package/dist/node/adapters/imessage.d.ts +17 -0
  163. package/dist/node/adapters/imessage.js +118 -0
  164. package/dist/node/adapters/slack.d.ts +26 -0
  165. package/dist/node/adapters/slack.js +259 -0
  166. package/dist/node/adapters/sms.d.ts +23 -0
  167. package/dist/node/adapters/sms.js +161 -0
  168. package/dist/node/adapters/telegram.d.ts +17 -0
  169. package/dist/node/adapters/telegram.js +101 -0
  170. package/dist/node/adapters/webchat.d.ts +27 -0
  171. package/dist/node/adapters/webchat.js +160 -0
  172. package/dist/node/adapters/whatsapp.d.ts +28 -0
  173. package/dist/node/adapters/whatsapp.js +230 -0
  174. package/dist/node/cli.d.ts +2 -0
  175. package/dist/node/cli.js +325 -0
  176. package/dist/node/config.d.ts +17 -0
  177. package/dist/node/config.js +31 -0
  178. package/dist/node/runtime.d.ts +50 -0
  179. package/dist/node/runtime.js +351 -0
  180. package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
  181. package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
  182. package/dist/server/handlers/analytics.d.ts +17 -0
  183. package/dist/server/handlers/analytics.js +266 -0
  184. package/dist/server/handlers/api-keys.d.ts +6 -0
  185. package/dist/server/handlers/api-keys.js +221 -0
  186. package/dist/server/handlers/billing.d.ts +33 -0
  187. package/dist/server/handlers/billing.js +272 -0
  188. package/dist/server/handlers/browser.d.ts +10 -0
  189. package/dist/server/handlers/browser.js +517 -0
  190. package/dist/server/handlers/catalog.d.ts +99 -0
  191. package/dist/server/handlers/catalog.js +976 -0
  192. package/dist/server/handlers/comms.d.ts +254 -0
  193. package/dist/server/handlers/comms.js +588 -0
  194. package/dist/server/handlers/creations.d.ts +6 -0
  195. package/dist/server/handlers/creations.js +479 -0
  196. package/dist/server/handlers/crm.d.ts +89 -0
  197. package/dist/server/handlers/crm.js +538 -0
  198. package/dist/server/handlers/discovery.d.ts +6 -0
  199. package/dist/server/handlers/discovery.js +288 -0
  200. package/dist/server/handlers/embeddings.d.ts +92 -0
  201. package/dist/server/handlers/embeddings.js +197 -0
  202. package/dist/server/handlers/enrichment.d.ts +8 -0
  203. package/dist/server/handlers/enrichment.js +768 -0
  204. package/dist/server/handlers/image-gen.d.ts +6 -0
  205. package/dist/server/handlers/image-gen.js +409 -0
  206. package/dist/server/handlers/inventory.d.ts +319 -0
  207. package/dist/server/handlers/inventory.js +447 -0
  208. package/dist/server/handlers/kali.d.ts +10 -0
  209. package/dist/server/handlers/kali.js +210 -0
  210. package/dist/server/handlers/llm-providers.d.ts +6 -0
  211. package/dist/server/handlers/llm-providers.js +673 -0
  212. package/dist/server/handlers/local-agent.d.ts +6 -0
  213. package/dist/server/handlers/local-agent.js +118 -0
  214. package/dist/server/handlers/meta-ads.d.ts +111 -0
  215. package/dist/server/handlers/meta-ads.js +2279 -0
  216. package/dist/server/handlers/nodes.d.ts +33 -0
  217. package/dist/server/handlers/nodes.js +699 -0
  218. package/dist/server/handlers/operations.d.ts +138 -0
  219. package/dist/server/handlers/operations.js +131 -0
  220. package/dist/server/handlers/platform.d.ts +23 -0
  221. package/dist/server/handlers/platform.js +227 -0
  222. package/dist/server/handlers/supply-chain.d.ts +19 -0
  223. package/dist/server/handlers/supply-chain.js +327 -0
  224. package/dist/server/handlers/transcription.d.ts +17 -0
  225. package/dist/server/handlers/transcription.js +121 -0
  226. package/dist/server/handlers/video-gen.d.ts +6 -0
  227. package/dist/server/handlers/video-gen.js +466 -0
  228. package/dist/server/handlers/voice.d.ts +8 -0
  229. package/dist/server/handlers/voice.js +1146 -0
  230. package/dist/server/handlers/workflow-steps.d.ts +86 -0
  231. package/dist/server/handlers/workflow-steps.js +2349 -0
  232. package/dist/server/handlers/workflows.d.ts +7 -0
  233. package/dist/server/handlers/workflows.js +989 -0
  234. package/dist/server/index.d.ts +1 -0
  235. package/dist/server/index.js +2427 -0
  236. package/dist/server/lib/batch-client.d.ts +80 -0
  237. package/dist/server/lib/batch-client.js +467 -0
  238. package/dist/server/lib/code-worker-pool.d.ts +31 -0
  239. package/dist/server/lib/code-worker-pool.js +224 -0
  240. package/dist/server/lib/code-worker.d.ts +1 -0
  241. package/dist/server/lib/code-worker.js +188 -0
  242. package/dist/server/lib/compaction-service.d.ts +32 -0
  243. package/dist/server/lib/compaction-service.js +162 -0
  244. package/dist/server/lib/logger.d.ts +19 -0
  245. package/dist/server/lib/logger.js +46 -0
  246. package/dist/server/lib/otel.d.ts +38 -0
  247. package/dist/server/lib/otel.js +126 -0
  248. package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
  249. package/dist/server/lib/pg-rate-limiter.js +86 -0
  250. package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
  251. package/dist/server/lib/prompt-sanitizer.js +177 -0
  252. package/dist/server/lib/provider-capabilities.d.ts +85 -0
  253. package/dist/server/lib/provider-capabilities.js +190 -0
  254. package/dist/server/lib/provider-failover.d.ts +74 -0
  255. package/dist/server/lib/provider-failover.js +210 -0
  256. package/dist/server/lib/rate-limiter.d.ts +39 -0
  257. package/dist/server/lib/rate-limiter.js +147 -0
  258. package/dist/server/lib/server-agent-loop.d.ts +107 -0
  259. package/dist/server/lib/server-agent-loop.js +667 -0
  260. package/dist/server/lib/server-subagent.d.ts +78 -0
  261. package/dist/server/lib/server-subagent.js +203 -0
  262. package/dist/server/lib/session-checkpoint.d.ts +51 -0
  263. package/dist/server/lib/session-checkpoint.js +145 -0
  264. package/dist/server/lib/ssrf-guard.d.ts +13 -0
  265. package/dist/server/lib/ssrf-guard.js +240 -0
  266. package/dist/server/lib/supabase-client.d.ts +7 -0
  267. package/dist/server/lib/supabase-client.js +78 -0
  268. package/dist/server/lib/template-resolver.d.ts +31 -0
  269. package/dist/server/lib/template-resolver.js +215 -0
  270. package/dist/server/lib/utils.d.ts +16 -0
  271. package/dist/server/lib/utils.js +147 -0
  272. package/dist/server/local-agent-gateway.d.ts +82 -0
  273. package/dist/server/local-agent-gateway.js +426 -0
  274. package/dist/server/providers/anthropic.d.ts +20 -0
  275. package/dist/server/providers/anthropic.js +199 -0
  276. package/dist/server/providers/bedrock.d.ts +20 -0
  277. package/dist/server/providers/bedrock.js +194 -0
  278. package/dist/server/providers/gemini.d.ts +24 -0
  279. package/dist/server/providers/gemini.js +486 -0
  280. package/dist/server/providers/openai.d.ts +24 -0
  281. package/dist/server/providers/openai.js +522 -0
  282. package/dist/server/providers/registry.d.ts +32 -0
  283. package/dist/server/providers/registry.js +58 -0
  284. package/dist/server/providers/shared.d.ts +32 -0
  285. package/dist/server/providers/shared.js +124 -0
  286. package/dist/server/providers/types.d.ts +92 -0
  287. package/dist/server/providers/types.js +12 -0
  288. package/dist/server/proxy-handlers.d.ts +6 -0
  289. package/dist/server/proxy-handlers.js +89 -0
  290. package/dist/server/tool-router.d.ts +149 -0
  291. package/dist/server/tool-router.js +803 -0
  292. package/dist/server/validation.d.ts +24 -0
  293. package/dist/server/validation.js +301 -0
  294. package/dist/server/worker.d.ts +19 -0
  295. package/dist/server/worker.js +201 -0
  296. package/dist/setup.d.ts +8 -0
  297. package/dist/setup.js +181 -0
  298. package/dist/shared/agent-core.d.ts +157 -0
  299. package/dist/shared/agent-core.js +534 -0
  300. package/dist/shared/anthropic-types.d.ts +105 -0
  301. package/dist/shared/anthropic-types.js +7 -0
  302. package/dist/shared/api-client.d.ts +90 -0
  303. package/dist/shared/api-client.js +379 -0
  304. package/dist/shared/constants.d.ts +33 -0
  305. package/dist/shared/constants.js +80 -0
  306. package/dist/shared/sse-parser.d.ts +26 -0
  307. package/dist/shared/sse-parser.js +259 -0
  308. package/dist/shared/tool-dispatch.d.ts +52 -0
  309. package/dist/shared/tool-dispatch.js +191 -0
  310. package/dist/shared/types.d.ts +72 -0
  311. package/dist/shared/types.js +7 -0
  312. package/dist/updater.d.ts +25 -0
  313. package/dist/updater.js +140 -0
  314. package/dist/webchat/widget.d.ts +0 -0
  315. package/dist/webchat/widget.js +397 -0
  316. package/package.json +95 -0
  317. package/src/cli/services/builtin-skills/commit.md +19 -0
  318. package/src/cli/services/builtin-skills/review-pr.md +21 -0
  319. package/src/cli/services/builtin-skills/review.md +18 -0
@@ -0,0 +1,26 @@
1
+ import { BaseAdapter, type OutboundMessage } from "./base.js";
2
+ export interface SlackConfig {
3
+ bot_token: string;
4
+ app_token: string;
5
+ allowed_channels?: string[];
6
+ mention_required?: boolean;
7
+ max_message_length?: number;
8
+ }
9
+ export declare class SlackAdapter extends BaseAdapter {
10
+ readonly type = "slack";
11
+ readonly name: string;
12
+ private config;
13
+ private ws;
14
+ private botUserId;
15
+ private reconnectAttempts;
16
+ private pingTimer;
17
+ constructor(name: string, config: SlackConfig);
18
+ start(): Promise<void>;
19
+ stop(): Promise<void>;
20
+ sendMessage(msg: OutboundMessage): Promise<boolean>;
21
+ private fetchBotIdentity;
22
+ private connectSocketMode;
23
+ private handleSocketMessage;
24
+ private handleEvent;
25
+ private scheduleReconnect;
26
+ }
@@ -0,0 +1,259 @@
1
+ import { BaseAdapter } from "./base.js";
2
+ const SLACK_API = "https://slack.com/api";
3
+ const MAX_MESSAGE_LENGTH = 4000;
4
+ export class SlackAdapter extends BaseAdapter {
5
+ type = "slack";
6
+ name;
7
+ config;
8
+ ws = null;
9
+ botUserId = null;
10
+ reconnectAttempts = 0;
11
+ pingTimer = null;
12
+ constructor(name, config) {
13
+ super();
14
+ this.name = name;
15
+ this.config = config;
16
+ }
17
+ async start() {
18
+ if (this.running)
19
+ return;
20
+ this.running = true;
21
+ this.reconnectAttempts = 0;
22
+ // Fetch bot user ID for mention filtering
23
+ await this.fetchBotIdentity();
24
+ // Connect via Socket Mode
25
+ console.log(`[slack] Connecting via Socket Mode...`);
26
+ await this.connectSocketMode();
27
+ }
28
+ async stop() {
29
+ this.running = false;
30
+ if (this.pingTimer) {
31
+ clearInterval(this.pingTimer);
32
+ this.pingTimer = null;
33
+ }
34
+ if (this.ws) {
35
+ this.ws.close(1000, "Shutting down");
36
+ this.ws = null;
37
+ }
38
+ }
39
+ async sendMessage(msg) {
40
+ try {
41
+ const channelId = msg.metadata?.channel_id || msg.conversation_id;
42
+ if (!channelId) {
43
+ console.error("[slack] No channel_id to send to");
44
+ return false;
45
+ }
46
+ const maxLen = this.config.max_message_length || MAX_MESSAGE_LENGTH;
47
+ let content = msg.content;
48
+ // Split long messages
49
+ const chunks = [];
50
+ while (content.length > 0) {
51
+ chunks.push(content.slice(0, maxLen));
52
+ content = content.slice(maxLen);
53
+ }
54
+ for (const chunk of chunks) {
55
+ const body = {
56
+ channel: channelId,
57
+ text: chunk,
58
+ };
59
+ // Thread reply if we have a thread_ts
60
+ if (msg.metadata?.thread_ts) {
61
+ body.thread_ts = msg.metadata.thread_ts;
62
+ }
63
+ const res = await fetch(`${SLACK_API}/chat.postMessage`, {
64
+ method: "POST",
65
+ headers: {
66
+ "Content-Type": "application/json; charset=utf-8",
67
+ Authorization: `Bearer ${this.config.bot_token}`,
68
+ },
69
+ body: JSON.stringify(body),
70
+ });
71
+ const data = await res.json();
72
+ if (!data.ok) {
73
+ console.error(`[slack] Send failed:`, data.error);
74
+ this.stats.errors++;
75
+ return false;
76
+ }
77
+ }
78
+ this.stats.messages_out++;
79
+ this.stats.last_message_at = new Date().toISOString();
80
+ return true;
81
+ }
82
+ catch (err) {
83
+ console.error(`[slack] Send error:`, err.message);
84
+ this.stats.errors++;
85
+ return false;
86
+ }
87
+ }
88
+ async fetchBotIdentity() {
89
+ try {
90
+ const res = await fetch(`${SLACK_API}/auth.test`, {
91
+ method: "POST",
92
+ headers: {
93
+ Authorization: `Bearer ${this.config.bot_token}`,
94
+ },
95
+ });
96
+ const data = await res.json();
97
+ if (data.ok) {
98
+ this.botUserId = data.user_id;
99
+ console.log(`[slack] Authenticated as ${data.user} (${data.user_id})`);
100
+ }
101
+ else {
102
+ console.error(`[slack] Auth failed:`, data.error);
103
+ }
104
+ }
105
+ catch (err) {
106
+ console.error(`[slack] Failed to fetch identity:`, err.message);
107
+ }
108
+ }
109
+ async connectSocketMode() {
110
+ if (!this.running)
111
+ return;
112
+ try {
113
+ // Request a WebSocket URL via apps.connections.open
114
+ const res = await fetch(`${SLACK_API}/apps.connections.open`, {
115
+ method: "POST",
116
+ headers: {
117
+ Authorization: `Bearer ${this.config.app_token}`,
118
+ },
119
+ });
120
+ const data = await res.json();
121
+ if (!data.ok) {
122
+ console.error(`[slack] Socket Mode connection failed:`, data.error);
123
+ this.scheduleReconnect();
124
+ return;
125
+ }
126
+ const wsUrl = data.url;
127
+ this.ws = new WebSocket(wsUrl);
128
+ this.ws.onopen = () => {
129
+ console.log(`[slack] Socket Mode connected`);
130
+ this.reconnectAttempts = 0;
131
+ // Ping every 30s to keep connection alive
132
+ this.pingTimer = setInterval(() => {
133
+ if (this.ws?.readyState === WebSocket.OPEN) {
134
+ this.ws.send(JSON.stringify({ type: "ping" }));
135
+ }
136
+ }, 30_000);
137
+ };
138
+ this.ws.onmessage = (event) => {
139
+ try {
140
+ const data = JSON.parse(String(event.data));
141
+ this.handleSocketMessage(data);
142
+ }
143
+ catch (err) {
144
+ console.error(`[slack] Failed to parse message:`, err.message);
145
+ }
146
+ };
147
+ this.ws.onclose = (event) => {
148
+ console.log(`[slack] Socket closed: ${event.code} ${event.reason}`);
149
+ if (this.pingTimer) {
150
+ clearInterval(this.pingTimer);
151
+ this.pingTimer = null;
152
+ }
153
+ if (this.running)
154
+ this.scheduleReconnect();
155
+ };
156
+ this.ws.onerror = () => {
157
+ console.error(`[slack] Socket error`);
158
+ };
159
+ }
160
+ catch (err) {
161
+ console.error(`[slack] Connection error:`, err.message);
162
+ this.scheduleReconnect();
163
+ }
164
+ }
165
+ handleSocketMessage(data) {
166
+ // Acknowledge envelope (required for Socket Mode)
167
+ if (data.envelope_id) {
168
+ this.ws?.send(JSON.stringify({ envelope_id: data.envelope_id }));
169
+ }
170
+ switch (data.type) {
171
+ case "hello":
172
+ console.log(`[slack] Socket Mode handshake complete`);
173
+ break;
174
+ case "disconnect":
175
+ console.log(`[slack] Server requested disconnect: ${data.reason}`);
176
+ this.ws?.close(1000, "Server disconnect");
177
+ break;
178
+ case "events_api": {
179
+ const event = data.payload?.event;
180
+ if (event) {
181
+ this.handleEvent(event).catch(err => {
182
+ console.error(`[slack] Error handling event:`, err.message);
183
+ this.stats.errors++;
184
+ });
185
+ }
186
+ break;
187
+ }
188
+ }
189
+ }
190
+ async handleEvent(event) {
191
+ // Only handle message events
192
+ if (event.type !== "message" && event.type !== "app_mention")
193
+ return;
194
+ // Ignore bot messages and message edits/deletions
195
+ if (event.bot_id || event.subtype)
196
+ return;
197
+ const channelId = event.channel;
198
+ // Filter by allowed channels
199
+ if (this.config.allowed_channels?.length) {
200
+ if (!this.config.allowed_channels.includes(channelId))
201
+ return;
202
+ }
203
+ // For regular messages, check mention requirement
204
+ if (event.type === "message" && this.config.mention_required && this.botUserId) {
205
+ const mentionPattern = `<@${this.botUserId}>`;
206
+ if (!event.text?.includes(mentionPattern))
207
+ return;
208
+ }
209
+ // Clean up content — remove bot mention
210
+ let content = event.text || "";
211
+ if (this.botUserId) {
212
+ content = content.replace(new RegExp(`<@${this.botUserId}>`, "g"), "").trim();
213
+ }
214
+ if (!content)
215
+ return;
216
+ const payload = {
217
+ sender_id: event.user || "unknown",
218
+ content,
219
+ metadata: {
220
+ channel_id: channelId,
221
+ thread_ts: event.thread_ts || event.ts, // Use thread_ts for threading, fallback to message ts
222
+ message_ts: event.ts,
223
+ team_id: event.team,
224
+ },
225
+ };
226
+ // Fetch user display name
227
+ if (event.user) {
228
+ try {
229
+ const res = await fetch(`${SLACK_API}/users.info?user=${event.user}`, {
230
+ headers: { Authorization: `Bearer ${this.config.bot_token}` },
231
+ });
232
+ const data = await res.json();
233
+ if (data.ok) {
234
+ payload.sender_name = data.user?.profile?.display_name || data.user?.real_name || data.user?.name;
235
+ }
236
+ }
237
+ catch {
238
+ // Non-critical — proceed without name
239
+ }
240
+ }
241
+ this.stats.messages_in++;
242
+ this.stats.last_message_at = new Date().toISOString();
243
+ if (this.onInboundMessage) {
244
+ await this.onInboundMessage(payload);
245
+ }
246
+ }
247
+ scheduleReconnect() {
248
+ if (!this.running)
249
+ return;
250
+ this.reconnectAttempts++;
251
+ const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 60_000);
252
+ console.log(`[slack] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})...`);
253
+ setTimeout(() => {
254
+ if (!this.running)
255
+ return;
256
+ this.connectSocketMode();
257
+ }, delay);
258
+ }
259
+ }
@@ -0,0 +1,23 @@
1
+ import { BaseAdapter, type OutboundMessage } from "./base.js";
2
+ export interface SmsConfig {
3
+ account_sid: string;
4
+ auth_token: string;
5
+ from_number: string;
6
+ webhook_port?: number;
7
+ }
8
+ export declare class SmsAdapter extends BaseAdapter {
9
+ readonly type = "sms";
10
+ readonly name: string;
11
+ private config;
12
+ private server;
13
+ private reconnectAttempts;
14
+ constructor(name: string, config: SmsConfig);
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ sendMessage(msg: OutboundMessage): Promise<boolean>;
18
+ private startWebhookServer;
19
+ /** Handle inbound Twilio SMS webhook (POST with URL-encoded form data) */
20
+ private handleIncoming;
21
+ private processWebhookPayload;
22
+ private scheduleRestart;
23
+ }
@@ -0,0 +1,161 @@
1
+ import { createServer } from "node:http";
2
+ import { BaseAdapter } from "./base.js";
3
+ const DEFAULT_WEBHOOK_PORT = 3101;
4
+ export class SmsAdapter extends BaseAdapter {
5
+ type = "sms";
6
+ name;
7
+ config;
8
+ server = null;
9
+ reconnectAttempts = 0;
10
+ constructor(name, config) {
11
+ super();
12
+ this.name = name;
13
+ this.config = config;
14
+ }
15
+ async start() {
16
+ if (this.running)
17
+ return;
18
+ this.running = true;
19
+ this.reconnectAttempts = 0;
20
+ console.log(`[sms] Starting Twilio webhook server...`);
21
+ this.startWebhookServer();
22
+ }
23
+ async stop() {
24
+ this.running = false;
25
+ if (this.server) {
26
+ await new Promise((resolve) => {
27
+ this.server.close(() => resolve());
28
+ });
29
+ this.server = null;
30
+ }
31
+ console.log(`[sms] Webhook server stopped`);
32
+ }
33
+ async sendMessage(msg) {
34
+ try {
35
+ const toNumber = msg.metadata?.from_number || msg.sender_id;
36
+ if (!toNumber) {
37
+ console.error("[sms] No recipient phone number");
38
+ return false;
39
+ }
40
+ const url = `https://api.twilio.com/2010-04-01/Accounts/${this.config.account_sid}/Messages.json`;
41
+ // Twilio API uses URL-encoded form data with Basic auth
42
+ const body = new URLSearchParams({
43
+ To: toNumber,
44
+ From: this.config.from_number,
45
+ Body: msg.content,
46
+ });
47
+ const credentials = Buffer.from(`${this.config.account_sid}:${this.config.auth_token}`).toString("base64");
48
+ const res = await fetch(url, {
49
+ method: "POST",
50
+ headers: {
51
+ "Content-Type": "application/x-www-form-urlencoded",
52
+ Authorization: `Basic ${credentials}`,
53
+ },
54
+ body: body.toString(),
55
+ });
56
+ if (res.ok) {
57
+ this.stats.messages_out++;
58
+ this.stats.last_message_at = new Date().toISOString();
59
+ return true;
60
+ }
61
+ const err = await res.text();
62
+ console.error(`[sms] Send failed (${res.status}):`, err);
63
+ this.stats.errors++;
64
+ return false;
65
+ }
66
+ catch (err) {
67
+ console.error(`[sms] Send error:`, err.message);
68
+ this.stats.errors++;
69
+ return false;
70
+ }
71
+ }
72
+ startWebhookServer() {
73
+ const port = this.config.webhook_port || DEFAULT_WEBHOOK_PORT;
74
+ this.server = createServer((req, res) => {
75
+ if (req.method === "POST") {
76
+ this.handleIncoming(req, res);
77
+ }
78
+ else {
79
+ // Health check endpoint
80
+ res.writeHead(200, { "Content-Type": "text/plain" });
81
+ res.end("WhaleNode SMS adapter running");
82
+ }
83
+ });
84
+ this.server.on("error", (err) => {
85
+ console.error(`[sms] Server error:`, err.message);
86
+ this.stats.errors++;
87
+ if (this.running)
88
+ this.scheduleRestart();
89
+ });
90
+ this.server.listen(port, () => {
91
+ console.log(`[sms] Twilio webhook server listening on port ${port}`);
92
+ });
93
+ }
94
+ /** Handle inbound Twilio SMS webhook (POST with URL-encoded form data) */
95
+ handleIncoming(req, res) {
96
+ let body = "";
97
+ req.on("data", (chunk) => {
98
+ body += chunk.toString();
99
+ });
100
+ req.on("end", () => {
101
+ // Respond with empty TwiML to acknowledge receipt
102
+ res.writeHead(200, { "Content-Type": "application/xml" });
103
+ res.end("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response></Response>");
104
+ this.processWebhookPayload(body).catch((err) => {
105
+ console.error(`[sms] Error processing webhook:`, err.message);
106
+ this.stats.errors++;
107
+ });
108
+ });
109
+ }
110
+ async processWebhookPayload(raw) {
111
+ // Twilio sends URL-encoded form data
112
+ const params = new URLSearchParams(raw);
113
+ const fromNumber = params.get("From");
114
+ const toNumber = params.get("To");
115
+ const messageBody = params.get("Body");
116
+ const messageSid = params.get("MessageSid");
117
+ if (!fromNumber || !messageBody) {
118
+ return;
119
+ }
120
+ const payload = {
121
+ sender_id: fromNumber,
122
+ content: messageBody,
123
+ metadata: {
124
+ from_number: fromNumber,
125
+ to_number: toNumber,
126
+ message_sid: messageSid,
127
+ num_media: params.get("NumMedia"),
128
+ from_city: params.get("FromCity"),
129
+ from_state: params.get("FromState"),
130
+ from_country: params.get("FromCountry"),
131
+ },
132
+ };
133
+ this.stats.messages_in++;
134
+ this.stats.last_message_at = new Date().toISOString();
135
+ if (this.onInboundMessage) {
136
+ await this.onInboundMessage(payload).catch((err) => {
137
+ console.error(`[sms] Error handling message:`, err.message);
138
+ this.stats.errors++;
139
+ });
140
+ }
141
+ }
142
+ scheduleRestart() {
143
+ if (!this.running)
144
+ return;
145
+ this.reconnectAttempts++;
146
+ const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 60_000);
147
+ console.log(`[sms] Restarting webhook server in ${delay}ms (attempt ${this.reconnectAttempts})...`);
148
+ setTimeout(() => {
149
+ if (!this.running)
150
+ return;
151
+ if (this.server) {
152
+ this.server.close(() => {
153
+ this.startWebhookServer();
154
+ });
155
+ }
156
+ else {
157
+ this.startWebhookServer();
158
+ }
159
+ }, delay);
160
+ }
161
+ }
@@ -0,0 +1,17 @@
1
+ import { BaseAdapter, type OutboundMessage } from "./base.js";
2
+ export interface TelegramConfig {
3
+ bot_token: string;
4
+ allowed_chats?: number[];
5
+ }
6
+ export declare class TelegramAdapter extends BaseAdapter {
7
+ readonly type = "telegram";
8
+ readonly name: string;
9
+ private config;
10
+ private offset;
11
+ private pollTimer;
12
+ constructor(name: string, config: TelegramConfig);
13
+ start(): Promise<void>;
14
+ stop(): Promise<void>;
15
+ sendMessage(msg: OutboundMessage): Promise<boolean>;
16
+ private poll;
17
+ }
@@ -0,0 +1,101 @@
1
+ import { BaseAdapter } from "./base.js";
2
+ export class TelegramAdapter extends BaseAdapter {
3
+ type = "telegram";
4
+ name;
5
+ config;
6
+ offset = 0;
7
+ pollTimer = null;
8
+ constructor(name, config) {
9
+ super();
10
+ this.name = name;
11
+ this.config = config;
12
+ }
13
+ async start() {
14
+ if (this.running)
15
+ return;
16
+ this.running = true;
17
+ console.log(`[telegram] Starting long-poll for bot...`);
18
+ this.poll();
19
+ }
20
+ async stop() {
21
+ this.running = false;
22
+ if (this.pollTimer) {
23
+ clearTimeout(this.pollTimer);
24
+ this.pollTimer = null;
25
+ }
26
+ }
27
+ async sendMessage(msg) {
28
+ try {
29
+ const chatId = msg.metadata?.chat_id || msg.conversation_id;
30
+ if (!chatId)
31
+ return false;
32
+ const res = await fetch(`https://api.telegram.org/bot${this.config.bot_token}/sendMessage`, {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json" },
35
+ body: JSON.stringify({
36
+ chat_id: chatId,
37
+ text: msg.content,
38
+ parse_mode: "Markdown",
39
+ }),
40
+ });
41
+ if (res.ok) {
42
+ this.stats.messages_out++;
43
+ this.stats.last_message_at = new Date().toISOString();
44
+ return true;
45
+ }
46
+ this.stats.errors++;
47
+ return false;
48
+ }
49
+ catch {
50
+ this.stats.errors++;
51
+ return false;
52
+ }
53
+ }
54
+ async poll() {
55
+ if (!this.running)
56
+ return;
57
+ try {
58
+ const res = await fetch(`https://api.telegram.org/bot${this.config.bot_token}/getUpdates?offset=${this.offset}&timeout=30`);
59
+ const data = await res.json();
60
+ if (data.ok && data.result?.length) {
61
+ for (const update of data.result) {
62
+ this.offset = update.update_id + 1;
63
+ const message = update.message;
64
+ if (!message?.text)
65
+ continue;
66
+ // Filter by allowed chats
67
+ if (this.config.allowed_chats?.length) {
68
+ if (!this.config.allowed_chats.includes(message.chat.id))
69
+ continue;
70
+ }
71
+ const payload = {
72
+ sender_id: String(message.from?.id || "unknown"),
73
+ sender_name: [message.from?.first_name, message.from?.last_name].filter(Boolean).join(" "),
74
+ content: message.text,
75
+ metadata: {
76
+ chat_id: message.chat.id,
77
+ chat_type: message.chat.type,
78
+ message_id: message.message_id,
79
+ },
80
+ };
81
+ this.stats.messages_in++;
82
+ this.stats.last_message_at = new Date().toISOString();
83
+ if (this.onInboundMessage) {
84
+ await this.onInboundMessage(payload).catch(err => {
85
+ console.error(`[telegram] Error handling message:`, err.message);
86
+ this.stats.errors++;
87
+ });
88
+ }
89
+ }
90
+ }
91
+ }
92
+ catch (err) {
93
+ console.error(`[telegram] Poll error:`, err.message);
94
+ this.stats.errors++;
95
+ }
96
+ // Schedule next poll (backoff on errors)
97
+ if (this.running) {
98
+ this.pollTimer = setTimeout(() => this.poll(), 1000);
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,27 @@
1
+ import { BaseAdapter, type OutboundMessage } from "./base.js";
2
+ export interface WebchatConfig {
3
+ port?: number;
4
+ allowed_origins?: string[];
5
+ max_message_length?: number;
6
+ }
7
+ /**
8
+ * WebChat adapter — runs a local HTTP server that serves a chat widget API.
9
+ * Customers connect via embedded JS widget on any website.
10
+ *
11
+ * Endpoints:
12
+ * POST /message — send a message (returns agent response)
13
+ * GET /health — health check
14
+ * OPTIONS * — CORS preflight
15
+ */
16
+ export declare class WebchatAdapter extends BaseAdapter {
17
+ readonly type = "webchat";
18
+ readonly name: string;
19
+ private config;
20
+ private server;
21
+ private port;
22
+ private outboundQueue;
23
+ constructor(name: string, config?: WebchatConfig);
24
+ start(): Promise<void>;
25
+ stop(): Promise<void>;
26
+ sendMessage(msg: OutboundMessage): Promise<boolean>;
27
+ }