@fusedashlabs/ui9000-workspace
Version:
UI9000 workspace MCP. One tool, show_workspace, draws a chart from your table. Set TYPESAFE_API_KEY to let Jev choose the chart.
49 lines (48 loc) • 1.74 kB
JavaScript
import { validateSpec } from '../validate/validate-spec.js';
/**
* Validate then mount. Hostile specs never reach load() or the host.
* Mount is a catalog loader on a known id — not host markup or element registry APIs.
*/
export async function interpretWorkspace(toolResult, catalog, load, host) {
const raw = extractSpec(toolResult);
if (raw === undefined) {
return {
mounted: false,
code: 'invalid_result',
reason: 'tool result has no workspace spec',
};
}
const validated = validateSpec(raw, catalog);
if (!validated.ok) {
return { mounted: false, code: validated.code, reason: validated.reason };
}
const mounter = await load(validated.spec.component);
if (!mounter || typeof mounter.mount !== 'function') {
return {
mounted: false,
code: 'unknown_component',
reason: `no mounter registered for "${validated.spec.component}"`,
};
}
host.replaceChildren();
await mounter.mount(host, validated.spec);
return { mounted: true, spec: validated.spec };
}
function extractSpec(toolResult) {
if (!isPlain(toolResult))
return undefined;
if ('spec' in toolResult)
return toolResult.spec;
if (isPlain(toolResult.structuredContent) && 'spec' in toolResult.structuredContent) {
return toolResult.structuredContent.spec;
}
if (isPlain(toolResult._meta) && 'spec' in toolResult._meta) {
return toolResult._meta.spec;
}
if (typeof toolResult.component === 'string')
return toolResult;
return undefined;
}
function isPlain(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}