canicode 0.5.0 → 0.5.2
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 +46 -2
- package/dist/mcp/server.js +18 -0
- package/dist/mcp/server.js.map +1 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -9,12 +9,17 @@
|
|
|
9
9
|
<a href="https://github.com/let-sunny/canicode/actions/workflows/ci.yml"><img src="https://github.com/let-sunny/canicode/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
10
10
|
<a href="https://github.com/let-sunny/canicode/actions/workflows/release.yml"><img src="https://github.com/let-sunny/canicode/actions/workflows/release.yml/badge.svg" alt="Release"></a>
|
|
11
11
|
<a href="https://let-sunny.github.io/canicode/"><img src="https://img.shields.io/badge/Try_it-GitHub_Pages-blue" alt="GitHub Pages"></a>
|
|
12
|
+
<a href="https://www.figma.com/community/plugin/1617144221046795292/canicode"><img src="https://img.shields.io/badge/Figma_Plugin-under_review-orange" alt="Figma Plugin"></a>
|
|
12
13
|
</p>
|
|
13
14
|
|
|
14
15
|
<p align="center">Analyze Figma designs. Score how dev-friendly and AI-friendly they are. Get actionable issues before writing code.</p>
|
|
15
16
|
|
|
16
17
|
<p align="center"><strong><a href="https://let-sunny.github.io/canicode/">Try it in your browser</a></strong> — no install needed.</p>
|
|
17
18
|
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="docs/screenshot.png" alt="CanICode Report" width="720">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
18
23
|
```bash
|
|
19
24
|
npm install -g canicode
|
|
20
25
|
canicode init --token YOUR_FIGMA_TOKEN
|
|
@@ -40,13 +45,37 @@ canicode analyze "https://www.figma.com/design/ABC123/MyDesign?node-id=1-234"
|
|
|
40
45
|
|
|
41
46
|
Each issue is classified: **Blocking** > **Risk** > **Missing Info** > **Suggestion**.
|
|
42
47
|
|
|
43
|
-
Scores use density + diversity weighting per category, combined into an overall grade (S/A+/A/B+/B/C+/C/D/F).
|
|
48
|
+
Scores use density + diversity weighting per category, combined into an overall grade (S/A+/A/B+/B/C+/C/D/F). Rule scores are calibrated against actual code conversion difficulty — see [Calibration](docs/CALIBRATION.md) for how scores are validated.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Everything is Configurable
|
|
53
|
+
|
|
54
|
+
| What | How | Example |
|
|
55
|
+
|------|-----|---------|
|
|
56
|
+
| **Presets** | Built-in score profiles | `canicode analyze <url> --preset strict` |
|
|
57
|
+
| **Config overrides** | Adjust scores, severity, exclude nodes | `canicode analyze <url> --config ./config.json` |
|
|
58
|
+
| **Custom rules** | Add your own checks with pattern matching | `canicode analyze <url> --custom-rules ./rules.json` |
|
|
59
|
+
| **Combine** | Use all together | `canicode analyze <url> --preset ai-ready --config ./config.json --custom-rules ./rules.json` |
|
|
60
|
+
|
|
61
|
+
| Preset | What it does |
|
|
62
|
+
|--------|-------------|
|
|
63
|
+
| `relaxed` | Downgrades blocking → risk, scores −50% |
|
|
64
|
+
| `dev-friendly` | Layout and handoff rules only |
|
|
65
|
+
| `ai-ready` | Structure and naming weights +150% |
|
|
66
|
+
| `strict` | All rules enabled, scores +150% |
|
|
67
|
+
|
|
68
|
+
> **Custom rules tip:** Ask any LLM *"Write a canicode custom rule that checks X"* — it can generate the JSON for you. See [`docs/CUSTOMIZATION.md`](docs/CUSTOMIZATION.md) for the full guide.
|
|
44
69
|
|
|
45
70
|
---
|
|
46
71
|
|
|
47
72
|
## Getting Started
|
|
48
73
|
|
|
49
|
-
|
|
74
|
+
Five ways to use CanICode. Pick one.
|
|
75
|
+
|
|
76
|
+
### Figma Plugin (under review)
|
|
77
|
+
|
|
78
|
+
Install from **[Figma Community](https://www.figma.com/community/plugin/1617144221046795292/canicode)** — analyze directly inside Figma. No tokens needed.
|
|
50
79
|
|
|
51
80
|
### Web (no install)
|
|
52
81
|
|
|
@@ -212,6 +241,13 @@ canicode analyze <url> --custom-rules ./my-rules.json
|
|
|
212
241
|
|
|
213
242
|
Conditions use AND logic — all must match for the rule to fire. Available conditions: `type`, `notType`, `nameContains`, `nameNotContains`, `namePattern`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `hasAutoLayout`, `hasChildren`, `minChildren`, `maxChildren`, `isComponent`, `isInstance`, `hasComponentId`, `isVisible`, `hasFills`, `hasStrokes`, `hasEffects`, `minDepth`, `maxDepth`.
|
|
214
243
|
|
|
244
|
+
Combine with config overrides:
|
|
245
|
+
```bash
|
|
246
|
+
canicode analyze <url> --config ./config.json --custom-rules ./rules.json
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
> **Tip:** Ask any LLM *"Write a canicode custom rule that checks X"* with the conditions above — it can generate the JSON for you.
|
|
250
|
+
|
|
215
251
|
See [`examples/custom-rules.json`](examples/custom-rules.json) | [`docs/CUSTOMIZATION.md`](docs/CUSTOMIZATION.md)
|
|
216
252
|
|
|
217
253
|
</details>
|
|
@@ -228,6 +264,8 @@ Diversity Score = (1 - unique violated rules / total rules in category) × 100
|
|
|
228
264
|
|
|
229
265
|
Severity weights issues — a single blocking issue counts 3x more than a suggestion. Scores are calculated per category and combined into an overall grade (S/A+/A/B+/B/C+/C/D/F).
|
|
230
266
|
|
|
267
|
+
> Weights and rule scores are validated through a 4-agent calibration pipeline. See [docs/CALIBRATION.md](docs/CALIBRATION.md) for details.
|
|
268
|
+
|
|
231
269
|
</details>
|
|
232
270
|
|
|
233
271
|
<details>
|
|
@@ -323,6 +361,12 @@ pnpm lint # type check
|
|
|
323
361
|
- [x] **Phase 5** — Custom rules with pattern matching (node name/type/attribute conditions)
|
|
324
362
|
- [ ] **Phase 6** — Screenshot comparison (Figma vs AI-generated code, visual diff)
|
|
325
363
|
|
|
364
|
+
## Support
|
|
365
|
+
|
|
366
|
+
- **Bug reports:** [GitHub Issues](https://github.com/let-sunny/canicode/issues)
|
|
367
|
+
- **Questions and discussions:** [GitHub Issues](https://github.com/let-sunny/canicode/issues)
|
|
368
|
+
- **Privacy:** See [PRIVACY.md](PRIVACY.md) for details on data collection and how to opt out
|
|
369
|
+
|
|
326
370
|
## License
|
|
327
371
|
|
|
328
372
|
MIT
|
package/dist/mcp/server.js
CHANGED
|
@@ -3268,6 +3268,12 @@ Typical flow with Figma MCP:
|
|
|
3268
3268
|
configPath: z.string().optional().describe("Path to config JSON file for rule overrides"),
|
|
3269
3269
|
customRulesPath: z.string().optional().describe("Path to custom rules JSON file")
|
|
3270
3270
|
},
|
|
3271
|
+
{
|
|
3272
|
+
readOnlyHint: false,
|
|
3273
|
+
destructiveHint: false,
|
|
3274
|
+
openWorldHint: true,
|
|
3275
|
+
title: "Analyze Figma Design"
|
|
3276
|
+
},
|
|
3271
3277
|
async ({ designData, input, fileKey, fileName, token, preset, targetNodeId, configPath, customRulesPath }) => {
|
|
3272
3278
|
trackEvent(EVENTS.MCP_TOOL_CALLED, { tool: "analyze" });
|
|
3273
3279
|
try {
|
|
@@ -3374,6 +3380,12 @@ server.tool(
|
|
|
3374
3380
|
"list-rules",
|
|
3375
3381
|
"List all available analysis rules with their current configuration",
|
|
3376
3382
|
{},
|
|
3383
|
+
{
|
|
3384
|
+
readOnlyHint: true,
|
|
3385
|
+
destructiveHint: false,
|
|
3386
|
+
openWorldHint: false,
|
|
3387
|
+
title: "List Analysis Rules"
|
|
3388
|
+
},
|
|
3377
3389
|
async () => {
|
|
3378
3390
|
const rules = ruleRegistry.getAll().map((rule) => {
|
|
3379
3391
|
const config2 = RULE_CONFIGS[rule.definition.id];
|
|
@@ -3411,6 +3423,12 @@ Use this when the user asks about customization, configuration, rule settings, o
|
|
|
3411
3423
|
{
|
|
3412
3424
|
topic: z.enum(["all", "config", "custom-rules", "rules"]).optional().describe("Specific topic: config (overrides), custom-rules (adding new rules), rules (all rule IDs). Default: all")
|
|
3413
3425
|
},
|
|
3426
|
+
{
|
|
3427
|
+
readOnlyHint: true,
|
|
3428
|
+
destructiveHint: false,
|
|
3429
|
+
openWorldHint: false,
|
|
3430
|
+
title: "Get Customization Guide"
|
|
3431
|
+
},
|
|
3414
3432
|
async ({ topic }) => {
|
|
3415
3433
|
const { readFile: readFile4 } = await import('fs/promises');
|
|
3416
3434
|
const { resolve: resolve4, dirname } = await import('path');
|