@reqvire-org/ads 0.3.3 → 0.3.6
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/README.md +17 -5
- package/dist/behaviors.mjs +157 -0
- package/dist/bootstrap-ds/ADS.md +16 -3
- package/dist/bootstrap-ds/README.md +10 -0
- package/dist/bootstrap-ds/design-system/controllers/.gitkeep +0 -0
- package/dist/boundaries.mjs +3 -0
- package/dist/check.mjs +20 -2
- package/dist/cli.mjs +17 -0
- package/dist/config.mjs +23 -3
- package/dist/css-values.mjs +26 -0
- package/dist/index.mjs +2 -0
- package/dist/init.mjs +1 -1
- package/dist/mcp/build-status.mjs +17 -7
- package/dist/mcp/catalog.mjs +11 -8
- package/dist/mcp/context.mjs +3 -3
- package/dist/mcp/edit-preparation.mjs +111 -0
- package/dist/mcp/mutations.mjs +64 -38
- package/dist/mcp/preview-owner-guard.mjs +29 -0
- package/dist/mcp/preview-watch.mjs +38 -8
- package/dist/mcp/preview-widget.bundle.js +2 -2
- package/dist/mcp/prompts.mjs +2 -2
- package/dist/mcp/server.mjs +88 -41
- package/dist/mcp/showcase-host.mjs +9 -5
- package/dist/mcp/text-diff.mjs +19 -0
- package/dist/preview-resources.mjs +45 -8
- package/dist/preview-scope.mjs +30 -0
- package/dist/public-api.mjs +39 -0
- package/dist/scenarios-compiler.mjs +41 -19
- package/dist/scenarios.mjs +72 -42
- package/dist/scoped-tokens.mjs +57 -0
- package/dist/skills/README.md +3 -3
- package/dist/skills/ads-break-ui/SKILL.md +26 -2
- package/dist/skills/ads-break-ui/references/guarded-editing.md +44 -0
- package/dist/skills/ads-break-ui/references/verification.md +6 -0
- package/dist/skills/ads-designer/SKILL.md +27 -3
- package/dist/skills/ads-designer/assets/bootstrap-ds/ADS.md +16 -3
- package/dist/skills/ads-designer/assets/bootstrap-ds/README.md +10 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/controllers/.gitkeep +0 -0
- package/dist/skills/ads-designer/references/cli.md +1 -1
- package/dist/skills/ads-designer/references/design-craft.md +1 -1
- package/dist/skills/ads-designer/references/guarded-editing.md +44 -0
- package/dist/skills/ads-import/SKILL.md +26 -2
- package/dist/skills/ads-import/references/cli.md +1 -1
- package/dist/skills/ads-import/references/guarded-editing.md +44 -0
- package/dist/skills/ads-import/references/tokens.md +4 -2
- package/dist/skills/{ads-assimilate → ads-migrate}/SKILL.md +32 -8
- package/dist/skills/ads-migrate/agents/openai.yaml +4 -0
- package/dist/skills/{ads-assimilate → ads-migrate}/references/cli.md +1 -1
- package/dist/skills/ads-migrate/references/guarded-editing.md +44 -0
- package/dist/skills/{ads-assimilate → ads-migrate}/references/native-implementation.md +11 -0
- package/dist/skills/ads-motion/SKILL.md +26 -2
- package/dist/skills/ads-motion/references/guarded-editing.md +44 -0
- package/dist/token-fixtures.mjs +30 -0
- package/dist/tokens.mjs +11 -4
- package/dist/units.mjs +35 -9
- package/dist/verification/browser.mjs +27 -0
- package/dist/verification/playwright-reporter.cjs +20 -0
- package/dist/verification.mjs +214 -0
- package/docs/ADS.md +72 -4
- package/docs/ARCHITECTURE.md +60 -1
- package/docs/BEHAVIORS.md +241 -0
- package/docs/CHANGELOG.md +56 -0
- package/docs/GUIDE.md +24 -4
- package/docs/MCP.md +106 -12
- package/package.json +4 -2
- package/dist/skills/ads-assimilate/agents/openai.yaml +0 -4
- /package/dist/skills/{ads-assimilate → ads-migrate}/references/lint-and-docs.md +0 -0
- /package/dist/skills/{ads-assimilate → ads-migrate}/references/testing.md +0 -0
|
@@ -2,7 +2,9 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { statSync, mkdirSync, writeFileSync, renameSync, rmSync, realpathSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { buildFailure, inspectBuildStatus } from "./build-status.mjs";
|
|
7
|
+
import { previewSessionDirectories, withPreviewSession } from "../preview-scope.mjs";
|
|
6
8
|
|
|
7
9
|
function stamp(file) {
|
|
8
10
|
try { const stat = statSync(file); return `${stat.mtimeMs}:${stat.ctimeMs}:${stat.size}`; }
|
|
@@ -16,6 +18,7 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
16
18
|
let session = randomUUID();
|
|
17
19
|
let state = command ? "idle" : "disabled";
|
|
18
20
|
let child;
|
|
21
|
+
let ownerGuard;
|
|
19
22
|
let error;
|
|
20
23
|
let closed;
|
|
21
24
|
let childClosed = false;
|
|
@@ -23,6 +26,7 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
23
26
|
let stopping;
|
|
24
27
|
let restarting;
|
|
25
28
|
let disposed = false;
|
|
29
|
+
let stalled = false;
|
|
26
30
|
const baselines = new Map();
|
|
27
31
|
const ready = new Set();
|
|
28
32
|
const requests = new Set();
|
|
@@ -69,6 +73,23 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
69
73
|
log.write(`ads mcp: ${error}\n`);
|
|
70
74
|
return;
|
|
71
75
|
}
|
|
76
|
+
if (child.pid) {
|
|
77
|
+
// A small independent guard owns a pipe from this MCP process. It can
|
|
78
|
+
// terminate the detached compiler group even if this process is SIGKILLed.
|
|
79
|
+
const guard = ownerGuard = spawn(process.execPath, [fileURLToPath(new URL("./preview-owner-guard.mjs", import.meta.url)), String(child.pid)], {
|
|
80
|
+
stdio: ["pipe", "ignore", "pipe"], detached: process.platform !== "win32", windowsHide: true,
|
|
81
|
+
});
|
|
82
|
+
guard.stdin.on("error", () => {}); // Owner shutdown can race guard exit.
|
|
83
|
+
guard.stderr.pipe(log, { end: false });
|
|
84
|
+
function guardFailed(failure) {
|
|
85
|
+
if (ownerGuard !== guard || state === "stopping" || childClosed) return;
|
|
86
|
+
error = `Preview ownership guard failed: ${failure.message ?? failure}. Invoke the preview again after fixing the launcher.`;
|
|
87
|
+
state = "failed";
|
|
88
|
+
kill("SIGKILL");
|
|
89
|
+
}
|
|
90
|
+
guard.once("error", guardFailed);
|
|
91
|
+
guard.once("exit", (code, signal) => guardFailed(signal ?? code));
|
|
92
|
+
}
|
|
72
93
|
child.stdout.pipe(log, { end: false });
|
|
73
94
|
child.stderr.pipe(log, { end: false });
|
|
74
95
|
closed = new Promise((resolve) => child.once("close", (code, signal) => {
|
|
@@ -76,6 +97,8 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
76
97
|
// Finish cleanup now, before discarding the owned process-group ID.
|
|
77
98
|
kill("SIGKILL");
|
|
78
99
|
childClosed = true;
|
|
100
|
+
const guard = ownerGuard; ownerGuard = undefined;
|
|
101
|
+
guard?.stdin.end("disarm\n");
|
|
79
102
|
clearTimeout(killTimer);
|
|
80
103
|
if (state !== "stopping") {
|
|
81
104
|
state = "failed";
|
|
@@ -102,14 +125,14 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
102
125
|
requestFile = path.join(root, ".ds", `preview-requests-${session}.json`);
|
|
103
126
|
reportFile = path.join(root, ".ds", `build-status-${session}.json`);
|
|
104
127
|
state = "idle"; error = undefined; child = closed = stopping = undefined; childClosed = false;
|
|
105
|
-
ready.clear(); baselines.clear(); active = undefined;
|
|
128
|
+
ready.clear(); baselines.clear(); active = undefined; stalled = false;
|
|
106
129
|
start();
|
|
107
130
|
})().finally(() => { restarting = undefined; });
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
async function ensure(file, signal) {
|
|
111
134
|
if (signal?.aborted) throw new Error("Preview request cancelled.");
|
|
112
|
-
if (state === "failed" || restarting) await restart();
|
|
135
|
+
if (state === "failed" || restarting || stalled) await restart();
|
|
113
136
|
if (disposed) throw new Error("Preview watcher is stopped.");
|
|
114
137
|
start();
|
|
115
138
|
request(file);
|
|
@@ -132,27 +155,33 @@ export function createPreviewWatch(root, config, { log = process.stderr, buildTi
|
|
|
132
155
|
if (build?.state === "unreported" && current !== null && current !== baseline) { ready.add(file); return build; }
|
|
133
156
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
134
157
|
}
|
|
135
|
-
|
|
158
|
+
stalled = true;
|
|
159
|
+
const report = buildStatus();
|
|
160
|
+
throw Object.assign(new Error(`Preview build is still pending${report.progress ? ` in ${report.progress.phase} for ${Math.round((Date.now() - Date.parse(report.progress.updatedAt)) / 1000)}s` : ""}. Inspect ads://project/build and builder logs. Invoke the preview again to restart the timed-out builder within this MCP session.`), { build: { ...report, watcher: status(), code: "ADS_PREVIEW_PENDING" } });
|
|
136
161
|
}
|
|
137
162
|
|
|
138
|
-
const status = () => ({ state, ...(child?.pid ? { pid: child.pid } : {}), ...(error ? { error } : {}) });
|
|
139
|
-
const
|
|
163
|
+
const status = () => ({ state, ...(stalled ? { stalled: true } : {}), ...(child?.pid ? { pid: child.pid } : {}), ...(ownerGuard?.pid ? { guardPid: ownerGuard.pid } : {}), ...(error ? { error } : {}) });
|
|
164
|
+
const resourceSession = () => command && config.previewManifest ? session : undefined;
|
|
165
|
+
const buildStatus = () => inspectBuildStatus(root, config, command ? { session, previewSession: resourceSession(), file: reportFile, processState: status() } : {});
|
|
166
|
+
function clearOutput() {
|
|
167
|
+
for (const directory of previewSessionDirectories(withPreviewSession({ root, config: { mcp: config } }, resourceSession()))) rmSync(directory, { recursive: true, force: true });
|
|
168
|
+
}
|
|
140
169
|
|
|
141
170
|
async function stopChild() {
|
|
142
171
|
rmSync(requestFile, { force: true });
|
|
143
172
|
if (stopping) return stopping;
|
|
144
|
-
if (!child || childClosed) { if (command) state = "stopped"; rmSync(reportFile, { force: true }); return; }
|
|
173
|
+
if (!child || childClosed) { if (command) state = "stopped"; rmSync(reportFile, { force: true }); clearOutput(); return; }
|
|
145
174
|
if (state === "stopped") return;
|
|
146
175
|
state = "stopping";
|
|
147
176
|
stopping = (async () => {
|
|
148
177
|
kill("SIGTERM");
|
|
149
178
|
clearTimeout(killTimer);
|
|
150
179
|
const timer = setTimeout(() => kill("SIGKILL"), 1500);
|
|
151
|
-
try { await closed; } finally { clearTimeout(timer); rmSync(reportFile, { force: true }); }
|
|
180
|
+
try { await closed; } finally { clearTimeout(timer); rmSync(reportFile, { force: true }); clearOutput(); }
|
|
152
181
|
})();
|
|
153
182
|
return stopping;
|
|
154
183
|
}
|
|
155
|
-
return { start, ensure, async stop() { disposed = true; await restarting; return stopChild(); }, kill: () => kill("SIGKILL"), status, buildStatus, setApps(apps) {
|
|
184
|
+
return { start, ensure, async stop() { disposed = true; await restarting; return stopChild(); }, kill: () => kill("SIGKILL"), status, resourceSession, buildStatus, setApps(apps) {
|
|
156
185
|
for (const app of apps) {
|
|
157
186
|
const file = path.resolve(root, app.file);
|
|
158
187
|
if (!baselines.has(file)) baselines.set(file, stamp(file));
|
|
@@ -171,6 +200,7 @@ export function createReconfigurablePreviewWatch(root, config, options) {
|
|
|
171
200
|
start() { if (!stopped && !replacing) current.start(); },
|
|
172
201
|
async ensure(file, signal) { await pending; if (stopped) throw new Error("Preview watcher is stopped."); return current.ensure(file, signal); },
|
|
173
202
|
status() { return replacing ? { state: "reconfiguring" } : current.status(); },
|
|
203
|
+
resourceSession() { return current.resourceSession(); },
|
|
174
204
|
buildStatus() { return current.buildStatus(); },
|
|
175
205
|
setApps(next) { apps = next; current.setApps(next); },
|
|
176
206
|
kill() { current.kill(); },
|
|
@@ -100,9 +100,9 @@ Boolean requesting whether a visible border and background is provided by the ho
|
|
|
100
100
|
- omitted: host decides border`)}),Bx=d.object({method:d.literal("ui/request-display-mode"),params:d.object({mode:da.describe("The display mode being requested.")})}),Dv=d.object({mode:da.describe("The display mode that was actually set. May differ from requested if not supported.")}).passthrough(),Vv=d.union([d.literal("model"),d.literal("app")]).describe("Tool visibility scope - who can access the tool."),Wx=d.object({resourceUri:d.string().optional(),visibility:d.array(Vv).optional().describe(`Who can access this tool. Default: ["model", "app"]
|
|
101
101
|
- "model": Tool visible to and callable by the agent
|
|
102
102
|
- "app": Tool callable by the app from this server only`),csp:d.never().optional(),permissions:d.never().optional()}),Gx=d.object({mimeTypes:d.array(d.string()).optional().describe('Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.')}),Kx=d.object({method:d.literal("ui/download-file"),params:d.object({contents:d.array(d.union([go,So])).describe("Resource contents to download \u2014 embedded (inline data) or linked (host fetches). Uses standard MCP resource types.")})}),Yx=d.object({method:d.literal("ui/message"),params:d.object({role:d.literal("user").describe('Message role, currently only "user" is supported.'),content:d.array(Fe).describe("Message content blocks (text, image, etc.).")})}),Qx=d.object({method:d.literal("ui/notifications/sandbox-resource-ready"),params:d.object({html:d.string().describe("HTML content to load into the inner iframe."),sandbox:d.string().optional().describe("Optional override for the inner iframe's sandbox attribute."),csp:_f.optional().describe("CSP configuration from resource metadata."),permissions:yf.optional().describe("Sandbox permissions from resource metadata.")})}),Hv=d.object({method:d.literal("ui/notifications/tool-result"),params:Ot.describe("Standard MCP tool execution result.")}),x_=d.object({toolInfo:d.object({id:Ne.optional().describe("JSON-RPC id of the tools/call request."),tool:It.describe("Tool definition including name, inputSchema, etc.")}).optional().describe("Metadata of the tool call that instantiated this App."),theme:Tv.optional().describe("Current color theme preference."),styles:Av.optional().describe("Style configuration for theming the app."),displayMode:da.optional().describe("How the UI is currently displayed."),availableDisplayModes:d.array(da).optional().describe("Display modes the host supports."),containerDimensions:d.union([d.object({height:d.number().describe("Fixed container height in pixels.")}),d.object({maxHeight:d.union([d.number(),d.undefined()]).optional().describe("Maximum container height in pixels.")})]).and(d.union([d.object({width:d.number().describe("Fixed container width in pixels.")}),d.object({maxWidth:d.union([d.number(),d.undefined()]).optional().describe("Maximum container width in pixels.")})])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other
|
|
103
|
-
container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:d.string().optional().describe("User's language and region preference in BCP 47 format."),timeZone:d.string().optional().describe("User's timezone in IANA format."),userAgent:d.string().optional().describe("Host application identifier."),platform:d.union([d.literal("web"),d.literal("desktop"),d.literal("mobile")]).optional().describe("Platform type for responsive design decisions."),deviceCapabilities:d.object({touch:d.boolean().optional().describe("Whether the device supports touch input."),hover:d.boolean().optional().describe("Whether the device supports hover interactions.")}).optional().describe("Device input capabilities."),safeAreaInsets:d.object({top:d.number().describe("Top safe area inset in pixels."),right:d.number().describe("Right safe area inset in pixels."),bottom:d.number().describe("Bottom safe area inset in pixels."),left:d.number().describe("Left safe area inset in pixels.")}).optional().describe("Mobile safe area boundaries in pixels.")}).passthrough(),Fv=d.object({method:d.literal("ui/notifications/host-context-changed"),params:x_.describe("Partial context update containing only changed fields.")}),Xx=d.object({method:d.literal("ui/update-model-context"),params:d.object({content:d.array(Fe).optional().describe("Context content blocks (text, image, etc.)."),structuredContent:d.record(d.string(),d.unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.")})}),eP=d.object({method:d.literal("ui/initialize"),params:d.object({appInfo:Ve.describe("App identification (name and version)."),appCapabilities:Zv.describe("Features and capabilities this app provides."),protocolVersion:d.string().describe("Protocol version this app supports.")})}),Jv=d.object({protocolVersion:d.string().describe('Negotiated protocol version string (e.g., "2025-11-21").'),hostInfo:Ve.describe("Host application identification and version."),hostCapabilities:Uv.describe("Features and capabilities provided by the host."),hostContext:x_.describe("Rich context about the host environment.")}).passthrough(),Bv={target:"draft-2020-12"};async function R_(e,t){let o=e["~standard"];if(o.jsonSchema)return o.jsonSchema[t](Bv);throw Error(`Schema (vendor: ${o.vendor}) does not implement Standard JSON Schema (~standard.jsonSchema). Use a library that does (zod v4, ArkType, Valibot) or wrap your schema accordingly.`)}async function w_(e,t,o=""){let r=await e["~standard"].validate(t);if(r.issues){let n=r.issues.map(s=>{let i=s.path?.map(c=>typeof c=="object"?c.key:c).join(".");return i?`${i}: ${s.message}`:s.message}).join("; ");throw Error(o+n)}return r.value}function Wv(e,t){let o={...e,...t};return t.experimental!==void 0&&(o.experimental={...e.experimental,...t.experimental}),t.tools!==void 0&&(o.tools={...e.tools,...t.tools}),o}var Jl=class e extends mf{_appInfo;_appCapabilities;options;_hostCapabilities;_hostInfo;_hostContext;_registeredTools={};_initializedSent=!1;_registeredEvents=new Set;_events=new ff;_methods=new gf;setRequestHandler=(...t)=>{let[o,...r]=z_("request",t)??t;this._methods.claim(o,"setRequestHandler"),super.setRequestHandler.call(this,o,...r)};setNotificationHandler=(...t)=>{let[o,...r]=z_("notification",t)??t;this._methods.claim(o,"setNotificationHandler"),super.setNotificationHandler.call(this,o,...r)};removeRequestHandler=t=>{this._methods.release(t),super.removeRequestHandler(t)};removeNotificationHandler=t=>{this._methods.release(t),super.removeNotificationHandler(t)};replaceRequestHandler=(t,...o)=>{this._methods.replace(t),super.setRequestHandler.call(this,t,...o)};_assertInitialized(t){if(this._initializedSent)return;let o=`[ext-apps] App.${t}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(o);console.warn(`${o}. This will throw in a future release.`)}eventSchemas={toolinput:Ov,toolinputpartial:Nv,toolresult:Hv,toolcancelled:Mv,hostcontextchanged:Fv};static ONE_SHOT_EVENTS=new Set(["toolinput","toolinputpartial","toolresult","toolcancelled"]);_everHadListener=new Set;_assertHandlerTiming(t){if(!e.ONE_SHOT_EVENTS.has(t)||this._everHadListener.has(t)||(this._everHadListener.add(t),!this._initializedSent))return;let o=`[ext-apps] "${String(t)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(o);console.warn(o)}setEventHandler(t,o){o&&this._assertHandlerTiming(t),this._ensureEventSlot(t),this._events.setHandler(t,o)}addEventListener(t,o){this._assertHandlerTiming(t),this._ensureEventSlot(t),this._events.addEventListener(t,o)}removeEventListener(t,o){this._events.removeEventListener(t,o)}_ensureEventSlot(t){if(this._registeredEvents.has(t))return;let o=this.eventSchemas[t];if(!o)throw Error(`Unknown event: ${String(t)}`);this.setNotificationHandler(o.shape.method.value,{params:o.shape.params},r=>{let n=r;t==="hostcontextchanged"&&(this._hostContext={...this._hostContext,...n}),this._events.dispatch(t,n)}),this._registeredEvents.add(t)}getEventHandler(t){return this._events.getHandler(t)}warnIfRequestHandlerReplaced(t,o,r){o&&r&&console.warn(`[MCP Apps] ${t} handler replaced. Previous handler will no longer be called.`)}constructor(t,o={},r={autoResize:!0}){super(r),this._appInfo=t,this._appCapabilities=o,this.options=r,this._methods.replace("notifications/cancelled"),this._methods.replace("notifications/progress"),!r.allowUnsafeEval&&d.config({jitless:!0}),this.replaceRequestHandler("ping",n=>(console.log("Received ping:",n.params),{})),this.setEventHandler("hostcontextchanged",void 0)}buildContext(t){return t}registerAppCapabilities(t){if(this.transport)throw Error("Cannot register capabilities after transport is established");this._appCapabilities=Wv(this._appCapabilities,t)}registerTool(t,o,r){if(this._registeredTools[t])throw Error(`Tool ${t} is already registered`);let n=this,s=()=>{n._initializedSent&&n._appCapabilities.tools?.listChanged&&n.sendToolListChanged()},i=o.inputSchema!==void 0,c={title:o.title,description:o.description,inputSchema:o.inputSchema,outputSchema:o.outputSchema,annotations:o.annotations,_meta:o._meta,enabled:!0,enable(){this.enabled=!0,s()},disable(){this.enabled=!1,s()},update(l){Object.assign(this,l),s()},remove(){n._registeredTools[t]===c&&(delete n._registeredTools[t],s())},handler:async(l,u)=>{if(!c.enabled)throw Error(`Tool ${t} is disabled`);let m;if(i){let S=c.inputSchema,_=S?await w_(S,l??{},`Invalid input for tool ${t}: `):l??{};m=await r(_,u)}else m=await r(u);return c.outputSchema&&!m.isError&&(m.structuredContent=await w_(c.outputSchema,m.structuredContent,`Invalid output for tool ${t}: `)),m}};return this._registeredTools[t]=c,!this._appCapabilities.tools&&!this.transport&&this.registerAppCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),s(),c}_toolHandlersInitialized=!1;ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(t,o)=>{let r=this._registeredTools[t.name];if(!r)throw Error(`Tool ${t.name} not found`);return r.handler(t.arguments,o)},this.onlisttools=async(t,o)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([r,n])=>n.enabled).map(async([r,n])=>{let s={name:r,title:n.title,description:n.description,inputSchema:n.inputSchema?await R_(n.inputSchema,"input"):{type:"object",properties:{}}};return n.outputSchema&&(s.outputSchema=await R_(n.outputSchema,"output")),n.annotations&&(s.annotations=n.annotations),n._meta&&(s._meta=n._meta),s}))}))}async sendToolListChanged(t={}){this._assertInitialized("sendToolListChanged"),await this.notification({method:"notifications/tools/list_changed",params:t})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler("toolinput")}set ontoolinput(t){this.setEventHandler("toolinput",t)}get ontoolinputpartial(){return this.getEventHandler("toolinputpartial")}set ontoolinputpartial(t){this.setEventHandler("toolinputpartial",t)}get ontoolresult(){return this.getEventHandler("toolresult")}set ontoolresult(t){this.setEventHandler("toolresult",t)}get ontoolcancelled(){return this.getEventHandler("toolcancelled")}set ontoolcancelled(t){this.setEventHandler("toolcancelled",t)}get onhostcontextchanged(){return this.getEventHandler("hostcontextchanged")}set onhostcontextchanged(t){this.setEventHandler("hostcontextchanged",t)}_onteardown;get onteardown(){return this._onteardown}set onteardown(t){this.warnIfRequestHandlerReplaced("onteardown",this._onteardown,t),this._onteardown=t,this.replaceRequestHandler("ui/resource-teardown",{params:jv.shape.params,result:Lv},(o,r)=>{if(!this._onteardown)throw Error("No onteardown handler set");return this._onteardown(o,r)})}_oncalltool;get oncalltool(){return this._oncalltool}set oncalltool(t){this.warnIfRequestHandlerReplaced("oncalltool",this._oncalltool,t),this._oncalltool=t,this.replaceRequestHandler("tools/call",(o,r)=>{if(!this._oncalltool)throw Error("No oncalltool handler set");return this._oncalltool(o.params,r)})}_onlisttools;get onlisttools(){return this._onlisttools}set onlisttools(t){this.warnIfRequestHandlerReplaced("onlisttools",this._onlisttools,t),this._onlisttools=t,this.replaceRequestHandler("tools/list",(o,r)=>{if(!this._onlisttools)throw Error("No onlisttools handler set");return this._onlisttools(o.params,r)})}assertCapabilityForMethod(t){switch(t){case"sampling/createMessage":if(!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${t})`);break}}assertRequestHandlerCapability(t){switch(t){case"tools/call":case"tools/list":if(!this._appCapabilities.tools)throw Error(`Client does not support tool capability (required for ${t})`);return;default:return}}assertNotificationCapability(t){}async callServerTool(t,o){if(this._assertInitialized("callServerTool"),typeof t=="string")throw Error(`callServerTool() expects an object as its first argument, but received a string ("${t}"). Did you mean: callServerTool({ name: "${t}", arguments: { ... } })?`);return await this.request({method:"tools/call",params:t},{onprogress:()=>{},resetTimeoutOnProgress:!0,...o})}async readServerResource(t,o){return this._assertInitialized("readServerResource"),await this.request({method:"resources/read",params:t},o)}async listServerResources(t,o){return this._assertInitialized("listServerResources"),await this.request({method:"resources/list",params:t},o)}async createSamplingMessage(t,o){return this._assertInitialized("createSamplingMessage"),await this.request({method:"sampling/createMessage",params:t},o)}sendMessage(t,o){return this._assertInitialized("sendMessage"),this.request({method:"ui/message",params:t},Iv,o)}sendLog(t){return this.notification({method:"notifications/message",params:t})}updateModelContext(t,o){return this._assertInitialized("updateModelContext"),this.request({method:"ui/update-model-context",params:t},Ct,o)}openLink(t,o){return this._assertInitialized("openLink"),this.request({method:"ui/open-link",params:t},$v,o)}sendOpenLink=this.openLink;downloadFile(t,o){return this._assertInitialized("downloadFile"),this.request({method:"ui/download-file",params:t},Cv,o)}requestTeardown(t={}){return this.notification({method:"ui/notifications/request-teardown",params:t})}requestDisplayMode(t,o){return this._assertInitialized("requestDisplayMode"),this.request({method:"ui/request-display-mode",params:t},Dv,o)}sendSizeChanged(t){return this.notification({method:"ui/notifications/size-changed",params:t})}setupSizeChangedNotifications(){let t=!1,o=0,r=0,n=()=>{t||(t=!0,requestAnimationFrame(()=>{t=!1;let i=document.documentElement,c=i.style.height;i.style.height="max-content";let l=Math.ceil(i.getBoundingClientRect().height);i.style.height=c;let u=Math.ceil(window.innerWidth);(u!==o||l!==r)&&(o=u,r=l,this.sendSizeChanged({width:u,height:l}))}))};n();let s=new ResizeObserver(n);return s.observe(document.documentElement),s.observe(document.body),()=>s.disconnect()}async connect(t=new Sf(window.parent,window.parent),o){if(this.transport)throw Error("App is already connected. Call close() before connecting again.");this._initializedSent=!1;try{await super.connect(t);let r=await this.request({method:"ui/initialize",params:{appCapabilities:this._appCapabilities,appInfo:this._appInfo,protocolVersion:xv}},Jv,o);if(r===void 0)throw Error(`Server sent invalid initialize result: ${r}`);this._hostCapabilities=r.hostCapabilities,this._hostInfo=r.hostInfo,this._hostContext=r.hostContext,await this.notification({method:"ui/notifications/initialized"}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(r){throw this.close(),r}}};var Bl=class{constructor(t){this.read=t,this.records=new Map,this.bytes=new Map,this.urls=new Map,this.styles=new Map,this.styleReady=new Map,this.revisions=new Set,this.importing=Promise.resolve(),this.generation=0,this.closed=!1,globalThis.__dsPreviewImport=o=>this.importModule(o)}register(t){if(t.schemaVersion!==1||!Array.isArray(t.scenarios)||!t.assets||typeof t.revision!="string")throw new Error("Unsupported preview manifest. Rebuild previews with the installed ADS version.");if(this.revisions.add(t.revision),this.revisions.size>20)throw Object.assign(new Error("Reopen the preview to release modules retained across 20 build revisions."),{code:"ADS_PREVIEW_REOPEN"});for(let[o,r]of Object.entries(t.assets)){if(!/^ads:\/\/assets\/[a-f0-9]{64}\.[a-z0-9]+$/.test(o)||!/^sha256:[a-f0-9]{64}$/.test(r.digest)||!["imports","dynamicImports","styles","references"].every(n=>Array.isArray(r[n])&&r[n].every(s=>Object.hasOwn(t.assets,s))))throw new Error("Invalid preview dependency graph.");if(this.records.has(o)&&this.records.get(o).digest!==r.digest)throw new Error("An immutable preview resource changed its content.");this.records.set(o,r)}}async resource(t){if(!this.bytes.has(t)){let o=(async()=>{let r=this.records.get(t);if(!r)throw new Error(`Unknown preview dependency: ${t}`);let n=await this.read(t);if(this.closed)throw new Error("The preview App was closed.");let s=n.contents.find(u=>u.uri===t);if(!s)throw new Error(`Missing preview dependency: ${t}`);let i=typeof s.text=="string"?new TextEncoder().encode(s.text):Uint8Array.from(atob(s.blob),u=>u.charCodeAt(0)),c=await crypto.subtle.digest("SHA-256",i),l="sha256:"+[...new Uint8Array(c)].map(u=>u.toString(16).padStart(2,"0")).join("");if(i.length!==r.size||l!==r.digest)throw new Error("Preview resource integrity check failed. Rebuild and reopen the preview.");return i})();this.bytes.set(t,o),o.catch(()=>this.bytes.delete(t))}return this.bytes.get(t)}closure(t){let o=[],r=new Set,n=s=>{if(r.has(s))return;r.add(s);let i=this.records.get(s);if(!i)throw new Error(`Missing preview dependency metadata: ${s}`);for(let c of[...i.imports,...i.styles,...i.references])n(c);o.push(s)};return n(t),o}async materialize(t){let o=this.closure(t);await Promise.all(o.map(n=>this.resource(n)));let r={};for(let n of o){if(this.closed)throw new Error("The preview App was closed.");if(this.urls.has(n))continue;let s=this.records.get(n),i=await this.resource(n);if(s.kind==="module"||s.mimeType==="text/css"){let l=new TextDecoder().decode(i);for(let u of s.references){let m=this.urls.get(u);if(!m)throw new Error("Unsupported cyclic asset reference.");l=l.replaceAll(u,m)}i=l}let c=URL.createObjectURL(new Blob([i],{type:s.mimeType}));this.urls.set(n,c),s.kind==="module"&&(r[n]=c)}if(Object.keys(r).length){let n=document.createElement("script");n.type="importmap",n.textContent=JSON.stringify({imports:r}),document.head.append(n)}return o}async importModule(t){let o=this.importing.then(()=>this.materialize(t));this.importing=o.catch(()=>{});let r=await o;for(let n of r){if(this.records.get(n).mimeType!=="text/css")continue;if(this.styles.has(n)){await this.styleReady.get(n);continue}let i=document.createElement("link");i.rel="stylesheet",i.href=this.urls.get(n),this.styles.set(n,i);let c=new Promise((l,u)=>{i.onload=l,i.onerror=()=>u(new Error("The host CSP blocked a preview stylesheet."))});this.styleReady.set(n,c),document.head.append(i);try{await c}catch(l){throw i.remove(),this.styles.delete(n),this.styleReady.delete(n),l}}return import(t)}async mount(t,o,r){let n=++this.generation;this.register(t);let s=t.scenarios.find(l=>l.id===o);if(!s)throw new Error("The selected scenario is no longer registered.");let i=await this.importModule(s.module);if(n!==this.generation||(await this.unmount?.(),n!==this.generation||this.closed))return!1;r.replaceChildren();let c=new Set(this.closure(s.module));for(let[l,u]of this.styles)c.has(l)||(u.remove(),this.styles.delete(l),this.styleReady.delete(l));for(let l of this.closure(s.module))this.styles.has(l)&&document.head.append(this.styles.get(l));if(typeof i.mount!="function")throw new Error("The compiled scenario has no mount adapter.");if(this.unmount=i.mount(r),typeof this.unmount!="function")throw new Error("The scenario mount adapter must return an unmount callback.");return!0}async dispose(){if(!this.closed){this.closed=!0,++this.generation,await this.unmount?.();for(let t of this.styles.values())t.remove();for(let t of this.urls.values())URL.revokeObjectURL(t);this.styles.clear(),this.styleReady.clear(),this.urls.clear(),this.bytes.clear(),this.records.clear(),delete globalThis.__dsPreviewImport}}};function P_(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&typeof t=="object"&&typeof t.token=="string"&&/^--[\w-]+$/.test(t.token)&&typeof t.property=="string"&&/^-?[a-z][a-z0-9-]*$/.test(t.property)&&typeof t.probe=="string"&&t.probe.trim().length>0)&&new Set(e.map(t=>`${t.token}:${t.property}`)).size===e.length}function T_(e,t){let o=t.getComputedStyle(e),r=e.getBoundingClientRect();if(o.display==="none"||o.visibility!=="visible"||!e.getClientRects().length||!(r.width||r.height))return!1;for(let n=e;n;n=n.parentElement)if(Number(t.getComputedStyle(n).opacity)===0)return!1;return!0}function k_(e,t){if(!P_(t))return{ok:!1,diagnostics:["Token preview needs explicit { token, property, probe } samples from the project fixture. Rebuild with the current compiler."]};let o=e.ownerDocument,r=o.defaultView,n=o.documentElement,s=[],i=[],c=[...e.querySelectorAll("[data-ads-token], [data-ads-property]")],l=new Set(t.map(u=>`${u.token}:${u.property}`));for(let u of c)l.has(`${u.dataset.adsToken}:${u.dataset.adsProperty}`)||s.push(`Undeclared rendered token sample ${u.dataset.adsToken}:${u.dataset.adsProperty}.`);for(let u of t){if(!r.CSS.supports(u.property,u.probe)){s.push(`${u.token}: the fixture probe is invalid for ${u.property}.`);continue}let m=r.getComputedStyle(n).getPropertyValue(u.token).trim();if(!m||!r.CSS.supports(u.property,m)){s.push(`${u.token}: its current value is invalid for the fixture's ${u.property} binding.`);continue}let S=c.filter(y=>y.dataset.adsToken===u.token&&y.dataset.adsProperty===u.property);if(!S.length){s.push(`${u.token} needs a rendered ${u.property} sample, not only a name/value label.`);continue}let _=!1;for(let y of S){let P=[];for(let q=y.parentElement;q&&q!==e;q=q.parentElement)q.tagName==="DETAILS"&&!q.open&&(q.open=!0,P.push(q));let E=n.getAttribute("style"),C=y.getAttribute("style");try{y.style.setProperty("transition","none","important");let q=r.getComputedStyle(y).getPropertyValue(u.property),J=T_(y,r);n.style.setProperty(u.token,u.probe,"important");let L=r.getComputedStyle(y).getPropertyValue(u.property);_=!!(L&&L!==q&&(J||T_(y,r)))}finally{E===null?n.removeAttribute("style"):n.setAttribute("style",E),C===null?y.removeAttribute("style"):y.setAttribute("style",C);for(let q of P)q.open=!1}if(_)break}_?i.push(u):s.push(`${u.token} has no visible ${u.property} sample that responds to its value. Hardcoded copies do not satisfy coverage.`)}return{ok:!s.length,verified:i,diagnostics:s}}var We=new Jl({name:"ADS resource preview",version:"1.0.0"},{},{autoResize:!0}),E_=document.getElementById("root"),bf=document.getElementById("ads-preview-status"),vf=async e=>{if(!We.getHostCapabilities()?.serverResources)throw new Error("This host does not forward MCP resource reads. Open the same preview in the ADS showcase.");try{return await We.readServerResource({uri:e},{timeout:15e3})}catch(t){throw t.code===-32601||t.message==="Method not found"?new Error("This host does not forward MCP resource reads. Open the same preview in the ADS showcase."):t}},Gl=new Bl(vf),Vr,ha,$_,Rf,zf=!1,vo=0,pa={},Be="";function Mt(e,t=!1){bf.textContent=e,bf.hidden=!e,bf.setAttribute("role",t?"alert":"status")}async function Wl(e,t={}){try{We.getHostCapabilities()?.logging&&await We.sendLog({level:e==="error"?"error":"info",logger:"ads-preview",data:{state:e,id:Vr,...t}})}catch{}}function C_(e){pa={...pa,...e,styles:{...pa.styles,...e.styles}},["light","dark"].includes(pa.theme)&&(document.documentElement.dataset.theme=pa.theme)}async function I_(){return JSON.parse((await vf("ads://preview/manifest")).contents.find(e=>typeof e.text=="string").text)}async function wf(e,t){if(e===Vr&&t&&t===ha){Mt(Be,!!Be),await Wl(Be?"error":"ready",Be?{message:Be}:{revision:ha});return}let o=++vo;++Gl.generation,Vr=e,Be="",Mt(""),await Wl("loading");try{let r=await I_();if(t&&r.revision!==t)throw new Error("Preview changed while opening. Select it again to use the current build.");if(o!==vo||!await Gl.mount(r,e,E_)||o!==vo||(ha=r.revision,$_=r.session,await new Promise(i=>requestAnimationFrame(()=>requestAnimationFrame(i))),await document.fonts.ready,o!==vo))return;let s=r.scenarios.find(i=>i.id===e);if(s?.kind==="tokens"){let i=k_(E_,s.samples);if(!i.ok)throw Be=`Token preview verification failed:
|
|
103
|
+
container holding the app. Specify either width or maxWidth, and either height or maxHeight.`),locale:d.string().optional().describe("User's language and region preference in BCP 47 format."),timeZone:d.string().optional().describe("User's timezone in IANA format."),userAgent:d.string().optional().describe("Host application identifier."),platform:d.union([d.literal("web"),d.literal("desktop"),d.literal("mobile")]).optional().describe("Platform type for responsive design decisions."),deviceCapabilities:d.object({touch:d.boolean().optional().describe("Whether the device supports touch input."),hover:d.boolean().optional().describe("Whether the device supports hover interactions.")}).optional().describe("Device input capabilities."),safeAreaInsets:d.object({top:d.number().describe("Top safe area inset in pixels."),right:d.number().describe("Right safe area inset in pixels."),bottom:d.number().describe("Bottom safe area inset in pixels."),left:d.number().describe("Left safe area inset in pixels.")}).optional().describe("Mobile safe area boundaries in pixels.")}).passthrough(),Fv=d.object({method:d.literal("ui/notifications/host-context-changed"),params:x_.describe("Partial context update containing only changed fields.")}),Xx=d.object({method:d.literal("ui/update-model-context"),params:d.object({content:d.array(Fe).optional().describe("Context content blocks (text, image, etc.)."),structuredContent:d.record(d.string(),d.unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.")})}),eP=d.object({method:d.literal("ui/initialize"),params:d.object({appInfo:Ve.describe("App identification (name and version)."),appCapabilities:Zv.describe("Features and capabilities this app provides."),protocolVersion:d.string().describe("Protocol version this app supports.")})}),Jv=d.object({protocolVersion:d.string().describe('Negotiated protocol version string (e.g., "2025-11-21").'),hostInfo:Ve.describe("Host application identification and version."),hostCapabilities:Uv.describe("Features and capabilities provided by the host."),hostContext:x_.describe("Rich context about the host environment.")}).passthrough(),Bv={target:"draft-2020-12"};async function R_(e,t){let o=e["~standard"];if(o.jsonSchema)return o.jsonSchema[t](Bv);throw Error(`Schema (vendor: ${o.vendor}) does not implement Standard JSON Schema (~standard.jsonSchema). Use a library that does (zod v4, ArkType, Valibot) or wrap your schema accordingly.`)}async function w_(e,t,o=""){let r=await e["~standard"].validate(t);if(r.issues){let n=r.issues.map(s=>{let i=s.path?.map(c=>typeof c=="object"?c.key:c).join(".");return i?`${i}: ${s.message}`:s.message}).join("; ");throw Error(o+n)}return r.value}function Wv(e,t){let o={...e,...t};return t.experimental!==void 0&&(o.experimental={...e.experimental,...t.experimental}),t.tools!==void 0&&(o.tools={...e.tools,...t.tools}),o}var Jl=class e extends mf{_appInfo;_appCapabilities;options;_hostCapabilities;_hostInfo;_hostContext;_registeredTools={};_initializedSent=!1;_registeredEvents=new Set;_events=new ff;_methods=new gf;setRequestHandler=(...t)=>{let[o,...r]=z_("request",t)??t;this._methods.claim(o,"setRequestHandler"),super.setRequestHandler.call(this,o,...r)};setNotificationHandler=(...t)=>{let[o,...r]=z_("notification",t)??t;this._methods.claim(o,"setNotificationHandler"),super.setNotificationHandler.call(this,o,...r)};removeRequestHandler=t=>{this._methods.release(t),super.removeRequestHandler(t)};removeNotificationHandler=t=>{this._methods.release(t),super.removeNotificationHandler(t)};replaceRequestHandler=(t,...o)=>{this._methods.replace(t),super.setRequestHandler.call(this,t,...o)};_assertInitialized(t){if(this._initializedSent)return;let o=`[ext-apps] App.${t}() called before connect() completed the ui/initialize handshake. Await app.connect() before calling this method, or move data loading to an ontoolresult handler.`;if(this.options?.strict)throw Error(o);console.warn(`${o}. This will throw in a future release.`)}eventSchemas={toolinput:Ov,toolinputpartial:Nv,toolresult:Hv,toolcancelled:Mv,hostcontextchanged:Fv};static ONE_SHOT_EVENTS=new Set(["toolinput","toolinputpartial","toolresult","toolcancelled"]);_everHadListener=new Set;_assertHandlerTiming(t){if(!e.ONE_SHOT_EVENTS.has(t)||this._everHadListener.has(t)||(this._everHadListener.add(t),!this._initializedSent))return;let o=`[ext-apps] "${String(t)}" handler registered after connect() completed the ui/initialize handshake. The host may have already sent this notification. Register handlers before calling app.connect().`;if(this.options?.strict)throw Error(o);console.warn(o)}setEventHandler(t,o){o&&this._assertHandlerTiming(t),this._ensureEventSlot(t),this._events.setHandler(t,o)}addEventListener(t,o){this._assertHandlerTiming(t),this._ensureEventSlot(t),this._events.addEventListener(t,o)}removeEventListener(t,o){this._events.removeEventListener(t,o)}_ensureEventSlot(t){if(this._registeredEvents.has(t))return;let o=this.eventSchemas[t];if(!o)throw Error(`Unknown event: ${String(t)}`);this.setNotificationHandler(o.shape.method.value,{params:o.shape.params},r=>{let n=r;t==="hostcontextchanged"&&(this._hostContext={...this._hostContext,...n}),this._events.dispatch(t,n)}),this._registeredEvents.add(t)}getEventHandler(t){return this._events.getHandler(t)}warnIfRequestHandlerReplaced(t,o,r){o&&r&&console.warn(`[MCP Apps] ${t} handler replaced. Previous handler will no longer be called.`)}constructor(t,o={},r={autoResize:!0}){super(r),this._appInfo=t,this._appCapabilities=o,this.options=r,this._methods.replace("notifications/cancelled"),this._methods.replace("notifications/progress"),!r.allowUnsafeEval&&d.config({jitless:!0}),this.replaceRequestHandler("ping",n=>(console.log("Received ping:",n.params),{})),this.setEventHandler("hostcontextchanged",void 0)}buildContext(t){return t}registerAppCapabilities(t){if(this.transport)throw Error("Cannot register capabilities after transport is established");this._appCapabilities=Wv(this._appCapabilities,t)}registerTool(t,o,r){if(this._registeredTools[t])throw Error(`Tool ${t} is already registered`);let n=this,s=()=>{n._initializedSent&&n._appCapabilities.tools?.listChanged&&n.sendToolListChanged()},i=o.inputSchema!==void 0,c={title:o.title,description:o.description,inputSchema:o.inputSchema,outputSchema:o.outputSchema,annotations:o.annotations,_meta:o._meta,enabled:!0,enable(){this.enabled=!0,s()},disable(){this.enabled=!1,s()},update(l){Object.assign(this,l),s()},remove(){n._registeredTools[t]===c&&(delete n._registeredTools[t],s())},handler:async(l,u)=>{if(!c.enabled)throw Error(`Tool ${t} is disabled`);let m;if(i){let S=c.inputSchema,_=S?await w_(S,l??{},`Invalid input for tool ${t}: `):l??{};m=await r(_,u)}else m=await r(u);return c.outputSchema&&!m.isError&&(m.structuredContent=await w_(c.outputSchema,m.structuredContent,`Invalid output for tool ${t}: `)),m}};return this._registeredTools[t]=c,!this._appCapabilities.tools&&!this.transport&&this.registerAppCapabilities({tools:{listChanged:!0}}),this.ensureToolHandlersInitialized(),s(),c}_toolHandlersInitialized=!1;ensureToolHandlersInitialized(){this._toolHandlersInitialized||(this._toolHandlersInitialized=!0,this.oncalltool=async(t,o)=>{let r=this._registeredTools[t.name];if(!r)throw Error(`Tool ${t.name} not found`);return r.handler(t.arguments,o)},this.onlisttools=async(t,o)=>({tools:await Promise.all(Object.entries(this._registeredTools).filter(([r,n])=>n.enabled).map(async([r,n])=>{let s={name:r,title:n.title,description:n.description,inputSchema:n.inputSchema?await R_(n.inputSchema,"input"):{type:"object",properties:{}}};return n.outputSchema&&(s.outputSchema=await R_(n.outputSchema,"output")),n.annotations&&(s.annotations=n.annotations),n._meta&&(s._meta=n._meta),s}))}))}async sendToolListChanged(t={}){this._assertInitialized("sendToolListChanged"),await this.notification({method:"notifications/tools/list_changed",params:t})}getHostCapabilities(){return this._hostCapabilities}getHostVersion(){return this._hostInfo}getHostContext(){return this._hostContext}get ontoolinput(){return this.getEventHandler("toolinput")}set ontoolinput(t){this.setEventHandler("toolinput",t)}get ontoolinputpartial(){return this.getEventHandler("toolinputpartial")}set ontoolinputpartial(t){this.setEventHandler("toolinputpartial",t)}get ontoolresult(){return this.getEventHandler("toolresult")}set ontoolresult(t){this.setEventHandler("toolresult",t)}get ontoolcancelled(){return this.getEventHandler("toolcancelled")}set ontoolcancelled(t){this.setEventHandler("toolcancelled",t)}get onhostcontextchanged(){return this.getEventHandler("hostcontextchanged")}set onhostcontextchanged(t){this.setEventHandler("hostcontextchanged",t)}_onteardown;get onteardown(){return this._onteardown}set onteardown(t){this.warnIfRequestHandlerReplaced("onteardown",this._onteardown,t),this._onteardown=t,this.replaceRequestHandler("ui/resource-teardown",{params:jv.shape.params,result:Lv},(o,r)=>{if(!this._onteardown)throw Error("No onteardown handler set");return this._onteardown(o,r)})}_oncalltool;get oncalltool(){return this._oncalltool}set oncalltool(t){this.warnIfRequestHandlerReplaced("oncalltool",this._oncalltool,t),this._oncalltool=t,this.replaceRequestHandler("tools/call",(o,r)=>{if(!this._oncalltool)throw Error("No oncalltool handler set");return this._oncalltool(o.params,r)})}_onlisttools;get onlisttools(){return this._onlisttools}set onlisttools(t){this.warnIfRequestHandlerReplaced("onlisttools",this._onlisttools,t),this._onlisttools=t,this.replaceRequestHandler("tools/list",(o,r)=>{if(!this._onlisttools)throw Error("No onlisttools handler set");return this._onlisttools(o.params,r)})}assertCapabilityForMethod(t){switch(t){case"sampling/createMessage":if(!this._hostCapabilities?.sampling)throw Error(`Host does not support sampling (required for ${t})`);break}}assertRequestHandlerCapability(t){switch(t){case"tools/call":case"tools/list":if(!this._appCapabilities.tools)throw Error(`Client does not support tool capability (required for ${t})`);return;default:return}}assertNotificationCapability(t){}async callServerTool(t,o){if(this._assertInitialized("callServerTool"),typeof t=="string")throw Error(`callServerTool() expects an object as its first argument, but received a string ("${t}"). Did you mean: callServerTool({ name: "${t}", arguments: { ... } })?`);return await this.request({method:"tools/call",params:t},{onprogress:()=>{},resetTimeoutOnProgress:!0,...o})}async readServerResource(t,o){return this._assertInitialized("readServerResource"),await this.request({method:"resources/read",params:t},o)}async listServerResources(t,o){return this._assertInitialized("listServerResources"),await this.request({method:"resources/list",params:t},o)}async createSamplingMessage(t,o){return this._assertInitialized("createSamplingMessage"),await this.request({method:"sampling/createMessage",params:t},o)}sendMessage(t,o){return this._assertInitialized("sendMessage"),this.request({method:"ui/message",params:t},Iv,o)}sendLog(t){return this.notification({method:"notifications/message",params:t})}updateModelContext(t,o){return this._assertInitialized("updateModelContext"),this.request({method:"ui/update-model-context",params:t},Ct,o)}openLink(t,o){return this._assertInitialized("openLink"),this.request({method:"ui/open-link",params:t},$v,o)}sendOpenLink=this.openLink;downloadFile(t,o){return this._assertInitialized("downloadFile"),this.request({method:"ui/download-file",params:t},Cv,o)}requestTeardown(t={}){return this.notification({method:"ui/notifications/request-teardown",params:t})}requestDisplayMode(t,o){return this._assertInitialized("requestDisplayMode"),this.request({method:"ui/request-display-mode",params:t},Dv,o)}sendSizeChanged(t){return this.notification({method:"ui/notifications/size-changed",params:t})}setupSizeChangedNotifications(){let t=!1,o=0,r=0,n=()=>{t||(t=!0,requestAnimationFrame(()=>{t=!1;let i=document.documentElement,c=i.style.height;i.style.height="max-content";let l=Math.ceil(i.getBoundingClientRect().height);i.style.height=c;let u=Math.ceil(window.innerWidth);(u!==o||l!==r)&&(o=u,r=l,this.sendSizeChanged({width:u,height:l}))}))};n();let s=new ResizeObserver(n);return s.observe(document.documentElement),s.observe(document.body),()=>s.disconnect()}async connect(t=new Sf(window.parent,window.parent),o){if(this.transport)throw Error("App is already connected. Call close() before connecting again.");this._initializedSent=!1;try{await super.connect(t);let r=await this.request({method:"ui/initialize",params:{appCapabilities:this._appCapabilities,appInfo:this._appInfo,protocolVersion:xv}},Jv,o);if(r===void 0)throw Error(`Server sent invalid initialize result: ${r}`);this._hostCapabilities=r.hostCapabilities,this._hostInfo=r.hostInfo,this._hostContext=r.hostContext,await this.notification({method:"ui/notifications/initialized"}),this._initializedSent=!0,this.options?.autoResize&&this.setupSizeChangedNotifications()}catch(r){throw this.close(),r}}};var Bl=class{constructor(t){this.read=t,this.records=new Map,this.bytes=new Map,this.urls=new Map,this.styles=new Map,this.styleReady=new Map,this.revisions=new Set,this.importing=Promise.resolve(),this.generation=0,this.closed=!1,globalThis.__dsPreviewImport=o=>this.importModule(o)}register(t){if(t.schemaVersion!==1||!Array.isArray(t.scenarios)||!t.assets||typeof t.revision!="string")throw new Error("Unsupported preview manifest. Rebuild previews with the installed ADS version.");if(this.revisions.add(t.revision),this.revisions.size>20)throw Object.assign(new Error("Reopen the preview to release modules retained across 20 build revisions."),{code:"ADS_PREVIEW_REOPEN"});for(let[o,r]of Object.entries(t.assets)){if(!/^ads:\/\/assets\/[a-f0-9]{64}\.[a-z0-9]+$/.test(o)||!/^sha256:[a-f0-9]{64}$/.test(r.digest)||!["imports","dynamicImports","styles","references"].every(n=>Array.isArray(r[n])&&r[n].every(s=>Object.hasOwn(t.assets,s))))throw new Error("Invalid preview dependency graph.");if(this.records.has(o)&&this.records.get(o).digest!==r.digest)throw new Error("An immutable preview resource changed its content.");this.records.set(o,r)}}async resource(t){if(!this.bytes.has(t)){let o=(async()=>{let r=this.records.get(t);if(!r)throw new Error(`Unknown preview dependency: ${t}`);let n=await this.read(t);if(this.closed)throw new Error("The preview App was closed.");let s=n.contents.find(u=>u.uri===t);if(!s)throw new Error(`Missing preview dependency: ${t}`);let i=typeof s.text=="string"?new TextEncoder().encode(s.text):Uint8Array.from(atob(s.blob),u=>u.charCodeAt(0)),c=await crypto.subtle.digest("SHA-256",i),l="sha256:"+[...new Uint8Array(c)].map(u=>u.toString(16).padStart(2,"0")).join("");if(i.length!==r.size||l!==r.digest)throw new Error("Preview resource integrity check failed. Rebuild and reopen the preview.");return i})();this.bytes.set(t,o),o.catch(()=>this.bytes.delete(t))}return this.bytes.get(t)}closure(t){let o=[],r=new Set,n=s=>{if(r.has(s))return;r.add(s);let i=this.records.get(s);if(!i)throw new Error(`Missing preview dependency metadata: ${s}`);for(let c of[...i.imports,...i.styles,...i.references])n(c);o.push(s)};return n(t),o}async materialize(t){let o=this.closure(t);await Promise.all(o.map(n=>this.resource(n)));let r={};for(let n of o){if(this.closed)throw new Error("The preview App was closed.");if(this.urls.has(n))continue;let s=this.records.get(n),i=await this.resource(n);if(s.kind==="module"||s.mimeType==="text/css"){let l=new TextDecoder().decode(i);for(let u of s.references){let m=this.urls.get(u);if(!m)throw new Error("Unsupported cyclic asset reference.");l=l.replaceAll(u,m)}i=l}let c=URL.createObjectURL(new Blob([i],{type:s.mimeType}));this.urls.set(n,c),s.kind==="module"&&(r[n]=c)}if(Object.keys(r).length){let n=document.createElement("script");n.type="importmap",n.textContent=JSON.stringify({imports:r}),document.head.append(n)}return o}async importModule(t){let o=this.importing.then(()=>this.materialize(t));this.importing=o.catch(()=>{});let r=await o;for(let n of r){if(this.records.get(n).mimeType!=="text/css")continue;if(this.styles.has(n)){await this.styleReady.get(n);continue}let i=document.createElement("link");i.rel="stylesheet",i.href=this.urls.get(n),this.styles.set(n,i);let c=new Promise((l,u)=>{i.onload=l,i.onerror=()=>u(new Error("The host CSP blocked a preview stylesheet."))});this.styleReady.set(n,c),document.head.append(i);try{await c}catch(l){throw i.remove(),this.styles.delete(n),this.styleReady.delete(n),l}}return import(t)}async mount(t,o,r){let n=++this.generation;this.register(t);let s=t.scenarios.find(l=>l.id===o);if(!s)throw new Error("The selected scenario is no longer registered.");let i=await this.importModule(s.module);if(n!==this.generation||(await this.unmount?.(),n!==this.generation||this.closed))return!1;r.replaceChildren();let c=new Set(this.closure(s.module));for(let[l,u]of this.styles)c.has(l)||(u.remove(),this.styles.delete(l),this.styleReady.delete(l));for(let l of this.closure(s.module))this.styles.has(l)&&document.head.append(this.styles.get(l));if(typeof i.mount!="function")throw new Error("The compiled scenario has no mount adapter.");if(this.unmount=i.mount(r),typeof this.unmount!="function")throw new Error("The scenario mount adapter must return an unmount callback.");return!0}async dispose(){if(!this.closed){this.closed=!0,++this.generation,await this.unmount?.();for(let t of this.styles.values())t.remove();for(let t of this.urls.values())URL.revokeObjectURL(t);this.styles.clear(),this.styleReady.clear(),this.urls.clear(),this.bytes.clear(),this.records.clear(),delete globalThis.__dsPreviewImport}}};function P_(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&typeof t=="object"&&typeof t.token=="string"&&/^--[\w-]+$/.test(t.token)&&typeof t.property=="string"&&/^-?[a-z][a-z0-9-]*$/.test(t.property)&&typeof t.probe=="string"&&t.probe.trim().length>0)&&new Set(e.map(t=>`${t.token}:${t.property}`)).size===e.length}function T_(e,t){let o=t.getComputedStyle(e),r=e.getBoundingClientRect();if(o.display==="none"||o.visibility!=="visible"||!e.getClientRects().length||!(r.width||r.height))return!1;for(let n=e;n;n=n.parentElement)if(Number(t.getComputedStyle(n).opacity)===0)return!1;return!0}function k_(e,t){if(!P_(t))return{ok:!1,diagnostics:["Token preview needs explicit { token, property, probe } samples from the project fixture. Rebuild with the current compiler."]};let o=e.ownerDocument,r=o.defaultView,n=o.documentElement,s=[],i=[],c=[...e.querySelectorAll("[data-ads-token], [data-ads-property]")],l=new Set(t.map(u=>`${u.token}:${u.property}`));for(let u of c)l.has(`${u.dataset.adsToken}:${u.dataset.adsProperty}`)||s.push(`Undeclared rendered token sample ${u.dataset.adsToken}:${u.dataset.adsProperty}.`);for(let u of t){if(!r.CSS.supports(u.property,u.probe)){s.push(`${u.token}: the fixture probe is invalid for ${u.property}.`);continue}let m=r.getComputedStyle(n).getPropertyValue(u.token).trim();if(!m||!r.CSS.supports(u.property,m)){s.push(`${u.token}: its current value is invalid for the fixture's ${u.property} binding.`);continue}let S=c.filter(y=>y.dataset.adsToken===u.token&&y.dataset.adsProperty===u.property);if(!S.length){s.push(`${u.token} needs a rendered ${u.property} sample, not only a name/value label.`);continue}let _=!1;for(let y of S){let P=[];for(let q=y.parentElement;q&&q!==e;q=q.parentElement)q.tagName==="DETAILS"&&!q.open&&(q.open=!0,P.push(q));let E=n.getAttribute("style"),C=y.getAttribute("style");try{y.style.setProperty("transition","none","important");let q=r.getComputedStyle(y).getPropertyValue(u.property),J=T_(y,r);n.style.setProperty(u.token,u.probe,"important");let L=r.getComputedStyle(y).getPropertyValue(u.property);_=!!(L&&L!==q&&(J||T_(y,r)))}finally{E===null?n.removeAttribute("style"):n.setAttribute("style",E),C===null?y.removeAttribute("style"):y.setAttribute("style",C);for(let q of P)q.open=!1}if(_)break}_?i.push(u):s.push(`${u.token} has no visible ${u.property} sample that responds to its value. Hardcoded copies do not satisfy coverage.`)}return{ok:!s.length,verified:i,diagnostics:s}}var We=new Jl({name:"ADS resource preview",version:"1.0.0"},{},{autoResize:!0}),E_=document.getElementById("root"),bf=document.getElementById("ads-preview-status"),vf=async e=>{if(!We.getHostCapabilities()?.serverResources)throw new Error("This host does not forward MCP resource reads. Open the same preview in the ADS showcase.");try{return await We.readServerResource({uri:e},{timeout:15e3})}catch(t){throw t.code===-32601||t.message==="Method not found"?new Error("This host does not forward MCP resource reads. Open the same preview in the ADS showcase."):t}},Gl=new Bl(vf),Vr,ha,$_,Rf,zf=!1,vo=0,pa={},Be="";function Mt(e,t=!1){bf.textContent=e,bf.hidden=!e,bf.setAttribute("role",t?"alert":"status")}async function Wl(e,t={}){try{We.getHostCapabilities()?.logging&&await We.sendLog({level:e==="error"?"error":"info",logger:"ads-preview",data:{state:e,id:Vr,...t}})}catch{}}function C_(e){pa={...pa,...e,styles:{...pa.styles,...e.styles}},["light","dark"].includes(pa.theme)&&(document.documentElement.dataset.theme=pa.theme)}async function I_(){return JSON.parse((await vf("ads://preview/manifest")).contents.find(e=>typeof e.text=="string").text)}async function wf(e,t){if(e===Vr&&t&&t===ha){Mt(Be,!!Be),await Wl(Be?"error":"ready",Be?{message:Be}:{revision:ha});return}let o=++vo;++Gl.generation,Vr=e,document.documentElement.dataset.adsScenario=e,document.documentElement.dataset.adsPreviewState="loading",Be="",Mt(""),await Wl("loading");try{let r=await I_();if(t&&r.revision!==t)throw new Error("Preview changed while opening. Select it again to use the current build.");if(o!==vo||!await Gl.mount(r,e,E_)||o!==vo||(ha=r.revision,$_=r.session,await new Promise(i=>requestAnimationFrame(()=>requestAnimationFrame(i))),await document.fonts.ready,o!==vo))return;let s=r.scenarios.find(i=>i.id===e);if(s?.kind==="tokens"){let i=k_(E_,s.samples);if(!i.ok)throw Be=`Token preview verification failed:
|
|
104
104
|
${i.diagnostics.slice(0,20).join(`
|
|
105
|
-
`)}`,new Error(Be)}o===vo&&(Mt(""),await Wl("ready",{revision:ha}))}catch(r){o===vo&&(Mt(r.message,!0),await Wl("error",{message:r.message,...r.code?{code:r.code}:{}}))}}async function Gv(){if(!(!Vr||zf||document.visibilityState==="hidden")){zf=!0;try{let t=JSON.parse((await vf("ads://project/build")).contents.find(o=>typeof o.text=="string").text).previews.find(o=>o.id===Vr);if(!t||!t.current){let o=t?.diagnostics?.[0]?.message;Mt(o?`Build failed. Showing the previous preview.
|
|
105
|
+
`)}`,new Error(Be)}o===vo&&(document.documentElement.dataset.adsPreviewState="ready",Mt(""),await Wl("ready",{revision:ha}))}catch(r){o===vo&&(document.documentElement.dataset.adsPreviewState="error",Mt(r.message,!0),await Wl("error",{message:r.message,...r.code?{code:r.code}:{}}))}}async function Gv(){if(!(!Vr||zf||document.visibilityState==="hidden")){zf=!0;try{let t=JSON.parse((await vf("ads://project/build")).contents.find(o=>typeof o.text=="string").text).previews.find(o=>o.id===Vr);if(!t||!t.current){let o=t?.diagnostics?.[0]?.message;Mt(o?`Build failed. Showing the previous preview.
|
|
106
106
|
${o}`:"Rebuilding. This is the previous preview.",!!o)}else{let o=await I_();o.revision!==ha||o.session!==$_?await wf(Vr):Mt(Be,!!Be)}}catch(e){Mt(`Preview freshness unavailable: ${e.message}`,!0)}finally{zf=!1}}}We.ontoolresult=e=>{let t=e.structuredContent;t?.scenario?.id&&wf(t.scenario.id,t.manifestRevision)};We.onhostcontextchanged=C_;We.onteardown=async()=>(++vo,clearInterval(Rf),await Gl.dispose(),{});try{if(await We.connect(),C_(We.getHostContext()??{}),!We.getHostCapabilities()?.serverResources)throw new Error("This host does not forward MCP resource reads. Open the same preview in the ADS showcase.");Rf=setInterval(()=>{Gv()},2e3);let e=document.getElementById("ads-preview-selection");e&&wf(JSON.parse(e.textContent).id)}catch(e){Mt(e.message,!0)}window.addEventListener("pagehide",()=>{clearInterval(Rf),Gl.dispose()},{once:!0});
|
|
107
107
|
/*! Bundled license information:
|
|
108
108
|
|
package/dist/mcp/prompts.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const reasoning = `ADS is development tooling. The project owns its components, patterns, token values and branding.
|
|
2
|
-
Start with ads_status and use its projectRoot, workflow and project commands; the MCP workspace may be nested inside the client repository. If ADS tools are not exposed, read ads://project/guide then ads://project/status. Find existing public UI with ads_catalog and load one relevant ADS workflow via ads_skills/ads_read_skill. UI implementation/refinement uses ads-designer; library adaptation ads-
|
|
2
|
+
Start with ads_status and use its projectRoot, workflow and project commands; the MCP workspace may be nested inside the client repository. If ADS tools are not exposed, read ads://project/guide then ads://project/status. Find existing public UI with ads_catalog and load one relevant ADS workflow via ads_skills/ads_read_skill. UI implementation/refinement uses ads-designer; library adaptation ads-migrate; ADS transfer ads-import; motion ads-motion; stress testing ads-break-ui. Domain-model workflows are separate. Inspect the relevant public API, local guide, token definitions and real showcase fixture before proposing changes. Keep source/instruction discovery scoped to the target project, ancestry and selected external sources; broad scans of /mnt or home are not needed to discover this ADS.
|
|
3
3
|
When ads_status.mutations.enabled, discover one owner with ads_units, read relevant ranges with ads_read_file and send only a Git unified diff through ads_apply_patch({unit,patch,dryRun}). A unit includes its own scenarios/fixtures; imported peers remain separate. tokens is the token foundation unit. Only that owner's public re-exports may change in the shared entry; preserve unrelated statements including export {};. Token manifests list companionFiles: include required foundation import changes only for canonical token files created/deleted in the same patch, preserving other imports/comments and canonical order. Use dryRun to review validation. Rejected patches leave source unchanged; fix diagnostics rather than bypassing checks with direct writes. Shared globals use foundation; guides use documentation; assets use discovered assets/* units. Intentional configuration, registered project guards/builders and rule exceptions use configuration, which validates the proposed settings and refreshes its compiler. Keep mandatory ADS gates. For large/binary diffs, pass patchFile pointing to .ds/patches/<name>.patch rather than loading bytes into context; Git binary patches require installed Git. When editing is disabled, use local editing tools.
|
|
4
4
|
Reason through Data (design-token values, semantic roles and relationships), UX (structure, behavior, accessibility, states and layout), and Skin (token-backed identity and visual states). Business data is a separate application-owned input, supplied through typed props or injected callbacks/services. The project uses Linaria extraction for owned styles; MCP adds no production runtime.
|
|
5
5
|
Choose an existing public component or pattern first. Keep application data/routing/effects in the application and fixture data/state beside its scenario. Change presentation in its owning ADS implementation, then demonstrate the same public API in the showcase. Put demo-only sizing and framing in a public review/layout pattern; add component props for deliberate runtime API needs and preserve required behavior. Do not create a widget-only replica or override component internals.
|
|
6
6
|
For token source inspection, call ads_tokens with a focused query. For token samples, components, patterns and composition, use ads_scenarios to select a path-derived id and invoke ads_show_scenario. Showcase and MCP mount that exact entry and its colocated fixture; no page initialization is required. The showcase is a minimal tool-owned shell plus an MCP client and Apps host. Its menus come from tools; it invokes the same entry tools and refreshes the active scenario through notifications. The reusable App loads framework runtime, foundation CSS, fonts and selected modules via MCP resources inside its sandbox. Keep project execution and styles out of the outer host; preserve mount/unmount cleanup and lazy dependencies. Use the existing ads_status showcase URL, or ads showcase when no MCP runtime is connected. Projects supply scenarios/fixtures and the compiler, not browser page files or another shell. Tool metadata selects an MCP App; a resources/read of HTML alone is not proof of rendered UI. If the host has no Apps view, give the configured showcase URL and use text/resources.
|
|
7
7
|
Check ads_status.previewWatch before launching a separate preview builder. A configured watcher is managed by ads mcp. Check ads_status.build or ads://project/build after changes: running does not mean ready, and unreported freshness is not evidence of current source. Reported preview failures include structured diagnostics; fix the owning source and wait for a successful rebuild, then invoke the preview tool again. Notifications may not reach the agent, so read status explicitly. Build revisions identify reported compilation attempts, not proof of runtime/visual correctness. Do not invent replacement UI to bypass a failed preview.
|
|
8
8
|
Skills: use ads_skills to select a workflow and read its SKILL.md with ads_read_skill. Resolve relative supporting files from that skill URI. Reading instructions does not prove native skill activation or authorize unrelated actions.
|
|
9
|
-
Ask for missing intent only when it changes the outcome. State the proposed behavior, states and difficult content. Preserve lazy loading, workers, caches, cancellation, reduced motion, focus and keyboard behavior. Run ads_check plus the project's registered lint, typecheck, build and relevant tests; inspect the actual browser/rendered app at narrow and wide sizes in both themes. Static success does not establish visual or interaction parity.`;
|
|
9
|
+
Ask for missing intent only when it changes the outcome. State the proposed behavior, states and difficult content. Preserve lazy loading, workers, caches, cancellation, reduced motion, focus and keyboard behavior. For controllers and hooks, read ads://guides/behaviors. Discover guarantees/checks with ads_behaviors and run ads_verify; read current execution evidence. Keep behavior.json and checks development-only. Use the configured framework and declared dependencies, not MCP host globals. Preserve covers for rendered UI; exercises links behavioral APIs to demonstrations, not passing guarantees. Run ads_check plus the project's registered lint, typecheck, build and relevant tests; inspect the actual browser/rendered app at narrow and wide sizes in both themes. Static success does not establish visual or interaction parity.`;
|
|
10
10
|
|
|
11
11
|
export function promptDefinitions(skills) {
|
|
12
12
|
const prompts = [
|