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,241 @@
1
+ /**
2
+ * Local Command Executor — safely runs commands on the user's machine.
3
+ *
4
+ * Features:
5
+ * - Persistent sessions (cwd preserved per session_id)
6
+ * - Output streaming with truncation
7
+ * - Timeout enforcement
8
+ * - Background job support
9
+ */
10
+ import { spawn } from "node:child_process";
11
+ import { randomUUID } from "node:crypto";
12
+ import os from "node:os";
13
+ const MAX_OUTPUT_CHARS = 500 * 1024; // 500KB safety cap
14
+ const DEFAULT_TIMEOUT = 30_000;
15
+ // ============================================================================
16
+ // SESSION STATE
17
+ // ============================================================================
18
+ /** Map<sessionId, cwd> — persistent working directory per session */
19
+ const sessions = new Map();
20
+ const backgroundJobs = new Map();
21
+ export async function exec(command, options = {}) {
22
+ const sessionId = options.session_id || "default";
23
+ const timeout = Math.min(options.timeout || DEFAULT_TIMEOUT, 600_000);
24
+ // Get or create session cwd
25
+ if (!sessions.has(sessionId)) {
26
+ sessions.set(sessionId, os.homedir());
27
+ }
28
+ const cwd = sessions.get(sessionId);
29
+ return new Promise((resolve) => {
30
+ const startTime = Date.now();
31
+ let stdout = "";
32
+ let stderr = "";
33
+ let killed = false;
34
+ let done = false;
35
+ const shell = process.platform === "win32" ? "cmd.exe" : "/bin/bash";
36
+ const shellArgs = process.platform === "win32" ? ["/c", command] : ["-c", command];
37
+ const proc = spawn(shell, shellArgs, {
38
+ cwd,
39
+ env: { ...process.env },
40
+ stdio: ["pipe", "pipe", "pipe"],
41
+ });
42
+ const timer = setTimeout(() => {
43
+ if (!done) {
44
+ killed = true;
45
+ proc.kill("SIGKILL");
46
+ }
47
+ }, timeout);
48
+ proc.stdout?.on("data", (data) => {
49
+ const chunk = data.toString();
50
+ if (stdout.length < MAX_OUTPUT_CHARS) {
51
+ stdout += chunk;
52
+ }
53
+ });
54
+ proc.stderr?.on("data", (data) => {
55
+ const chunk = data.toString();
56
+ if (stderr.length < MAX_OUTPUT_CHARS) {
57
+ stderr += chunk;
58
+ }
59
+ });
60
+ proc.on("close", (code) => {
61
+ done = true;
62
+ clearTimeout(timer);
63
+ // Update session cwd if command included cd
64
+ // Parse the last directory from a subshell approach
65
+ if (command.includes("cd ")) {
66
+ try {
67
+ const pwdProc = spawn(shell, ["-c", `cd "${cwd}" && ${command} && pwd`], {
68
+ cwd,
69
+ stdio: ["pipe", "pipe", "pipe"],
70
+ timeout: 3000,
71
+ });
72
+ let newCwd = "";
73
+ pwdProc.stdout?.on("data", (d) => { newCwd += d.toString(); });
74
+ pwdProc.on("close", () => {
75
+ const dir = newCwd.trim().split("\n").pop()?.trim();
76
+ if (dir)
77
+ sessions.set(sessionId, dir);
78
+ });
79
+ }
80
+ catch {
81
+ // Ignore cwd tracking failures
82
+ }
83
+ }
84
+ // Truncate if needed
85
+ if (stdout.length > MAX_OUTPUT_CHARS) {
86
+ stdout = stdout.substring(0, MAX_OUTPUT_CHARS) + `\n...[truncated, ${stdout.length} total chars]`;
87
+ }
88
+ if (stderr.length > MAX_OUTPUT_CHARS) {
89
+ stderr = stderr.substring(0, MAX_OUTPUT_CHARS) + `\n...[truncated, ${stderr.length} total chars]`;
90
+ }
91
+ resolve({
92
+ success: code === 0,
93
+ stdout,
94
+ stderr,
95
+ exit_code: code ?? -1,
96
+ killed,
97
+ cwd: sessions.get(sessionId) || cwd,
98
+ duration_ms: Date.now() - startTime,
99
+ });
100
+ });
101
+ proc.on("error", (err) => {
102
+ done = true;
103
+ clearTimeout(timer);
104
+ resolve({
105
+ success: false,
106
+ stdout,
107
+ stderr: err.message,
108
+ exit_code: -1,
109
+ killed: false,
110
+ cwd,
111
+ duration_ms: Date.now() - startTime,
112
+ });
113
+ });
114
+ });
115
+ }
116
+ // ============================================================================
117
+ // BACKGROUND JOBS
118
+ // ============================================================================
119
+ export function execBackground(command, sessionId) {
120
+ const jobId = randomUUID();
121
+ const cwd = sessions.get(sessionId || "default") || os.homedir();
122
+ const shell = process.platform === "win32" ? "cmd.exe" : "/bin/bash";
123
+ const shellArgs = process.platform === "win32" ? ["/c", command] : ["-c", command];
124
+ const proc = spawn(shell, shellArgs, {
125
+ cwd,
126
+ env: { ...process.env },
127
+ stdio: ["pipe", "pipe", "pipe"],
128
+ detached: true,
129
+ });
130
+ const job = {
131
+ id: jobId,
132
+ command,
133
+ process: proc,
134
+ stdout: "",
135
+ stderr: "",
136
+ startedAt: Date.now(),
137
+ exitCode: null,
138
+ killed: false,
139
+ done: false,
140
+ };
141
+ proc.stdout?.on("data", (data) => {
142
+ if (job.stdout.length < MAX_OUTPUT_CHARS) {
143
+ job.stdout += data.toString();
144
+ }
145
+ });
146
+ proc.stderr?.on("data", (data) => {
147
+ if (job.stderr.length < MAX_OUTPUT_CHARS) {
148
+ job.stderr += data.toString();
149
+ }
150
+ });
151
+ proc.on("close", (code) => {
152
+ job.exitCode = code;
153
+ job.done = true;
154
+ });
155
+ proc.on("error", (err) => {
156
+ job.stderr += `\nProcess error: ${err.message}`;
157
+ job.done = true;
158
+ job.exitCode = -1;
159
+ });
160
+ backgroundJobs.set(jobId, job);
161
+ return { job_id: jobId };
162
+ }
163
+ export function getJobStatus(jobId, tail) {
164
+ const job = backgroundJobs.get(jobId);
165
+ if (!job)
166
+ return null;
167
+ let stdout = job.stdout;
168
+ let stderr = job.stderr;
169
+ if (tail && tail > 0) {
170
+ stdout = stdout.slice(-tail);
171
+ stderr = stderr.slice(-tail);
172
+ }
173
+ return {
174
+ job_id: job.id,
175
+ command: job.command,
176
+ running: !job.done,
177
+ exit_code: job.exitCode,
178
+ killed: job.killed,
179
+ stdout,
180
+ stderr,
181
+ duration_ms: Date.now() - job.startedAt,
182
+ };
183
+ }
184
+ export function killJob(jobId) {
185
+ const job = backgroundJobs.get(jobId);
186
+ if (!job || job.done)
187
+ return false;
188
+ job.killed = true;
189
+ try {
190
+ if (job.process.pid) {
191
+ process.kill(-job.process.pid, "SIGKILL");
192
+ }
193
+ else {
194
+ job.process.kill("SIGKILL");
195
+ }
196
+ }
197
+ catch {
198
+ job.process.kill("SIGKILL");
199
+ }
200
+ return true;
201
+ }
202
+ export function listJobs() {
203
+ return [...backgroundJobs.values()].map(job => ({
204
+ job_id: job.id,
205
+ command: job.command.substring(0, 100),
206
+ running: !job.done,
207
+ exit_code: job.exitCode,
208
+ duration_ms: Date.now() - job.startedAt,
209
+ }));
210
+ }
211
+ // ============================================================================
212
+ // SESSION MANAGEMENT
213
+ // ============================================================================
214
+ export function listSessions() {
215
+ return [...sessions.entries()].map(([id, cwd]) => ({ session_id: id, cwd }));
216
+ }
217
+ export function resetSessions() {
218
+ sessions.clear();
219
+ for (const [id, job] of backgroundJobs) {
220
+ if (!job.done) {
221
+ try {
222
+ job.process.kill("SIGKILL");
223
+ }
224
+ catch { /* */ }
225
+ }
226
+ }
227
+ backgroundJobs.clear();
228
+ }
229
+ export function getSystemInfo() {
230
+ return {
231
+ platform: process.platform,
232
+ arch: process.arch,
233
+ hostname: os.hostname(),
234
+ user: os.userInfo().username,
235
+ home: os.homedir(),
236
+ cpus: os.cpus().length,
237
+ memory_gb: Math.round(os.totalmem() / 1024 / 1024 / 1024 * 10) / 10,
238
+ uptime_hours: Math.round(os.uptime() / 3600 * 10) / 10,
239
+ node_version: process.version,
240
+ };
241
+ }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SwagManager Local Agent — CLI entry point.
4
+ *
5
+ * Connects to SwagManager cloud via WebSocket, auto-discovers local security tools,
6
+ * and executes commands from Claude on the user's machine.
7
+ *
8
+ * Usage:
9
+ * whale agent start --key YOUR_API_KEY
10
+ * whale agent start --key YOUR_API_KEY --server wss://custom.server/agent/ws
11
+ * whale agent discover # list detected tools
12
+ * whale agent info # system info
13
+ */
14
+ export {};
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SwagManager Local Agent — CLI entry point.
4
+ *
5
+ * Connects to SwagManager cloud via WebSocket, auto-discovers local security tools,
6
+ * and executes commands from Claude on the user's machine.
7
+ *
8
+ * Usage:
9
+ * whale agent start --key YOUR_API_KEY
10
+ * whale agent start --key YOUR_API_KEY --server wss://custom.server/agent/ws
11
+ * whale agent discover # list detected tools
12
+ * whale agent info # system info
13
+ */
14
+ import { LocalAgentConnection } from "./connection.js";
15
+ import { discoverTools } from "./discovery.js";
16
+ import { getSystemInfo } from "./executor.js";
17
+ const args = process.argv.slice(2);
18
+ const command = args[0];
19
+ function getFlag(name) {
20
+ const idx = args.indexOf(`--${name}`);
21
+ if (idx >= 0 && idx + 1 < args.length)
22
+ return args[idx + 1];
23
+ // Also check -k shorthand for --key
24
+ if (name === "key") {
25
+ const shortIdx = args.indexOf("-k");
26
+ if (shortIdx >= 0 && shortIdx + 1 < args.length)
27
+ return args[shortIdx + 1];
28
+ }
29
+ return undefined;
30
+ }
31
+ // ============================================================================
32
+ // BANNER
33
+ // ============================================================================
34
+ function printBanner() {
35
+ console.log(`
36
+ ____ __ __
37
+ / ___|_ ____ _ __ _ | \\/ | __ _ _ __ __ _ __ _ ___ _ __
38
+ \\___ \\ \\ /\\ / / _\` |/ _\` | | |\\/| |/ _\` | '_ \\ / _\` |/ _\` |/ _ \\ '__|
39
+ ___) \\ V V / (_| | (_| | | | | | (_| | | | | (_| | (_| | __/ |
40
+ |____/ \\_/\\_/ \\__,_|\\__, | |_| |_|\\__,_|_| |_|\\__,_|\\__, |\\___|_|
41
+ |___/ |___/
42
+ Local Security Agent v1.0
43
+ `);
44
+ }
45
+ // ============================================================================
46
+ // COMMANDS
47
+ // ============================================================================
48
+ async function startAgent() {
49
+ const apiKey = getFlag("key") || process.env.SWAGMANAGER_API_KEY;
50
+ if (!apiKey) {
51
+ console.error("Error: API key required. Use --key YOUR_KEY or set SWAGMANAGER_API_KEY");
52
+ console.error("");
53
+ console.error("Generate a key:");
54
+ console.error(" In Claude Code, run: mcp__swagmanager__api_keys({action: 'generate', name: 'local-agent'})");
55
+ process.exit(1);
56
+ }
57
+ const serverUrl = getFlag("server") || process.env.SWAGMANAGER_SERVER_URL;
58
+ printBanner();
59
+ const agentConfig = {
60
+ apiKey,
61
+ };
62
+ if (serverUrl)
63
+ agentConfig.serverUrl = serverUrl;
64
+ const agent = new LocalAgentConnection({
65
+ ...agentConfig,
66
+ onConnected: () => {
67
+ console.log("[whale agent] Connected and ready. Waiting for commands from Claude...");
68
+ console.log("[whale agent] Press Ctrl+C to disconnect.");
69
+ },
70
+ onDisconnected: (reason) => {
71
+ console.log(`[whale agent] Disconnected: ${reason}`);
72
+ },
73
+ onError: (err) => {
74
+ console.error(`[whale agent] Error: ${err.message}`);
75
+ },
76
+ onLog: (msg) => {
77
+ console.log(msg);
78
+ },
79
+ });
80
+ // Graceful shutdown
81
+ process.on("SIGINT", () => {
82
+ console.log("\n[whale agent] Shutting down...");
83
+ agent.disconnect();
84
+ process.exit(0);
85
+ });
86
+ process.on("SIGTERM", () => {
87
+ agent.disconnect();
88
+ process.exit(0);
89
+ });
90
+ try {
91
+ await agent.connect();
92
+ }
93
+ catch (err) {
94
+ console.error(`[whale agent] Failed to connect: ${err.message}`);
95
+ process.exit(1);
96
+ }
97
+ // Keep process alive
98
+ setInterval(() => { }, 60_000);
99
+ }
100
+ function showDiscover() {
101
+ printBanner();
102
+ console.log("Scanning for security tools...\n");
103
+ const tools = discoverTools();
104
+ if (tools.length === 0) {
105
+ console.log("No security tools found.\n");
106
+ console.log("Install some tools:");
107
+ console.log(" brew install nmap wireshark hashcat hydra aircrack-ng");
108
+ console.log(" pip install sqlmap");
109
+ return;
110
+ }
111
+ // Group by category
112
+ const byCategory = new Map();
113
+ for (const tool of tools) {
114
+ const cat = byCategory.get(tool.category) || [];
115
+ cat.push(tool);
116
+ byCategory.set(tool.category, cat);
117
+ }
118
+ const categoryNames = {
119
+ network_scanning: "Network Scanning",
120
+ packet_analysis: "Packet Analysis",
121
+ web_security: "Web Application Security",
122
+ exploitation: "Exploitation Frameworks",
123
+ password_cracking: "Password Cracking",
124
+ wireless: "Wireless Attacks",
125
+ recon: "Reconnaissance & OSINT",
126
+ post_exploitation: "Post-Exploitation",
127
+ forensics: "Forensics",
128
+ utility: "Utilities",
129
+ };
130
+ for (const [category, categoryTools] of byCategory) {
131
+ console.log(`\n ${categoryNames[category] || category}`);
132
+ console.log(" " + "-".repeat(40));
133
+ for (const tool of categoryTools) {
134
+ const version = tool.version ? ` (v${tool.version})` : "";
135
+ const running = tool.running ? " [RUNNING]" : "";
136
+ console.log(` ${tool.name.padEnd(20)} ${tool.path}${version}${running}`);
137
+ }
138
+ }
139
+ console.log(`\n Total: ${tools.length} tools found\n`);
140
+ }
141
+ function showInfo() {
142
+ const info = getSystemInfo();
143
+ console.log("\nSystem Information:");
144
+ console.log(" " + "-".repeat(40));
145
+ for (const [key, value] of Object.entries(info)) {
146
+ console.log(` ${key.padEnd(20)} ${value}`);
147
+ }
148
+ console.log("");
149
+ }
150
+ function showHelp() {
151
+ printBanner();
152
+ console.log("Usage:");
153
+ console.log(" whale agent start --key YOUR_API_KEY Connect to SwagManager cloud");
154
+ console.log(" whale agent discover List detected security tools");
155
+ console.log(" whale agent info Show system information");
156
+ console.log(" whale agent help Show this help");
157
+ console.log("");
158
+ console.log("Options:");
159
+ console.log(" --key, -k API key for authentication");
160
+ console.log(" --server Custom server URL (default: wss://whale-agent.fly.dev/agent/ws)");
161
+ console.log("");
162
+ console.log("Environment Variables:");
163
+ console.log(" SWAGMANAGER_API_KEY API key (alternative to --key)");
164
+ console.log(" SWAGMANAGER_SERVER_URL Server URL (alternative to --server)");
165
+ console.log("");
166
+ }
167
+ // ============================================================================
168
+ // MAIN
169
+ // ============================================================================
170
+ switch (command) {
171
+ case "start":
172
+ case "connect":
173
+ case "run":
174
+ startAgent().catch((err) => {
175
+ console.error("Fatal:", err.message);
176
+ process.exit(1);
177
+ });
178
+ break;
179
+ case "discover":
180
+ case "scan":
181
+ case "tools":
182
+ showDiscover();
183
+ break;
184
+ case "info":
185
+ case "status":
186
+ showInfo();
187
+ break;
188
+ case "help":
189
+ case "--help":
190
+ case "-h":
191
+ case undefined:
192
+ showHelp();
193
+ break;
194
+ default:
195
+ console.error(`Unknown command: ${command}`);
196
+ showHelp();
197
+ process.exit(1);
198
+ }
@@ -0,0 +1,35 @@
1
+ export interface MessagePayload {
2
+ sender_id: string;
3
+ sender_name?: string;
4
+ content: string;
5
+ content_type?: string;
6
+ metadata?: Record<string, unknown>;
7
+ conversation_id?: string;
8
+ }
9
+ export interface OutboundMessage {
10
+ id: string;
11
+ content: string;
12
+ sender_id: string;
13
+ sender_name?: string;
14
+ conversation_id?: string;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+ export interface AdapterStats {
18
+ messages_in: number;
19
+ messages_out: number;
20
+ last_message_at?: string;
21
+ errors: number;
22
+ }
23
+ export declare abstract class BaseAdapter {
24
+ abstract readonly type: string;
25
+ abstract readonly name: string;
26
+ protected stats: AdapterStats;
27
+ protected running: boolean;
28
+ abstract start(): Promise<void>;
29
+ abstract stop(): Promise<void>;
30
+ abstract sendMessage(msg: OutboundMessage): Promise<boolean>;
31
+ getStats(): AdapterStats;
32
+ isRunning(): boolean;
33
+ protected onInboundMessage?: (msg: MessagePayload) => Promise<void>;
34
+ setMessageHandler(handler: (msg: MessagePayload) => Promise<void>): void;
35
+ }
@@ -0,0 +1,10 @@
1
+ export class BaseAdapter {
2
+ stats = { messages_in: 0, messages_out: 0, errors: 0 };
3
+ running = false;
4
+ getStats() { return { ...this.stats }; }
5
+ isRunning() { return this.running; }
6
+ onInboundMessage;
7
+ setMessageHandler(handler) {
8
+ this.onInboundMessage = handler;
9
+ }
10
+ }
@@ -0,0 +1,29 @@
1
+ import { BaseAdapter, type OutboundMessage } from "./base.js";
2
+ export interface DiscordConfig {
3
+ bot_token: string;
4
+ allowed_channels?: string[];
5
+ allowed_guilds?: string[];
6
+ mention_required?: boolean;
7
+ max_message_length?: number;
8
+ }
9
+ export declare class DiscordAdapter extends BaseAdapter {
10
+ readonly type = "discord";
11
+ readonly name: string;
12
+ private config;
13
+ private ws;
14
+ private heartbeatTimer;
15
+ private sequence;
16
+ private sessionId;
17
+ private resumeUrl;
18
+ private botUserId;
19
+ private reconnectAttempts;
20
+ constructor(name: string, config: DiscordConfig);
21
+ start(): Promise<void>;
22
+ stop(): Promise<void>;
23
+ sendMessage(msg: OutboundMessage): Promise<boolean>;
24
+ private connectGateway;
25
+ private handleGatewayMessage;
26
+ private handleDispatch;
27
+ private handleMessage;
28
+ private scheduleReconnect;
29
+ }