@lyse-labs/lyse 0.1.0-alpha.2 → 0.2.0-alpha.1
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 +0 -5
- package/dist/cli.js +67 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/__tests__/add-ci-gate.test.d.ts +1 -0
- package/dist/commands/__tests__/add-ci-gate.test.js +149 -0
- package/dist/commands/__tests__/add-ci-gate.test.js.map +1 -0
- package/dist/commands/add-ci-gate.d.ts +26 -0
- package/dist/commands/add-ci-gate.js +429 -0
- package/dist/commands/add-ci-gate.js.map +1 -0
- package/dist/commands/audit-pipeline.js +1 -1
- package/dist/commands/audit-pipeline.js.map +1 -1
- package/dist/commands/fix.d.ts +8 -8
- package/dist/commands/init.d.ts +3 -3
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp-setup.js +1 -1
- package/dist/commands/mcp-setup.js.map +1 -1
- package/dist/config/schema.d.ts +14 -14
- package/dist/llm/__tests__/layer4-stage.test.d.ts +1 -0
- package/dist/llm/__tests__/layer4-stage.test.js +157 -0
- package/dist/llm/__tests__/layer4-stage.test.js.map +1 -0
- package/dist/llm/__tests__/validator.test.d.ts +1 -0
- package/dist/llm/__tests__/validator.test.js +156 -0
- package/dist/llm/__tests__/validator.test.js.map +1 -0
- package/dist/llm/connectors/__tests__/anthropic-adapter.test.d.ts +1 -0
- package/dist/llm/connectors/__tests__/anthropic-adapter.test.js +99 -0
- package/dist/llm/connectors/__tests__/anthropic-adapter.test.js.map +1 -0
- package/dist/llm/connectors/__tests__/cache.test.d.ts +1 -0
- package/dist/llm/connectors/__tests__/cache.test.js +50 -0
- package/dist/llm/connectors/__tests__/cache.test.js.map +1 -0
- package/dist/llm/connectors/__tests__/noop-adapter.test.d.ts +1 -0
- package/dist/llm/connectors/__tests__/noop-adapter.test.js +21 -0
- package/dist/llm/connectors/__tests__/noop-adapter.test.js.map +1 -0
- package/dist/llm/connectors/__tests__/openai-compatible-adapter.test.d.ts +1 -0
- package/dist/llm/connectors/__tests__/openai-compatible-adapter.test.js +82 -0
- package/dist/llm/connectors/__tests__/openai-compatible-adapter.test.js.map +1 -0
- package/dist/llm/connectors/__tests__/resolver.test.d.ts +1 -0
- package/dist/llm/connectors/__tests__/resolver.test.js +140 -0
- package/dist/llm/connectors/__tests__/resolver.test.js.map +1 -0
- package/dist/llm/connectors/anthropic-adapter.d.ts +12 -0
- package/dist/llm/connectors/anthropic-adapter.js +57 -0
- package/dist/llm/connectors/anthropic-adapter.js.map +1 -0
- package/dist/llm/connectors/cache.d.ts +15 -0
- package/dist/llm/connectors/cache.js +57 -0
- package/dist/llm/connectors/cache.js.map +1 -0
- package/dist/llm/connectors/noop-adapter.d.ts +4 -0
- package/dist/llm/connectors/noop-adapter.js +12 -0
- package/dist/llm/connectors/noop-adapter.js.map +1 -0
- package/dist/llm/connectors/openai-compatible-adapter.d.ts +13 -0
- package/dist/llm/connectors/openai-compatible-adapter.js +47 -0
- package/dist/llm/connectors/openai-compatible-adapter.js.map +1 -0
- package/dist/llm/connectors/resolver.d.ts +9 -0
- package/dist/llm/connectors/resolver.js +162 -0
- package/dist/llm/connectors/resolver.js.map +1 -0
- package/dist/llm/connectors/types.d.ts +25 -0
- package/dist/llm/connectors/types.js +13 -0
- package/dist/llm/connectors/types.js.map +1 -0
- package/dist/llm/layer4-stage.d.ts +8 -6
- package/dist/llm/layer4-stage.js +145 -9
- package/dist/llm/layer4-stage.js.map +1 -1
- package/dist/llm/rubric-stub.d.ts +8 -0
- package/dist/llm/rubric-stub.js +4 -0
- package/dist/llm/rubric-stub.js.map +1 -0
- package/dist/llm/validator.d.ts +18 -0
- package/dist/llm/validator.js +81 -0
- package/dist/llm/validator.js.map +1 -0
- package/dist/parsers/ai-tokens.d.ts +10 -0
- package/dist/parsers/ai-tokens.js +156 -0
- package/dist/parsers/ai-tokens.js.map +1 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js +13 -3
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js.map +1 -1
- package/dist/reliability/catalogue/sub-axes.js +16 -0
- package/dist/reliability/catalogue/sub-axes.js.map +1 -1
- package/dist/reliability/types.d.ts +1 -1
- package/dist/rule-runner.js +1 -1
- package/dist/rule-runner.js.map +1 -1
- package/dist/rules/ai-governance-ai-content-live-region.d.ts +11 -0
- package/dist/rules/ai-governance-ai-content-live-region.js +304 -0
- package/dist/rules/ai-governance-ai-content-live-region.js.map +1 -0
- package/dist/rules/ai-governance-ai-loading-error-states.d.ts +9 -0
- package/dist/rules/ai-governance-ai-loading-error-states.js +214 -0
- package/dist/rules/ai-governance-ai-loading-error-states.js.map +1 -0
- package/dist/rules/ai-governance-ai-marker-anti-patterns.d.ts +15 -0
- package/dist/rules/ai-governance-ai-marker-anti-patterns.js +178 -0
- package/dist/rules/ai-governance-ai-marker-anti-patterns.js.map +1 -0
- package/dist/rules/ai-governance-ai-marker-component-present.d.ts +28 -0
- package/dist/rules/ai-governance-ai-marker-component-present.js +320 -0
- package/dist/rules/ai-governance-ai-marker-component-present.js.map +1 -0
- package/dist/rules/ai-governance-ai-token-requires-marker.d.ts +17 -0
- package/dist/rules/ai-governance-ai-token-requires-marker.js +206 -0
- package/dist/rules/ai-governance-ai-token-requires-marker.js.map +1 -0
- package/dist/rules/ai-governance-ai-tokens-reserved.d.ts +8 -0
- package/dist/rules/ai-governance-ai-tokens-reserved.js +85 -0
- package/dist/rules/ai-governance-ai-tokens-reserved.js.map +1 -0
- package/dist/rules/ai-governance-disclaimer-present.d.ts +18 -0
- package/dist/rules/ai-governance-disclaimer-present.js +210 -0
- package/dist/rules/ai-governance-disclaimer-present.js.map +1 -0
- package/dist/rules/ai-governance-explainability-affordance.d.ts +14 -0
- package/dist/rules/ai-governance-explainability-affordance.js +196 -0
- package/dist/rules/ai-governance-explainability-affordance.js.map +1 -0
- package/dist/rules/ai-governance-feedback-control-present.d.ts +19 -0
- package/dist/rules/ai-governance-feedback-control-present.js +223 -0
- package/dist/rules/ai-governance-feedback-control-present.js.map +1 -0
- package/dist/rules/ai-governance-human-control-affordances.d.ts +16 -0
- package/dist/rules/ai-governance-human-control-affordances.js +228 -0
- package/dist/rules/ai-governance-human-control-affordances.js.map +1 -0
- package/dist/rules/ai-governance-value-gate-doc-present.d.ts +18 -0
- package/dist/rules/ai-governance-value-gate-doc-present.js +206 -0
- package/dist/rules/ai-governance-value-gate-doc-present.js.map +1 -0
- package/dist/rules/ai-surface-agent-instruction-files.d.ts +33 -0
- package/dist/rules/ai-surface-agent-instruction-files.js +310 -0
- package/dist/rules/ai-surface-agent-instruction-files.js.map +1 -0
- package/dist/rules/ai-surface-llms-txt-structure.d.ts +18 -0
- package/dist/rules/ai-surface-llms-txt-structure.js +200 -0
- package/dist/rules/ai-surface-llms-txt-structure.js.map +1 -0
- package/dist/rules/ai-surface-mcp-config-present.d.ts +23 -0
- package/dist/rules/ai-surface-mcp-config-present.js +193 -0
- package/dist/rules/ai-surface-mcp-config-present.js.map +1 -0
- package/dist/rules/ai-surface-shadcn-registry-valid.d.ts +22 -0
- package/dist/rules/ai-surface-shadcn-registry-valid.js +247 -0
- package/dist/rules/ai-surface-shadcn-registry-valid.js.map +1 -0
- package/dist/rules/components-contracts-strictness.d.ts +48 -0
- package/dist/rules/components-contracts-strictness.js +372 -0
- package/dist/rules/components-contracts-strictness.js.map +1 -0
- package/dist/rules/registry.js +32 -0
- package/dist/rules/registry.js.map +1 -1
- package/dist/rules/tokens-dtcg-conformance.d.ts +55 -19
- package/dist/rules/tokens-dtcg-conformance.js +320 -82
- package/dist/rules/tokens-dtcg-conformance.js.map +1 -1
- package/dist/scorer.js +4 -3
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js.map +1 -1
- package/package.json +41 -16
- package/rules-manifest.json +431 -6
- package/schemas/v1/lyse-rules.json +1 -1
- package/dist/commands/ci-setup.d.ts +0 -9
- package/dist/commands/ci-setup.js +0 -42
- package/dist/commands/ci-setup.js.map +0 -1
- package/dist/commands/templates/lyse-workflow.yml.template +0 -30
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createLyseRule } from "./_rule-module.js";
|
|
4
|
+
const RULE_ID = "ai-surface/llms-txt-structure";
|
|
5
|
+
const MAX_FILE_BYTES = 1_000_000;
|
|
6
|
+
const README_CANDIDATES = ["README.md", "README", "readme.md"];
|
|
7
|
+
const ALLOWLIST_DIRECTIVE = "lyse-disable ai-surface/llms-txt-structure";
|
|
8
|
+
const H1_RE = /^#\s+\S/;
|
|
9
|
+
const H2_RE = /^##\s+\S/;
|
|
10
|
+
const BLOCKQUOTE_RE = /^>\s+\S/;
|
|
11
|
+
const LIST_LINK_RE = /^\s*[-*]\s+\[([^\]]*)\]\(([^)]*)\)/;
|
|
12
|
+
function readFileIfSmall(absPath) {
|
|
13
|
+
try {
|
|
14
|
+
const stat = statSync(absPath);
|
|
15
|
+
if (!stat.isFile())
|
|
16
|
+
return null;
|
|
17
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
18
|
+
return null;
|
|
19
|
+
const content = readFileSync(absPath, "utf8");
|
|
20
|
+
// Strip UTF-8 BOM so VSCode-with-BOM / Notepad-default files don't break H1 detection.
|
|
21
|
+
return content.startsWith("") ? content.slice(1) : content;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function hasAllowlistDirective(repoRoot) {
|
|
28
|
+
for (const candidate of README_CANDIDATES) {
|
|
29
|
+
const abs = join(repoRoot, candidate);
|
|
30
|
+
const content = readFileIfSmall(abs);
|
|
31
|
+
if (content !== null && content.includes(ALLOWLIST_DIRECTIVE)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
function analyseStructure(content) {
|
|
38
|
+
const report = {
|
|
39
|
+
hasH1: false,
|
|
40
|
+
hasBlockquote: false,
|
|
41
|
+
hasSection: false,
|
|
42
|
+
malformedLinks: [],
|
|
43
|
+
};
|
|
44
|
+
const lines = content.split("\n");
|
|
45
|
+
let firstMeaningfulIdx = -1;
|
|
46
|
+
for (let i = 0; i < lines.length; i++) {
|
|
47
|
+
if ((lines[i] ?? "").trim().length > 0) {
|
|
48
|
+
firstMeaningfulIdx = i;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (firstMeaningfulIdx >= 0 && H1_RE.test(lines[firstMeaningfulIdx] ?? "")) {
|
|
53
|
+
report.hasH1 = true;
|
|
54
|
+
}
|
|
55
|
+
if (report.hasH1) {
|
|
56
|
+
for (let i = firstMeaningfulIdx + 1; i < lines.length; i++) {
|
|
57
|
+
const line = lines[i] ?? "";
|
|
58
|
+
if (line.trim().length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
if (BLOCKQUOTE_RE.test(line)) {
|
|
61
|
+
report.hasBlockquote = true;
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let currentSectionLine = -1;
|
|
67
|
+
for (let i = 0; i < lines.length; i++) {
|
|
68
|
+
const line = lines[i] ?? "";
|
|
69
|
+
if (H2_RE.test(line)) {
|
|
70
|
+
report.hasSection = true;
|
|
71
|
+
currentSectionLine = i + 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (currentSectionLine < 0)
|
|
75
|
+
continue;
|
|
76
|
+
const match = line.match(LIST_LINK_RE);
|
|
77
|
+
if (!match)
|
|
78
|
+
continue;
|
|
79
|
+
const title = (match[1] ?? "").trim();
|
|
80
|
+
const url = (match[2] ?? "").trim();
|
|
81
|
+
if (title.length === 0 || url.length === 0) {
|
|
82
|
+
report.malformedLinks.push({
|
|
83
|
+
line: i + 1,
|
|
84
|
+
message: title.length === 0 && url.length === 0
|
|
85
|
+
? "Section link is missing both title and URL"
|
|
86
|
+
: title.length === 0
|
|
87
|
+
? "Section link is missing a title"
|
|
88
|
+
: "Section link is missing a URL",
|
|
89
|
+
suggestion: "format each entry as `- [<title>](<url>): <description>` per llmstxt.org spec",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return report;
|
|
94
|
+
}
|
|
95
|
+
const evaluate = async (ctx, _files) => {
|
|
96
|
+
const findings = [];
|
|
97
|
+
if (!ctx.repoRoot) {
|
|
98
|
+
return { findings, opportunities: 0 };
|
|
99
|
+
}
|
|
100
|
+
if (hasAllowlistDirective(ctx.repoRoot)) {
|
|
101
|
+
return { findings, opportunities: 0 };
|
|
102
|
+
}
|
|
103
|
+
const llmsTxtAbs = join(ctx.repoRoot, "llms.txt");
|
|
104
|
+
const content = readFileIfSmall(llmsTxtAbs);
|
|
105
|
+
if (content === null) {
|
|
106
|
+
findings.push({
|
|
107
|
+
ruleId: RULE_ID,
|
|
108
|
+
axis: "ai-surface",
|
|
109
|
+
severity: "warning",
|
|
110
|
+
location: { file: "llms.txt", line: 1, column: 1 },
|
|
111
|
+
message: "No llms.txt at repo root — AI agents have no top-level map of the design system",
|
|
112
|
+
suggestion: "add an llms.txt file (llmstxt.org spec) with an H1 title, a blockquote summary, and `## <section>` link lists",
|
|
113
|
+
});
|
|
114
|
+
return { findings, opportunities: 1 };
|
|
115
|
+
}
|
|
116
|
+
const report = analyseStructure(content);
|
|
117
|
+
if (!report.hasH1) {
|
|
118
|
+
findings.push({
|
|
119
|
+
ruleId: RULE_ID,
|
|
120
|
+
axis: "ai-surface",
|
|
121
|
+
severity: "error",
|
|
122
|
+
location: { file: "llms.txt", line: 1, column: 1 },
|
|
123
|
+
message: "llms.txt is missing a top-level `# <title>` H1 heading",
|
|
124
|
+
suggestion: "start the file with a single `# <Project Title>` line, per llmstxt.org",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (!report.hasBlockquote) {
|
|
128
|
+
findings.push({
|
|
129
|
+
ruleId: RULE_ID,
|
|
130
|
+
axis: "ai-surface",
|
|
131
|
+
severity: "error",
|
|
132
|
+
location: { file: "llms.txt", line: 1, column: 1 },
|
|
133
|
+
message: "llms.txt is missing a `> <summary>` blockquote after the H1",
|
|
134
|
+
suggestion: "add a one-sentence `> ...` blockquote summarising the project right after the H1",
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (!report.hasSection) {
|
|
138
|
+
findings.push({
|
|
139
|
+
ruleId: RULE_ID,
|
|
140
|
+
axis: "ai-surface",
|
|
141
|
+
severity: "error",
|
|
142
|
+
location: { file: "llms.txt", line: 1, column: 1 },
|
|
143
|
+
message: "llms.txt has no `## <section>` headings — link lists are required by the spec",
|
|
144
|
+
suggestion: "add at least one `## <Section>` heading followed by `- [<title>](<url>): <description>` items, per llmstxt.org",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
for (const issue of report.malformedLinks) {
|
|
148
|
+
findings.push({
|
|
149
|
+
ruleId: RULE_ID,
|
|
150
|
+
axis: "ai-surface",
|
|
151
|
+
severity: "error",
|
|
152
|
+
location: { file: "llms.txt", line: issue.line, column: 1 },
|
|
153
|
+
message: issue.message,
|
|
154
|
+
suggestion: issue.suggestion,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return { findings, opportunities: 1 };
|
|
158
|
+
};
|
|
159
|
+
export const rule = createLyseRule({
|
|
160
|
+
meta: {
|
|
161
|
+
axis: "ai-surface",
|
|
162
|
+
lyseRuleId: RULE_ID,
|
|
163
|
+
defaultSeverity: "warning",
|
|
164
|
+
shortDescription: "llms.txt at repo root must follow the llmstxt.org structure",
|
|
165
|
+
fullDescription: "Detects whether a design-system repository ships an `llms.txt` file at the repo root and validates the file's structure against the llmstxt.org specification: a single `# <title>` H1, a `> <summary>` blockquote, and at least one `## <section>` heading whose list items follow `- [<title>](<url>): <description>`. Absence emits a warning. A present-but-malformed `llms.txt` emits one error per structural issue. The optional companion file `llms-full.txt` is detected as a bonus signal but is not required.",
|
|
166
|
+
helpUri: "https://github.com/lyse-labs/lyse/blob/main/docs/rules/ai-surface-llms-txt-structure.md",
|
|
167
|
+
rationale: `Why it matters
|
|
168
|
+
|
|
169
|
+
\`llms.txt\` (llmstxt.org, Tantum 2024) is the emerging convention for handing AI agents a token-cheap, curated map of a project. For a design system this is the AI-Consumable surface: a single discoverable entry that lists the canonical Quickstart, API reference, component index, and policy docs without forcing the agent to crawl the whole repo.
|
|
170
|
+
|
|
171
|
+
Absence is a missed opportunity, not a bug — agents fall back to scanning the README and source tree, which is slower and more expensive. Structural errors (missing H1, missing summary, malformed link rows) are scored as errors because consumers (cursor, claude code, custom agents) parse the file on the assumption it follows the spec, and silent malformations break the contract.
|
|
172
|
+
|
|
173
|
+
The companion \`llms-full.txt\` — a single-file inlining of every linked document — is a strong bonus signal but is not enforced as a hard requirement.`,
|
|
174
|
+
examples: [
|
|
175
|
+
{
|
|
176
|
+
good: `# Acme DS
|
|
177
|
+
|
|
178
|
+
> A token-first React design system.
|
|
179
|
+
|
|
180
|
+
## Docs
|
|
181
|
+
|
|
182
|
+
- [Quickstart](https://acme.dev/quickstart): Get started in 3 minutes.
|
|
183
|
+
- [API reference](https://acme.dev/api): Full method index.`,
|
|
184
|
+
bad: `Welcome to Acme DS. We ship Buttons and Cards.
|
|
185
|
+
|
|
186
|
+
- random link list`,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
allowlist: [
|
|
190
|
+
"files larger than 1 MB at `llms.txt` — skipped to avoid pathological cases",
|
|
191
|
+
"repos whose README at the root contains the directive `lyse-disable ai-surface/llms-txt-structure` — rule is N/A",
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
defaultOptions: [],
|
|
195
|
+
create: () => ({ evaluate }),
|
|
196
|
+
});
|
|
197
|
+
export const _internal = {
|
|
198
|
+
analyseStructure,
|
|
199
|
+
};
|
|
200
|
+
//# sourceMappingURL=ai-surface-llms-txt-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-surface-llms-txt-structure.js","sourceRoot":"","sources":["../../src/rules/ai-surface-llms-txt-structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Rule } from "../types.js";
|
|
2
|
+
interface ServerValidation {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
reason?: string;
|
|
5
|
+
}
|
|
6
|
+
declare function isAllowlisted(repoRoot: string): boolean;
|
|
7
|
+
declare function discoverConfigs(repoRoot: string): string[];
|
|
8
|
+
declare function validateServerEntry(name: string, entry: unknown): ServerValidation;
|
|
9
|
+
interface ConfigValidation {
|
|
10
|
+
errors: string[];
|
|
11
|
+
validServers: number;
|
|
12
|
+
}
|
|
13
|
+
declare function validateConfig(data: unknown): ConfigValidation;
|
|
14
|
+
export declare const rule: Rule;
|
|
15
|
+
export declare const _internal: {
|
|
16
|
+
validateConfig: typeof validateConfig;
|
|
17
|
+
validateServerEntry: typeof validateServerEntry;
|
|
18
|
+
isAllowlisted: typeof isAllowlisted;
|
|
19
|
+
discoverConfigs: typeof discoverConfigs;
|
|
20
|
+
CANDIDATE_PATHS: string[];
|
|
21
|
+
DISABLE_DIRECTIVE: string;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createLyseRule } from "./_rule-module.js";
|
|
4
|
+
const RULE_ID = "ai-surface/mcp-config-present";
|
|
5
|
+
const MAX_FILE_BYTES = 1_000_000;
|
|
6
|
+
const CANDIDATE_PATHS = [
|
|
7
|
+
".mcp.json",
|
|
8
|
+
".cursor/mcp.json",
|
|
9
|
+
"claude_desktop_config.json",
|
|
10
|
+
];
|
|
11
|
+
const README_CANDIDATES = ["README.md", "README", "readme.md", "README.mdx"];
|
|
12
|
+
const DISABLE_DIRECTIVE = `lyse-disable ${RULE_ID}`;
|
|
13
|
+
function readJsonIfSmall(absPath) {
|
|
14
|
+
try {
|
|
15
|
+
const stat = statSync(absPath);
|
|
16
|
+
if (!stat.isFile())
|
|
17
|
+
return { data: null, parseError: "not a regular file" };
|
|
18
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
19
|
+
return { data: null, parseError: "file too large" };
|
|
20
|
+
const raw = readFileSync(absPath, "utf8");
|
|
21
|
+
if (raw.trim().length === 0)
|
|
22
|
+
return { data: null, parseError: "empty file" };
|
|
23
|
+
return { data: JSON.parse(raw), parseError: null };
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
return { data: null, parseError: e instanceof Error ? e.message : "unknown parse error" };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isAllowlisted(repoRoot) {
|
|
30
|
+
for (const candidate of README_CANDIDATES) {
|
|
31
|
+
const abs = join(repoRoot, candidate);
|
|
32
|
+
if (!existsSync(abs))
|
|
33
|
+
continue;
|
|
34
|
+
try {
|
|
35
|
+
const stat = statSync(abs);
|
|
36
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES)
|
|
37
|
+
continue;
|
|
38
|
+
const raw = readFileSync(abs, "utf8");
|
|
39
|
+
if (raw.includes(DISABLE_DIRECTIVE))
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// ignore unreadable README
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
function discoverConfigs(repoRoot) {
|
|
49
|
+
const found = [];
|
|
50
|
+
for (const candidate of CANDIDATE_PATHS) {
|
|
51
|
+
const abs = join(repoRoot, candidate);
|
|
52
|
+
if (existsSync(abs))
|
|
53
|
+
found.push(candidate);
|
|
54
|
+
}
|
|
55
|
+
return found;
|
|
56
|
+
}
|
|
57
|
+
function validateServerEntry(name, entry) {
|
|
58
|
+
if (name.trim().length === 0) {
|
|
59
|
+
return { ok: false, reason: "server name is not a non-empty string" };
|
|
60
|
+
}
|
|
61
|
+
if (typeof entry !== "object" || entry === null) {
|
|
62
|
+
return { ok: false, reason: `server "${name}" is not an object` };
|
|
63
|
+
}
|
|
64
|
+
const e = entry;
|
|
65
|
+
if (typeof e.command !== "string" || e.command.trim().length === 0) {
|
|
66
|
+
return { ok: false, reason: `server "${name}" missing \`command\` (string)` };
|
|
67
|
+
}
|
|
68
|
+
if (e.args !== undefined && !Array.isArray(e.args)) {
|
|
69
|
+
return { ok: false, reason: `server "${name}" has \`args\` that is not an array` };
|
|
70
|
+
}
|
|
71
|
+
return { ok: true };
|
|
72
|
+
}
|
|
73
|
+
function validateConfig(data) {
|
|
74
|
+
if (typeof data !== "object" || data === null) {
|
|
75
|
+
return { errors: ["config root is not a JSON object"], validServers: 0 };
|
|
76
|
+
}
|
|
77
|
+
const shape = data;
|
|
78
|
+
if (!("mcpServers" in shape)) {
|
|
79
|
+
return { errors: ["missing top-level `mcpServers` object"], validServers: 0 };
|
|
80
|
+
}
|
|
81
|
+
const servers = shape.mcpServers;
|
|
82
|
+
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
83
|
+
return { errors: ["`mcpServers` must be an object"], validServers: 0 };
|
|
84
|
+
}
|
|
85
|
+
const entries = Object.entries(servers);
|
|
86
|
+
if (entries.length === 0) {
|
|
87
|
+
return { errors: ["`mcpServers` object is empty (declare at least one server)"], validServers: 0 };
|
|
88
|
+
}
|
|
89
|
+
const errors = [];
|
|
90
|
+
let validServers = 0;
|
|
91
|
+
for (const [name, entry] of entries) {
|
|
92
|
+
const result = validateServerEntry(name, entry);
|
|
93
|
+
if (!result.ok) {
|
|
94
|
+
errors.push(result.reason ?? `server "${name}" is invalid`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
validServers += 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { errors, validServers };
|
|
101
|
+
}
|
|
102
|
+
const evaluate = async (ctx, _files) => {
|
|
103
|
+
const findings = [];
|
|
104
|
+
if (!ctx.repoRoot) {
|
|
105
|
+
return { findings, opportunities: 0 };
|
|
106
|
+
}
|
|
107
|
+
if (isAllowlisted(ctx.repoRoot)) {
|
|
108
|
+
return { findings, opportunities: 0 };
|
|
109
|
+
}
|
|
110
|
+
const configs = discoverConfigs(ctx.repoRoot);
|
|
111
|
+
if (configs.length === 0) {
|
|
112
|
+
findings.push({
|
|
113
|
+
ruleId: RULE_ID,
|
|
114
|
+
axis: "ai-surface",
|
|
115
|
+
severity: "warning",
|
|
116
|
+
location: { file: ".mcp.json", line: 1, column: 1 },
|
|
117
|
+
message: "No MCP config file found — design system is not declared as AI-agent-accessible",
|
|
118
|
+
suggestion: "create `.mcp.json` (Claude Code), `.cursor/mcp.json` (Cursor), or `claude_desktop_config.json` declaring at least one MCP server with a `command`",
|
|
119
|
+
});
|
|
120
|
+
return { findings, opportunities: 1 };
|
|
121
|
+
}
|
|
122
|
+
let opportunities = 0;
|
|
123
|
+
for (const rel of configs) {
|
|
124
|
+
opportunities += 1;
|
|
125
|
+
const abs = join(ctx.repoRoot, rel);
|
|
126
|
+
const { data, parseError } = readJsonIfSmall(abs);
|
|
127
|
+
if (parseError !== null) {
|
|
128
|
+
findings.push({
|
|
129
|
+
ruleId: RULE_ID,
|
|
130
|
+
axis: "ai-surface",
|
|
131
|
+
severity: "error",
|
|
132
|
+
location: { file: rel, line: 1, column: 1 },
|
|
133
|
+
message: `MCP config is not valid JSON (${parseError})`,
|
|
134
|
+
suggestion: "ensure the config is parseable JSON with a top-level `mcpServers` object",
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const outcome = validateConfig(data);
|
|
139
|
+
for (const err of outcome.errors) {
|
|
140
|
+
findings.push({
|
|
141
|
+
ruleId: RULE_ID,
|
|
142
|
+
axis: "ai-surface",
|
|
143
|
+
severity: "error",
|
|
144
|
+
location: { file: rel, line: 1, column: 1 },
|
|
145
|
+
message: err,
|
|
146
|
+
suggestion: "each server entry must have a non-empty string key and a `command` (string); `args` (array) is optional",
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { findings, opportunities };
|
|
151
|
+
};
|
|
152
|
+
export const rule = createLyseRule({
|
|
153
|
+
meta: {
|
|
154
|
+
axis: "ai-surface",
|
|
155
|
+
lyseRuleId: RULE_ID,
|
|
156
|
+
defaultSeverity: "warning",
|
|
157
|
+
shortDescription: "Design system should declare at least one MCP server",
|
|
158
|
+
fullDescription: "Looks for an MCP (Model Context Protocol) configuration file at the repo root: `.mcp.json` (Claude Code convention), `.cursor/mcp.json` (Cursor convention), or `claude_desktop_config.json`. When found, validates the file is parseable JSON, has a top-level `mcpServers` object with at least one entry, and each server entry has a non-empty string key and a `command` (string); `args` (array) is optional. Absence emits one warning (DS not yet AI-agent-accessible). Malformed JSON, missing/empty `mcpServers`, or invalid server entries emit errors.",
|
|
159
|
+
helpUri: "https://github.com/lyse-labs/lyse/blob/main/docs/rules/ai-surface-mcp-config-present.md",
|
|
160
|
+
rationale: `Why it matters
|
|
161
|
+
|
|
162
|
+
The Model Context Protocol (MCP) is the de-facto standard for letting coding agents (Claude Code, Cursor, Claude Desktop) call tools that surface a design system's components, tokens, and docs at lookup time. A design system without an MCP server declaration leaves agents to scrape README and source files heuristically — the cost-vs-accuracy regression documented in Stream 1 of the AI-Consumable track.
|
|
163
|
+
|
|
164
|
+
The signal is binary and cheap to enforce: either the repo declares at least one valid \`mcpServers\` entry or it doesn't. A warning (not info) reflects the strategic importance of AI-Consumable readiness for Track 2 design systems: shipping a stable MCP surface is now table-stakes.
|
|
165
|
+
|
|
166
|
+
Severity escalates to error when a config file is present but malformed — a broken \`.mcp.json\` silently breaks every agent that tries to connect, which is worse than no config at all.`,
|
|
167
|
+
examples: [
|
|
168
|
+
{
|
|
169
|
+
good: '{ "mcpServers": { "lyse": { "command": "npx", "args": ["@lyse-labs/lyse", "mcp"] } } }',
|
|
170
|
+
bad: '{ "mcpServers": {} }',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
good: '{ "mcpServers": { "design-system": { "command": "node", "args": ["./mcp-server.js"] } } }',
|
|
174
|
+
bad: '{ "servers": [] }',
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
allowlist: [
|
|
178
|
+
"files larger than 1 MB — skipped to avoid pathological cases",
|
|
179
|
+
"repos containing `// lyse-disable ai-surface/mcp-config-present` in an adjacent README — rule is N/A",
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
defaultOptions: [],
|
|
183
|
+
create: () => ({ evaluate }),
|
|
184
|
+
});
|
|
185
|
+
export const _internal = {
|
|
186
|
+
validateConfig,
|
|
187
|
+
validateServerEntry,
|
|
188
|
+
isAllowlisted,
|
|
189
|
+
discoverConfigs,
|
|
190
|
+
CANDIDATE_PATHS,
|
|
191
|
+
DISABLE_DIRECTIVE,
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=ai-surface-mcp-config-present.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-surface-mcp-config-present.js","sourceRoot":"","sources":["../../src/rules/ai-surface-mcp-config-present.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Rule } from "../types.js";
|
|
2
|
+
interface ItemValidation {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
reasons: string[];
|
|
5
|
+
}
|
|
6
|
+
declare function validateRegistryItem(item: unknown): ItemValidation;
|
|
7
|
+
declare function looksLikeRegistryItem(data: unknown): boolean;
|
|
8
|
+
declare function looksLikeRegistryCollection(data: unknown): boolean;
|
|
9
|
+
interface ParsedRegistry {
|
|
10
|
+
items: unknown[];
|
|
11
|
+
shape: "single" | "collection";
|
|
12
|
+
}
|
|
13
|
+
declare function extractRegistryItems(data: unknown): ParsedRegistry;
|
|
14
|
+
export declare const rule: Rule;
|
|
15
|
+
export declare const _internal: {
|
|
16
|
+
validateRegistryItem: typeof validateRegistryItem;
|
|
17
|
+
looksLikeRegistryItem: typeof looksLikeRegistryItem;
|
|
18
|
+
looksLikeRegistryCollection: typeof looksLikeRegistryCollection;
|
|
19
|
+
extractRegistryItems: typeof extractRegistryItems;
|
|
20
|
+
REGISTRY_CANDIDATES: string[];
|
|
21
|
+
};
|
|
22
|
+
export {};
|