@superblocksteam/gateway 2.0.0-SNAPSHOT.1d4c72c0ab174c21

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 (248) hide show
  1. package/LICENSE.txt +87 -0
  2. package/README.md +291 -0
  3. package/dist/agents/resolve-orchestrator-url.d.ts +22 -0
  4. package/dist/agents/resolve-orchestrator-url.js +38 -0
  5. package/dist/agents/resolve-orchestrator-url.js.map +1 -0
  6. package/dist/capabilities/integration-metadata.d.ts +28 -0
  7. package/dist/capabilities/integration-metadata.js +174 -0
  8. package/dist/capabilities/integration-metadata.js.map +1 -0
  9. package/dist/capabilities/lifecycle.d.ts +93 -0
  10. package/dist/capabilities/lifecycle.js +3450 -0
  11. package/dist/capabilities/lifecycle.js.map +1 -0
  12. package/dist/capabilities/query-integration.d.ts +14 -0
  13. package/dist/capabilities/query-integration.js +172 -0
  14. package/dist/capabilities/query-integration.js.map +1 -0
  15. package/dist/capabilities/source-files-archive.d.ts +11 -0
  16. package/dist/capabilities/source-files-archive.js +54 -0
  17. package/dist/capabilities/source-files-archive.js.map +1 -0
  18. package/dist/capabilities/types.d.ts +542 -0
  19. package/dist/capabilities/types.js +86 -0
  20. package/dist/capabilities/types.js.map +1 -0
  21. package/dist/capture/browser-contract.d.ts +46 -0
  22. package/dist/capture/browser-contract.js +34 -0
  23. package/dist/capture/browser-contract.js.map +1 -0
  24. package/dist/capture/browser-instructions.d.ts +10 -0
  25. package/dist/capture/browser-instructions.js +18 -0
  26. package/dist/capture/browser-instructions.js.map +1 -0
  27. package/dist/capture/capture-library-probe.d.ts +55 -0
  28. package/dist/capture/capture-library-probe.js +177 -0
  29. package/dist/capture/capture-library-probe.js.map +1 -0
  30. package/dist/capture/capture-library.d.ts +52 -0
  31. package/dist/capture/capture-library.js +249 -0
  32. package/dist/capture/capture-library.js.map +1 -0
  33. package/dist/capture/classify-library-paint.d.ts +21 -0
  34. package/dist/capture/classify-library-paint.js +13 -0
  35. package/dist/capture/classify-library-paint.js.map +1 -0
  36. package/dist/capture/host-mcp-scan.d.ts +16 -0
  37. package/dist/capture/host-mcp-scan.js +64 -0
  38. package/dist/capture/host-mcp-scan.js.map +1 -0
  39. package/dist/capture/library-parent-script.d.ts +35 -0
  40. package/dist/capture/library-parent-script.js +82 -0
  41. package/dist/capture/library-parent-script.js.map +1 -0
  42. package/dist/capture/mode.d.ts +29 -0
  43. package/dist/capture/mode.js +65 -0
  44. package/dist/capture/mode.js.map +1 -0
  45. package/dist/config.d.ts +148 -0
  46. package/dist/config.js +111 -0
  47. package/dist/config.js.map +1 -0
  48. package/dist/debug.d.ts +2 -0
  49. package/dist/debug.js +9 -0
  50. package/dist/debug.js.map +1 -0
  51. package/dist/deps.d.ts +38 -0
  52. package/dist/deps.js +2 -0
  53. package/dist/deps.js.map +1 -0
  54. package/dist/health/readiness.d.ts +99 -0
  55. package/dist/health/readiness.js +202 -0
  56. package/dist/health/readiness.js.map +1 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.js +8 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/integrations/filters.d.ts +8 -0
  61. package/dist/integrations/filters.js +40 -0
  62. package/dist/integrations/filters.js.map +1 -0
  63. package/dist/integrations/map.d.ts +27 -0
  64. package/dist/integrations/map.js +43 -0
  65. package/dist/integrations/map.js.map +1 -0
  66. package/dist/integrations/profile-key.d.ts +19 -0
  67. package/dist/integrations/profile-key.js +35 -0
  68. package/dist/integrations/profile-key.js.map +1 -0
  69. package/dist/integrations/read-only-postgres-query.d.ts +2 -0
  70. package/dist/integrations/read-only-postgres-query.js +164 -0
  71. package/dist/integrations/read-only-postgres-query.js.map +1 -0
  72. package/dist/main.d.ts +2 -0
  73. package/dist/main.js +5 -0
  74. package/dist/main.js.map +1 -0
  75. package/dist/orchestrator/client.d.ts +62 -0
  76. package/dist/orchestrator/client.js +160 -0
  77. package/dist/orchestrator/client.js.map +1 -0
  78. package/dist/playwright/ensure-chromium.d.ts +24 -0
  79. package/dist/playwright/ensure-chromium.js +60 -0
  80. package/dist/playwright/ensure-chromium.js.map +1 -0
  81. package/dist/preview/capture-screenshot.d.ts +67 -0
  82. package/dist/preview/capture-screenshot.js +179 -0
  83. package/dist/preview/capture-screenshot.js.map +1 -0
  84. package/dist/preview/viewer-url.d.ts +82 -0
  85. package/dist/preview/viewer-url.js +130 -0
  86. package/dist/preview/viewer-url.js.map +1 -0
  87. package/dist/process/fault-barrier.d.ts +55 -0
  88. package/dist/process/fault-barrier.js +113 -0
  89. package/dist/process/fault-barrier.js.map +1 -0
  90. package/dist/sabs/agent-facing-text.d.ts +35 -0
  91. package/dist/sabs/agent-facing-text.js +165 -0
  92. package/dist/sabs/agent-facing-text.js.map +1 -0
  93. package/dist/sabs/app-state.d.ts +126 -0
  94. package/dist/sabs/app-state.js +332 -0
  95. package/dist/sabs/app-state.js.map +1 -0
  96. package/dist/sabs/awaited-decision.d.ts +47 -0
  97. package/dist/sabs/awaited-decision.js +124 -0
  98. package/dist/sabs/awaited-decision.js.map +1 -0
  99. package/dist/sabs/browser-context.d.ts +53 -0
  100. package/dist/sabs/browser-context.js +92 -0
  101. package/dist/sabs/browser-context.js.map +1 -0
  102. package/dist/sabs/editor-client-methods.d.ts +164 -0
  103. package/dist/sabs/editor-client-methods.js +750 -0
  104. package/dist/sabs/editor-client-methods.js.map +1 -0
  105. package/dist/sabs/editor-socket.d.ts +84 -0
  106. package/dist/sabs/editor-socket.js +64 -0
  107. package/dist/sabs/editor-socket.js.map +1 -0
  108. package/dist/sabs/recent-tool-runs.d.ts +14 -0
  109. package/dist/sabs/recent-tool-runs.js +61 -0
  110. package/dist/sabs/recent-tool-runs.js.map +1 -0
  111. package/dist/sabs/session-peer.d.ts +392 -0
  112. package/dist/sabs/session-peer.js +11 -0
  113. package/dist/sabs/session-peer.js.map +1 -0
  114. package/dist/sabs/streamed-reply.d.ts +42 -0
  115. package/dist/sabs/streamed-reply.js +110 -0
  116. package/dist/sabs/streamed-reply.js.map +1 -0
  117. package/dist/sabs/turn-collector.d.ts +169 -0
  118. package/dist/sabs/turn-collector.js +506 -0
  119. package/dist/sabs/turn-collector.js.map +1 -0
  120. package/dist/sabs/websocket-session-peer.d.ts +540 -0
  121. package/dist/sabs/websocket-session-peer.js +3289 -0
  122. package/dist/sabs/websocket-session-peer.js.map +1 -0
  123. package/dist/security/constant-time.d.ts +9 -0
  124. package/dist/security/constant-time.js +13 -0
  125. package/dist/security/constant-time.js.map +1 -0
  126. package/dist/server/client.d.ts +405 -0
  127. package/dist/server/client.js +684 -0
  128. package/dist/server/client.js.map +1 -0
  129. package/dist/server/identity-reads.d.ts +76 -0
  130. package/dist/server/identity-reads.js +209 -0
  131. package/dist/server/identity-reads.js.map +1 -0
  132. package/dist/start.d.ts +24 -0
  133. package/dist/start.js +81 -0
  134. package/dist/start.js.map +1 -0
  135. package/dist/stores/memory.d.ts +42 -0
  136. package/dist/stores/memory.js +121 -0
  137. package/dist/stores/memory.js.map +1 -0
  138. package/dist/stores/types.d.ts +74 -0
  139. package/dist/stores/types.js +11 -0
  140. package/dist/stores/types.js.map +1 -0
  141. package/dist/telemetry/mcp-client.d.ts +22 -0
  142. package/dist/telemetry/mcp-client.js +140 -0
  143. package/dist/telemetry/mcp-client.js.map +1 -0
  144. package/dist/telemetry/metrics.d.ts +41 -0
  145. package/dist/telemetry/metrics.js +103 -0
  146. package/dist/telemetry/metrics.js.map +1 -0
  147. package/dist/telemetry/runtime.d.ts +9 -0
  148. package/dist/telemetry/runtime.js +118 -0
  149. package/dist/telemetry/runtime.js.map +1 -0
  150. package/dist/transports/mcp/admin-tools.d.ts +56 -0
  151. package/dist/transports/mcp/admin-tools.js +252 -0
  152. package/dist/transports/mcp/admin-tools.js.map +1 -0
  153. package/dist/transports/mcp/app-status-html.d.ts +11 -0
  154. package/dist/transports/mcp/app-status-html.js +899 -0
  155. package/dist/transports/mcp/app-status-html.js.map +1 -0
  156. package/dist/transports/mcp/client-presentation.d.ts +16 -0
  157. package/dist/transports/mcp/client-presentation.js +13 -0
  158. package/dist/transports/mcp/client-presentation.js.map +1 -0
  159. package/dist/transports/mcp/cowork-editor-url.d.ts +6 -0
  160. package/dist/transports/mcp/cowork-editor-url.js +10 -0
  161. package/dist/transports/mcp/cowork-editor-url.js.map +1 -0
  162. package/dist/transports/mcp/decision-card-html.d.ts +26 -0
  163. package/dist/transports/mcp/decision-card-html.js +876 -0
  164. package/dist/transports/mcp/decision-card-html.js.map +1 -0
  165. package/dist/transports/mcp/decision-elicitation.d.ts +116 -0
  166. package/dist/transports/mcp/decision-elicitation.js +292 -0
  167. package/dist/transports/mcp/decision-elicitation.js.map +1 -0
  168. package/dist/transports/mcp/dispatch-probe.d.ts +24 -0
  169. package/dist/transports/mcp/dispatch-probe.js +48 -0
  170. package/dist/transports/mcp/dispatch-probe.js.map +1 -0
  171. package/dist/transports/mcp/editor-document-probe.d.ts +4 -0
  172. package/dist/transports/mcp/editor-document-probe.js +35 -0
  173. package/dist/transports/mcp/editor-document-probe.js.map +1 -0
  174. package/dist/transports/mcp/editor-integration-setup-url.d.ts +8 -0
  175. package/dist/transports/mcp/editor-integration-setup-url.js +23 -0
  176. package/dist/transports/mcp/editor-integration-setup-url.js.map +1 -0
  177. package/dist/transports/mcp/format-tool-content.d.ts +20 -0
  178. package/dist/transports/mcp/format-tool-content.js +89 -0
  179. package/dist/transports/mcp/format-tool-content.js.map +1 -0
  180. package/dist/transports/mcp/instructions/index.d.ts +23 -0
  181. package/dist/transports/mcp/instructions/index.js +81 -0
  182. package/dist/transports/mcp/instructions/index.js.map +1 -0
  183. package/dist/transports/mcp/instructions/result.d.ts +18 -0
  184. package/dist/transports/mcp/instructions/result.js +58 -0
  185. package/dist/transports/mcp/instructions/result.js.map +1 -0
  186. package/dist/transports/mcp/instructions/tools/ask-user.d.ts +2 -0
  187. package/dist/transports/mcp/instructions/tools/ask-user.js +17 -0
  188. package/dist/transports/mcp/instructions/tools/ask-user.js.map +1 -0
  189. package/dist/transports/mcp/instructions/tools/check-app-progress.d.ts +3 -0
  190. package/dist/transports/mcp/instructions/tools/check-app-progress.js +75 -0
  191. package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -0
  192. package/dist/transports/mcp/instructions/tools/check-publish-progress.d.ts +3 -0
  193. package/dist/transports/mcp/instructions/tools/check-publish-progress.js +23 -0
  194. package/dist/transports/mcp/instructions/tools/check-publish-progress.js.map +1 -0
  195. package/dist/transports/mcp/instructions/tools/copy.d.ts +14 -0
  196. package/dist/transports/mcp/instructions/tools/copy.js +35 -0
  197. package/dist/transports/mcp/instructions/tools/copy.js.map +1 -0
  198. package/dist/transports/mcp/instructions/tools/create-integration.d.ts +4 -0
  199. package/dist/transports/mcp/instructions/tools/create-integration.js +41 -0
  200. package/dist/transports/mcp/instructions/tools/create-integration.js.map +1 -0
  201. package/dist/transports/mcp/instructions/tools/edit-app.d.ts +2 -0
  202. package/dist/transports/mcp/instructions/tools/edit-app.js +18 -0
  203. package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -0
  204. package/dist/transports/mcp/instructions/tools/get-app.d.ts +3 -0
  205. package/dist/transports/mcp/instructions/tools/get-app.js +47 -0
  206. package/dist/transports/mcp/instructions/tools/get-app.js.map +1 -0
  207. package/dist/transports/mcp/instructions/tools/get-integration-metadata.d.ts +2 -0
  208. package/dist/transports/mcp/instructions/tools/get-integration-metadata.js +13 -0
  209. package/dist/transports/mcp/instructions/tools/get-integration-metadata.js.map +1 -0
  210. package/dist/transports/mcp/instructions/tools/index.d.ts +7 -0
  211. package/dist/transports/mcp/instructions/tools/index.js +26 -0
  212. package/dist/transports/mcp/instructions/tools/index.js.map +1 -0
  213. package/dist/transports/mcp/instructions/tools/preview-app.d.ts +3 -0
  214. package/dist/transports/mcp/instructions/tools/preview-app.js +14 -0
  215. package/dist/transports/mcp/instructions/tools/preview-app.js.map +1 -0
  216. package/dist/transports/mcp/instructions/tools/publish-app.d.ts +3 -0
  217. package/dist/transports/mcp/instructions/tools/publish-app.js +23 -0
  218. package/dist/transports/mcp/instructions/tools/publish-app.js.map +1 -0
  219. package/dist/transports/mcp/instructions/tools/start-app.d.ts +2 -0
  220. package/dist/transports/mcp/instructions/tools/start-app.js +22 -0
  221. package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -0
  222. package/dist/transports/mcp/instructions/tools/upload-artifact.d.ts +2 -0
  223. package/dist/transports/mcp/instructions/tools/upload-artifact.js +13 -0
  224. package/dist/transports/mcp/instructions/tools/upload-artifact.js.map +1 -0
  225. package/dist/transports/mcp/mcp-app-brand-css.d.ts +1 -0
  226. package/dist/transports/mcp/mcp-app-brand-css.js +180 -0
  227. package/dist/transports/mcp/mcp-app-brand-css.js.map +1 -0
  228. package/dist/transports/mcp/mount.d.ts +22 -0
  229. package/dist/transports/mcp/mount.js +1040 -0
  230. package/dist/transports/mcp/mount.js.map +1 -0
  231. package/dist/transports/mcp/native-browser-presence.d.ts +45 -0
  232. package/dist/transports/mcp/native-browser-presence.js +158 -0
  233. package/dist/transports/mcp/native-browser-presence.js.map +1 -0
  234. package/dist/transports/mcp/plan-approval.d.ts +38 -0
  235. package/dist/transports/mcp/plan-approval.js +175 -0
  236. package/dist/transports/mcp/plan-approval.js.map +1 -0
  237. package/dist/transports/mcp/progress-notifier.d.ts +39 -0
  238. package/dist/transports/mcp/progress-notifier.js +52 -0
  239. package/dist/transports/mcp/progress-notifier.js.map +1 -0
  240. package/dist/transports/mcp/session-directory.d.ts +7 -0
  241. package/dist/transports/mcp/session-directory.js +18 -0
  242. package/dist/transports/mcp/session-directory.js.map +1 -0
  243. package/dist/transports/mcp/tool-names.d.ts +2 -0
  244. package/dist/transports/mcp/tool-names.js +2 -0
  245. package/dist/transports/mcp/tool-names.js.map +1 -0
  246. package/package.json +78 -0
  247. package/skills/superblocks-build/SKILL.md +59 -0
  248. package/skills/superblocks-import/SKILL.md +88 -0
@@ -0,0 +1,750 @@
1
+ import { getBasePluginId, } from "@superblocksteam/shared";
2
+ import { listIntegrationsForClark, toPromptContextIntegration, } from "../integrations/map.js";
3
+ import { sanitizeAgentFacingConfiguration, sanitizeAgentFacingText, sanitizeAgentFacingValue, } from "./agent-facing-text.js";
4
+ const ADMIN_MCP_SETUP_MESSAGE = "Integrations CRUD is available on this Superblocks MCP via get_integration_config_schema, create_integration, update_integration, and list_integrations (same connector as start_app). Call get_integration_config_schema before create_integration. Use those Admin tools, then continue with edit_app. The headless editor session cannot open the Integrations UI.";
5
+ const INTEGRATION_REQUEST_RECORDED_MESSAGE = "The integration request was recorded for the MCP host. Continue with work that does not depend on this integration.";
6
+ function nonSecretIntegrationFields(fields) {
7
+ return sanitizeAgentFacingConfiguration(fields ?? {});
8
+ }
9
+ /**
10
+ * Clark tools that already use PROMPT access rules in the editor. The headless
11
+ * gateway has no human approval UI, so only these may be auto-approved; any
12
+ * other toolName is denied.
13
+ */
14
+ const HEADLESS_AUTO_APPROVED_TOOLS = new Set([
15
+ "build_deleteFile",
16
+ "build_installPackages",
17
+ "executeRequestToIntegration",
18
+ "runMigrationVerification",
19
+ "testApi",
20
+ "updateMigrationWritePolicy",
21
+ ]);
22
+ function taskLabel(summary) {
23
+ const parts = [
24
+ summary.label || summary.taskType,
25
+ summary.state,
26
+ summary.message,
27
+ ].filter((part) => Boolean(part && part.trim()));
28
+ return parts.join(": ").slice(0, 160);
29
+ }
30
+ function changeLabel(info) {
31
+ const parts = [info.action || info.status, info.type, info.name].filter((part) => Boolean(part && String(part).trim()));
32
+ return parts.join(" ").slice(0, 160);
33
+ }
34
+ function missingSessionError(action) {
35
+ return new Error(`the headless gateway session cannot ${action} without an active prompt session`);
36
+ }
37
+ function formatIntegrationResult(data) {
38
+ if (data === undefined) {
39
+ return { response: "" };
40
+ }
41
+ if (data === null) {
42
+ return { response: "null" };
43
+ }
44
+ if (typeof data === "string") {
45
+ return { response: sanitizeAgentFacingText(data) };
46
+ }
47
+ try {
48
+ // Sanitized as a value first, then as text. Serializing first leaves only
49
+ // the text patterns to work with, and those cannot see field names: a row
50
+ // with a short `password` column reads as ordinary JSON to them.
51
+ const serialized = JSON.stringify(sanitizeAgentFacingValue(data), null, 2);
52
+ if (serialized) {
53
+ return { response: sanitizeAgentFacingText(serialized) };
54
+ }
55
+ }
56
+ catch (error) {
57
+ return {
58
+ error: sanitizeAgentFacingText(`Failed to serialize integration result: ${error instanceof Error ? error.message : String(error)}`),
59
+ };
60
+ }
61
+ return { response: sanitizeAgentFacingText(String(data)) };
62
+ }
63
+ function extractIntegrationResult(executionResult) {
64
+ if (!executionResult || typeof executionResult !== "object") {
65
+ return executionResult;
66
+ }
67
+ const result = executionResult;
68
+ if (result.output?.result !== undefined) {
69
+ return result.output.result;
70
+ }
71
+ for (const event of result.events ?? []) {
72
+ const eventResult = event.result?.event?.end?.output?.result;
73
+ if (eventResult !== undefined) {
74
+ return eventResult;
75
+ }
76
+ }
77
+ return executionResult;
78
+ }
79
+ /**
80
+ * True only for interactive IdP / OAuth style failures — not generic HTTP 401s
81
+ * from control-plane hydration (e.g. missing JWT on integration fetch) and not
82
+ * SQL/object permission wording like Snowflake's "does not exist or not authorized".
83
+ */
84
+ function looksLikeInteractiveAuthRequired(message) {
85
+ return /authentication is required|please authenticate|oauth(?:\s+token)?|idp|login required|token (?:expired|missing)|interactive auth/i.test(message);
86
+ }
87
+ /** Snowflake object RBAC / wrong FQN — not Superblocks or IdP auth. */
88
+ function looksLikeSnowflakeObjectPermissionError(message) {
89
+ return /does not exist or not authorized/i.test(message);
90
+ }
91
+ function looksLikeOrchestratorJwtGate401(message) {
92
+ return /orchestrator.*\b401\b/i.test(message);
93
+ }
94
+ const SNOWFLAKE_OBJECT_PERMISSION_HINT = " This is a Snowflake object permission or schema/name error for the integration's role — not Superblocks re-auth. Fix the fully-qualified name or grant access, then retry.";
95
+ const ORCHESTRATOR_JWT_GATE_HINT = " This is Superblocks/orchestrator auth (the scoped JWT or selected profile), not Snowflake username/password. Do not tell the user to re-enter credentials in the integrations panel. If the build still reaches ready, treat this as a mid-build API-check note rather than a user-facing blocker.";
96
+ function clarifySdkExecutionErrorMessage(message) {
97
+ let clarified = message;
98
+ if (looksLikeOrchestratorJwtGate401(message)) {
99
+ if (!message.includes(ORCHESTRATOR_JWT_GATE_HINT.trim())) {
100
+ clarified = `${message}${ORCHESTRATOR_JWT_GATE_HINT}`;
101
+ }
102
+ }
103
+ else if (looksLikeSnowflakeObjectPermissionError(message)) {
104
+ if (!message.includes(SNOWFLAKE_OBJECT_PERMISSION_HINT.trim())) {
105
+ clarified = `${message}${SNOWFLAKE_OBJECT_PERMISSION_HINT}`;
106
+ }
107
+ }
108
+ return sanitizeAgentFacingText(clarified);
109
+ }
110
+ /**
111
+ * Runs Clark's executeRequestToIntegration the same way the browser editor
112
+ * does: one inline V2 API step against the orchestrator. Username/password and
113
+ * other stored-credential integrations execute here; interactive IdP auth
114
+ * surfaces as an error asking the user to authenticate in the editor.
115
+ */
116
+ export async function executeRequestToIntegrationViaOrchestrator(context, payload) {
117
+ let pluginId = payload.integrationHint?.type;
118
+ let integrationName = payload.integrationHint?.displayName ??
119
+ payload.integrationHint?.name ??
120
+ "Integration";
121
+ if (!pluginId) {
122
+ let row;
123
+ try {
124
+ row = await context.server.getIntegration({
125
+ apiKey: context.apiKey,
126
+ integrationId: payload.integrationId,
127
+ });
128
+ if (!row) {
129
+ const rows = await context.server.getSupersetIntegrations({
130
+ apiKey: context.apiKey,
131
+ applicationId: context.applicationId,
132
+ organizationId: context.organizationId,
133
+ });
134
+ row = rows.find((candidate) => candidate.id === payload.integrationId);
135
+ }
136
+ }
137
+ catch (error) {
138
+ console.warn("gateway failed to resolve integration for execute", {
139
+ applicationId: context.applicationId,
140
+ integrationId: payload.integrationId,
141
+ message: error instanceof Error ? error.message : String(error),
142
+ });
143
+ }
144
+ if (!row?.pluginId) {
145
+ return {
146
+ error: `Integration ${payload.integrationId} not found or not accessible`,
147
+ };
148
+ }
149
+ pluginId = row.pluginId;
150
+ integrationName = row.name || integrationName;
151
+ }
152
+ const pluginIdForStep = getBasePluginId(pluginId);
153
+ const now = new Date().toISOString();
154
+ const inlineApiId = `ai-inline-${payload.integrationId}-${Date.now()}`;
155
+ const definition = {
156
+ blocks: [
157
+ {
158
+ name: "InlineQuery",
159
+ step: {
160
+ integration: payload.integrationId,
161
+ [pluginIdForStep]: { ...payload.request },
162
+ },
163
+ },
164
+ ],
165
+ metadata: {
166
+ id: inlineApiId,
167
+ name: `${integrationName} AI Query`,
168
+ organization: context.organizationId,
169
+ timestamps: { created: now, updated: now },
170
+ },
171
+ trigger: { application: {} },
172
+ };
173
+ try {
174
+ const result = await context.orchestrator.executeV2Api({
175
+ apiKey: context.apiKey,
176
+ body: {
177
+ definition: { api: definition },
178
+ inputs: {},
179
+ options: {
180
+ includeEventOutputs: true,
181
+ includeEvents: true,
182
+ includeResolved: true,
183
+ isAiTriggered: true,
184
+ suppressTracking: true,
185
+ },
186
+ ...(context.profileKey
187
+ ? { profile: { name: context.profileKey } }
188
+ : {}),
189
+ },
190
+ profileKey: context.profileKey,
191
+ scopedToken: context.sessionToken,
192
+ });
193
+ if (result && typeof result === "object" && "systemError" in result) {
194
+ const systemError = String(result.systemError ??
195
+ "Integration execution failed");
196
+ if (looksLikeInteractiveAuthRequired(systemError)) {
197
+ return {
198
+ error: sanitizeAgentFacingText(`${systemError} Authenticate this integration in the Superblocks editor (open the app edit URL), then ask Superblocks to retry the query.`),
199
+ };
200
+ }
201
+ return { error: clarifySdkExecutionErrorMessage(systemError) };
202
+ }
203
+ if (result === undefined) {
204
+ return { error: "No response received from integration" };
205
+ }
206
+ const errors = result.errors;
207
+ const unhandled = errors
208
+ ?.filter((entry) => !entry.handled)
209
+ .map((entry) => entry.message);
210
+ if (unhandled && unhandled.length > 0) {
211
+ const message = JSON.stringify(unhandled);
212
+ if (looksLikeInteractiveAuthRequired(message)) {
213
+ return {
214
+ error: sanitizeAgentFacingText(`${message} Authenticate this integration in the Superblocks editor (open the app edit URL), then ask Superblocks to retry the query.`),
215
+ };
216
+ }
217
+ return { error: clarifySdkExecutionErrorMessage(message) };
218
+ }
219
+ return formatIntegrationResult(extractIntegrationResult(result));
220
+ }
221
+ catch (error) {
222
+ const message = error instanceof Error
223
+ ? error.message
224
+ : "Failed to execute integration query";
225
+ if (looksLikeInteractiveAuthRequired(message)) {
226
+ return {
227
+ error: sanitizeAgentFacingText(`${message} Authenticate this integration in the Superblocks editor (open the app edit URL), then ask Superblocks to retry the query.`),
228
+ };
229
+ }
230
+ return { error: clarifySdkExecutionErrorMessage(message) };
231
+ }
232
+ }
233
+ /**
234
+ * Prefills Clark's promptContext.integrations the same way the editor does.
235
+ */
236
+ export async function loadIntegrationsForPrompt(context) {
237
+ const rows = await context.server.getSupersetIntegrations({
238
+ apiKey: context.apiKey,
239
+ applicationId: context.applicationId,
240
+ organizationId: context.organizationId,
241
+ });
242
+ return listIntegrationsForClark(rows);
243
+ }
244
+ export function mapSdkExecutionResponse(response) {
245
+ if (response && typeof response === "object" && "systemError" in response) {
246
+ const systemError = response.systemError;
247
+ return {
248
+ success: false,
249
+ error: {
250
+ code: "SYSTEM_ERROR",
251
+ message: clarifySdkExecutionErrorMessage(typeof systemError === "string"
252
+ ? systemError
253
+ : "Orchestrator returned a system error"),
254
+ },
255
+ };
256
+ }
257
+ if (response &&
258
+ typeof response === "object" &&
259
+ "errors" in response &&
260
+ Array.isArray(response.errors) &&
261
+ response.errors.length > 0) {
262
+ const first = response
263
+ .errors[0];
264
+ return {
265
+ success: false,
266
+ error: {
267
+ code: "EXECUTION_ERROR",
268
+ message: clarifySdkExecutionErrorMessage(first?.message ?? "API execution failed"),
269
+ },
270
+ };
271
+ }
272
+ if (response && typeof response === "object") {
273
+ const output = response.output
274
+ ?.result;
275
+ return {
276
+ success: true,
277
+ output: sanitizeAgentFacingValue(output),
278
+ };
279
+ }
280
+ return {
281
+ success: false,
282
+ error: {
283
+ code: "EMPTY_RESPONSE",
284
+ message: "No response from orchestrator",
285
+ },
286
+ };
287
+ }
288
+ /**
289
+ * Server -> editor calls the dev server makes into the peer driving a turn,
290
+ * whether that peer negotiated protocol "editor" or "gateway".
291
+ *
292
+ * Leaving these unimplemented is not inert. ISocket answers an unknown method
293
+ * with `{ code: 2, message: "unknown method <name>" }`, and the dev server does
294
+ * not catch every one of those rejections — `resetScope` in particular escalates
295
+ * to `unhandledRejection`, which exits the sandbox with "Dev server fatal exit"
296
+ * and takes the in-flight Clark build down with it. A browser editor answers
297
+ * all of them, so a held gateway socket has to as well.
298
+ *
299
+ * Keyed on `GatewayClientMethods` rather than a hand-kept list so that a method
300
+ * added to the protocol upstream fails this package's typecheck instead of
301
+ * reaching a sandbox and crashing it. Same handler surface as
302
+ * `createEditorHandlers` in vite-plugin-file-sync's dev-server-ws-smoke-client,
303
+ * the other non-browser peer that speaks this protocol; it is not imported from
304
+ * there because the gateway does not depend on the vite plugin.
305
+ *
306
+ * When a listener is provided, chat, generation-state, task/change, and
307
+ * preview-ready pushes are forwarded so the gateway can wait for Clark's turn
308
+ * and surface progress over MCP.
309
+ */
310
+ export function createEditorClientMethods(getListener, onInbound, deps) {
311
+ // Notifications and state pushes. The gateway keeps no editor state unless a
312
+ // turn wait is armed, so acknowledging is the whole contract — the dev
313
+ // server only needs to know the peer is alive and listening.
314
+ const ack = [async () => undefined];
315
+ const setupUnavailable = [
316
+ async () => ({
317
+ error: ADMIN_MCP_SETUP_MESSAGE,
318
+ success: false,
319
+ }),
320
+ ];
321
+ const handlers = {
322
+ aiApplyApplicationEnvironmentSettings: ack,
323
+ aiClearToolPermission: ack,
324
+ aiPushApiUsageSummary: ack,
325
+ aiPushChangeInfo: [
326
+ async (info) => {
327
+ const label = changeLabel(info);
328
+ if (!label) {
329
+ return;
330
+ }
331
+ getListener?.()?.({ kind: "change_info", label });
332
+ },
333
+ ],
334
+ aiPushContextUsed: ack,
335
+ aiPushErrorSummary: ack,
336
+ aiPushMessage: [
337
+ async (message) => {
338
+ const listener = getListener?.();
339
+ listener?.({ kind: "message", message });
340
+ },
341
+ ],
342
+ aiPushPolicyAgentStep: ack,
343
+ aiPushPromptInterpretation: ack,
344
+ aiPushTaskStatus: [
345
+ async (summary) => {
346
+ const label = taskLabel(summary);
347
+ if (!label) {
348
+ return;
349
+ }
350
+ getListener?.()?.({ kind: "task_status", label });
351
+ },
352
+ ],
353
+ aiPushTokenUsage: ack,
354
+ aiRequestToolPermission: [
355
+ async (payload) => {
356
+ // Headless gateway has no editor approval UI. Auto-approve only the
357
+ // Clark agent tools that already have PROMPT access rules and must run
358
+ // unattended for local builds (testApi WRITE, migration checks, etc.).
359
+ // Unknown tools are denied by default.
360
+ if (!deps) {
361
+ return;
362
+ }
363
+ const toolName = payload.toolName?.trim() ?? "";
364
+ const approved = HEADLESS_AUTO_APPROVED_TOOLS.has(toolName);
365
+ await deps.respondToToolPermission({
366
+ approved,
367
+ messageId: payload.messageId,
368
+ requestId: payload.requestId ?? payload.messageId,
369
+ });
370
+ },
371
+ ],
372
+ // Says whether Clark left uncommitted work behind. The gateway needs it
373
+ // for the same reason the browser editor does: a pending draft has to be
374
+ // accepted before the app the edit URL serves matches what Clark built.
375
+ aiSetDraftState: [
376
+ async (payload) => {
377
+ getListener?.()?.({
378
+ kind: "draft_state",
379
+ hasDraft: Boolean(payload?.hasDraft),
380
+ });
381
+ },
382
+ ],
383
+ aiSetEditorHasDefaultStructure: [
384
+ async (payload) => {
385
+ if (payload?.hasDefaultStructure === "yes" ||
386
+ payload?.hasDefaultStructure === "no" ||
387
+ payload?.hasDefaultStructure === "unknown") {
388
+ getListener?.()?.({
389
+ hasDefaultStructure: payload.hasDefaultStructure,
390
+ kind: "editor_structure",
391
+ });
392
+ }
393
+ },
394
+ ],
395
+ aiSetGenerationState: [
396
+ async (snapshot) => {
397
+ if (typeof snapshot?.state === "string") {
398
+ getListener?.()?.({
399
+ ...(snapshot.generationId
400
+ ? { generationId: snapshot.generationId }
401
+ : {}),
402
+ ...(snapshot.gatewayObserverSource === "browser"
403
+ ? { gatewayObserverSource: "browser" }
404
+ : {}),
405
+ hasError: snapshot.hasError,
406
+ hasSuggestions: snapshot.hasSuggestions,
407
+ kind: "generation_state",
408
+ state: snapshot.state,
409
+ });
410
+ }
411
+ },
412
+ ],
413
+ appFactsChanged: ack,
414
+ clarkLog: ack,
415
+ closedByServer: ack,
416
+ error: ack,
417
+ manualDeleteApi: ack,
418
+ manualUpdateApi: ack,
419
+ notifyDeploySuccess: ack,
420
+ routerParseError: ack,
421
+ reloadIframe: [
422
+ async () => {
423
+ getListener?.()?.({ kind: "reload_iframe" });
424
+ },
425
+ ],
426
+ releasingLock: ack,
427
+ requestGitRefresh: ack,
428
+ resetScope: ack,
429
+ setApiDependencies: ack,
430
+ setDegradedMode: ack,
431
+ syncStatus: [
432
+ async (payload) => {
433
+ getListener?.()?.({
434
+ kind: "sync_status",
435
+ status: typeof payload?.status === "string" ? payload.status : undefined,
436
+ });
437
+ },
438
+ ],
439
+ updateApiInputs: ack,
440
+ updateScope: ack,
441
+ // No browser tab means no viewport to photograph. viewportUnavailable
442
+ // marks this as a refusal, not a failed capture. The screenshot tool
443
+ // does not read that flag; MCP turns omit the tool via disabledTools.
444
+ aiCaptureScreenshot: [
445
+ async () => ({
446
+ error: "the headless gateway session has no browser viewport",
447
+ success: false,
448
+ viewportUnavailable: true,
449
+ }),
450
+ ],
451
+ aiCloseIntegrationSetup: [async () => ({ success: true })],
452
+ aiDeleteIntegration: setupUnavailable,
453
+ aiExecuteRequestToIntegration: [
454
+ async (payload) => {
455
+ const context = deps?.getContext();
456
+ if (!context) {
457
+ return {
458
+ error: "the headless gateway session cannot execute integration requests without an active prompt session",
459
+ };
460
+ }
461
+ const result = await executeRequestToIntegrationViaOrchestrator(context, payload);
462
+ const name = payload.integrationHint?.name ||
463
+ payload.integrationId ||
464
+ "integration";
465
+ deps?.onToolRun?.({
466
+ detail: result,
467
+ kind: "test_integration",
468
+ name,
469
+ success: !("error" in result && result.error),
470
+ });
471
+ return result;
472
+ },
473
+ ],
474
+ aiExecuteSdkApi: [
475
+ async (payload) => {
476
+ const context = deps?.getContext();
477
+ if (!context) {
478
+ throw missingSessionError("execute SDK APIs");
479
+ }
480
+ if (!payload.entryPoint) {
481
+ const missing = {
482
+ success: false,
483
+ error: {
484
+ code: "UNKNOWN_API",
485
+ message: `No entryPoint registered for API "${payload.apiName}". Was it discovered?`,
486
+ },
487
+ };
488
+ deps?.onToolRun?.({
489
+ detail: missing,
490
+ kind: "test_api",
491
+ name: payload.apiName,
492
+ success: false,
493
+ });
494
+ return missing;
495
+ }
496
+ try {
497
+ const inSync = await context.waitUntilFilesSynced();
498
+ if (!inSync) {
499
+ const syncing = {
500
+ success: false,
501
+ error: {
502
+ code: "SYSTEM_ERROR",
503
+ message: "The API files are still syncing. Wait for the current edit to finish saving, then retry testApi.",
504
+ },
505
+ };
506
+ deps?.onToolRun?.({
507
+ detail: syncing,
508
+ kind: "test_api",
509
+ name: payload.apiName,
510
+ success: false,
511
+ });
512
+ return syncing;
513
+ }
514
+ const response = await context.orchestrator.executeSdkApiV3({
515
+ apiKey: context.apiKey,
516
+ applicationId: context.applicationId,
517
+ branchName: context.branchName,
518
+ entryPoint: payload.entryPoint,
519
+ exportName: payload.exportName,
520
+ inputs: payload.input ?? {},
521
+ profileKey: context.profileKey,
522
+ scopedToken: context.sessionToken,
523
+ });
524
+ const mapped = mapSdkExecutionResponse(response);
525
+ deps?.onToolRun?.({
526
+ detail: mapped,
527
+ kind: "test_api",
528
+ name: payload.apiName,
529
+ success: mapped.success,
530
+ });
531
+ return mapped;
532
+ }
533
+ catch (error) {
534
+ const failed = {
535
+ success: false,
536
+ error: {
537
+ code: "SYSTEM_ERROR",
538
+ message: error instanceof Error
539
+ ? clarifySdkExecutionErrorMessage(error.message)
540
+ : "Failed to execute SDK API",
541
+ },
542
+ };
543
+ deps?.onToolRun?.({
544
+ detail: failed,
545
+ kind: "test_api",
546
+ name: payload.apiName,
547
+ success: false,
548
+ });
549
+ return failed;
550
+ }
551
+ },
552
+ ],
553
+ aiExecuteV2Api: [
554
+ async (payload) => {
555
+ const context = deps?.getContext();
556
+ if (!context) {
557
+ throw missingSessionError("execute V2 APIs");
558
+ }
559
+ if (payload.api.type === "fetch") {
560
+ return {
561
+ systemError: `V2 API fetch for '${payload.api.apiName}' requires the browser editor; use SDK APIs (aiExecuteSdkApi) from Gateway, or open the app in the UI.`,
562
+ };
563
+ }
564
+ const now = new Date().toISOString();
565
+ const definition = {
566
+ ...payload.api.definition,
567
+ metadata: {
568
+ ...(payload.api.definition.metadata ?? {}),
569
+ organization: context.organizationId,
570
+ timestamps: { created: now, updated: now },
571
+ },
572
+ trigger: { application: {} },
573
+ };
574
+ try {
575
+ const result = await context.orchestrator.executeV2Api({
576
+ apiKey: context.apiKey,
577
+ body: {
578
+ definition: { api: definition },
579
+ inputs: payload.inputs ?? {},
580
+ options: {
581
+ includeEventOutputs: true,
582
+ includeEvents: true,
583
+ includeResolved: true,
584
+ isAiTriggered: true,
585
+ suppressTracking: true,
586
+ },
587
+ ...(context.profileKey
588
+ ? { profile: { name: context.profileKey } }
589
+ : {}),
590
+ },
591
+ profileKey: context.profileKey,
592
+ scopedToken: context.sessionToken,
593
+ });
594
+ if (result && typeof result === "object" && "systemError" in result) {
595
+ return result;
596
+ }
597
+ if (result === undefined) {
598
+ return { systemError: "No response received from API execution" };
599
+ }
600
+ const outputs = result.output?.result ?? {};
601
+ return {
602
+ errors: result.errors,
603
+ outputs,
604
+ };
605
+ }
606
+ catch (error) {
607
+ return {
608
+ systemError: error instanceof Error
609
+ ? error.message
610
+ : "Failed to execute V2 API",
611
+ };
612
+ }
613
+ },
614
+ ],
615
+ aiGetIntegration: [
616
+ async (payload) => {
617
+ const context = deps?.getContext();
618
+ if (!context) {
619
+ throw missingSessionError("provide integration metadata");
620
+ }
621
+ // A rejection here cancels Clark's turn, so every lookup failure
622
+ // degrades to the unknown-integration placeholder below.
623
+ let row;
624
+ try {
625
+ row = await context.server.getIntegration({
626
+ apiKey: context.apiKey,
627
+ integrationId: payload.integrationId,
628
+ });
629
+ if (!row) {
630
+ const rows = await context.server.getSupersetIntegrations({
631
+ apiKey: context.apiKey,
632
+ applicationId: context.applicationId,
633
+ organizationId: context.organizationId,
634
+ });
635
+ row = rows.find((candidate) => candidate.id === payload.integrationId);
636
+ }
637
+ }
638
+ catch (error) {
639
+ console.warn("gateway failed to load integration for Clark", {
640
+ applicationId: context.applicationId,
641
+ integrationId: payload.integrationId,
642
+ message: error instanceof Error ? error.message : String(error),
643
+ });
644
+ }
645
+ if (!row) {
646
+ return {
647
+ displayName: payload.integrationId,
648
+ id: payload.integrationId,
649
+ metadata: {},
650
+ name: payload.integrationId,
651
+ type: "unknown",
652
+ };
653
+ }
654
+ let metadata = {};
655
+ try {
656
+ metadata = await context.orchestrator.getMetadata({
657
+ apiKey: context.apiKey,
658
+ integrationId: payload.integrationId,
659
+ profileKey: context.profileKey,
660
+ scopedToken: context.sessionToken,
661
+ });
662
+ }
663
+ catch {
664
+ metadata = {};
665
+ }
666
+ return toPromptContextIntegration(row, metadata);
667
+ },
668
+ ],
669
+ aiGetIntegrationDependents: [
670
+ async () => ({
671
+ error: "the headless gateway session cannot inspect integration dependents",
672
+ success: false,
673
+ }),
674
+ ],
675
+ aiGetIntegrationFormSchema: [
676
+ async () => ({
677
+ error: ADMIN_MCP_SETUP_MESSAGE,
678
+ success: false,
679
+ }),
680
+ ],
681
+ aiGetIntegrations: [
682
+ async () => {
683
+ const context = deps?.getContext();
684
+ if (!context) {
685
+ return [];
686
+ }
687
+ try {
688
+ return await loadIntegrationsForPrompt(context);
689
+ }
690
+ catch (error) {
691
+ // Clark cancels the whole turn if this rejects, so a failed lookup
692
+ // degrades to "no integrations" instead of killing the build.
693
+ console.warn("gateway failed to list integrations for Clark", {
694
+ applicationId: context.applicationId,
695
+ message: error instanceof Error ? error.message : String(error),
696
+ });
697
+ return [];
698
+ }
699
+ },
700
+ ],
701
+ aiGetOpenApiSpec: [async () => undefined],
702
+ aiNavigatePreviewRoute: [
703
+ async () => ({
704
+ error: "the headless gateway session has no browser route",
705
+ success: false,
706
+ }),
707
+ ],
708
+ aiOpenExistingIntegration: setupUnavailable,
709
+ aiOpenIntegrationSetup: [
710
+ async (input) => {
711
+ getListener?.()?.({
712
+ configuration: nonSecretIntegrationFields(input.fields),
713
+ kind: "missing_integration",
714
+ ...(input.label?.trim() ? { name: input.label.trim() } : {}),
715
+ pluginId: input.pluginId,
716
+ });
717
+ return {
718
+ error: INTEGRATION_REQUEST_RECORDED_MESSAGE,
719
+ success: false,
720
+ };
721
+ },
722
+ ],
723
+ aiSaveIntegration: setupUnavailable,
724
+ aiTestIntegrationConnection: [
725
+ async () => ({
726
+ error: {
727
+ details: "",
728
+ message: ADMIN_MCP_SETUP_MESSAGE,
729
+ },
730
+ success: false,
731
+ }),
732
+ ],
733
+ aiUpdateIntegrationFields: setupUnavailable,
734
+ };
735
+ const observed = handlers;
736
+ if (onInbound) {
737
+ for (const key of Object.keys(observed)) {
738
+ const chain = observed[key];
739
+ observed[key] = chain.map((handler) => async (...args) => {
740
+ onInbound(key);
741
+ return handler(...args);
742
+ });
743
+ }
744
+ }
745
+ // ISocket's MethodHandlers is keyed on the socket's own generic parameters,
746
+ // which the gateway leaves empty because it calls only one server method.
747
+ // Exhaustiveness is already enforced above, on the protocol type.
748
+ return observed;
749
+ }
750
+ //# sourceMappingURL=editor-client-methods.js.map