@expressivecss/mcp-server 0.2.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.
- package/.claude-plugin/plugin.json +14 -0
- package/.cursor-plugin/plugin.json +25 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE +101 -0
- package/README.md +240 -0
- package/capability-roadmap.json +3109 -0
- package/component-decisions.json +6950 -0
- package/component-guides.json +171 -0
- package/contract.json +27 -0
- package/lint.mjs +68 -0
- package/mcp.json +14 -0
- package/package.json +49 -0
- package/sample-hermes-config.yaml +13 -0
- package/scripts/resolve-version.mjs +736 -0
- package/semantics-data.json +1166 -0
- package/server.js +2380 -0
- package/smoke.mjs +1237 -0
package/contract.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"generatedBy": "scripts/gen-expressivecss-skill.mjs",
|
|
4
|
+
"frameworkVersion": "0.10.1",
|
|
5
|
+
"skillVersion": "0.7.0",
|
|
6
|
+
"matchingTag": "v0.10.1",
|
|
7
|
+
"releaseTags": [
|
|
8
|
+
"v0.10.0",
|
|
9
|
+
"v0.10.1",
|
|
10
|
+
"v0.5.0",
|
|
11
|
+
"v0.6.0",
|
|
12
|
+
"v0.7.0",
|
|
13
|
+
"v0.7.0-rc.0",
|
|
14
|
+
"v0.8.0",
|
|
15
|
+
"v0.9.0",
|
|
16
|
+
"v0.9.1"
|
|
17
|
+
],
|
|
18
|
+
"sources": [
|
|
19
|
+
"llm.md",
|
|
20
|
+
"semantics.json",
|
|
21
|
+
"docs/src/data/nav.ts",
|
|
22
|
+
"docs/src/data/component-decisions.json",
|
|
23
|
+
"package.json",
|
|
24
|
+
"CHANGELOG.md"
|
|
25
|
+
],
|
|
26
|
+
"sourceHash": "98b9da3400da3b8e16a86e4b52989317a369033dc3b6446441f955d8abfbe09e"
|
|
27
|
+
}
|
package/lint.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Command-line front end for the static checks `rules_enforcer` runs: the
|
|
4
|
+
* bundled semantics rules plus the legacy-pattern and initialization checks.
|
|
5
|
+
*
|
|
6
|
+
* expressivecss-lint <file>... Report findings; exit 1 when any.
|
|
7
|
+
* expressivecss-lint --hook Read a Claude Code PostToolUse payload on
|
|
8
|
+
* stdin, lint `tool_input.file_path` when
|
|
9
|
+
* it is a markup file, exit 2 on findings
|
|
10
|
+
* so the message goes back to the agent.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { pathToFileURL } from 'node:url';
|
|
15
|
+
import { inspectAuthoringRules, readInspectionFile } from './server.js';
|
|
16
|
+
|
|
17
|
+
// Markdown is left out: a doc concatenates many independent examples, so page-level rules misfire.
|
|
18
|
+
const MARKUP = new Set(['.html', '.htm', '.astro', '.jsx', '.tsx', '.vue', '.svelte']);
|
|
19
|
+
const MAX_BYTES = 2 * 1024 * 1024;
|
|
20
|
+
const problem = (id, rule) => ({ id, severity: 'high', rule, location: { line: 1, column: 1 }, snippet: '' });
|
|
21
|
+
|
|
22
|
+
/** Findings for one file. A file that cannot be fully inspected is a finding too, never a silent pass. */
|
|
23
|
+
export async function lintFile(file) {
|
|
24
|
+
let text;
|
|
25
|
+
try {
|
|
26
|
+
({ text } = await readInspectionFile(file, process.cwd(), MAX_BYTES));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return [problem('file-not-inspected', `Skipped: ${error.message}. Files must be regular, inside the working directory, and at most ${MAX_BYTES} bytes.`)];
|
|
29
|
+
}
|
|
30
|
+
// ponytail: JSX/Astro/Vue are parsed as HTML after `className` -> `class`; expression-heavy markup can hide from selector rules.
|
|
31
|
+
const issues = inspectAuthoringRules(text.replace(/\bclassName=/gu, 'class='));
|
|
32
|
+
if (issues.truncatedReason) issues.push(problem('inspection-truncated', `Static inspection stopped early: ${issues.truncatedReason}. Split the file or reduce its markup.`));
|
|
33
|
+
return issues;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function format(file, issues) {
|
|
37
|
+
return issues
|
|
38
|
+
.map((issue) => `${file}:${issue.location.line}:${issue.location.column} ${issue.id} [${issue.severity}] ${issue.rule}${issue.snippet ? `\n ${issue.snippet}` : ''}`)
|
|
39
|
+
.join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function main(argv) {
|
|
43
|
+
if (argv[0] === '--hook') {
|
|
44
|
+
const payload = JSON.parse(readFileSync(0, 'utf8') || '{}');
|
|
45
|
+
const file = payload.tool_input?.file_path;
|
|
46
|
+
if (!file || !MARKUP.has(path.extname(file).toLowerCase())) return 0;
|
|
47
|
+
const issues = await lintFile(file);
|
|
48
|
+
if (!issues.length) return 0;
|
|
49
|
+
console.error(`ExpressiveCSS lint found ${issues.length} issue(s). Fix them before continuing:\n${format(file, issues)}`);
|
|
50
|
+
return 2;
|
|
51
|
+
}
|
|
52
|
+
if (!argv.length || argv[0] === '--help') {
|
|
53
|
+
console.error('Usage: expressivecss-lint <file>... | --hook');
|
|
54
|
+
return argv.length ? 0 : 1;
|
|
55
|
+
}
|
|
56
|
+
let total = 0;
|
|
57
|
+
for (const file of argv) {
|
|
58
|
+
const issues = await lintFile(file);
|
|
59
|
+
total += issues.length;
|
|
60
|
+
if (issues.length) console.log(format(file, issues));
|
|
61
|
+
}
|
|
62
|
+
console.error(total ? `${total} issue(s) in ${argv.length} file(s).` : `No issues in ${argv.length} file(s).`);
|
|
63
|
+
return total ? 1 : 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (process.argv[1] && pathToFileURL(realpathSync(process.argv[1])).href === import.meta.url) {
|
|
67
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
68
|
+
}
|
package/mcp.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"expressivecss-mcp": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": ["-y", "@expressivecss/mcp-server@latest"],
|
|
6
|
+
"env": {
|
|
7
|
+
"EXPRESSIVECSS_MCP_MAX_COMPONENT_RESPONSE_CHARS": "24000",
|
|
8
|
+
"EXPRESSIVECSS_MCP_MAX_COMPONENT_SKIPS": "7",
|
|
9
|
+
"EXPRESSIVECSS_MCP_QA_MAX_FILES": "300",
|
|
10
|
+
"EXPRESSIVECSS_MCP_QA_MAX_MB": "2"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@expressivecss/mcp-server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "ExpressiveCSS MCP server with Design→QA workflow tools.",
|
|
5
|
+
"homepage": "https://www.expressivecss.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/BaezFJ/ExpressiveCSS.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"expressivecss-mcp": "server.js",
|
|
14
|
+
"expressivecss-lint": "lint.mjs"
|
|
15
|
+
},
|
|
16
|
+
"main": "server.js",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "node smoke.mjs",
|
|
22
|
+
"prepack": "npm test"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"server.js",
|
|
26
|
+
"lint.mjs",
|
|
27
|
+
"component-guides.json",
|
|
28
|
+
"component-decisions.json",
|
|
29
|
+
"capability-roadmap.json",
|
|
30
|
+
"contract.json",
|
|
31
|
+
"semantics-data.json",
|
|
32
|
+
"smoke.mjs",
|
|
33
|
+
"scripts/resolve-version.mjs",
|
|
34
|
+
"README.md",
|
|
35
|
+
"mcp.json",
|
|
36
|
+
".claude-plugin/plugin.json",
|
|
37
|
+
".cursor-plugin/plugin.json",
|
|
38
|
+
"sample-hermes-config.yaml",
|
|
39
|
+
"CHANGELOG.md"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
43
|
+
"jsdom": "^30.1.1",
|
|
44
|
+
"zod": "^4.6.5"
|
|
45
|
+
},
|
|
46
|
+
"overrides": {
|
|
47
|
+
"qs": "6.16.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Example Hermes MCP wiring for this server.
|
|
2
|
+
# Apply these values with `hermes config set` rather than hand-editing the file.
|
|
3
|
+
|
|
4
|
+
mcp_servers:
|
|
5
|
+
expressivecss-mcp:
|
|
6
|
+
command: node
|
|
7
|
+
args:
|
|
8
|
+
- /ABSOLUTE/PATH/TO/REPO/mcp/expressivecss/server.js
|
|
9
|
+
env:
|
|
10
|
+
EXPRESSIVECSS_MCP_MAX_COMPONENT_RESPONSE_CHARS: "24000"
|
|
11
|
+
EXPRESSIVECSS_MCP_MAX_COMPONENT_SKIPS: "7"
|
|
12
|
+
EXPRESSIVECSS_MCP_QA_MAX_FILES: "300"
|
|
13
|
+
EXPRESSIVECSS_MCP_QA_MAX_MB: "2"
|