@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.
- package/LICENSE.txt +87 -0
- package/README.md +291 -0
- package/dist/agents/resolve-orchestrator-url.d.ts +22 -0
- package/dist/agents/resolve-orchestrator-url.js +38 -0
- package/dist/agents/resolve-orchestrator-url.js.map +1 -0
- package/dist/capabilities/integration-metadata.d.ts +28 -0
- package/dist/capabilities/integration-metadata.js +174 -0
- package/dist/capabilities/integration-metadata.js.map +1 -0
- package/dist/capabilities/lifecycle.d.ts +93 -0
- package/dist/capabilities/lifecycle.js +3450 -0
- package/dist/capabilities/lifecycle.js.map +1 -0
- package/dist/capabilities/query-integration.d.ts +14 -0
- package/dist/capabilities/query-integration.js +172 -0
- package/dist/capabilities/query-integration.js.map +1 -0
- package/dist/capabilities/source-files-archive.d.ts +11 -0
- package/dist/capabilities/source-files-archive.js +54 -0
- package/dist/capabilities/source-files-archive.js.map +1 -0
- package/dist/capabilities/types.d.ts +542 -0
- package/dist/capabilities/types.js +86 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/capture/browser-contract.d.ts +46 -0
- package/dist/capture/browser-contract.js +34 -0
- package/dist/capture/browser-contract.js.map +1 -0
- package/dist/capture/browser-instructions.d.ts +10 -0
- package/dist/capture/browser-instructions.js +18 -0
- package/dist/capture/browser-instructions.js.map +1 -0
- package/dist/capture/capture-library-probe.d.ts +55 -0
- package/dist/capture/capture-library-probe.js +177 -0
- package/dist/capture/capture-library-probe.js.map +1 -0
- package/dist/capture/capture-library.d.ts +52 -0
- package/dist/capture/capture-library.js +249 -0
- package/dist/capture/capture-library.js.map +1 -0
- package/dist/capture/classify-library-paint.d.ts +21 -0
- package/dist/capture/classify-library-paint.js +13 -0
- package/dist/capture/classify-library-paint.js.map +1 -0
- package/dist/capture/host-mcp-scan.d.ts +16 -0
- package/dist/capture/host-mcp-scan.js +64 -0
- package/dist/capture/host-mcp-scan.js.map +1 -0
- package/dist/capture/library-parent-script.d.ts +35 -0
- package/dist/capture/library-parent-script.js +82 -0
- package/dist/capture/library-parent-script.js.map +1 -0
- package/dist/capture/mode.d.ts +29 -0
- package/dist/capture/mode.js +65 -0
- package/dist/capture/mode.js.map +1 -0
- package/dist/config.d.ts +148 -0
- package/dist/config.js +111 -0
- package/dist/config.js.map +1 -0
- package/dist/debug.d.ts +2 -0
- package/dist/debug.js +9 -0
- package/dist/debug.js.map +1 -0
- package/dist/deps.d.ts +38 -0
- package/dist/deps.js +2 -0
- package/dist/deps.js.map +1 -0
- package/dist/health/readiness.d.ts +99 -0
- package/dist/health/readiness.js +202 -0
- package/dist/health/readiness.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/filters.d.ts +8 -0
- package/dist/integrations/filters.js +40 -0
- package/dist/integrations/filters.js.map +1 -0
- package/dist/integrations/map.d.ts +27 -0
- package/dist/integrations/map.js +43 -0
- package/dist/integrations/map.js.map +1 -0
- package/dist/integrations/profile-key.d.ts +19 -0
- package/dist/integrations/profile-key.js +35 -0
- package/dist/integrations/profile-key.js.map +1 -0
- package/dist/integrations/read-only-postgres-query.d.ts +2 -0
- package/dist/integrations/read-only-postgres-query.js +164 -0
- package/dist/integrations/read-only-postgres-query.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +5 -0
- package/dist/main.js.map +1 -0
- package/dist/orchestrator/client.d.ts +62 -0
- package/dist/orchestrator/client.js +160 -0
- package/dist/orchestrator/client.js.map +1 -0
- package/dist/playwright/ensure-chromium.d.ts +24 -0
- package/dist/playwright/ensure-chromium.js +60 -0
- package/dist/playwright/ensure-chromium.js.map +1 -0
- package/dist/preview/capture-screenshot.d.ts +67 -0
- package/dist/preview/capture-screenshot.js +179 -0
- package/dist/preview/capture-screenshot.js.map +1 -0
- package/dist/preview/viewer-url.d.ts +82 -0
- package/dist/preview/viewer-url.js +130 -0
- package/dist/preview/viewer-url.js.map +1 -0
- package/dist/process/fault-barrier.d.ts +55 -0
- package/dist/process/fault-barrier.js +113 -0
- package/dist/process/fault-barrier.js.map +1 -0
- package/dist/sabs/agent-facing-text.d.ts +35 -0
- package/dist/sabs/agent-facing-text.js +165 -0
- package/dist/sabs/agent-facing-text.js.map +1 -0
- package/dist/sabs/app-state.d.ts +126 -0
- package/dist/sabs/app-state.js +332 -0
- package/dist/sabs/app-state.js.map +1 -0
- package/dist/sabs/awaited-decision.d.ts +47 -0
- package/dist/sabs/awaited-decision.js +124 -0
- package/dist/sabs/awaited-decision.js.map +1 -0
- package/dist/sabs/browser-context.d.ts +53 -0
- package/dist/sabs/browser-context.js +92 -0
- package/dist/sabs/browser-context.js.map +1 -0
- package/dist/sabs/editor-client-methods.d.ts +164 -0
- package/dist/sabs/editor-client-methods.js +750 -0
- package/dist/sabs/editor-client-methods.js.map +1 -0
- package/dist/sabs/editor-socket.d.ts +84 -0
- package/dist/sabs/editor-socket.js +64 -0
- package/dist/sabs/editor-socket.js.map +1 -0
- package/dist/sabs/recent-tool-runs.d.ts +14 -0
- package/dist/sabs/recent-tool-runs.js +61 -0
- package/dist/sabs/recent-tool-runs.js.map +1 -0
- package/dist/sabs/session-peer.d.ts +392 -0
- package/dist/sabs/session-peer.js +11 -0
- package/dist/sabs/session-peer.js.map +1 -0
- package/dist/sabs/streamed-reply.d.ts +42 -0
- package/dist/sabs/streamed-reply.js +110 -0
- package/dist/sabs/streamed-reply.js.map +1 -0
- package/dist/sabs/turn-collector.d.ts +169 -0
- package/dist/sabs/turn-collector.js +506 -0
- package/dist/sabs/turn-collector.js.map +1 -0
- package/dist/sabs/websocket-session-peer.d.ts +540 -0
- package/dist/sabs/websocket-session-peer.js +3289 -0
- package/dist/sabs/websocket-session-peer.js.map +1 -0
- package/dist/security/constant-time.d.ts +9 -0
- package/dist/security/constant-time.js +13 -0
- package/dist/security/constant-time.js.map +1 -0
- package/dist/server/client.d.ts +405 -0
- package/dist/server/client.js +684 -0
- package/dist/server/client.js.map +1 -0
- package/dist/server/identity-reads.d.ts +76 -0
- package/dist/server/identity-reads.js +209 -0
- package/dist/server/identity-reads.js.map +1 -0
- package/dist/start.d.ts +24 -0
- package/dist/start.js +81 -0
- package/dist/start.js.map +1 -0
- package/dist/stores/memory.d.ts +42 -0
- package/dist/stores/memory.js +121 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/stores/types.d.ts +74 -0
- package/dist/stores/types.js +11 -0
- package/dist/stores/types.js.map +1 -0
- package/dist/telemetry/mcp-client.d.ts +22 -0
- package/dist/telemetry/mcp-client.js +140 -0
- package/dist/telemetry/mcp-client.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +41 -0
- package/dist/telemetry/metrics.js +103 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/runtime.d.ts +9 -0
- package/dist/telemetry/runtime.js +118 -0
- package/dist/telemetry/runtime.js.map +1 -0
- package/dist/transports/mcp/admin-tools.d.ts +56 -0
- package/dist/transports/mcp/admin-tools.js +252 -0
- package/dist/transports/mcp/admin-tools.js.map +1 -0
- package/dist/transports/mcp/app-status-html.d.ts +11 -0
- package/dist/transports/mcp/app-status-html.js +899 -0
- package/dist/transports/mcp/app-status-html.js.map +1 -0
- package/dist/transports/mcp/client-presentation.d.ts +16 -0
- package/dist/transports/mcp/client-presentation.js +13 -0
- package/dist/transports/mcp/client-presentation.js.map +1 -0
- package/dist/transports/mcp/cowork-editor-url.d.ts +6 -0
- package/dist/transports/mcp/cowork-editor-url.js +10 -0
- package/dist/transports/mcp/cowork-editor-url.js.map +1 -0
- package/dist/transports/mcp/decision-card-html.d.ts +26 -0
- package/dist/transports/mcp/decision-card-html.js +876 -0
- package/dist/transports/mcp/decision-card-html.js.map +1 -0
- package/dist/transports/mcp/decision-elicitation.d.ts +116 -0
- package/dist/transports/mcp/decision-elicitation.js +292 -0
- package/dist/transports/mcp/decision-elicitation.js.map +1 -0
- package/dist/transports/mcp/dispatch-probe.d.ts +24 -0
- package/dist/transports/mcp/dispatch-probe.js +48 -0
- package/dist/transports/mcp/dispatch-probe.js.map +1 -0
- package/dist/transports/mcp/editor-document-probe.d.ts +4 -0
- package/dist/transports/mcp/editor-document-probe.js +35 -0
- package/dist/transports/mcp/editor-document-probe.js.map +1 -0
- package/dist/transports/mcp/editor-integration-setup-url.d.ts +8 -0
- package/dist/transports/mcp/editor-integration-setup-url.js +23 -0
- package/dist/transports/mcp/editor-integration-setup-url.js.map +1 -0
- package/dist/transports/mcp/format-tool-content.d.ts +20 -0
- package/dist/transports/mcp/format-tool-content.js +89 -0
- package/dist/transports/mcp/format-tool-content.js.map +1 -0
- package/dist/transports/mcp/instructions/index.d.ts +23 -0
- package/dist/transports/mcp/instructions/index.js +81 -0
- package/dist/transports/mcp/instructions/index.js.map +1 -0
- package/dist/transports/mcp/instructions/result.d.ts +18 -0
- package/dist/transports/mcp/instructions/result.js +58 -0
- package/dist/transports/mcp/instructions/result.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/ask-user.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/ask-user.js +17 -0
- package/dist/transports/mcp/instructions/tools/ask-user.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.js +75 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js +23 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/copy.d.ts +14 -0
- package/dist/transports/mcp/instructions/tools/copy.js +35 -0
- package/dist/transports/mcp/instructions/tools/copy.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/create-integration.d.ts +4 -0
- package/dist/transports/mcp/instructions/tools/create-integration.js +41 -0
- package/dist/transports/mcp/instructions/tools/create-integration.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/edit-app.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/edit-app.js +18 -0
- package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/get-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/get-app.js +47 -0
- package/dist/transports/mcp/instructions/tools/get-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js +13 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/index.d.ts +7 -0
- package/dist/transports/mcp/instructions/tools/index.js +26 -0
- package/dist/transports/mcp/instructions/tools/index.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/preview-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/preview-app.js +14 -0
- package/dist/transports/mcp/instructions/tools/preview-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/publish-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/publish-app.js +23 -0
- package/dist/transports/mcp/instructions/tools/publish-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/start-app.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/start-app.js +22 -0
- package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.js +13 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.js.map +1 -0
- package/dist/transports/mcp/mcp-app-brand-css.d.ts +1 -0
- package/dist/transports/mcp/mcp-app-brand-css.js +180 -0
- package/dist/transports/mcp/mcp-app-brand-css.js.map +1 -0
- package/dist/transports/mcp/mount.d.ts +22 -0
- package/dist/transports/mcp/mount.js +1040 -0
- package/dist/transports/mcp/mount.js.map +1 -0
- package/dist/transports/mcp/native-browser-presence.d.ts +45 -0
- package/dist/transports/mcp/native-browser-presence.js +158 -0
- package/dist/transports/mcp/native-browser-presence.js.map +1 -0
- package/dist/transports/mcp/plan-approval.d.ts +38 -0
- package/dist/transports/mcp/plan-approval.js +175 -0
- package/dist/transports/mcp/plan-approval.js.map +1 -0
- package/dist/transports/mcp/progress-notifier.d.ts +39 -0
- package/dist/transports/mcp/progress-notifier.js +52 -0
- package/dist/transports/mcp/progress-notifier.js.map +1 -0
- package/dist/transports/mcp/session-directory.d.ts +7 -0
- package/dist/transports/mcp/session-directory.js +18 -0
- package/dist/transports/mcp/session-directory.js.map +1 -0
- package/dist/transports/mcp/tool-names.d.ts +2 -0
- package/dist/transports/mcp/tool-names.js +2 -0
- package/dist/transports/mcp/tool-names.js.map +1 -0
- package/package.json +78 -0
- package/skills/superblocks-build/SKILL.md +59 -0
- package/skills/superblocks-import/SKILL.md +88 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-status-html.js","sourceRoot":"","sources":["../../../src/transports/mcp/app-status-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,kCAAkC,CAAC;AAE1E,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6E7B,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyyBlB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What surfaces a host has. MCP advertises no capability for a host's own
|
|
3
|
+
* browser or ask/choice UI, so `clientInfo.name` is the only signal.
|
|
4
|
+
*/
|
|
5
|
+
export type ClientPresentationCapabilities = {
|
|
6
|
+
/** Cowork puts a decision to the user with its own choice UI, so ask_user is wrong there. */
|
|
7
|
+
hasNativeAskForm: boolean;
|
|
8
|
+
hasNativeBrowser: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** Presentation surfaces plus the one capability MCP does advertise. */
|
|
11
|
+
export type ClientProfile = ClientPresentationCapabilities & {
|
|
12
|
+
supportsFormElicitation: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare function clientPresentationCapabilities(client: {
|
|
15
|
+
name: string;
|
|
16
|
+
} | undefined): ClientPresentationCapabilities;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What surfaces a host has. MCP advertises no capability for a host's own
|
|
3
|
+
* browser or ask/choice UI, so `clientInfo.name` is the only signal.
|
|
4
|
+
*/
|
|
5
|
+
export function clientPresentationCapabilities(client) {
|
|
6
|
+
const isCowork = client?.name === "local-agent-mode-superblocks" ||
|
|
7
|
+
client?.name.startsWith("local-agent-mode-plugin:") === true;
|
|
8
|
+
return {
|
|
9
|
+
hasNativeAskForm: isCowork,
|
|
10
|
+
hasNativeBrowser: isCowork,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=client-presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-presentation.js","sourceRoot":"","sources":["../../../src/transports/mcp/client-presentation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,UAAU,8BAA8B,CAC5C,MAAoC;IAEpC,MAAM,QAAQ,GACZ,MAAM,EAAE,IAAI,KAAK,8BAA8B;QAC/C,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,0BAA0B,CAAC,KAAK,IAAI,CAAC;IAC/D,OAAO;QACL,gBAAgB,EAAE,QAAQ;QAC1B,gBAAgB,EAAE,QAAQ;KAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor only renders in Cowork's host mode when the URL says so, so every
|
|
3
|
+
* editor URL handed to the embedded browser carries the param - a build's
|
|
4
|
+
* navigation and a publish's details page alike.
|
|
5
|
+
*/
|
|
6
|
+
export declare function withCoworkEditorHost(url: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { URL_PARAMS } from "@superblocksteam/library-shared";
|
|
2
|
+
/**
|
|
3
|
+
* The editor only renders in Cowork's host mode when the URL says so, so every
|
|
4
|
+
* editor URL handed to the embedded browser carries the param - a build's
|
|
5
|
+
* navigation and a publish's details page alike.
|
|
6
|
+
*/
|
|
7
|
+
export function withCoworkEditorHost(url) {
|
|
8
|
+
return `${url}${url.includes("?") ? "&" : "?"}${URL_PARAMS.editorHost}=cowork`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=cowork-editor-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cowork-editor-url.js","sourceRoot":"","sources":["../../../src/transports/mcp/cowork-editor-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE7D;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,UAAU,CAAC,UAAU,SAAS,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained MCP App HTML for the plan or question Superblocks stopped on.
|
|
3
|
+
*
|
|
4
|
+
* A host with form elicitation gets a native picker and never opens this. This
|
|
5
|
+
* is for the hosts that have none - Claude Desktop today - where the whole
|
|
6
|
+
* decision UX would otherwise be the model choosing to write the plan out and
|
|
7
|
+
* ask. It does that inconsistently, so the card puts the plan on screen with
|
|
8
|
+
* Build it / Change something next to it.
|
|
9
|
+
*
|
|
10
|
+
* The answer travels as `ui/message`, not a direct `edit_app` call. A plan
|
|
11
|
+
* approval first consumes a private capability through an app-only tool, then
|
|
12
|
+
* `ui/message` posts the answer as the user's own turn so the agent loop
|
|
13
|
+
* continues exactly as it would have had they typed it.
|
|
14
|
+
*
|
|
15
|
+
* The card is an accelerator, never the only route: the decision is in the tool
|
|
16
|
+
* result as data too, and a host that will not deliver `ui/message` is told to
|
|
17
|
+
* answer in the chat rather than left with a dead form.
|
|
18
|
+
*
|
|
19
|
+
* Speaks the MCP Apps postMessage dialect without bundling ext-apps into the
|
|
20
|
+
* card (hosts cache UI resources; keep this file small and inline). Bump the
|
|
21
|
+
* resource URI when the HTML changes so Claude Desktop refreshes its cache.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PLAN_APPROVAL_TOKEN_META_KEY = "superblocks/plan-approval-token";
|
|
24
|
+
export declare const CONFIRM_PLAN_APPROVAL_TOOL = "confirm_plan_approval";
|
|
25
|
+
export declare const APP_DECISION_RESOURCE_URI = "ui://gateway/decision-v20.html";
|
|
26
|
+
export declare const APP_DECISION_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Superblocks needs an answer</title>\n <style>\n h1 {\n margin: 0;\n font-size: var(--font-text-md-size, 14px);\n font-weight: var(--font-weight-semibold, 600);\n }\n .meta {\n color: var(--sb-app-text-tertiary);\n font-size: var(--font-text-xs-size, 12px);\n }\n .reply {\n display: none;\n color: var(--sb-app-text-secondary);\n }\n .reply.shown {\n display: block;\n }\n .plan {\n display: none;\n max-height: 340px;\n margin: 0;\n overflow: auto;\n padding: 10px;\n border: var(--border-width-regular, 1px) solid var(--sb-app-border);\n border-radius: var(--border-radius-md, 8px);\n background: var(--sb-app-background-subtle);\n font-size: var(--font-text-xs-size, 12px);\n word-break: break-word;\n }\n .plan.shown {\n display: block;\n }\n .plan > :first-child,\n .question > :first-child {\n margin-top: 0;\n }\n .plan > :last-child,\n .question > :last-child {\n margin-bottom: 0;\n }\n .plan h1,\n .plan h2,\n .plan h3,\n .plan p,\n .question h1,\n .question h2,\n .question h3,\n .question p {\n margin: 10px 0;\n }\n .plan h1,\n .plan h2,\n .plan h3,\n .question h1,\n .question h2,\n .question h3 {\n font-size: inherit;\n font-weight: var(--font-weight-semibold, 600);\n }\n .plan ul,\n .plan ol,\n .question ul,\n .question ol {\n margin: 10px 0;\n padding-left: 20px;\n }\n .plan blockquote,\n .question blockquote {\n margin: 10px 0;\n padding-left: 10px;\n border-left: 3px solid var(--sb-app-border);\n color: var(--sb-app-text-secondary);\n }\n .plan pre,\n .question pre {\n overflow: auto;\n padding: 8px;\n border-radius: var(--border-radius-md, 8px);\n background: var(--sb-app-background);\n }\n .plan a,\n .question a {\n color: var(--sb-app-info-text);\n }\n .entity-tag {\n display: inline-flex;\n align-items: center;\n padding: 0 4px;\n max-width: 100%;\n overflow-wrap: anywhere;\n border: var(--border-width-regular, 1px) solid var(--sb-app-border);\n border-radius: 4px;\n background: var(--sb-app-background);\n color: var(--sb-app-info-text);\n font-weight: 400;\n line-height: 18px;\n vertical-align: middle;\n white-space: normal;\n }\n .task {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n }\n .task input {\n margin: 0;\n }\n .plan code,\n .question code,\n button code {\n font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);\n }\n .question {\n display: none;\n overflow-wrap: anywhere;\n font-weight: var(--font-weight-medium, 500);\n }\n .question.shown {\n display: block;\n }\n .actions {\n display: none;\n flex-wrap: wrap;\n gap: 8px;\n }\n .actions.shown {\n display: flex;\n }\n #options {\n flex-direction: column;\n flex-wrap: nowrap;\n }\n #options > .option-button {\n width: 100%;\n overflow-wrap: anywhere;\n text-align: left;\n }\n .refine {\n display: none;\n flex-direction: column;\n gap: 8px;\n }\n .refine.shown {\n display: flex;\n }\n textarea {\n width: 100%;\n box-sizing: border-box;\n min-height: 64px;\n padding: 8px;\n border: var(--border-width-regular, 1px) solid var(--sb-app-border);\n border-radius: var(--border-radius-md, 8px);\n background: var(--sb-app-background);\n color: var(--sb-app-text);\n font: inherit;\n resize: vertical;\n }\n .note {\n color: var(--sb-app-text-secondary);\n font-size: var(--font-text-xs-size, 12px);\n }\n\n :root {\n color-scheme: light dark;\n --sb-app-background: var(\n --color-background-primary,\n light-dark(#ffffff, #1b1c1f)\n );\n --sb-app-background-subtle: var(\n --color-background-secondary,\n light-dark(#f9fafb, #24272b)\n );\n --sb-app-background-hover: var(\n --color-background-tertiary,\n light-dark(#f3f4f6, #2f3437)\n );\n --sb-app-background-inverse: var(\n --color-background-inverse,\n light-dark(#121517, #f9fafb)\n );\n --sb-app-text: var(\n --color-text-primary,\n light-dark(#121517, #f9fafb)\n );\n --sb-app-text-secondary: var(\n --color-text-secondary,\n light-dark(#5a6272, #c6cad2)\n );\n --sb-app-text-tertiary: var(\n --color-text-tertiary,\n light-dark(#6b7280, #a4aab7)\n );\n --sb-app-text-inverse: var(\n --color-text-inverse,\n light-dark(#ffffff, #121517)\n );\n --sb-app-border: var(\n --color-border-primary,\n light-dark(#e8eaed, #454d5f)\n );\n --sb-app-ring: var(\n --color-ring-primary,\n light-dark(#0077b6, #27bbff)\n );\n --sb-app-info-background: var(\n --color-background-info,\n light-dark(#e6f5ff, #083a50)\n );\n --sb-app-info-text: var(\n --color-text-info,\n light-dark(#00679e, #7dd3fc)\n );\n --sb-app-info-border: var(\n --color-border-info,\n light-dark(#c2e7ff, #075985)\n );\n --sb-app-success-background: var(\n --color-background-success,\n light-dark(#e8f8ef, #0a3926)\n );\n --sb-app-success-text: var(\n --color-text-success,\n light-dark(#087a43, #6ee7b7)\n );\n --sb-app-success-border: var(\n --color-border-success,\n light-dark(#b8e8cf, #087a43)\n );\n --sb-app-warning-background: var(\n --color-background-warning,\n light-dark(#fff7e6, #49350a)\n );\n --sb-app-warning-text: var(\n --color-text-warning,\n light-dark(#946200, #fcd34d)\n );\n --sb-app-warning-border: var(\n --color-border-warning,\n light-dark(#f5d996, #946200)\n );\n --sb-app-danger-background: var(\n --color-background-danger,\n light-dark(#fff1f1, #4a1d1d)\n );\n --sb-app-danger-text: var(\n --color-text-danger,\n light-dark(#c54141, #fca5a5)\n );\n --sb-app-danger-border: var(\n --color-border-danger,\n light-dark(#ffcaca, #c54141)\n );\n }\n * {\n box-sizing: border-box;\n }\n body {\n min-width: 0;\n margin: 0;\n overflow-x: hidden;\n background: transparent;\n color: var(--sb-app-text);\n font-family: var(--font-sans, system-ui, -apple-system, sans-serif);\n font-size: var(--font-text-sm-size, 13px);\n line-height: var(--font-text-sm-line-height, 1.45);\n }\n .card {\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: var(--border-width-regular, 1px) solid var(--sb-app-border);\n border-radius: var(--border-radius-lg, 12px);\n background: var(--sb-app-background);\n box-shadow: var(--shadow-sm, 0 1px 2px rgba(18, 21, 23, 0.08));\n }\n h1,\n .meta,\n .note {\n min-width: 0;\n overflow-wrap: anywhere;\n }\n .note:empty {\n position: absolute;\n }\n button,\n textarea {\n font: inherit;\n }\n button {\n appearance: none;\n min-width: 0;\n padding: 8px 12px;\n border: var(--border-width-regular, 1px) solid var(--sb-app-border);\n border-radius: var(--border-radius-md, 8px);\n background: var(--sb-app-background-subtle);\n color: var(--sb-app-text);\n font-weight: var(--font-weight-medium, 500);\n line-height: var(--font-text-sm-line-height, 1.45);\n cursor: pointer;\n }\n button:hover:not(:disabled) {\n background: var(--sb-app-background-hover);\n }\n .button-primary {\n border-color: var(--sb-app-background-inverse);\n background: var(--sb-app-background-inverse);\n color: var(--sb-app-text-inverse);\n }\n .button-primary:hover:not(:disabled) {\n border-color: var(--sb-app-background-inverse);\n background: var(--sb-app-background-inverse);\n }\n button:focus-visible,\n textarea:focus-visible,\n a:focus-visible {\n outline: 2px solid var(--sb-app-ring);\n outline-offset: 2px;\n }\n button:disabled {\n opacity: 0.48;\n cursor: not-allowed;\n }\n .actions {\n min-width: 0;\n }\n .actions > button {\n overflow-wrap: anywhere;\n }\n @media (max-width: 360px) {\n .actions {\n flex-direction: column;\n flex-wrap: nowrap;\n }\n .actions > button {\n width: 100%;\n }\n }\n\n </style>\n</head>\n<body>\n <div class=\"card\">\n <h1 id=\"heading\">Superblocks</h1>\n <div id=\"appId\" class=\"meta\"></div>\n <div id=\"reply\" class=\"reply\"></div>\n <div id=\"plan\" class=\"plan\"></div>\n <div id=\"question\" class=\"question\"></div>\n <div id=\"options\" class=\"actions\"></div>\n <div id=\"planActions\" class=\"actions\">\n <button id=\"approve\" class=\"button-primary\" type=\"button\">Build it</button>\n <button id=\"refine\" class=\"button-secondary\" type=\"button\">Change something</button>\n </div>\n <div id=\"refineBox\" class=\"refine\">\n <textarea id=\"feedback\" placeholder=\"What should change?\"></textarea>\n <button id=\"sendRefine\" class=\"button-primary\" type=\"button\">Send</button>\n </div>\n <div id=\"note\" class=\"note\" aria-live=\"polite\"></div>\n </div>\n <script>\n (() => {\n const PROTOCOL_VERSION = \"2026-01-26\";\n let nextId = 1;\n const pending = new Map();\n let applicationId = \"\";\n let appName = \"\";\n let reply = \"\";\n let decision = null;\n let status = \"\";\n let refining = false;\n let sending = false;\n let answered = false;\n let approvalToken = \"\";\n let optionButtons = [];\n let lastHeight = 0;\n\n function post(message) {\n window.parent.postMessage(message, \"*\");\n }\n\n function notify(method, params) {\n post({ jsonrpc: \"2.0\", method, params });\n }\n\n function request(method, params) {\n const id = nextId++;\n return new Promise((resolve, reject) => {\n pending.set(id, { resolve, reject });\n post({ jsonrpc: \"2.0\", id, method, params });\n });\n }\n\n function element(id) {\n return document.getElementById(id);\n }\n\n function show(id, on) {\n const node = element(id);\n if (node && node.classList) {\n node.classList.toggle(\"shown\", on);\n }\n }\n\n // Hosts size the card from this notification alone; without it the card\n // is laid out at zero height and never appears.\n function reportSize() {\n const height = Math.ceil(document.documentElement.scrollHeight || 0);\n if (height <= 0 || height === lastHeight) {\n return;\n }\n lastHeight = height;\n notify(\"ui/notifications/size-changed\", {\n height,\n width: Math.ceil(window.innerWidth || 0),\n });\n }\n\n function note(text) {\n element(\"note\").textContent = text;\n show(\"note\", Boolean(text));\n reportSize();\n }\n\n function applyHostContext(context) {\n if (!context || typeof context !== \"object\") {\n return;\n }\n const root = document.documentElement;\n if (context.theme === \"light\" || context.theme === \"dark\") {\n root.setAttribute(\"data-theme\", context.theme);\n root.style.colorScheme = context.theme;\n }\n const variables = context.styles && context.styles.variables;\n if (variables && root.style) {\n for (const name of Object.keys(variables)) {\n const value = variables[name];\n if (typeof value === \"string\") {\n root.style.setProperty(name, value);\n }\n }\n }\n const fonts = context.styles && context.styles.css?.fonts;\n if (typeof fonts === \"string\") {\n let fontStyle = document.getElementById(\"__mcp-host-fonts\");\n if (!fontStyle) {\n fontStyle = document.createElement(\"style\");\n fontStyle.id = \"__mcp-host-fonts\";\n document.head.appendChild(fontStyle);\n }\n fontStyle.textContent = fonts;\n }\n reportSize();\n }\n\n function setBusy(on) {\n element(\"approve\").disabled = on;\n element(\"refine\").disabled = on;\n element(\"sendRefine\").disabled = on;\n for (const button of optionButtons) {\n button.disabled = on;\n }\n }\n\n /**\n * Posts the answer as the user's own turn.\n *\n * Not tools/call: calling edit_app from in here starts a build the host\n * agent never learns about, so nothing polls it and nothing is relayed.\n */\n function answer(text) {\n if (!text || sending || answered) {\n return;\n }\n sending = true;\n setBusy(true);\n note(\"Sending your answer\u2026\");\n request(\"ui/message\", {\n content: [{ text: text, type: \"text\" }],\n role: \"user\",\n })\n .then((result) => {\n sending = false;\n if (result && result.isError) {\n refused();\n return;\n }\n answered = true;\n setBusy(true);\n // The host taking the message is not the same as the user's turn\n // going anywhere: Claude Desktop leaves it in the composer as a\n // draft. Claiming it was sent strands the user on a build that is\n // waiting for their enter key.\n note(\"Your answer is in the chat \u2014 press enter there to send it.\");\n })\n .catch(refused);\n }\n\n function refused() {\n sending = false;\n setBusy(false);\n note(\n \"This host would not take your answer from the card \u2014 reply in the chat instead.\",\n );\n }\n\n function approvalRefused() {\n sending = false;\n setBusy(false);\n note(\n \"This host could not verify your approval - approve this plan in the Superblocks editor instead.\",\n );\n }\n\n function approve() {\n if (sending || answered) {\n return;\n }\n if (!approvalToken) {\n approvalRefused();\n return;\n }\n sending = true;\n setBusy(true);\n note(\"Confirming your approval...\");\n request(\"tools/call\", {\n arguments: { approvalToken: approvalToken },\n name: \"confirm_plan_approval\",\n })\n .then((result) => {\n sending = false;\n if (result && result.isError) {\n approvalRefused();\n return;\n }\n answer(\"Build it \u2014 approve the Superblocks plan as written.\");\n })\n .catch(approvalRefused);\n }\n\n function renderOptions(options) {\n const host = element(\"options\");\n host.replaceChildren();\n optionButtons = [];\n options.forEach((option, index) => {\n const button = document.createElement(\"button\");\n button.id = \"option-\" + index;\n button.className = \"button-secondary option-button\";\n button.type = \"button\";\n button.innerHTML = markdownInline(option, false);\n // Verbatim: an option Superblocks did not offer reaches it as a\n // prompt answering a question it never asked.\n button.addEventListener(\"click\", () => answer(option));\n host.appendChild(button);\n optionButtons.push(button);\n });\n show(\"options\", options.length > 0);\n }\n\n function waitingNote() {\n if (status === \"building\") {\n return \"Superblocks is still building \u2014 nothing to answer yet.\";\n }\n // Something opened this card, so \"nothing is waiting on you\" is a dead\n // end: say where the answer to that actually is.\n return \"Nothing to answer here \u2014 the chat has the latest.\";\n }\n\n function escapeHtml(text) {\n return String(text).replace(/[&<>\"']/g, (character) => {\n return {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n }[character];\n });\n }\n\n function markdownInline(text, allowLinks = true) {\n const codeDelimiter = String.fromCharCode(96);\n const emphasis = (text) =>\n text\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"<strong>$1</strong>\")\n .replace(/__([^_]+)__/g, \"<strong>$1</strong>\")\n .replace(/(^|[^*])\\*([^*]+)\\*(?!\\*)/g, \"$1<em>$2</em>\")\n .replace(\n /(^|[^A-Za-z0-9_])_([^_]+)_(?![A-Za-z0-9_])/g,\n \"$1<em>$2</em>\",\n );\n const safeLink = (url) => {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"https:\" && Boolean(parsed.hostname);\n } catch {\n return false;\n }\n };\n const entities = /@((?:(?!\\[id=)[^@\\r\\n])+?(?<!\\s))\\[id=[^\\]\\r\\n]+\\]/gu;\n const links = /\\[([^\\]]+)\\]\\(([^\\s)]+)\\)/g;\n const renderLinks = (value, allowLinks) => {\n const output = [];\n let offset = 0;\n const text = String(value);\n for (const match of text.matchAll(links)) {\n const index = match.index ?? 0;\n if (text[index - 1] === \"!\") {\n continue;\n }\n output.push(emphasis(escapeHtml(text.slice(offset, index))));\n const label = match[1];\n const url = match[2];\n if (safeLink(url)) {\n output.push(\n allowLinks\n ? '<a href=\"' +\n escapeHtml(url) +\n '\" target=\"_blank\" rel=\"noopener noreferrer\">' +\n markdownInline(label, false) +\n \"</a>\"\n : markdownInline(label, false),\n );\n } else {\n output.push(emphasis(escapeHtml(match[0])));\n }\n offset = index + match[0].length;\n }\n output.push(emphasis(escapeHtml(text.slice(offset))));\n return output.join(\"\");\n };\n const renderText = (value, allowLinks) => {\n const text = String(value);\n let placeholderDelimiter = String.fromCharCode(0);\n while (text.includes(placeholderDelimiter)) {\n placeholderDelimiter += String.fromCharCode(0);\n }\n const linkDestinations = Array.from(text.matchAll(links), (match) => {\n const start = (match.index ?? 0) + match[1].length + 3;\n return { start, end: start + match[2].length };\n });\n const entityTags = [];\n const tokenized = text.replace(entities, (match, label, index) => {\n if (\n linkDestinations.some(\n ({ start, end }) => index >= start && index < end,\n )\n ) {\n return match;\n }\n const placeholder =\n placeholderDelimiter + entityTags.length + placeholderDelimiter;\n entityTags.push(\n '<span class=\"entity-tag\">' + escapeHtml(label) + \"</span>\",\n );\n return placeholder;\n });\n return entityTags.reduce(\n (html, tag, index) =>\n html.replace(\n placeholderDelimiter + index + placeholderDelimiter,\n () => tag,\n ),\n renderLinks(tokenized, allowLinks),\n );\n };\n return String(text)\n .split(/(\\x60[^\\x60]+\\x60)/)\n .map((part) =>\n part.startsWith(codeDelimiter) && part.endsWith(codeDelimiter)\n ? \"<code>\" + escapeHtml(part.slice(1, -1)) + \"</code>\"\n : renderText(part, allowLinks),\n )\n .join(\"\");\n }\n\n function markdownHtml(markdown) {\n const lines = String(markdown).replace(/\\r/g, \"\").split(\"\\n\");\n const output = [];\n const lists = [];\n let paragraph = [];\n const closeParagraph = () => {\n if (paragraph.length > 0) {\n output.push(\"<p>\" + markdownInline(paragraph.join(\" \")) + \"</p>\");\n paragraph = [];\n }\n };\n const closeList = () => {\n const list = lists.pop();\n if (!list) {\n return;\n }\n if (list.open) {\n output.push(\"</li>\");\n }\n output.push(\"</\" + list.tag + \">\");\n };\n const closeLists = () => {\n while (lists.length > 0) {\n closeList();\n }\n };\n const listItem = (line) => {\n const match = /^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/.exec(line);\n if (!match) {\n return undefined;\n }\n return {\n content: match[3],\n indent: match[1].replace(/\\t/g, \" \").length,\n tag: /\\d+\\./.test(match[2]) ? \"ol\" : \"ul\",\n };\n };\n const renderListItem = (item) => {\n while (\n lists.length > 0 &&\n item.indent < lists[lists.length - 1].indent\n ) {\n closeList();\n }\n let list = lists[lists.length - 1];\n if (\n !list ||\n item.indent > list.indent ||\n (item.indent === list.indent && item.tag !== list.tag)\n ) {\n if (list && item.indent === list.indent) {\n closeList();\n }\n output.push(\"<\" + item.tag + \">\");\n list = { indent: item.indent, open: false, tag: item.tag };\n lists.push(list);\n }\n if (list.open) {\n output.push(\"</li>\");\n }\n const task = /^\\[([ xX])\\]\\s+(.+)$/.exec(item.content);\n output.push(\n \"<li>\" +\n (task\n ? '<label class=\"task\"><input type=\"checkbox\" disabled' +\n (task[1].toLowerCase() === \"x\" ? \" checked\" : \"\") +\n \">\" +\n markdownInline(task[2]) +\n \"</label>\"\n : markdownInline(item.content)),\n );\n list.open = true;\n };\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index];\n const fence = /^\\x60{3}[^\\x60]*\\s*$/.exec(line);\n if (fence) {\n closeParagraph();\n closeLists();\n const code = [];\n while (\n index + 1 < lines.length &&\n !/^\\x60{3}\\s*$/.test(lines[index + 1])\n ) {\n index += 1;\n code.push(lines[index]);\n }\n if (index + 1 < lines.length) {\n index += 1;\n }\n output.push(\n \"<pre><code>\" + escapeHtml(code.join(\"\\n\")) + \"</code></pre>\",\n );\n continue;\n }\n const heading = /^(#{1,3})\\s+(.+?)\\s*$/.exec(line);\n const quote = /^>\\s?(.*)$/.exec(line);\n const item = listItem(line);\n const rule = /^(---+|\\*\\*\\*+|___+)$/.test(line.trim());\n if (heading) {\n closeParagraph();\n closeLists();\n const level = heading[1].length;\n output.push(\"<h\" + level + \">\" + markdownInline(heading[2]) + \"</h\" + level + \">\");\n } else if (quote) {\n closeParagraph();\n closeLists();\n const quoted = [];\n while (index < lines.length) {\n const next = /^>\\s?(.*)$/.exec(lines[index]);\n if (!next) {\n break;\n }\n quoted.push(next[1]);\n index += 1;\n }\n index -= 1;\n output.push(\"<blockquote>\" + markdownHtml(quoted.join(\"\\n\")) + \"</blockquote>\");\n } else if (item) {\n closeParagraph();\n renderListItem(item);\n } else if (rule) {\n closeParagraph();\n closeLists();\n output.push(\"<hr>\");\n } else if (line.trim()) {\n closeLists();\n paragraph.push(line.trim());\n } else {\n closeParagraph();\n closeLists();\n }\n }\n closeParagraph();\n closeLists();\n return output.join(\"\");\n }\n\n function render() {\n const waiting = status === \"needs_decision\";\n const plan =\n waiting && decision && decision.kind === \"plan\" ? decision : null;\n const choice =\n waiting && decision && decision.kind === \"multi_choice\"\n ? decision\n : null;\n\n element(\"heading\").textContent = plan\n ? \"Superblocks proposed a plan\"\n : choice\n ? \"Superblocks has a question\"\n : waiting\n ? \"Superblocks is waiting on you\"\n : \"Superblocks\";\n element(\"appId\").textContent = appName || applicationId;\n // Superblocks narrates its whole working session into the reply. Once\n // there is a plan or a question, that narration is preamble in front\n // of the thing being asked, so it is dropped: the ask is the ask. It\n // survives only when there is nothing structured, where the reply is\n // itself the whole question and hiding it leaves a blank card.\n const narrationOnly = Boolean(plan || choice);\n element(\"reply\").textContent = narrationOnly ? \"\" : reply;\n show(\"reply\", Boolean(reply) && !narrationOnly);\n element(\"plan\").innerHTML = plan ? markdownHtml(plan.plan) : \"\";\n show(\"plan\", Boolean(plan));\n element(\"question\").innerHTML = choice\n ? markdownHtml(choice.question)\n : \"\";\n show(\"question\", Boolean(choice));\n show(\"planActions\", Boolean(plan));\n renderOptions(choice ? choice.options : []);\n // A turn can stop waiting on the user having streamed its plan or\n // question as chat text, leaving nothing structured to lay out. The\n // reply is then the whole ask, so free text is the only honest form.\n show(\"refineBox\", plan ? refining : waiting && !choice);\n setBusy(answered || sending);\n if (!answered && !sending) {\n note(waiting ? \"\" : waitingNote());\n }\n reportSize();\n }\n\n function applyPayload(payload) {\n let value = payload;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch (error) {\n return;\n }\n }\n if (!value || typeof value !== \"object\") {\n return;\n }\n if (Array.isArray(value.content)) {\n applyContent(value.content);\n if (value.structuredContent) {\n applyPayload(value.structuredContent);\n }\n return;\n }\n if (value.result && typeof value.result === \"object\") {\n applyPayload(value.result);\n return;\n }\n if (value.kind === \"ok\" && value.value) {\n value = value.value;\n }\n if (typeof value.applicationId === \"string\") {\n applicationId = value.applicationId;\n }\n if (typeof value.name === \"string\") {\n appName = value.name;\n }\n if (typeof value.reply === \"string\") {\n reply = value.reply;\n }\n if (typeof value.status === \"string\") {\n status = value.status;\n }\n if (\"decision\" in value) {\n decision =\n value.decision && typeof value.decision === \"object\"\n ? value.decision\n : null;\n }\n render();\n }\n\n function applyContent(content) {\n for (const part of content || []) {\n if (part && part.type === \"text\" && typeof part.text === \"string\") {\n applyPayload(part.text);\n }\n }\n }\n\n function applyApprovalMetadata(value) {\n const metadata = value && typeof value === \"object\" ? value._meta : null;\n if (\n metadata &&\n typeof metadata[\"superblocks/plan-approval-token\"] === \"string\"\n ) {\n approvalToken = metadata[\"superblocks/plan-approval-token\"];\n }\n }\n\n function handleHostMessage(event) {\n // App documents are opaque-origin, so the host window is the only\n // identity available to authenticate a message against.\n if (event.source !== window.parent) {\n return;\n }\n const data = event.data;\n if (!data || typeof data !== \"object\") {\n return;\n }\n if (data.method === \"ping\") {\n post({ jsonrpc: \"2.0\", id: data.id, result: {} });\n return;\n }\n if (data.id != null && pending.has(data.id)) {\n const waiter = pending.get(data.id);\n pending.delete(data.id);\n if (data.error) {\n waiter.reject(data.error);\n } else {\n waiter.resolve(data.result);\n }\n return;\n }\n const method = data.method;\n const params = data.params || {};\n if (\n method === \"ui/notifications/tool-result\" ||\n method === \"ui/tool-result\" ||\n method === \"tools/call\"\n ) {\n approvalToken = \"\";\n applyApprovalMetadata(params);\n applyApprovalMetadata(params.result);\n applyContent(params.content || (params.result || {}).content || []);\n if (params.structuredContent) {\n applyPayload(params.structuredContent);\n }\n }\n if (method === \"ui/notifications/tool-input\" && params.arguments) {\n applyPayload(params.arguments);\n }\n if (method === \"ui/notifications/host-context-changed\") {\n applyHostContext(params);\n }\n }\n\n window.addEventListener(\"message\", handleHostMessage);\n\n element(\"approve\").addEventListener(\"click\", approve);\n element(\"refine\").addEventListener(\"click\", () => {\n refining = true;\n element(\"approve\").className = \"button-secondary\";\n show(\"refineBox\", true);\n element(\"feedback\").focus();\n reportSize();\n });\n element(\"sendRefine\").addEventListener(\"click\", () => {\n const feedback = (element(\"feedback\").value || \"\").trim();\n if (!feedback) {\n return;\n }\n answer(\n decision && decision.kind === \"plan\"\n ? \"Change the Superblocks plan: \" + feedback\n : feedback,\n );\n });\n\n if (typeof ResizeObserver === \"function\") {\n new ResizeObserver(reportSize).observe(document.documentElement);\n }\n\n void request(\"ui/initialize\", {\n appCapabilities: { availableDisplayModes: [\"inline\"] },\n appInfo: { name: \"gateway-decision\", version: \"0.0.1\" },\n protocolVersion: PROTOCOL_VERSION,\n })\n .then((result) => {\n // Hosts hold back tool results until the app confirms it is ready.\n notify(\"ui/notifications/initialized\", {});\n applyHostContext(result && result.hostContext);\n if (result && result.toolResult) {\n approvalToken = \"\";\n applyApprovalMetadata(result.toolResult);\n applyPayload(result.toolResult);\n }\n })\n .catch(() => {\n // Hosts that push tool results via notification still work.\n })\n .finally(reportSize);\n })();\n </script>\n</body>\n</html>\n";
|