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,61 @@
1
+ /**
2
+ * CLI Telemetry — fire-and-forget span logging to audit_logs
3
+ *
4
+ * Session-scoped conversationId + auto-incrementing turnNumber.
5
+ * Uses same column schema as executor.ts telemetry (trace_id, span_id, etc).
6
+ * Never blocks or crashes the chat.
7
+ */
8
+ export interface ExecutionContext {
9
+ source: string;
10
+ userId?: string;
11
+ userEmail?: string;
12
+ traceId?: string;
13
+ spanId?: string;
14
+ parentSpanId?: string;
15
+ traceFlags?: number;
16
+ requestId?: string;
17
+ parentId?: string;
18
+ rowId?: string;
19
+ serviceName?: string;
20
+ serviceVersion?: string;
21
+ agentId?: string;
22
+ agentName?: string;
23
+ conversationId?: string;
24
+ turnNumber?: number;
25
+ model?: string;
26
+ inputTokens?: number;
27
+ outputTokens?: number;
28
+ totalCost?: number;
29
+ costBefore?: number;
30
+ turnCost?: number;
31
+ iteration?: number;
32
+ toolType?: string;
33
+ }
34
+ /**
35
+ * Set the conversation ID (used by worker threads to share parent's conversation)
36
+ */
37
+ export declare function setConversationId(id: string): void;
38
+ /**
39
+ * Get the current conversation ID
40
+ */
41
+ export declare function getConversationId(): string;
42
+ /**
43
+ * Initialize the telemetry client with a specific auth token.
44
+ * Used by worker threads that receive the token from the parent.
45
+ */
46
+ export declare function initializeTelemetryClient(authToken: string): void;
47
+ export declare function generateTraceId(): string;
48
+ export declare function generateSpanId(): string;
49
+ export declare function nextTurn(): number;
50
+ export declare function createTurnContext(overrides?: Partial<ExecutionContext>): ExecutionContext;
51
+ export declare function getTurnNumber(): number;
52
+ export interface SpanOptions {
53
+ action: string;
54
+ severity?: "info" | "warn" | "error";
55
+ durationMs: number;
56
+ context: ExecutionContext;
57
+ storeId?: string;
58
+ error?: string;
59
+ details?: Record<string, unknown>;
60
+ }
61
+ export declare function logSpan(opts: SpanOptions): void;
@@ -0,0 +1,209 @@
1
+ /**
2
+ * CLI Telemetry — fire-and-forget span logging to audit_logs
3
+ *
4
+ * Session-scoped conversationId + auto-incrementing turnNumber.
5
+ * Uses same column schema as executor.ts telemetry (trace_id, span_id, etc).
6
+ * Never blocks or crashes the chat.
7
+ */
8
+ import { createClient } from "@supabase/supabase-js";
9
+ import { createRequire } from "module";
10
+ import { resolveConfig, loadConfig } from "./config-store.js";
11
+ import { getValidToken, createAuthenticatedClient } from "./auth-service.js";
12
+ import { captureError } from "./error-logger.js";
13
+ const require = createRequire(import.meta.url);
14
+ const PKG_VERSION = require("../../../package.json").version;
15
+ // ============================================================================
16
+ // SESSION STATE
17
+ // ============================================================================
18
+ let conversationId = crypto.randomUUID();
19
+ let turnNumber = 0;
20
+ /**
21
+ * Set the conversation ID (used by worker threads to share parent's conversation)
22
+ */
23
+ export function setConversationId(id) {
24
+ conversationId = id;
25
+ }
26
+ /**
27
+ * Get the current conversation ID
28
+ */
29
+ export function getConversationId() {
30
+ return conversationId;
31
+ }
32
+ let supabaseClient = null;
33
+ /**
34
+ * Initialize the telemetry client with a specific auth token.
35
+ * Used by worker threads that receive the token from the parent.
36
+ */
37
+ export function initializeTelemetryClient(authToken) {
38
+ if (supabaseClient)
39
+ return; // Already initialized
40
+ supabaseClient = createAuthenticatedClient(authToken);
41
+ if (process.env.DEBUG_TELEMETRY) {
42
+ process.stderr.write(`[telemetry] initialized client with provided auth token\n`);
43
+ }
44
+ }
45
+ // ============================================================================
46
+ // W3C TRACE CONTEXT GENERATORS
47
+ // ============================================================================
48
+ export function generateTraceId() {
49
+ // Use proper UUID format so it's compatible with Postgres uuid columns
50
+ return crypto.randomUUID();
51
+ }
52
+ export function generateSpanId() {
53
+ const bytes = new Uint8Array(8);
54
+ crypto.getRandomValues(bytes);
55
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, "0")).join("");
56
+ }
57
+ // ============================================================================
58
+ // SUPABASE CLIENT (lazy init)
59
+ // ============================================================================
60
+ async function getClient() {
61
+ if (supabaseClient)
62
+ return supabaseClient;
63
+ const config = resolveConfig();
64
+ // Prefer service role key
65
+ if (config.supabaseUrl && config.supabaseKey) {
66
+ supabaseClient = createClient(config.supabaseUrl, config.supabaseKey, {
67
+ auth: { persistSession: false, autoRefreshToken: false },
68
+ });
69
+ if (process.env.DEBUG_TELEMETRY) {
70
+ process.stderr.write(`[telemetry] using service role key\n`);
71
+ }
72
+ return supabaseClient;
73
+ }
74
+ // Fallback: user JWT
75
+ const token = await getValidToken();
76
+ if (token) {
77
+ supabaseClient = createAuthenticatedClient(token);
78
+ if (process.env.DEBUG_TELEMETRY) {
79
+ process.stderr.write(`[telemetry] using user JWT token\n`);
80
+ }
81
+ return supabaseClient;
82
+ }
83
+ if (process.env.DEBUG_TELEMETRY) {
84
+ process.stderr.write(`[telemetry] NO CLIENT - no service key and no valid token\n`);
85
+ process.stderr.write(`[telemetry] config.supabaseUrl: ${config.supabaseUrl}\n`);
86
+ process.stderr.write(`[telemetry] config.supabaseKey: ${config.supabaseKey ? 'set' : 'not set'}\n`);
87
+ }
88
+ return null;
89
+ }
90
+ // ============================================================================
91
+ // TURN CONTEXT
92
+ // ============================================================================
93
+ export function nextTurn() {
94
+ return ++turnNumber;
95
+ }
96
+ export function createTurnContext(overrides) {
97
+ // Get user info from config
98
+ const { user_id, email } = loadConfig();
99
+ return {
100
+ source: "whale_cli",
101
+ serviceName: "whale-code",
102
+ serviceVersion: PKG_VERSION,
103
+ conversationId,
104
+ turnNumber,
105
+ traceId: generateTraceId(),
106
+ spanId: generateSpanId(),
107
+ traceFlags: 1,
108
+ userId: user_id,
109
+ userEmail: email,
110
+ ...overrides,
111
+ };
112
+ }
113
+ export function getTurnNumber() {
114
+ return turnNumber;
115
+ }
116
+ export function logSpan(opts) {
117
+ // Fire-and-forget — don't await, log errors in debug mode
118
+ _logSpan(opts).catch((err) => {
119
+ if (process.env.DEBUG_TELEMETRY) {
120
+ process.stderr.write(`[telemetry error] ${opts.action}: ${err.message}\n`);
121
+ }
122
+ });
123
+ }
124
+ async function _logSpan(opts) {
125
+ if (process.env.DEBUG_TELEMETRY) {
126
+ process.stderr.write(`[telemetry] _logSpan called for ${opts.action}\n`);
127
+ }
128
+ const client = await getClient();
129
+ if (!client) {
130
+ if (process.env.DEBUG_TELEMETRY) {
131
+ process.stderr.write(`[telemetry] no client for ${opts.action}\n`);
132
+ }
133
+ return;
134
+ }
135
+ const now = new Date();
136
+ const startTime = new Date(now.getTime() - opts.durationMs);
137
+ const ctx = opts.context;
138
+ // Debug: log team-related spans (only when DEBUG_TELEMETRY is set)
139
+ if (process.env.DEBUG_TELEMETRY && (opts.action.startsWith("team.") || opts.details?.parent_conversation_id)) {
140
+ process.stderr.write(`[telemetry:team] action=${opts.action}\n`);
141
+ process.stderr.write(`[telemetry:team] conversation_id=${ctx.conversationId}\n`);
142
+ process.stderr.write(`[telemetry:team] parent_conversation_id=${opts.details?.parent_conversation_id}\n`);
143
+ }
144
+ const row = {
145
+ action: opts.action,
146
+ severity: opts.severity || (opts.error ? "error" : "info"),
147
+ store_id: opts.storeId || resolveConfig().storeId || null,
148
+ user_id: ctx.userId || null,
149
+ user_email: ctx.userEmail || null,
150
+ resource_type: "cli_span",
151
+ resource_id: opts.action,
152
+ request_id: ctx.traceId,
153
+ parent_id: ctx.parentId || null,
154
+ duration_ms: opts.durationMs,
155
+ error_message: opts.error || null,
156
+ // OTEL columns
157
+ trace_id: ctx.traceId,
158
+ span_id: ctx.spanId,
159
+ trace_flags: ctx.traceFlags ?? 1,
160
+ span_kind: "INTERNAL",
161
+ service_name: ctx.serviceName || "whale-code",
162
+ service_version: ctx.serviceVersion || PKG_VERSION,
163
+ status_code: opts.error ? "ERROR" : "OK",
164
+ start_time: startTime.toISOString(),
165
+ end_time: now.toISOString(),
166
+ // AI telemetry — use ?? to handle 0 correctly
167
+ model: ctx.model || null,
168
+ input_tokens: ctx.inputTokens ?? null,
169
+ output_tokens: ctx.outputTokens ?? null,
170
+ total_cost: ctx.totalCost ?? null,
171
+ turn_number: ctx.turnNumber ?? null,
172
+ conversation_id: ctx.conversationId || null,
173
+ details: {
174
+ source: ctx.source || "whale_cli",
175
+ conversation_id: ctx.conversationId || conversationId,
176
+ turn_number: ctx.turnNumber ?? turnNumber,
177
+ parent_span_id: ctx.parentSpanId || null,
178
+ ...opts.details,
179
+ },
180
+ };
181
+ // Allow caller to control row ID so children can reference it via parent_id
182
+ if (ctx.rowId)
183
+ row.id = ctx.rowId;
184
+ const { error } = await client.from("audit_logs").insert(row);
185
+ if (error) {
186
+ if (process.env.DEBUG_TELEMETRY) {
187
+ process.stderr.write(`[telemetry db error] ${opts.action}: ${error.message}\n`);
188
+ process.stderr.write(`[telemetry db error] code: ${error.code}\n`);
189
+ process.stderr.write(`[telemetry db error] hint: ${error.hint}\n`);
190
+ }
191
+ }
192
+ else if (opts.details?.is_teammate && process.env.DEBUG_TELEMETRY) {
193
+ process.stderr.write(`[telemetry] teammate span logged: ${opts.action}\n`);
194
+ }
195
+ // Bridge errors to the error logging system
196
+ if (opts.error) {
197
+ captureError({
198
+ errorType: opts.action,
199
+ errorMessage: opts.error,
200
+ severity: "error",
201
+ traceId: ctx.traceId,
202
+ spanId: ctx.spanId,
203
+ storeId: opts.storeId || resolveConfig().storeId,
204
+ userId: ctx.userId,
205
+ userEmail: ctx.userEmail,
206
+ tags: { action: opts.action },
207
+ });
208
+ }
209
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Agent Tools — task, team_create, task_output, task_stop, config, ask_user, lsp, skill
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { ToolResult } from "../../../shared/types.js";
7
+ export declare function configTool(input: Record<string, unknown>): ToolResult;
8
+ export declare function askUser(input: Record<string, unknown>): ToolResult;
9
+ export declare function lspTool(input: Record<string, unknown>): Promise<ToolResult>;
10
+ export declare function skillTool(input: Record<string, unknown>): ToolResult;
11
+ export declare function taskTool(input: Record<string, unknown>): Promise<ToolResult>;
12
+ export declare function taskOutput(input: Record<string, unknown>): Promise<ToolResult>;
13
+ export declare function taskStop(input: Record<string, unknown>): ToolResult;
14
+ export declare function teamCreateTool(input: Record<string, unknown>): Promise<ToolResult>;
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Agent Tools — task, team_create, task_output, task_stop, config, ask_user, lsp, skill
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { readFileSync, existsSync } from "fs";
7
+ import { dirname, join } from "path";
8
+ import { homedir } from "os";
9
+ import { runSubagent, runSubagentBackground, } from "../subagent.js";
10
+ import { createTurnContext, getTurnNumber, } from "../telemetry.js";
11
+ import { runAgentTeam, } from "../team-lead.js";
12
+ import { readAgentOutput, stopBackgroundAgent } from "../background-processes.js";
13
+ import { readProcessOutput, killProcess } from "../background-processes.js";
14
+ import { getGlobalEmitter } from "../agent-events.js";
15
+ import { executeLSP } from "../lsp-manager.js";
16
+ import { debugLog } from "../debug-log.js";
17
+ import { setPermissionMode, getPermissionMode } from "../permission-modes.js";
18
+ import { getModel, setModel } from "../model-manager.js";
19
+ // ============================================================================
20
+ // CONFIG TOOL
21
+ // ============================================================================
22
+ export function configTool(input) {
23
+ const setting = input.setting;
24
+ const value = input.value;
25
+ switch (setting) {
26
+ case "model": {
27
+ if (!value)
28
+ return { success: true, output: `Current model: ${getModel()}` };
29
+ const result = setModel(value);
30
+ if (!result.success) {
31
+ return { success: false, output: result.error || `Unknown model: ${value}` };
32
+ }
33
+ return { success: true, output: `Model set to: ${result.model}` };
34
+ }
35
+ case "mode":
36
+ case "permission_mode": {
37
+ if (!value)
38
+ return { success: true, output: `Current mode: ${getPermissionMode()}` };
39
+ if (!["default", "plan", "yolo"].includes(value)) {
40
+ return { success: false, output: `Invalid mode: ${value}. Use: default, plan, yolo` };
41
+ }
42
+ const result = setPermissionMode(value);
43
+ return { success: result.success, output: result.message };
44
+ }
45
+ case "memory": {
46
+ if (!value) {
47
+ const memPath = join(homedir(), ".swagmanager", "memory", "MEMORY.md");
48
+ if (!existsSync(memPath))
49
+ return { success: true, output: "No memory file found." };
50
+ const content = readFileSync(memPath, "utf-8");
51
+ return { success: true, output: `Memory (${content.length} chars):\n${content.slice(0, 20_000)}` };
52
+ }
53
+ return { success: false, output: "Use read_file/write_file to edit memory directly." };
54
+ }
55
+ default:
56
+ return { success: false, output: `Unknown setting: ${setting}. Available: model, mode, memory` };
57
+ }
58
+ }
59
+ // ============================================================================
60
+ // ASK USER
61
+ // ============================================================================
62
+ export function askUser(input) {
63
+ const question = input.question;
64
+ const options = input.options;
65
+ if (!question)
66
+ return { success: false, output: "question is required" };
67
+ if (!options || options.length < 2)
68
+ return { success: false, output: "at least 2 options required" };
69
+ // Emit the question via the global event emitter for the UI to render
70
+ const emitter = getGlobalEmitter();
71
+ if (emitter) {
72
+ emitter.emit("ask_user", { question, options });
73
+ }
74
+ // Format question as text for the model to see in the response
75
+ const optionLines = options.map((o, i) => ` ${i + 1}. **${o.label}** — ${o.description}`).join("\n");
76
+ return {
77
+ success: true,
78
+ output: `Question presented to user:\n${question}\n\nOptions:\n${optionLines}\n\n(Waiting for user response...)`,
79
+ };
80
+ }
81
+ // ============================================================================
82
+ // LSP TOOL
83
+ // ============================================================================
84
+ export async function lspTool(input) {
85
+ const operation = input.operation;
86
+ if (!operation)
87
+ return { success: false, output: "operation is required" };
88
+ return await executeLSP(operation, input);
89
+ }
90
+ // ============================================================================
91
+ // SKILL TOOL
92
+ // ============================================================================
93
+ export function skillTool(input) {
94
+ const skillName = input.skill;
95
+ if (!skillName)
96
+ return { success: false, output: "skill name is required" };
97
+ const args = (input.args || "").split(/\s+/).filter(Boolean);
98
+ // Resolution order:
99
+ // 1. .whale/commands/{skill}.md (project-local)
100
+ // 2. ~/.swagmanager/commands/{skill}.md (user global)
101
+ // 3. Built-in skills bundled with package
102
+ const localPath = join(process.cwd(), ".whale", "commands", `${skillName}.md`);
103
+ const globalPath = join(homedir(), ".swagmanager", "commands", `${skillName}.md`);
104
+ // Built-in skills: check both dist/ and src/ locations
105
+ const thisFileDir = dirname(new URL(import.meta.url).pathname);
106
+ const builtinPaths = [
107
+ join(thisFileDir, "..", "builtin-skills", `${skillName}.md`), // dist/cli/services/tools/../builtin-skills/
108
+ join(thisFileDir, "..", "..", "..", "..", "src", "cli", "services", "builtin-skills", `${skillName}.md`), // src/ from dist/
109
+ ];
110
+ let template = null;
111
+ let source = "";
112
+ // Check local -> global -> builtin (multiple paths)
113
+ const candidates = [
114
+ [localPath, "local"],
115
+ [globalPath, "global"],
116
+ ...builtinPaths.map(p => [p, "builtin"]),
117
+ ];
118
+ for (const [path, src] of candidates) {
119
+ if (existsSync(path)) {
120
+ try {
121
+ let content = readFileSync(path, "utf-8");
122
+ // Strip frontmatter
123
+ if (content.startsWith("---")) {
124
+ const endIdx = content.indexOf("---", 3);
125
+ if (endIdx !== -1) {
126
+ content = content.slice(endIdx + 3).trim();
127
+ }
128
+ }
129
+ template = content;
130
+ source = src;
131
+ break;
132
+ }
133
+ catch { /* skip */ }
134
+ }
135
+ }
136
+ if (!template) {
137
+ return {
138
+ success: false,
139
+ output: `Skill not found: ${skillName}. Available locations:\n .whale/commands/${skillName}.md\n ~/.swagmanager/commands/${skillName}.md\n\nBuilt-in skills: commit, review, review-pr`,
140
+ };
141
+ }
142
+ // Expand arguments ($1, $2, $ARGS)
143
+ let expanded = template;
144
+ for (let i = 0; i < args.length; i++) {
145
+ expanded = expanded.replace(new RegExp(`\\$${i + 1}`, "g"), args[i]);
146
+ }
147
+ expanded = expanded.replace(/\$ARGS/g, args.join(" "));
148
+ expanded = expanded.replace(/\$\d+/g, ""); // Clean up unused
149
+ return {
150
+ success: true,
151
+ output: `[Skill: ${skillName} (${source})]\n\n${expanded.trim()}`,
152
+ };
153
+ }
154
+ // ============================================================================
155
+ // TASK TOOL — subagent execution
156
+ // ============================================================================
157
+ /** Create parent trace context for subagent hierarchy */
158
+ function getParentTraceContext() {
159
+ const ctx = createTurnContext();
160
+ return {
161
+ traceId: ctx.traceId,
162
+ spanId: ctx.spanId,
163
+ conversationId: ctx.conversationId,
164
+ turnNumber: getTurnNumber(),
165
+ userId: ctx.userId,
166
+ userEmail: ctx.userEmail,
167
+ };
168
+ }
169
+ export async function taskTool(input) {
170
+ const prompt = input.prompt;
171
+ const subagent_type = input.subagent_type;
172
+ const model = input.model || "haiku";
173
+ const runInBackground = input.run_in_background;
174
+ const maxTurns = input.max_turns;
175
+ const agentName = input.name;
176
+ const teamName = input.team_name;
177
+ const mode = input.mode;
178
+ if (!prompt)
179
+ return { success: false, output: "prompt is required" };
180
+ if (!subagent_type)
181
+ return { success: false, output: "subagent_type is required" };
182
+ // Apply permission mode for subagent if specified
183
+ if (mode) {
184
+ setPermissionMode(mode);
185
+ // Note: mode resets are handled by subagent isolation
186
+ }
187
+ debugLog("tools", `task: ${agentName || subagent_type}`, { model, maxTurns, teamName, mode });
188
+ try {
189
+ // Background mode: start agent, return output file path immediately
190
+ if (runInBackground) {
191
+ const { agentId, outputFile } = await runSubagentBackground({
192
+ prompt,
193
+ subagent_type,
194
+ model,
195
+ max_turns: maxTurns,
196
+ name: agentName,
197
+ run_in_background: true,
198
+ parentTraceContext: getParentTraceContext(),
199
+ });
200
+ return {
201
+ success: true,
202
+ output: `Background agent started.\n agent_id: ${agentId}\n output_file: ${outputFile}\n\nUse task_output with task_id="${agentId}" to check progress.`,
203
+ };
204
+ }
205
+ // Foreground mode: run agent synchronously
206
+ const result = await runSubagent({
207
+ prompt,
208
+ subagent_type,
209
+ model,
210
+ max_turns: maxTurns,
211
+ name: agentName,
212
+ parentTraceContext: getParentTraceContext(),
213
+ });
214
+ return {
215
+ success: result.success,
216
+ output: result.output,
217
+ };
218
+ }
219
+ catch (err) {
220
+ return {
221
+ success: false,
222
+ output: `Task failed: ${err.message || err}`,
223
+ };
224
+ }
225
+ }
226
+ // ============================================================================
227
+ // TASK OUTPUT / TASK STOP
228
+ // ============================================================================
229
+ export async function taskOutput(input) {
230
+ const taskId = input.task_id;
231
+ const block = input.block ?? true;
232
+ const timeout = Math.min(input.timeout || 30000, 120000);
233
+ if (!taskId)
234
+ return { success: false, output: "task_id is required" };
235
+ // Check if it's a background agent (agent-xxx prefix)
236
+ if (taskId.startsWith("agent-")) {
237
+ const agentResult = readAgentOutput(taskId);
238
+ if (!agentResult)
239
+ return { success: false, output: `Agent not found: ${taskId}. Use list_shells to see available tasks.` };
240
+ // If blocking and still running, poll until done or timeout
241
+ if (block && agentResult.status === "running") {
242
+ const start = Date.now();
243
+ while (Date.now() - start < timeout) {
244
+ await new Promise(r => setTimeout(r, 1000));
245
+ const updated = readAgentOutput(taskId);
246
+ if (updated && updated.status !== "running") {
247
+ return { success: true, output: `[${updated.status}]\n${updated.output}` };
248
+ }
249
+ }
250
+ const final = readAgentOutput(taskId);
251
+ return { success: true, output: `[${final?.status || "running"} — timed out waiting]\n${final?.output || ""}` };
252
+ }
253
+ return { success: true, output: `[${agentResult.status}]\n${agentResult.output}` };
254
+ }
255
+ // Fall back to shell process output (bash_output behavior)
256
+ const result = readProcessOutput(taskId, {});
257
+ if ("error" in result)
258
+ return { success: false, output: result.error };
259
+ const statusIcon = result.status === "running" ? "\u25CF" : result.status === "completed" ? "\u2713" : "\u2715";
260
+ const lines = [];
261
+ lines.push(`${statusIcon} Task ${taskId} — ${result.status}`);
262
+ if (result.exitCode !== undefined)
263
+ lines.push(` Exit code: ${result.exitCode}`);
264
+ if (result.newOutput) {
265
+ lines.push(` Output:`);
266
+ lines.push(result.newOutput);
267
+ }
268
+ if (result.newErrors) {
269
+ lines.push(` Errors:`);
270
+ lines.push(result.newErrors);
271
+ }
272
+ if (!result.newOutput && !result.newErrors)
273
+ lines.push(" (no new output since last check)");
274
+ return { success: true, output: lines.join("\n") };
275
+ }
276
+ export function taskStop(input) {
277
+ const taskId = input.task_id;
278
+ if (!taskId)
279
+ return { success: false, output: "task_id is required" };
280
+ // Check if it's a background agent
281
+ if (taskId.startsWith("agent-")) {
282
+ const result = stopBackgroundAgent(taskId);
283
+ return { success: result.success, output: result.message };
284
+ }
285
+ // Fall back to shell kill
286
+ const result = killProcess(taskId);
287
+ return { success: result.success, output: result.message };
288
+ }
289
+ // ============================================================================
290
+ // TEAM CREATE
291
+ // ============================================================================
292
+ export async function teamCreateTool(input) {
293
+ const name = input.name;
294
+ const teammateCount = input.teammate_count;
295
+ const model = input.model || "sonnet";
296
+ const tasksInput = input.tasks;
297
+ if (!name)
298
+ return { success: false, output: "name is required" };
299
+ if (!teammateCount || teammateCount < 1) {
300
+ return { success: false, output: "teammate_count must be at least 1" };
301
+ }
302
+ if (!tasksInput || tasksInput.length === 0) {
303
+ return { success: false, output: "tasks array is required and must not be empty" };
304
+ }
305
+ // Validate task count vs teammate count
306
+ if (tasksInput.length < teammateCount) {
307
+ return {
308
+ success: false,
309
+ output: `Not enough tasks (${tasksInput.length}) for ${teammateCount} teammates. Add more tasks or reduce teammates.`,
310
+ };
311
+ }
312
+ const config = {
313
+ name,
314
+ teammateCount,
315
+ model,
316
+ tasks: tasksInput,
317
+ };
318
+ try {
319
+ const result = await runAgentTeam(config);
320
+ // Build summary output
321
+ const lines = [
322
+ `## Team: ${name}`,
323
+ `Status: ${result.success ? "SUCCESS" : "PARTIAL"}`,
324
+ `Duration: ${(result.durationMs / 1000).toFixed(1)}s`,
325
+ `Tokens: ${result.tokensUsed.input} in, ${result.tokensUsed.output} out`,
326
+ "",
327
+ "### Task Results",
328
+ ];
329
+ for (const task of result.taskResults) {
330
+ const icon = task.status === "completed" ? "[done]" : "[fail]";
331
+ lines.push(`${icon} ${task.description}`);
332
+ if (task.result) {
333
+ lines.push(` ${task.result.slice(0, 200)}${task.result.length > 200 ? "..." : ""}`);
334
+ }
335
+ }
336
+ return {
337
+ success: result.success,
338
+ output: lines.join("\n"),
339
+ };
340
+ }
341
+ catch (err) {
342
+ return {
343
+ success: false,
344
+ output: `Team failed: ${err.message || err}`,
345
+ };
346
+ }
347
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * File Operations — read, write, edit, multi-edit, notebook, list, search
3
+ *
4
+ * Extracted from local-tools.ts for single-responsibility.
5
+ */
6
+ import { ToolResult } from "../../../shared/types.js";
7
+ export declare function resolvePath(p: string): string;
8
+ export declare function readFile(input: Record<string, unknown>): Promise<ToolResult>;
9
+ export declare function writeFile(input: Record<string, unknown>): ToolResult;
10
+ export declare function editFile(input: Record<string, unknown>): ToolResult;
11
+ export declare function multiEdit(input: Record<string, unknown>): ToolResult;
12
+ export declare function notebookEdit(input: Record<string, unknown>): ToolResult;
13
+ export declare function listDirectory(input: Record<string, unknown>): ToolResult;
14
+ export declare function searchFiles(input: Record<string, unknown>): ToolResult;
15
+ export declare function searchContent(input: Record<string, unknown>): ToolResult;