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.
- package/README.md +95 -0
- package/bin/swag-agent.js +9 -0
- package/bin/swagmanager-mcp.js +321 -0
- package/dist/cli/app.d.ts +26 -0
- package/dist/cli/app.js +64 -0
- package/dist/cli/chat/AgentSelector.d.ts +14 -0
- package/dist/cli/chat/AgentSelector.js +14 -0
- package/dist/cli/chat/ChatApp.d.ts +9 -0
- package/dist/cli/chat/ChatApp.js +267 -0
- package/dist/cli/chat/ChatInput.d.ts +39 -0
- package/dist/cli/chat/ChatInput.js +509 -0
- package/dist/cli/chat/MarkdownText.d.ts +10 -0
- package/dist/cli/chat/MarkdownText.js +20 -0
- package/dist/cli/chat/MessageList.d.ts +37 -0
- package/dist/cli/chat/MessageList.js +80 -0
- package/dist/cli/chat/ModelSelector.d.ts +20 -0
- package/dist/cli/chat/ModelSelector.js +73 -0
- package/dist/cli/chat/RewindViewer.d.ts +26 -0
- package/dist/cli/chat/RewindViewer.js +185 -0
- package/dist/cli/chat/StoreSelector.d.ts +14 -0
- package/dist/cli/chat/StoreSelector.js +24 -0
- package/dist/cli/chat/StreamingText.d.ts +12 -0
- package/dist/cli/chat/StreamingText.js +12 -0
- package/dist/cli/chat/SubagentPanel.d.ts +45 -0
- package/dist/cli/chat/SubagentPanel.js +110 -0
- package/dist/cli/chat/TeamPanel.d.ts +21 -0
- package/dist/cli/chat/TeamPanel.js +42 -0
- package/dist/cli/chat/ToolIndicator.d.ts +25 -0
- package/dist/cli/chat/ToolIndicator.js +436 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
- package/dist/cli/commands/config-cmd.d.ts +10 -0
- package/dist/cli/commands/config-cmd.js +99 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +172 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.js +278 -0
- package/dist/cli/commands/mcp.d.ts +12 -0
- package/dist/cli/commands/mcp.js +162 -0
- package/dist/cli/login/LoginApp.d.ts +7 -0
- package/dist/cli/login/LoginApp.js +157 -0
- package/dist/cli/print-mode.d.ts +31 -0
- package/dist/cli/print-mode.js +202 -0
- package/dist/cli/serve-mode.d.ts +37 -0
- package/dist/cli/serve-mode.js +636 -0
- package/dist/cli/services/agent-definitions.d.ts +25 -0
- package/dist/cli/services/agent-definitions.js +91 -0
- package/dist/cli/services/agent-events.d.ts +178 -0
- package/dist/cli/services/agent-events.js +175 -0
- package/dist/cli/services/agent-loop.d.ts +90 -0
- package/dist/cli/services/agent-loop.js +762 -0
- package/dist/cli/services/agent-worker-base.d.ts +97 -0
- package/dist/cli/services/agent-worker-base.js +220 -0
- package/dist/cli/services/auth-service.d.ts +30 -0
- package/dist/cli/services/auth-service.js +160 -0
- package/dist/cli/services/background-processes.d.ts +126 -0
- package/dist/cli/services/background-processes.js +318 -0
- package/dist/cli/services/browser-auth.d.ts +24 -0
- package/dist/cli/services/browser-auth.js +180 -0
- package/dist/cli/services/claude-md-loader.d.ts +16 -0
- package/dist/cli/services/claude-md-loader.js +58 -0
- package/dist/cli/services/config-store.d.ts +47 -0
- package/dist/cli/services/config-store.js +79 -0
- package/dist/cli/services/debug-log.d.ts +10 -0
- package/dist/cli/services/debug-log.js +52 -0
- package/dist/cli/services/error-logger.d.ts +58 -0
- package/dist/cli/services/error-logger.js +269 -0
- package/dist/cli/services/file-history.d.ts +21 -0
- package/dist/cli/services/file-history.js +83 -0
- package/dist/cli/services/format-server-response.d.ts +16 -0
- package/dist/cli/services/format-server-response.js +440 -0
- package/dist/cli/services/git-context.d.ts +11 -0
- package/dist/cli/services/git-context.js +66 -0
- package/dist/cli/services/hooks.d.ts +85 -0
- package/dist/cli/services/hooks.js +258 -0
- package/dist/cli/services/interactive-tools.d.ts +125 -0
- package/dist/cli/services/interactive-tools.js +260 -0
- package/dist/cli/services/keybinding-manager.d.ts +52 -0
- package/dist/cli/services/keybinding-manager.js +115 -0
- package/dist/cli/services/local-tools.d.ts +22 -0
- package/dist/cli/services/local-tools.js +697 -0
- package/dist/cli/services/lsp-manager.d.ts +18 -0
- package/dist/cli/services/lsp-manager.js +717 -0
- package/dist/cli/services/mcp-client.d.ts +48 -0
- package/dist/cli/services/mcp-client.js +157 -0
- package/dist/cli/services/memory-manager.d.ts +16 -0
- package/dist/cli/services/memory-manager.js +57 -0
- package/dist/cli/services/model-manager.d.ts +18 -0
- package/dist/cli/services/model-manager.js +71 -0
- package/dist/cli/services/model-router.d.ts +26 -0
- package/dist/cli/services/model-router.js +149 -0
- package/dist/cli/services/permission-modes.d.ts +13 -0
- package/dist/cli/services/permission-modes.js +43 -0
- package/dist/cli/services/rewind.d.ts +84 -0
- package/dist/cli/services/rewind.js +194 -0
- package/dist/cli/services/ripgrep.d.ts +28 -0
- package/dist/cli/services/ripgrep.js +138 -0
- package/dist/cli/services/sandbox.d.ts +29 -0
- package/dist/cli/services/sandbox.js +97 -0
- package/dist/cli/services/server-tools.d.ts +61 -0
- package/dist/cli/services/server-tools.js +543 -0
- package/dist/cli/services/session-persistence.d.ts +23 -0
- package/dist/cli/services/session-persistence.js +99 -0
- package/dist/cli/services/subagent-worker.d.ts +19 -0
- package/dist/cli/services/subagent-worker.js +41 -0
- package/dist/cli/services/subagent.d.ts +47 -0
- package/dist/cli/services/subagent.js +647 -0
- package/dist/cli/services/system-prompt.d.ts +7 -0
- package/dist/cli/services/system-prompt.js +198 -0
- package/dist/cli/services/team-lead.d.ts +73 -0
- package/dist/cli/services/team-lead.js +512 -0
- package/dist/cli/services/team-state.d.ts +77 -0
- package/dist/cli/services/team-state.js +398 -0
- package/dist/cli/services/teammate.d.ts +31 -0
- package/dist/cli/services/teammate.js +689 -0
- package/dist/cli/services/telemetry.d.ts +61 -0
- package/dist/cli/services/telemetry.js +209 -0
- package/dist/cli/services/tools/agent-tools.d.ts +14 -0
- package/dist/cli/services/tools/agent-tools.js +347 -0
- package/dist/cli/services/tools/file-ops.d.ts +15 -0
- package/dist/cli/services/tools/file-ops.js +487 -0
- package/dist/cli/services/tools/search-tools.d.ts +8 -0
- package/dist/cli/services/tools/search-tools.js +186 -0
- package/dist/cli/services/tools/shell-exec.d.ts +10 -0
- package/dist/cli/services/tools/shell-exec.js +168 -0
- package/dist/cli/services/tools/task-manager.d.ts +28 -0
- package/dist/cli/services/tools/task-manager.js +209 -0
- package/dist/cli/services/tools/web-tools.d.ts +11 -0
- package/dist/cli/services/tools/web-tools.js +395 -0
- package/dist/cli/setup/SetupApp.d.ts +9 -0
- package/dist/cli/setup/SetupApp.js +191 -0
- package/dist/cli/shared/MatrixIntro.d.ts +4 -0
- package/dist/cli/shared/MatrixIntro.js +83 -0
- package/dist/cli/shared/Theme.d.ts +74 -0
- package/dist/cli/shared/Theme.js +127 -0
- package/dist/cli/shared/WhaleBanner.d.ts +10 -0
- package/dist/cli/shared/WhaleBanner.js +12 -0
- package/dist/cli/shared/markdown.d.ts +21 -0
- package/dist/cli/shared/markdown.js +756 -0
- package/dist/cli/status/StatusApp.d.ts +4 -0
- package/dist/cli/status/StatusApp.js +105 -0
- package/dist/cli/stores/StoreApp.d.ts +7 -0
- package/dist/cli/stores/StoreApp.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +538 -0
- package/dist/local-agent/connection.d.ts +48 -0
- package/dist/local-agent/connection.js +332 -0
- package/dist/local-agent/discovery.d.ts +18 -0
- package/dist/local-agent/discovery.js +146 -0
- package/dist/local-agent/executor.d.ts +34 -0
- package/dist/local-agent/executor.js +241 -0
- package/dist/local-agent/index.d.ts +14 -0
- package/dist/local-agent/index.js +198 -0
- package/dist/node/adapters/base.d.ts +35 -0
- package/dist/node/adapters/base.js +10 -0
- package/dist/node/adapters/discord.d.ts +29 -0
- package/dist/node/adapters/discord.js +299 -0
- package/dist/node/adapters/email.d.ts +23 -0
- package/dist/node/adapters/email.js +218 -0
- package/dist/node/adapters/imessage.d.ts +17 -0
- package/dist/node/adapters/imessage.js +118 -0
- package/dist/node/adapters/slack.d.ts +26 -0
- package/dist/node/adapters/slack.js +259 -0
- package/dist/node/adapters/sms.d.ts +23 -0
- package/dist/node/adapters/sms.js +161 -0
- package/dist/node/adapters/telegram.d.ts +17 -0
- package/dist/node/adapters/telegram.js +101 -0
- package/dist/node/adapters/webchat.d.ts +27 -0
- package/dist/node/adapters/webchat.js +160 -0
- package/dist/node/adapters/whatsapp.d.ts +28 -0
- package/dist/node/adapters/whatsapp.js +230 -0
- package/dist/node/cli.d.ts +2 -0
- package/dist/node/cli.js +325 -0
- package/dist/node/config.d.ts +17 -0
- package/dist/node/config.js +31 -0
- package/dist/node/runtime.d.ts +50 -0
- package/dist/node/runtime.js +351 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
- package/dist/server/handlers/analytics.d.ts +17 -0
- package/dist/server/handlers/analytics.js +266 -0
- package/dist/server/handlers/api-keys.d.ts +6 -0
- package/dist/server/handlers/api-keys.js +221 -0
- package/dist/server/handlers/billing.d.ts +33 -0
- package/dist/server/handlers/billing.js +272 -0
- package/dist/server/handlers/browser.d.ts +10 -0
- package/dist/server/handlers/browser.js +517 -0
- package/dist/server/handlers/catalog.d.ts +99 -0
- package/dist/server/handlers/catalog.js +976 -0
- package/dist/server/handlers/comms.d.ts +254 -0
- package/dist/server/handlers/comms.js +588 -0
- package/dist/server/handlers/creations.d.ts +6 -0
- package/dist/server/handlers/creations.js +479 -0
- package/dist/server/handlers/crm.d.ts +89 -0
- package/dist/server/handlers/crm.js +538 -0
- package/dist/server/handlers/discovery.d.ts +6 -0
- package/dist/server/handlers/discovery.js +288 -0
- package/dist/server/handlers/embeddings.d.ts +92 -0
- package/dist/server/handlers/embeddings.js +197 -0
- package/dist/server/handlers/enrichment.d.ts +8 -0
- package/dist/server/handlers/enrichment.js +768 -0
- package/dist/server/handlers/image-gen.d.ts +6 -0
- package/dist/server/handlers/image-gen.js +409 -0
- package/dist/server/handlers/inventory.d.ts +319 -0
- package/dist/server/handlers/inventory.js +447 -0
- package/dist/server/handlers/kali.d.ts +10 -0
- package/dist/server/handlers/kali.js +210 -0
- package/dist/server/handlers/llm-providers.d.ts +6 -0
- package/dist/server/handlers/llm-providers.js +673 -0
- package/dist/server/handlers/local-agent.d.ts +6 -0
- package/dist/server/handlers/local-agent.js +118 -0
- package/dist/server/handlers/meta-ads.d.ts +111 -0
- package/dist/server/handlers/meta-ads.js +2279 -0
- package/dist/server/handlers/nodes.d.ts +33 -0
- package/dist/server/handlers/nodes.js +699 -0
- package/dist/server/handlers/operations.d.ts +138 -0
- package/dist/server/handlers/operations.js +131 -0
- package/dist/server/handlers/platform.d.ts +23 -0
- package/dist/server/handlers/platform.js +227 -0
- package/dist/server/handlers/supply-chain.d.ts +19 -0
- package/dist/server/handlers/supply-chain.js +327 -0
- package/dist/server/handlers/transcription.d.ts +17 -0
- package/dist/server/handlers/transcription.js +121 -0
- package/dist/server/handlers/video-gen.d.ts +6 -0
- package/dist/server/handlers/video-gen.js +466 -0
- package/dist/server/handlers/voice.d.ts +8 -0
- package/dist/server/handlers/voice.js +1146 -0
- package/dist/server/handlers/workflow-steps.d.ts +86 -0
- package/dist/server/handlers/workflow-steps.js +2349 -0
- package/dist/server/handlers/workflows.d.ts +7 -0
- package/dist/server/handlers/workflows.js +989 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2427 -0
- package/dist/server/lib/batch-client.d.ts +80 -0
- package/dist/server/lib/batch-client.js +467 -0
- package/dist/server/lib/code-worker-pool.d.ts +31 -0
- package/dist/server/lib/code-worker-pool.js +224 -0
- package/dist/server/lib/code-worker.d.ts +1 -0
- package/dist/server/lib/code-worker.js +188 -0
- package/dist/server/lib/compaction-service.d.ts +32 -0
- package/dist/server/lib/compaction-service.js +162 -0
- package/dist/server/lib/logger.d.ts +19 -0
- package/dist/server/lib/logger.js +46 -0
- package/dist/server/lib/otel.d.ts +38 -0
- package/dist/server/lib/otel.js +126 -0
- package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
- package/dist/server/lib/pg-rate-limiter.js +86 -0
- package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
- package/dist/server/lib/prompt-sanitizer.js +177 -0
- package/dist/server/lib/provider-capabilities.d.ts +85 -0
- package/dist/server/lib/provider-capabilities.js +190 -0
- package/dist/server/lib/provider-failover.d.ts +74 -0
- package/dist/server/lib/provider-failover.js +210 -0
- package/dist/server/lib/rate-limiter.d.ts +39 -0
- package/dist/server/lib/rate-limiter.js +147 -0
- package/dist/server/lib/server-agent-loop.d.ts +107 -0
- package/dist/server/lib/server-agent-loop.js +667 -0
- package/dist/server/lib/server-subagent.d.ts +78 -0
- package/dist/server/lib/server-subagent.js +203 -0
- package/dist/server/lib/session-checkpoint.d.ts +51 -0
- package/dist/server/lib/session-checkpoint.js +145 -0
- package/dist/server/lib/ssrf-guard.d.ts +13 -0
- package/dist/server/lib/ssrf-guard.js +240 -0
- package/dist/server/lib/supabase-client.d.ts +7 -0
- package/dist/server/lib/supabase-client.js +78 -0
- package/dist/server/lib/template-resolver.d.ts +31 -0
- package/dist/server/lib/template-resolver.js +215 -0
- package/dist/server/lib/utils.d.ts +16 -0
- package/dist/server/lib/utils.js +147 -0
- package/dist/server/local-agent-gateway.d.ts +82 -0
- package/dist/server/local-agent-gateway.js +426 -0
- package/dist/server/providers/anthropic.d.ts +20 -0
- package/dist/server/providers/anthropic.js +199 -0
- package/dist/server/providers/bedrock.d.ts +20 -0
- package/dist/server/providers/bedrock.js +194 -0
- package/dist/server/providers/gemini.d.ts +24 -0
- package/dist/server/providers/gemini.js +486 -0
- package/dist/server/providers/openai.d.ts +24 -0
- package/dist/server/providers/openai.js +522 -0
- package/dist/server/providers/registry.d.ts +32 -0
- package/dist/server/providers/registry.js +58 -0
- package/dist/server/providers/shared.d.ts +32 -0
- package/dist/server/providers/shared.js +124 -0
- package/dist/server/providers/types.d.ts +92 -0
- package/dist/server/providers/types.js +12 -0
- package/dist/server/proxy-handlers.d.ts +6 -0
- package/dist/server/proxy-handlers.js +89 -0
- package/dist/server/tool-router.d.ts +149 -0
- package/dist/server/tool-router.js +803 -0
- package/dist/server/validation.d.ts +24 -0
- package/dist/server/validation.js +301 -0
- package/dist/server/worker.d.ts +19 -0
- package/dist/server/worker.js +201 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +181 -0
- package/dist/shared/agent-core.d.ts +157 -0
- package/dist/shared/agent-core.js +534 -0
- package/dist/shared/anthropic-types.d.ts +105 -0
- package/dist/shared/anthropic-types.js +7 -0
- package/dist/shared/api-client.d.ts +90 -0
- package/dist/shared/api-client.js +379 -0
- package/dist/shared/constants.d.ts +33 -0
- package/dist/shared/constants.js +80 -0
- package/dist/shared/sse-parser.d.ts +26 -0
- package/dist/shared/sse-parser.js +259 -0
- package/dist/shared/tool-dispatch.d.ts +52 -0
- package/dist/shared/tool-dispatch.js +191 -0
- package/dist/shared/types.d.ts +72 -0
- package/dist/shared/types.js +7 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +140 -0
- package/dist/webchat/widget.d.ts +0 -0
- package/dist/webchat/widget.js +397 -0
- package/package.json +95 -0
- package/src/cli/services/builtin-skills/commit.md +19 -0
- package/src/cli/services/builtin-skills/review-pr.md +21 -0
- package/src/cli/services/builtin-skills/review.md +18 -0
package/dist/node/cli.js
ADDED
|
@@ -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
|
+
}
|