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,147 @@
1
+ // server/lib/utils.ts — Shared utility functions
2
+ /** Escape characters that could manipulate PostgREST/ILIKE filter syntax.
3
+ * Escapes ILIKE wildcards (%, _) and backslashes, plus strips commas and parens
4
+ * that could manipulate PostgREST operators. */
5
+ export function sanitizeFilterValue(val) {
6
+ // First escape ILIKE wildcards and backslashes
7
+ let escaped = val.replace(/[\\%_]/g, (ch) => `\\${ch}`);
8
+ // Then strip PostgREST operator chars
9
+ escaped = escaped.replace(/[,\(\)]/g, "");
10
+ return escaped;
11
+ }
12
+ /** Group array items by a key, returning counts */
13
+ export function groupBy(arr, key) {
14
+ const counts = {};
15
+ for (const item of arr) {
16
+ const val = item[key] || "unknown";
17
+ counts[val] = (counts[val] || 0) + 1;
18
+ }
19
+ return counts;
20
+ }
21
+ /** Escape a value for CSV output */
22
+ export function escapeCSV(val) {
23
+ if (val === null || val === undefined)
24
+ return "";
25
+ const str = String(val);
26
+ if (str.includes(",") || str.includes('"') || str.includes("\n")) {
27
+ return '"' + str.replace(/"/g, '""') + '"';
28
+ }
29
+ return str;
30
+ }
31
+ /** Fill {{key}} placeholders in a template string */
32
+ export function fillTemplate(template, data) {
33
+ return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, key) => {
34
+ const parts = key.split(".");
35
+ let val = data;
36
+ for (const p of parts) {
37
+ if (val === null || val === undefined)
38
+ return match;
39
+ val = val[p];
40
+ }
41
+ return val !== null && val !== undefined ? String(val) : match;
42
+ });
43
+ }
44
+ /** Extract concise metrics from tool results for audit logging (never full payloads). */
45
+ export function summarizeResult(toolName, action, data) {
46
+ const d = data;
47
+ try {
48
+ switch (toolName) {
49
+ case "analytics": {
50
+ switch (action) {
51
+ case "summary": {
52
+ if (Array.isArray(d)) {
53
+ const row = d[0] || {};
54
+ return { total_revenue: row.totalRevenue || row.total_revenue, total_orders: row.totalOrders || row.total_orders, avg_order: row.avgOrderValue || row.avg_order_value, rows: d.length };
55
+ }
56
+ return { total_revenue: d.totalRevenue || d.total_revenue, total_orders: d.totalOrders || d.total_orders, avg_order: d.avgOrderValue, profit_margin: d.profitMargin, unique_customers: d.uniqueCustomers };
57
+ }
58
+ case "by_location":
59
+ return { locations: Array.isArray(d) ? d.length : 0, total_revenue: Array.isArray(d) ? d.reduce((s, r) => s + (r.revenue || 0), 0) : 0 };
60
+ case "detailed":
61
+ return { rows: Array.isArray(d) ? d.length : 0 };
62
+ case "by_category":
63
+ return { categories: d.categories ? d.categories.length : 0, total_revenue: d.totalRevenue, days: d.days };
64
+ case "product_sales":
65
+ return { products: d.products ? d.products.length : 0, total_revenue: d.totalRevenue, total_units: d.totalUnits, days: d.days };
66
+ case "category_velocity":
67
+ return { items: d.results ? d.results.length : 0, days: d.days };
68
+ case "customers":
69
+ case "customer_intelligence":
70
+ return { rows: Array.isArray(d) ? d.length : (d.customers ? d.customers.length : 0) };
71
+ case "products":
72
+ case "product_intelligence":
73
+ return { rows: Array.isArray(d) ? d.length : 0 };
74
+ case "inventory_intelligence":
75
+ return { rows: Array.isArray(d) ? d.length : 0 };
76
+ case "marketing":
77
+ case "marketing_intelligence":
78
+ return { rows: Array.isArray(d) ? d.length : 0 };
79
+ case "fraud":
80
+ case "fraud_detection":
81
+ return { total_orders: d.totalOrders, high_risk: d.highRisk, medium_risk: d.mediumRisk, avg_risk_score: d.avgRiskScore };
82
+ case "employee":
83
+ case "employee_performance":
84
+ return { rows: Array.isArray(d) ? d.length : 0 };
85
+ case "behavior":
86
+ case "behavioral_analytics":
87
+ return { sessions: d.summary?.sessions, page_views: d.summary?.pageViews };
88
+ case "full":
89
+ case "business_intelligence":
90
+ return { rows: Array.isArray(d) ? d.length : 0 };
91
+ case "discover":
92
+ return { rows: Array.isArray(d) ? d.length : 0 };
93
+ default:
94
+ return { rows: Array.isArray(d) ? d.length : 1 };
95
+ }
96
+ }
97
+ case "inventory":
98
+ return { action, rows: Array.isArray(d) ? d.length : 1 };
99
+ case "inventory_query":
100
+ return { action, rows: Array.isArray(d) ? d.length : (d.products ? d.products.length : (d.summary ? 1 : 0)) };
101
+ case "purchase_orders":
102
+ if (action === "list")
103
+ return { count: Array.isArray(d) ? d.length : (d.purchase_orders ? d.purchase_orders.length : 0) };
104
+ return { po_id: d.id, po_number: d.po_number, status: d.status };
105
+ case "transfers":
106
+ if (action === "list")
107
+ return { count: Array.isArray(d) ? d.length : 0 };
108
+ return { transfer_id: d.id, transfer_number: d.transfer_number, status: d.status };
109
+ case "orders":
110
+ return { count: Array.isArray(d) ? d.length : (d.orders ? d.orders.length : 1) };
111
+ case "customers":
112
+ return { count: Array.isArray(d) ? d.length : (d.customers ? d.customers.length : 1) };
113
+ case "products":
114
+ if (action === "browse")
115
+ return { categories: d.data ? d.data.categories?.length || 0 : 0, status_summary: d.data ? d.data.product_status_summary : undefined };
116
+ return { action, count: Array.isArray(d) ? d.length : (d.count ?? (d.products ? d.products.length : (d.id ? 1 : 0))) };
117
+ case "audit_trail":
118
+ return { count: d.count, days: d.days, actions: d.summary ? Object.keys(d.summary).length : 0 };
119
+ case "telemetry":
120
+ return { action, count: d.count || (Array.isArray(d) ? d.length : 0) };
121
+ case "alerts":
122
+ return { total: d.total };
123
+ default:
124
+ return { rows: Array.isArray(d) ? d.length : 1 };
125
+ }
126
+ }
127
+ catch {
128
+ return { rows: Array.isArray(d) ? d.length : 1 };
129
+ }
130
+ }
131
+ /** Timeout wrapper for tool execution with AbortSignal support.
132
+ * Creates an AbortController, races the promise against a timeout,
133
+ * and aborts the signal on timeout so underlying work (fetch etc.) can cancel. */
134
+ export function withTimeout(promiseOrFactory, ms, name) {
135
+ const controller = new AbortController();
136
+ const promise = typeof promiseOrFactory === "function"
137
+ ? promiseOrFactory(controller.signal)
138
+ : promiseOrFactory;
139
+ let timer;
140
+ const timeoutPromise = new Promise((_, reject) => {
141
+ timer = setTimeout(() => {
142
+ controller.abort();
143
+ reject(new Error(`Tool ${name} timed out after ${ms}ms`));
144
+ }, ms);
145
+ });
146
+ return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer));
147
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Local Agent Gateway — WebSocket server for local agent connections.
3
+ *
4
+ * Accepts outbound WebSocket connections from user machines running swag-agent.
5
+ * Authenticates per-store via API key, maintains connection pool, routes commands.
6
+ *
7
+ * Architecture:
8
+ * Claude Code → MCP stdio → Fly.io server → local_agent handler
9
+ * → this gateway → WebSocket → user's local swag-agent → execute locally
10
+ *
11
+ * Same pattern as kali.ts but routes through WebSocket instead of HTTP to Fly.io internal.
12
+ */
13
+ import { WebSocket } from "ws";
14
+ import type http from "node:http";
15
+ export interface LocalAgent {
16
+ ws: WebSocket;
17
+ storeId: string;
18
+ userId: string | null;
19
+ capabilities: string[];
20
+ connectedAt: Date;
21
+ lastPong: number;
22
+ agentId: string;
23
+ platform: string;
24
+ hostname: string;
25
+ }
26
+ export interface AgentResult {
27
+ success: boolean;
28
+ stdout?: string;
29
+ stderr?: string;
30
+ exit_code?: number;
31
+ data?: unknown;
32
+ error?: string;
33
+ killed?: boolean;
34
+ cwd?: string;
35
+ duration_ms?: number;
36
+ tools?: string[];
37
+ }
38
+ export declare function initLocalAgentGateway(server: http.Server): void;
39
+ /**
40
+ * Check if a store has a connected local agent.
41
+ */
42
+ export declare function hasLocalAgent(storeId: string): boolean;
43
+ /**
44
+ * Get info about connected agents for a store.
45
+ */
46
+ export declare function getAgentInfo(storeId: string): Array<{
47
+ agent_id: string;
48
+ platform: string;
49
+ hostname: string;
50
+ capabilities: string[];
51
+ connected_at: string;
52
+ uptime_seconds: number;
53
+ }>;
54
+ /**
55
+ * Execute a command on the user's local machine via their connected agent.
56
+ */
57
+ export declare function executeOnLocalAgent(storeId: string, command: string, options?: {
58
+ session_id?: string;
59
+ timeout?: number;
60
+ agent_id?: string;
61
+ }): Promise<AgentResult>;
62
+ /**
63
+ * Execute a managed tool on the local agent (burp, zap, tshark, etc.)
64
+ */
65
+ export declare function executeToolOnLocalAgent(storeId: string, tool: string, args: Record<string, unknown>, options?: {
66
+ timeout?: number;
67
+ agent_id?: string;
68
+ }): Promise<AgentResult>;
69
+ /**
70
+ * Request tool discovery from agent.
71
+ */
72
+ export declare function discoverLocalTools(storeId: string): Promise<AgentResult>;
73
+ /**
74
+ * Get gateway statistics.
75
+ */
76
+ export declare function getGatewayStats(): {
77
+ total_agents: number;
78
+ total_stores: number;
79
+ pending_requests: number;
80
+ agents_by_store: Record<string, number>;
81
+ };
82
+ export declare function shutdownGateway(): void;
@@ -0,0 +1,426 @@
1
+ /**
2
+ * Local Agent Gateway — WebSocket server for local agent connections.
3
+ *
4
+ * Accepts outbound WebSocket connections from user machines running swag-agent.
5
+ * Authenticates per-store via API key, maintains connection pool, routes commands.
6
+ *
7
+ * Architecture:
8
+ * Claude Code → MCP stdio → Fly.io server → local_agent handler
9
+ * → this gateway → WebSocket → user's local swag-agent → execute locally
10
+ *
11
+ * Same pattern as kali.ts but routes through WebSocket instead of HTTP to Fly.io internal.
12
+ */
13
+ import { WebSocketServer, WebSocket } from "ws";
14
+ import { randomUUID, createHash } from "node:crypto";
15
+ import { createClient } from "@supabase/supabase-js";
16
+ // ============================================================================
17
+ // CONNECTION POOL
18
+ // ============================================================================
19
+ /** Map<storeId, LocalAgent[]> — multiple agents per store (e.g. multiple machines) */
20
+ const agentPool = new Map();
21
+ /** Map<requestId, pending request> */
22
+ const pendingRequests = new Map();
23
+ const MAX_AGENTS_PER_STORE = 5;
24
+ const HEARTBEAT_INTERVAL_MS = 30_000;
25
+ const PONG_TIMEOUT_MS = 45_000;
26
+ const MAX_OUTPUT_CHARS = 500 * 1024; // 500KB safety cap — context_management handles limits
27
+ // ============================================================================
28
+ // GATEWAY
29
+ // ============================================================================
30
+ let wss = null;
31
+ let heartbeatTimer = null;
32
+ let supabaseClient = null;
33
+ export function initLocalAgentGateway(server) {
34
+ const SUPABASE_URL = process.env.SUPABASE_URL;
35
+ const SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY;
36
+ supabaseClient = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY);
37
+ wss = new WebSocketServer({ noServer: true });
38
+ // Handle HTTP upgrade on /agent/ws path
39
+ server.on("upgrade", (req, socket, head) => {
40
+ const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
41
+ if (url.pathname !== "/agent/ws") {
42
+ socket.destroy();
43
+ return;
44
+ }
45
+ wss.handleUpgrade(req, socket, head, (ws) => {
46
+ wss.emit("connection", ws, req);
47
+ });
48
+ });
49
+ wss.on("connection", handleConnection);
50
+ // Heartbeat — ping all agents, disconnect stale ones
51
+ heartbeatTimer = setInterval(() => {
52
+ const now = Date.now();
53
+ for (const [storeId, agents] of agentPool) {
54
+ for (let i = agents.length - 1; i >= 0; i--) {
55
+ const agent = agents[i];
56
+ if (now - agent.lastPong > PONG_TIMEOUT_MS) {
57
+ console.log(`[local-agent] Disconnecting stale agent ${agent.agentId} (store=${storeId})`);
58
+ agent.ws.terminate();
59
+ agents.splice(i, 1);
60
+ }
61
+ else if (agent.ws.readyState === WebSocket.OPEN) {
62
+ send(agent.ws, { type: "ping" });
63
+ }
64
+ }
65
+ if (agents.length === 0)
66
+ agentPool.delete(storeId);
67
+ }
68
+ }, HEARTBEAT_INTERVAL_MS);
69
+ heartbeatTimer.unref();
70
+ console.log("[local-agent] Gateway initialized on /agent/ws");
71
+ }
72
+ function handleConnection(ws, _req) {
73
+ let authenticated = false;
74
+ let agent = null;
75
+ // Auth timeout — must authenticate within 10 seconds
76
+ const authTimer = setTimeout(() => {
77
+ if (!authenticated) {
78
+ send(ws, { type: "error", error: "Authentication timeout" });
79
+ ws.close(4001, "Authentication timeout");
80
+ }
81
+ }, 10_000);
82
+ ws.on("message", async (raw) => {
83
+ let msg;
84
+ try {
85
+ msg = JSON.parse(raw.toString());
86
+ }
87
+ catch {
88
+ send(ws, { type: "error", error: "Invalid JSON" });
89
+ return;
90
+ }
91
+ // Handle auth
92
+ if (msg.type === "auth") {
93
+ clearTimeout(authTimer);
94
+ const authResult = await authenticateAgent(msg);
95
+ if (!authResult) {
96
+ send(ws, { type: "error", error: "Invalid API key" });
97
+ ws.close(4003, "Authentication failed");
98
+ return;
99
+ }
100
+ agent = {
101
+ ws,
102
+ storeId: authResult.storeId.toLowerCase(),
103
+ userId: authResult.userId,
104
+ capabilities: msg.capabilities || [],
105
+ connectedAt: new Date(),
106
+ lastPong: Date.now(),
107
+ agentId: randomUUID(),
108
+ platform: msg.platform || "unknown",
109
+ hostname: msg.hostname || "unknown",
110
+ };
111
+ // Add to pool
112
+ const existing = agentPool.get(agent.storeId) || [];
113
+ if (existing.length >= MAX_AGENTS_PER_STORE) {
114
+ // Disconnect oldest
115
+ const oldest = existing.shift();
116
+ send(oldest.ws, { type: "error", error: "Replaced by newer agent connection" });
117
+ oldest.ws.close(4004, "Replaced by newer connection");
118
+ }
119
+ existing.push(agent);
120
+ agentPool.set(agent.storeId, existing);
121
+ authenticated = true;
122
+ send(ws, {
123
+ type: "authenticated",
124
+ agent_id: agent.agentId,
125
+ message: `Connected to SwagManager. ${agent.capabilities.length} local tools registered.`,
126
+ });
127
+ console.log(`[local-agent] Agent connected: store=${agent.storeId} platform=${agent.platform} hostname=${agent.hostname} tools=${agent.capabilities.length}`);
128
+ // Audit log
129
+ if (supabaseClient) {
130
+ supabaseClient.from("audit_logs").insert({
131
+ action: "local_agent.connected",
132
+ severity: "info",
133
+ store_id: agent.storeId,
134
+ resource_type: "local_agent",
135
+ resource_id: agent.agentId,
136
+ source: "local_agent",
137
+ details: {
138
+ platform: agent.platform,
139
+ hostname: agent.hostname,
140
+ capabilities: agent.capabilities,
141
+ },
142
+ user_id: agent.userId,
143
+ }).then(({ error }) => {
144
+ if (error)
145
+ console.error("[local-agent] audit insert failed:", error.message);
146
+ });
147
+ }
148
+ return;
149
+ }
150
+ if (!authenticated || !agent) {
151
+ send(ws, { type: "error", error: "Not authenticated" });
152
+ return;
153
+ }
154
+ // Handle pong
155
+ if (msg.type === "pong") {
156
+ agent.lastPong = Date.now();
157
+ return;
158
+ }
159
+ // Handle tool discovery response
160
+ if (msg.type === "tools") {
161
+ agent.capabilities = msg.tools;
162
+ console.log(`[local-agent] Updated tools for ${agent.agentId}: ${msg.tools.join(", ")}`);
163
+ return;
164
+ }
165
+ // Handle command result
166
+ if (msg.type === "result") {
167
+ const pending = pendingRequests.get(msg.request_id);
168
+ if (!pending)
169
+ return; // Already timed out or cancelled
170
+ clearTimeout(pending.timer);
171
+ pendingRequests.delete(msg.request_id);
172
+ // Truncate large outputs
173
+ const result = {
174
+ success: msg.success,
175
+ stdout: truncate(msg.stdout),
176
+ stderr: truncate(msg.stderr),
177
+ exit_code: msg.exit_code,
178
+ data: msg.data,
179
+ error: msg.error,
180
+ killed: msg.killed,
181
+ cwd: msg.cwd,
182
+ duration_ms: msg.duration_ms,
183
+ };
184
+ pending.resolve(result);
185
+ }
186
+ });
187
+ ws.on("close", () => {
188
+ clearTimeout(authTimer);
189
+ if (agent) {
190
+ const agents = agentPool.get(agent.storeId);
191
+ if (agents) {
192
+ const idx = agents.findIndex(a => a.agentId === agent.agentId);
193
+ if (idx >= 0)
194
+ agents.splice(idx, 1);
195
+ if (agents.length === 0)
196
+ agentPool.delete(agent.storeId);
197
+ }
198
+ console.log(`[local-agent] Agent disconnected: ${agent.agentId} (store=${agent.storeId})`);
199
+ // Pending requests for this agent will be cleaned up by their timeouts
200
+ }
201
+ });
202
+ ws.on("error", (err) => {
203
+ console.error("[local-agent] WebSocket error:", err.message);
204
+ });
205
+ }
206
+ // ============================================================================
207
+ // AUTHENTICATION
208
+ // ============================================================================
209
+ async function authenticateAgent(msg) {
210
+ if (!supabaseClient || !msg.api_key)
211
+ return null;
212
+ const keyHash = createHash("sha256").update(msg.api_key).digest("hex");
213
+ // Look up API key by hash in api_keys table
214
+ const { data, error } = await supabaseClient
215
+ .from("api_keys")
216
+ .select("id, store_id, owner_user_id")
217
+ .eq("key_hash", keyHash)
218
+ .eq("is_active", true)
219
+ .single();
220
+ if (error || !data)
221
+ return null;
222
+ // Update last_used_at
223
+ supabaseClient.from("api_keys")
224
+ .update({ last_used_at: new Date().toISOString() })
225
+ .eq("id", data.id)
226
+ .then(() => { });
227
+ return { storeId: data.store_id, userId: data.owner_user_id || null };
228
+ }
229
+ // ============================================================================
230
+ // PUBLIC API — used by local-agent handler
231
+ // ============================================================================
232
+ /**
233
+ * Check if a store has a connected local agent.
234
+ */
235
+ export function hasLocalAgent(storeId) {
236
+ const agents = agentPool.get(storeId.toLowerCase());
237
+ return !!agents?.some(a => a.ws.readyState === WebSocket.OPEN);
238
+ }
239
+ /**
240
+ * Get info about connected agents for a store.
241
+ */
242
+ export function getAgentInfo(storeId) {
243
+ const agents = agentPool.get(storeId.toLowerCase()) || [];
244
+ return agents
245
+ .filter(a => a.ws.readyState === WebSocket.OPEN)
246
+ .map(a => ({
247
+ agent_id: a.agentId,
248
+ platform: a.platform,
249
+ hostname: a.hostname,
250
+ capabilities: a.capabilities,
251
+ connected_at: a.connectedAt.toISOString(),
252
+ uptime_seconds: Math.floor((Date.now() - a.connectedAt.getTime()) / 1000),
253
+ }));
254
+ }
255
+ /**
256
+ * Execute a command on the user's local machine via their connected agent.
257
+ */
258
+ export async function executeOnLocalAgent(storeId, command, options = {}) {
259
+ const agent = pickAgent(storeId, options.agent_id);
260
+ if (!agent) {
261
+ return {
262
+ success: false,
263
+ error: `No local agent connected for this store. Install and run: npx swagmanager-agent`,
264
+ };
265
+ }
266
+ const requestId = randomUUID();
267
+ const timeout = Math.min(options.timeout || 30000, 600000);
268
+ return new Promise((resolve, reject) => {
269
+ const timer = setTimeout(() => {
270
+ pendingRequests.delete(requestId);
271
+ resolve({
272
+ success: false,
273
+ error: `Local agent command timed out after ${timeout}ms`,
274
+ });
275
+ }, timeout + 5000); // 5s buffer over command timeout
276
+ pendingRequests.set(requestId, { resolve, reject, timer });
277
+ const msg = {
278
+ type: "exec",
279
+ request_id: requestId,
280
+ command,
281
+ session_id: options.session_id,
282
+ timeout,
283
+ };
284
+ send(agent.ws, msg);
285
+ });
286
+ }
287
+ /**
288
+ * Execute a managed tool on the local agent (burp, zap, tshark, etc.)
289
+ */
290
+ export async function executeToolOnLocalAgent(storeId, tool, args, options = {}) {
291
+ const agent = pickAgent(storeId, options.agent_id);
292
+ if (!agent) {
293
+ return {
294
+ success: false,
295
+ error: `No local agent connected. Install: npx swagmanager-agent`,
296
+ };
297
+ }
298
+ // Check if agent has this tool
299
+ if (!agent.capabilities.includes(tool)) {
300
+ return {
301
+ success: false,
302
+ error: `Local agent does not have tool "${tool}" installed. Available: ${agent.capabilities.join(", ") || "none"}`,
303
+ };
304
+ }
305
+ const requestId = randomUUID();
306
+ const timeout = Math.min(options.timeout || 30000, 600000);
307
+ return new Promise((resolve, reject) => {
308
+ const timer = setTimeout(() => {
309
+ pendingRequests.delete(requestId);
310
+ resolve({
311
+ success: false,
312
+ error: `Local tool "${tool}" timed out after ${timeout}ms`,
313
+ });
314
+ }, timeout + 5000);
315
+ pendingRequests.set(requestId, { resolve, reject, timer });
316
+ const msg = {
317
+ type: "tool_exec",
318
+ request_id: requestId,
319
+ tool,
320
+ args,
321
+ timeout,
322
+ };
323
+ send(agent.ws, msg);
324
+ });
325
+ }
326
+ /**
327
+ * Request tool discovery from agent.
328
+ */
329
+ export async function discoverLocalTools(storeId) {
330
+ const agent = pickAgent(storeId.toLowerCase());
331
+ if (!agent) {
332
+ return {
333
+ success: false,
334
+ error: `No local agent connected. Install: npx swagmanager-agent`,
335
+ };
336
+ }
337
+ const requestId = randomUUID();
338
+ return new Promise((resolve) => {
339
+ const timer = setTimeout(() => {
340
+ pendingRequests.delete(requestId);
341
+ resolve({ success: false, error: "Discovery timed out" });
342
+ }, 15000);
343
+ pendingRequests.set(requestId, {
344
+ resolve,
345
+ reject: () => resolve({ success: false, error: "Discovery failed" }),
346
+ timer,
347
+ });
348
+ send(agent.ws, { type: "discover", request_id: requestId });
349
+ });
350
+ }
351
+ /**
352
+ * Get gateway statistics.
353
+ */
354
+ export function getGatewayStats() {
355
+ const agentsByStore = {};
356
+ let totalAgents = 0;
357
+ for (const [storeId, agents] of agentPool) {
358
+ const active = agents.filter(a => a.ws.readyState === WebSocket.OPEN).length;
359
+ if (active > 0) {
360
+ agentsByStore[storeId] = active;
361
+ totalAgents += active;
362
+ }
363
+ }
364
+ return {
365
+ total_agents: totalAgents,
366
+ total_stores: Object.keys(agentsByStore).length,
367
+ pending_requests: pendingRequests.size,
368
+ agents_by_store: agentsByStore,
369
+ };
370
+ }
371
+ // ============================================================================
372
+ // INTERNALS
373
+ // ============================================================================
374
+ function pickAgent(storeId, agentId) {
375
+ const agents = agentPool.get(storeId.toLowerCase());
376
+ if (!agents?.length)
377
+ return null;
378
+ // Filter to open connections
379
+ const open = agents.filter(a => a.ws.readyState === WebSocket.OPEN);
380
+ if (open.length === 0)
381
+ return null;
382
+ // Target specific agent if requested
383
+ if (agentId) {
384
+ return open.find(a => a.agentId === agentId) || null;
385
+ }
386
+ // Pick agent with most recent pong (most responsive)
387
+ return open.reduce((best, a) => a.lastPong > best.lastPong ? a : best);
388
+ }
389
+ function send(ws, data) {
390
+ if (ws.readyState === WebSocket.OPEN) {
391
+ ws.send(JSON.stringify(data));
392
+ }
393
+ }
394
+ function truncate(text) {
395
+ if (!text || text.length <= MAX_OUTPUT_CHARS)
396
+ return text;
397
+ return text.substring(0, MAX_OUTPUT_CHARS) + `\n...[truncated, ${text.length} total chars]`;
398
+ }
399
+ // ============================================================================
400
+ // SHUTDOWN
401
+ // ============================================================================
402
+ export function shutdownGateway() {
403
+ if (heartbeatTimer) {
404
+ clearInterval(heartbeatTimer);
405
+ heartbeatTimer = null;
406
+ }
407
+ // Close all agent connections
408
+ for (const [, agents] of agentPool) {
409
+ for (const agent of agents) {
410
+ send(agent.ws, { type: "shutdown", message: "Server shutting down" });
411
+ agent.ws.close(1001, "Server shutdown");
412
+ }
413
+ }
414
+ agentPool.clear();
415
+ // Reject all pending requests
416
+ for (const [, pending] of pendingRequests) {
417
+ clearTimeout(pending.timer);
418
+ pending.resolve({ success: false, error: "Gateway shutting down" });
419
+ }
420
+ pendingRequests.clear();
421
+ if (wss) {
422
+ wss.close();
423
+ wss = null;
424
+ }
425
+ console.log("[local-agent] Gateway shut down");
426
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Anthropic Provider Adapter — direct Anthropic API passthrough.
3
+ *
4
+ * Simplest adapter: system prompt gets cache_control blocks, tools get
5
+ * { name, description, input_schema }, streaming events pass through as-is.
6
+ *
7
+ * Phase 7.1: Also encapsulates thinking config, context management,
8
+ * output token limits, and compaction config for Anthropic/Claude models.
9
+ */
10
+ import type { ProviderAdapter, ProviderStreamConfig, ProviderCapabilities, ThinkingConfigResult, ContextManagementConfig, CompactionConfig } from "./types.js";
11
+ import type http from "node:http";
12
+ export declare class AnthropicAdapter implements ProviderAdapter {
13
+ name: string;
14
+ handleStream(res: http.ServerResponse, config: ProviderStreamConfig, corsHeaders: Record<string, string>): Promise<void>;
15
+ getThinkingConfig(model: string, enabled: boolean): ThinkingConfigResult;
16
+ getMaxOutputTokens(model: string, agentMax?: number): number;
17
+ getContextManagement(model: string): ContextManagementConfig;
18
+ getCompactionConfig(_model: string): CompactionConfig;
19
+ getCapabilities(): ProviderCapabilities;
20
+ }