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,332 @@
1
+ /**
2
+ * Local Agent Connection — maintains WebSocket connection to SwagManager cloud.
3
+ *
4
+ * Features:
5
+ * - Outbound WSS connection (no firewall issues)
6
+ * - Auto-reconnection with exponential backoff
7
+ * - Heartbeat/pong handling
8
+ * - Command routing to executor
9
+ */
10
+ import WebSocket from "ws";
11
+ import os from "node:os";
12
+ import { discoverTools } from "./discovery.js";
13
+ import { exec, getSystemInfo } from "./executor.js";
14
+ // ============================================================================
15
+ // CONFIG
16
+ // ============================================================================
17
+ const DEFAULT_SERVER_URL = "wss://whale-agent.fly.dev/agent/ws";
18
+ const MAX_RECONNECT_DELAY_MS = 60_000;
19
+ const INITIAL_RECONNECT_DELAY_MS = 1_000;
20
+ // ============================================================================
21
+ // AGENT CONNECTION
22
+ // ============================================================================
23
+ export class LocalAgentConnection {
24
+ ws = null;
25
+ config;
26
+ reconnectAttempts = 0;
27
+ reconnectTimer = null;
28
+ intentionalClose = false;
29
+ discoveredTools = [];
30
+ _agentId = null;
31
+ constructor(config) {
32
+ this.config = {
33
+ serverUrl: DEFAULT_SERVER_URL,
34
+ autoReconnect: true,
35
+ onConnected: () => { },
36
+ onDisconnected: () => { },
37
+ onError: () => { },
38
+ onLog: () => { },
39
+ ...config,
40
+ };
41
+ }
42
+ /**
43
+ * Connect to the SwagManager cloud gateway.
44
+ */
45
+ async connect() {
46
+ this.intentionalClose = false;
47
+ // Discover tools before connecting
48
+ this.log("Scanning for installed security tools...");
49
+ this.discoveredTools = discoverTools();
50
+ this.log(`Found ${this.discoveredTools.length} tools: ${this.discoveredTools.map(t => t.name).join(", ") || "none"}`);
51
+ this.log(`Connecting to ${this.config.serverUrl}...`);
52
+ return new Promise((resolve, reject) => {
53
+ try {
54
+ this.ws = new WebSocket(this.config.serverUrl, {
55
+ headers: {
56
+ "User-Agent": "swag-agent/1.0",
57
+ },
58
+ });
59
+ }
60
+ catch (err) {
61
+ reject(err);
62
+ return;
63
+ }
64
+ const connectTimeout = setTimeout(() => {
65
+ if (this.ws?.readyState !== WebSocket.OPEN) {
66
+ this.ws?.terminate();
67
+ reject(new Error("Connection timeout"));
68
+ }
69
+ }, 15_000);
70
+ this.ws.on("open", () => {
71
+ clearTimeout(connectTimeout);
72
+ this.reconnectAttempts = 0;
73
+ // Send auth message
74
+ this.send({
75
+ type: "auth",
76
+ api_key: this.config.apiKey,
77
+ capabilities: this.discoveredTools.map(t => t.name),
78
+ platform: process.platform,
79
+ hostname: os.hostname(),
80
+ version: "1.0.0",
81
+ });
82
+ });
83
+ this.ws.on("message", (raw) => {
84
+ let msg;
85
+ try {
86
+ msg = JSON.parse(raw.toString());
87
+ }
88
+ catch {
89
+ this.log("Received invalid JSON");
90
+ return;
91
+ }
92
+ this.handleMessage(msg, resolve);
93
+ });
94
+ this.ws.on("close", (code, reason) => {
95
+ clearTimeout(connectTimeout);
96
+ const reasonStr = reason?.toString() || `code ${code}`;
97
+ this.log(`Disconnected: ${reasonStr}`);
98
+ this.config.onDisconnected(reasonStr);
99
+ if (!this.intentionalClose && this.config.autoReconnect) {
100
+ this.scheduleReconnect();
101
+ }
102
+ });
103
+ this.ws.on("error", (err) => {
104
+ clearTimeout(connectTimeout);
105
+ this.config.onError(err);
106
+ if (this.ws?.readyState !== WebSocket.OPEN) {
107
+ reject(err);
108
+ }
109
+ });
110
+ });
111
+ }
112
+ /**
113
+ * Disconnect gracefully.
114
+ */
115
+ disconnect() {
116
+ this.intentionalClose = true;
117
+ if (this.reconnectTimer) {
118
+ clearTimeout(this.reconnectTimer);
119
+ this.reconnectTimer = null;
120
+ }
121
+ if (this.ws) {
122
+ this.ws.close(1000, "Agent shutting down");
123
+ this.ws = null;
124
+ }
125
+ }
126
+ /**
127
+ * Check if connected.
128
+ */
129
+ get connected() {
130
+ return this.ws?.readyState === WebSocket.OPEN;
131
+ }
132
+ // ============================================================================
133
+ // MESSAGE HANDLING
134
+ // ============================================================================
135
+ handleMessage(msg, connectResolve) {
136
+ switch (msg.type) {
137
+ case "authenticated":
138
+ this._agentId = msg.agent_id;
139
+ this.log(msg.message || "Authenticated");
140
+ this.config.onConnected();
141
+ connectResolve?.();
142
+ break;
143
+ case "error":
144
+ this.log(`Server error: ${msg.error}`);
145
+ if (msg.error?.includes("Authentication")) {
146
+ this.intentionalClose = true; // Don't reconnect on auth failure
147
+ }
148
+ break;
149
+ case "ping":
150
+ this.send({ type: "pong" });
151
+ break;
152
+ case "exec":
153
+ this.handleExec(msg);
154
+ break;
155
+ case "tool_exec":
156
+ this.handleToolExec(msg);
157
+ break;
158
+ case "discover":
159
+ this.handleDiscover(msg);
160
+ break;
161
+ case "shutdown":
162
+ this.log("Server requested shutdown — will reconnect");
163
+ // Do NOT set intentionalClose — server restarts (deploys) should auto-reconnect
164
+ this.ws?.close(1000, "Server shutdown");
165
+ break;
166
+ default:
167
+ this.log(`Unknown message type: ${msg.type}`);
168
+ }
169
+ }
170
+ async handleExec(msg) {
171
+ const { request_id, command, session_id, timeout } = msg;
172
+ if (!command) {
173
+ this.sendResult(request_id, { success: false, error: "No command provided" });
174
+ return;
175
+ }
176
+ this.log(`Executing: ${command.substring(0, 80)}${command.length > 80 ? "..." : ""}`);
177
+ try {
178
+ const result = await exec(command, { session_id, timeout });
179
+ this.sendResult(request_id, result);
180
+ }
181
+ catch (err) {
182
+ this.sendResult(request_id, {
183
+ success: false,
184
+ error: err.message || "Execution failed",
185
+ });
186
+ }
187
+ }
188
+ async handleToolExec(msg) {
189
+ const { request_id, tool, args, timeout } = msg;
190
+ this.log(`Tool exec: ${tool}`);
191
+ // Route to tool-specific handlers or fallback to generic exec
192
+ try {
193
+ let result;
194
+ switch (tool) {
195
+ case "tshark": {
196
+ const iface = args.interface || (process.platform === "darwin" ? "en0" : "eth0");
197
+ const filter = args.filter ? `-f "${args.filter}"` : "";
198
+ const count = args.count || 100;
199
+ const cmd = `tshark -i ${iface} ${filter} -c ${count} 2>&1`;
200
+ result = await exec(cmd, { timeout: timeout || 60000 });
201
+ break;
202
+ }
203
+ case "burpsuite": {
204
+ const port = args.port || 1337;
205
+ const action = args.action || "status";
206
+ if (action === "status") {
207
+ result = await exec(`curl -s http://localhost:${port}/v0.1/ 2>&1 || echo "Burp Suite not running on port ${port}"`, { timeout: 5000 });
208
+ }
209
+ else if (action === "scan") {
210
+ result = await exec(`curl -s -X POST http://localhost:${port}/v0.1/scan -H "Content-Type: application/json" -d '${JSON.stringify({ urls: [args.target_url] })}' 2>&1`, { timeout: 10000 });
211
+ }
212
+ else {
213
+ result = { success: false, error: `Unknown burpsuite action: ${action}` };
214
+ }
215
+ break;
216
+ }
217
+ case "zap": {
218
+ const port = args.port || 8090;
219
+ const action = args.action || "status";
220
+ const apiKey = args.api_key || "";
221
+ const base = `http://localhost:${port}/JSON`;
222
+ if (action === "status") {
223
+ result = await exec(`curl -s "${base}/core/view/version/?apikey=${apiKey}" 2>&1`, { timeout: 5000 });
224
+ }
225
+ else if (action === "spider") {
226
+ result = await exec(`curl -s "${base}/spider/action/scan/?apikey=${apiKey}&url=${encodeURIComponent(args.target_url || "")}" 2>&1`, { timeout: 10000 });
227
+ }
228
+ else if (action === "active_scan") {
229
+ result = await exec(`curl -s "${base}/ascan/action/scan/?apikey=${apiKey}&url=${encodeURIComponent(args.target_url || "")}" 2>&1`, { timeout: 10000 });
230
+ }
231
+ else {
232
+ result = { success: false, error: `Unknown zap action: ${action}` };
233
+ }
234
+ break;
235
+ }
236
+ case "aircrack-ng": {
237
+ const action = args.action || "help";
238
+ if (action === "scan") {
239
+ const iface = args.interface || "wlan0";
240
+ result = await exec(`airmon-ng start ${iface} && airodump-ng ${iface}mon --write /tmp/airodump --output-format csv -w 10 2>&1`, { timeout: timeout || 30000 });
241
+ }
242
+ else if (action === "crack") {
243
+ const capFile = args.cap_file;
244
+ const wordlist = args.wordlist || "/usr/share/wordlists/rockyou.txt";
245
+ if (!capFile) {
246
+ result = { success: false, error: "cap_file is required" };
247
+ }
248
+ else {
249
+ result = await exec(`aircrack-ng -w ${wordlist} ${capFile} 2>&1`, { timeout: timeout || 300000 });
250
+ }
251
+ }
252
+ else {
253
+ result = await exec(`aircrack-ng --help 2>&1`, { timeout: 5000 });
254
+ }
255
+ break;
256
+ }
257
+ case "netdiscover": {
258
+ const iface = args.interface || (process.platform === "darwin" ? "en0" : "eth0");
259
+ const range = args.range || "";
260
+ const rangeFlag = range ? `-r ${range}` : "";
261
+ result = await exec(`netdiscover -i ${iface} ${rangeFlag} -P -N 2>&1 | head -50`, { timeout: timeout || 30000 });
262
+ break;
263
+ }
264
+ default:
265
+ // Generic: try to run as command
266
+ result = await exec(`${tool} ${args.args || ""} 2>&1`, { timeout: timeout || 30000 });
267
+ }
268
+ this.sendResult(request_id, result);
269
+ }
270
+ catch (err) {
271
+ this.sendResult(request_id, {
272
+ success: false,
273
+ error: err.message || `Tool ${tool} failed`,
274
+ });
275
+ }
276
+ }
277
+ handleDiscover(msg) {
278
+ const tools = discoverTools();
279
+ this.discoveredTools = tools;
280
+ // Update capabilities on the server
281
+ this.send({
282
+ type: "tools",
283
+ tools: tools.map(t => t.name),
284
+ });
285
+ // Also send as result
286
+ this.sendResult(msg.request_id, {
287
+ success: true,
288
+ data: {
289
+ tools: tools.map(t => ({
290
+ name: t.name,
291
+ path: t.path,
292
+ version: t.version,
293
+ category: t.category,
294
+ running: t.running,
295
+ })),
296
+ system: getSystemInfo(),
297
+ },
298
+ });
299
+ }
300
+ // ============================================================================
301
+ // HELPERS
302
+ // ============================================================================
303
+ send(data) {
304
+ if (this.ws?.readyState === WebSocket.OPEN) {
305
+ this.ws.send(JSON.stringify(data));
306
+ }
307
+ }
308
+ sendResult(requestId, result) {
309
+ this.send({
310
+ type: "result",
311
+ request_id: requestId,
312
+ ...result,
313
+ });
314
+ }
315
+ scheduleReconnect() {
316
+ this.reconnectAttempts++;
317
+ const delay = Math.min(INITIAL_RECONNECT_DELAY_MS * Math.pow(2, this.reconnectAttempts - 1), MAX_RECONNECT_DELAY_MS);
318
+ this.log(`Reconnecting in ${Math.round(delay / 1000)}s (attempt ${this.reconnectAttempts})...`);
319
+ this.reconnectTimer = setTimeout(async () => {
320
+ try {
321
+ await this.connect();
322
+ }
323
+ catch (err) {
324
+ this.log(`Reconnect failed: ${err.message}`);
325
+ // connect() will trigger close event which will schedule another reconnect
326
+ }
327
+ }, delay);
328
+ }
329
+ log(msg) {
330
+ this.config.onLog(`[swag-agent] ${msg}`);
331
+ }
332
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Local Tool Discovery — auto-detect security tools installed on the user's machine.
3
+ *
4
+ * Scans PATH for known security tools and checks for running services (Burp, ZAP).
5
+ * Returns a capabilities list that the gateway uses for routing.
6
+ */
7
+ export interface DiscoveredTool {
8
+ name: string;
9
+ path: string;
10
+ version?: string;
11
+ category: string;
12
+ running?: boolean;
13
+ }
14
+ export declare function discoverTools(): DiscoveredTool[];
15
+ /**
16
+ * Get just the tool names (for capabilities list).
17
+ */
18
+ export declare function discoverToolNames(): string[];
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Local Tool Discovery — auto-detect security tools installed on the user's machine.
3
+ *
4
+ * Scans PATH for known security tools and checks for running services (Burp, ZAP).
5
+ * Returns a capabilities list that the gateway uses for routing.
6
+ */
7
+ import { execSync } from "node:child_process";
8
+ const TOOL_SPECS = [
9
+ // Network Scanning
10
+ { name: "nmap", binaries: ["nmap"], category: "network_scanning", versionFlag: "--version" },
11
+ { name: "masscan", binaries: ["masscan"], category: "network_scanning", versionFlag: "--version" },
12
+ { name: "netdiscover", binaries: ["netdiscover"], category: "network_scanning" },
13
+ // Packet Analysis
14
+ { name: "tshark", binaries: ["tshark"], category: "packet_analysis", versionFlag: "--version" },
15
+ { name: "wireshark", binaries: ["wireshark"], category: "packet_analysis", versionFlag: "--version" },
16
+ { name: "tcpdump", binaries: ["tcpdump"], category: "packet_analysis", versionFlag: "--version" },
17
+ // Web Application Security
18
+ { name: "sqlmap", binaries: ["sqlmap"], category: "web_security", versionFlag: "--version" },
19
+ { name: "gobuster", binaries: ["gobuster"], category: "web_security", versionFlag: "version" },
20
+ { name: "nikto", binaries: ["nikto"], category: "web_security", versionFlag: "-Version" },
21
+ { name: "dirb", binaries: ["dirb"], category: "web_security" },
22
+ { name: "ffuf", binaries: ["ffuf"], category: "web_security", versionFlag: "-V" },
23
+ {
24
+ name: "burpsuite",
25
+ binaries: ["burpsuite", "BurpSuiteCommunity", "BurpSuitePro"],
26
+ category: "web_security",
27
+ serviceCheck: () => checkPort(8080) || checkPort(1337),
28
+ },
29
+ {
30
+ name: "zap",
31
+ binaries: ["zaproxy", "zap", "zap.sh"],
32
+ category: "web_security",
33
+ serviceCheck: () => checkPort(8090),
34
+ },
35
+ // Exploitation
36
+ { name: "metasploit", binaries: ["msfconsole", "msfvenom"], category: "exploitation", versionFlag: "--version" },
37
+ { name: "setoolkit", binaries: ["setoolkit", "se-toolkit"], category: "exploitation" },
38
+ // Password Cracking
39
+ { name: "john", binaries: ["john"], category: "password_cracking", versionFlag: "--help" },
40
+ { name: "hashcat", binaries: ["hashcat"], category: "password_cracking", versionFlag: "--version" },
41
+ { name: "hydra", binaries: ["hydra"], category: "password_cracking", versionFlag: "-h" },
42
+ // Wireless
43
+ { name: "aircrack-ng", binaries: ["aircrack-ng"], category: "wireless", versionFlag: "--help" },
44
+ { name: "airodump-ng", binaries: ["airodump-ng"], category: "wireless" },
45
+ { name: "aireplay-ng", binaries: ["aireplay-ng"], category: "wireless" },
46
+ { name: "wifite", binaries: ["wifite", "wifite2"], category: "wireless" },
47
+ // Reconnaissance
48
+ { name: "recon-ng", binaries: ["recon-ng"], category: "recon" },
49
+ { name: "maltego", binaries: ["maltego"], category: "recon" },
50
+ { name: "theharvester", binaries: ["theHarvester", "theharvester"], category: "recon" },
51
+ { name: "amass", binaries: ["amass"], category: "recon", versionFlag: "version" },
52
+ { name: "subfinder", binaries: ["subfinder"], category: "recon", versionFlag: "-version" },
53
+ // Post-Exploitation
54
+ { name: "responder", binaries: ["responder", "Responder.py"], category: "post_exploitation" },
55
+ { name: "impacket", binaries: ["impacket-smbclient", "impacket-secretsdump"], category: "post_exploitation" },
56
+ { name: "evil-winrm", binaries: ["evil-winrm"], category: "post_exploitation" },
57
+ { name: "chisel", binaries: ["chisel"], category: "post_exploitation" },
58
+ // Forensics
59
+ { name: "autopsy", binaries: ["autopsy"], category: "forensics" },
60
+ { name: "volatility", binaries: ["vol.py", "volatility3", "vol3"], category: "forensics" },
61
+ { name: "binwalk", binaries: ["binwalk"], category: "forensics", versionFlag: "--help" },
62
+ // Misc
63
+ { name: "curl", binaries: ["curl"], category: "utility", versionFlag: "--version" },
64
+ { name: "wget", binaries: ["wget"], category: "utility", versionFlag: "--version" },
65
+ { name: "python3", binaries: ["python3"], category: "utility", versionFlag: "--version" },
66
+ { name: "docker", binaries: ["docker"], category: "utility", versionFlag: "--version" },
67
+ ];
68
+ export function discoverTools() {
69
+ const discovered = [];
70
+ for (const spec of TOOL_SPECS) {
71
+ for (const bin of spec.binaries) {
72
+ const path = which(bin);
73
+ if (!path)
74
+ continue;
75
+ const tool = {
76
+ name: spec.name,
77
+ path,
78
+ category: spec.category,
79
+ };
80
+ // Try to get version
81
+ if (spec.versionFlag) {
82
+ try {
83
+ const output = execSync(`${bin} ${spec.versionFlag} 2>&1`, {
84
+ timeout: 5000,
85
+ encoding: "utf8",
86
+ stdio: ["pipe", "pipe", "pipe"],
87
+ });
88
+ // Extract version number from first line
89
+ const match = output.match(/(\d+\.\d+[\.\d]*)/);
90
+ if (match)
91
+ tool.version = match[1];
92
+ }
93
+ catch {
94
+ // Tool exists but version check failed — still valid
95
+ }
96
+ }
97
+ // Check if running as service
98
+ if (spec.serviceCheck) {
99
+ try {
100
+ tool.running = spec.serviceCheck();
101
+ }
102
+ catch {
103
+ tool.running = false;
104
+ }
105
+ }
106
+ discovered.push(tool);
107
+ break; // Found one binary for this tool, move to next
108
+ }
109
+ }
110
+ return discovered;
111
+ }
112
+ /**
113
+ * Get just the tool names (for capabilities list).
114
+ */
115
+ export function discoverToolNames() {
116
+ return discoverTools().map(t => t.name);
117
+ }
118
+ // ============================================================================
119
+ // HELPERS
120
+ // ============================================================================
121
+ function which(binary) {
122
+ try {
123
+ const result = execSync(`which ${binary} 2>/dev/null`, {
124
+ timeout: 3000,
125
+ encoding: "utf8",
126
+ stdio: ["pipe", "pipe", "pipe"],
127
+ }).trim();
128
+ return result || null;
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
134
+ function checkPort(port) {
135
+ try {
136
+ execSync(`lsof -i :${port} -sTCP:LISTEN 2>/dev/null | head -1`, {
137
+ timeout: 3000,
138
+ encoding: "utf8",
139
+ stdio: ["pipe", "pipe", "pipe"],
140
+ });
141
+ return true;
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
@@ -0,0 +1,34 @@
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
+ export interface ExecResult {
11
+ success: boolean;
12
+ stdout: string;
13
+ stderr: string;
14
+ exit_code: number;
15
+ killed: boolean;
16
+ cwd: string;
17
+ duration_ms: number;
18
+ }
19
+ export declare function exec(command: string, options?: {
20
+ session_id?: string;
21
+ timeout?: number;
22
+ }): Promise<ExecResult>;
23
+ export declare function execBackground(command: string, sessionId?: string): {
24
+ job_id: string;
25
+ };
26
+ export declare function getJobStatus(jobId: string, tail?: number): Record<string, unknown> | null;
27
+ export declare function killJob(jobId: string): boolean;
28
+ export declare function listJobs(): Array<Record<string, unknown>>;
29
+ export declare function listSessions(): Array<{
30
+ session_id: string;
31
+ cwd: string;
32
+ }>;
33
+ export declare function resetSessions(): void;
34
+ export declare function getSystemInfo(): Record<string, unknown>;