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,325 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { loadConfig, saveConfig, requireConfig, getConfigPath } from "./config.js";
4
+ import { NodeRuntime } from "./runtime.js";
5
+ import { initErrorLogger, setErrorLoggerUser, captureError } from "../cli/services/error-logger.js";
6
+ import { loadConfig as loadCliConfig } from "../cli/services/config-store.js";
7
+ const args = process.argv.slice(2);
8
+ const command = args[0];
9
+ const subcommand = args[1];
10
+ // Initialize error logging — uses ~/.swagmanager/config.json for Supabase credentials
11
+ initErrorLogger({ serviceName: "whale-node" });
12
+ const cliCfg = loadCliConfig();
13
+ if (cliCfg.user_id || cliCfg.email || cliCfg.store_id) {
14
+ setErrorLoggerUser(cliCfg.user_id, cliCfg.email, cliCfg.store_id);
15
+ }
16
+ // Global error handlers — capture crashes to error_events
17
+ process.on("uncaughtException", (err) => {
18
+ captureError({ error: err, severity: "fatal", tags: { source: "whale-node", handler: "uncaughtException" } });
19
+ });
20
+ process.on("unhandledRejection", (reason) => {
21
+ const err = reason instanceof Error ? reason : new Error(String(reason));
22
+ captureError({ error: err, severity: "error", tags: { source: "whale-node", handler: "unhandledRejection" } });
23
+ });
24
+ async function main() {
25
+ switch (command) {
26
+ case "node":
27
+ await handleNodeCommand(subcommand, args.slice(2));
28
+ break;
29
+ case "channel":
30
+ await handleChannelCommand(subcommand, args.slice(2));
31
+ break;
32
+ case "status":
33
+ await handleStatus();
34
+ break;
35
+ case "version":
36
+ console.log("WhaleNode CLI v1.1.0");
37
+ break;
38
+ case "help":
39
+ default:
40
+ printHelp();
41
+ }
42
+ }
43
+ async function handleNodeCommand(sub, args) {
44
+ switch (sub) {
45
+ case "register": {
46
+ const { values } = parseArgs({
47
+ args,
48
+ options: {
49
+ name: { type: "string" },
50
+ store: { type: "string" },
51
+ server: { type: "string", default: "https://whale-agent.fly.dev" },
52
+ token: { type: "string" },
53
+ },
54
+ });
55
+ if (!values.name || !values.store || !values.token) {
56
+ console.error("Usage: whale node register --name 'My Mac' --store STORE_ID --token JWT_TOKEN");
57
+ process.exit(1);
58
+ }
59
+ console.log(`Registering node "${values.name}"...`);
60
+ const res = await fetch(`${values.server}/nodes/register`, {
61
+ method: "POST",
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ Authorization: `Bearer ${values.token}`,
65
+ },
66
+ body: JSON.stringify({
67
+ name: values.name,
68
+ store_id: values.store,
69
+ }),
70
+ });
71
+ const data = await res.json();
72
+ if (!data.success) {
73
+ console.error(`Registration failed: ${data.error}`);
74
+ process.exit(1);
75
+ }
76
+ const config = {
77
+ node_id: data.node.id,
78
+ api_key: data.api_key,
79
+ store_id: values.store,
80
+ server_url: values.server,
81
+ channels: [],
82
+ };
83
+ saveConfig(config);
84
+ console.log(`\nNode registered successfully!`);
85
+ console.log(` Node ID: ${data.node.id}`);
86
+ console.log(` API Key: ${data.api_key}`);
87
+ console.log(` Config: ${getConfigPath()}`);
88
+ console.log(`\nSave your API key -- it cannot be retrieved later.`);
89
+ console.log(`\nNext: whale channel add imessage|telegram`);
90
+ break;
91
+ }
92
+ case "start": {
93
+ const config = requireConfig();
94
+ const runtime = new NodeRuntime(config);
95
+ await runtime.start();
96
+ // Keep process alive
97
+ await new Promise(() => { });
98
+ break;
99
+ }
100
+ case "status": {
101
+ await handleStatus();
102
+ break;
103
+ }
104
+ default:
105
+ console.log("Usage: whale node [register|start|status]");
106
+ }
107
+ }
108
+ async function handleChannelCommand(sub, args) {
109
+ switch (sub) {
110
+ case "add": {
111
+ const channelType = args[0];
112
+ const validTypes = ["imessage", "telegram", "discord", "slack", "whatsapp", "sms", "email"];
113
+ if (!channelType || !validTypes.includes(channelType)) {
114
+ console.error(`Usage: whale channel add [${validTypes.join("|")}]`);
115
+ process.exit(1);
116
+ }
117
+ const config = requireConfig();
118
+ const { values } = parseArgs({
119
+ args: args.slice(1),
120
+ options: {
121
+ name: { type: "string" },
122
+ token: { type: "string" }, // Bot token (Telegram, Discord, Slack bot)
123
+ "app-token": { type: "string" }, // Slack app-level token
124
+ groups: { type: "string" }, // iMessage group IDs (comma-separated)
125
+ channels: { type: "string" }, // Discord/Slack channel IDs (comma-separated)
126
+ guilds: { type: "string" }, // Discord guild IDs (comma-separated)
127
+ mention: { type: "string", default: "" }, // Require @mention
128
+ // WhatsApp Cloud API
129
+ "phone-number-id": { type: "string" }, // WhatsApp phone number ID
130
+ "access-token": { type: "string" }, // WhatsApp access token
131
+ "verify-token": { type: "string" }, // WhatsApp webhook verify token
132
+ "allowed-numbers": { type: "string" }, // Comma-separated allowed phone numbers
133
+ // Twilio SMS
134
+ "account-sid": { type: "string" }, // Twilio account SID
135
+ "auth-token": { type: "string" }, // Twilio auth token
136
+ "from-number": { type: "string" }, // Twilio sender phone number
137
+ // Resend Email
138
+ "api-key": { type: "string" }, // Resend API key
139
+ "from-address": { type: "string" }, // Sender email address
140
+ "webhook-secret": { type: "string" }, // Resend webhook signing secret
141
+ // Shared
142
+ "webhook-port": { type: "string" }, // Webhook server port
143
+ },
144
+ });
145
+ const channelName = values.name || `${channelType}-${Date.now()}`;
146
+ let channelConfig = {};
147
+ switch (channelType) {
148
+ case "imessage":
149
+ channelConfig = {
150
+ watch_groups: values.groups ? values.groups.split(",").map(Number) : [],
151
+ mention_required: values.mention || null,
152
+ max_message_length: 4000,
153
+ };
154
+ break;
155
+ case "telegram":
156
+ if (!values.token) {
157
+ console.error("Telegram requires --token BOT_TOKEN");
158
+ process.exit(1);
159
+ }
160
+ channelConfig = {
161
+ bot_token: values.token,
162
+ allowed_chats: [],
163
+ };
164
+ break;
165
+ case "discord":
166
+ if (!values.token) {
167
+ console.error("Discord requires --token BOT_TOKEN");
168
+ process.exit(1);
169
+ }
170
+ channelConfig = {
171
+ bot_token: values.token,
172
+ allowed_channels: values.channels ? values.channels.split(",") : [],
173
+ allowed_guilds: values.guilds ? values.guilds.split(",") : [],
174
+ mention_required: values.mention !== "" ? true : false,
175
+ };
176
+ break;
177
+ case "slack":
178
+ if (!values.token || !values["app-token"]) {
179
+ console.error("Slack requires --token BOT_TOKEN --app-token APP_TOKEN");
180
+ process.exit(1);
181
+ }
182
+ channelConfig = {
183
+ bot_token: values.token,
184
+ app_token: values["app-token"],
185
+ allowed_channels: values.channels ? values.channels.split(",") : [],
186
+ mention_required: values.mention !== "" ? true : false,
187
+ };
188
+ break;
189
+ case "whatsapp":
190
+ if (!values["phone-number-id"] || !values["access-token"] || !values["verify-token"]) {
191
+ console.error("WhatsApp requires --phone-number-id ID --access-token TOKEN --verify-token SECRET");
192
+ process.exit(1);
193
+ }
194
+ channelConfig = {
195
+ phone_number_id: values["phone-number-id"],
196
+ access_token: values["access-token"],
197
+ verify_token: values["verify-token"],
198
+ allowed_numbers: values["allowed-numbers"] ? values["allowed-numbers"].split(",") : [],
199
+ ...(values["webhook-port"] ? { webhook_port: Number(values["webhook-port"]) } : {}),
200
+ };
201
+ break;
202
+ case "sms":
203
+ if (!values["account-sid"] || !values["auth-token"] || !values["from-number"]) {
204
+ console.error("SMS requires --account-sid SID --auth-token TOKEN --from-number +1234567890");
205
+ process.exit(1);
206
+ }
207
+ channelConfig = {
208
+ account_sid: values["account-sid"],
209
+ auth_token: values["auth-token"],
210
+ from_number: values["from-number"],
211
+ ...(values["webhook-port"] ? { webhook_port: Number(values["webhook-port"]) } : {}),
212
+ };
213
+ break;
214
+ case "email":
215
+ if (!values["api-key"] || !values["from-address"]) {
216
+ console.error("Email requires --api-key KEY --from-address sender@example.com");
217
+ process.exit(1);
218
+ }
219
+ channelConfig = {
220
+ api_key: values["api-key"],
221
+ from_address: values["from-address"],
222
+ ...(values["webhook-secret"] ? { webhook_secret: values["webhook-secret"] } : {}),
223
+ ...(values["webhook-port"] ? { webhook_port: Number(values["webhook-port"]) } : {}),
224
+ };
225
+ break;
226
+ default:
227
+ console.error(`Unknown channel type: ${channelType}`);
228
+ process.exit(1);
229
+ }
230
+ // Register channel with server
231
+ console.log(`Adding ${channelType} channel "${channelName}"...`);
232
+ const res = await fetch(`${config.server_url}/channels`, {
233
+ method: "POST",
234
+ headers: {
235
+ "Content-Type": "application/json",
236
+ Authorization: `Bearer ${config.api_key}`,
237
+ },
238
+ body: JSON.stringify({
239
+ store_id: config.store_id,
240
+ node_id: config.node_id,
241
+ type: channelType,
242
+ name: channelName,
243
+ config: channelConfig,
244
+ }),
245
+ });
246
+ const data = await res.json();
247
+ if (!data.success) {
248
+ console.error(`Failed to add channel: ${data.error}`);
249
+ process.exit(1);
250
+ }
251
+ // Save to local config
252
+ config.channels.push({
253
+ id: data.channel.id,
254
+ type: channelType,
255
+ name: channelName,
256
+ config: channelConfig,
257
+ });
258
+ saveConfig(config);
259
+ console.log(`Channel added!`);
260
+ console.log(` ID: ${data.channel.id}`);
261
+ console.log(` Type: ${channelType}`);
262
+ console.log(` Name: ${channelName}`);
263
+ break;
264
+ }
265
+ case "list": {
266
+ const config = requireConfig();
267
+ if (!config.channels.length) {
268
+ console.log("No channels configured. Run: whale channel add [imessage|telegram|discord|slack|whatsapp|sms|email]");
269
+ return;
270
+ }
271
+ console.log("Configured channels:");
272
+ for (const ch of config.channels) {
273
+ console.log(` ${ch.type.padEnd(10)} ${ch.name.padEnd(20)} ${ch.id}`);
274
+ }
275
+ break;
276
+ }
277
+ default:
278
+ console.log("Usage: whale channel [add|list]");
279
+ }
280
+ }
281
+ async function handleStatus() {
282
+ const config = loadConfig();
283
+ if (!config) {
284
+ console.log("Not configured. Run: whale node register --name 'My Mac' --store STORE_ID --token JWT");
285
+ return;
286
+ }
287
+ console.log("WhaleNode Status:");
288
+ console.log(` Node ID: ${config.node_id}`);
289
+ console.log(` Store: ${config.store_id}`);
290
+ console.log(` Server: ${config.server_url}`);
291
+ console.log(` Channels: ${config.channels.length}`);
292
+ console.log(` Config: ${getConfigPath()}`);
293
+ }
294
+ function printHelp() {
295
+ console.log(`
296
+ WhaleNode CLI v1.1.0 — Bridge local channels to WhaleTools AI agents
297
+
298
+ Commands:
299
+ whale node register Register this machine as a WhaleNode
300
+ whale node start Start the node (heartbeat + channel adapters)
301
+ whale node status Show node status
302
+
303
+ whale channel add Add a channel adapter
304
+ whale channel list List configured channels
305
+
306
+ whale status Quick status check
307
+ whale version Show version
308
+ whale help Show this help
309
+
310
+ Channel Types:
311
+ imessage --groups 109,110 --mention @whale
312
+ telegram --token BOT_TOKEN
313
+ discord --token BOT_TOKEN [--channels ID1,ID2] [--guilds ID1] [--mention]
314
+ slack --token BOT_TOKEN --app-token APP_TOKEN [--channels ID1,ID2] [--mention]
315
+ whatsapp --phone-number-id ID --access-token TOKEN --verify-token SECRET [--allowed-numbers +1...,+2...]
316
+ sms --account-sid SID --auth-token TOKEN --from-number +1234567890 [--webhook-port 3101]
317
+ email --api-key KEY --from-address sender@example.com [--webhook-secret SECRET] [--webhook-port 3102]
318
+ `);
319
+ }
320
+ main().catch(err => {
321
+ captureError({ error: err instanceof Error ? err : new Error(String(err)), severity: "fatal", tags: { source: "whale-node", handler: "main" } });
322
+ console.error("Error:", err.message);
323
+ // Give error logger a moment to flush before exit
324
+ setTimeout(() => process.exit(1), 500);
325
+ });
@@ -0,0 +1,17 @@
1
+ export interface ChannelConfig {
2
+ id: string;
3
+ type: string;
4
+ name: string;
5
+ config: Record<string, unknown>;
6
+ }
7
+ export interface NodeConfig {
8
+ node_id: string;
9
+ api_key: string;
10
+ store_id: string;
11
+ server_url: string;
12
+ channels: ChannelConfig[];
13
+ }
14
+ export declare function getConfigPath(): string;
15
+ export declare function loadConfig(): NodeConfig | null;
16
+ export declare function saveConfig(config: NodeConfig): void;
17
+ export declare function requireConfig(): NodeConfig;
@@ -0,0 +1,31 @@
1
+ // Config stored at ~/.whaletools/config.json
2
+ // Fields: node_id, api_key, store_id, server_url, channels[]
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ const CONFIG_DIR = join(homedir(), ".whaletools");
7
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
8
+ export function getConfigPath() { return CONFIG_FILE; }
9
+ export function loadConfig() {
10
+ if (!existsSync(CONFIG_FILE))
11
+ return null;
12
+ try {
13
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export function saveConfig(config) {
20
+ if (!existsSync(CONFIG_DIR))
21
+ mkdirSync(CONFIG_DIR, { recursive: true });
22
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
23
+ }
24
+ export function requireConfig() {
25
+ const config = loadConfig();
26
+ if (!config) {
27
+ console.error("Not configured. Run: whale node register --name 'My Node' --store STORE_ID --server URL");
28
+ process.exit(1);
29
+ }
30
+ return config;
31
+ }
@@ -0,0 +1,50 @@
1
+ import type { NodeConfig } from "./config.js";
2
+ import type { MessagePayload } from "./adapters/base.js";
3
+ export type NodeStatus = "starting" | "connected" | "degraded" | "disconnected";
4
+ export interface NodeRuntimeStats {
5
+ status: NodeStatus;
6
+ uptime_seconds: number;
7
+ heartbeats_sent: number;
8
+ heartbeats_failed: number;
9
+ messages_relayed: number;
10
+ messages_failed: number;
11
+ consecutive_server_failures: number;
12
+ last_server_contact: string | null;
13
+ adapters: Record<string, {
14
+ type: string;
15
+ running: boolean;
16
+ messages_in: number;
17
+ messages_out: number;
18
+ errors: number;
19
+ }>;
20
+ }
21
+ export declare class NodeRuntime {
22
+ private config;
23
+ private adapters;
24
+ private heartbeatTimer;
25
+ private pollTimers;
26
+ private running;
27
+ private startedAt;
28
+ private status;
29
+ private consecutiveServerFailures;
30
+ private lastServerContact;
31
+ private heartbeatsSent;
32
+ private heartbeatsFailed;
33
+ private messagesRelayed;
34
+ private messagesFailed;
35
+ constructor(config: NodeConfig);
36
+ getStats(): NodeRuntimeStats;
37
+ start(): Promise<void>;
38
+ stop(): Promise<void>;
39
+ private startAdapter;
40
+ /** Fetch with retry and exponential backoff */
41
+ private fetchWithRetry;
42
+ /** Track server connectivity health */
43
+ private recordServerContact;
44
+ /** Poll for undelivered outbound messages and deliver via adapter */
45
+ private pollOutbound;
46
+ /** Relay inbound and deliver response synchronously with retry */
47
+ relayAndDeliver(channelId: string, msg: MessagePayload): Promise<void>;
48
+ private markDelivered;
49
+ private sendHeartbeat;
50
+ }