@reqvire-org/ads 0.3.8 → 0.3.10
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/dist/atomic-trace.mjs +3 -198
- package/dist/bootstrap-ds/scripts/build-mcp-previews.mjs +2 -1
- package/dist/bootstrap-ds/vite.config.ts +2 -1
- package/dist/check.mjs +12 -3
- package/dist/linaria/atomic-css.cjs +2 -0
- package/dist/linaria/atomic-styled.cjs +2 -0
- package/dist/linaria/preserve-values.cjs +32 -0
- package/dist/linaria.d.mts +1 -0
- package/dist/linaria.mjs +9 -0
- package/dist/mcp/preview-widget.bundle.js +1 -1
- package/dist/mcp/resource-loader.js +5 -2
- package/dist/mcp/server.mjs +3 -1
- package/dist/preview-resources.mjs +2 -1
- package/dist/scenario-trace.mjs +149 -0
- package/dist/scenarios-compiler.mjs +2 -1
- package/dist/scenarios.mjs +13 -6
- package/dist/skills/ads-break-ui/SKILL.md +9 -2
- package/dist/skills/ads-break-ui/references/atomic-styles.md +50 -0
- package/dist/skills/ads-break-ui/references/scenarios.md +98 -0
- package/dist/skills/ads-designer/SKILL.md +12 -3
- package/dist/skills/ads-designer/assets/bootstrap-ds/scripts/build-mcp-previews.mjs +2 -1
- package/dist/skills/ads-designer/assets/bootstrap-ds/vite.config.ts +2 -1
- package/dist/skills/ads-designer/references/atomic-styles.md +50 -0
- package/dist/skills/ads-designer/references/scenarios.md +98 -0
- package/dist/skills/ads-import/SKILL.md +9 -2
- package/dist/skills/ads-import/references/atomic-styles.md +50 -0
- package/dist/skills/ads-import/references/scenarios.md +98 -0
- package/dist/skills/ads-migrate/SKILL.md +9 -2
- package/dist/skills/ads-migrate/references/atomic-styles.md +50 -0
- package/dist/skills/ads-migrate/references/scenarios.md +98 -0
- package/dist/skills/ads-motion/SKILL.md +9 -2
- package/dist/skills/ads-motion/references/atomic-styles.md +50 -0
- package/dist/skills/ads-motion/references/scenarios.md +98 -0
- package/dist/source-values.mjs +247 -0
- package/dist/verification/browser.mjs +21 -12
- package/dist/verification/playwright-reporter.cjs +6 -2
- package/dist/verification.mjs +13 -4
- package/docs/ADS.md +20 -5
- package/docs/ARCHITECTURE.md +18 -0
- package/docs/BEHAVIORS.md +11 -1
- package/docs/CHANGELOG.md +27 -1
- package/docs/MCP.md +16 -0
- package/package.json +10 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { isInside } from "./config.mjs";
|
|
3
|
+
import { uiOperation } from "./ui-framework.mjs";
|
|
4
|
+
|
|
5
|
+
export const unknown = reason => ({ kind: "unknown", reason });
|
|
6
|
+
export const literal = value => ({ kind: "literal", value });
|
|
7
|
+
export const reference = (node, env = new Map(), via = []) => node ? { kind: "node", node, env, via } : literal(undefined);
|
|
8
|
+
export const union = values => values.length === 1 ? values[0] : { kind: "union", values };
|
|
9
|
+
export const isFunction = node => node && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node));
|
|
10
|
+
const nameOf = node => node && (ts.isIdentifier(node) || ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) ? node.text : undefined;
|
|
11
|
+
export function unwrap(node) {
|
|
12
|
+
while (node && (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node))) node = node.expression;
|
|
13
|
+
return node;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Bounded symbolic source traversal. No project code is imported or executed. */
|
|
17
|
+
export function createSourceValues(program, options, { preserveCall = () => false, strict = false } = {}) {
|
|
18
|
+
const checker = program.getTypeChecker();
|
|
19
|
+
const symbol = node => {
|
|
20
|
+
const value = checker.getSymbolAtLocation(ts.isPropertyAccessExpression(node) ? node.name : node);
|
|
21
|
+
return value?.valueDeclaration && ts.isShorthandPropertyAssignment(value.valueDeclaration) ? checker.getShorthandAssignmentValueSymbol(value.valueDeclaration) ?? value : value;
|
|
22
|
+
};
|
|
23
|
+
function declaration(node) {
|
|
24
|
+
let value = symbol(node);
|
|
25
|
+
if (value?.flags & ts.SymbolFlags.Alias) value = checker.getAliasedSymbol(value);
|
|
26
|
+
return value?.valueDeclaration;
|
|
27
|
+
}
|
|
28
|
+
const writes = new Set(), escapes = new Set(), aliases = [];
|
|
29
|
+
if (strict) {
|
|
30
|
+
function root(node) {
|
|
31
|
+
node = unwrap(node);
|
|
32
|
+
while (node && (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node))) node = unwrap(node.expression);
|
|
33
|
+
return node && ts.isIdentifier(node) ? symbol(node) : null;
|
|
34
|
+
}
|
|
35
|
+
function scan(node) {
|
|
36
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) writes.add(root(node.left));
|
|
37
|
+
if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && [ts.SyntaxKind.PlusPlusToken, ts.SyntaxKind.MinusMinusToken].includes(node.operator)) writes.add(root(node.operand));
|
|
38
|
+
if (ts.isDeleteExpression(node)) writes.add(root(node.expression));
|
|
39
|
+
if (ts.isCallExpression(node) || ts.isNewExpression(node)) for (const argument of node.arguments ?? []) {
|
|
40
|
+
const value = unwrap(argument);
|
|
41
|
+
if (ts.isIdentifier(value)) escapes.add(symbol(value));
|
|
42
|
+
}
|
|
43
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && root(node.initializer)) aliases.push([symbol(node.name), root(node.initializer)]);
|
|
44
|
+
ts.forEachChild(node, scan);
|
|
45
|
+
}
|
|
46
|
+
for (const file of program.getSourceFiles()) if (isInside(options.dsRoot, file.fileName)) scan(file);
|
|
47
|
+
const targets = new Map();
|
|
48
|
+
for (const [alias, target] of aliases) { if (!targets.has(alias)) targets.set(alias, []); targets.get(alias).push(target); }
|
|
49
|
+
for (const affected of [writes, escapes]) {
|
|
50
|
+
const queue = [...affected];
|
|
51
|
+
for (let index = 0; index < queue.length; ++index) for (const target of targets.get(queue[index]) ?? []) if (!affected.has(target)) { affected.add(target); queue.push(target); }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const state = () => ({ budget: { steps: 0 }, depth: 0, calls: new Set() });
|
|
55
|
+
function next(context) { return { ...context, depth: context.depth + 1 }; }
|
|
56
|
+
function exhausted(context) { return ++context.budget.steps > 4000 || context.depth > 48; }
|
|
57
|
+
function at(node, kind, name) {
|
|
58
|
+
const source = node.getSourceFile(), position = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
59
|
+
return { file: source.fileName, line: position.line + 1, column: position.character + 1, kind, name: name.slice(0, 100) };
|
|
60
|
+
}
|
|
61
|
+
function withVia(value, via) {
|
|
62
|
+
if (value.kind === "union") return { ...value, values: value.values.map(item => withVia(item, via)) };
|
|
63
|
+
return value.kind === "node" ? { ...value, via: [...new Map([...via, ...value.via].map(item => [JSON.stringify(item), item])).values()].slice(0, 16) } : value;
|
|
64
|
+
}
|
|
65
|
+
function withDefault(value, fallback, context) {
|
|
66
|
+
if (!fallback) return value;
|
|
67
|
+
value = resolve(value, next(context));
|
|
68
|
+
if (value.kind === "literal") return value.value === undefined ? fallback : value;
|
|
69
|
+
if (value.kind === "unknown") return union([value, fallback]);
|
|
70
|
+
if (value.kind === "union") return union(value.values.map(item => withDefault(item, fallback, next(context))));
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
function bind(pattern, value, env, via, context) {
|
|
74
|
+
if (ts.isIdentifier(pattern)) { env.set(symbol(pattern), value); return; }
|
|
75
|
+
if (ts.isObjectBindingPattern(pattern)) {
|
|
76
|
+
const excluded = new Set();
|
|
77
|
+
for (const part of pattern.elements) {
|
|
78
|
+
const key = nameOf(part.propertyName ?? part.name);
|
|
79
|
+
if (part.dotDotDotToken) bind(part.name, { kind: "rest", value, excluded: new Set(excluded) }, env, via, next(context));
|
|
80
|
+
else {
|
|
81
|
+
if (key === undefined) continue;
|
|
82
|
+
excluded.add(key);
|
|
83
|
+
bind(part.name, withDefault(get(value, key, next(context)), part.initializer && reference(part.initializer, env, via), context), env, via, next(context));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} else if (ts.isArrayBindingPattern(pattern)) {
|
|
87
|
+
pattern.elements.forEach((part, index) => {
|
|
88
|
+
if (ts.isBindingElement(part) && !part.dotDotDotToken) bind(part.name, withDefault(get(value, String(index), next(context)), part.initializer && reference(part.initializer, env, via), context), env, via, next(context));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function boundElement(node, env, via, context) {
|
|
93
|
+
let owner = node;
|
|
94
|
+
while (ts.isBindingElement(owner) || ts.isObjectBindingPattern(owner) || ts.isArrayBindingPattern(owner)) owner = owner.parent;
|
|
95
|
+
if (!ts.isVariableDeclaration(owner) || !owner.initializer || !(owner.parent.flags & ts.NodeFlags.Const)) return unknown();
|
|
96
|
+
const local = new Map(env);
|
|
97
|
+
bind(owner.name, reference(owner.initializer, env, via), local, via, next(context));
|
|
98
|
+
return local.get(symbol(node.name)) ?? unknown();
|
|
99
|
+
}
|
|
100
|
+
function get(value, key, context) {
|
|
101
|
+
value = resolve(value, next(context));
|
|
102
|
+
if (strict && value.kind === "context" && key === "Provider") return { kind: "provider" };
|
|
103
|
+
if (value.kind === "union") return union(value.values.map(item => get(item, key, next(context))));
|
|
104
|
+
if (value.kind === "rest") return value.excluded.has(key) ? literal(undefined) : get(value.value, key, next(context));
|
|
105
|
+
const layers = value.kind === "object" ? value.layers : [];
|
|
106
|
+
if (value.kind === "node" && ts.isObjectLiteralExpression(value.node)) {
|
|
107
|
+
for (const property of value.node.properties) {
|
|
108
|
+
if (ts.isSpreadAssignment(property)) layers.push(reference(property.expression, value.env, value.via));
|
|
109
|
+
else {
|
|
110
|
+
const name = nameOf(property.name);
|
|
111
|
+
if (name !== undefined) layers.push(new Map([[name, strict && (ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) ? unknown("An accessor is not a statically known property.") : reference(ts.isShorthandPropertyAssignment(property) ? property.name : ts.isMethodDeclaration(property) ? property : property.initializer, value.env, value.via)]]));
|
|
112
|
+
else if (strict) layers.push(unknown("A computed object key may replace the selected property."));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else if (value.kind === "node" && ts.isArrayLiteralExpression(value.node)) {
|
|
116
|
+
return reference(value.node.elements[Number(key)], value.env, value.via);
|
|
117
|
+
} else if (value.kind !== "object") return unknown(value.reason);
|
|
118
|
+
for (let index = layers.length - 1; index >= 0; index--) {
|
|
119
|
+
const layer = layers[index];
|
|
120
|
+
if (layer instanceof Map) { if (layer.has(key)) return layer.get(key); }
|
|
121
|
+
else {
|
|
122
|
+
const selected = get(layer, key, next(context));
|
|
123
|
+
if (selected.kind === "literal" && selected.value === undefined) continue;
|
|
124
|
+
// An opaque later spread may replace an earlier explicit property.
|
|
125
|
+
if (selected.kind === "unknown" || selected.kind === "union") return union([selected, get({ kind: "object", layers: layers.slice(0, index) }, key, next(context))]);
|
|
126
|
+
return selected;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return literal(undefined);
|
|
130
|
+
}
|
|
131
|
+
function keys(value, context) {
|
|
132
|
+
value = resolve(value, next(context));
|
|
133
|
+
if (value.kind === "union") return [...new Set(value.values.flatMap(item => keys(item, next(context))))];
|
|
134
|
+
if (value.kind === "node" && ts.isObjectLiteralExpression(value.node)) return value.node.properties.flatMap(property => ts.isSpreadAssignment(property) ? keys(reference(property.expression, value.env, value.via), next(context)) : nameOf(property.name) ?? []);
|
|
135
|
+
if (value.kind === "object") return [...new Set(value.layers.flatMap(layer => layer instanceof Map ? [...layer.keys()] : keys(layer, next(context))))];
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
function returns(fn, args, context, kind = "helper") {
|
|
139
|
+
if (context.calls.has(fn.node)) return [unknown("Recursive local call could not be fully traced.")];
|
|
140
|
+
if (!fn.node.body || fn.node.asteriskToken || fn.node.modifiers?.some(item => item.kind === ts.SyntaxKind.AsyncKeyword)) return [unknown("Async, generator or declaration-only calls are outside atomic source tracing.")];
|
|
141
|
+
const env = new Map(fn.env), via = [...fn.via, at(fn.node, kind, fn.node.name?.getText() ?? "local function")];
|
|
142
|
+
const inner = { ...next(context), calls: new Set([...context.calls, fn.node]) };
|
|
143
|
+
for (const [index, parameter] of fn.node.parameters.entries()) {
|
|
144
|
+
if (parameter.dotDotDotToken) { bind(parameter.name, { kind: "array", values: args.slice(index) }, env, via, inner); break; }
|
|
145
|
+
bind(parameter.name, withDefault(resolve(args[index] ?? literal(undefined), inner), parameter.initializer && reference(parameter.initializer, env, via), inner), env, via, inner);
|
|
146
|
+
}
|
|
147
|
+
const outputs = [];
|
|
148
|
+
function statement(node) {
|
|
149
|
+
if (ts.isReturnStatement(node)) { outputs.push(reference(node.expression, env, via)); return true; }
|
|
150
|
+
if (ts.isBlock(node)) { for (const child of node.statements) if (statement(child)) return true; }
|
|
151
|
+
else if (ts.isIfStatement(node)) {
|
|
152
|
+
const condition = resolve(reference(node.expression, env, via), inner);
|
|
153
|
+
if (condition.kind === "literal") return condition.value ? statement(node.thenStatement) : node.elseStatement ? statement(node.elseStatement) : false;
|
|
154
|
+
const left = statement(node.thenStatement), right = node.elseStatement ? statement(node.elseStatement) : false;
|
|
155
|
+
return left && right;
|
|
156
|
+
} else if (ts.isThrowStatement(node)) { if (strict) outputs.push(unknown("A throwing branch does not establish a returned value.")); return true; }
|
|
157
|
+
else if (ts.isIterationStatement(node, false) || ts.isSwitchStatement(node) || ts.isTryStatement(node)) outputs.push(unknown("Loop, switch or try control flow could not be fully traced."));
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
if (ts.isBlock(fn.node.body)) { if (!statement(fn.node.body) && strict) outputs.push(literal(undefined)); }
|
|
161
|
+
else outputs.push(reference(fn.node.body, env, via));
|
|
162
|
+
// Keep call stacks with lazy return references, including nested helpers.
|
|
163
|
+
return outputs.length ? outputs.map(value => ({ ...value, context: inner })) : [literal(undefined)];
|
|
164
|
+
}
|
|
165
|
+
function resolve(value, context) {
|
|
166
|
+
if (!value) return literal(undefined);
|
|
167
|
+
context = value.context ?? context;
|
|
168
|
+
if (exhausted(context)) return unknown("Atomic source tracing reached its depth or work limit.");
|
|
169
|
+
if (value.kind !== "node") return value;
|
|
170
|
+
const node = unwrap(value.node), { env, via } = value;
|
|
171
|
+
if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) return { ...literal(ts.isNumericLiteral(node) ? Number(node.text) : node.text), ...(strict ? { origin: node, via } : {}) };
|
|
172
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword || node.kind === ts.SyntaxKind.FalseKeyword) return literal(node.kind === ts.SyntaxKind.TrueKeyword);
|
|
173
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) return literal(null);
|
|
174
|
+
if (ts.isIdentifier(node)) {
|
|
175
|
+
if (strict && writes.has(symbol(node))) return unknown("A written binding or object is not a statically known value.");
|
|
176
|
+
if (strict && ["Fragment", "StrictMode"].includes(uiOperation(node, checker))) return { kind: "provider" };
|
|
177
|
+
if (env.has(symbol(node))) {
|
|
178
|
+
const result = resolve(env.get(symbol(node)), next(context));
|
|
179
|
+
return strict && escapes.has(symbol(node)) && (result.kind === "object" || result.kind === "array" || result.kind === "node" && (ts.isObjectLiteralExpression(result.node) || ts.isArrayLiteralExpression(result.node))) ? unknown("An object passed to another call may have been mutated.") : result;
|
|
180
|
+
}
|
|
181
|
+
const owner = declaration(node);
|
|
182
|
+
if (owner && isInside(options.dsRoot, owner.getSourceFile().fileName)) {
|
|
183
|
+
if (isFunction(owner)) return reference(owner, env, via);
|
|
184
|
+
if (ts.isVariableDeclaration(owner) && owner.initializer && owner.parent.flags & ts.NodeFlags.Const) {
|
|
185
|
+
const result = resolve(reference(owner.initializer, env, via), next(context));
|
|
186
|
+
return strict && escapes.has(symbol(node)) && (result.kind === "object" || result.kind === "array" || result.kind === "node" && (ts.isObjectLiteralExpression(result.node) || ts.isArrayLiteralExpression(result.node))) ? unknown("An object passed to another call may have been mutated.") : result;
|
|
187
|
+
}
|
|
188
|
+
if (ts.isBindingElement(owner)) return resolve(boundElement(owner, env, via, context), next(context));
|
|
189
|
+
}
|
|
190
|
+
return node.text === "undefined" && !owner ? literal(undefined) : unknown();
|
|
191
|
+
}
|
|
192
|
+
if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
|
|
193
|
+
const key = ts.isPropertyAccessExpression(node) ? literal(node.name.text) : resolve(reference(node.argumentExpression, env, via), next(context));
|
|
194
|
+
const object = reference(node.expression, env, via);
|
|
195
|
+
if (key.kind === "literal") {
|
|
196
|
+
const selected = get(object, String(key.value), next(context));
|
|
197
|
+
const owner = declaration(node);
|
|
198
|
+
if (selected.kind === "unknown" && owner && isInside(options.dsRoot, owner.getSourceFile().fileName)) {
|
|
199
|
+
if (isFunction(owner)) return reference(owner, env, via);
|
|
200
|
+
if (ts.isVariableDeclaration(owner) && owner.initializer && owner.parent.flags & ts.NodeFlags.Const) return resolve(reference(owner.initializer, env, via), next(context));
|
|
201
|
+
}
|
|
202
|
+
return resolve(selected, next(context));
|
|
203
|
+
}
|
|
204
|
+
const names = keys(object, next(context));
|
|
205
|
+
if (strict) return unknown("A dynamic property selection is not a statically known value.");
|
|
206
|
+
return names.length ? union(names.map(name => get(object, name, next(context)))) : unknown();
|
|
207
|
+
}
|
|
208
|
+
if (ts.isConditionalExpression(node)) {
|
|
209
|
+
const condition = resolve(reference(node.condition, env, via), next(context));
|
|
210
|
+
return condition.kind === "literal" ? resolve(reference(condition.value ? node.whenTrue : node.whenFalse, env, via), next(context)) : union([reference(node.whenTrue, env, via), reference(node.whenFalse, env, via)]);
|
|
211
|
+
}
|
|
212
|
+
if (ts.isBinaryExpression(node)) {
|
|
213
|
+
const left = resolve(reference(node.left, env, via), next(context)), right = reference(node.right, env, via), operator = node.operatorToken.kind;
|
|
214
|
+
if (operator === ts.SyntaxKind.AmpersandAmpersandToken) return left.kind === "literal" ? left.value ? right : literal(undefined) : union([literal(undefined), right]);
|
|
215
|
+
if (operator === ts.SyntaxKind.BarBarToken) return left.kind === "literal" ? left.value ? left : right : union([left, right]);
|
|
216
|
+
if (operator === ts.SyntaxKind.QuestionQuestionToken) return left.kind === "literal" ? left.value == null ? right : left : union([left, right]);
|
|
217
|
+
const other = resolve(right, next(context));
|
|
218
|
+
if (left.kind === "literal" && other.kind === "literal" && [ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken].includes(operator)) return literal(operator === ts.SyntaxKind.EqualsEqualsEqualsToken ? left.value === other.value : left.value !== other.value);
|
|
219
|
+
}
|
|
220
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
|
|
221
|
+
const operand = resolve(reference(node.operand, env, via), next(context));
|
|
222
|
+
return operand.kind === "literal" ? literal(!operand.value) : unknown();
|
|
223
|
+
}
|
|
224
|
+
if (ts.isCallExpression(node) && !preserveCall(node.expression)) {
|
|
225
|
+
if (strict && uiOperation(node.expression, checker) === "createContext") return { kind: "context" };
|
|
226
|
+
if (["memo", "forwardRef"].includes(uiOperation(node.expression, checker))) return resolve(reference(node.arguments[0], env, via), next(context));
|
|
227
|
+
const fn = resolve(reference(node.expression, env, via), next(context));
|
|
228
|
+
if (fn.kind === "node" && isFunction(fn.node)) {
|
|
229
|
+
const outputs = returns(fn, node.arguments.map(argument => reference(argument, env, via)), next(context));
|
|
230
|
+
return withVia(resolve(union(outputs), next(context)), outputs.flatMap(item => item.via ?? []));
|
|
231
|
+
}
|
|
232
|
+
return unknown(`Call ${node.expression.getText().slice(0, 80)} could not be traced to a local function.`);
|
|
233
|
+
}
|
|
234
|
+
return { ...value, node };
|
|
235
|
+
}
|
|
236
|
+
function arrays(value, context) {
|
|
237
|
+
value = resolve(value, next(context));
|
|
238
|
+
if (value.kind === "array") return value.values;
|
|
239
|
+
if (value.kind === "node" && ts.isArrayLiteralExpression(value.node)) return value.node.elements.map(node => reference(node, value.env, value.via));
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function props(node, env = new Map(), via = []) {
|
|
244
|
+
return { kind: "object", layers: node.attributes.properties.map(attribute => ts.isJsxSpreadAttribute(attribute) ? reference(attribute.expression, env, via) : new Map([[attribute.name.text, attribute.initializer ? ts.isJsxExpression(attribute.initializer) ? reference(attribute.initializer.expression, env, via) : reference(attribute.initializer, env, via) : literal(true)]])) };
|
|
245
|
+
}
|
|
246
|
+
return { state, next, at, resolve, get, arrays, returns, props, declaration };
|
|
247
|
+
}
|
|
@@ -11,17 +11,26 @@ export async function openBehaviorScenario(page, checkId, { timeout = 30000 } =
|
|
|
11
11
|
const check = request.checks.find(check => check.id === checkId);
|
|
12
12
|
const url = check && request.scenarios[check.scenario];
|
|
13
13
|
if (!url) throw new Error("This check has no managed browser scenario. StrictMode profiles must supply a project development harness; production preview bundles do not replay React development effects.");
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const failures = [];
|
|
15
|
+
const failed = request => {
|
|
16
|
+
if (failures.length < 5) failures.push(`${request.method()} ${request.url().slice(0, 300)}: ${request.failure()?.errorText ?? "request failed"}`);
|
|
17
|
+
};
|
|
18
|
+
page.on("requestfailed", failed);
|
|
19
|
+
try {
|
|
20
|
+
await page.goto(url, { waitUntil: "load", timeout });
|
|
21
|
+
const end = Date.now() + timeout;
|
|
22
|
+
while (Date.now() < end) {
|
|
23
|
+
for (const frame of page.frames().filter(frame => frame !== page.mainFrame())) {
|
|
24
|
+
const state = await frame.evaluate(() => ({ state: document.documentElement.dataset.adsPreviewState, id: document.documentElement.dataset.adsScenario, message: document.getElementById("ads-preview-status")?.textContent })).catch(() => ({}));
|
|
25
|
+
if (state.id === check.scenario && state.state === "ready") return frame;
|
|
26
|
+
if (state.id === check.scenario && state.state === "error") throw new Error(state.message || "The MCP App failed before verification.");
|
|
27
|
+
}
|
|
28
|
+
const error = await page.evaluate(() => document.querySelector('#status[data-error="true"]')?.textContent).catch(() => null);
|
|
29
|
+
if (error) throw new Error(error);
|
|
30
|
+
await page.waitForTimeout(50);
|
|
21
31
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
throw new Error("Timed out waiting for the selected MCP App scenario to become current and ready. Inspect ads_status and ads://project/build.");
|
|
32
|
+
throw new Error("Timed out waiting for the selected MCP App scenario to become current and ready. Inspect ads_status and ads://project/build.");
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Scenario ${check.scenario}: ${error.message}${failures.length ? `\nFailed browser requests:\n${failures.join("\n")}` : ""}`, { cause: error });
|
|
35
|
+
} finally { page.off("requestfailed", failed); }
|
|
27
36
|
}
|
|
@@ -6,15 +6,19 @@ module.exports = class AdsBehaviorReporter {
|
|
|
6
6
|
constructor() {
|
|
7
7
|
this.request = JSON.parse(readFileSync(process.env.ADS_VERIFY_REQUEST, "utf8"));
|
|
8
8
|
this.cases = [];
|
|
9
|
+
this.errors = [];
|
|
9
10
|
}
|
|
10
11
|
onTestEnd(test, result) {
|
|
11
12
|
const file = path.relative(this.request.projectRoot, test.location.file).replaceAll("\\", "/");
|
|
12
13
|
for (const tag of test.tags ?? []) {
|
|
13
14
|
if (!tag.startsWith("@ads:")) continue;
|
|
14
|
-
this.cases.push({ id: tag.slice(5), file, status: result.status === "passed" && test.expectedStatus === "passed" ? "passed" : ["skipped", "interrupted"].includes(result.status) ? "skipped" : "failed", message: result.errors?.map(error => error.message).join("\n").slice(0, 4000) });
|
|
15
|
+
this.cases.push({ id: tag.slice(5), file, status: result.status === "passed" && test.expectedStatus === "passed" ? "passed" : ["skipped", "interrupted"].includes(result.status) ? "skipped" : "failed", message: result.errors?.map(error => error.message || error.stack || error.value || "The browser runner reported an error without details.").join("\n").slice(0, 4000) });
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
onError(error) {
|
|
19
|
+
if (this.errors.length < 5) this.errors.push(String(error.message || error.stack || error.value || "The browser runner reported a suite error without details.").slice(0, 4000));
|
|
20
|
+
}
|
|
17
21
|
onEnd() {
|
|
18
|
-
writeFileSync(process.env.ADS_VERIFY_REPORT, JSON.stringify({ schemaVersion: 1, runId: this.request.runId, cases: this.cases.slice(0, 500) }));
|
|
22
|
+
writeFileSync(process.env.ADS_VERIFY_REPORT, JSON.stringify({ schemaVersion: 1, runId: this.request.runId, cases: this.cases.slice(0, 500), errors: this.errors }));
|
|
19
23
|
}
|
|
20
24
|
};
|
package/dist/verification.mjs
CHANGED
|
@@ -170,7 +170,11 @@ export function createVerificationController(root) {
|
|
|
170
170
|
if (profile.mode === "browser" && group.some(check => check.scenario)) {
|
|
171
171
|
const { startAdsMcp } = await import("./mcp/server.mjs");
|
|
172
172
|
host ??= await startAdsMcp(root, { stdio: false, showcase: true });
|
|
173
|
-
for (const check of group.filter(check => check.scenario)) {
|
|
173
|
+
for (const check of group.filter(check => check.scenario)) {
|
|
174
|
+
const url = new URL(host.url), scenario = context.scenarios.find(entry => entry.id === check.scenario);
|
|
175
|
+
url.searchParams.set(scenario?.kind === "tokens" ? "category" : "scenario", check.scenario);
|
|
176
|
+
scenarios[check.scenario] = url.href;
|
|
177
|
+
}
|
|
174
178
|
}
|
|
175
179
|
const requestContext = { schemaVersion: 1, runId, projectRoot: root, framework: options.config.framework, profile: profileName, mode: profile.mode ?? "unit", checks: group.map(({ contract: _contract, ...check }) => check), scenarios };
|
|
176
180
|
writeFileSync(request, JSON.stringify(requestContext));
|
|
@@ -182,19 +186,24 @@ export function createVerificationController(root) {
|
|
|
182
186
|
if (!existsSync(report) || realpathSync(report) !== report || lstatSync(report).size > 1024 * 1024) throw new Error("Runner produced no valid bounded verification report. A successful exit alone is not passing evidence.");
|
|
183
187
|
reportValue = JSON.parse(readFileSync(report, "utf8"));
|
|
184
188
|
if (reportValue.schemaVersion !== 1 || reportValue.runId !== runId || !Array.isArray(reportValue.cases) || reportValue.cases.length > 500) throw new Error("Runner report has the wrong run ID/schema or too many cases.");
|
|
185
|
-
} catch (error) { runnerError = error; diagnostics.push({ rule: "behavior-runner", message: error.message, output: error.output?.slice(-4000), profile: profileName }); }
|
|
189
|
+
} catch (error) { runnerError = error; reportValue = undefined; diagnostics.push({ rule: "behavior-runner", message: error.message, output: error.output?.slice(-4000), profile: profileName }); }
|
|
190
|
+
const suiteErrors = Array.isArray(reportValue?.errors) ? reportValue.errors.slice(0, 5).map(error => String(error).slice(0, 1000)) : [];
|
|
191
|
+
const runnerFailure = run && (run.code !== 0 || suiteErrors.length) ? `Registered runner ${profileName} ${run.code !== 0 ? `exited with code ${run.code ?? "unknown"}` : "reported a suite error"}. ${suiteErrors.join("; ") || reportValue?.cases.filter(item => item?.status === "failed").slice(0, 3).map(item => `${item.id}: ${item.message || "failed without a case diagnostic"}`).join("; ") || "Inspect the runner output and verification report."}`.slice(0, 3000) : undefined;
|
|
192
|
+
if (runnerFailure) diagnostics.push({ rule: "behavior-runner", message: runnerFailure, output: run.output?.slice(-4000), profile: profileName });
|
|
186
193
|
const afterOptions = loadConfig(root), afterContext = inputContext(afterOptions);
|
|
187
194
|
for (const check of group) {
|
|
188
195
|
const file = slash(path.relative(root, path.resolve(root, path.dirname(check.contract.file), check.file)));
|
|
189
196
|
const matches = reportValue?.cases.filter(item => item && item.id === check.case && item.file === file) ?? [];
|
|
190
|
-
|
|
197
|
+
const reportedStatus = matches.length && matches.every(item => item.status === "passed") ? "passed" : matches.length && matches.every(item => item.status === "skipped") ? "skipped" : "failed";
|
|
198
|
+
let status = !run || runnerFailure ? "failed" : reportedStatus;
|
|
191
199
|
if (runnerError?.code === "ENOENT") status = "unavailable";
|
|
192
200
|
const current = behaviorInputs(afterOptions, check.contract, check, afterContext).revision === check.inputRevision;
|
|
193
201
|
if (!current) status = "stale";
|
|
194
202
|
if (signal.aborted) status = "cancelled";
|
|
195
203
|
results.push({ unit: check.unit, check: check.id, file: check.file, case: check.case, profile: profileName, status, current, revision: check.inputRevision, runId, completedAt: new Date().toISOString(),
|
|
196
204
|
previewRevision: profile.mode === "browser" ? host?.previewRevision() ?? readPreviewManifest(options)?.revision ?? null : null,
|
|
197
|
-
|
|
205
|
+
...(runnerFailure ? { reportedStatus, runnerExitCode: run.code } : {}),
|
|
206
|
+
message: runnerError?.message ?? (matches.filter(item => item.status !== "passed").map(item => String(item.message || `Case reported ${item.status} without a diagnostic.`).slice(0, 2000)).join("\n") || (!matches.length ? "The selected case did not execute/report. Missing and skipped cases do not pass." : runnerFailure ? `This case reported ${reportedStatus}, but the complete run did not pass. ${runnerFailure}` : "")), report: slash(path.relative(root, report)) });
|
|
198
207
|
}
|
|
199
208
|
if (signal.aborted) break;
|
|
200
209
|
}
|
package/docs/ADS.md
CHANGED
|
@@ -141,7 +141,11 @@ TSX or JSON equivalents are supported. An empty fixture is valid without inputs.
|
|
|
141
141
|
`scenario-contract`, `scenario-render` and `scenario-coverage` checks require valid
|
|
142
142
|
entries and reachable public render references for every public renderable
|
|
143
143
|
component/pattern, including unused exports and Linaria styled exports. Types, constants and utility functions
|
|
144
|
-
are excluded.
|
|
144
|
+
are excluded. Explicit `covers` entries can receive transitive evidence through a
|
|
145
|
+
rendered parent's returned JSX, fixture props/defaults and known framework
|
|
146
|
+
wrappers/providers. Unknown branches contribute only their common public parts;
|
|
147
|
+
unused JSX and callbacks contribute none. Bounded tracing does not automatically
|
|
148
|
+
add dependency APIs to `covers`. Coverage is a static source policy; it does not prove runtime
|
|
145
149
|
mounting, correct props, every branch/state or visual parity. The older
|
|
146
150
|
`showcase-coverage` policy also checks application render references.
|
|
147
151
|
|
|
@@ -156,6 +160,11 @@ or applies the right CSS property. Browser review still verifies the samples.
|
|
|
156
160
|
Scenarios and fixture helpers are development-only wherever colocated. Runtime
|
|
157
161
|
source and the public barrel cannot import or re-export them. Showcase/scenario
|
|
158
162
|
code defines no CSS, custom classes or native controls; use public ADS APIs.
|
|
163
|
+
Scenarios may consume public class helpers whose returned styles trace to owned
|
|
164
|
+
Linaria. Stable hooks in that owner may accompany real styles; strings forwarded
|
|
165
|
+
from scenarios, hook-only returns and untraceable outputs remain invalid.
|
|
166
|
+
`exercises` does not authorize classes. See the skill-local
|
|
167
|
+
[scenario contract guide](../skills/ads-designer/references/scenarios.md).
|
|
159
168
|
Neither ADS implementations nor scenarios import application code. Live business
|
|
160
169
|
data belongs to application adapters; ADS receives inputs or injected callbacks.
|
|
161
170
|
Direct global `fetch`, XHR, WebSocket and EventSource use is rejected. Renderer
|
|
@@ -200,6 +209,11 @@ Measured runtime variables retain their existing exact `styleWrites` boundary.
|
|
|
200
209
|
|
|
201
210
|
A colocated scenario sets `kind:"tokens"` and declares real fixture `samples`
|
|
202
211
|
consumed by a public review pattern. Its ID still derives from its source path.
|
|
212
|
+
Discovery attaches its owner's registered definition sheet as `stylesheets` on
|
|
213
|
+
the generated scenario record; `previewEntriesPlugin` imports it directly into
|
|
214
|
+
that preview's module graph. CSS-only package side effects can then tree-shake
|
|
215
|
+
the runtime component without dropping the token definitions. Keep the runtime
|
|
216
|
+
CSS import for product use; the token scenario need not import or render its owner.
|
|
203
217
|
Every local token needs this real sample coverage, just like shared tokens.
|
|
204
218
|
Definitions, metadata, fixture and token scenario belong to the same edit unit.
|
|
205
219
|
Manifests/fixtures are development inputs; production includes the runtime's
|
|
@@ -400,10 +414,11 @@ Validate accepted and rejected cases, configuration, and false-positive limits.
|
|
|
400
414
|
|
|
401
415
|
## Bootstrap and updates
|
|
402
416
|
|
|
403
|
-
The atomic composition
|
|
404
|
-
|
|
405
|
-
MCP serves
|
|
406
|
-
|
|
417
|
+
The atomic composition and scenario contract guides live in each skill's
|
|
418
|
+
`references/atomic-styles.md` and `references/scenarios.md`. The maintained copies
|
|
419
|
+
are in `skills/ads-designer/references/`; MCP serves those packaged references.
|
|
420
|
+
`npm run sync:skill-references` copies them to the other skills for standalone use;
|
|
421
|
+
`npm run check:skill-references`
|
|
407
422
|
rejects drift during the tool build. Published packages include these references
|
|
408
423
|
under `dist/skills/`.
|
|
409
424
|
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -146,6 +146,14 @@ of every unused variant. Atomic composition still requires care with the cascade
|
|
|
146
146
|
Apply extraction to application and project preview builds, preserve intentional
|
|
147
147
|
foundation CSS, and inspect compiled output when performance matters. The
|
|
148
148
|
[implementation guide](../design-system/README.md#bundling-notes) covers these details.
|
|
149
|
+
Both extraction pipelines use the build-only `@reqvire-org/ads/linaria` tag
|
|
150
|
+
resolver. It delegates atomization and nesting to the project's installed Linaria
|
|
151
|
+
processor while preserving custom-property token streams around that pass.
|
|
152
|
+
Arithmetic becomes meaningful after `var()` substitution, so stripping whitespace
|
|
153
|
+
can invalidate otherwise valid source. Verify emitted CSS and computed browser
|
|
154
|
+
values; source guards alone cannot establish extraction correctness. The
|
|
155
|
+
skill-local [atomic styling guide](../skills/ads-designer/references/atomic-styles.md#preserve-custom-property-arithmetic-during-extraction)
|
|
156
|
+
documents integration and source-workaround semantics.
|
|
149
157
|
|
|
150
158
|
## Public APIs preserve the boundary
|
|
151
159
|
|
|
@@ -286,6 +294,14 @@ their required parent. Every declared token and every public renderable componen
|
|
|
286
294
|
and pattern needs addressable coverage. Token references must exist in the real
|
|
287
295
|
foundation; claimed token/UI coverage must be reachable from the scenario entry.
|
|
288
296
|
Types, constants and utilities do not require UI scenarios.
|
|
297
|
+
Explicitly declared public children can share a parent's scenario when bounded
|
|
298
|
+
source tracing reaches them through its returned JSX and selected props/defaults.
|
|
299
|
+
Opaque conditional branches do not grant speculative coverage. Scenarios may
|
|
300
|
+
consume deliberate public class helpers when their returned styles retain
|
|
301
|
+
runtime-owned Linaria provenance; stable owner-authored hooks may accompany real
|
|
302
|
+
styles. This preserves ownership rather than granting scenario styling freedom.
|
|
303
|
+
The skill-local [scenario guide](../skills/ads-designer/references/scenarios.md)
|
|
304
|
+
explains evidence, limits and diagnostics.
|
|
289
305
|
|
|
290
306
|
After source changes, validation and compilation must both succeed before a new
|
|
291
307
|
graph becomes current. MCP announces build/resource updates. The built-in client
|
|
@@ -418,6 +434,8 @@ verification, and the browser check does not judge design quality.
|
|
|
418
434
|
An optional owner-local token namespace keeps component/pattern constants beside
|
|
419
435
|
their consumer. Its definition-only stylesheet contains root/theme custom
|
|
420
436
|
properties and is imported by the runtime owner; UI styling remains in Linaria.
|
|
437
|
+
Independent owner-token preview entries also import the registered definition
|
|
438
|
+
sheet directly, so tree-shaking an unused runtime owner cannot remove their values.
|
|
421
439
|
Namespaces, aliases, ownership and actual colocated sample coverage are checked.
|
|
422
440
|
The shared foundation remains the cross-owner vocabulary. See the
|
|
423
441
|
[owner-token contract](ADS.md#owner-local-tokens).
|
package/docs/BEHAVIORS.md
CHANGED
|
@@ -140,7 +140,17 @@ and any required test setup in that project. The ADS tooling host gains no
|
|
|
140
140
|
framework or browser dependency from a profile.
|
|
141
141
|
|
|
142
142
|
The Playwright adapter appends selected file paths, its reporter and a generated
|
|
143
|
-
artifact directory.
|
|
143
|
+
artifact directory.
|
|
144
|
+
|
|
145
|
+
Runner failures remain blocking even when some selected cases reported passed.
|
|
146
|
+
Those results retain `reportedStatus` and `runnerExitCode`, and explain the suite
|
|
147
|
+
failure rather than returning an empty message. Suite-level browser errors and
|
|
148
|
+
bounded runner output appear in diagnostics. `openBehaviorScenario` includes the
|
|
149
|
+
scenario ID and failed browser requests in startup failures; App resource errors
|
|
150
|
+
identify the resource URI. Failed assertions and startup errors are not retried
|
|
151
|
+
automatically. Fix or investigate the failure before explicitly verifying again.
|
|
152
|
+
|
|
153
|
+
Use native test tags for stable case identity:
|
|
144
154
|
|
|
145
155
|
```ts
|
|
146
156
|
import { test, expect } from "@playwright/test";
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.3.10
|
|
4
|
+
|
|
5
|
+
- Attach registered owner-local token sheets to independently compiled token
|
|
6
|
+
previews, preserving definitions under CSS-only package side effects without
|
|
7
|
+
retaining runtime owners or loading peer sheets. Verify resource closure in
|
|
8
|
+
React/Preact and rendered samples in a sandboxed App in both themes.
|
|
9
|
+
- Route managed browser checks for owner-local token scenarios through the
|
|
10
|
+
discovered token category, independent of their component/pattern file paths.
|
|
11
|
+
|
|
12
|
+
## 0.3.9
|
|
13
|
+
|
|
14
|
+
- Credit explicitly declared public child renders reached through parents,
|
|
15
|
+
fixture props/defaults and known framework wrappers/providers. Share bounded
|
|
16
|
+
source evaluation with atomic review; unresolved paths, unused JSX and
|
|
17
|
+
callbacks do not manufacture child coverage.
|
|
18
|
+
- Allow scenario class helpers with proven runtime Linaria provenance and stable
|
|
19
|
+
owner-authored hooks alongside real styles. Reject consumer strings, private
|
|
20
|
+
styles, empty templates and untraceable returns; document the contract in all
|
|
21
|
+
five portable skills and `ads://guides/scenarios`.
|
|
22
|
+
- Preserve custom-property token streams through Linaria atomic extraction with
|
|
23
|
+
the build-only `@reqvire-org/ads/linaria` resolver. Integrate the resolver in
|
|
24
|
+
product and MCP preview starter builds; verify extracted arithmetic and real
|
|
25
|
+
browser transforms using generic fixtures with and without CSS minification.
|
|
26
|
+
- Explain suite-wide verification failures on otherwise passing cases, retain
|
|
27
|
+
their reported status, and surface runner-level errors. Include scenario IDs,
|
|
28
|
+
failed requests and App resource URIs in startup diagnostics without retrying
|
|
29
|
+
failed checks automatically.
|
|
4
30
|
|
|
5
31
|
## 0.3.8
|
|
6
32
|
|
package/docs/MCP.md
CHANGED
|
@@ -441,6 +441,12 @@ project's normal lint/build gates.
|
|
|
441
441
|
|
|
442
442
|
`ads_scenarios` discovers path-derived IDs for token, component, pattern and
|
|
443
443
|
composition scenarios. `ads_catalog` links public exports to their coverage.
|
|
444
|
+
`covers` can include public children reached through the rendered parent's
|
|
445
|
+
returned JSX with known props/defaults. Public class helpers require verified
|
|
446
|
+
runtime Linaria provenance; `exercises` alone grants no class permission. The
|
|
447
|
+
`ads://guides/scenarios` resource and each skill's
|
|
448
|
+
[local scenario reference](../skills/ads-designer/references/scenarios.md) describe
|
|
449
|
+
the bounded checks and diagnostics.
|
|
444
450
|
`ads_show_scenario({id})` selects an independently mountable entry with its own
|
|
445
451
|
fixtures. `ads_show_tokens({category})` selects a discovered token scenario;
|
|
446
452
|
omitting category selects the first token entry. The tool contains no project
|
|
@@ -554,9 +560,19 @@ framework compilation and Linaria extraction. The starter's
|
|
|
554
560
|
- Its `buildGraph(entries, options, track)` adapter runs one multi-entry Vite build
|
|
555
561
|
with `previewEntriesPlugin()` and `createPreviewResources()` from
|
|
556
562
|
`@reqvire-org/ads/scenarios/vite`.
|
|
563
|
+
Generated owner-token entries include `stylesheets` derived from the registered
|
|
564
|
+
owner manifest. Pass the entries intact: the plugin imports those definition
|
|
565
|
+
sheets even when the runtime owner is tree-shaken. A replacement entry plugin
|
|
566
|
+
must preserve these dependencies without importing unrelated owners.
|
|
557
567
|
- Keep `preserveEntrySignatures: "strict"`, `cssCodeSplit: true`,
|
|
558
568
|
`assetsInlineLimit: 0`, `modulePreload: false`, and `write: false`. Include the
|
|
559
569
|
supplied dependency-tracking plugin and the project's Linaria/framework plugins.
|
|
570
|
+
- Use `linariaTagResolver` from `@reqvire-org/ads/linaria` in WyW's `tagResolver`
|
|
571
|
+
option in both the product build and preview builder. It preserves opaque
|
|
572
|
+
custom-property values through atomic extraction, including whitespace needed
|
|
573
|
+
by arithmetic later substituted into `calc()`. Existing custom builders need
|
|
574
|
+
this integration explicitly; disabling minification does not fix extraction.
|
|
575
|
+
See the skill-local [atomic styling guide](../skills/ads-designer/references/atomic-styles.md#preserve-custom-property-arithmetic-during-extraction).
|
|
560
576
|
- `showcase/mcp/main.tsx` exports `mountScenario(Scenario, container)` and returns
|
|
561
577
|
an unmount callback. It imports the same project foundation used in production.
|
|
562
578
|
It creates no App bridge; ADS supplies that bridge once.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reqvire-org/ads",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A design system your agent can see and shape. Your components. Your look. Your code.",
|
|
6
6
|
"repository": {
|
|
@@ -87,6 +87,14 @@
|
|
|
87
87
|
"vite": "^6.0.7"
|
|
88
88
|
},
|
|
89
89
|
"license": "MIT",
|
|
90
|
+
"peerDependencies": {
|
|
91
|
+
"@linaria/atomic": "^8.0.0"
|
|
92
|
+
},
|
|
93
|
+
"peerDependenciesMeta": {
|
|
94
|
+
"@linaria/atomic": {
|
|
95
|
+
"optional": true
|
|
96
|
+
}
|
|
97
|
+
},
|
|
90
98
|
"engines": {
|
|
91
99
|
"node": ">=22.12.0"
|
|
92
100
|
},
|
|
@@ -96,6 +104,7 @@
|
|
|
96
104
|
"exports": {
|
|
97
105
|
".": "./dist/index.mjs",
|
|
98
106
|
"./oxlint": "./dist/oxlint.mjs",
|
|
107
|
+
"./linaria": "./dist/linaria.mjs",
|
|
99
108
|
"./tokens": "./dist/contracts/tokens.json",
|
|
100
109
|
"./mcp": "./dist/mcp/server.mjs",
|
|
101
110
|
"./mcp/build": "./dist/mcp/build-status.mjs",
|