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,97 @@
1
+ /**
2
+ * Agent Worker Base — shared utilities for subagent.ts and teammate.ts
3
+ *
4
+ * Extracts the common plumbing:
5
+ * - API calling (auth, build request, call proxy, collect stream, convert response)
6
+ * - Tool execution with loop detection, truncation, and result formatting
7
+ * - Token tracking
8
+ *
9
+ * Both subagent and teammate keep their own types, system prompts, and lifecycle logic.
10
+ * This module provides composable functions, NOT a class hierarchy.
11
+ */
12
+ import type Anthropic from "@anthropic-ai/sdk";
13
+ import { LoopDetector } from "../../shared/agent-core.js";
14
+ import type { ContextProfile, StreamResult } from "../../shared/types.js";
15
+ /** Unified response from an API call — used by both subagent and teammate */
16
+ export interface AgentAPIResponse {
17
+ content: Anthropic.ContentBlock[];
18
+ usage: {
19
+ input_tokens: number;
20
+ output_tokens: number;
21
+ };
22
+ stop_reason: string;
23
+ }
24
+ /** Options for callAgentAPI */
25
+ export interface AgentAPIOptions {
26
+ modelId: string;
27
+ contextProfile: ContextProfile;
28
+ systemPrompt: string;
29
+ messages: Anthropic.MessageParam[];
30
+ tools: Anthropic.Tool[];
31
+ thinkingEnabled?: boolean;
32
+ maxOutputTokens?: number;
33
+ timeoutMs?: number;
34
+ /** If true, add cache_control to last tool */
35
+ cacheLastTool?: boolean;
36
+ }
37
+ /** Result of executing a single tool */
38
+ export interface ToolExecResult {
39
+ success: boolean;
40
+ output: string;
41
+ }
42
+ /** Callbacks for tool execution progress */
43
+ export interface ToolExecCallbacks {
44
+ onToolStart?: (toolName: string, input: Record<string, unknown>) => void;
45
+ onToolEnd?: (toolName: string, success: boolean, durationMs: number) => void;
46
+ }
47
+ /** Options for executeToolBlocks */
48
+ export interface ExecuteToolBlocksOptions {
49
+ toolBlocks: Anthropic.ToolUseBlock[];
50
+ loopDetector: LoopDetector;
51
+ callbacks?: ToolExecCallbacks;
52
+ /** Additional tool executor for domain-specific tools (e.g., team tools) */
53
+ customExecutor?: (name: string, input: Record<string, unknown>) => Promise<ToolExecResult | null>;
54
+ /** Max chars per tool result (default 30_000) */
55
+ maxToolResultChars?: number;
56
+ /** Timeout per tool call in ms (no timeout if not set) */
57
+ toolTimeoutMs?: number;
58
+ }
59
+ /** Result of executing all tool blocks in a turn */
60
+ export interface ToolBlocksResult {
61
+ toolResults: Anthropic.ToolResultBlockParam[];
62
+ toolsUsed: string[];
63
+ /** Set by custom executor if a domain event occurred (e.g., team task completed) */
64
+ customSignals: Record<string, unknown>;
65
+ }
66
+ /**
67
+ * Convert a StreamResult (from SSE collector) to the AgentAPIResponse format
68
+ * that both subagent and teammate expect.
69
+ *
70
+ * Subagent includes thinking blocks; teammate does not (thinkingEnabled=false).
71
+ */
72
+ export declare function streamResultToResponse(result: StreamResult, includeThinking: boolean): AgentAPIResponse;
73
+ /**
74
+ * Call the server proxy API, collect the SSE stream, and return a typed response.
75
+ * Handles auth, request building, caching setup, and stream collection.
76
+ */
77
+ export declare function callAgentAPI(opts: AgentAPIOptions): Promise<AgentAPIResponse>;
78
+ /**
79
+ * Execute an array of tool use blocks, handling:
80
+ * - Loop detection (via LoopDetector)
81
+ * - Routing to local, server, or custom executor
82
+ * - Result truncation to maxToolResultChars
83
+ * - Optional per-tool timeout
84
+ *
85
+ * Returns tool results ready to append to messages, plus metadata.
86
+ */
87
+ export declare function executeToolBlocks(opts: ExecuteToolBlocksOptions): Promise<ToolBlocksResult>;
88
+ /** Extract text blocks from a response */
89
+ export declare function extractTextBlocks(content: Anthropic.ContentBlock[]): Anthropic.TextBlock[];
90
+ /** Extract tool use blocks from a response */
91
+ export declare function extractToolUseBlocks(content: Anthropic.ContentBlock[]): Anthropic.ToolUseBlock[];
92
+ /** Get combined text from all text blocks */
93
+ export declare function getResponseText(content: Anthropic.ContentBlock[]): string;
94
+ /** Yield to event loop to prevent blocking (microtask resolution) */
95
+ export declare function yieldToEventLoop(): Promise<void>;
96
+ /** Longer yield for UI-critical moments (before long API calls, ~1 frame at 60fps) */
97
+ export declare function yieldForRender(): Promise<void>;
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Agent Worker Base — shared utilities for subagent.ts and teammate.ts
3
+ *
4
+ * Extracts the common plumbing:
5
+ * - API calling (auth, build request, call proxy, collect stream, convert response)
6
+ * - Tool execution with loop detection, truncation, and result formatting
7
+ * - Token tracking
8
+ *
9
+ * Both subagent and teammate keep their own types, system prompts, and lifecycle logic.
10
+ * This module provides composable functions, NOT a class hierarchy.
11
+ */
12
+ import { getProxyUrl, resolveConfig } from "./config-store.js";
13
+ import { getValidToken, refreshSession } from "./auth-service.js";
14
+ import { parseSSEStream, collectStreamResult } from "../../shared/sse-parser.js";
15
+ import { callServerProxy, buildAPIRequest, buildSystemBlocks, } from "../../shared/api-client.js";
16
+ import { isLocalTool, executeLocalTool, } from "./local-tools.js";
17
+ import { isServerTool, executeServerTool, } from "./server-tools.js";
18
+ // ============================================================================
19
+ // LONG-RUNNING TOOL TIMEOUT (mirrors tool-dispatch.ts)
20
+ // ============================================================================
21
+ /** Tools that spawn workers/subprocesses and need much longer than 2 min */
22
+ const LONG_RUNNING_TOOL_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
23
+ const LONG_RUNNING_TOOLS = new Set(["team_create", "task", "delegate_task"]);
24
+ // ============================================================================
25
+ // API CLIENT — unified proxy caller
26
+ // ============================================================================
27
+ /**
28
+ * Convert a StreamResult (from SSE collector) to the AgentAPIResponse format
29
+ * that both subagent and teammate expect.
30
+ *
31
+ * Subagent includes thinking blocks; teammate does not (thinkingEnabled=false).
32
+ */
33
+ export function streamResultToResponse(result, includeThinking) {
34
+ const content = [];
35
+ if (includeThinking) {
36
+ for (const tb of result.thinkingBlocks) {
37
+ content.push({
38
+ type: "thinking",
39
+ thinking: tb.thinking,
40
+ signature: tb.signature,
41
+ });
42
+ }
43
+ }
44
+ if (result.text) {
45
+ content.push({ type: "text", text: result.text });
46
+ }
47
+ for (const tu of result.toolUseBlocks) {
48
+ content.push({
49
+ type: "tool_use",
50
+ id: tu.id,
51
+ name: tu.name,
52
+ input: tu.input,
53
+ });
54
+ }
55
+ return {
56
+ content,
57
+ usage: {
58
+ input_tokens: result.usage.inputTokens,
59
+ output_tokens: result.usage.outputTokens,
60
+ },
61
+ stop_reason: result.stopReason,
62
+ };
63
+ }
64
+ /**
65
+ * Call the server proxy API, collect the SSE stream, and return a typed response.
66
+ * Handles auth, request building, caching setup, and stream collection.
67
+ */
68
+ export async function callAgentAPI(opts) {
69
+ const token = await getValidToken();
70
+ if (!token)
71
+ throw new Error("No API key available. Run `whale login`.");
72
+ const apiConfig = buildAPIRequest({
73
+ model: opts.modelId,
74
+ contextProfile: opts.contextProfile,
75
+ thinkingEnabled: opts.thinkingEnabled ?? false,
76
+ maxOutputTokens: opts.maxOutputTokens,
77
+ });
78
+ // Optionally add cache_control to last tool
79
+ let tools;
80
+ if (opts.cacheLastTool && opts.tools.length > 0) {
81
+ tools = [
82
+ ...opts.tools.slice(0, -1),
83
+ { ...opts.tools[opts.tools.length - 1], cache_control: { type: "ephemeral" } },
84
+ ];
85
+ }
86
+ else {
87
+ tools = [...opts.tools];
88
+ }
89
+ const system = buildSystemBlocks(opts.systemPrompt);
90
+ const { storeId } = resolveConfig();
91
+ const stream = await callServerProxy({
92
+ proxyUrl: getProxyUrl(),
93
+ token,
94
+ model: opts.modelId,
95
+ system,
96
+ messages: opts.messages,
97
+ tools,
98
+ apiConfig,
99
+ storeId: storeId || undefined,
100
+ ...(opts.timeoutMs ? { timeoutMs: opts.timeoutMs } : {}),
101
+ onTokenRefresh: async () => {
102
+ const result = await refreshSession();
103
+ return result.success ? result.config.access_token : null;
104
+ },
105
+ });
106
+ const result = await collectStreamResult(parseSSEStream(stream));
107
+ return streamResultToResponse(result, opts.thinkingEnabled ?? false);
108
+ }
109
+ // ============================================================================
110
+ // TOOL EXECUTION — shared loop with detection, routing, and truncation
111
+ // ============================================================================
112
+ /**
113
+ * Execute an array of tool use blocks, handling:
114
+ * - Loop detection (via LoopDetector)
115
+ * - Routing to local, server, or custom executor
116
+ * - Result truncation to maxToolResultChars
117
+ * - Optional per-tool timeout
118
+ *
119
+ * Returns tool results ready to append to messages, plus metadata.
120
+ */
121
+ export async function executeToolBlocks(opts) {
122
+ const { toolBlocks, loopDetector, callbacks, customExecutor, maxToolResultChars = 30_000, toolTimeoutMs, } = opts;
123
+ const toolResults = [];
124
+ const toolsUsed = [];
125
+ const customSignals = {};
126
+ async function executeSingle(tu) {
127
+ // Circuit breaker check
128
+ const loopCheck = loopDetector.recordCall(tu.name, tu.input);
129
+ if (loopCheck.blocked) {
130
+ return {
131
+ type: "tool_result",
132
+ tool_use_id: tu.id,
133
+ content: JSON.stringify({ error: loopCheck.reason }),
134
+ };
135
+ }
136
+ callbacks?.onToolStart?.(tu.name, tu.input);
137
+ const toolStart = Date.now();
138
+ let result;
139
+ try {
140
+ const executeOne = async () => {
141
+ if (customExecutor) {
142
+ const customResult = await customExecutor(tu.name, tu.input);
143
+ if (customResult !== null)
144
+ return customResult;
145
+ }
146
+ if (isLocalTool(tu.name)) {
147
+ return await executeLocalTool(tu.name, tu.input);
148
+ }
149
+ else if (isServerTool(tu.name)) {
150
+ return await executeServerTool(tu.name, tu.input);
151
+ }
152
+ else {
153
+ return { success: false, output: `Unknown tool: ${tu.name}` };
154
+ }
155
+ };
156
+ if (toolTimeoutMs) {
157
+ const effectiveTimeout = LONG_RUNNING_TOOLS.has(tu.name)
158
+ ? Math.max(toolTimeoutMs, LONG_RUNNING_TOOL_TIMEOUT_MS)
159
+ : toolTimeoutMs;
160
+ result = await Promise.race([
161
+ executeOne(),
162
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Tool ${tu.name} timed out after ${effectiveTimeout / 1000}s`)), effectiveTimeout)),
163
+ ]);
164
+ }
165
+ else {
166
+ result = await executeOne();
167
+ }
168
+ }
169
+ catch (toolErr) {
170
+ result = { success: false, output: `Tool execution error: ${toolErr.message || String(toolErr)}` };
171
+ }
172
+ const toolDuration = Date.now() - toolStart;
173
+ loopDetector.recordResult(tu.name, result.success, tu.input);
174
+ callbacks?.onToolEnd?.(tu.name, result.success, toolDuration);
175
+ if (!toolsUsed.includes(tu.name)) {
176
+ toolsUsed.push(tu.name);
177
+ }
178
+ let contentStr = JSON.stringify(result.success ? result.output : { error: result.output });
179
+ if (contentStr.length > maxToolResultChars) {
180
+ contentStr =
181
+ contentStr.slice(0, maxToolResultChars) +
182
+ `\n\n... (truncated — ${contentStr.length.toLocaleString()} chars total)`;
183
+ }
184
+ return {
185
+ type: "tool_result",
186
+ tool_use_id: tu.id,
187
+ content: contentStr,
188
+ };
189
+ }
190
+ // Execute all tool calls in parallel — the model already determined these are independent
191
+ const batchResults = await Promise.all(toolBlocks.map(tu => executeSingle(tu)));
192
+ toolResults.push(...batchResults);
193
+ return { toolResults, toolsUsed, customSignals };
194
+ }
195
+ // ============================================================================
196
+ // CONTENT BLOCK HELPERS
197
+ // ============================================================================
198
+ /** Extract text blocks from a response */
199
+ export function extractTextBlocks(content) {
200
+ return content.filter((b) => b.type === "text");
201
+ }
202
+ /** Extract tool use blocks from a response */
203
+ export function extractToolUseBlocks(content) {
204
+ return content.filter((b) => b.type === "tool_use");
205
+ }
206
+ /** Get combined text from all text blocks */
207
+ export function getResponseText(content) {
208
+ return extractTextBlocks(content).map((b) => b.text).join("\n");
209
+ }
210
+ // ============================================================================
211
+ // YIELD HELPERS — prevent blocking the event loop during long agent loops
212
+ // ============================================================================
213
+ /** Yield to event loop to prevent blocking (microtask resolution) */
214
+ export function yieldToEventLoop() {
215
+ return new Promise((resolve) => setTimeout(resolve, 0));
216
+ }
217
+ /** Longer yield for UI-critical moments (before long API calls, ~1 frame at 60fps) */
218
+ export function yieldForRender() {
219
+ return new Promise((resolve) => setTimeout(resolve, 16));
220
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Auth Service — Supabase email/password auth with token management
3
+ *
4
+ * Same Supabase project as the macOS app. Users login with their
5
+ * SwagManager credentials; the CLI stores JWT tokens locally.
6
+ */
7
+ import { type SupabaseClient } from "@supabase/supabase-js";
8
+ import { type SwagManagerConfig } from "./config-store.js";
9
+ declare const SUPABASE_URL = "https://uaednwpxursknmwdeejn.supabase.co";
10
+ declare const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVhZWRud3B4dXJza25td2RlZWpuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA5OTcyMzMsImV4cCI6MjA3NjU3MzIzM30.N8jPwlyCBB5KJB5I-XaK6m-mq88rSR445AWFJJmwRCg";
11
+ export { SUPABASE_URL, SUPABASE_ANON_KEY };
12
+ export declare function createAuthenticatedClient(accessToken: string): SupabaseClient;
13
+ export interface AuthResult {
14
+ success: boolean;
15
+ error?: string;
16
+ config?: SwagManagerConfig;
17
+ }
18
+ export interface StoreInfo {
19
+ id: string;
20
+ name: string;
21
+ slug?: string;
22
+ }
23
+ export declare function signIn(email: string, password: string): Promise<AuthResult>;
24
+ export declare function signUp(email: string, password: string): Promise<AuthResult>;
25
+ export declare function refreshSession(): Promise<AuthResult>;
26
+ export declare function getValidToken(): Promise<string | null>;
27
+ export declare function signOut(): void;
28
+ export declare function getStoresForUser(accessToken: string, _userId: string): Promise<StoreInfo[]>;
29
+ export declare function selectStore(storeId: string, storeName: string): void;
30
+ export declare function isLoggedIn(): boolean;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Auth Service — Supabase email/password auth with token management
3
+ *
4
+ * Same Supabase project as the macOS app. Users login with their
5
+ * SwagManager credentials; the CLI stores JWT tokens locally.
6
+ */
7
+ import { createClient } from "@supabase/supabase-js";
8
+ import { loadConfig, saveConfig, clearConfig, updateConfig } from "./config-store.js";
9
+ // Public credentials (same as SupabaseConfig.swift)
10
+ const SUPABASE_URL = "https://uaednwpxursknmwdeejn.supabase.co";
11
+ const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVhZWRud3B4dXJza25td2RlZWpuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA5OTcyMzMsImV4cCI6MjA3NjU3MzIzM30.N8jPwlyCBB5KJB5I-XaK6m-mq88rSR445AWFJJmwRCg";
12
+ export { SUPABASE_URL, SUPABASE_ANON_KEY };
13
+ // Create a bare Supabase client (no stored session)
14
+ function createAnonClient() {
15
+ return createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
16
+ auth: { persistSession: false, autoRefreshToken: false },
17
+ });
18
+ }
19
+ // Create a Supabase client authenticated with a user's JWT
20
+ export function createAuthenticatedClient(accessToken) {
21
+ return createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
22
+ auth: { persistSession: false, autoRefreshToken: false },
23
+ global: { headers: { Authorization: `Bearer ${accessToken}` } },
24
+ });
25
+ }
26
+ // Sign in with email/password
27
+ export async function signIn(email, password) {
28
+ const client = createAnonClient();
29
+ const { data, error } = await client.auth.signInWithPassword({ email, password });
30
+ if (error)
31
+ return { success: false, error: error.message };
32
+ if (!data.session)
33
+ return { success: false, error: "No session returned" };
34
+ const config = {
35
+ access_token: data.session.access_token,
36
+ refresh_token: data.session.refresh_token,
37
+ user_id: data.user.id,
38
+ email: data.user.email || email,
39
+ expires_at: data.session.expires_at,
40
+ };
41
+ // Try to extract store from JWT user_metadata first (most reliable)
42
+ const meta = data.user.user_metadata;
43
+ if (meta?.vendor_id) {
44
+ config.store_id = meta.vendor_id;
45
+ config.store_name = meta.store_name || undefined;
46
+ }
47
+ // If no store from metadata, try querying
48
+ if (!config.store_id) {
49
+ const stores = await getStoresForUser(config.access_token, data.user.id);
50
+ if (stores.length === 1) {
51
+ config.store_id = stores[0].id;
52
+ config.store_name = stores[0].name;
53
+ }
54
+ }
55
+ saveConfig(config);
56
+ return { success: true, config };
57
+ }
58
+ // Sign up with email/password
59
+ export async function signUp(email, password) {
60
+ const client = createAnonClient();
61
+ const { data, error } = await client.auth.signUp({ email, password });
62
+ if (error)
63
+ return { success: false, error: error.message };
64
+ if (!data.session) {
65
+ return { success: true, error: "Check your email to confirm your account" };
66
+ }
67
+ const config = {
68
+ access_token: data.session.access_token,
69
+ refresh_token: data.session.refresh_token,
70
+ user_id: data.user.id,
71
+ email: data.user.email || email,
72
+ expires_at: data.session.expires_at,
73
+ };
74
+ saveConfig(config);
75
+ return { success: true, config };
76
+ }
77
+ // Refresh an expired session
78
+ export async function refreshSession() {
79
+ const config = loadConfig();
80
+ if (!config.refresh_token)
81
+ return { success: false, error: "Not logged in" };
82
+ const client = createAnonClient();
83
+ const { data, error } = await client.auth.refreshSession({
84
+ refresh_token: config.refresh_token,
85
+ });
86
+ if (error) {
87
+ clearConfig();
88
+ return { success: false, error: `Session expired: ${error.message}` };
89
+ }
90
+ if (!data.session) {
91
+ clearConfig();
92
+ return { success: false, error: "Could not refresh session" };
93
+ }
94
+ const updated = {
95
+ ...config,
96
+ access_token: data.session.access_token,
97
+ refresh_token: data.session.refresh_token,
98
+ expires_at: data.session.expires_at,
99
+ };
100
+ saveConfig(updated);
101
+ return { success: true, config: updated };
102
+ }
103
+ // Get a valid access token, auto-refreshing if needed
104
+ export async function getValidToken() {
105
+ const config = loadConfig();
106
+ if (!config.access_token)
107
+ return null;
108
+ // Check if token is expired (with 5-min buffer)
109
+ // If expires_at is missing, force a refresh to be safe
110
+ const now = Math.floor(Date.now() / 1000);
111
+ if (!config.expires_at || config.expires_at - 300 < now) {
112
+ const result = await refreshSession();
113
+ if (!result.success)
114
+ return null;
115
+ return result.config.access_token;
116
+ }
117
+ return config.access_token;
118
+ }
119
+ // Sign out — clear stored tokens
120
+ export function signOut() {
121
+ clearConfig();
122
+ }
123
+ // Get stores for the authenticated user
124
+ // RLS on the stores table filters to only stores the user has access to,
125
+ // same as the Swift app does: client.from("stores").select()
126
+ export async function getStoresForUser(accessToken, _userId) {
127
+ const client = createAuthenticatedClient(accessToken);
128
+ // Let RLS filter — same pattern as the macOS app (SupabaseService.fetchStores)
129
+ const { data: stores, error } = await client
130
+ .from("stores")
131
+ .select("id, store_name, slug")
132
+ .limit(20);
133
+ if (error) {
134
+ // Fallback: try via the users table (auth_user_id column, not id)
135
+ const { data: userData } = await client
136
+ .from("users")
137
+ .select("store_id")
138
+ .eq("auth_user_id", _userId)
139
+ .single();
140
+ if (userData?.store_id) {
141
+ const { data: store } = await client
142
+ .from("stores")
143
+ .select("id, store_name, slug")
144
+ .eq("id", userData.store_id)
145
+ .single();
146
+ return store ? [{ id: store.id, name: store.store_name, slug: store.slug }] : [];
147
+ }
148
+ return [];
149
+ }
150
+ return (stores || []).map((s) => ({ id: s.id, name: s.store_name, slug: s.slug }));
151
+ }
152
+ // Select a store and save to config
153
+ export function selectStore(storeId, storeName) {
154
+ updateConfig({ store_id: storeId, store_name: storeName });
155
+ }
156
+ // Check if logged in (has auth tokens)
157
+ export function isLoggedIn() {
158
+ const config = loadConfig();
159
+ return !!(config.access_token && config.refresh_token);
160
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Background Process Management — Claude Code-style async shell execution
3
+ *
4
+ * Enables running long-running processes (dev servers, watchers, builds)
5
+ * without blocking the agent loop.
6
+ *
7
+ * Tools:
8
+ * - run_command with run_in_background: true
9
+ * - bash_output: Read output from running/completed process
10
+ * - kill_shell: Terminate a background process
11
+ */
12
+ import { ChildProcess } from "child_process";
13
+ export interface BackgroundProcess {
14
+ id: string;
15
+ command: string;
16
+ cwd: string;
17
+ startedAt: Date;
18
+ status: "running" | "completed" | "failed" | "killed";
19
+ exitCode?: number;
20
+ outputBuffer: string[];
21
+ errorBuffer: string[];
22
+ process: ChildProcess | null;
23
+ lastReadIndex: number;
24
+ lastErrorReadIndex: number;
25
+ }
26
+ export interface ProcessOutput {
27
+ id: string;
28
+ status: BackgroundProcess["status"];
29
+ newOutput: string;
30
+ newErrors: string;
31
+ exitCode?: number;
32
+ }
33
+ export declare function spawnBackground(command: string, options?: {
34
+ cwd?: string;
35
+ timeout?: number;
36
+ description?: string;
37
+ }): Promise<{
38
+ id: string;
39
+ message: string;
40
+ status: "running" | "failed";
41
+ }>;
42
+ export declare function readProcessOutput(id: string, options?: {
43
+ filter?: string;
44
+ }): ProcessOutput | {
45
+ error: string;
46
+ };
47
+ export declare function killProcess(id: string): {
48
+ success: boolean;
49
+ message: string;
50
+ };
51
+ export declare function listProcesses(): Array<{
52
+ id: string;
53
+ pid: number | undefined;
54
+ command: string;
55
+ status: BackgroundProcess["status"];
56
+ startedAt: string;
57
+ runtime: string;
58
+ outputLines: number;
59
+ errorLines: number;
60
+ }>;
61
+ interface BackgroundAgent {
62
+ id: string;
63
+ type: string;
64
+ outputFile: string;
65
+ startTime: number;
66
+ status: "running" | "completed" | "failed";
67
+ }
68
+ export declare function registerBackgroundAgent(id: string, type: string, outputFile: string): void;
69
+ export declare function getAgentStatus(id: string): BackgroundAgent | null;
70
+ export declare function markAgentDone(id: string, success: boolean): void;
71
+ export declare function readAgentOutput(id: string): {
72
+ status: string;
73
+ output: string;
74
+ } | null;
75
+ export declare function listBackgroundAgents(): BackgroundAgent[];
76
+ export declare function stopBackgroundAgent(id: string): {
77
+ success: boolean;
78
+ message: string;
79
+ };
80
+ export declare const BACKGROUND_TOOL_DEFINITIONS: ({
81
+ name: string;
82
+ description: string;
83
+ input_schema: {
84
+ type: string;
85
+ properties: {
86
+ bash_id: {
87
+ type: string;
88
+ description: string;
89
+ };
90
+ filter: {
91
+ type: string;
92
+ description: string;
93
+ };
94
+ shell_id?: undefined;
95
+ };
96
+ required: string[];
97
+ };
98
+ } | {
99
+ name: string;
100
+ description: string;
101
+ input_schema: {
102
+ type: string;
103
+ properties: {
104
+ shell_id: {
105
+ type: string;
106
+ description: string;
107
+ };
108
+ bash_id?: undefined;
109
+ filter?: undefined;
110
+ };
111
+ required: string[];
112
+ };
113
+ } | {
114
+ name: string;
115
+ description: string;
116
+ input_schema: {
117
+ type: string;
118
+ properties: {
119
+ bash_id?: undefined;
120
+ filter?: undefined;
121
+ shell_id?: undefined;
122
+ };
123
+ required: never[];
124
+ };
125
+ })[];
126
+ export {};