@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,899 @@
1
+ import { MCP_APP_BRAND_CSS } from "./mcp-app-brand-css.js";
2
+ /**
3
+ * Self-contained MCP App HTML for Gateway status and open-link buttons.
4
+ *
5
+ * openLink buttons keep URLs in JS memory only (not printed).
6
+ *
7
+ * Speaks the MCP Apps postMessage dialect without bundling ext-apps into the
8
+ * card (hosts cache UI resources; keep this file small and inline). Bump the
9
+ * resource URI when the HTML changes so Claude Desktop refreshes its cache.
10
+ */
11
+ export const APP_STATUS_RESOURCE_URI = "ui://gateway/app-status-v35.html";
12
+ export const APP_STATUS_HTML = `<!DOCTYPE html>
13
+ <html lang="en">
14
+ <head>
15
+ <meta charset="utf-8" />
16
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
17
+ <title>Superblocks app</title>
18
+ <style>
19
+ .head {
20
+ display: flex;
21
+ min-width: 0;
22
+ align-items: center;
23
+ gap: 8px;
24
+ }
25
+ h1 {
26
+ flex: 1;
27
+ margin: 0;
28
+ font-size: var(--font-text-md-size, 14px);
29
+ font-weight: var(--font-weight-semibold, 600);
30
+ }
31
+ .status {
32
+ padding: 2px 8px;
33
+ border: var(--border-width-regular, 1px) solid var(--sb-app-border);
34
+ border-radius: var(--border-radius-full, 999px);
35
+ background: var(--sb-app-background-subtle);
36
+ color: var(--sb-app-text-secondary);
37
+ font-size: var(--font-text-xs-size, 12px);
38
+ text-transform: lowercase;
39
+ }
40
+ .status[data-tone="info"] {
41
+ border-color: var(--sb-app-info-border);
42
+ background: var(--sb-app-info-background);
43
+ color: var(--sb-app-info-text);
44
+ }
45
+ .status[data-tone="success"] {
46
+ border-color: var(--sb-app-success-border);
47
+ background: var(--sb-app-success-background);
48
+ color: var(--sb-app-success-text);
49
+ }
50
+ .status[data-tone="warning"] {
51
+ border-color: var(--sb-app-warning-border);
52
+ background: var(--sb-app-warning-background);
53
+ color: var(--sb-app-warning-text);
54
+ }
55
+ .status[data-tone="danger"] {
56
+ border-color: var(--sb-app-danger-border);
57
+ background: var(--sb-app-danger-background);
58
+ color: var(--sb-app-danger-text);
59
+ }
60
+ .meta {
61
+ color: var(--sb-app-text-tertiary);
62
+ font-size: var(--font-text-xs-size, 12px);
63
+ }
64
+ .note {
65
+ color: var(--sb-app-warning-text);
66
+ font-size: var(--font-text-xs-size, 12px);
67
+ }
68
+ .shot {
69
+ display: none;
70
+ max-width: 100%;
71
+ width: 100%;
72
+ border: var(--border-width-regular, 1px) solid var(--sb-app-border);
73
+ border-radius: var(--border-radius-md, 8px);
74
+ }
75
+ .shot.shown {
76
+ display: block;
77
+ }
78
+ .actions {
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ gap: 8px;
82
+ }
83
+ @media (max-width: 360px) {
84
+ .head {
85
+ align-items: flex-start;
86
+ flex-direction: column;
87
+ }
88
+ }
89
+ ${MCP_APP_BRAND_CSS}
90
+ </style>
91
+ </head>
92
+ <body>
93
+ <div class="card">
94
+ <div class="head">
95
+ <h1>Superblocks app</h1>
96
+ <span id="status" class="status" data-tone="info" aria-live="polite">loading</span>
97
+ </div>
98
+ <div id="appId" class="meta"></div>
99
+ <img id="shot" class="shot" alt="Preview of the running app" />
100
+ <div id="note" class="note" aria-live="polite"></div>
101
+ <div class="actions">
102
+ <button id="openEditor" class="button-secondary" type="button" disabled>Open editor</button>
103
+ <button id="openPreview" class="button-secondary" type="button" disabled>Open preview</button>
104
+ <button id="publishApp" class="button-primary" type="button" disabled>Publish app</button>
105
+ </div>
106
+ </div>
107
+ <script>
108
+ (() => {
109
+ const PROTOCOL_VERSION = "2026-01-26";
110
+ // Statuses with no usable build to publish. "building" is deliberately
111
+ // absent because a stale badge should not strand the button.
112
+ const UNBUILT_STATUSES = [
113
+ "cancelled",
114
+ "checkpoint_failed",
115
+ "detached",
116
+ "failed",
117
+ "live_edit_terminated",
118
+ "needs_decision",
119
+ "no_changes",
120
+ "timeout",
121
+ ];
122
+ const BLOCKED_ACTIONS = [
123
+ "answer_question",
124
+ "approve_plan",
125
+ "open_editor",
126
+ "retry_build",
127
+ ];
128
+ const STATUS_TONES = {
129
+ building: "info",
130
+ cancelled: "warning",
131
+ checkpoint_failed: "danger",
132
+ deployed: "success",
133
+ detached: "warning",
134
+ failed: "danger",
135
+ live_edit_terminated: "danger",
136
+ loading: "info",
137
+ needs_decision: "warning",
138
+ no_changes: "warning",
139
+ publish_failed: "danger",
140
+ publishing: "info",
141
+ ready: "success",
142
+ timeout: "danger",
143
+ waiting: "info",
144
+ };
145
+ let nextId = 1;
146
+ const pending = new Map();
147
+ let applicationId = "";
148
+ let appName = "";
149
+ let branch = "";
150
+ let commitId = "";
151
+ let directoryHash = "";
152
+ let pendingAction = "";
153
+ let editUrl = "";
154
+ let previewUrl = "";
155
+ let publishUrl = "";
156
+ let canOpenLinks = false;
157
+ let canCallTools = false;
158
+ let publishing = false;
159
+ let teardownRequested = false;
160
+ let lastHeight = 0;
161
+ let buildWatchStartedAtMs;
162
+ let refreshInFlightGeneration = -1;
163
+ let refreshTimer = 0;
164
+ let refreshGeneration = 0;
165
+ const BUILD_WATCH_MS = 20 * 60_000;
166
+ const POLL_INTERVAL_MS = 2000;
167
+
168
+ function post(message) {
169
+ window.parent.postMessage(message, "*");
170
+ }
171
+
172
+ function notify(method, params) {
173
+ post({ jsonrpc: "2.0", method, params });
174
+ }
175
+
176
+ function request(method, params) {
177
+ const id = nextId++;
178
+ return new Promise((resolve, reject) => {
179
+ pending.set(id, { resolve, reject });
180
+ post({ jsonrpc: "2.0", id, method, params });
181
+ });
182
+ }
183
+
184
+ function element(id) {
185
+ return document.getElementById(id);
186
+ }
187
+
188
+ function show(id, on) {
189
+ const node = element(id);
190
+ if (node && node.classList) {
191
+ node.classList.toggle("shown", on);
192
+ }
193
+ }
194
+
195
+ function renderStatus(status) {
196
+ const badge = element("status");
197
+ badge.textContent = status;
198
+ badge.setAttribute(
199
+ "data-tone",
200
+ Object.hasOwn(STATUS_TONES, status) ? STATUS_TONES[status] : "neutral",
201
+ );
202
+ }
203
+
204
+ // Hosts size the card from this notification alone; without it the card
205
+ // is laid out at zero height and never appears.
206
+ function reportSize() {
207
+ if (teardownRequested) {
208
+ return;
209
+ }
210
+ const height = Math.ceil(document.documentElement.scrollHeight || 0);
211
+ if (height <= 0 || height === lastHeight) {
212
+ return;
213
+ }
214
+ lastHeight = height;
215
+ notify("ui/notifications/size-changed", {
216
+ height,
217
+ width: Math.ceil(window.innerWidth || 0),
218
+ });
219
+ }
220
+
221
+ function note(text) {
222
+ element("note").textContent = text;
223
+ show("note", Boolean(text));
224
+ reportSize();
225
+ }
226
+
227
+ function isPlainHttp(url) {
228
+ return url.slice(0, 5).toLowerCase() === "http:";
229
+ }
230
+
231
+ /** A UUID says nothing; the name the user asked Superblocks for does. */
232
+ function renderIdentity() {
233
+ element("appId").textContent = appName || applicationId;
234
+ }
235
+
236
+ /**
237
+ * Draws the screenshot the tool captured.
238
+ *
239
+ * Hosts that render an MCP App render it *instead of* the tool's content
240
+ * blocks, so the image block get_app returns never reaches the user on
241
+ * its own — the card has to take it out of the result and show it.
242
+ */
243
+ function showScreenshot(dataBase64, mimeType) {
244
+ if (typeof dataBase64 !== "string" || !dataBase64) {
245
+ return;
246
+ }
247
+ element("shot").src =
248
+ "data:" + (mimeType || "image/jpeg") + ";base64," + dataBase64;
249
+ show("shot", true);
250
+ reportSize();
251
+ }
252
+
253
+ /** Applies every part of an MCP content array the card understands. */
254
+ function applyContent(content) {
255
+ for (const part of content || []) {
256
+ if (!part) {
257
+ continue;
258
+ }
259
+ if (part.type === "text" && typeof part.text === "string") {
260
+ applyPayload(part.text);
261
+ }
262
+ if (part.type === "image") {
263
+ showScreenshot(part.data, part.mimeType);
264
+ }
265
+ }
266
+ }
267
+
268
+ /**
269
+ * True when publishing would deploy the empty starter template.
270
+ * pendingAction is the server's own "nothing to preview" signal;
271
+ * wait_for_build is the building exception. Status is only a fallback
272
+ * when the payload omitted pendingAction. loading/waiting with no
273
+ * preview fail closed so Publish is not clickable before get_app
274
+ * returns.
275
+ */
276
+ function nothingToPublish() {
277
+ const badge = element("status").textContent;
278
+ if (UNBUILT_STATUSES.indexOf(badge) !== -1) {
279
+ return true;
280
+ }
281
+ if (previewUrl || publishUrl) {
282
+ return false;
283
+ }
284
+ if (pendingAction === "wait_for_build") {
285
+ return false;
286
+ }
287
+ if (BLOCKED_ACTIONS.indexOf(pendingAction) !== -1) {
288
+ return true;
289
+ }
290
+ if (!badge || badge === "loading" || badge === "waiting") {
291
+ return true;
292
+ }
293
+ return false;
294
+ }
295
+
296
+ /**
297
+ * Keep URLs in memory for openLink — never print them (preview JWTs are
298
+ * huge and ugly in the card).
299
+ */
300
+ function renderActions() {
301
+ const status = element("status").textContent;
302
+ const previewReady = status === "ready";
303
+ const rollingOut = status === "publishing";
304
+ const published = Boolean(publishUrl) && !rollingOut;
305
+ element("openEditor").disabled = !editUrl || !canOpenLinks;
306
+ element("openPreview").disabled =
307
+ !previewReady || !previewUrl || !canOpenLinks;
308
+ // Once the app is live, publishing again is not what anyone wants from
309
+ // this button — going to the live app is.
310
+ element("publishApp").textContent = rollingOut
311
+ ? "Publishing..."
312
+ : published
313
+ ? "Open published app"
314
+ : "Publish app";
315
+ element("publishApp").disabled = rollingOut
316
+ ? true
317
+ : published
318
+ ? !canOpenLinks
319
+ : !applicationId ||
320
+ !canCallTools ||
321
+ publishing ||
322
+ nothingToPublish();
323
+ // Only warn about what is actually broken. Hosts that do open links
324
+ // handle local http fine; if one refuses, refused() says so then.
325
+ if (!canOpenLinks && (editUrl || previewUrl) && !publishUrl) {
326
+ note("This host cannot open links for me — ask the model for an https preview URL.");
327
+ }
328
+ reportSize();
329
+ }
330
+
331
+ /** Only ever ask the host to open a real web address. */
332
+ function webUrl(candidate) {
333
+ try {
334
+ const parsed = new URL(candidate);
335
+ return parsed.protocol === "http:" || parsed.protocol === "https:"
336
+ ? candidate
337
+ : "";
338
+ } catch {
339
+ return "";
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Merges whatever the host sent. Hosts replay tool input as well as tool
345
+ * results, and the input carries no status or URLs — overwriting from a
346
+ * partial payload is what showed the card as "unknown".
347
+ *
348
+ * Hosts also disagree on the shape: some pass the capability JSON, some
349
+ * pass the MCP content/text envelope (Claude Desktop on initialize), and
350
+ * some nest that under structuredContent.
351
+ */
352
+ function applyPayload(raw) {
353
+ let data = raw;
354
+ if (typeof raw === "string") {
355
+ try {
356
+ data = JSON.parse(raw);
357
+ } catch {
358
+ return;
359
+ }
360
+ }
361
+ if (!data || typeof data !== "object") {
362
+ return;
363
+ }
364
+ // MCP tool-result / initialize toolResult envelope.
365
+ if (Array.isArray(data.content)) {
366
+ applyContent(data.content);
367
+ if (data.structuredContent) {
368
+ applyPayload(data.structuredContent);
369
+ }
370
+ return;
371
+ }
372
+ if (data.result && typeof data.result === "object") {
373
+ applyPayload(data.result);
374
+ return;
375
+ }
376
+ const value = data.kind === "ok" ? data.value : data;
377
+ if (!value || typeof value !== "object") {
378
+ return;
379
+ }
380
+ if (
381
+ value.browserNavigation &&
382
+ typeof value.browserNavigation === "object" &&
383
+ value.browserNavigation.action === "open_editor"
384
+ ) {
385
+ if (!teardownRequested) {
386
+ teardownRequested = true;
387
+ refreshGeneration += 1;
388
+ clearRefreshTimer();
389
+ document.body.hidden = true;
390
+ notify("ui/notifications/size-changed", { height: 0, width: 0 });
391
+ notify("ui/notifications/request-teardown", {});
392
+ }
393
+ return;
394
+ }
395
+ if (teardownRequested) {
396
+ return;
397
+ }
398
+ if (typeof value.status === "string") {
399
+ renderStatus(value.status);
400
+ }
401
+ if (typeof value.applicationId === "string") {
402
+ applicationId = value.applicationId;
403
+ renderIdentity();
404
+ }
405
+ if (typeof value.name === "string" && value.name) {
406
+ appName = value.name;
407
+ renderIdentity();
408
+ }
409
+ if (typeof value.branch === "string") {
410
+ branch = value.branch;
411
+ }
412
+ if (typeof value.directoryHash === "string") {
413
+ directoryHash = value.directoryHash;
414
+ }
415
+ if (
416
+ typeof value.commitId === "string" ||
417
+ typeof value.previewUrl === "string" ||
418
+ (typeof value.applicationId === "string" &&
419
+ typeof value.status === "string")
420
+ ) {
421
+ commitId =
422
+ typeof value.commitId === "string" ? value.commitId : "";
423
+ }
424
+ if (typeof value.pendingAction === "string") {
425
+ pendingAction = value.pendingAction;
426
+ } else if (typeof value.status === "string") {
427
+ pendingAction = "";
428
+ }
429
+ if (typeof value.screenshotBase64 === "string") {
430
+ showScreenshot(value.screenshotBase64, "image/jpeg");
431
+ }
432
+ if (typeof value.editUrl === "string") {
433
+ editUrl = webUrl(value.editUrl);
434
+ }
435
+ if (typeof value.previewUrl === "string") {
436
+ previewUrl = webUrl(value.previewUrl);
437
+ } else if (typeof value.status === "string" && !commitId) {
438
+ previewUrl = "";
439
+ }
440
+ if (typeof value.publishUrl === "string") {
441
+ publishUrl = webUrl(value.publishUrl);
442
+ }
443
+ // Hosts that deliver URLs without a status left the badge on the HTML
444
+ // default ("loading") even after the app was built.
445
+ const badge = element("status").textContent;
446
+ if (
447
+ !value.status &&
448
+ editUrl &&
449
+ (badge === "" || badge === "loading" || badge === "waiting")
450
+ ) {
451
+ renderStatus(previewUrl ? "ready" : "building");
452
+ }
453
+ renderActions();
454
+ if (
455
+ canCallTools &&
456
+ commitId &&
457
+ element("status").textContent === "publishing"
458
+ ) {
459
+ scheduleRefresh(retryDelay());
460
+ }
461
+ }
462
+
463
+ /**
464
+ * Ask the app-only status tool when the host gave us no result, or while
465
+ * status is still building.
466
+ */
467
+ function clearRefreshTimer() {
468
+ if (refreshTimer) {
469
+ clearTimeout(refreshTimer);
470
+ refreshTimer = 0;
471
+ }
472
+ }
473
+
474
+ function retryDelay() {
475
+ return POLL_INTERVAL_MS;
476
+ }
477
+
478
+ function scheduleRefresh(delayMs) {
479
+ clearRefreshTimer();
480
+ if (
481
+ element("status").textContent !== "publishing" &&
482
+ buildWatchStartedAtMs !== undefined &&
483
+ Date.now() - buildWatchStartedAtMs >= BUILD_WATCH_MS
484
+ ) {
485
+ note("Stopped checking whether the app is still building.");
486
+ return;
487
+ }
488
+ refreshTimer = setTimeout(() => {
489
+ refreshTimer = 0;
490
+ refreshFromServer();
491
+ }, delayMs);
492
+ }
493
+
494
+ function refreshFromServer() {
495
+ clearRefreshTimer();
496
+ if (
497
+ teardownRequested ||
498
+ !canCallTools ||
499
+ refreshInFlightGeneration === refreshGeneration ||
500
+ publishing
501
+ ) {
502
+ return;
503
+ }
504
+ if (typeof document.hidden === "boolean" && document.hidden) {
505
+ scheduleRefresh(retryDelay());
506
+ return;
507
+ }
508
+ const badge = element("status").textContent;
509
+ const publishStatus = badge === "publishing";
510
+ if (editUrl && badge !== "building" && !publishStatus) {
511
+ buildWatchStartedAtMs = undefined;
512
+ return;
513
+ }
514
+ if (!publishStatus) {
515
+ if (badge === "building") {
516
+ if (buildWatchStartedAtMs === undefined) {
517
+ buildWatchStartedAtMs = Date.now();
518
+ }
519
+ } else {
520
+ buildWatchStartedAtMs = undefined;
521
+ }
522
+ if (
523
+ buildWatchStartedAtMs !== undefined &&
524
+ Date.now() - buildWatchStartedAtMs >= BUILD_WATCH_MS
525
+ ) {
526
+ note("Stopped checking whether the app is still building.");
527
+ return;
528
+ }
529
+ }
530
+ const generation = refreshGeneration;
531
+ refreshInFlightGeneration = generation;
532
+ const previewStatus = !publishStatus && Boolean(commitId && directoryHash);
533
+ request("tools/call", {
534
+ name: publishStatus
535
+ ? "check_publish_progress"
536
+ : previewStatus
537
+ ? "get_preview_status"
538
+ : "get_app_status",
539
+ arguments: {
540
+ ...(applicationId ? { applicationId } : {}),
541
+ ...(!publishStatus && branch ? { branch } : {}),
542
+ ...(publishStatus && commitId ? { commitId } : {}),
543
+ ...(previewStatus ? { commitId, directoryHash } : {}),
544
+ },
545
+ })
546
+ .then((result) => {
547
+ if (refreshInFlightGeneration === generation) {
548
+ refreshInFlightGeneration = -1;
549
+ }
550
+ if (generation !== refreshGeneration) {
551
+ if (
552
+ !publishing &&
553
+ element("status").textContent === "building" &&
554
+ refreshInFlightGeneration !== refreshGeneration
555
+ ) {
556
+ scheduleRefresh(retryDelay());
557
+ }
558
+ return;
559
+ }
560
+ const publishError = publishStatus
561
+ ? terminalPublishErrorOf(result)
562
+ : "";
563
+ if (publishError) {
564
+ refreshGeneration += 1;
565
+ clearRefreshTimer();
566
+ publishUrl = "";
567
+ renderStatus("publish_failed");
568
+ note(publishError);
569
+ renderActions();
570
+ return;
571
+ }
572
+ if (!result || result.isError) {
573
+ scheduleRefresh(retryDelay());
574
+ return;
575
+ }
576
+ applyPayload(result);
577
+ if (result.structuredContent) {
578
+ applyPayload(result.structuredContent);
579
+ }
580
+ const status = element("status").textContent;
581
+ if (status === "deployed") {
582
+ note(
583
+ publishUrl
584
+ ? "Published - open the live app with Open published app."
585
+ : "Published - the app is live.",
586
+ );
587
+ return;
588
+ }
589
+ if (status === "publishing") {
590
+ scheduleRefresh(retryDelay());
591
+ return;
592
+ }
593
+ if (status !== "building") {
594
+ return;
595
+ }
596
+ scheduleRefresh(retryDelay());
597
+ })
598
+ .catch(() => {
599
+ if (refreshInFlightGeneration === generation) {
600
+ refreshInFlightGeneration = -1;
601
+ }
602
+ if (generation !== refreshGeneration) {
603
+ return;
604
+ }
605
+ scheduleRefresh(retryDelay());
606
+ });
607
+ }
608
+
609
+ function applyHostContext(context) {
610
+ if (!context || typeof context !== "object") {
611
+ return;
612
+ }
613
+ const root = document.documentElement;
614
+ if (context.theme === "light" || context.theme === "dark") {
615
+ root.setAttribute("data-theme", context.theme);
616
+ root.style.colorScheme = context.theme;
617
+ }
618
+ const variables = context.styles && context.styles.variables;
619
+ const style = root.style;
620
+ if (variables && style && typeof style.setProperty === "function") {
621
+ for (const name of Object.keys(variables)) {
622
+ const value = variables[name];
623
+ if (typeof value === "string") {
624
+ style.setProperty(name, value);
625
+ }
626
+ }
627
+ }
628
+ const fonts = context.styles && context.styles.css?.fonts;
629
+ if (typeof fonts === "string") {
630
+ let fontStyle = document.getElementById("__mcp-host-fonts");
631
+ if (!fontStyle) {
632
+ fontStyle = document.createElement("style");
633
+ fontStyle.id = "__mcp-host-fonts";
634
+ document.head.appendChild(fontStyle);
635
+ }
636
+ fontStyle.textContent = fonts;
637
+ }
638
+ reportSize();
639
+ }
640
+
641
+ function capabilityFailureOf(result) {
642
+ if (!result || !Array.isArray(result.content)) {
643
+ return null;
644
+ }
645
+ for (const block of result.content) {
646
+ if (!block || block.type !== "text" || !block.text) {
647
+ continue;
648
+ }
649
+ try {
650
+ const parsed = JSON.parse(block.text);
651
+ if (parsed && parsed.kind === "error") {
652
+ return {
653
+ code: parsed.code || "",
654
+ message: parsed.message || parsed.code || "Tool call failed.",
655
+ };
656
+ }
657
+ } catch {
658
+ continue;
659
+ }
660
+ }
661
+ return null;
662
+ }
663
+
664
+ function capabilityErrorOf(result) {
665
+ return capabilityFailureOf(result)?.message || "";
666
+ }
667
+
668
+ function terminalPublishErrorOf(result) {
669
+ const failure = capabilityFailureOf(result);
670
+ if (
671
+ !failure ||
672
+ ![
673
+ "publish_failed",
674
+ "publish_needs_acknowledgement",
675
+ "publish_timeout",
676
+ ].includes(failure.code)
677
+ ) {
678
+ return "";
679
+ }
680
+ return failure.message;
681
+ }
682
+
683
+ /** First text block of a failed tool result, for the note line. */
684
+ function errorTextOf(result, fallback) {
685
+ const capabilityError = capabilityErrorOf(result);
686
+ if (capabilityError) {
687
+ return capabilityError;
688
+ }
689
+ const first =
690
+ result && Array.isArray(result.content) ? result.content[0] : null;
691
+ return first && first.text ? String(first.text).slice(0, 280) : fallback;
692
+ }
693
+
694
+ function refused(url) {
695
+ note(
696
+ isPlainHttp(url)
697
+ ? "This host only opens https links, and this app is served over http — ask for an https preview URL."
698
+ : "The host could not open the link — try again or ask the model for another URL.",
699
+ );
700
+ }
701
+
702
+ function openLink(url) {
703
+ if (!url || !canOpenLinks) {
704
+ return;
705
+ }
706
+ request("ui/open-link", { url })
707
+ .then((result) => {
708
+ if (result && result.isError) {
709
+ refused(url);
710
+ return;
711
+ }
712
+ note("");
713
+ })
714
+ .catch(() => refused(url));
715
+ }
716
+
717
+ /**
718
+ * Asks the host to proxy publish_app back to this MCP server. The prompt
719
+ * is the commit message createCommit needs; the card supplies a fixed one
720
+ * so the user does not have to type through the model.
721
+ */
722
+ function publish() {
723
+ if (!applicationId || !canCallTools || publishing) {
724
+ return;
725
+ }
726
+ if (nothingToPublish()) {
727
+ note("Nothing to publish yet: this turn did not build the app.");
728
+ return;
729
+ }
730
+ publishing = true;
731
+ refreshGeneration += 1;
732
+ clearRefreshTimer();
733
+ renderActions();
734
+ note("Publishing…");
735
+ const args = {
736
+ applicationId,
737
+ idempotencyKey:
738
+ "mcp-app-publish:" + applicationId + ":" + Date.now(),
739
+ prompt: "Published from Gateway status card",
740
+ };
741
+ if (commitId) {
742
+ args.commitId = commitId;
743
+ }
744
+ if (branch) {
745
+ args.branch = branch;
746
+ }
747
+ request("tools/call", { name: "publish_app", arguments: args })
748
+ .then((result) => {
749
+ publishing = false;
750
+ const publishError = capabilityErrorOf(result);
751
+ if (!result || result.isError || publishError) {
752
+ note(errorTextOf(result, "Publish failed."));
753
+ renderActions();
754
+ refreshFromServer();
755
+ return;
756
+ }
757
+ applyContent(result.content || []);
758
+ if (result.structuredContent) {
759
+ applyPayload(result.structuredContent);
760
+ }
761
+ const status = element("status").textContent;
762
+ note(
763
+ status === "publishing"
764
+ ? "Publish accepted; the deploy is still rolling out."
765
+ : publishUrl
766
+ ? "Published - open the live app with Open published app."
767
+ : "Published - the app is live.",
768
+ );
769
+ renderActions();
770
+ })
771
+ .catch((error) => {
772
+ publishing = false;
773
+ note(
774
+ (error && error.message) ||
775
+ "The host could not call publish_app.",
776
+ );
777
+ renderActions();
778
+ refreshFromServer();
779
+ });
780
+ }
781
+
782
+ function handleHostMessage(event) {
783
+ // App documents are opaque-origin, so the host window is the only
784
+ // identity available to authenticate a message against.
785
+ if (event.source !== window.parent) {
786
+ return;
787
+ }
788
+ const data = event.data;
789
+ if (!data || typeof data !== "object") {
790
+ return;
791
+ }
792
+ if (data.method === "ping") {
793
+ post({ jsonrpc: "2.0", id: data.id, result: {} });
794
+ return;
795
+ }
796
+ if (data.id != null && pending.has(data.id)) {
797
+ const waiter = pending.get(data.id);
798
+ pending.delete(data.id);
799
+ if (data.error) {
800
+ waiter.reject(data.error);
801
+ } else {
802
+ waiter.resolve(data.result);
803
+ }
804
+ return;
805
+ }
806
+ const method = data.method;
807
+ const params = data.params || {};
808
+ if (
809
+ method === "ui/notifications/tool-result" ||
810
+ method === "ui/tool-result" ||
811
+ method === "tools/call"
812
+ ) {
813
+ applyContent(params.content || params.result?.content || []);
814
+ if (params.structuredContent) {
815
+ applyPayload(params.structuredContent);
816
+ }
817
+ refreshGeneration += 1;
818
+ if (element("status").textContent === "building") {
819
+ refreshFromServer();
820
+ }
821
+ }
822
+ if (method === "ui/notifications/tool-input" && params.arguments) {
823
+ applyPayload(params.arguments);
824
+ refreshFromServer();
825
+ }
826
+ if (method === "ui/notifications/host-context-changed") {
827
+ applyHostContext(params);
828
+ }
829
+ }
830
+
831
+ window.addEventListener("message", handleHostMessage);
832
+
833
+ element("openEditor").addEventListener("click", () => openLink(editUrl));
834
+ element("openPreview").addEventListener("click", () =>
835
+ openLink(previewUrl),
836
+ );
837
+ element("publishApp").addEventListener("click", () => {
838
+ if (element("status").textContent === "publishing") {
839
+ return;
840
+ }
841
+ if (publishUrl) {
842
+ openLink(publishUrl);
843
+ return;
844
+ }
845
+ publish();
846
+ });
847
+
848
+ if (typeof ResizeObserver === "function") {
849
+ new ResizeObserver(reportSize).observe(document.documentElement);
850
+ }
851
+
852
+ void request("ui/initialize", {
853
+ appCapabilities: {
854
+ availableDisplayModes: ["inline"],
855
+ },
856
+ appInfo: { name: "gateway-app-status", version: "0.0.8" },
857
+ protocolVersion: PROTOCOL_VERSION,
858
+ })
859
+ .then((result) => {
860
+ // Hosts hold back tool results until the app confirms it is ready.
861
+ notify("ui/notifications/initialized", {});
862
+ // Buttons that cannot work are worse than no buttons: hosts without
863
+ // openLinks silently drop ui/open-link.
864
+ canOpenLinks = Boolean(
865
+ result && result.hostCapabilities && result.hostCapabilities.openLinks,
866
+ );
867
+ canCallTools = Boolean(
868
+ result &&
869
+ result.hostCapabilities &&
870
+ result.hostCapabilities.serverTools,
871
+ );
872
+ if (result && result.toolResult) {
873
+ applyPayload(result.toolResult);
874
+ }
875
+ if (teardownRequested) {
876
+ return;
877
+ }
878
+ applyHostContext(result && result.hostContext);
879
+ renderActions();
880
+ const badge = element("status").textContent;
881
+ if (badge === "publishing") {
882
+ return;
883
+ }
884
+ if (!applicationId && (!badge || badge === "loading")) {
885
+ scheduleRefresh(500);
886
+ } else {
887
+ refreshFromServer();
888
+ }
889
+ })
890
+ .catch(() => {
891
+ // Hosts that push tool results via notification still work.
892
+ })
893
+ .finally(reportSize);
894
+ })();
895
+ </script>
896
+ </body>
897
+ </html>
898
+ `;
899
+ //# sourceMappingURL=app-status-html.js.map