adsa-cli 0.1.1 → 0.1.4
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/README.md +98 -11
- package/bin/adsa.mjs +143 -27
- package/lib/badge.mjs +28 -12
- package/lib/config.mjs +123 -47
- package/lib/history.mjs +9 -7
- package/lib/reference.mjs +32 -0
- package/lib/report.mjs +17 -12
- package/lib/scan.mjs +416 -61
- package/lib/score.mjs +19 -7
- package/lib/target.mjs +82 -0
- package/package.json +1 -1
- package/rubric/reference.json +293 -0
- package/skills/ds-audit/SKILL.md +37 -2
package/lib/score.mjs
CHANGED
|
@@ -10,6 +10,8 @@ const here = dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
export const RUBRIC = JSON.parse(readFileSync(join(here, "..", "rubric", "rubric.json"), "utf8"));
|
|
11
11
|
|
|
12
12
|
const pct = (n) => `${Math.round(n * 100)}%`;
|
|
13
|
+
/** Evidence lines end up on a landing page and in a pull request. They read as English. */
|
|
14
|
+
const plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
13
15
|
|
|
14
16
|
/** What "accessibility documentation" means in the vocabulary of each platform. */
|
|
15
17
|
const A11Y_LABEL = {
|
|
@@ -22,10 +24,13 @@ const A11Y_LABEL = {
|
|
|
22
24
|
const SCORERS = {
|
|
23
25
|
"agent-instructions"(f) {
|
|
24
26
|
const files = f.agentFiles.filter((a) => a.lines > 3);
|
|
25
|
-
|
|
27
|
+
// A file in the package's own directory is about the package. Requiring the
|
|
28
|
+
// name in the text is the right question for a monorepo root, and the wrong one
|
|
29
|
+
// for the AGENTS.md a single-package repository keeps beside its components.
|
|
30
|
+
const main = files.find((a) => a.mentionsPackage) || files.find((a) => a.scope !== "repo") || files[0];
|
|
26
31
|
if (!main) return { score: 1, evidence: ["No AGENTS.md, CLAUDE.md or equivalent in the repository."] };
|
|
27
|
-
const ev = [`${main.file}, ${main.lines} lines.`];
|
|
28
|
-
if (!main.mentionsPackage) {
|
|
32
|
+
const ev = [`${main.label || main.file}, ${main.lines} lines.`];
|
|
33
|
+
if (!main.mentionsPackage && main.scope === "repo") {
|
|
29
34
|
ev.push(`It never mentions ${f.name}, so an agent gets no design-system rules from it.`);
|
|
30
35
|
return { score: 1, evidence: ev };
|
|
31
36
|
}
|
|
@@ -46,15 +51,22 @@ const SCORERS = {
|
|
|
46
51
|
"machine-surface"(f) {
|
|
47
52
|
const m = f.machine;
|
|
48
53
|
const ev = [];
|
|
54
|
+
const served = m.servedMcp || [];
|
|
55
|
+
const siblings = m.siblingClis || [];
|
|
56
|
+
const commands = m.commands || [];
|
|
49
57
|
if (m.mcpInPackage) ev.push(`An MCP server ships inside the package (bin: ${m.binNames.join(", ")}).`);
|
|
58
|
+
if (served.length) ev.push(`This repository serves an MCP server: ${served.slice(0, 3).join(", ")}.`);
|
|
50
59
|
if (m.declaredServers.length) ev.push(`${m.mcpConfigs.join(", ")} registers ${m.declaredServers.join(", ")}.`);
|
|
51
60
|
if (m.cliShipped && !m.mcpInPackage) ev.push(`A CLI ships with the package (bin: ${m.binNames.join(", ")}).`);
|
|
61
|
+
if (siblings.length) ev.push(`A CLI ships from ${siblings.map((c) => `${c.name} (${c.bin.join(", ")})`).slice(0, 2).join(", ")}.`);
|
|
52
62
|
if (m.llmsTxt.length) ev.push(`${m.llmsTxt.join(", ")} present.`);
|
|
53
63
|
if (m.skills.length) ev.push(`${m.skills.length} agent skill${m.skills.length === 1 ? "" : "s"} published.`);
|
|
64
|
+
if (commands.length) ev.push(`${commands.length} agent command${commands.length === 1 ? "" : "s"} published.`);
|
|
54
65
|
if (m.storybookMcp) ev.push("@storybook/addon-mcp is installed, which answers from a running Storybook in this repo only.");
|
|
55
66
|
if (!ev.length) ev.push("No MCP server, no docs CLI, no llms.txt, no published skills: an agent has to read files.");
|
|
56
|
-
const
|
|
57
|
-
|
|
67
|
+
const mcp = m.mcpInPackage || m.declaredServers.length || served.length;
|
|
68
|
+
const queryable = m.cliShipped || siblings.length || m.llmsTxt.length || m.skills.length || commands.length || m.storybookMcp;
|
|
69
|
+
return { score: mcp ? 5 : queryable ? 3 : 1, evidence: ev };
|
|
58
70
|
},
|
|
59
71
|
|
|
60
72
|
"docs-coverage"(f) {
|
|
@@ -74,7 +86,7 @@ const SCORERS = {
|
|
|
74
86
|
const ev = [`${f.guides.length} guides, ${s.blocks} code blocks, ${s.guidesWithPropTable} with a prop table.`];
|
|
75
87
|
if (s.guidesGenerated) ev.push(`${s.guidesGenerated} guides carry a generated marker.`);
|
|
76
88
|
else ev.push("No guide is marked as generated, so every table is hand-maintained.");
|
|
77
|
-
if (s.unknownCount) ev.push(`${s.unknownCount}
|
|
89
|
+
if (s.unknownCount) ev.push(`${plural(s.unknownCount, "import")} in the guides ${s.unknownCount === 1 ? "names a symbol" : "name symbols"} this repo does not export, e.g. ${s.unknownImports.slice(0, 3).map((u) => `${u.name} in ${u.guide}`).join("; ")}.`);
|
|
78
90
|
else ev.push("Every symbol imported in the guides exists in the source.");
|
|
79
91
|
ev.push(s.compiledInCi ? "CI checks the guides against the code." : "Nothing compares the guides to the code.");
|
|
80
92
|
let score = s.compiledInCi && s.guidesGenerated ? 5 : s.guidesGenerated || s.guidesWithPropTable ? 3 : 1;
|
|
@@ -123,7 +135,7 @@ const SCORERS = {
|
|
|
123
135
|
|
|
124
136
|
verification(f) {
|
|
125
137
|
const v = f.verification;
|
|
126
|
-
const ev = [`${v.testFiles
|
|
138
|
+
const ev = [`${plural(v.testFiles, "test file")}, ${plural(v.storyFiles, "story", "stories")}.`];
|
|
127
139
|
const bits = [v.testScript && "test", v.typecheckScript && "typecheck", v.lintScript && "lint"].filter(Boolean);
|
|
128
140
|
ev.push(bits.length ? `Scripts: ${bits.join(", ")}.` : "No test, typecheck or lint script.");
|
|
129
141
|
if (v.workflows.length) ev.push(`CI: ${v.workflows.join(", ")}.`);
|
package/lib/target.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which directory to audit. A design system usually lives in a monorepo, and the
|
|
3
|
+
* package the reader means is rarely the directory they typed: they hand over the
|
|
4
|
+
* repository and expect the tool to find the components.
|
|
5
|
+
*
|
|
6
|
+
* Getting this wrong is the worst thing this tool can do. Every dimension is then
|
|
7
|
+
* measured from inside the wrong folder, and "no agent instructions in the
|
|
8
|
+
* repository" means "none in a subfolder of a repository that has them".
|
|
9
|
+
*/
|
|
10
|
+
import { join, basename } from "node:path";
|
|
11
|
+
import { isDir, readJson, rel } from "./fsx.mjs";
|
|
12
|
+
import { countGuides, workspaceDirs } from "./config.mjs";
|
|
13
|
+
import { countComponents } from "./scan.mjs";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} root the directory the reader named
|
|
17
|
+
* @param {{workspace?:string, noWorkspace?:boolean}} options `--workspace` / `--no-workspace`
|
|
18
|
+
* @returns {{ dir:string, note:string|null, candidates:Array<object>, error?:string }}
|
|
19
|
+
*/
|
|
20
|
+
export function resolveTarget(root, options = {}) {
|
|
21
|
+
if (options.noWorkspace) return { dir: root, note: null, candidates: [] };
|
|
22
|
+
|
|
23
|
+
if (options.workspace) {
|
|
24
|
+
const all = profile(workspaceDirs(root), true);
|
|
25
|
+
const wanted = all.find((c) => c.name === options.workspace || basename(c.dir) === options.workspace || rel(root, c.dir) === options.workspace);
|
|
26
|
+
if (!wanted) {
|
|
27
|
+
const known = all.map((c) => c.name).join(", ") || "none";
|
|
28
|
+
return { dir: root, note: null, candidates: all, error: `No workspace matches "${options.workspace}". This repository has: ${known}.` };
|
|
29
|
+
}
|
|
30
|
+
return { dir: wanted.dir, note: `workspace: audited ${wanted.name} (--workspace)`, candidates: all };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// A root that publishes the components itself is the package, whatever else the
|
|
34
|
+
// repository keeps beside it: its own export map is what a consumer installs.
|
|
35
|
+
const pkg = readJson(join(root, "package.json"));
|
|
36
|
+
const rootExports = Object.keys(pkg?.exports || {}).filter((k) => k.startsWith("./")).length;
|
|
37
|
+
if (rootExports >= 5 || isDir(join(root, "guidelines"))) return { dir: root, note: null, candidates: [] };
|
|
38
|
+
|
|
39
|
+
const workspaces = workspaceDirs(root);
|
|
40
|
+
if (!workspaces.length) return { dir: root, note: null, candidates: [] };
|
|
41
|
+
|
|
42
|
+
// Published packages first. Only when none of them exports a component does a
|
|
43
|
+
// private workspace count: a repository that keeps its components in its own docs
|
|
44
|
+
// app — a registry, a showcase — still keeps them somewhere, and reporting a
|
|
45
|
+
// repository full of components as having none is the worse answer.
|
|
46
|
+
const published = profile(workspaces, false);
|
|
47
|
+
const all = published.some((c) => c.components > 0) ? published : profile(workspaces, true);
|
|
48
|
+
const withComponents = all.filter((c) => c.components > 0);
|
|
49
|
+
if (!withComponents.length) return { dir: root, note: null, candidates: all };
|
|
50
|
+
|
|
51
|
+
const best = withComponents[0];
|
|
52
|
+
const runnerUp = withComponents[1];
|
|
53
|
+
const note = `workspace: audited ${best.name}, ${best.components} components${runnerUp ? ` (next: ${runnerUp.name}, ${runnerUp.components})` : ""}`;
|
|
54
|
+
return { dir: best.dir, note, candidates: withComponents };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Rank the packages by what actually distinguishes a design system: the number of
|
|
59
|
+
* components a consumer can import from it. Ranking by the presence of a `docs/`
|
|
60
|
+
* folder — what this did before — hands the audit to whichever package happens to
|
|
61
|
+
* keep markdown next to it, and a codemod package with thirty migration notes beat
|
|
62
|
+
* the component library every time.
|
|
63
|
+
*
|
|
64
|
+
* `explicit` is a name the reader typed, so nothing is filtered out: a private
|
|
65
|
+
* workspace is still a package somebody can ask to audit.
|
|
66
|
+
*/
|
|
67
|
+
/** `"private": "true"` is in the wild, and reads as published to a strict check. */
|
|
68
|
+
const isPrivate = (pkg) => pkg.private === true || pkg.private === "true";
|
|
69
|
+
|
|
70
|
+
function profile(dirs, explicit) {
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const dir of dirs) {
|
|
73
|
+
const pkg = readJson(join(dir, "package.json"));
|
|
74
|
+
if (!pkg || (isPrivate(pkg) && !explicit)) continue;
|
|
75
|
+
const components = countComponents(dir);
|
|
76
|
+
const guides = countGuides(dir);
|
|
77
|
+
const exports_ = Object.keys(pkg.exports || {}).filter((k) => k.startsWith("./")).length;
|
|
78
|
+
if (!explicit && !components && !guides && !exports_) continue;
|
|
79
|
+
out.push({ dir, name: pkg.name || basename(dir), components, guides, exports: exports_ });
|
|
80
|
+
}
|
|
81
|
+
return out.sort((a, b) => b.components - a.components || b.guides - a.guides || b.exports - a.exports);
|
|
82
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "Public design systems audited with this rubric, at the commit named. Reproduce with `npx adsa-cli audit <clone>`.",
|
|
3
|
+
"rubric": "1.0",
|
|
4
|
+
"measured": "2026-09-10",
|
|
5
|
+
"systems": [
|
|
6
|
+
{
|
|
7
|
+
"name": "Astryx",
|
|
8
|
+
"org": "Meta",
|
|
9
|
+
"repo": "facebook/astryx",
|
|
10
|
+
"commit": "5447429bac",
|
|
11
|
+
"package": "@astryxdesign/core",
|
|
12
|
+
"version": "0.5.4",
|
|
13
|
+
"packageDir": "packages/core",
|
|
14
|
+
"total": 33,
|
|
15
|
+
"max": 45,
|
|
16
|
+
"dimensions": {
|
|
17
|
+
"agent-instructions": 3,
|
|
18
|
+
"machine-surface": 5,
|
|
19
|
+
"docs-coverage": 3,
|
|
20
|
+
"docs-freshness": 3,
|
|
21
|
+
"tokens": 3,
|
|
22
|
+
"patterns": 5,
|
|
23
|
+
"a11y": 3,
|
|
24
|
+
"verification": 5,
|
|
25
|
+
"gap-handling": 3
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "Chakra UI",
|
|
30
|
+
"org": "",
|
|
31
|
+
"repo": "chakra-ui/chakra-ui",
|
|
32
|
+
"commit": "67abe9fb80",
|
|
33
|
+
"package": "@chakra-ui/react",
|
|
34
|
+
"version": "3.37.0",
|
|
35
|
+
"packageDir": "packages/react",
|
|
36
|
+
"total": 29,
|
|
37
|
+
"max": 45,
|
|
38
|
+
"dimensions": {
|
|
39
|
+
"agent-instructions": 3,
|
|
40
|
+
"machine-surface": 5,
|
|
41
|
+
"docs-coverage": 3,
|
|
42
|
+
"docs-freshness": 3,
|
|
43
|
+
"tokens": 5,
|
|
44
|
+
"patterns": 5,
|
|
45
|
+
"a11y": 1,
|
|
46
|
+
"verification": 3,
|
|
47
|
+
"gap-handling": 1
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "React Spectrum",
|
|
52
|
+
"org": "Adobe",
|
|
53
|
+
"repo": "adobe/react-spectrum",
|
|
54
|
+
"commit": "4693fcc844",
|
|
55
|
+
"package": "@react-spectrum/s2",
|
|
56
|
+
"version": "1.7.1",
|
|
57
|
+
"packageDir": "packages/@react-spectrum/s2",
|
|
58
|
+
"total": 25,
|
|
59
|
+
"max": 45,
|
|
60
|
+
"dimensions": {
|
|
61
|
+
"agent-instructions": 3,
|
|
62
|
+
"machine-surface": 5,
|
|
63
|
+
"docs-coverage": 3,
|
|
64
|
+
"docs-freshness": 3,
|
|
65
|
+
"tokens": 3,
|
|
66
|
+
"patterns": 3,
|
|
67
|
+
"a11y": 1,
|
|
68
|
+
"verification": 3,
|
|
69
|
+
"gap-handling": 1
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "shadcn/ui",
|
|
74
|
+
"org": "",
|
|
75
|
+
"repo": "shadcn-ui/ui",
|
|
76
|
+
"commit": "3ba91b1cc8",
|
|
77
|
+
"package": "v4",
|
|
78
|
+
"version": "0.1.0",
|
|
79
|
+
"packageDir": "apps/v4",
|
|
80
|
+
"total": 25,
|
|
81
|
+
"max": 45,
|
|
82
|
+
"dimensions": {
|
|
83
|
+
"agent-instructions": 1,
|
|
84
|
+
"machine-surface": 5,
|
|
85
|
+
"docs-coverage": 3,
|
|
86
|
+
"docs-freshness": 3,
|
|
87
|
+
"tokens": 3,
|
|
88
|
+
"patterns": 5,
|
|
89
|
+
"a11y": 1,
|
|
90
|
+
"verification": 3,
|
|
91
|
+
"gap-handling": 1
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "HeroUI",
|
|
96
|
+
"org": "",
|
|
97
|
+
"repo": "heroui-inc/heroui",
|
|
98
|
+
"commit": "98553cefdc",
|
|
99
|
+
"package": "@heroui/react",
|
|
100
|
+
"version": "3.2.4",
|
|
101
|
+
"packageDir": "packages/react",
|
|
102
|
+
"total": 23,
|
|
103
|
+
"max": 45,
|
|
104
|
+
"dimensions": {
|
|
105
|
+
"agent-instructions": 3,
|
|
106
|
+
"machine-surface": 3,
|
|
107
|
+
"docs-coverage": 1,
|
|
108
|
+
"docs-freshness": 1,
|
|
109
|
+
"tokens": 3,
|
|
110
|
+
"patterns": 5,
|
|
111
|
+
"a11y": 3,
|
|
112
|
+
"verification": 3,
|
|
113
|
+
"gap-handling": 1
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "Polaris",
|
|
118
|
+
"org": "Shopify",
|
|
119
|
+
"repo": "Shopify/polaris",
|
|
120
|
+
"commit": "3f7954ae42",
|
|
121
|
+
"package": "@shopify/polaris",
|
|
122
|
+
"version": "13.10.1",
|
|
123
|
+
"packageDir": "polaris-react",
|
|
124
|
+
"total": 23,
|
|
125
|
+
"max": 45,
|
|
126
|
+
"dimensions": {
|
|
127
|
+
"agent-instructions": 1,
|
|
128
|
+
"machine-surface": 3,
|
|
129
|
+
"docs-coverage": 1,
|
|
130
|
+
"docs-freshness": 3,
|
|
131
|
+
"tokens": 5,
|
|
132
|
+
"patterns": 5,
|
|
133
|
+
"a11y": 1,
|
|
134
|
+
"verification": 3,
|
|
135
|
+
"gap-handling": 1
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "BoardUI",
|
|
140
|
+
"org": "",
|
|
141
|
+
"repo": "BoardUI/boardui",
|
|
142
|
+
"commit": "3e76e28261",
|
|
143
|
+
"package": "boardui@0.5.5",
|
|
144
|
+
"packageDir": ".",
|
|
145
|
+
"via": "npx boardui add + skill, in the starter repo",
|
|
146
|
+
"total": 21,
|
|
147
|
+
"max": 45,
|
|
148
|
+
"dimensions": {
|
|
149
|
+
"agent-instructions": 3,
|
|
150
|
+
"machine-surface": 3,
|
|
151
|
+
"docs-coverage": 1,
|
|
152
|
+
"docs-freshness": 1,
|
|
153
|
+
"tokens": 3,
|
|
154
|
+
"patterns": 5,
|
|
155
|
+
"a11y": 1,
|
|
156
|
+
"verification": 3,
|
|
157
|
+
"gap-handling": 1
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"name": "Mantine",
|
|
162
|
+
"org": "",
|
|
163
|
+
"repo": "mantinedev/mantine",
|
|
164
|
+
"commit": "61049ecd95",
|
|
165
|
+
"package": "@mantine/core",
|
|
166
|
+
"version": "9.6.1",
|
|
167
|
+
"packageDir": "packages/@mantine/core",
|
|
168
|
+
"total": 21,
|
|
169
|
+
"max": 45,
|
|
170
|
+
"dimensions": {
|
|
171
|
+
"agent-instructions": 3,
|
|
172
|
+
"machine-surface": 3,
|
|
173
|
+
"docs-coverage": 3,
|
|
174
|
+
"docs-freshness": 1,
|
|
175
|
+
"tokens": 3,
|
|
176
|
+
"patterns": 3,
|
|
177
|
+
"a11y": 1,
|
|
178
|
+
"verification": 3,
|
|
179
|
+
"gap-handling": 1
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "Base UI",
|
|
184
|
+
"org": "MUI",
|
|
185
|
+
"repo": "mui/base-ui",
|
|
186
|
+
"commit": "9f4551b4cb",
|
|
187
|
+
"package": "@base-ui/react",
|
|
188
|
+
"version": "1.8.0",
|
|
189
|
+
"packageDir": "packages/react",
|
|
190
|
+
"total": 19,
|
|
191
|
+
"max": 45,
|
|
192
|
+
"dimensions": {
|
|
193
|
+
"agent-instructions": 1,
|
|
194
|
+
"machine-surface": 3,
|
|
195
|
+
"docs-coverage": 1,
|
|
196
|
+
"docs-freshness": 3,
|
|
197
|
+
"tokens": 1,
|
|
198
|
+
"patterns": 5,
|
|
199
|
+
"a11y": 1,
|
|
200
|
+
"verification": 3,
|
|
201
|
+
"gap-handling": 1
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"name": "Carbon",
|
|
206
|
+
"org": "IBM",
|
|
207
|
+
"repo": "carbon-design-system/carbon",
|
|
208
|
+
"commit": "12277c649e",
|
|
209
|
+
"package": "@carbon/react",
|
|
210
|
+
"version": "1.116.0",
|
|
211
|
+
"packageDir": "packages/react",
|
|
212
|
+
"total": 19,
|
|
213
|
+
"max": 45,
|
|
214
|
+
"dimensions": {
|
|
215
|
+
"agent-instructions": 3,
|
|
216
|
+
"machine-surface": 3,
|
|
217
|
+
"docs-coverage": 1,
|
|
218
|
+
"docs-freshness": 1,
|
|
219
|
+
"tokens": 3,
|
|
220
|
+
"patterns": 3,
|
|
221
|
+
"a11y": 1,
|
|
222
|
+
"verification": 3,
|
|
223
|
+
"gap-handling": 1
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"name": "Primer",
|
|
228
|
+
"org": "GitHub",
|
|
229
|
+
"repo": "primer/react",
|
|
230
|
+
"commit": "4dc92ecc50",
|
|
231
|
+
"package": "@primer/react",
|
|
232
|
+
"version": "38.38.0",
|
|
233
|
+
"packageDir": "packages/react",
|
|
234
|
+
"total": 17,
|
|
235
|
+
"max": 45,
|
|
236
|
+
"dimensions": {
|
|
237
|
+
"agent-instructions": 3,
|
|
238
|
+
"machine-surface": 5,
|
|
239
|
+
"docs-coverage": 1,
|
|
240
|
+
"docs-freshness": 1,
|
|
241
|
+
"tokens": 1,
|
|
242
|
+
"patterns": 1,
|
|
243
|
+
"a11y": 1,
|
|
244
|
+
"verification": 3,
|
|
245
|
+
"gap-handling": 1
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "Radix Primitives",
|
|
250
|
+
"org": "WorkOS",
|
|
251
|
+
"repo": "radix-ui/primitives",
|
|
252
|
+
"commit": "f7ecd5ab16",
|
|
253
|
+
"package": "radix-ui",
|
|
254
|
+
"version": "1.6.7",
|
|
255
|
+
"packageDir": "packages/react/radix-ui",
|
|
256
|
+
"total": 13,
|
|
257
|
+
"max": 45,
|
|
258
|
+
"dimensions": {
|
|
259
|
+
"agent-instructions": 3,
|
|
260
|
+
"machine-surface": 1,
|
|
261
|
+
"docs-coverage": 1,
|
|
262
|
+
"docs-freshness": 1,
|
|
263
|
+
"tokens": 1,
|
|
264
|
+
"patterns": 1,
|
|
265
|
+
"a11y": 1,
|
|
266
|
+
"verification": 3,
|
|
267
|
+
"gap-handling": 1
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"name": "Untitled UI React",
|
|
272
|
+
"org": "",
|
|
273
|
+
"repo": "untitleduico/react",
|
|
274
|
+
"commit": "c981a73bcd",
|
|
275
|
+
"package": "@untitledui/react",
|
|
276
|
+
"version": "0.0.0",
|
|
277
|
+
"packageDir": ".",
|
|
278
|
+
"total": 13,
|
|
279
|
+
"max": 45,
|
|
280
|
+
"dimensions": {
|
|
281
|
+
"agent-instructions": 3,
|
|
282
|
+
"machine-surface": 1,
|
|
283
|
+
"docs-coverage": 1,
|
|
284
|
+
"docs-freshness": 1,
|
|
285
|
+
"tokens": 1,
|
|
286
|
+
"patterns": 1,
|
|
287
|
+
"a11y": 1,
|
|
288
|
+
"verification": 3,
|
|
289
|
+
"gap-handling": 1
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
}
|
package/skills/ds-audit/SKILL.md
CHANGED
|
@@ -49,6 +49,23 @@ npx adsa-cli audit <path> # score, report, .adsa/score.json
|
|
|
49
49
|
npx adsa-cli audit <path> --json # the same, machine-readable
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
**Show the tool's own output.** It prints a coloured bar per dimension, the band the
|
|
53
|
+
score falls in, and where that score sits against the public design systems in the reference set. Paste
|
|
54
|
+
that block as it came out. Do not rebuild it as a markdown table: your table drops the
|
|
55
|
+
bars, the band and the standing, and it is one retyping away from being wrong about a
|
|
56
|
+
number the reader could otherwise have checked.
|
|
57
|
+
|
|
58
|
+
The run opens `report.html` and prints its `file://` link. Do not ask whether to open
|
|
59
|
+
it, and do not offer to fix everything before the reader has read anything — the
|
|
60
|
+
report is the deliverable, and what to fix first is a decision it exists to inform.
|
|
61
|
+
|
|
62
|
+
**Check the scan line before you believe the score.** `scanned:` says which directories
|
|
63
|
+
were read and which package was picked out of a monorepo. If the guides say `none
|
|
64
|
+
found` and you can see a documentation site in the repository, the audit is measuring
|
|
65
|
+
the wrong folder: fix it with `--workspace <name>` or a `guides` entry in
|
|
66
|
+
`adsa.config.json`, and re-run before reporting anything. A wrong scope reads as an
|
|
67
|
+
undocumented system, and that is the one mistake that makes the whole audit worthless.
|
|
68
|
+
|
|
52
69
|
Read `.adsa/report.md` and the evidence under every dimension. The score is a
|
|
53
70
|
starting point, not the finding.
|
|
54
71
|
|
|
@@ -80,8 +97,21 @@ so every invention is a gap the system never declared.
|
|
|
80
97
|
|
|
81
98
|
## Phase 4 — Compare
|
|
82
99
|
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
The reference set is measured, not remembered: `rubric/reference.json` in the tool
|
|
101
|
+
holds every public design system measured with this rubric, at a named commit, and
|
|
102
|
+
the terminal already told the reader where their score sits in it. Quote that, and
|
|
103
|
+
reproduce any figure you are unsure of with `npx adsa-cli audit <clone>`.
|
|
104
|
+
|
|
105
|
+
Two things to say out loud, because a reader will otherwise assume the opposite:
|
|
106
|
+
|
|
107
|
+
- **45 is nobody's score.** The best-documented public system measured reaches 33.
|
|
108
|
+
A number in the twenties is the middle of the field, not a failing grade.
|
|
109
|
+
- **This is not a ranking of design systems.** It measures what a coding agent can
|
|
110
|
+
find in the repository. A system whose documentation lives on an excellent website
|
|
111
|
+
scores low here and may be the better design system for people.
|
|
112
|
+
|
|
113
|
+
Then say where the system stands by trait, not by vibe. The ones worth checking, and
|
|
114
|
+
what each is known for:
|
|
85
115
|
|
|
86
116
|
| System | What to look at |
|
|
87
117
|
| :-- | :-- |
|
|
@@ -111,6 +141,9 @@ Then say what to do first, in one sentence, and stop. Do not pad.
|
|
|
111
141
|
|
|
112
142
|
## Phase 6 — Fix
|
|
113
143
|
|
|
144
|
+
Only after the reader has seen the findings, and one fix at a time unless they ask
|
|
145
|
+
for more. `fix --all` is theirs to run, not yours to propose as the first move.
|
|
146
|
+
|
|
114
147
|
```bash
|
|
115
148
|
npx adsa-cli fix --list # what is automatic and what is a brief
|
|
116
149
|
npx adsa-cli fix agents-md # writes files
|
|
@@ -126,6 +159,8 @@ After the fixes: `npx adsa-cli audit` again. The delta is the deliverable.
|
|
|
126
159
|
## Rules
|
|
127
160
|
|
|
128
161
|
- Never invent a finding. Every claim names a file, a line or a command output.
|
|
162
|
+
- Never retype the tool's output. Paste it.
|
|
163
|
+
- A score without its band and its standing is a number nobody can act on.
|
|
129
164
|
- Report a dimension you could not assess as not assessed. Do not guess a number.
|
|
130
165
|
- Quote the repository, not your memory of similar repositories.
|
|
131
166
|
- The score belongs to a version. Say which one you audited.
|