feat: release design system engine, studio and component contracts

This commit is contained in:
Clintchiz committed 2026-10-19 13:09:03 +05:30
1 parent ff1065fb27
commit 3943b946d6
693 files changed
+175546 -3894

No files matched your search

+138
View File
@@ -0,0 +1,138 @@
import type { McpTool } from "./index.ts";
const string = { type: "string" };
const fields: Record<string, Record<string, unknown>> = {
package: { notes: string },
upgrade_plan: { source: string },
upgrade: { source: string },
inspect: {},
capabilities: {},
context: { components: { type: "array", items: string, maxItems: 12 } },
create: { source: string },
propose: {
source: string,
patches: {
type: "array",
maxItems: 48,
items: {
type: "object",
properties: { path: string, value: {} },
required: ["path", "value"],
additionalProperties: false,
},
},
},
locks: { locks: { type: "array", items: string, maxItems: 128 } },
page: {
page: {
type: "object",
properties: {
id: string,
title: string,
components: {
type: "array",
minItems: 1,
maxItems: 12,
items: {
type: "object",
properties: { component: string, props: { type: "object" } },
required: ["component"],
additionalProperties: false,
},
},
},
required: ["id", "title", "components"],
additionalProperties: false,
},
},
validate: {},
preview: { pageId: string },
diff: {},
apply: { baseApplicationRevision: string },
revert: {
target: { type: "string", enum: ["draft", "checkpoint", "application"] },
baseApplicationRevision: string,
},
export: {},
conformance: {
source: string,
exceptions: {
type: "array",
maxItems: 64,
items: {
type: "object",
properties: { code: string, path: string, reason: string },
required: ["code", "path", "reason"],
additionalProperties: false,
},
},
},
};
const descriptions: Record<string, string> = {
package:
"Export a verified self-contained design package with a content digest. No filesystem or draft mutation.",
upgrade_plan:
"Review a shared package upgrade, including integrity, identity, locks and migration diagnostics, without changing the draft.",
upgrade:
"Adopt a verified shared design package as a recoverable history entry; draft revision and decision locks are rechecked.",
inspect: "Inspect recoverable source, valid preview, locks, pages and revisions.",
capabilities: "List contracted components, operations and explicit integration limits.",
context: "Get resolved tokens, selected component APIs, parts, constraints and generation rules.",
create:
"Create a recoverable design draft from optional canonical source; invalid source remains recoverable.",
propose:
"Propose canonical source or token/recipe JSON-pointer patches respecting decision locks.",
locks: "Set explicit decision locks for future edits.",
page: "Save a bounded literal page specification composed of contracted components; returns generated .wrn source.",
validate: "Validate draft and saved page specifications.",
preview:
"Render a saved page through trusted shipped components. Returns CSP-protected static HTML.",
diff: "Review design changes against the applied baseline and affected page ids.",
apply:
"Save an application design bundle after checking draft and application revisions. Explicit app integration still required.",
revert:
"Undo a draft edit, swap the previous draft checkpoint, or revert the application bundle pointer.",
export:
"Export raw draft recovery data, valid design artifacts and generated page sources without writing routes.",
conformance:
"Statically check .wrn source for unknown APIs, invented variants and token bypasses. Warnings need exact reviewed exceptions.",
};
export const DESIGN_WRITES = new Set([
"create",
"propose",
"locks",
"page",
"apply",
"revert",
"upgrade",
]);
export function designTools(writable: boolean): McpTool[] {
return Object.entries(fields)
.filter(([name]) => writable || !DESIGN_WRITES.has(name))
.map(([name, properties]) => ({
name: "wrnexus_design_" + name,
description: descriptions[name]!,
inputSchema: {
type: "object",
properties: {
...properties,
...(["context", "preview", "export", "apply"].includes(name)
? { mode: string, density: string }
: {}),
...(DESIGN_WRITES.has(name) ? { baseRevision: string } : {}),
},
required: [
...(DESIGN_WRITES.has(name) ? ["baseRevision"] : []),
...({
upgrade_plan: ["source"],
upgrade: ["source"],
page: ["page"],
preview: ["pageId"],
locks: ["locks"],
apply: ["baseApplicationRevision"],
conformance: ["source"],
}[name] ?? []),
],
additionalProperties: false,
},
}));
}
+29 -2
View File
@@ -1,3 +1,4 @@
import { designTools } from "./design-tools.ts";
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { extname, join, relative, resolve } from "node:path";
@@ -8,9 +9,13 @@ export interface McpTool {
type: "object";
properties?: Record<string, unknown>;
additionalProperties?: boolean;
required?: string[];
};
}
export interface McpServerOptions {
/** Opt-in local workspace design operations. */
design?: boolean;
designWrite?: boolean;
maxFiles?: number;
maxFileBytes?: number;
fetch?: typeof fetch;
@@ -138,6 +143,8 @@ export function createFrameworkMcpServer(
options: McpServerOptions = {},
): McpServer {
const root = resolve(appRoot);
const toolSet = [...TOOLS, ...(options.design ? designTools(options.designWrite === true) : [])];
let design: import("@wrnexus/design-studio/agents").DesignAgentService | undefined;
const limits = {
maxFiles: options.maxFiles ?? 200,
maxFileBytes: options.maxFileBytes ?? 128 * 1024,
@@ -145,6 +152,26 @@ export function createFrameworkMcpServer(
const files = (directories: string[], extensions?: string[]) =>
walk(root, directories, limits, extensions);
const call = async (name: string, args: Record<string, unknown> = {}): Promise<unknown> => {
if (name.startsWith("wrnexus_design_") && toolSet.some((tool) => tool.name === name)) {
if (!design) {
const { DesignAgentService } = await import("@wrnexus/design-studio/agents").catch(
(error: unknown) => {
if (
error &&
typeof error === "object" &&
"code" in error &&
["MODULE_NOT_FOUND", "ERR_MODULE_NOT_FOUND"].includes(String(error.code))
)
throw Error(
"WRN-MCP-DESIGN-INSTALL: install a compatible @wrnexus/design-studio package to enable design tools.",
);
throw error;
},
);
design = new DesignAgentService(root, options.designWrite === true);
}
return design.call(name.slice("wrnexus_design_".length), args);
}
if (name === "wrnexus_routes")
return files(["app/pages", "app/api"], [".wrn", ".ts", ".tsx", ".js", ".jsx"])
.map(({ file }) => ({
@@ -219,7 +246,7 @@ export function createFrameworkMcpServer(
throw new Error(`WRN-MCP-TOOL: unknown tool '${name}'.`);
};
return {
tools: () => TOOLS.map((tool) => ({ ...tool })),
tools: () => toolSet.map((tool) => ({ ...tool })),
call,
async handle(message) {
if (!message || typeof message !== "object")
@@ -237,7 +264,7 @@ export function createFrameworkMcpServer(
},
};
if (request.method === "tools/list")
return { jsonrpc: "2.0", id: request.id ?? null, result: { tools: TOOLS } };
return { jsonrpc: "2.0", id: request.id ?? null, result: { tools: toolSet } };
if (request.method === "tools/call") {
try {
const value = await call(
+10 -4
View File
@@ -1,9 +1,12 @@
#!/usr/bin/env bun
import { createInterface } from "node:readline";
import { createFrameworkMcpServer } from "./index.ts";
import { createFrameworkMcpServer, type McpServerOptions } from "./index.ts";
export async function runMcpStdio(root = process.cwd()): Promise<void> {
const server = createFrameworkMcpServer(root);
export async function runMcpStdio(
root = process.cwd(),
options: McpServerOptions = {},
): Promise<void> {
const server = createFrameworkMcpServer(root, options);
const lines = createInterface({ input: process.stdin, terminal: false });
for await (const line of lines) {
if (!line.trim()) continue;
@@ -23,5 +26,8 @@ export async function runMcpStdio(root = process.cwd()): Promise<void> {
if (import.meta.main) {
const root = process.argv.find((value) => value.startsWith("--root="))?.slice(7) ?? process.cwd();
await runMcpStdio(root);
await runMcpStdio(root, {
design: process.argv.includes("--design") || process.argv.includes("--design-write"),
designWrite: process.argv.includes("--design-write"),
});
}