@reqvire-org/ads 0.0.0-stage → 0.2.9
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 +21 -0
- package/README.md +284 -2
- package/dist/assets.mjs +52 -0
- package/dist/bootstrap-ds/ADS.md +203 -0
- package/dist/bootstrap-ds/README.md +98 -0
- package/dist/bootstrap-ds/biome.css.json +21 -0
- package/dist/bootstrap-ds/design-system/assets/brand/README.md +28 -0
- package/dist/bootstrap-ds/design-system/assets/fonts/.gitkeep +0 -0
- package/dist/bootstrap-ds/design-system/components/.gitkeep +0 -0
- package/dist/bootstrap-ds/design-system/composition/.gitkeep +0 -0
- package/dist/bootstrap-ds/design-system/index.ts +5 -0
- package/dist/bootstrap-ds/design-system/patterns/.gitkeep +0 -0
- package/dist/bootstrap-ds/design-system/showcase/mcp/index.html +1 -0
- package/dist/bootstrap-ds/design-system/showcase/mcp/main.tsx +8 -0
- package/dist/bootstrap-ds/design-system/styles.css +5 -0
- package/dist/bootstrap-ds/design-system/tokens/Foundation.fixture.ts +47 -0
- package/dist/bootstrap-ds/design-system/tokens/Foundation.scenario.tsx +14 -0
- package/dist/bootstrap-ds/design-system/tokens/base.css +27 -0
- package/dist/bootstrap-ds/design-system/tokens/colors.css +29 -0
- package/dist/bootstrap-ds/design-system/tokens/elevation.css +15 -0
- package/dist/bootstrap-ds/design-system/tokens/spacing.css +15 -0
- package/dist/bootstrap-ds/design-system/tokens/typography.css +13 -0
- package/dist/bootstrap-ds/ds.config.json +13 -0
- package/dist/bootstrap-ds/gitignore.template +8 -0
- package/dist/bootstrap-ds/package-lock.json +4660 -0
- package/dist/bootstrap-ds/package.json +41 -0
- package/dist/bootstrap-ds/scripts/build-mcp-previews.mjs +33 -0
- package/dist/bootstrap-ds/src/vite-env.d.ts +7 -0
- package/dist/bootstrap-ds/tsconfig.build.json +12 -0
- package/dist/bootstrap-ds/tsconfig.json +20 -0
- package/dist/bootstrap-ds/vite.config.ts +21 -0
- package/dist/boundaries.mjs +130 -0
- package/dist/brand-assets.mjs +82 -0
- package/dist/check.mjs +222 -0
- package/dist/cli.mjs +106 -0
- package/dist/config.mjs +181 -0
- package/dist/contracts/tokens.json +52 -0
- package/dist/html.mjs +30 -0
- package/dist/index.mjs +9 -0
- package/dist/init.mjs +194 -0
- package/dist/lint-config.mjs +40 -0
- package/dist/mcp/THIRD_PARTY_NOTICES.md +786 -0
- package/dist/mcp/apps.mjs +53 -0
- package/dist/mcp/build-status.mjs +164 -0
- package/dist/mcp/catalog.mjs +65 -0
- package/dist/mcp/context.mjs +69 -0
- package/dist/mcp/mutations.mjs +301 -0
- package/dist/mcp/patch.mjs +114 -0
- package/dist/mcp/preview-watch.mjs +169 -0
- package/dist/mcp/preview-widget.bundle.js +113 -0
- package/dist/mcp/project-widget.bundle.js +113 -0
- package/dist/mcp/prompts.mjs +28 -0
- package/dist/mcp/resource-loader.js +138 -0
- package/dist/mcp/sandbox-host.mjs +22 -0
- package/dist/mcp/server.mjs +377 -0
- package/dist/mcp/showcase-host.mjs +68 -0
- package/dist/mcp/skills.mjs +77 -0
- package/dist/mcp/widget.bundle.js +150 -0
- package/dist/oxlint.mjs +81 -0
- package/dist/preview-resources.mjs +198 -0
- package/dist/project-documents.mjs +27 -0
- package/dist/public-props.mjs +74 -0
- package/dist/scenarios-compiler.mjs +287 -0
- package/dist/scenarios-vite.d.mts +3 -0
- package/dist/scenarios-vite.mjs +71 -0
- package/dist/scenarios.mjs +212 -0
- package/dist/showcase/client.bundle.js +127 -0
- package/dist/showcase/index.html +17 -0
- package/dist/showcase/sandbox.js +30 -0
- package/dist/showcase/style.css +7 -0
- package/dist/showcase-coverage.mjs +118 -0
- package/dist/showcase.mjs +77 -0
- package/dist/skills/README.md +68 -0
- package/dist/skills/ads-assimilate/SKILL.md +292 -0
- package/dist/skills/ads-assimilate/agents/openai.yaml +4 -0
- package/dist/skills/ads-assimilate/references/cli.md +111 -0
- package/dist/skills/ads-assimilate/references/lint-and-docs.md +87 -0
- package/dist/skills/ads-assimilate/references/native-implementation.md +98 -0
- package/dist/skills/ads-assimilate/references/testing.md +107 -0
- package/dist/skills/ads-break-ui/LICENSE.upstream +21 -0
- package/dist/skills/ads-break-ui/README.md +16 -0
- package/dist/skills/ads-break-ui/SKILL.md +235 -0
- package/dist/skills/ads-break-ui/agents/openai.yaml +4 -0
- package/dist/skills/ads-break-ui/references/catalog.md +135 -0
- package/dist/skills/ads-break-ui/references/verification.md +48 -0
- package/dist/skills/ads-designer/LICENSE.upstream +21 -0
- package/dist/skills/ads-designer/README.md +19 -0
- package/dist/skills/ads-designer/SKILL.md +400 -0
- package/dist/skills/ads-designer/agents/openai.yaml +4 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/ADS.md +203 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/README.md +98 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/biome.css.json +21 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/assets/brand/README.md +28 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/assets/fonts/.gitkeep +0 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/components/.gitkeep +0 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/composition/.gitkeep +0 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/index.ts +5 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/patterns/.gitkeep +0 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/showcase/mcp/index.html +1 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/showcase/mcp/main.tsx +8 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/styles.css +5 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/Foundation.fixture.ts +47 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/Foundation.scenario.tsx +14 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/base.css +27 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/colors.css +29 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/elevation.css +15 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/spacing.css +15 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/design-system/tokens/typography.css +13 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/ds.config.json +13 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/gitignore.template +8 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/package-lock.json +4660 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/package.json +41 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/scripts/build-mcp-previews.mjs +33 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/src/vite-env.d.ts +7 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/tsconfig.build.json +12 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/tsconfig.json +20 -0
- package/dist/skills/ads-designer/assets/bootstrap-ds/vite.config.ts +21 -0
- package/dist/skills/ads-designer/references/cli.md +111 -0
- package/dist/skills/ads-designer/references/design-craft.md +65 -0
- package/dist/skills/ads-designer/references/mobile.md +73 -0
- package/dist/skills/ads-import/SKILL.md +335 -0
- package/dist/skills/ads-import/agents/openai.yaml +4 -0
- package/dist/skills/ads-import/references/branding.md +44 -0
- package/dist/skills/ads-import/references/cli.md +111 -0
- package/dist/skills/ads-import/references/implementation.md +111 -0
- package/dist/skills/ads-import/references/tokens.md +96 -0
- package/dist/skills/ads-motion/LICENSE.upstream +21 -0
- package/dist/skills/ads-motion/README.md +22 -0
- package/dist/skills/ads-motion/SKILL.md +217 -0
- package/dist/skills/ads-motion/agents/openai.yaml +4 -0
- package/dist/skills/ads-motion/references/audit.md +44 -0
- package/dist/skills/ads-motion/references/build.md +81 -0
- package/dist/skills/ads-motion/references/performance.md +55 -0
- package/dist/skills/ads-motion/references/review.md +35 -0
- package/dist/skills/ads-motion/references/verification.md +39 -0
- package/dist/token-policy.mjs +10 -0
- package/dist/tokens.mjs +142 -0
- package/dist/ui-framework.mjs +59 -0
- package/dist/units.mjs +168 -0
- package/docs/ADS.md +310 -0
- package/docs/ARCHITECTURE.md +311 -0
- package/docs/CHANGELOG.md +106 -0
- package/docs/GUIDE.md +722 -0
- package/docs/MCP.md +690 -0
- package/package.json +107 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="light">
|
|
3
|
+
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>ADS Showcase</title><link rel="stylesheet" href="/style.css"></head>
|
|
4
|
+
<body>
|
|
5
|
+
<header id="header">
|
|
6
|
+
<div id="brand"><span class="mark">ADS</span><span id="title">Design System</span><button id="pane-toggle" aria-label="Hide navigation pane" aria-expanded="true" aria-controls="sidebar" title="Hide navigation pane"><svg viewBox="0 0 16 16"><path d="M10 4l-4 4 4 4"/></svg></button></div>
|
|
7
|
+
<nav id="sections" aria-label="Showcase sections">
|
|
8
|
+
<button data-section="tokens" aria-current="page"><svg viewBox="0 0 16 16"><path d="m8 2 6 3-6 3-6-3 6-3Zm-6 6 6 3 6-3M2 11l6 3 6-3"/></svg>Tokens</button>
|
|
9
|
+
<button data-section="components"><svg viewBox="0 0 16 16"><path d="m8 1 6 3.5v7L8 15l-6-3.5v-7L8 1Zm-6 3.5 6 3.5 6-3.5M8 8v7"/></svg>Components</button>
|
|
10
|
+
<button data-section="patterns"><svg viewBox="0 0 16 16"><rect x="2" y="2" width="5" height="5"/><rect x="10" y="2" width="4" height="5"/><rect x="2" y="10" width="5" height="4"/><rect x="10" y="10" width="4" height="4"/></svg>Patterns</button>
|
|
11
|
+
<button data-section="composition"><svg viewBox="0 0 16 16"><path d="M2 2h4v4H2zM10 2h4v4h-4zM2 10h4v4H2zM10 10h4v4h-4z"/></svg>Composition</button>
|
|
12
|
+
</nav>
|
|
13
|
+
<div class="actions"><button id="theme" aria-label="Use dark theme" title="Use dark theme"><svg viewBox="0 0 16 16"><path d="M13.5 9a5.5 5.5 0 0 1-6.5-6.5A5.5 5.5 0 1 0 13.5 9Z"/></svg></button><button id="minimize" aria-label="Minimize showcase menu" title="Minimize showcase menu (refresh to restore)"><svg viewBox="0 0 16 16"><path d="m4 10 4-4 4 4"/></svg></button></div>
|
|
14
|
+
</header>
|
|
15
|
+
<main><aside id="sidebar"><nav id="entries" aria-label="Tokens"></nav></aside><section id="preview" aria-label="Preview"><p id="status" role="status">Connecting to ADS MCP…</p><div id="loader" role="status" aria-label="Loading preview" hidden><span class="spinner" aria-hidden="true"></span></div><div id="frame-slot"></div></section></main>
|
|
16
|
+
<script type="module" src="/client.js"></script>
|
|
17
|
+
</body></html>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const parentOrigin = new URL(location.href).searchParams.get("parent");
|
|
2
|
+
let view;
|
|
3
|
+
function domains(values = []) {
|
|
4
|
+
return values.filter(value => /^(?:https?:\/\/[a-z0-9.*:[\]-]+(?::\d+)?|data:|blob:|about:)$/i.test(value)).join(" ");
|
|
5
|
+
}
|
|
6
|
+
function policy(csp = {}) {
|
|
7
|
+
const resources = domains(csp.resourceDomains);
|
|
8
|
+
return `default-src 'none';script-src 'unsafe-inline' ${resources};style-src 'unsafe-inline' ${resources};img-src data: ${resources};font-src ${resources || "'none'"};media-src ${resources || "'none'"};worker-src ${resources || "'none'"};connect-src ${domains(csp.connectDomains) || "'none'"};frame-src ${domains(csp.frameDomains) || "'none'"};base-uri ${domains(csp.baseUriDomains) || "'none'"};object-src 'none'`;
|
|
9
|
+
}
|
|
10
|
+
window.addEventListener("message", event => {
|
|
11
|
+
if (event.source === parent && event.origin === parentOrigin) {
|
|
12
|
+
const message = event.data;
|
|
13
|
+
if (message?.method === "ui/notifications/sandbox-resource-ready") {
|
|
14
|
+
const { html, csp } = message.params ?? {};
|
|
15
|
+
if (typeof html !== "string") return;
|
|
16
|
+
const document = new DOMParser().parseFromString(html, "text/html");
|
|
17
|
+
const meta = document.createElement("meta");
|
|
18
|
+
meta.httpEquiv = "Content-Security-Policy";
|
|
19
|
+
meta.content = policy(csp);
|
|
20
|
+
document.head.prepend(meta);
|
|
21
|
+
view?.remove();
|
|
22
|
+
view = window.document.createElement("iframe");
|
|
23
|
+
view.title = "Design-system App";
|
|
24
|
+
view.setAttribute("sandbox", "allow-scripts");
|
|
25
|
+
window.document.body.append(view);
|
|
26
|
+
view.srcdoc = "<!doctype html>" + document.documentElement.outerHTML;
|
|
27
|
+
} else if (message?.jsonrpc === "2.0" && !message.method?.startsWith("ui/notifications/sandbox-")) view?.contentWindow.postMessage(message, "*");
|
|
28
|
+
} else if (event.source === view?.contentWindow && event.data?.jsonrpc === "2.0" && !event.data.method?.startsWith("ui/notifications/sandbox-")) parent.postMessage(event.data, parentOrigin);
|
|
29
|
+
});
|
|
30
|
+
parent.postMessage({ jsonrpc: "2.0", method: "ui/notifications/sandbox-proxy-ready", params: {} }, parentOrigin);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
:root{font:13px/1.5 system-ui,sans-serif;color-scheme:light;background:#fafafa;color:#444;--frame-bg:#fafafa;--frame-ink:#444;--frame-line:#ddd;--pane-width:min(276px,42vw)}
|
|
2
|
+
:root[data-theme="dark"]{color-scheme:dark;--frame-bg:#181818;--frame-ink:#ddd;--frame-line:#444;background:var(--frame-bg);color:var(--frame-ink)}
|
|
3
|
+
*{box-sizing:border-box}body{margin:0;height:100vh;display:flex;flex-direction:column;overflow:hidden}button,a{font:inherit;color:inherit}button{cursor:pointer;background:transparent;border:1px solid var(--frame-line);border-radius:4px}button:focus-visible,a:focus-visible{outline:2px solid var(--frame-ink);outline-offset:2px}svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;flex:none}svg:not([aria-label]){pointer-events:none}
|
|
4
|
+
header{height:52px;display:flex;flex:none;border-bottom:1px solid var(--frame-line);align-items:stretch;background:var(--frame-bg)}#brand{width:var(--pane-width);display:flex;flex:none;gap:8px;align-items:center;padding:0 12px;border-right:1px solid var(--frame-line);font-weight:600;white-space:nowrap}#brand .mark{font-weight:700}#title{min-width:0;overflow:hidden;text-overflow:ellipsis}#pane-toggle{width:28px;height:28px;margin-inline-start:auto;display:grid;place-items:center;flex:none}.collapsed #brand{width:44px;padding:0 8px;border-right:0}.collapsed #brand .mark,.collapsed #title{display:none}
|
|
5
|
+
#sections{display:flex;gap:4px;align-items:center;min-width:0;overflow-x:auto;padding:8px}#sections button{display:flex;align-items:center;gap:8px;flex:none;border-color:transparent;padding:6px 10px}#sections button[aria-current="page"]{border-color:var(--frame-line)}#sections svg{opacity:.7}.actions{display:flex;align-items:center;gap:4px;margin-inline-start:auto;padding:8px;flex:none}.actions button{width:28px;height:28px;display:grid;place-items:center}
|
|
6
|
+
main{flex:1;min-height:0;display:flex}#sidebar{width:var(--pane-width);flex:none;border-right:1px solid var(--frame-line);overflow-y:auto;background:var(--frame-bg)}#entries{display:flex;flex-direction:column;gap:4px;padding:8px}#entries a{flex:none;padding:8px;border:1px solid transparent;border-radius:4px;text-decoration:none;overflow-wrap:anywhere}#entries a:hover,#entries a[aria-current="page"]{border-color:var(--frame-line)}#entries a[aria-current="page"]{font-weight:600}
|
|
7
|
+
#preview{position:relative;flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden}#frame-slot{flex:1;min-height:0;min-width:0}iframe{display:block;width:100%;height:100%;border:0}#status{position:absolute;z-index:1;inset:12px 12px auto;margin:0;padding:12px 16px;border:1px solid var(--frame-line);border-radius:4px;background:var(--frame-bg);white-space:pre-wrap;overflow-wrap:anywhere;max-height:30vh;overflow:auto}#status[data-error="true"]{color:CanvasText;background:Canvas;border-color:GrayText}#loader{position:absolute;inset:0;z-index:2;display:grid;place-items:center;background:var(--frame-bg)}.spinner{width:24px;height:24px;border:2px solid var(--frame-line);border-top-color:var(--frame-ink);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.spinner{animation:none}}[hidden],.collapsed #sidebar{display:none!important}@media(max-width:760px){#title{display:none}}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import { uiOperation } from "./ui-framework.mjs";
|
|
4
|
+
import { isInside, isTestFile, isDevelopmentFile } from "./config.mjs";
|
|
5
|
+
|
|
6
|
+
// Compare statically rendered public UI, not imports or every value in a barrel.
|
|
7
|
+
// Symbol identity keeps aliases, same-file exports, and shadowed names distinct.
|
|
8
|
+
export function inspectShowcaseCoverage(options, program, report) {
|
|
9
|
+
const { dsRoot, sourceRoot, config } = options;
|
|
10
|
+
const checker = program.getTypeChecker();
|
|
11
|
+
const entry = program.getSourceFile(path.join(dsRoot, config.publicEntry));
|
|
12
|
+
const module = entry && checker.getSymbolAtLocation(entry);
|
|
13
|
+
if (!module) return;
|
|
14
|
+
const showcase = path.join(dsRoot, "showcase");
|
|
15
|
+
const implementations = [path.join(dsRoot, "components"), path.join(dsRoot, "patterns")];
|
|
16
|
+
|
|
17
|
+
function symbolOf(expression) {
|
|
18
|
+
while (expression && (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isSatisfiesExpression(expression) || ts.isNonNullExpression(expression))) expression = expression.expression;
|
|
19
|
+
if (!expression) return null;
|
|
20
|
+
if (ts.isElementAccessExpression(expression) && expression.argumentExpression && ts.isStringLiteralLike(expression.argumentExpression)) {
|
|
21
|
+
return checker.getPropertyOfType(checker.getTypeAtLocation(expression.expression), expression.argumentExpression.text);
|
|
22
|
+
}
|
|
23
|
+
return checker.getSymbolAtLocation(expression);
|
|
24
|
+
}
|
|
25
|
+
function canonical(symbol, seen = new Set()) {
|
|
26
|
+
if (!symbol || seen.has(symbol)) return null;
|
|
27
|
+
seen.add(symbol);
|
|
28
|
+
if (symbol.flags & ts.SymbolFlags.Alias) return canonical(checker.getAliasedSymbol(symbol), seen);
|
|
29
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
30
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
31
|
+
const target = symbolOf(declaration.initializer);
|
|
32
|
+
if (target) return canonical(target, seen);
|
|
33
|
+
}
|
|
34
|
+
if (ts.isBindingElement(declaration) && ts.isObjectBindingPattern(declaration.parent) && ts.isVariableDeclaration(declaration.parent.parent)) {
|
|
35
|
+
const initializer = declaration.parent.parent.initializer;
|
|
36
|
+
const key = declaration.propertyName ?? declaration.name;
|
|
37
|
+
if (initializer && (ts.isIdentifier(key) || ts.isStringLiteralLike(key))) {
|
|
38
|
+
const target = checker.getPropertyOfType(checker.getTypeAtLocation(initializer), key.text);
|
|
39
|
+
if (target) return canonical(target, seen);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return symbol.declarations?.length ? symbol : null;
|
|
44
|
+
}
|
|
45
|
+
// The declaration also unifies a named default export with its local name.
|
|
46
|
+
function identity(symbol) { return symbol?.valueDeclaration ?? symbol?.declarations?.[0]; }
|
|
47
|
+
const publicUi = new Map();
|
|
48
|
+
for (const exported of checker.getExportsOfModule(module)) {
|
|
49
|
+
const symbol = canonical(exported);
|
|
50
|
+
const declaration = identity(symbol);
|
|
51
|
+
if (!declaration || !(symbol.flags & ts.SymbolFlags.Value)) continue;
|
|
52
|
+
if (!implementations.some((directory) => isInside(directory, declaration.getSourceFile().fileName))) continue;
|
|
53
|
+
const item = publicUi.get(declaration) ?? { symbol, names: [] };
|
|
54
|
+
item.names.push(exported.name);
|
|
55
|
+
publicUi.set(declaration, item);
|
|
56
|
+
}
|
|
57
|
+
if (!publicUi.size) return;
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
function uses(node, consume, helpers = false) {
|
|
61
|
+
function visit(child) {
|
|
62
|
+
if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child)) {
|
|
63
|
+
if (!(ts.isIdentifier(child.tagName) && /^[a-z]/.test(child.tagName.text))) consume(canonical(symbolOf(child.tagName)), child, true);
|
|
64
|
+
}
|
|
65
|
+
if (ts.isCallExpression(child)) {
|
|
66
|
+
const operation = uiOperation(child.expression, checker);
|
|
67
|
+
if (operation === "createElement" || helpers && ["memo", "forwardRef"].includes(operation)) consume(canonical(symbolOf(child.arguments[0])), child, true);
|
|
68
|
+
// A shared render helper can contain the actual component JSX.
|
|
69
|
+
if (helpers && !operation) consume(canonical(symbolOf(child.expression)), child, false);
|
|
70
|
+
}
|
|
71
|
+
ts.forEachChild(child, visit);
|
|
72
|
+
}
|
|
73
|
+
visit(node);
|
|
74
|
+
}
|
|
75
|
+
const dependencies = new Map();
|
|
76
|
+
function children(symbol) {
|
|
77
|
+
const key = identity(symbol);
|
|
78
|
+
if (dependencies.has(key)) return dependencies.get(key);
|
|
79
|
+
const result = new Map();
|
|
80
|
+
dependencies.set(key, result);
|
|
81
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
82
|
+
const file = declaration.getSourceFile().fileName;
|
|
83
|
+
if (isTestFile(file) || ![sourceRoot, showcase, ...implementations].some((directory) => isInside(directory, file))) continue;
|
|
84
|
+
uses(declaration, (child, _node, ui) => { if (child) result.set(child, ui || result.get(child) || false); }, true);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function rendered(symbol, consume, seen = new Map(), ui = true) {
|
|
89
|
+
const key = identity(symbol);
|
|
90
|
+
if (!key || seen.has(key) && (!ui || seen.get(key))) return;
|
|
91
|
+
seen.set(key, ui || seen.get(key) || false);
|
|
92
|
+
if (ui && publicUi.has(key)) consume(key);
|
|
93
|
+
for (const [child, childUi] of children(symbol)) rendered(child, consume, seen, childUi);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const production = new Map();
|
|
97
|
+
const demonstrated = new Set();
|
|
98
|
+
for (const source of program.getSourceFiles()) {
|
|
99
|
+
const file = source.fileName;
|
|
100
|
+
if (isTestFile(file)) continue;
|
|
101
|
+
const example = isDevelopmentFile(file, options);
|
|
102
|
+
const application = isInside(sourceRoot, file) && !isInside(dsRoot, file);
|
|
103
|
+
if (!example && !application) continue;
|
|
104
|
+
uses(source, (symbol, node) => rendered(symbol, (key) => {
|
|
105
|
+
if (example) demonstrated.add(key);
|
|
106
|
+
else {
|
|
107
|
+
const direct = identity(symbol) === key;
|
|
108
|
+
if (!production.has(key) || direct && !production.get(key).direct) production.set(key, { node, direct });
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
for (const [key, { node }] of production) {
|
|
113
|
+
if (demonstrated.has(key)) continue;
|
|
114
|
+
const source = node.getSourceFile();
|
|
115
|
+
const position = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
116
|
+
report(source.fileName, "showcase-coverage", `Public ADS UI ${publicUi.get(key).names.join(" / ")} is rendered by application source but has no showcase render reference. Add an example using the public API; an import alone or a test harness does not count.`, position.line + 1, position.character + 1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { isInside, isTestFile } from "./config.mjs";
|
|
5
|
+
|
|
6
|
+
export const showcasePages = ["TokensPage", "ComponentsPage", "PatternsPage", "CompositionPage"];
|
|
7
|
+
|
|
8
|
+
export function inspectShowcasePages({ dsRoot, config }, program, resolve, report) {
|
|
9
|
+
const pages = path.join(dsRoot, "showcase/pages");
|
|
10
|
+
if (!existsSync(pages)) return; // A project with no showcase yet still checks.
|
|
11
|
+
const entries = readdirSync(pages, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.[cm]?[jt]sx?$/.test(entry.name) && !isTestFile(entry.name));
|
|
12
|
+
if (!entries.length) return; // The built-in MCP client needs no project browser pages.
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
if (!showcasePages.includes(entry.name.replace(/\.[^.]+$/, ""))) report(path.join(pages, entry.name), "showcase-pages", "Showcase pages are TokensPage, ComponentsPage, PatternsPage, and CompositionPage. Put scenarios beside their owners or under composition/.");
|
|
15
|
+
}
|
|
16
|
+
for (const name of showcasePages) {
|
|
17
|
+
if (!entries.some((entry) => entry.name.replace(/\.[^.]+$/, "") === name)) report(pages, "showcase-pages", `Missing ${name}: use the standard Tokens, Components, Patterns, and Composition showcase pages.`);
|
|
18
|
+
}
|
|
19
|
+
const cache = new Map();
|
|
20
|
+
function exports(file, chain = new Set()) {
|
|
21
|
+
if (cache.has(file)) return cache.get(file);
|
|
22
|
+
if (chain.has(file)) return new Map();
|
|
23
|
+
chain = new Set([...chain, file]);
|
|
24
|
+
const result = new Map();
|
|
25
|
+
const source = program.getSourceFile(file);
|
|
26
|
+
if (!source) return result;
|
|
27
|
+
for (const node of source.statements) {
|
|
28
|
+
if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
29
|
+
const target = resolve(node.moduleSpecifier.text, file)[0];
|
|
30
|
+
const nested = exports(target, chain);
|
|
31
|
+
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
|
32
|
+
for (const item of node.exportClause.elements) result.set(item.name.text, nested.get((item.propertyName ?? item.name).text) ?? target);
|
|
33
|
+
} else if (!node.exportClause) for (const [name, owner] of nested) result.set(name, owner);
|
|
34
|
+
} else if (node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
35
|
+
if (node.name && ts.isIdentifier(node.name)) result.set(node.name.text, file);
|
|
36
|
+
if (ts.isVariableStatement(node)) for (const decl of node.declarationList.declarations) if (ts.isIdentifier(decl.name)) result.set(decl.name.text, file);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
cache.set(file, result);
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
const publicExports = exports(path.join(dsRoot, config.publicEntry));
|
|
43
|
+
const visited = new Set();
|
|
44
|
+
function catalogue(file) {
|
|
45
|
+
if (visited.has(file)) return;
|
|
46
|
+
visited.add(file);
|
|
47
|
+
const source = program.getSourceFile(file);
|
|
48
|
+
if (!source) return;
|
|
49
|
+
function visit(node) {
|
|
50
|
+
let specifier;
|
|
51
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) specifier = node.moduleSpecifier.text;
|
|
52
|
+
const dynamic = ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword;
|
|
53
|
+
if (dynamic && node.arguments[0] && ts.isStringLiteral(node.arguments[0])) specifier = node.arguments[0].text;
|
|
54
|
+
if (specifier === config.publicAlias && !node.importClause?.isTypeOnly && !node.isTypeOnly) {
|
|
55
|
+
const bindings = node.importClause?.namedBindings ?? node.exportClause;
|
|
56
|
+
// Named imports/re-exports keep the catalogue's dependency ownership explicit.
|
|
57
|
+
// Namespace/dynamic imports can select arbitrary exports, so check their whole surface.
|
|
58
|
+
const named = bindings && (ts.isNamedImports(bindings) || ts.isNamedExports(bindings));
|
|
59
|
+
const imported = named ? bindings.elements.filter((item) => !item.isTypeOnly).map((item) => (item.propertyName ?? item.name).text)
|
|
60
|
+
: dynamic || bindings || ts.isExportDeclaration(node) ? [...publicExports.keys()]
|
|
61
|
+
: node.importClause?.name ? ["default"] : [];
|
|
62
|
+
for (const name of imported) {
|
|
63
|
+
const owner = publicExports.get(name);
|
|
64
|
+
if (owner && isInside(path.join(dsRoot, "patterns"), owner) && !isInside(path.join(dsRoot, "patterns/showcase"), owner)) {
|
|
65
|
+
const position = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
66
|
+
report(file, "showcase-catalogue", `${name} is a pattern. Demonstrate it in PatternsPage or CompositionPage; TokensPage and ComponentsPage use primitives and the shared showcase frame.`, position.line + 1, position.character + 1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else if (specifier) {
|
|
70
|
+
for (const target of resolve(specifier, file)) if (isInside(path.join(dsRoot, "showcase"), target)) catalogue(target);
|
|
71
|
+
}
|
|
72
|
+
ts.forEachChild(node, visit);
|
|
73
|
+
}
|
|
74
|
+
visit(source);
|
|
75
|
+
}
|
|
76
|
+
for (const entry of entries) if (/^(?:TokensPage|ComponentsPage)\./.test(entry.name)) catalogue(path.join(pages, entry.name));
|
|
77
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# ADS skills
|
|
2
|
+
|
|
3
|
+
Install the skills you need with `npx skills`:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx skills add reqvire-org/design-system --skill ads-designer --skill ads-import --skill ads-assimilate --skill ads-break-ui --skill ads-motion
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
For local development, install from this checkout:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx skills add ./skills --skill ads-designer --skill ads-import --skill ads-assimilate --skill ads-break-ui --skill ads-motion
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Each skill includes its own instructions and references. `ads-designer` also
|
|
16
|
+
includes an empty bootstrap scaffold, so starting from zero needs no example
|
|
17
|
+
repository. Skills operate on a project's local ADS; they do not install a UI
|
|
18
|
+
catalogue or replace the project's theme values.
|
|
19
|
+
|
|
20
|
+
The [stdio MCP server](../docs/MCP.md#skills) also serves these skills and supporting
|
|
21
|
+
files from the npm distribution. Native Skills discovery is available on the
|
|
22
|
+
newer protocol; ordinary tools/resources provide explicit access on older
|
|
23
|
+
clients. MCP serving does not install or automatically activate a skill.
|
|
24
|
+
|
|
25
|
+
For inspection, start with `ads_status`, search the public API with `ads_catalog`,
|
|
26
|
+
read its source/available guides and relevant tokens, then discover an entry with
|
|
27
|
+
`ads_scenarios` and render it with `ads_show_scenario`. Check build freshness after
|
|
28
|
+
edits. The [MCP inspection guide](../docs/MCP.md#inspect-the-design-system) explains
|
|
29
|
+
the sequence, resource-only fallback and limits of metadata versus rendered review.
|
|
30
|
+
|
|
31
|
+
Each workflow updates relevant showcase examples, runs build guards, inspects
|
|
32
|
+
the browser, and provides a running URL or exact command for review. See the
|
|
33
|
+
[architecture](../docs/ARCHITECTURE.md) for the rationale and tooling requirements.
|
|
34
|
+
|
|
35
|
+
| Skill | Use | Example |
|
|
36
|
+
|-------|-----|---------|
|
|
37
|
+
| [ads-designer](ads-designer/SKILL.md) | Bootstrap or build UI using the local ADS, with craft/mobile guidance | `$ads-designer build a settings page using this project's ADS` |
|
|
38
|
+
| [ads-import](ads-import/SKILL.md) | Import selected external ADS source, brand artwork, or compatible source token values | `$ads-import /path/to/source-repo component Toast` |
|
|
39
|
+
| [ads-assimilate](ads-assimilate/SKILL.md) | Study an external component library and implement a native counterpart | `$ads-assimilate https://github.com/emilkowalski/sonner` |
|
|
40
|
+
| [ads-break-ui](ads-break-ui/SKILL.md) | Stress-test real components/patterns; optionally fix demonstrated failures | `$ads-break-ui AppShell +fix` |
|
|
41
|
+
| [ads-motion](ads-motion/SKILL.md) | Implement, review, audit, or profile motion | `$ads-motion review Toast` |
|
|
42
|
+
|
|
43
|
+
For token values, use `$ads-import /path/to/source-repo tokens`; for original
|
|
44
|
+
artwork and its guidance, use `$ads-import /path/to/source-repo brand`. ADS token
|
|
45
|
+
names and ownership prefixes are fixed; imports conform to that architecture.
|
|
46
|
+
For motion, the
|
|
47
|
+
request selects the mode, for example `build`, `audit`, or `performance`.
|
|
48
|
+
Review/audit requests report findings; a fix request authorizes implementation.
|
|
49
|
+
The import workflow is a skill, not a CLI `ads import` command.
|
|
50
|
+
|
|
51
|
+
`ads-break-ui`, `ads-motion`, and the craft/mobile references in `ads-designer`
|
|
52
|
+
adapt [Emil Kowalski's MIT-licensed skills](https://github.com/emilkowalski/skills).
|
|
53
|
+
Their local READMEs record pinned source revisions and specific influences;
|
|
54
|
+
each folder retains the upstream MIT notice. Preserve those notices when
|
|
55
|
+
redistributing the skills. Component-library notices belong beside the imported component in its receiving
|
|
56
|
+
project, separate from these skill notices.
|
|
57
|
+
|
|
58
|
+
The showcase is a tool-owned minimal shell plus an MCP client and Apps host.
|
|
59
|
+
Its four sections discover token categories and scenario entries through MCP.
|
|
60
|
+
The skills use the connected runtime URL, or `ads showcase` for browser-only work;
|
|
61
|
+
they do not generate page browsers or duplicate the tool shell. Scenarios,
|
|
62
|
+
fixtures and adapters remain colocated with their owners; larger entries live in
|
|
63
|
+
`composition/`. One managed project compiler supplies both human and agent views.
|
|
64
|
+
|
|
65
|
+
Project/component rules are registered in `ds.config.json`. Scoped Oxlint settings
|
|
66
|
+
do not disable independent architecture checks. Each skill contains the workflow
|
|
67
|
+
needed when installed on its own; the designer includes the empty foundation and
|
|
68
|
+
a React/Vite preview compiler adapter, without any component catalogue.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ads-assimilate
|
|
3
|
+
description: "Implement or refine a native design-system component from a component-library URL, studying the original implementation and verifying behavior, visuals, and motion against the real reference. Use for component assimilation, including local documentation and justified usage lint rules; not for simply installing or wrapping a dependency."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ADS Assimilate
|
|
7
|
+
|
|
8
|
+
When ADS MCP is connected, discover public UI and addressable scenarios with
|
|
9
|
+
`ads_status`/`ads_catalog`; use `ads_tokens` for definitions and values, and
|
|
10
|
+
`ads_scenarios`/`ads_show_scenario` for real project scenarios. Keep the external
|
|
11
|
+
library as the behavioral reference.
|
|
12
|
+
If Apps are unavailable, inspect the normal showcase. Resolve MCP-served skill
|
|
13
|
+
references relative to this `SKILL.md` URI and load them lazily; a resource read
|
|
14
|
+
does not itself activate the skill.
|
|
15
|
+
Use the returned `projectRoot` and `project.commands`; the connected ADS may be
|
|
16
|
+
inside a different or nested repository. Inspect the selected public API, owning
|
|
17
|
+
source/available guides and relevant tokens, then mount its discovered scenario.
|
|
18
|
+
Metadata and source reads do not prove rendered behavior.
|
|
19
|
+
|
|
20
|
+
When `ads_status.mutations.enabled`, discover the owner with `ads_units`, read
|
|
21
|
+
relevant ranges with `ads_read_file` and send only a Git unified diff through
|
|
22
|
+
`ads_apply_patch({ unit, patch, dryRun })`. A unit includes its own implementation,
|
|
23
|
+
scenarios and fixtures; imported peers remain separate. `tokens` is the token
|
|
24
|
+
foundation unit. Unit discovery and file ownership are distinct from preview IDs.
|
|
25
|
+
Include only that owner's required re-exports in the public entry. Use
|
|
26
|
+
`dryRun: true` to inspect validation; applying re-runs the gates. Fix rejected
|
|
27
|
+
patches in their owner. Shared styles/helpers use `foundation`, root guides use
|
|
28
|
+
`documentation`, and branding/fonts use their discovered `assets/*` unit.
|
|
29
|
+
Intentional configuration, rule exceptions, registered guard code and compiler
|
|
30
|
+
changes use `configuration`; validate the proposed settings and keep mandatory
|
|
31
|
+
ADS gates. For binary/large assets, generate `git diff --binary --full-index` into
|
|
32
|
+
`.ds/patches/<name>.patch` and send `patchFile` instead of inline `patch`, so bytes
|
|
33
|
+
stay out of model context. Binary changes require Git. When editing is disabled,
|
|
34
|
+
use the client's normal source-editing tools.
|
|
35
|
+
|
|
36
|
+
Before trusting a preview after edits, check `ads_status.build` or
|
|
37
|
+
`ads://project/build`. Fix build diagnostics in owned source; an older view or
|
|
38
|
+
unreported freshness is not evidence of current code. Notifications may not
|
|
39
|
+
reach the agent.
|
|
40
|
+
|
|
41
|
+
Turn a supplied component-library reference into a native component in the current
|
|
42
|
+
design-system repository. Preserve the requested interaction contract while
|
|
43
|
+
using the target system's primitives, tokens, styling architecture, and public API.
|
|
44
|
+
Aim for a close adaptation: the reference's function, layout, interaction details,
|
|
45
|
+
and animation style should remain recognizable. Change what native integration
|
|
46
|
+
requires; broader redesign belongs to an explicit user request.
|
|
47
|
+
|
|
48
|
+
React and native Preact are supported. Preserve the target runtime in both
|
|
49
|
+
production and scenario builds; never alias React to Preact just to shrink a
|
|
50
|
+
preview. Native Preact uses its own JSX transform, hooks and DOM events (live
|
|
51
|
+
text updates use `onInput`). Native SVG uses DOM names such as `stroke-width`,
|
|
52
|
+
not React presentation aliases. Keep Linaria extraction and the same public APIs.
|
|
53
|
+
The shipped empty starter uses React; the tool repository's working example
|
|
54
|
+
uses Preact. Neither is a component dependency of the receiving project.
|
|
55
|
+
|
|
56
|
+
ADS is tooling only. Implement in the target project's
|
|
57
|
+
local ADS folder: the project owns the component source and theme values, and
|
|
58
|
+
the app imports its local public barrel (normally `@ds`). Shared tooling supplies
|
|
59
|
+
contracts, rules, skills, and empty scaffolding. Component libraries, patterns,
|
|
60
|
+
themes and scenarios are external sources, loaded through explicit ADS
|
|
61
|
+
workflows. Do not look for a built-in or optional UI catalogue in the tool.
|
|
62
|
+
|
|
63
|
+
## Input
|
|
64
|
+
|
|
65
|
+
Invocation accepts a library/repository/documentation URL as its first argument:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
$ads-assimilate <library-url> [component-name] [requirements]
|
|
69
|
+
$ads-assimilate https://github.com/emilkowalski/sonner toast
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The URL is the required reference, not a request to install the library into the
|
|
73
|
+
product. Use the current repository as the target unless the user names another.
|
|
74
|
+
Infer the component from the request or a single-component library. If the URL
|
|
75
|
+
is missing, ask for it. If a multi-component library leaves the component
|
|
76
|
+
ambiguous, inspect its catalogue and clarify the target while doing independent
|
|
77
|
+
repository research. Optional requirements can specify API compatibility,
|
|
78
|
+
appearance, behavior, migrations, and a playground.
|
|
79
|
+
|
|
80
|
+
Read [references/cli.md](references/cli.md) and invoke supported ADS CLI commands
|
|
81
|
+
through `npx` using the actual published version or a local tarball. Use the CLI
|
|
82
|
+
for setup and checks while this skill owns reference research and implementation.
|
|
83
|
+
|
|
84
|
+
## Establish the contract
|
|
85
|
+
|
|
86
|
+
Read repository instructions, the main README, architecture/token documentation
|
|
87
|
+
such as `docs/ARCHITECTURE.md` and `docs/ADS.md` when present (or existing project guides), relevant component guides,
|
|
88
|
+
public exports, and lint/build scripts.
|
|
89
|
+
Reuse the target's structure; do not redesign the system to accommodate the reference.
|
|
90
|
+
ADS requires Linaria for component and pattern styling. Adapt reference styles to
|
|
91
|
+
colocated `@linaria/atomic` blocks and verify extraction in application and
|
|
92
|
+
preview builds. Preserve the target framework; `ads init` does not configure
|
|
93
|
+
Linaria for it.
|
|
94
|
+
|
|
95
|
+
Open the supplied URL and the relevant primary source, official usage docs, CSS,
|
|
96
|
+
animation code, tests, and license. Record the version or commit inspected.
|
|
97
|
+
Published-package behavior can differ from repository HEAD: use one identified
|
|
98
|
+
runtime reference for the comparison and call out source-version differences.
|
|
99
|
+
|
|
100
|
+
Establish what should match: supported states, lifecycle, keyboard/pointer
|
|
101
|
+
behavior, focus, timing, layout/stacking, motion, and responsive behavior. Treat
|
|
102
|
+
token/brand adaptation and API reshaping as explicit design decisions. When the
|
|
103
|
+
user requests matching UX, reproduce the observed behavior, including quirks.
|
|
104
|
+
Do not silently improve timers, focus restoration, cleanup, gestures, or placement.
|
|
105
|
+
Propose any necessary deviation with its concrete effect and obtain a direction
|
|
106
|
+
when existing instructions do not resolve the tradeoff.
|
|
107
|
+
|
|
108
|
+
## Implement and integrate
|
|
109
|
+
|
|
110
|
+
Use [native-implementation.md](references/native-implementation.md) for research
|
|
111
|
+
and implementation mechanics. Keep state, geometry, and visual policy in their
|
|
112
|
+
owning layers. Export the native API through the public barrel, add real showcase
|
|
113
|
+
examples, and migrate authorized consumers without changing unrelated surfaces.
|
|
114
|
+
|
|
115
|
+
Write the component-local README with usage, API, behavior, motion, token hooks,
|
|
116
|
+
validation, and any agreed differences. Include a References and credits section:
|
|
117
|
+
link the original library, studied source/docs/articles, identify the reference
|
|
118
|
+
version or commit, credit its authors, and say which features influenced the
|
|
119
|
+
native implementation. Keep shared project architecture in its ADS guide; the
|
|
120
|
+
receiving project's main README also credits inspiration and links to the local
|
|
121
|
+
guide. Do not add the imported component's catalogue or API to core tooling docs.
|
|
122
|
+
|
|
123
|
+
Read [lint-and-docs.md](references/lint-and-docs.md) when documenting the component
|
|
124
|
+
or evaluating usage rules. Add local rules only for concrete misuse that static
|
|
125
|
+
analysis can establish. Colocate rule ownership with the component and register
|
|
126
|
+
it through shared tooling; avoid duplicating existing TypeScript or lint checks.
|
|
127
|
+
|
|
128
|
+
## Verify against the original
|
|
129
|
+
|
|
130
|
+
Use the project showcase as the permanent native demonstration and shared
|
|
131
|
+
review surface for agents and humans. Discover its existing run/build commands;
|
|
132
|
+
use the built-in MCP client and configure project preview compilation. Examples and
|
|
133
|
+
composition scenarios import the real public ADS API and the same token/foundation styles
|
|
134
|
+
as the application. Put reusable UI discovered while building a mock in ADS
|
|
135
|
+
components/patterns first. Colocate sample data and state/callback adapters with
|
|
136
|
+
the scenario; larger entries belong under `composition/`. Browsing pages only
|
|
137
|
+
select these entries. The scenario labels, controls and review layouts are public ADS entities with defined
|
|
138
|
+
APIs. The outer shell belongs to the tool client. Showcase/scenario files define no CSS, custom classes, or widget markup.
|
|
139
|
+
Change the owning ADS pattern when a frame layout is missing; do not recreate
|
|
140
|
+
the assimilated UI there or override its internals.
|
|
141
|
+
|
|
142
|
+
The showcase is a minimal shell plus an MCP client and Apps host, supplied by ADS
|
|
143
|
+
tooling. It discovers Tokens/Components/Patterns/Composition entries through MCP
|
|
144
|
+
tools and renders their scenarios in the preview App. Navigation, theme and
|
|
145
|
+
pane/header visibility belong to the tool client. Do not create page files,
|
|
146
|
+
copy its shell into the project or assemble a second catalogue/rendering pipeline.
|
|
147
|
+
|
|
148
|
+
When MCP is connected, open the running URL from `ads_status`. Otherwise run the
|
|
149
|
+
installed `ads showcase` or the project's `dev:showcase` script. Do not launch a
|
|
150
|
+
second runtime/compiler for the same connected project. A configured project
|
|
151
|
+
preview watcher publishes a shared graph on first demand and after source
|
|
152
|
+
changes. The built-in client refreshes discovery and the active scenario in the
|
|
153
|
+
same App after a successful build. Shared runtime, foundation CSS, fonts and
|
|
154
|
+
selected scenario modules load through MCP
|
|
155
|
+
resources inside the sandboxed App. Never inject project styles/runtime into
|
|
156
|
+
the outer host. Keep the configured framework, compiler and mount/unmount adapter
|
|
157
|
+
consistent; scenario teardown must release owned timers, portals and workers.
|
|
158
|
+
The host shows errors and marks retained output as stale. Other hosts may need an
|
|
159
|
+
explicit preview-tool invocation. Compilation remains project-owned and required
|
|
160
|
+
for TSX/Linaria; it is automatic, not eliminated.
|
|
161
|
+
|
|
162
|
+
Reusable review layouts belong in public project ADS patterns, while scenario
|
|
163
|
+
files define no CSS, custom classes or widget replicas. Keep real presentation in
|
|
164
|
+
its component/pattern owner. The tooling shell's CSS is outside that project
|
|
165
|
+
contract. Legacy custom showcase pages may be retained during migration; new
|
|
166
|
+
projects require no TokensPage/ComponentsPage/PatternsPage/CompositionPage files.
|
|
167
|
+
|
|
168
|
+
Colocate `Scenario.tsx` and `fixture.ts` with tokens and each component/pattern; flat owners
|
|
169
|
+
may use `<Owner>.scenario.tsx` and `<Owner>.fixture.ts`. Put larger entries under
|
|
170
|
+
`composition/<Name>/Scenario.tsx` with their own `fixture.ts`. Export a default
|
|
171
|
+
zero-input mountable view and literal metadata, for example
|
|
172
|
+
`export const scenario = { title: "Button states", covers: ["Button"] };`.
|
|
173
|
+
Import the real UI from the public ADS alias. Keep fixture inputs, simulated
|
|
174
|
+
services and initial state/callback adapters beside the scenario. Empty fixtures
|
|
175
|
+
are valid for an entry with no inputs. Extra development helpers use a
|
|
176
|
+
`scenario/` or `fixtures/` subfolder, or `<Owner>.scenario-adapter.ts`, so guards
|
|
177
|
+
recognize their role even beside runtime code. Never require a page, router or store to
|
|
178
|
+
initialize the entry. Several contextual public parts may share one scenario.
|
|
179
|
+
|
|
180
|
+
IDs derive from ADS-relative filenames: both `components/core/Button/Scenario.tsx`
|
|
181
|
+
and `components/core/Button.scenario.tsx` identify `components/core/Button`.
|
|
182
|
+
Use one form, no duplicate IDs or hand-maintained registry. Renames change IDs.
|
|
183
|
+
The showcase and external hosts mount the same discovered entry. The Vite
|
|
184
|
+
adapter uses `previewEntriesPlugin` and `createPreviewResources` with
|
|
185
|
+
`runScenarioCompiler` to publish the shared graph. Its framework mount adapter
|
|
186
|
+
returns cleanup; the project owns rendering and Linaria extraction. The older
|
|
187
|
+
`scenarioRegistryPlugin` is only for retained legacy browsers. MCP discovers
|
|
188
|
+
metadata without importing executable TSX. Existing apps need an explicitly
|
|
189
|
+
integrated compiler; init alone adds no compiler or extraction setup.
|
|
190
|
+
Use `ads_scenarios` (query/kind/limit) and `ads_show_scenario({id})` to open an exact
|
|
191
|
+
entry. Check its build freshness; HTML delivery is not browser verification.
|
|
192
|
+
If Apps or resource forwarding are unavailable, open that scenario in the real
|
|
193
|
+
showcase, using the tool result's URL. Do not build a preview-only replica.
|
|
194
|
+
|
|
195
|
+
For a production screen, find and render the application's public screen pattern.
|
|
196
|
+
Its owner supplies structure, controls, layout and presentation. Scenario fixtures
|
|
197
|
+
supply data/state/callbacks. Move shared presentation into a pattern if needed,
|
|
198
|
+
preserving existing behavior and lazy imports, workers, caching and cancellation.
|
|
199
|
+
Do not reassemble an alternative screen or substitute placeholder content.
|
|
200
|
+
Screen reuse remains skill guidance, not a dedicated screen-parity lint.
|
|
201
|
+
|
|
202
|
+
Resolve `scenario-contract`, `scenario-render` and `scenario-coverage` findings
|
|
203
|
+
with meaningful entries. Every public renderable component and pattern needs an
|
|
204
|
+
addressable scenario, including unused exports; types/constants/utilities do not.
|
|
205
|
+
Only public render references reachable from the default entry count. Tests and
|
|
206
|
+
unused imports/functions do not. Static reachability does not prove successful
|
|
207
|
+
mounting, correct content, every branch/state or visual parity: open each affected
|
|
208
|
+
entry independently and verify real behavior at narrow/wide sizes in both themes.
|
|
209
|
+
The older `showcase-coverage` policy separately checks application references.
|
|
210
|
+
|
|
211
|
+
Token previews use that same scenario pipeline. Colocate a token scenario and
|
|
212
|
+
fixture under the configured token directory. Use static metadata
|
|
213
|
+
`{ title: "Typography", covers: ["TokenSamples"], tokens: fixture.tokens }` with
|
|
214
|
+
literal const fixture fields; names/sample text are fixture data, values come
|
|
215
|
+
from the real foundation CSS. Reuse a public project review pattern for styled
|
|
216
|
+
samples. The minimal starter's foundation value scenario can have `covers: []`.
|
|
217
|
+
Every declared token needs reachable scenario coverage; adding/removing a token
|
|
218
|
+
requires fixture updates. Fix `token-scenario-reference`, `token-scenario-render`
|
|
219
|
+
and `token-scenario-coverage` findings. Metadata and unused fixture fields do not
|
|
220
|
+
count. Discover exact token IDs with `ads_scenarios({kind:"tokens"})`; mount them
|
|
221
|
+
with `ads_show_scenario({id})` or `ads_show_tokens({category:id})`. With the shared
|
|
222
|
+
resource compiler, omitting category opens the first project token scenario.
|
|
223
|
+
Legacy compilers retain the generic definition inspector. Use `ads_tokens` for
|
|
224
|
+
source definitions and values; inspecting definitions does not prove UI parity.
|
|
225
|
+
The tool keeps the shared naming contract; sample templates and their token
|
|
226
|
+
lists belong to the project.
|
|
227
|
+
|
|
228
|
+
Scenarios, colocated fixtures and helpers are development-only. Never export them
|
|
229
|
+
from the runtime barrel or import them in production, including through aliases,
|
|
230
|
+
re-exports or dynamic imports. They may not import application stores, routers,
|
|
231
|
+
providers or HTTP clients. Live business data is application-owned; UI uses typed
|
|
232
|
+
inputs or injected services/callbacks. Direct global fetch/XHR/WebSocket/EventSource
|
|
233
|
+
is rejected; custom clients and computed access require review/project guards.
|
|
234
|
+
Use local simulated services in fixtures. Tests may import fixtures; load real
|
|
235
|
+
foundation CSS rather than assigning shared token values in JavaScript. Keep
|
|
236
|
+
full-app integration harnesses and workflow coverage in application test support.
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
Register component/project Oxlint plugins and rules in `ds.config.json`. Use
|
|
241
|
+
scoped `oxlint.overrides` for justified file-specific settings; never edit
|
|
242
|
+
`.ds/oxlintrc.json`. These overrides configure Oxlint, not the independent
|
|
243
|
+
architecture checks in `ads check`. Measured renderer properties and documented
|
|
244
|
+
non-state hooks use explicit `boundaries`; shared token writes and primitive
|
|
245
|
+
state overrides cannot be allowlisted. Add generic architectural protections to
|
|
246
|
+
ADS core and keep domain/component-specific rules registered in project setup.
|
|
247
|
+
|
|
248
|
+
Update meaningful variants, states, content, themes, and container sizes in the
|
|
249
|
+
showcase. Run ADS/project guards before its build as well as the app build.
|
|
250
|
+
Fix appearance and motion in the shared implementation so both consumers change
|
|
251
|
+
together. Temporary upstream comparison pages are separate from the permanent
|
|
252
|
+
native showcase and use the actual upstream runtime.
|
|
253
|
+
|
|
254
|
+
Use [testing.md](references/testing.md) to select meaningful tests and compare the
|
|
255
|
+
native component with the **actual original component**, not another native demo.
|
|
256
|
+
Use matching content, configuration, theme intent, viewport, and input modality.
|
|
257
|
+
Measure state changes, computed geometry, timing, and animation frames, then
|
|
258
|
+
inspect screenshots. A screenshot alone does not establish behavior or motion parity.
|
|
259
|
+
|
|
260
|
+
Keep browser automation in isolated pages/contexts. Rebuild static playgrounds
|
|
261
|
+
after source changes. Test the public consumer path as well as component internals;
|
|
262
|
+
check root mounting and routing where the component has shared lifecycle.
|
|
263
|
+
|
|
264
|
+
Preserve the target's performance strategy when changing ownership: lazy imports,
|
|
265
|
+
worker execution, caches, memoization, cancellation, and stale-result rejection.
|
|
266
|
+
Public exports must not eagerly load heavy renderers for unrelated consumers.
|
|
267
|
+
Compare relevant bundle loading and existing performance/lifecycle tests before
|
|
268
|
+
and after a migration. Shared screen patterns can accept injected services;
|
|
269
|
+
architectural reuse does not require moving application services into the ADS.
|
|
270
|
+
|
|
271
|
+
Run the target's required lint, type checking, build, and relevant component/rule
|
|
272
|
+
tests. Inspect the target's actual scripts; an imported component or upstream
|
|
273
|
+
example may have its own test entry. Do not assume `test:toast` or a showcase
|
|
274
|
+
build exists in every project. Repeat only affected checks after new changes.
|
|
275
|
+
|
|
276
|
+
Follow [references/cli.md](references/cli.md) to integrate the tool as a
|
|
277
|
+
development dependency in the target's actual lint/build pipeline.
|
|
278
|
+
Register applicable local rules through its project-owned plugin adapter and
|
|
279
|
+
`ds.config.json`, then run the normal project build. Its lint step refreshes
|
|
280
|
+
configuration and runs ADS/core/project rules automatically. Use npx for bootstrap
|
|
281
|
+
or ad hoc checks. Core checks complement component/rule tests and the browser
|
|
282
|
+
comparison; they do not establish runtime or motion parity.
|
|
283
|
+
|
|
284
|
+
## Deliver
|
|
285
|
+
|
|
286
|
+
Report what was implemented, verified matches, remaining agreed differences,
|
|
287
|
+
test evidence, and any concrete limits of the comparison. Link the component
|
|
288
|
+
guide and give full local URLs for running playgrounds, clearly identifying
|
|
289
|
+
which page is native and which uses the original. State the reference version.
|
|
290
|
+
Do not claim complete parity for untested states, or call a native replica a real
|
|
291
|
+
upstream reference. Keep comparison dependencies and downloaded source outside
|
|
292
|
+
the production dependency graph unless the user chose otherwise.
|