agentready-design-cli 0.2.0 → 0.3.0

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.
@@ -1020,8 +1020,52 @@ var allChecks = {
1020
1020
  ...checks8
1021
1021
  };
1022
1022
 
1023
+ // src/fusion-annotations.ts
1024
+ var FUSION_PATHS = {
1025
+ "1.1": "Builder Fusion's `npx @builder.io/dev-tools@latest index-repo` auto-detects design tokens in CSS/Tailwind/SCSS at index time and exposes them to the agent and to design mode without requiring a separate DTCG export. Useful for teams that haven't adopted Style Dictionary yet.",
1026
+ "1.2": "If primitives exist in code but no semantic layer has been defined, Fusion's index can pick up CSS variable aliases as a partial semantic layer. For teams without any tokens in code, Design System Intelligence Lite can bootstrap a token set from a Figma file, markdown, or prompt \u2014 no CLI required.",
1027
+ "1.3": 'Once `index-repo` has run, tokens are enumerable to the agent via the Design System Intelligence MCP server and via `@`-mention in chat. This satisfies the "single source" requirement at the agent layer even if the underlying code still has multiple token files.',
1028
+ "1.4": "Builder Fusion's strict mode (project setting) restricts the design mode style picker to indexed tokens only, providing a runtime enforcement layer in addition to (not instead of) lint-time enforcement.",
1029
+ "2.1": "Running `index-repo` against a component library produces a machine-readable component index that Fusion and any MCP-compatible agent (Claude Code, Cursor) can consume. This is an alternative to publishing a CEM if the goal is agent consumption rather than tooling interoperability.",
1030
+ "3.1": "The Design System Intelligence MCP server can serve as the canonical agent-facing entry point even if human-facing docs remain scattered. Note that this addresses agent discoverability, not human discoverability.",
1031
+ "3.4": "Builder's Design System Intelligence produces LLM-friendly documentation derived from the indexed codebase, serving a similar function to `llms.txt` for agents using the DSI MCP server. Publishing `llms.txt` is still recommended for agents not using the MCP server.",
1032
+ "4.3": "Index existing pages or templates as additional repos in the Fusion workspace \u2014 Fusion will treat them as pattern references the agent can draw from when generating new pages. This works as a stopgap if a formal `recipes/` directory doesn't exist yet.",
1033
+ "5.1": "Fusion reads `AGENTS.md` from the project root as one of its instruction sources. Hand-curate it; auto-generation is discouraged by the rubric and by Builder's own guidance.",
1034
+ "5.2": "The Design System Intelligence MCP server ships with Builder Fusion and exposes the indexed component and token data to any MCP-compatible agent. This is the lowest-friction way to satisfy 5.2 if the system is already indexed.",
1035
+ "5.3": "Builder Fusion reads `.builder/rules/` files and `AGENTS.md` as always-on context. Keep foundational rules (spacing, color, type) at the top level and component-specific guidance in named files (e.g. `flashbar-variants.mdc`) so the agent can resolve them just-in-time rather than loading everything every turn.",
1036
+ "5.4": "Once components are indexed, Fusion resolves canonical import paths automatically and `@`-mention in chat enforces stable identifiers regardless of file structure.",
1037
+ "6.3": "Builder Fusion supports two-index workflows for migrations \u2014 index both the legacy and target versions, and the agent can reason about both during a migration. This operationalizes version targeting rather than relying on documentation alone.",
1038
+ "7.1": "If Storybook stories exist, indexing them via `index-repo` pulls usage examples into the agent's context. Stories then double as agent training data, not just human documentation."
1039
+ };
1040
+ var COMMON_FAILURE_MODES = {
1041
+ "1.1": "Tokens are detected at index time but fail to resolve in rendered output \u2014 the agent uses the correct token reference, but the wrong value renders in preview because the runtime resolution chain is broken.",
1042
+ "1.2": "Without a semantic layer, the agent picks primitive tokens by visual similarity rather than intent (e.g., `gray-700` instead of `text-default`), producing output that drifts from the system as it scales.",
1043
+ "1.3": "Multiple token sources exist (one in code, one in Figma, one in a doc) and the agent silently picks one \u2014 usually the most recently touched \u2014 without surfacing the conflict to the user.",
1044
+ "2.1": "Without a machine-readable manifest, the agent infers props from usage examples and gets variants subtly wrong (correct name, wrong values), which often passes review until QA.",
1045
+ "2.3": "When composition rules aren't explicit, the agent nests components in ways the library wasn't designed for (e.g., Button-in-Button, nested form controls) and the failure only surfaces at integration time.",
1046
+ "2.4": "Without documented anti-patterns, when the agent hits a build error during a multi-step plan it abandons design-system components and inlines raw markup or SVGs to make the error go away, rather than fixing within-system.",
1047
+ "3.3": "With only happy-path examples, the agent treats edge cases (loading, empty, error states) as out-of-scope and silently omits them from generated output.",
1048
+ "4.1": "Without layout primitives, the agent reaches for raw Flexbox and CSS Grid with hardcoded values, producing layouts that pass visual review but break responsive behavior.",
1049
+ "4.3": "When no patterns layer exists, the agent reconstructs common compositions (empty states, page headers, data table toolbars) from primitives each time, producing inconsistent variants of the same pattern across a codebase.",
1050
+ "5.3": "Rules files load into context but the agent skips reading component-scoped rules at the moment they apply, generating output that violates documented per-component guidance even though the rule was technically available.",
1051
+ "6.2": "Without machine-readable deprecation metadata, the agent generates code using deprecated APIs because there's no signal that they're deprecated \u2014 the components still exist, the props still work, the docs still describe them.",
1052
+ "7.2": "Without visual regression, drift in rendered output (wrong fonts, off-by-a-token spacing) ships unnoticed until a designer reviews production.",
1053
+ "8.1": "Without evals, regressions in agent behavior under stress (build errors, missing components, ambiguous prompts) go undetected. Teams discover them in customer POCs rather than in CI."
1054
+ };
1055
+
1023
1056
  // src/runner.ts
1024
1057
  import { readFile as readFile2 } from "fs/promises";
1058
+ var CLI_VERSION = "0.3.0";
1059
+ function annotate(criterion) {
1060
+ const fusionPath = FUSION_PATHS[criterion.id];
1061
+ const commonFailureMode = COMMON_FAILURE_MODES[criterion.id];
1062
+ if (!fusionPath && !commonFailureMode) return criterion;
1063
+ return {
1064
+ ...criterion,
1065
+ ...fusionPath ? { fusionPath } : {},
1066
+ ...commonFailureMode ? { commonFailureMode } : {}
1067
+ };
1068
+ }
1025
1069
  async function runAssessment(opts) {
1026
1070
  const ctx = new CheckContext(opts.target);
1027
1071
  let existing = null;
@@ -1036,21 +1080,23 @@ async function runAssessment(opts) {
1036
1080
  for (const entry of RUBRIC) {
1037
1081
  const existingHit = existing?.criteria.find((c) => c.id === entry.id);
1038
1082
  if (existingHit && existingHit.status === "scored") {
1039
- criteria.push(existingHit);
1083
+ criteria.push(annotate(existingHit));
1040
1084
  continue;
1041
1085
  }
1042
1086
  const check = allChecks[entry.id];
1043
1087
  if (!check) {
1044
- criteria.push({
1045
- id: entry.id,
1046
- category: entry.category,
1047
- title: entry.title,
1048
- score: null,
1049
- status: "pending",
1050
- pending: "requires-agent",
1051
- rationale: "No deterministic check implemented; requires an agent.",
1052
- evidence: []
1053
- });
1088
+ criteria.push(
1089
+ annotate({
1090
+ id: entry.id,
1091
+ category: entry.category,
1092
+ title: entry.title,
1093
+ score: null,
1094
+ status: "pending",
1095
+ pending: "requires-agent",
1096
+ rationale: "No deterministic check implemented; requires an agent.",
1097
+ evidence: []
1098
+ })
1099
+ );
1054
1100
  continue;
1055
1101
  }
1056
1102
  try {
@@ -1066,30 +1112,32 @@ async function runAssessment(opts) {
1066
1112
  ...result.rationale ? { rationale: result.rationale } : {},
1067
1113
  ...result.suggestion ? { suggestion: result.suggestion } : {}
1068
1114
  };
1069
- criteria.push(criterion);
1115
+ criteria.push(annotate(criterion));
1070
1116
  } catch (err) {
1071
- criteria.push({
1072
- id: entry.id,
1073
- category: entry.category,
1074
- title: entry.title,
1075
- score: null,
1076
- status: "error",
1077
- rationale: `Check threw: ${err.message}`,
1078
- evidence: []
1079
- });
1117
+ criteria.push(
1118
+ annotate({
1119
+ id: entry.id,
1120
+ category: entry.category,
1121
+ title: entry.title,
1122
+ score: null,
1123
+ status: "error",
1124
+ rationale: `Check threw: ${err.message}`,
1125
+ evidence: []
1126
+ })
1127
+ );
1080
1128
  }
1081
1129
  }
1082
1130
  const rollup = computeRollup(criteria);
1083
1131
  const backlog = generateBacklog(criteria);
1084
1132
  return {
1085
- schemaVersion: "0.1.0",
1133
+ schemaVersion: "0.1.1",
1086
1134
  rubricVersion: "0.1.0",
1087
1135
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1088
1136
  target: { path: ctx.root, name: opts.name ?? existing?.target?.name },
1089
1137
  producer: {
1090
1138
  kind: existing ? "merged" : "cli",
1091
1139
  name: "agentready-design-cli",
1092
- version: "0.1.0"
1140
+ version: CLI_VERSION
1093
1141
  },
1094
1142
  criteria,
1095
1143
  rollup,
@@ -1174,7 +1222,11 @@ function renderMarkdown(report) {
1174
1222
  }).filter(Boolean).join("; ");
1175
1223
  if (ev) lines.push(` - _Evidence:_ ${ev}`);
1176
1224
  }
1225
+ if (c.commonFailureMode && c.status === "scored" && c.score !== null && c.score <= 2) {
1226
+ lines.push(` - _Common failure mode:_ ${c.commonFailureMode}`);
1227
+ }
1177
1228
  if (c.suggestion) lines.push(` - _Suggestion:_ ${c.suggestion}`);
1229
+ if (c.fusionPath) lines.push(` - _Fusion path:_ ${c.fusionPath}`);
1178
1230
  }
1179
1231
  }
1180
1232
  lines.push("");
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  generateBacklog,
7
7
  renderMarkdown,
8
8
  runAssessment
9
- } from "./chunk-WHGIRQPX.js";
9
+ } from "./chunk-4AF47E7U.js";
10
10
 
11
11
  // src/cli.ts
12
12
  import { writeFile, mkdir } from "fs/promises";
@@ -76,7 +76,7 @@ You are auditing the current repository against the **Agent-Ready Design v0.1 ru
76
76
 
77
77
  - **5.1** \`AGENTS.md\` (or \`CLAUDE.md\`) exists and is **hand-curated** (per ETH Zurich evidence, auto-generated ones often *hurt* performance).
78
78
  - **5.2** An MCP server (or registry endpoint) exposes the system to agents.
79
- - **5.3** Always-on foundational rules (spacing/color/type) are injected into every agent run via rules files.
79
+ - **5.3** Always-on foundational rules (spacing/color/type) are injected into every agent run via rules files, AND component-scoped rules are organized so the agent can resolve them just-in-time rather than loading every rule every turn. Loading every rule into context per turn is a known anti-pattern that degrades agent output quality.
80
80
  - **5.4** Components are addressable by stable, predictable identifiers (one canonical import path).
81
81
 
82
82
  ### Category 6 \u2014 Distribution & Versioning
@@ -148,7 +148,16 @@ Print this format in your response:
148
148
  - **1.1 Tokens exist as exported, versioned source files. \u2014 N/4**
149
149
  - Rationale: <one sentence>
150
150
  - Evidence: \`tokens/colors.json:1\` \u2026
151
+ - Common failure mode (if scored low): <commonFailureMode if present>
151
152
  - Suggestion: <how to raise one level>
153
+ - Fusion path: <fusionPath if present>
154
+
155
+ Conditional rendering rules:
156
+
157
+ - \`Common failure mode\` line is rendered **only when** the criterion's score is \u2264 2 **and** \`commonFailureMode\` is set on the criterion. Skip the line entirely otherwise.
158
+ - \`Fusion path\` line is rendered **whenever** \`fusionPath\` is set on the criterion, regardless of score. Skip it entirely otherwise.
159
+
160
+ Both fields are optional in the schema \u2014 many criteria will not have either populated, and that's the expected state. Do **not** invent text for criteria that don't already have \`fusionPath\` or \`commonFailureMode\` set in \`agent-ready-report.json\`; just preserve whatever the CLI emitted.
152
161
 
153
162
  \u2026 (continue for every criterion)
154
163
 
@@ -164,7 +173,7 @@ Also write \`agent-ready-report.json\` at the repo root, conforming to the schem
164
173
 
165
174
  \`\`\`jsonc
166
175
  {
167
- "schemaVersion": "0.1.0",
176
+ "schemaVersion": "0.1.1",
168
177
  "rubricVersion": "0.1.0",
169
178
  "generatedAt": "<ISO timestamp>",
170
179
  "target": { "path": "<repo path>", "name": "<optional>" },
@@ -181,7 +190,9 @@ Also write \`agent-ready-report.json\` at the repo root, conforming to the schem
181
190
  { "kind": "file", "path": "tokens/colors.css", "line": 1 },
182
191
  { "kind": "glob", "path": "**/*.tokens.json", "detail": "no matches" }
183
192
  ],
184
- "suggestion": "Add Style Dictionary v4 with DTCG JSON output."
193
+ "suggestion": "Add Style Dictionary v4 with DTCG JSON output.",
194
+ "fusionPath": "<preserve verbatim if present in agent-ready-report.json; otherwise omit>",
195
+ "commonFailureMode": "<preserve verbatim if present in agent-ready-report.json; otherwise omit>"
185
196
  }
186
197
  // \u2026 one entry per criterion (31 total) \u2026
187
198
  ],
@@ -288,7 +299,49 @@ async function gatherSample(ctx) {
288
299
  }
289
300
  return sample;
290
301
  }
302
+ var PENDING_PER_CHUNK = 6;
291
303
  async function callRemote(opts) {
304
+ const pending = opts.report.criteria.filter((c) => c.status === "pending");
305
+ if (pending.length === 0) return { deltas: [] };
306
+ const scored = opts.report.criteria.filter((c) => c.status === "scored");
307
+ const chunks = [];
308
+ for (let i = 0; i < pending.length; i += PENDING_PER_CHUNK) {
309
+ chunks.push(pending.slice(i, i + PENDING_PER_CHUNK));
310
+ }
311
+ const results = await Promise.all(
312
+ chunks.map(
313
+ (chunk) => callRemoteOnce({
314
+ apiUrl: opts.apiUrl,
315
+ sample: opts.sample,
316
+ signal: opts.signal,
317
+ // Each chunk gets its own pending subset plus the full scored context.
318
+ report: {
319
+ ...opts.report,
320
+ criteria: [...chunk, ...scored]
321
+ }
322
+ })
323
+ )
324
+ );
325
+ const deltas = results.flatMap((r) => r.deltas ?? []);
326
+ const totalInput = results.reduce(
327
+ (n, r) => n + (r.meta?.inputTokens ?? 0),
328
+ 0
329
+ );
330
+ const totalOutput = results.reduce(
331
+ (n, r) => n + (r.meta?.outputTokens ?? 0),
332
+ 0
333
+ );
334
+ return {
335
+ deltas,
336
+ meta: {
337
+ model: results[0]?.meta?.model,
338
+ pendingScored: deltas.length,
339
+ inputTokens: totalInput,
340
+ outputTokens: totalOutput
341
+ }
342
+ };
343
+ }
344
+ async function callRemoteOnce(opts) {
292
345
  const url = opts.apiUrl ?? process.env.AGENT_READY_API_URL ?? DEFAULT_API_URL;
293
346
  const res = await fetch(url, {
294
347
  method: "POST",
package/dist/index.d.ts CHANGED
@@ -39,6 +39,10 @@ interface Criterion {
39
39
  rationale?: string;
40
40
  evidence: Evidence[];
41
41
  suggestion?: string;
42
+ /** Builder Fusion-specific path to address this criterion, if one exists. */
43
+ fusionPath?: string;
44
+ /** Short, anonymized description of how this criterion's absence breaks in customer POCs. */
45
+ commonFailureMode?: string;
42
46
  }
43
47
 
44
48
  interface BacklogItem {
@@ -59,7 +63,7 @@ interface Rollup {
59
63
  }
60
64
 
61
65
  interface Report {
62
- schemaVersion: "0.1.0";
66
+ schemaVersion: "0.1.1";
63
67
  rubricVersion: "0.1.0";
64
68
  generatedAt: string;
65
69
  target: { path: string; name?: string; repository?: string };
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  generateBacklog,
8
8
  renderMarkdown,
9
9
  runAssessment
10
- } from "./chunk-WHGIRQPX.js";
10
+ } from "./chunk-4AF47E7U.js";
11
11
  export {
12
12
  RUBRIC,
13
13
  TIER_LABELS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentready-design-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Deterministic checks for the Agent-Ready Design rubric. Run against a design-system repo to score what can be scored without an LLM.",
5
5
  "license": "MIT",
6
6
  "author": "Hunter Gillispie <hunter@builder.io>",