whale-code 6.4.0 → 6.5.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 (187) hide show
  1. package/bin/swagmanager-mcp.js +7 -0
  2. package/dist/cli/app.js +30 -2
  3. package/dist/cli/chat/ChatApp.d.ts +4 -4
  4. package/dist/cli/chat/ChatApp.js +114 -44
  5. package/dist/cli/chat/ChatInput.d.ts +13 -6
  6. package/dist/cli/chat/ChatInput.js +433 -89
  7. package/dist/cli/chat/MemoryManager.d.ts +15 -0
  8. package/dist/cli/chat/MemoryManager.js +61 -0
  9. package/dist/cli/chat/MessageList.d.ts +8 -0
  10. package/dist/cli/chat/MessageList.js +1 -1
  11. package/dist/cli/chat/NodeManager.d.ts +30 -0
  12. package/dist/cli/chat/NodeManager.js +89 -0
  13. package/dist/cli/chat/NodeSelector.d.ts +19 -0
  14. package/dist/cli/chat/NodeSelector.js +37 -0
  15. package/dist/cli/chat/PlanApproval.d.ts +17 -0
  16. package/dist/cli/chat/PlanApproval.js +82 -0
  17. package/dist/cli/chat/SessionManager.d.ts +16 -0
  18. package/dist/cli/chat/SessionManager.js +43 -0
  19. package/dist/cli/chat/SlashMenu.d.ts +38 -0
  20. package/dist/cli/chat/SlashMenu.js +208 -0
  21. package/dist/cli/chat/StatusBar.d.ts +16 -0
  22. package/dist/cli/chat/StatusBar.js +22 -0
  23. package/dist/cli/chat/ThemeSelector.d.ts +14 -0
  24. package/dist/cli/chat/ThemeSelector.js +29 -0
  25. package/dist/cli/chat/ToolIndicator.d.ts +8 -0
  26. package/dist/cli/chat/ToolIndicator.js +33 -9
  27. package/dist/cli/chat/hooks/useAgentLoop.d.ts +2 -1
  28. package/dist/cli/chat/hooks/useAgentLoop.js +22 -17
  29. package/dist/cli/chat/hooks/useSlashCommands.d.ts +19 -0
  30. package/dist/cli/chat/hooks/useSlashCommands.js +254 -15
  31. package/dist/cli/commands/config-cmd.js +4 -25
  32. package/dist/cli/commands/db.d.ts +13 -0
  33. package/dist/cli/commands/db.js +243 -0
  34. package/dist/cli/commands/doctor.js +6 -9
  35. package/dist/cli/commands/mcp.js +1 -20
  36. package/dist/cli/services/agent-events.d.ts +22 -1
  37. package/dist/cli/services/agent-events.js +9 -0
  38. package/dist/cli/services/agent-loop.js +66 -2
  39. package/dist/cli/services/agent-worker-base.js +21 -6
  40. package/dist/cli/services/api-retry.d.ts +25 -0
  41. package/dist/cli/services/api-retry.js +91 -0
  42. package/dist/cli/services/auth-service.d.ts +1 -1
  43. package/dist/cli/services/auth-service.js +40 -19
  44. package/dist/cli/services/background-processes.js +26 -2
  45. package/dist/cli/services/config-store.d.ts +13 -1
  46. package/dist/cli/services/config-store.js +116 -13
  47. package/dist/cli/services/format-server-response.js +12 -6
  48. package/dist/cli/services/ink-resize-fix.d.ts +18 -0
  49. package/dist/cli/services/ink-resize-fix.js +66 -0
  50. package/dist/cli/services/interactive-tools.d.ts +14 -0
  51. package/dist/cli/services/interactive-tools.js +47 -2
  52. package/dist/cli/services/keybinding-manager.js +1 -1
  53. package/dist/cli/services/local-tools.js +35 -2
  54. package/dist/cli/services/server-tools.js +175 -3
  55. package/dist/cli/services/subagent.js +15 -3
  56. package/dist/cli/services/system-prompt.js +5 -3
  57. package/dist/cli/services/task-decomposer.d.ts +35 -0
  58. package/dist/cli/services/task-decomposer.js +199 -0
  59. package/dist/cli/services/team-lead.d.ts +18 -0
  60. package/dist/cli/services/team-lead.js +80 -0
  61. package/dist/cli/services/teammate.js +5 -5
  62. package/dist/cli/services/telemetry.d.ts +8 -2
  63. package/dist/cli/services/telemetry.js +116 -92
  64. package/dist/cli/services/tools/agent-tools.d.ts +1 -0
  65. package/dist/cli/services/tools/agent-tools.js +50 -4
  66. package/dist/cli/services/tools/file-ops.d.ts +2 -0
  67. package/dist/cli/services/tools/file-ops.js +71 -19
  68. package/dist/cli/services/tools/shell-exec.js +22 -12
  69. package/dist/cli/shared/Theme.d.ts +1 -2
  70. package/dist/cli/shared/Theme.js +1 -1
  71. package/dist/cli/shared/WhaleBanner.d.ts +4 -1
  72. package/dist/cli/shared/WhaleBanner.js +12 -8
  73. package/dist/cli/shared/markdown.d.ts +5 -4
  74. package/dist/cli/shared/markdown.js +376 -334
  75. package/dist/cli/shared/theme-manager.d.ts +27 -0
  76. package/dist/cli/shared/theme-manager.js +178 -0
  77. package/dist/cli/shared/theme-presets.d.ts +16 -0
  78. package/dist/cli/shared/theme-presets.js +265 -0
  79. package/dist/index.js +0 -51
  80. package/dist/node/adapters/imessage.d.ts +10 -0
  81. package/dist/node/adapters/imessage.js +45 -6
  82. package/dist/node/cli.js +459 -8
  83. package/dist/node/config.d.ts +17 -0
  84. package/dist/node/gateway-client.d.ts +55 -0
  85. package/dist/node/gateway-client.js +201 -0
  86. package/dist/node/portal/clipboard.d.ts +28 -0
  87. package/dist/node/portal/clipboard.js +183 -0
  88. package/dist/node/portal/discovery.d.ts +29 -0
  89. package/dist/node/portal/discovery.js +61 -0
  90. package/dist/node/portal/forward.d.ts +30 -0
  91. package/dist/node/portal/forward.js +90 -0
  92. package/dist/node/portal/index.d.ts +47 -0
  93. package/dist/node/portal/index.js +250 -0
  94. package/dist/node/portal/multiplexer.d.ts +48 -0
  95. package/dist/node/portal/multiplexer.js +207 -0
  96. package/dist/node/portal/permissions.d.ts +36 -0
  97. package/dist/node/portal/permissions.js +131 -0
  98. package/dist/node/portal/protocol.d.ts +140 -0
  99. package/dist/node/portal/protocol.js +193 -0
  100. package/dist/node/portal/screen.d.ts +18 -0
  101. package/dist/node/portal/screen.js +93 -0
  102. package/dist/node/portal/session.d.ts +68 -0
  103. package/dist/node/portal/session.js +127 -0
  104. package/dist/node/portal/shell.d.ts +26 -0
  105. package/dist/node/portal/shell.js +142 -0
  106. package/dist/node/portal/stream.d.ts +43 -0
  107. package/dist/node/portal/stream.js +90 -0
  108. package/dist/node/portal/transfer.d.ts +33 -0
  109. package/dist/node/portal/transfer.js +231 -0
  110. package/dist/node/portal/ui.d.ts +16 -0
  111. package/dist/node/portal/ui.js +148 -0
  112. package/dist/node/remote-desktop/compile-helper.d.ts +13 -0
  113. package/dist/node/remote-desktop/compile-helper.js +73 -0
  114. package/dist/node/remote-desktop/index.d.ts +67 -0
  115. package/dist/node/remote-desktop/index.js +220 -0
  116. package/dist/node/remote-desktop/protocol.d.ts +96 -0
  117. package/dist/node/remote-desktop/protocol.js +67 -0
  118. package/dist/node/runtime.d.ts +8 -1
  119. package/dist/node/runtime.js +117 -9
  120. package/dist/server/handlers/__test-utils__/test-db.d.ts +25 -0
  121. package/dist/server/handlers/__test-utils__/test-db.js +128 -0
  122. package/dist/server/handlers/api-keys.js +26 -2
  123. package/dist/server/handlers/browser.d.ts +0 -4
  124. package/dist/server/handlers/browser.js +0 -46
  125. package/dist/server/handlers/catalog.js +37 -14
  126. package/dist/server/handlers/clickhouse.d.ts +10 -0
  127. package/dist/server/handlers/clickhouse.js +215 -0
  128. package/dist/server/handlers/comms.d.ts +308 -4
  129. package/dist/server/handlers/comms.js +444 -11
  130. package/dist/server/handlers/creations.js +1 -1
  131. package/dist/server/handlers/crm.d.ts +54 -8
  132. package/dist/server/handlers/crm.js +353 -68
  133. package/dist/server/handlers/embeddings.js +3 -3
  134. package/dist/server/handlers/enrichment.js +39 -55
  135. package/dist/server/handlers/inventory.js +1 -1
  136. package/dist/server/handlers/kali.d.ts +9 -1
  137. package/dist/server/handlers/kali.js +50 -1
  138. package/dist/server/handlers/media.d.ts +8 -0
  139. package/dist/server/handlers/media.js +902 -0
  140. package/dist/server/handlers/meta-ads.js +6 -3
  141. package/dist/server/handlers/nodes.d.ts +2 -0
  142. package/dist/server/handlers/nodes.js +331 -40
  143. package/dist/server/handlers/operations.d.ts +4 -6
  144. package/dist/server/handlers/operations.js +99 -38
  145. package/dist/server/handlers/platform.js +224 -107
  146. package/dist/server/handlers/remove-bg.d.ts +6 -0
  147. package/dist/server/handlers/remove-bg.js +96 -0
  148. package/dist/server/handlers/storefront.d.ts +6 -0
  149. package/dist/server/handlers/storefront.js +477 -0
  150. package/dist/server/handlers/supply-chain.js +21 -3
  151. package/dist/server/handlers/workflow-steps.js +87 -31
  152. package/dist/server/handlers/workflows.js +4 -1
  153. package/dist/server/index.js +334 -88
  154. package/dist/server/lib/clickhouse-buffer.d.ts +48 -0
  155. package/dist/server/lib/clickhouse-buffer.js +175 -0
  156. package/dist/server/lib/clickhouse-client.d.ts +112 -0
  157. package/dist/server/lib/clickhouse-client.js +141 -0
  158. package/dist/server/lib/coa-renderer.d.ts +91 -0
  159. package/dist/server/lib/coa-renderer.js +411 -0
  160. package/dist/server/lib/compaction-service.js +45 -1
  161. package/dist/server/lib/pdf-renderer.d.ts +143 -0
  162. package/dist/server/lib/pdf-renderer.js +867 -0
  163. package/dist/server/lib/react-pdf-layout.d.ts +40 -0
  164. package/dist/server/lib/react-pdf-layout.js +437 -0
  165. package/dist/server/lib/server-agent-loop.d.ts +2 -0
  166. package/dist/server/lib/server-agent-loop.js +61 -15
  167. package/dist/server/lib/server-subagent.d.ts +3 -0
  168. package/dist/server/lib/server-subagent.js +7 -4
  169. package/dist/server/lib/supabase-client.js +51 -3
  170. package/dist/server/lib/template-resolver.js +14 -4
  171. package/dist/server/lib/utils.js +15 -0
  172. package/dist/server/local-agent-gateway.d.ts +44 -0
  173. package/dist/server/local-agent-gateway.js +389 -49
  174. package/dist/server/providers/anthropic.js +12 -2
  175. package/dist/server/providers/gemini.js +17 -2
  176. package/dist/server/proxy-handlers.js +151 -0
  177. package/dist/server/tool-router.d.ts +2 -2
  178. package/dist/server/tool-router.js +25 -35
  179. package/dist/shared/agent-core.d.ts +5 -2
  180. package/dist/shared/agent-core.js +30 -4
  181. package/dist/shared/api-client.js +54 -3
  182. package/dist/shared/sse-parser.d.ts +1 -1
  183. package/dist/shared/sse-parser.js +5 -2
  184. package/dist/shared/tool-dispatch.js +1 -1
  185. package/package.json +16 -10
  186. package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +0 -11
  187. package/dist/server/handlers/__test-utils__/mock-supabase.js +0 -393
@@ -12,7 +12,10 @@ import { batchClient } from "../lib/batch-client.js";
12
12
  import { getProvider } from "../../shared/constants.js";
13
13
  import { createLogger } from "../lib/logger.js";
14
14
  import { startSpan } from "../lib/otel.js";
15
+ import { queueSpan, auditRowToSpan, classifyErrorType } from "../lib/clickhouse-buffer.js";
15
16
  const log = createLogger("workflow-steps");
17
+ // In-memory sliding-window rate limiter for webhooks (replaces audit_logs read)
18
+ const webhookRateCounters = new Map();
16
19
  // ============================================================================
17
20
  // CONSTANTS
18
21
  // ============================================================================
@@ -1053,13 +1056,13 @@ async function updateToolCircuitBreaker(supabase, toolId, success, errorMessage)
1053
1056
  circuit_breaker_state: "open", circuit_breaker_failures: newFailures,
1054
1057
  circuit_breaker_tripped_at: new Date().toISOString(),
1055
1058
  }).eq("id", toolId);
1056
- const { error: toolCbErr } = await supabase.from("audit_logs").insert({
1059
+ queueSpan(auditRowToSpan({
1057
1060
  action: "workflow.circuit_breaker.tripped", severity: "warning",
1058
1061
  resource_type: "user_tool", resource_id: toolId, source: "workflow_engine",
1062
+ service_name: "workflow-engine", span_kind: "INTERNAL", status_code: "OK",
1063
+ start_time: new Date().toISOString(), end_time: new Date().toISOString(),
1059
1064
  details: { failures: newFailures, threshold: data.circuit_breaker_threshold },
1060
- });
1061
- if (toolCbErr)
1062
- log.warn({ err: toolCbErr.message, toolId }, "tool circuit breaker audit failed");
1065
+ }));
1063
1066
  }
1064
1067
  else {
1065
1068
  await supabase.from("user_tools").update({ circuit_breaker_failures: newFailures }).eq("id", toolId);
@@ -1085,13 +1088,13 @@ async function handleWorkflowCircuitBreaker(supabase, workflowId, success, error
1085
1088
  circuit_breaker_state: "open", circuit_breaker_failures: newFailures,
1086
1089
  circuit_breaker_tripped_at: new Date().toISOString(),
1087
1090
  }).eq("id", workflowId);
1088
- const { error: wfCbErr } = await supabase.from("audit_logs").insert({
1091
+ queueSpan(auditRowToSpan({
1089
1092
  action: "workflow.circuit_breaker.tripped", severity: "warning",
1090
1093
  resource_type: "workflow", resource_id: workflowId, source: "workflow_engine",
1094
+ service_name: "workflow-engine", span_kind: "INTERNAL", status_code: "OK",
1095
+ start_time: new Date().toISOString(), end_time: new Date().toISOString(),
1091
1096
  details: { failures: newFailures, threshold: data.circuit_breaker_threshold },
1092
- });
1093
- if (wfCbErr)
1094
- log.warn({ err: wfCbErr.message, workflowId }, "workflow circuit breaker audit failed");
1097
+ }));
1095
1098
  }
1096
1099
  else {
1097
1100
  await supabase.from("workflows").update({ circuit_breaker_failures: newFailures }).eq("id", workflowId);
@@ -1286,6 +1289,49 @@ export async function processWaitingSteps(supabase) {
1286
1289
  }
1287
1290
  }
1288
1291
  }
1292
+ // 1b. Goal steps waiting for goal completion
1293
+ const { data: goalSteps } = await supabase
1294
+ .from("workflow_step_runs")
1295
+ .select("id, run_id, step_key, output, step_type")
1296
+ .eq("status", "waiting")
1297
+ .eq("step_type", "goal")
1298
+ .limit(50);
1299
+ if (goalSteps?.length) {
1300
+ const goalIds = goalSteps
1301
+ .map(s => s.output?.goal_id)
1302
+ .filter(Boolean);
1303
+ if (goalIds.length) {
1304
+ const { data: goals } = await supabase
1305
+ .from("goals")
1306
+ .select("id, status, final_summary, failure_reason, total_cost_usd, total_rounds")
1307
+ .in("id", goalIds)
1308
+ .in("status", ["completed", "failed", "cancelled"]);
1309
+ if (goals?.length) {
1310
+ const goalMap = new Map(goals.map(g => [g.id, g]));
1311
+ for (const step of goalSteps) {
1312
+ const goalId = step.output?.goal_id;
1313
+ const goal = goalMap.get(goalId);
1314
+ if (!goal)
1315
+ continue;
1316
+ const success = goal.status === "completed";
1317
+ await supabase.from("workflow_step_runs").update({
1318
+ status: success ? "success" : "failed",
1319
+ output: {
1320
+ goal_id: goalId,
1321
+ goal_status: goal.status,
1322
+ summary: goal.final_summary,
1323
+ total_cost_usd: goal.total_cost_usd,
1324
+ total_rounds: goal.total_rounds,
1325
+ },
1326
+ error_message: success ? null : goal.failure_reason,
1327
+ completed_at: new Date().toISOString(),
1328
+ }).eq("id", step.id);
1329
+ await accumulateAndAdvance(supabase, step.id, step.run_id, step.step_key, success, { goal_id: goalId, summary: goal.final_summary }, success ? null : goal.failure_reason);
1330
+ resolved++;
1331
+ }
1332
+ }
1333
+ }
1334
+ }
1289
1335
  // 2. P1 FIX: Use aggregate RPC to eliminate N+1 queries (was 4 queries per parent)
1290
1336
  const { data: aggregatedParents, error: aggErr } = await supabase.rpc("get_waiting_parents_with_children");
1291
1337
  if (aggErr) {
@@ -1779,18 +1825,21 @@ export async function executeAndAdvance(supabase, step, traceId) {
1779
1825
  if (cpError)
1780
1826
  log.warn({ err: cpError.message, runId: step.run_id, stepKey: step.step_key }, "checkpoint insert failed");
1781
1827
  }
1782
- // Audit
1783
- const { error: stepAuditErr } = await supabase.from("audit_logs").insert({
1828
+ // Telemetry → ClickHouse
1829
+ queueSpan(auditRowToSpan({
1784
1830
  action: `workflow.step.${result.success ? "completed" : "failed"}`,
1785
1831
  severity: result.success ? "info" : "error",
1786
1832
  store_id: step.store_id, resource_type: "workflow_step_run",
1787
1833
  resource_id: step.step_run_id, source: "workflow_engine", duration_ms: durationMs,
1788
1834
  request_id: traceId || null,
1835
+ service_name: "workflow-engine", span_kind: "INTERNAL",
1836
+ status_code: result.success ? "OK" : "ERROR",
1837
+ start_time: new Date(Date.now() - durationMs).toISOString(),
1838
+ end_time: new Date().toISOString(),
1839
+ error_type: result.error ? classifyErrorType(result.error) : undefined,
1789
1840
  details: { workflow_id: step.workflow_id, run_id: step.run_id, step_key: step.step_key, step_type: step.step_type, attempt: step.attempt_count },
1790
1841
  error_message: result.error || null,
1791
- });
1792
- if (stepAuditErr)
1793
- log.warn({ err: stepAuditErr.message, runId: step.run_id }, "step audit insert failed");
1842
+ }));
1794
1843
  // Surface step errors to clients via SSE broadcast + structured error_details
1795
1844
  if (!result.success && result.error) {
1796
1845
  await surfaceStepError(supabase, step, result.error);
@@ -2073,7 +2122,7 @@ export async function executeInlineChain(supabase, runId, depth = 0, traceId) {
2073
2122
  return;
2074
2123
  }
2075
2124
  // Steps that go async (delay, sub_workflow, parallel, for_each, approval) don't chain
2076
- const asyncTypes = new Set(["delay", "sub_workflow", "parallel", "for_each", "approval", "waitpoint"]);
2125
+ const asyncTypes = new Set(["delay", "sub_workflow", "parallel", "for_each", "approval", "waitpoint", "goal"]);
2077
2126
  if (asyncTypes.has(step.step_type))
2078
2127
  return;
2079
2128
  // Chain to next step
@@ -2185,17 +2234,20 @@ export async function completeWorkflowRun(supabase, runId, workflowId, storeId,
2185
2234
  // Circuit breaker
2186
2235
  if (workflowId)
2187
2236
  await handleWorkflowCircuitBreaker(supabase, workflowId, status === "success", errorMessage);
2188
- // Audit
2189
- const { error: runAuditErr } = await supabase.from("audit_logs").insert({
2237
+ // Telemetry → ClickHouse
2238
+ queueSpan(auditRowToSpan({
2190
2239
  action: `workflow.run.${status}`, severity: status === "success" ? "info" : "error",
2191
2240
  store_id: storeId || null, resource_type: "workflow_run", resource_id: runId,
2192
2241
  source: "workflow_engine", duration_ms: durationMs,
2193
2242
  request_id: resolvedTraceId,
2243
+ service_name: "workflow-engine", span_kind: "INTERNAL",
2244
+ status_code: status === "success" ? "OK" : "ERROR",
2245
+ start_time: new Date(Date.now() - (durationMs || 0)).toISOString(),
2246
+ end_time: new Date().toISOString(),
2247
+ error_type: errorMessage ? classifyErrorType(errorMessage) : undefined,
2194
2248
  details: { workflow_id: workflowId, run_id: runId },
2195
2249
  error_message: errorMessage || null,
2196
- });
2197
- if (runAuditErr)
2198
- log.warn({ err: runAuditErr.message, runId }, "run completion audit failed");
2250
+ }));
2199
2251
  // Error notifications
2200
2252
  if (status === "failed" && workflowId) {
2201
2253
  await sendErrorNotification(supabase, workflowId, runId, storeId, errorMessage, errorStepKey);
@@ -2265,15 +2317,18 @@ export async function handleWebhookIngestion(supabase, slug, rawBody, headers, s
2265
2317
  const endpoint = endpoints?.[0];
2266
2318
  if (!endpoint)
2267
2319
  return { status: 404, body: { error: "Webhook endpoint not found" } };
2268
- // Rate limit
2269
- const oneMinAgo = new Date(Date.now() - 60_000).toISOString();
2270
- const { count: recentCount } = await supabase.from("audit_logs")
2271
- .select("id", { count: "exact", head: true })
2272
- .eq("resource_type", "webhook_endpoint").eq("resource_id", endpoint.id)
2273
- .gte("created_at", oneMinAgo);
2274
- if ((recentCount || 0) >= endpoint.max_requests_per_minute) {
2320
+ // Rate limit — in-memory sliding window (no DB round-trip)
2321
+ const now = Date.now();
2322
+ let counter = webhookRateCounters.get(endpoint.id);
2323
+ if (!counter) {
2324
+ counter = { timestamps: [] };
2325
+ webhookRateCounters.set(endpoint.id, counter);
2326
+ }
2327
+ counter.timestamps = counter.timestamps.filter(t => t > now - 60_000);
2328
+ if (counter.timestamps.length >= endpoint.max_requests_per_minute) {
2275
2329
  return { status: 429, body: { error: "Rate limit exceeded" } };
2276
2330
  }
2331
+ counter.timestamps.push(now);
2277
2332
  // HMAC verification
2278
2333
  if (endpoint.verify_signature) {
2279
2334
  const signature = headers["x-webhook-signature"] || headers["x-hub-signature-256"] || "";
@@ -2311,14 +2366,15 @@ export async function handleWebhookIngestion(supabase, slug, rawBody, headers, s
2311
2366
  last_received_at: new Date().toISOString(),
2312
2367
  total_received: (endpoint.total_received || 0) + 1,
2313
2368
  }).eq("id", endpoint.id);
2314
- // Audit
2315
- const { error: whAuditErr } = await supabase.from("audit_logs").insert({
2369
+ // Telemetry → ClickHouse
2370
+ queueSpan(auditRowToSpan({
2316
2371
  action: "webhook.received", severity: "info", store_id: endpoint.store_id,
2317
2372
  resource_type: "webhook_endpoint", resource_id: endpoint.id, source: "webhook",
2373
+ service_name: "workflow-engine", span_kind: "SERVER", status_code: "OK",
2374
+ start_time: new Date().toISOString(), end_time: new Date().toISOString(),
2375
+ input_bytes: rawBody.length,
2318
2376
  details: { slug, workflow_id: endpoint.workflow_id },
2319
- });
2320
- if (whAuditErr)
2321
- log.warn({ err: whAuditErr.message, slug }, "webhook audit insert failed");
2377
+ }));
2322
2378
  // Start workflow
2323
2379
  const { data: startResult } = await supabase.rpc("start_workflow_run", {
2324
2380
  p_workflow_id: endpoint.workflow_id, p_store_id: endpoint.store_id,
@@ -962,7 +962,7 @@ export async function handleWorkflows(supabase, args, storeId) {
962
962
  }
963
963
  case "list_tools": {
964
964
  const { data, error } = await supabase.from("ai_tool_registry")
965
- .select("name, description, category, definition")
965
+ .select("name, description, category, definition, tool_mode, is_read_only, requires_store_id")
966
966
  .eq("is_active", true)
967
967
  .or("tool_mode.is.null,tool_mode.neq.code")
968
968
  .order("category").order("name");
@@ -979,6 +979,9 @@ export async function handleWorkflows(supabase, args, storeId) {
979
979
  category: row.category || "other",
980
980
  actions,
981
981
  input_schema: inputSchema || null,
982
+ tool_mode: row.tool_mode || null,
983
+ is_read_only: row.is_read_only ?? false,
984
+ requires_store_id: row.requires_store_id ?? false,
982
985
  };
983
986
  });
984
987
  return { success: true, data: { tools } };