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,10 @@
1
+ /**
2
+ * Shell Execution — run_command and background process tools
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { ToolResult } from "../../../shared/types.js";
7
+ export declare function runCommand(input: Record<string, unknown>): Promise<ToolResult>;
8
+ export declare function bashOutput(input: Record<string, unknown>): ToolResult;
9
+ export declare function killShell(input: Record<string, unknown>): ToolResult;
10
+ export declare function listShellsFn(): ToolResult;
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Shell Execution — run_command and background process tools
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { join } from "path";
7
+ import { spawn } from "child_process";
8
+ import { homedir } from "os";
9
+ import { spawnBackground, readProcessOutput, killProcess, listProcesses } from "../background-processes.js";
10
+ import { getGlobalEmitter } from "../agent-events.js";
11
+ import { sandboxCommand, cleanupSandbox } from "../sandbox.js";
12
+ import { debugLog } from "../debug-log.js";
13
+ function resolvePath(p) {
14
+ if (p.startsWith("~/"))
15
+ return join(homedir(), p.slice(2));
16
+ return p;
17
+ }
18
+ export async function runCommand(input) {
19
+ let command = input.command;
20
+ const cwd = input.working_directory ? resolvePath(input.working_directory) : undefined;
21
+ const timeout = Math.min(input.timeout || 30000, 300000);
22
+ const background = input.run_in_background;
23
+ const description = input.description;
24
+ debugLog("tools", `run_command: ${description || command.slice(0, 80)}`, { cwd, timeout, background });
25
+ // UX guardrail only — the sandbox (macOS) is the real security boundary.
26
+ // This catches obvious destructive commands before they reach the sandbox.
27
+ if (command.length > 10000) {
28
+ return { success: false, output: "Command too long (max 10000 chars)" };
29
+ }
30
+ const DANGEROUS_PATTERNS = [
31
+ /\brm\s+(-[a-z]*f[a-z]*\s+)?(-[a-z]*r[a-z]*\s+)?(\/|~)/i,
32
+ /\brm\s+(-[a-z]*r[a-z]*\s+)?(-[a-z]*f[a-z]*\s+)?(\/|~)/i,
33
+ /\bmkfs\b/i,
34
+ /\bdd\s+.*\bif=/i,
35
+ />\s*\/dev\/sd/,
36
+ /:\(\)\s*\{.*\|.*&\s*\}\s*;/,
37
+ /\bchmod\s+(-[a-z]*R[a-z]*\s+)?777\s+\//i,
38
+ /\bchown\s+(-[a-z]*R[a-z]*\s+).*\//i,
39
+ /\bcurl\b.*\|\s*(ba)?sh\b/i,
40
+ /\bwget\b.*\|\s*(ba)?sh\b/i,
41
+ /\b(python|perl|ruby|node)\s+-e\s+.*\b(system|exec|spawn)\b/i,
42
+ /base64\s+(-d|--decode)\s*\|\s*(ba)?sh/i,
43
+ ];
44
+ const command_lower = command.toLowerCase().replace(/\s+/g, " ");
45
+ if (DANGEROUS_PATTERNS.some((p) => p.test(command_lower))) {
46
+ return { success: false, output: "Command blocked for safety" };
47
+ }
48
+ // Apply sandbox wrapping (macOS only)
49
+ let sandboxProfilePath = null;
50
+ {
51
+ const effectiveCwd = cwd || process.cwd();
52
+ const sandboxResult = sandboxCommand(command, effectiveCwd);
53
+ command = sandboxResult.wrapped;
54
+ sandboxProfilePath = sandboxResult.profilePath;
55
+ }
56
+ // Background mode — spawn detached, validate, return with status
57
+ if (background) {
58
+ const result = await spawnBackground(command, { cwd, timeout: 600_000, description: input.description });
59
+ return { success: result.status === "running", output: result.message };
60
+ }
61
+ // Foreground async — spawn + stream output via events
62
+ return new Promise((resolve) => {
63
+ const stdout = [];
64
+ const stderr = [];
65
+ let killed = false;
66
+ const child = spawn(command, [], {
67
+ shell: true,
68
+ cwd,
69
+ env: { ...process.env, FORCE_COLOR: "0" },
70
+ stdio: ["pipe", "pipe", "pipe"],
71
+ });
72
+ const emitter = getGlobalEmitter();
73
+ child.stdout?.on("data", (data) => {
74
+ const text = data.toString();
75
+ stdout.push(text);
76
+ // Emit live output for UI streaming
77
+ for (const line of text.split("\n")) {
78
+ if (line.trim())
79
+ emitter.emitToolOutput("run_command", line);
80
+ }
81
+ });
82
+ child.stderr?.on("data", (data) => {
83
+ const text = data.toString();
84
+ stderr.push(text);
85
+ for (const line of text.split("\n")) {
86
+ if (line.trim())
87
+ emitter.emitToolOutput("run_command", line);
88
+ }
89
+ });
90
+ // Timeout kill
91
+ const timer = setTimeout(() => {
92
+ if (!killed) {
93
+ killed = true;
94
+ child.kill("SIGTERM");
95
+ setTimeout(() => child.kill("SIGKILL"), 3000);
96
+ }
97
+ }, timeout);
98
+ child.on("exit", (code) => {
99
+ clearTimeout(timer);
100
+ cleanupSandbox(sandboxProfilePath);
101
+ const output = stdout.join("") + (stderr.length > 0 ? "\n" + stderr.join("") : "");
102
+ if (killed) {
103
+ resolve({ success: false, output: `Command timed out after ${timeout}ms.\n${output}`.slice(0, 5000) });
104
+ }
105
+ else if (code === 0) {
106
+ let out = output || "(no output)";
107
+ if (out.length > 500_000) {
108
+ out = out.slice(0, 500_000) + `\n\n... (safety truncated — ${output.length.toLocaleString()} chars total)`;
109
+ }
110
+ resolve({ success: true, output: out });
111
+ }
112
+ else {
113
+ resolve({ success: false, output: `Exit code ${code ?? "?"}:\n${output}`.slice(0, 5000) });
114
+ }
115
+ });
116
+ child.on("error", (err) => {
117
+ clearTimeout(timer);
118
+ cleanupSandbox(sandboxProfilePath);
119
+ resolve({ success: false, output: `Spawn error: ${err.message}` });
120
+ });
121
+ });
122
+ }
123
+ // Background tool handlers
124
+ export function bashOutput(input) {
125
+ const id = input.bash_id;
126
+ const filter = input.filter;
127
+ const result = readProcessOutput(id, { filter });
128
+ if ("error" in result)
129
+ return { success: false, output: result.error };
130
+ const statusIcon = result.status === "running" ? "\u25CF" : result.status === "completed" ? "\u2713" : "\u2715";
131
+ const statusColor = result.status === "running" ? "running" : result.status === "completed" ? "completed" : "failed";
132
+ const lines = [];
133
+ lines.push(`${statusIcon} Process ${id} — ${statusColor}`);
134
+ if (result.exitCode !== undefined)
135
+ lines.push(` Exit code: ${result.exitCode}`);
136
+ if (result.newOutput) {
137
+ lines.push(` Output:`);
138
+ lines.push(result.newOutput);
139
+ }
140
+ if (result.newErrors) {
141
+ lines.push(` Errors:`);
142
+ lines.push(result.newErrors);
143
+ }
144
+ if (!result.newOutput && !result.newErrors)
145
+ lines.push(" (no new output since last check)");
146
+ return { success: true, output: lines.join("\n") };
147
+ }
148
+ export function killShell(input) {
149
+ const id = (input.shell_id || input.bash_id);
150
+ const result = killProcess(id);
151
+ return { success: result.success, output: result.message };
152
+ }
153
+ export function listShellsFn() {
154
+ const procs = listProcesses();
155
+ if (procs.length === 0)
156
+ return { success: true, output: "No background processes." };
157
+ const lines = [`${procs.length} background process${procs.length !== 1 ? "es" : ""}:`, ""];
158
+ for (const p of procs) {
159
+ const icon = p.status === "running" ? "\u25CF" : p.status === "completed" ? "\u2713" : "\u2715";
160
+ lines.push(` ${icon} ${p.id} ${p.status} ${p.runtime}`);
161
+ lines.push(` ${p.command}`);
162
+ if (p.pid)
163
+ lines.push(` PID: ${p.pid}`);
164
+ lines.push(` stdout: ${p.outputLines} lines stderr: ${p.errorLines} lines`);
165
+ lines.push("");
166
+ }
167
+ return { success: true, output: lines.join("\n") };
168
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Task Manager — action-based CRUD task tracking with IDs and dependencies
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ * All consumers should import from local-tools.ts (re-export facade).
6
+ */
7
+ interface TaskItem {
8
+ id: string;
9
+ subject: string;
10
+ description: string;
11
+ status: "pending" | "in_progress" | "completed";
12
+ activeForm?: string;
13
+ owner?: string;
14
+ metadata?: Record<string, unknown>;
15
+ blocks: string[];
16
+ blockedBy: string[];
17
+ createdAt: string;
18
+ }
19
+ import { ToolResult } from "../../../shared/types.js";
20
+ declare let taskState: TaskItem[];
21
+ export declare function tasksTool(input: Record<string, unknown>): ToolResult;
22
+ /** Load tasks from disk for a session */
23
+ export declare function loadTodos(sessionId: string): void;
24
+ /** Link tasks to a session for persistence */
25
+ export declare function setTodoSessionId(id: string): void;
26
+ /** Get current task state (for UI display) */
27
+ export declare function getTodoState(): typeof taskState;
28
+ export {};
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Task Manager — action-based CRUD task tracking with IDs and dependencies
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ * All consumers should import from local-tools.ts (re-export facade).
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
8
+ import { join } from "path";
9
+ import { homedir } from "os";
10
+ // ============================================================================
11
+ // STATE
12
+ // ============================================================================
13
+ let taskState = [];
14
+ let taskCounter = 0;
15
+ let todoSessionId = null;
16
+ const TODOS_DIR = join(homedir(), ".swagmanager", "todos");
17
+ // ============================================================================
18
+ // TOOL IMPLEMENTATION
19
+ // ============================================================================
20
+ export function tasksTool(input) {
21
+ const action = input.action;
22
+ if (!action)
23
+ return { success: false, output: "action is required (create/update/list/get)" };
24
+ switch (action) {
25
+ case "create": {
26
+ const subject = input.subject;
27
+ const description = input.description;
28
+ if (!subject || !description)
29
+ return { success: false, output: "subject and description required for create" };
30
+ taskCounter++;
31
+ const task = {
32
+ id: String(taskCounter),
33
+ subject,
34
+ description,
35
+ status: "pending",
36
+ activeForm: input.activeForm,
37
+ owner: input.owner,
38
+ metadata: input.metadata,
39
+ blocks: [],
40
+ blockedBy: [],
41
+ createdAt: new Date().toISOString(),
42
+ };
43
+ taskState.push(task);
44
+ persistTasks();
45
+ return { success: true, output: `Created task #${task.id}: ${subject}` };
46
+ }
47
+ case "update": {
48
+ const taskId = input.taskId;
49
+ if (!taskId)
50
+ return { success: false, output: "taskId required for update" };
51
+ const task = taskState.find((t) => t.id === taskId);
52
+ if (!task)
53
+ return { success: false, output: `Task #${taskId} not found` };
54
+ const newStatus = input.status;
55
+ // Handle deletion
56
+ if (newStatus === "deleted") {
57
+ // Remove from other tasks' blocks/blockedBy
58
+ for (const t of taskState) {
59
+ t.blocks = t.blocks.filter((id) => id !== taskId);
60
+ t.blockedBy = t.blockedBy.filter((id) => id !== taskId);
61
+ }
62
+ taskState = taskState.filter((t) => t.id !== taskId);
63
+ persistTasks();
64
+ return { success: true, output: `Deleted task #${taskId}` };
65
+ }
66
+ if (newStatus && ["pending", "in_progress", "completed"].includes(newStatus)) {
67
+ task.status = newStatus;
68
+ }
69
+ if (input.subject_update)
70
+ task.subject = input.subject_update;
71
+ if (input.description !== undefined)
72
+ task.description = input.description;
73
+ if (input.activeForm !== undefined)
74
+ task.activeForm = input.activeForm;
75
+ if (input.owner !== undefined)
76
+ task.owner = input.owner;
77
+ if (input.metadata) {
78
+ task.metadata = { ...(task.metadata || {}), ...input.metadata };
79
+ // Remove null keys
80
+ for (const [k, v] of Object.entries(task.metadata)) {
81
+ if (v === null)
82
+ delete task.metadata[k];
83
+ }
84
+ }
85
+ // Dependency management
86
+ const addBlocks = input.addBlocks;
87
+ const addBlockedBy = input.addBlockedBy;
88
+ if (addBlocks) {
89
+ for (const id of addBlocks) {
90
+ if (!task.blocks.includes(id))
91
+ task.blocks.push(id);
92
+ const target = taskState.find((t) => t.id === id);
93
+ if (target && !target.blockedBy.includes(taskId))
94
+ target.blockedBy.push(taskId);
95
+ }
96
+ }
97
+ if (addBlockedBy) {
98
+ for (const id of addBlockedBy) {
99
+ if (!task.blockedBy.includes(id))
100
+ task.blockedBy.push(id);
101
+ const target = taskState.find((t) => t.id === id);
102
+ if (target && !target.blocks.includes(taskId))
103
+ target.blocks.push(taskId);
104
+ }
105
+ }
106
+ persistTasks();
107
+ return { success: true, output: `Updated task #${taskId}: ${task.subject} [${task.status}]` };
108
+ }
109
+ case "list": {
110
+ if (taskState.length === 0)
111
+ return { success: true, output: "No tasks." };
112
+ const icon = { pending: "[ ]", in_progress: "[~]", completed: "[x]" };
113
+ const lines = taskState.map((t) => {
114
+ let line = `#${t.id}. ${icon[t.status] || "[ ]"} ${t.subject}`;
115
+ if (t.owner)
116
+ line += ` (${t.owner})`;
117
+ // Show only open blockers
118
+ const openBlockers = t.blockedBy.filter((id) => {
119
+ const blocker = taskState.find((b) => b.id === id);
120
+ return blocker && blocker.status !== "completed";
121
+ });
122
+ if (openBlockers.length > 0)
123
+ line += ` <- blocked by #${openBlockers.join(", #")}`;
124
+ return line;
125
+ });
126
+ const counts = {
127
+ pending: taskState.filter((t) => t.status === "pending").length,
128
+ in_progress: taskState.filter((t) => t.status === "in_progress").length,
129
+ completed: taskState.filter((t) => t.status === "completed").length,
130
+ };
131
+ return {
132
+ success: true,
133
+ output: `Tasks (${taskState.length}: ${counts.completed} done, ${counts.in_progress} active, ${counts.pending} pending):\n${lines.join("\n")}`,
134
+ };
135
+ }
136
+ case "get": {
137
+ const taskId = input.taskId;
138
+ if (!taskId)
139
+ return { success: false, output: "taskId required for get" };
140
+ const task = taskState.find((t) => t.id === taskId);
141
+ if (!task)
142
+ return { success: false, output: `Task #${taskId} not found` };
143
+ const details = [
144
+ `# Task #${task.id}: ${task.subject}`,
145
+ `Status: ${task.status}`,
146
+ task.owner ? `Owner: ${task.owner}` : null,
147
+ task.activeForm ? `Active form: ${task.activeForm}` : null,
148
+ `Created: ${task.createdAt}`,
149
+ task.blocks.length ? `Blocks: #${task.blocks.join(", #")}` : null,
150
+ task.blockedBy.length ? `Blocked by: #${task.blockedBy.join(", #")}` : null,
151
+ task.metadata ? `Metadata: ${JSON.stringify(task.metadata)}` : null,
152
+ "",
153
+ task.description,
154
+ ].filter(Boolean).join("\n");
155
+ return { success: true, output: details };
156
+ }
157
+ default:
158
+ return { success: false, output: `Unknown action: ${action}. Use create/update/list/get.` };
159
+ }
160
+ }
161
+ /** Persist tasks to disk (fire-and-forget) */
162
+ function persistTasks() {
163
+ if (!todoSessionId)
164
+ return;
165
+ try {
166
+ if (!existsSync(TODOS_DIR))
167
+ mkdirSync(TODOS_DIR, { recursive: true });
168
+ writeFileSync(join(TODOS_DIR, `${todoSessionId}.json`), JSON.stringify({ tasks: taskState, counter: taskCounter }, null, 2), "utf-8");
169
+ }
170
+ catch { /* best effort */ }
171
+ }
172
+ /** Load tasks from disk for a session */
173
+ export function loadTodos(sessionId) {
174
+ const path = join(TODOS_DIR, `${sessionId}.json`);
175
+ if (!existsSync(path))
176
+ return;
177
+ try {
178
+ const raw = JSON.parse(readFileSync(path, "utf-8"));
179
+ // Support both old format (array) and new format ({tasks, counter})
180
+ if (Array.isArray(raw)) {
181
+ // Migrate old todo format
182
+ taskState = raw.map((t, i) => ({
183
+ id: t.id || String(i + 1),
184
+ subject: t.content || t.subject || "Untitled",
185
+ description: t.content || t.description || "",
186
+ status: t.status || "pending",
187
+ activeForm: t.activeForm,
188
+ blocks: t.blocks || [],
189
+ blockedBy: t.blockedBy || [],
190
+ createdAt: t.createdAt || new Date().toISOString(),
191
+ }));
192
+ taskCounter = taskState.length;
193
+ }
194
+ else if (raw.tasks) {
195
+ taskState = raw.tasks;
196
+ taskCounter = raw.counter || taskState.length;
197
+ }
198
+ todoSessionId = sessionId;
199
+ }
200
+ catch { /* skip corrupted */ }
201
+ }
202
+ /** Link tasks to a session for persistence */
203
+ export function setTodoSessionId(id) {
204
+ todoSessionId = id;
205
+ }
206
+ /** Get current task state (for UI display) */
207
+ export function getTodoState() {
208
+ return taskState;
209
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Web Tools — web_fetch and web_search implementations
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { ToolResult } from "../../../shared/types.js";
7
+ export declare function isBlockedUrl(urlStr: string): boolean;
8
+ export declare function webFetch(input: Record<string, unknown>): Promise<ToolResult>;
9
+ /** Enhanced HTML -> readable text/markdown converter */
10
+ export declare function htmlToText(html: string): string;
11
+ export declare function webSearch(input: Record<string, unknown>): Promise<ToolResult>;