canicode 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.
- package/LICENSE +21 -0
- package/README.md +298 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +4399 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +1104 -0
- package/dist/index.js +3513 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +3009 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +63 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1104 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { GetFileResponse } from '@figma/rest-api-spec';
|
|
3
|
+
|
|
4
|
+
declare const SeveritySchema: z.ZodEnum<{
|
|
5
|
+
blocking: "blocking";
|
|
6
|
+
risk: "risk";
|
|
7
|
+
"missing-info": "missing-info";
|
|
8
|
+
suggestion: "suggestion";
|
|
9
|
+
}>;
|
|
10
|
+
type Severity = z.infer<typeof SeveritySchema>;
|
|
11
|
+
declare const SEVERITY_WEIGHT: Record<Severity, number>;
|
|
12
|
+
declare const SEVERITY_LABELS: Record<Severity, string>;
|
|
13
|
+
|
|
14
|
+
declare const CategorySchema: z.ZodEnum<{
|
|
15
|
+
layout: "layout";
|
|
16
|
+
token: "token";
|
|
17
|
+
component: "component";
|
|
18
|
+
naming: "naming";
|
|
19
|
+
"ai-readability": "ai-readability";
|
|
20
|
+
"handoff-risk": "handoff-risk";
|
|
21
|
+
}>;
|
|
22
|
+
type Category = z.infer<typeof CategorySchema>;
|
|
23
|
+
declare const CATEGORIES: ("layout" | "token" | "component" | "naming" | "ai-readability" | "handoff-risk")[];
|
|
24
|
+
declare const CATEGORY_LABELS: Record<Category, string>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Figma node types required for analysis
|
|
28
|
+
* See @figma/rest-api-spec for full API types
|
|
29
|
+
*/
|
|
30
|
+
declare const AnalysisNodeTypeSchema: z.ZodEnum<{
|
|
31
|
+
DOCUMENT: "DOCUMENT";
|
|
32
|
+
CANVAS: "CANVAS";
|
|
33
|
+
FRAME: "FRAME";
|
|
34
|
+
GROUP: "GROUP";
|
|
35
|
+
SECTION: "SECTION";
|
|
36
|
+
COMPONENT: "COMPONENT";
|
|
37
|
+
COMPONENT_SET: "COMPONENT_SET";
|
|
38
|
+
INSTANCE: "INSTANCE";
|
|
39
|
+
RECTANGLE: "RECTANGLE";
|
|
40
|
+
ELLIPSE: "ELLIPSE";
|
|
41
|
+
VECTOR: "VECTOR";
|
|
42
|
+
TEXT: "TEXT";
|
|
43
|
+
LINE: "LINE";
|
|
44
|
+
BOOLEAN_OPERATION: "BOOLEAN_OPERATION";
|
|
45
|
+
STAR: "STAR";
|
|
46
|
+
REGULAR_POLYGON: "REGULAR_POLYGON";
|
|
47
|
+
SLICE: "SLICE";
|
|
48
|
+
STICKY: "STICKY";
|
|
49
|
+
SHAPE_WITH_TEXT: "SHAPE_WITH_TEXT";
|
|
50
|
+
CONNECTOR: "CONNECTOR";
|
|
51
|
+
WIDGET: "WIDGET";
|
|
52
|
+
EMBED: "EMBED";
|
|
53
|
+
LINK_UNFURL: "LINK_UNFURL";
|
|
54
|
+
TABLE: "TABLE";
|
|
55
|
+
TABLE_CELL: "TABLE_CELL";
|
|
56
|
+
}>;
|
|
57
|
+
type AnalysisNodeType = z.infer<typeof AnalysisNodeTypeSchema>;
|
|
58
|
+
declare const LayoutModeSchema: z.ZodEnum<{
|
|
59
|
+
NONE: "NONE";
|
|
60
|
+
HORIZONTAL: "HORIZONTAL";
|
|
61
|
+
VERTICAL: "VERTICAL";
|
|
62
|
+
}>;
|
|
63
|
+
type LayoutMode = z.infer<typeof LayoutModeSchema>;
|
|
64
|
+
declare const LayoutAlignSchema: z.ZodEnum<{
|
|
65
|
+
MIN: "MIN";
|
|
66
|
+
CENTER: "CENTER";
|
|
67
|
+
MAX: "MAX";
|
|
68
|
+
STRETCH: "STRETCH";
|
|
69
|
+
INHERIT: "INHERIT";
|
|
70
|
+
}>;
|
|
71
|
+
type LayoutAlign = z.infer<typeof LayoutAlignSchema>;
|
|
72
|
+
declare const LayoutPositioningSchema: z.ZodEnum<{
|
|
73
|
+
AUTO: "AUTO";
|
|
74
|
+
ABSOLUTE: "ABSOLUTE";
|
|
75
|
+
}>;
|
|
76
|
+
type LayoutPositioning = z.infer<typeof LayoutPositioningSchema>;
|
|
77
|
+
/**
|
|
78
|
+
* Lightweight FigmaNode type for analysis
|
|
79
|
+
* Contains only properties needed by rules
|
|
80
|
+
*/
|
|
81
|
+
declare const BaseAnalysisNodeSchema: z.ZodObject<{
|
|
82
|
+
id: z.ZodString;
|
|
83
|
+
name: z.ZodString;
|
|
84
|
+
type: z.ZodEnum<{
|
|
85
|
+
DOCUMENT: "DOCUMENT";
|
|
86
|
+
CANVAS: "CANVAS";
|
|
87
|
+
FRAME: "FRAME";
|
|
88
|
+
GROUP: "GROUP";
|
|
89
|
+
SECTION: "SECTION";
|
|
90
|
+
COMPONENT: "COMPONENT";
|
|
91
|
+
COMPONENT_SET: "COMPONENT_SET";
|
|
92
|
+
INSTANCE: "INSTANCE";
|
|
93
|
+
RECTANGLE: "RECTANGLE";
|
|
94
|
+
ELLIPSE: "ELLIPSE";
|
|
95
|
+
VECTOR: "VECTOR";
|
|
96
|
+
TEXT: "TEXT";
|
|
97
|
+
LINE: "LINE";
|
|
98
|
+
BOOLEAN_OPERATION: "BOOLEAN_OPERATION";
|
|
99
|
+
STAR: "STAR";
|
|
100
|
+
REGULAR_POLYGON: "REGULAR_POLYGON";
|
|
101
|
+
SLICE: "SLICE";
|
|
102
|
+
STICKY: "STICKY";
|
|
103
|
+
SHAPE_WITH_TEXT: "SHAPE_WITH_TEXT";
|
|
104
|
+
CONNECTOR: "CONNECTOR";
|
|
105
|
+
WIDGET: "WIDGET";
|
|
106
|
+
EMBED: "EMBED";
|
|
107
|
+
LINK_UNFURL: "LINK_UNFURL";
|
|
108
|
+
TABLE: "TABLE";
|
|
109
|
+
TABLE_CELL: "TABLE_CELL";
|
|
110
|
+
}>;
|
|
111
|
+
visible: z.ZodDefault<z.ZodBoolean>;
|
|
112
|
+
layoutMode: z.ZodOptional<z.ZodEnum<{
|
|
113
|
+
NONE: "NONE";
|
|
114
|
+
HORIZONTAL: "HORIZONTAL";
|
|
115
|
+
VERTICAL: "VERTICAL";
|
|
116
|
+
}>>;
|
|
117
|
+
layoutAlign: z.ZodOptional<z.ZodEnum<{
|
|
118
|
+
MIN: "MIN";
|
|
119
|
+
CENTER: "CENTER";
|
|
120
|
+
MAX: "MAX";
|
|
121
|
+
STRETCH: "STRETCH";
|
|
122
|
+
INHERIT: "INHERIT";
|
|
123
|
+
}>>;
|
|
124
|
+
layoutPositioning: z.ZodOptional<z.ZodEnum<{
|
|
125
|
+
AUTO: "AUTO";
|
|
126
|
+
ABSOLUTE: "ABSOLUTE";
|
|
127
|
+
}>>;
|
|
128
|
+
primaryAxisAlignItems: z.ZodOptional<z.ZodString>;
|
|
129
|
+
counterAxisAlignItems: z.ZodOptional<z.ZodString>;
|
|
130
|
+
itemSpacing: z.ZodOptional<z.ZodNumber>;
|
|
131
|
+
paddingLeft: z.ZodOptional<z.ZodNumber>;
|
|
132
|
+
paddingRight: z.ZodOptional<z.ZodNumber>;
|
|
133
|
+
paddingTop: z.ZodOptional<z.ZodNumber>;
|
|
134
|
+
paddingBottom: z.ZodOptional<z.ZodNumber>;
|
|
135
|
+
absoluteBoundingBox: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
136
|
+
x: z.ZodNumber;
|
|
137
|
+
y: z.ZodNumber;
|
|
138
|
+
width: z.ZodNumber;
|
|
139
|
+
height: z.ZodNumber;
|
|
140
|
+
}, z.core.$strip>>>;
|
|
141
|
+
componentId: z.ZodOptional<z.ZodString>;
|
|
142
|
+
componentPropertyDefinitions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
143
|
+
componentProperties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
144
|
+
styles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
145
|
+
fills: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
146
|
+
strokes: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
147
|
+
effects: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
148
|
+
boundVariables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
149
|
+
characters: z.ZodOptional<z.ZodString>;
|
|
150
|
+
style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
151
|
+
devStatus: z.ZodOptional<z.ZodObject<{
|
|
152
|
+
type: z.ZodEnum<{
|
|
153
|
+
NONE: "NONE";
|
|
154
|
+
READY_FOR_DEV: "READY_FOR_DEV";
|
|
155
|
+
COMPLETED: "COMPLETED";
|
|
156
|
+
}>;
|
|
157
|
+
description: z.ZodOptional<z.ZodString>;
|
|
158
|
+
}, z.core.$strip>>;
|
|
159
|
+
isAsset: z.ZodOptional<z.ZodBoolean>;
|
|
160
|
+
}, z.core.$strip>;
|
|
161
|
+
type AnalysisNode = z.infer<typeof BaseAnalysisNodeSchema> & {
|
|
162
|
+
children?: AnalysisNode[] | undefined;
|
|
163
|
+
};
|
|
164
|
+
declare const AnalysisNodeSchema: z.ZodType<AnalysisNode>;
|
|
165
|
+
/**
|
|
166
|
+
* Figma file metadata for analysis
|
|
167
|
+
*/
|
|
168
|
+
declare const AnalysisFileSchema: z.ZodObject<{
|
|
169
|
+
fileKey: z.ZodString;
|
|
170
|
+
name: z.ZodString;
|
|
171
|
+
lastModified: z.ZodString;
|
|
172
|
+
version: z.ZodString;
|
|
173
|
+
document: z.ZodType<AnalysisNode, unknown, z.core.$ZodTypeInternals<AnalysisNode, unknown>>;
|
|
174
|
+
components: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
175
|
+
key: z.ZodString;
|
|
176
|
+
name: z.ZodString;
|
|
177
|
+
description: z.ZodString;
|
|
178
|
+
}, z.core.$strip>>;
|
|
179
|
+
styles: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
180
|
+
key: z.ZodString;
|
|
181
|
+
name: z.ZodString;
|
|
182
|
+
styleType: z.ZodString;
|
|
183
|
+
}, z.core.$strip>>;
|
|
184
|
+
}, z.core.$strip>;
|
|
185
|
+
type AnalysisFile = z.infer<typeof AnalysisFileSchema>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Rule definition - static metadata (does not change)
|
|
189
|
+
*/
|
|
190
|
+
declare const RuleDefinitionSchema: z.ZodObject<{
|
|
191
|
+
id: z.ZodString;
|
|
192
|
+
name: z.ZodString;
|
|
193
|
+
category: z.ZodEnum<{
|
|
194
|
+
layout: "layout";
|
|
195
|
+
token: "token";
|
|
196
|
+
component: "component";
|
|
197
|
+
naming: "naming";
|
|
198
|
+
"ai-readability": "ai-readability";
|
|
199
|
+
"handoff-risk": "handoff-risk";
|
|
200
|
+
}>;
|
|
201
|
+
why: z.ZodString;
|
|
202
|
+
impact: z.ZodString;
|
|
203
|
+
fix: z.ZodString;
|
|
204
|
+
}, z.core.$strip>;
|
|
205
|
+
type RuleDefinition = z.infer<typeof RuleDefinitionSchema>;
|
|
206
|
+
/**
|
|
207
|
+
* Rule config - adjustable settings (can be modified via presets)
|
|
208
|
+
*/
|
|
209
|
+
declare const RuleConfigSchema: z.ZodObject<{
|
|
210
|
+
severity: z.ZodEnum<{
|
|
211
|
+
blocking: "blocking";
|
|
212
|
+
risk: "risk";
|
|
213
|
+
"missing-info": "missing-info";
|
|
214
|
+
suggestion: "suggestion";
|
|
215
|
+
}>;
|
|
216
|
+
score: z.ZodNumber;
|
|
217
|
+
depthWeight: z.ZodOptional<z.ZodNumber>;
|
|
218
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
219
|
+
options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
220
|
+
}, z.core.$strip>;
|
|
221
|
+
type RuleConfig = z.infer<typeof RuleConfigSchema>;
|
|
222
|
+
/**
|
|
223
|
+
* Context passed to rule check functions
|
|
224
|
+
*/
|
|
225
|
+
interface RuleContext {
|
|
226
|
+
file: AnalysisFile;
|
|
227
|
+
parent?: AnalysisNode | undefined;
|
|
228
|
+
depth: number;
|
|
229
|
+
maxDepth: number;
|
|
230
|
+
path: string[];
|
|
231
|
+
siblings?: AnalysisNode[] | undefined;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Rule violation result from check function
|
|
235
|
+
*/
|
|
236
|
+
interface RuleViolation {
|
|
237
|
+
ruleId: string;
|
|
238
|
+
nodeId: string;
|
|
239
|
+
nodePath: string;
|
|
240
|
+
message: string;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Rule check function signature
|
|
244
|
+
*/
|
|
245
|
+
type RuleCheckFn = (node: AnalysisNode, context: RuleContext, options?: Record<string, unknown>) => RuleViolation | null;
|
|
246
|
+
/**
|
|
247
|
+
* Complete rule with definition, config, and check function
|
|
248
|
+
*/
|
|
249
|
+
interface Rule {
|
|
250
|
+
definition: RuleDefinition;
|
|
251
|
+
check: RuleCheckFn;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Rule ID type for type safety
|
|
255
|
+
*/
|
|
256
|
+
type RuleId = "no-auto-layout" | "absolute-position-in-auto-layout" | "fixed-width-in-responsive-context" | "missing-responsive-behavior" | "group-usage" | "fixed-size-in-auto-layout" | "missing-min-width" | "missing-max-width" | "deep-nesting" | "overflow-hidden-abuse" | "inconsistent-sibling-layout-direction" | "raw-color" | "raw-font" | "inconsistent-spacing" | "magic-number-spacing" | "raw-shadow" | "raw-opacity" | "multiple-fill-colors" | "missing-component" | "detached-instance" | "nested-instance-override" | "variant-not-used" | "component-property-unused" | "single-use-component" | "default-name" | "non-semantic-name" | "inconsistent-naming-convention" | "numeric-suffix-name" | "too-long-name" | "ambiguous-structure" | "z-index-dependent-layout" | "missing-layout-hint" | "invisible-layer" | "empty-frame" | "hardcode-risk" | "text-truncation-unhandled" | "image-no-placeholder" | "prototype-link-in-design" | "no-dev-status";
|
|
257
|
+
/**
|
|
258
|
+
* Categories that support depthWeight
|
|
259
|
+
*/
|
|
260
|
+
declare const DEPTH_WEIGHT_CATEGORIES: Category[];
|
|
261
|
+
/**
|
|
262
|
+
* Check if a category supports depth weighting
|
|
263
|
+
*/
|
|
264
|
+
declare function supportsDepthWeight(category: Category): boolean;
|
|
265
|
+
|
|
266
|
+
declare const IssueSchema: z.ZodObject<{
|
|
267
|
+
nodeId: z.ZodString;
|
|
268
|
+
nodePath: z.ZodString;
|
|
269
|
+
figmaDeepLink: z.ZodString;
|
|
270
|
+
ruleId: z.ZodString;
|
|
271
|
+
message: z.ZodString;
|
|
272
|
+
severity: z.ZodEnum<{
|
|
273
|
+
blocking: "blocking";
|
|
274
|
+
risk: "risk";
|
|
275
|
+
"missing-info": "missing-info";
|
|
276
|
+
suggestion: "suggestion";
|
|
277
|
+
}>;
|
|
278
|
+
}, z.core.$strip>;
|
|
279
|
+
type Issue = z.infer<typeof IssueSchema>;
|
|
280
|
+
|
|
281
|
+
declare const CategoryScoreSchema: z.ZodObject<{
|
|
282
|
+
category: z.ZodEnum<{
|
|
283
|
+
layout: "layout";
|
|
284
|
+
token: "token";
|
|
285
|
+
component: "component";
|
|
286
|
+
naming: "naming";
|
|
287
|
+
"ai-readability": "ai-readability";
|
|
288
|
+
"handoff-risk": "handoff-risk";
|
|
289
|
+
}>;
|
|
290
|
+
score: z.ZodNumber;
|
|
291
|
+
maxScore: z.ZodNumber;
|
|
292
|
+
issueCount: z.ZodObject<{
|
|
293
|
+
error: z.ZodNumber;
|
|
294
|
+
warning: z.ZodNumber;
|
|
295
|
+
info: z.ZodNumber;
|
|
296
|
+
}, z.core.$strip>;
|
|
297
|
+
}, z.core.$strip>;
|
|
298
|
+
type CategoryScore = z.infer<typeof CategoryScoreSchema>;
|
|
299
|
+
|
|
300
|
+
declare const ReportMetadataSchema: z.ZodObject<{
|
|
301
|
+
fileKey: z.ZodString;
|
|
302
|
+
fileName: z.ZodString;
|
|
303
|
+
analyzedAt: z.ZodString;
|
|
304
|
+
version: z.ZodString;
|
|
305
|
+
}, z.core.$strip>;
|
|
306
|
+
type ReportMetadata = z.infer<typeof ReportMetadataSchema>;
|
|
307
|
+
declare const ReportSchema: z.ZodObject<{
|
|
308
|
+
metadata: z.ZodObject<{
|
|
309
|
+
fileKey: z.ZodString;
|
|
310
|
+
fileName: z.ZodString;
|
|
311
|
+
analyzedAt: z.ZodString;
|
|
312
|
+
version: z.ZodString;
|
|
313
|
+
}, z.core.$strip>;
|
|
314
|
+
totalScore: z.ZodNumber;
|
|
315
|
+
categoryScores: z.ZodArray<z.ZodObject<{
|
|
316
|
+
category: z.ZodEnum<{
|
|
317
|
+
layout: "layout";
|
|
318
|
+
token: "token";
|
|
319
|
+
component: "component";
|
|
320
|
+
naming: "naming";
|
|
321
|
+
"ai-readability": "ai-readability";
|
|
322
|
+
"handoff-risk": "handoff-risk";
|
|
323
|
+
}>;
|
|
324
|
+
score: z.ZodNumber;
|
|
325
|
+
maxScore: z.ZodNumber;
|
|
326
|
+
issueCount: z.ZodObject<{
|
|
327
|
+
error: z.ZodNumber;
|
|
328
|
+
warning: z.ZodNumber;
|
|
329
|
+
info: z.ZodNumber;
|
|
330
|
+
}, z.core.$strip>;
|
|
331
|
+
}, z.core.$strip>>;
|
|
332
|
+
issues: z.ZodArray<z.ZodObject<{
|
|
333
|
+
nodeId: z.ZodString;
|
|
334
|
+
nodePath: z.ZodString;
|
|
335
|
+
figmaDeepLink: z.ZodString;
|
|
336
|
+
ruleId: z.ZodString;
|
|
337
|
+
message: z.ZodString;
|
|
338
|
+
severity: z.ZodEnum<{
|
|
339
|
+
blocking: "blocking";
|
|
340
|
+
risk: "risk";
|
|
341
|
+
"missing-info": "missing-info";
|
|
342
|
+
suggestion: "suggestion";
|
|
343
|
+
}>;
|
|
344
|
+
}, z.core.$strip>>;
|
|
345
|
+
summary: z.ZodObject<{
|
|
346
|
+
totalNodes: z.ZodNumber;
|
|
347
|
+
analyzedNodes: z.ZodNumber;
|
|
348
|
+
errorCount: z.ZodNumber;
|
|
349
|
+
warningCount: z.ZodNumber;
|
|
350
|
+
infoCount: z.ZodNumber;
|
|
351
|
+
}, z.core.$strip>;
|
|
352
|
+
}, z.core.$strip>;
|
|
353
|
+
type Report = z.infer<typeof ReportSchema>;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Analysis issue with calculated score and metadata
|
|
357
|
+
*/
|
|
358
|
+
interface AnalysisIssue {
|
|
359
|
+
violation: RuleViolation;
|
|
360
|
+
rule: Rule;
|
|
361
|
+
config: RuleConfig;
|
|
362
|
+
depth: number;
|
|
363
|
+
maxDepth: number;
|
|
364
|
+
calculatedScore: number;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Analysis result from the rule engine
|
|
368
|
+
*/
|
|
369
|
+
interface AnalysisResult {
|
|
370
|
+
file: AnalysisFile;
|
|
371
|
+
issues: AnalysisIssue[];
|
|
372
|
+
maxDepth: number;
|
|
373
|
+
nodeCount: number;
|
|
374
|
+
analyzedAt: string;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Options for the rule engine
|
|
378
|
+
*/
|
|
379
|
+
interface RuleEngineOptions {
|
|
380
|
+
configs?: Record<RuleId, RuleConfig>;
|
|
381
|
+
enabledRules?: RuleId[];
|
|
382
|
+
disabledRules?: RuleId[];
|
|
383
|
+
targetNodeId?: string;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Rule engine for analyzing Figma files
|
|
387
|
+
*/
|
|
388
|
+
declare class RuleEngine {
|
|
389
|
+
private configs;
|
|
390
|
+
private enabledRuleIds;
|
|
391
|
+
private disabledRuleIds;
|
|
392
|
+
private targetNodeId;
|
|
393
|
+
constructor(options?: RuleEngineOptions);
|
|
394
|
+
/**
|
|
395
|
+
* Analyze a Figma file and return issues
|
|
396
|
+
*/
|
|
397
|
+
analyze(file: AnalysisFile): AnalysisResult;
|
|
398
|
+
/**
|
|
399
|
+
* Get rules that should be run based on configuration
|
|
400
|
+
*/
|
|
401
|
+
private getEnabledRules;
|
|
402
|
+
/**
|
|
403
|
+
* Recursively traverse the tree and run rules
|
|
404
|
+
*/
|
|
405
|
+
private traverseAndCheck;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Create a rule engine with default configuration
|
|
409
|
+
*/
|
|
410
|
+
declare function createRuleEngine(options?: RuleEngineOptions): RuleEngine;
|
|
411
|
+
/**
|
|
412
|
+
* Convenience function to analyze a file with default settings
|
|
413
|
+
*/
|
|
414
|
+
declare function analyzeFile(file: AnalysisFile, options?: RuleEngineOptions): AnalysisResult;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Score breakdown for a single category
|
|
418
|
+
*/
|
|
419
|
+
interface CategoryScoreResult {
|
|
420
|
+
category: Category;
|
|
421
|
+
score: number;
|
|
422
|
+
maxScore: number;
|
|
423
|
+
percentage: number;
|
|
424
|
+
issueCount: number;
|
|
425
|
+
uniqueRuleCount: number;
|
|
426
|
+
weightedIssueCount: number;
|
|
427
|
+
densityScore: number;
|
|
428
|
+
diversityScore: number;
|
|
429
|
+
bySeverity: Record<Severity, number>;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Overall score report
|
|
433
|
+
*/
|
|
434
|
+
interface ScoreReport {
|
|
435
|
+
overall: {
|
|
436
|
+
score: number;
|
|
437
|
+
maxScore: number;
|
|
438
|
+
percentage: number;
|
|
439
|
+
grade: Grade;
|
|
440
|
+
};
|
|
441
|
+
byCategory: Record<Category, CategoryScoreResult>;
|
|
442
|
+
summary: {
|
|
443
|
+
totalIssues: number;
|
|
444
|
+
blocking: number;
|
|
445
|
+
risk: number;
|
|
446
|
+
missingInfo: number;
|
|
447
|
+
suggestion: number;
|
|
448
|
+
nodeCount: number;
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Grade levels based on percentage
|
|
453
|
+
*/
|
|
454
|
+
type Grade = "S" | "A+" | "A" | "B+" | "B" | "C+" | "C" | "D" | "F";
|
|
455
|
+
/**
|
|
456
|
+
* Convert grade to a CSS-safe class name suffix
|
|
457
|
+
* e.g. "A+" -> "Aplus", "B+" -> "Bplus", "C+" -> "Cplus"
|
|
458
|
+
*/
|
|
459
|
+
declare function gradeToClassName(grade: Grade): string;
|
|
460
|
+
/**
|
|
461
|
+
* Calculate scores from analysis result using density + diversity scoring
|
|
462
|
+
*
|
|
463
|
+
* Density Score = 100 - (weighted issue count / node count) * 100
|
|
464
|
+
* Diversity Score = (1 - unique rules / total category rules) * 100
|
|
465
|
+
* Final Score = density * 0.7 + diversity * 0.3
|
|
466
|
+
*/
|
|
467
|
+
declare function calculateScores(result: AnalysisResult): ScoreReport;
|
|
468
|
+
/**
|
|
469
|
+
* Format score report as a summary string
|
|
470
|
+
*/
|
|
471
|
+
declare function formatScoreSummary(report: ScoreReport): string;
|
|
472
|
+
/**
|
|
473
|
+
* Get category label for display
|
|
474
|
+
*/
|
|
475
|
+
declare function getCategoryLabel(category: Category): string;
|
|
476
|
+
/**
|
|
477
|
+
* Get severity label for display
|
|
478
|
+
*/
|
|
479
|
+
declare function getSeverityLabel(severity: Severity): string;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Registry for all rules
|
|
483
|
+
*/
|
|
484
|
+
declare class RuleRegistry {
|
|
485
|
+
private rules;
|
|
486
|
+
/**
|
|
487
|
+
* Register a rule
|
|
488
|
+
*/
|
|
489
|
+
register(rule: Rule): void;
|
|
490
|
+
/**
|
|
491
|
+
* Get a rule by ID
|
|
492
|
+
*/
|
|
493
|
+
get(id: RuleId): Rule | undefined;
|
|
494
|
+
/**
|
|
495
|
+
* Get all registered rules
|
|
496
|
+
*/
|
|
497
|
+
getAll(): Rule[];
|
|
498
|
+
/**
|
|
499
|
+
* Get rules by category
|
|
500
|
+
*/
|
|
501
|
+
getByCategory(category: Category): Rule[];
|
|
502
|
+
/**
|
|
503
|
+
* Get enabled rules with their configs
|
|
504
|
+
*/
|
|
505
|
+
getEnabled(configs?: Record<RuleId, RuleConfig>): Rule[];
|
|
506
|
+
/**
|
|
507
|
+
* Get config for a rule
|
|
508
|
+
*/
|
|
509
|
+
getConfig(id: RuleId, configs?: Record<RuleId, RuleConfig>): RuleConfig;
|
|
510
|
+
/**
|
|
511
|
+
* Check if a rule is registered
|
|
512
|
+
*/
|
|
513
|
+
has(id: RuleId): boolean;
|
|
514
|
+
/**
|
|
515
|
+
* Get count of registered rules
|
|
516
|
+
*/
|
|
517
|
+
get size(): number;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Global rule registry instance
|
|
521
|
+
*/
|
|
522
|
+
declare const ruleRegistry: RuleRegistry;
|
|
523
|
+
/**
|
|
524
|
+
* Helper to create and register a rule
|
|
525
|
+
*/
|
|
526
|
+
declare function defineRule(rule: Rule): Rule;
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Central configuration for all rules
|
|
530
|
+
* Edit scores/severity here without touching rule logic
|
|
531
|
+
*/
|
|
532
|
+
declare const RULE_CONFIGS: Record<RuleId, RuleConfig>;
|
|
533
|
+
/**
|
|
534
|
+
* Preset types for different analysis modes
|
|
535
|
+
*/
|
|
536
|
+
type Preset = "relaxed" | "dev-friendly" | "ai-ready" | "strict";
|
|
537
|
+
/**
|
|
538
|
+
* Get rule configs with preset applied
|
|
539
|
+
*/
|
|
540
|
+
declare function getConfigsWithPreset(preset: Preset): Record<RuleId, RuleConfig>;
|
|
541
|
+
/**
|
|
542
|
+
* Get option value for a rule with type safety
|
|
543
|
+
*/
|
|
544
|
+
declare function getRuleOption<T>(ruleId: RuleId, optionKey: string, defaultValue: T): T;
|
|
545
|
+
|
|
546
|
+
declare const noAutoLayout: Rule;
|
|
547
|
+
declare const absolutePositionInAutoLayout: Rule;
|
|
548
|
+
declare const fixedWidthInResponsiveContext: Rule;
|
|
549
|
+
declare const missingResponsiveBehavior: Rule;
|
|
550
|
+
declare const groupUsage: Rule;
|
|
551
|
+
declare const fixedSizeInAutoLayout: Rule;
|
|
552
|
+
declare const missingMinWidth: Rule;
|
|
553
|
+
declare const missingMaxWidth: Rule;
|
|
554
|
+
declare const deepNesting: Rule;
|
|
555
|
+
declare const overflowHiddenAbuse: Rule;
|
|
556
|
+
declare const inconsistentSiblingLayoutDirection: Rule;
|
|
557
|
+
|
|
558
|
+
declare const rawColor: Rule;
|
|
559
|
+
declare const rawFont: Rule;
|
|
560
|
+
declare const inconsistentSpacing: Rule;
|
|
561
|
+
declare const magicNumberSpacing: Rule;
|
|
562
|
+
declare const rawShadow: Rule;
|
|
563
|
+
declare const rawOpacity: Rule;
|
|
564
|
+
declare const multipleFillColors: Rule;
|
|
565
|
+
|
|
566
|
+
declare const missingComponent: Rule;
|
|
567
|
+
declare const detachedInstance: Rule;
|
|
568
|
+
declare const nestedInstanceOverride: Rule;
|
|
569
|
+
declare const variantNotUsed: Rule;
|
|
570
|
+
declare const componentPropertyUnused: Rule;
|
|
571
|
+
declare const singleUseComponent: Rule;
|
|
572
|
+
|
|
573
|
+
declare const defaultName: Rule;
|
|
574
|
+
declare const nonSemanticName: Rule;
|
|
575
|
+
declare const inconsistentNamingConvention: Rule;
|
|
576
|
+
declare const numericSuffixName: Rule;
|
|
577
|
+
declare const tooLongName: Rule;
|
|
578
|
+
|
|
579
|
+
declare const ambiguousStructure: Rule;
|
|
580
|
+
declare const zIndexDependentLayout: Rule;
|
|
581
|
+
declare const missingLayoutHint: Rule;
|
|
582
|
+
declare const invisibleLayer: Rule;
|
|
583
|
+
declare const emptyFrame: Rule;
|
|
584
|
+
|
|
585
|
+
declare const hardcodeRisk: Rule;
|
|
586
|
+
declare const textTruncationUnhandled: Rule;
|
|
587
|
+
declare const imageNoPlaceholder: Rule;
|
|
588
|
+
declare const prototypeLinkInDesign: Rule;
|
|
589
|
+
declare const noDevStatus: Rule;
|
|
590
|
+
|
|
591
|
+
declare const FigmaUrlInfoSchema: z.ZodObject<{
|
|
592
|
+
fileKey: z.ZodString;
|
|
593
|
+
nodeId: z.ZodOptional<z.ZodString>;
|
|
594
|
+
fileName: z.ZodOptional<z.ZodString>;
|
|
595
|
+
}, z.core.$strip>;
|
|
596
|
+
type FigmaUrlInfo = z.infer<typeof FigmaUrlInfoSchema>;
|
|
597
|
+
declare function parseFigmaUrl(url: string): FigmaUrlInfo;
|
|
598
|
+
declare class FigmaUrlParseError extends Error {
|
|
599
|
+
constructor(message: string);
|
|
600
|
+
}
|
|
601
|
+
declare function buildFigmaDeepLink(fileKey: string, nodeId: string): string;
|
|
602
|
+
|
|
603
|
+
interface FigmaClientOptions {
|
|
604
|
+
token: string;
|
|
605
|
+
}
|
|
606
|
+
declare class FigmaClient {
|
|
607
|
+
private token;
|
|
608
|
+
constructor(options: FigmaClientOptions);
|
|
609
|
+
static fromEnv(): FigmaClient;
|
|
610
|
+
getFile(fileKey: string): Promise<GetFileResponse>;
|
|
611
|
+
/**
|
|
612
|
+
* Get rendered images for specific nodes
|
|
613
|
+
* Returns a map of nodeId → image URL
|
|
614
|
+
*/
|
|
615
|
+
getNodeImages(fileKey: string, nodeIds: string[], options?: {
|
|
616
|
+
format?: "png" | "svg" | "jpg";
|
|
617
|
+
scale?: number;
|
|
618
|
+
}): Promise<Record<string, string | null>>;
|
|
619
|
+
/**
|
|
620
|
+
* Download an image URL and return as base64
|
|
621
|
+
*/
|
|
622
|
+
fetchImageAsBase64(imageUrl: string): Promise<string>;
|
|
623
|
+
getFileNodes(fileKey: string, nodeIds: string[]): Promise<GetFileResponse>;
|
|
624
|
+
}
|
|
625
|
+
declare class FigmaClientError extends Error {
|
|
626
|
+
statusCode?: number | undefined;
|
|
627
|
+
responseBody?: unknown | undefined;
|
|
628
|
+
constructor(message: string, statusCode?: number | undefined, responseBody?: unknown | undefined);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Transform Figma API response to analysis types
|
|
633
|
+
*/
|
|
634
|
+
declare function transformFigmaResponse(fileKey: string, response: GetFileResponse): AnalysisFile;
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Load Figma data from a JSON file
|
|
638
|
+
* For MVP testing and fixture support
|
|
639
|
+
*/
|
|
640
|
+
declare function loadFigmaFileFromJson(filePath: string): Promise<AnalysisFile>;
|
|
641
|
+
/**
|
|
642
|
+
* Parse Figma data from a JSON string
|
|
643
|
+
*/
|
|
644
|
+
declare function parseFigmaJson(json: string, fileKey: string): AnalysisFile;
|
|
645
|
+
declare class FigmaFileLoadError extends Error {
|
|
646
|
+
filePath?: string | undefined;
|
|
647
|
+
constructor(message: string, filePath?: string | undefined);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Parse MCP get_metadata XML output into an AnalysisFile.
|
|
652
|
+
*
|
|
653
|
+
* The XML represents a subtree of the Figma file. We wrap it in a
|
|
654
|
+
* DOCUMENT node and fill in minimal file metadata.
|
|
655
|
+
*/
|
|
656
|
+
declare function parseMcpMetadataXml(xml: string, fileKey: string, fileName?: string): AnalysisFile;
|
|
657
|
+
|
|
658
|
+
declare const SamplingStrategySchema: z.ZodEnum<{
|
|
659
|
+
all: "all";
|
|
660
|
+
"top-issues": "top-issues";
|
|
661
|
+
random: "random";
|
|
662
|
+
}>;
|
|
663
|
+
type SamplingStrategy = z.infer<typeof SamplingStrategySchema>;
|
|
664
|
+
declare const CalibrationStatusSchema: z.ZodEnum<{
|
|
665
|
+
pending: "pending";
|
|
666
|
+
analyzing: "analyzing";
|
|
667
|
+
converting: "converting";
|
|
668
|
+
evaluating: "evaluating";
|
|
669
|
+
tuning: "tuning";
|
|
670
|
+
completed: "completed";
|
|
671
|
+
failed: "failed";
|
|
672
|
+
}>;
|
|
673
|
+
type CalibrationStatus = z.infer<typeof CalibrationStatusSchema>;
|
|
674
|
+
declare const CalibrationConfigSchema: z.ZodObject<{
|
|
675
|
+
input: z.ZodString;
|
|
676
|
+
token: z.ZodOptional<z.ZodString>;
|
|
677
|
+
targetNodeId: z.ZodOptional<z.ZodString>;
|
|
678
|
+
maxConversionNodes: z.ZodDefault<z.ZodNumber>;
|
|
679
|
+
samplingStrategy: z.ZodDefault<z.ZodEnum<{
|
|
680
|
+
all: "all";
|
|
681
|
+
"top-issues": "top-issues";
|
|
682
|
+
random: "random";
|
|
683
|
+
}>>;
|
|
684
|
+
outputPath: z.ZodDefault<z.ZodString>;
|
|
685
|
+
}, z.core.$strip>;
|
|
686
|
+
type CalibrationConfig = z.infer<typeof CalibrationConfigSchema>;
|
|
687
|
+
interface CalibrationRun {
|
|
688
|
+
config: CalibrationConfig;
|
|
689
|
+
status: CalibrationStatus;
|
|
690
|
+
startedAt: string;
|
|
691
|
+
completedAt?: string;
|
|
692
|
+
error?: string;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
declare const NodeIssueSummarySchema: z.ZodObject<{
|
|
696
|
+
nodeId: z.ZodString;
|
|
697
|
+
nodePath: z.ZodString;
|
|
698
|
+
totalScore: z.ZodNumber;
|
|
699
|
+
issueCount: z.ZodNumber;
|
|
700
|
+
flaggedRuleIds: z.ZodArray<z.ZodString>;
|
|
701
|
+
severities: z.ZodArray<z.ZodString>;
|
|
702
|
+
}, z.core.$strip>;
|
|
703
|
+
type NodeIssueSummary = z.infer<typeof NodeIssueSummarySchema>;
|
|
704
|
+
interface AnalysisAgentInput {
|
|
705
|
+
analysisResult: AnalysisResult;
|
|
706
|
+
}
|
|
707
|
+
interface AnalysisAgentOutput {
|
|
708
|
+
analysisResult: AnalysisResult;
|
|
709
|
+
scoreReport: ScoreReport;
|
|
710
|
+
nodeIssueSummaries: NodeIssueSummary[];
|
|
711
|
+
}
|
|
712
|
+
interface NodeIssueDetail {
|
|
713
|
+
ruleId: RuleId;
|
|
714
|
+
severity: Severity;
|
|
715
|
+
calculatedScore: number;
|
|
716
|
+
message: string;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
declare const DifficultySchema: z.ZodEnum<{
|
|
720
|
+
failed: "failed";
|
|
721
|
+
easy: "easy";
|
|
722
|
+
moderate: "moderate";
|
|
723
|
+
hard: "hard";
|
|
724
|
+
}>;
|
|
725
|
+
type Difficulty = z.infer<typeof DifficultySchema>;
|
|
726
|
+
declare const RuleRelatedStruggleSchema: z.ZodObject<{
|
|
727
|
+
ruleId: z.ZodString;
|
|
728
|
+
description: z.ZodString;
|
|
729
|
+
actualImpact: z.ZodEnum<{
|
|
730
|
+
failed: "failed";
|
|
731
|
+
easy: "easy";
|
|
732
|
+
moderate: "moderate";
|
|
733
|
+
hard: "hard";
|
|
734
|
+
}>;
|
|
735
|
+
}, z.core.$strip>;
|
|
736
|
+
type RuleRelatedStruggle = z.infer<typeof RuleRelatedStruggleSchema>;
|
|
737
|
+
declare const UncoveredStruggleSchema: z.ZodObject<{
|
|
738
|
+
description: z.ZodString;
|
|
739
|
+
suggestedCategory: z.ZodString;
|
|
740
|
+
estimatedImpact: z.ZodEnum<{
|
|
741
|
+
failed: "failed";
|
|
742
|
+
easy: "easy";
|
|
743
|
+
moderate: "moderate";
|
|
744
|
+
hard: "hard";
|
|
745
|
+
}>;
|
|
746
|
+
}, z.core.$strip>;
|
|
747
|
+
type UncoveredStruggle = z.infer<typeof UncoveredStruggleSchema>;
|
|
748
|
+
declare const ConversionRecordSchema: z.ZodObject<{
|
|
749
|
+
nodeId: z.ZodString;
|
|
750
|
+
nodePath: z.ZodString;
|
|
751
|
+
generatedCode: z.ZodString;
|
|
752
|
+
difficulty: z.ZodEnum<{
|
|
753
|
+
failed: "failed";
|
|
754
|
+
easy: "easy";
|
|
755
|
+
moderate: "moderate";
|
|
756
|
+
hard: "hard";
|
|
757
|
+
}>;
|
|
758
|
+
notes: z.ZodString;
|
|
759
|
+
ruleRelatedStruggles: z.ZodArray<z.ZodObject<{
|
|
760
|
+
ruleId: z.ZodString;
|
|
761
|
+
description: z.ZodString;
|
|
762
|
+
actualImpact: z.ZodEnum<{
|
|
763
|
+
failed: "failed";
|
|
764
|
+
easy: "easy";
|
|
765
|
+
moderate: "moderate";
|
|
766
|
+
hard: "hard";
|
|
767
|
+
}>;
|
|
768
|
+
}, z.core.$strip>>;
|
|
769
|
+
uncoveredStruggles: z.ZodArray<z.ZodObject<{
|
|
770
|
+
description: z.ZodString;
|
|
771
|
+
suggestedCategory: z.ZodString;
|
|
772
|
+
estimatedImpact: z.ZodEnum<{
|
|
773
|
+
failed: "failed";
|
|
774
|
+
easy: "easy";
|
|
775
|
+
moderate: "moderate";
|
|
776
|
+
hard: "hard";
|
|
777
|
+
}>;
|
|
778
|
+
}, z.core.$strip>>;
|
|
779
|
+
durationMs: z.ZodNumber;
|
|
780
|
+
}, z.core.$strip>;
|
|
781
|
+
type ConversionRecord = z.infer<typeof ConversionRecordSchema>;
|
|
782
|
+
interface ConversionExecutorResult {
|
|
783
|
+
generatedCode: string;
|
|
784
|
+
difficulty: Difficulty;
|
|
785
|
+
notes: string;
|
|
786
|
+
ruleRelatedStruggles: RuleRelatedStruggle[];
|
|
787
|
+
uncoveredStruggles: UncoveredStruggle[];
|
|
788
|
+
}
|
|
789
|
+
type ConversionExecutor = (nodeId: string, fileKey: string, flaggedRuleIds: string[]) => Promise<ConversionExecutorResult>;
|
|
790
|
+
interface ConversionAgentInput {
|
|
791
|
+
fileKey: string;
|
|
792
|
+
nodes: Array<{
|
|
793
|
+
nodeId: string;
|
|
794
|
+
nodePath: string;
|
|
795
|
+
flaggedRuleIds: string[];
|
|
796
|
+
}>;
|
|
797
|
+
}
|
|
798
|
+
interface ConversionAgentOutput {
|
|
799
|
+
records: ConversionRecord[];
|
|
800
|
+
skippedNodeIds: string[];
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
declare const MismatchTypeSchema: z.ZodEnum<{
|
|
804
|
+
overscored: "overscored";
|
|
805
|
+
underscored: "underscored";
|
|
806
|
+
"missing-rule": "missing-rule";
|
|
807
|
+
validated: "validated";
|
|
808
|
+
}>;
|
|
809
|
+
type MismatchType = z.infer<typeof MismatchTypeSchema>;
|
|
810
|
+
declare const MismatchCaseSchema: z.ZodObject<{
|
|
811
|
+
type: z.ZodEnum<{
|
|
812
|
+
overscored: "overscored";
|
|
813
|
+
underscored: "underscored";
|
|
814
|
+
"missing-rule": "missing-rule";
|
|
815
|
+
validated: "validated";
|
|
816
|
+
}>;
|
|
817
|
+
nodeId: z.ZodString;
|
|
818
|
+
nodePath: z.ZodString;
|
|
819
|
+
ruleId: z.ZodOptional<z.ZodString>;
|
|
820
|
+
currentScore: z.ZodOptional<z.ZodNumber>;
|
|
821
|
+
currentSeverity: z.ZodOptional<z.ZodEnum<{
|
|
822
|
+
blocking: "blocking";
|
|
823
|
+
risk: "risk";
|
|
824
|
+
"missing-info": "missing-info";
|
|
825
|
+
suggestion: "suggestion";
|
|
826
|
+
}>>;
|
|
827
|
+
actualDifficulty: z.ZodEnum<{
|
|
828
|
+
failed: "failed";
|
|
829
|
+
easy: "easy";
|
|
830
|
+
moderate: "moderate";
|
|
831
|
+
hard: "hard";
|
|
832
|
+
}>;
|
|
833
|
+
reasoning: z.ZodString;
|
|
834
|
+
}, z.core.$strip>;
|
|
835
|
+
type MismatchCase = z.infer<typeof MismatchCaseSchema>;
|
|
836
|
+
interface EvaluationAgentInput {
|
|
837
|
+
nodeIssueSummaries: Array<{
|
|
838
|
+
nodeId: string;
|
|
839
|
+
nodePath: string;
|
|
840
|
+
flaggedRuleIds: string[];
|
|
841
|
+
}>;
|
|
842
|
+
conversionRecords: Array<{
|
|
843
|
+
nodeId: string;
|
|
844
|
+
nodePath: string;
|
|
845
|
+
difficulty: string;
|
|
846
|
+
ruleRelatedStruggles: Array<{
|
|
847
|
+
ruleId: string;
|
|
848
|
+
description: string;
|
|
849
|
+
actualImpact: string;
|
|
850
|
+
}>;
|
|
851
|
+
uncoveredStruggles: Array<{
|
|
852
|
+
description: string;
|
|
853
|
+
suggestedCategory: string;
|
|
854
|
+
estimatedImpact: string;
|
|
855
|
+
}>;
|
|
856
|
+
}>;
|
|
857
|
+
ruleScores: Record<string, {
|
|
858
|
+
score: number;
|
|
859
|
+
severity: string;
|
|
860
|
+
}>;
|
|
861
|
+
}
|
|
862
|
+
interface EvaluationAgentOutput {
|
|
863
|
+
mismatches: MismatchCase[];
|
|
864
|
+
validatedRules: string[];
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
declare const ConfidenceSchema: z.ZodEnum<{
|
|
868
|
+
high: "high";
|
|
869
|
+
medium: "medium";
|
|
870
|
+
low: "low";
|
|
871
|
+
}>;
|
|
872
|
+
type Confidence = z.infer<typeof ConfidenceSchema>;
|
|
873
|
+
declare const ScoreAdjustmentSchema: z.ZodObject<{
|
|
874
|
+
ruleId: z.ZodString;
|
|
875
|
+
currentScore: z.ZodNumber;
|
|
876
|
+
proposedScore: z.ZodNumber;
|
|
877
|
+
currentSeverity: z.ZodEnum<{
|
|
878
|
+
blocking: "blocking";
|
|
879
|
+
risk: "risk";
|
|
880
|
+
"missing-info": "missing-info";
|
|
881
|
+
suggestion: "suggestion";
|
|
882
|
+
}>;
|
|
883
|
+
proposedSeverity: z.ZodOptional<z.ZodEnum<{
|
|
884
|
+
blocking: "blocking";
|
|
885
|
+
risk: "risk";
|
|
886
|
+
"missing-info": "missing-info";
|
|
887
|
+
suggestion: "suggestion";
|
|
888
|
+
}>>;
|
|
889
|
+
reasoning: z.ZodString;
|
|
890
|
+
confidence: z.ZodEnum<{
|
|
891
|
+
high: "high";
|
|
892
|
+
medium: "medium";
|
|
893
|
+
low: "low";
|
|
894
|
+
}>;
|
|
895
|
+
supportingCases: z.ZodNumber;
|
|
896
|
+
}, z.core.$strip>;
|
|
897
|
+
type ScoreAdjustment = z.infer<typeof ScoreAdjustmentSchema>;
|
|
898
|
+
declare const NewRuleProposalSchema: z.ZodObject<{
|
|
899
|
+
suggestedId: z.ZodString;
|
|
900
|
+
category: z.ZodString;
|
|
901
|
+
description: z.ZodString;
|
|
902
|
+
suggestedSeverity: z.ZodEnum<{
|
|
903
|
+
blocking: "blocking";
|
|
904
|
+
risk: "risk";
|
|
905
|
+
"missing-info": "missing-info";
|
|
906
|
+
suggestion: "suggestion";
|
|
907
|
+
}>;
|
|
908
|
+
suggestedScore: z.ZodNumber;
|
|
909
|
+
reasoning: z.ZodString;
|
|
910
|
+
supportingCases: z.ZodNumber;
|
|
911
|
+
}, z.core.$strip>;
|
|
912
|
+
type NewRuleProposal = z.infer<typeof NewRuleProposalSchema>;
|
|
913
|
+
interface TuningAgentInput {
|
|
914
|
+
mismatches: Array<{
|
|
915
|
+
type: string;
|
|
916
|
+
nodeId: string;
|
|
917
|
+
nodePath: string;
|
|
918
|
+
ruleId?: string | undefined;
|
|
919
|
+
currentScore?: number | undefined;
|
|
920
|
+
currentSeverity?: string | undefined;
|
|
921
|
+
actualDifficulty: string;
|
|
922
|
+
reasoning: string;
|
|
923
|
+
}>;
|
|
924
|
+
ruleScores: Record<string, {
|
|
925
|
+
score: number;
|
|
926
|
+
severity: string;
|
|
927
|
+
}>;
|
|
928
|
+
}
|
|
929
|
+
interface TuningAgentOutput {
|
|
930
|
+
adjustments: ScoreAdjustment[];
|
|
931
|
+
newRuleProposals: NewRuleProposal[];
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Extract rule scores map from analysis result for downstream agents
|
|
936
|
+
*/
|
|
937
|
+
declare function extractRuleScores(result: AnalysisResult): Record<string, {
|
|
938
|
+
score: number;
|
|
939
|
+
severity: string;
|
|
940
|
+
}>;
|
|
941
|
+
/**
|
|
942
|
+
* Analysis Agent - Step 1 of calibration pipeline
|
|
943
|
+
*
|
|
944
|
+
* Wraps existing analyzeFile + calculateScores and adds
|
|
945
|
+
* nodeId-grouped issue summaries for downstream agents.
|
|
946
|
+
*/
|
|
947
|
+
declare function runAnalysisAgent(input: AnalysisAgentInput): AnalysisAgentOutput;
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Conversion Agent - Step 2 of calibration pipeline
|
|
951
|
+
*
|
|
952
|
+
* Attempts code conversion for each node via an injected executor.
|
|
953
|
+
* Uses dependency inversion: the executor handles actual LLM/MCP calls.
|
|
954
|
+
* Failures on individual nodes are captured, not thrown.
|
|
955
|
+
*/
|
|
956
|
+
declare function runConversionAgent(input: ConversionAgentInput, executor: ConversionExecutor): Promise<ConversionAgentOutput>;
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Prompt template for the conversion executor.
|
|
960
|
+
*
|
|
961
|
+
* The executor (typically an LLM session with Figma MCP access) receives
|
|
962
|
+
* this prompt to guide code generation and difficulty assessment.
|
|
963
|
+
*/
|
|
964
|
+
declare function buildConversionPrompt(nodeId: string, fileKey: string, flaggedRuleIds: string[]): string;
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Evaluation Agent - Step 3 of calibration pipeline
|
|
968
|
+
*
|
|
969
|
+
* Deterministic comparison of analysis results vs conversion results.
|
|
970
|
+
* No LLM required — pure algorithmic evaluation.
|
|
971
|
+
*/
|
|
972
|
+
declare function runEvaluationAgent(input: EvaluationAgentInput): EvaluationAgentOutput;
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Tuning Agent - Step 4 of calibration pipeline
|
|
976
|
+
*
|
|
977
|
+
* Deterministic aggregation algorithm. No LLM required.
|
|
978
|
+
* Aggregates mismatch cases into score adjustment proposals.
|
|
979
|
+
*/
|
|
980
|
+
declare function runTuningAgent(input: TuningAgentInput): TuningAgentOutput;
|
|
981
|
+
|
|
982
|
+
interface CalibrationReportData {
|
|
983
|
+
fileKey: string;
|
|
984
|
+
fileName: string;
|
|
985
|
+
analyzedAt: string;
|
|
986
|
+
nodeCount: number;
|
|
987
|
+
issueCount: number;
|
|
988
|
+
convertedNodeCount: number;
|
|
989
|
+
skippedNodeCount: number;
|
|
990
|
+
scoreReport: ScoreReport;
|
|
991
|
+
mismatches: MismatchCase[];
|
|
992
|
+
validatedRules: string[];
|
|
993
|
+
adjustments: ScoreAdjustment[];
|
|
994
|
+
newRuleProposals: NewRuleProposal[];
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Generate a CALIBRATION_REPORT.md from calibration pipeline results
|
|
998
|
+
*/
|
|
999
|
+
declare function generateCalibrationReport(data: CalibrationReportData): string;
|
|
1000
|
+
|
|
1001
|
+
interface CalibrationRunOptions {
|
|
1002
|
+
enableActivityLog?: boolean;
|
|
1003
|
+
}
|
|
1004
|
+
interface CalibrationRunResult {
|
|
1005
|
+
status: CalibrationStatus;
|
|
1006
|
+
scoreReport: ScoreReport;
|
|
1007
|
+
nodeIssueSummaries: NodeIssueSummary[];
|
|
1008
|
+
mismatches: MismatchCase[];
|
|
1009
|
+
validatedRules: string[];
|
|
1010
|
+
adjustments: ScoreAdjustment[];
|
|
1011
|
+
newRuleProposals: NewRuleProposal[];
|
|
1012
|
+
reportPath: string;
|
|
1013
|
+
logPath?: string | undefined;
|
|
1014
|
+
error?: string;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Run Step 1 only: analysis + save JSON output
|
|
1018
|
+
*/
|
|
1019
|
+
declare function runCalibrationAnalyze(config: CalibrationConfig): Promise<{
|
|
1020
|
+
analysisOutput: ReturnType<typeof runAnalysisAgent> extends infer T ? T : never;
|
|
1021
|
+
ruleScores: Record<string, {
|
|
1022
|
+
score: number;
|
|
1023
|
+
severity: string;
|
|
1024
|
+
}>;
|
|
1025
|
+
fileKey: string;
|
|
1026
|
+
}>;
|
|
1027
|
+
/**
|
|
1028
|
+
* Run Steps 3+4: evaluation + tuning from pre-computed analysis and conversion data
|
|
1029
|
+
*/
|
|
1030
|
+
declare function runCalibrationEvaluate(analysisJson: {
|
|
1031
|
+
nodeIssueSummaries: NodeIssueSummary[];
|
|
1032
|
+
scoreReport: ScoreReport;
|
|
1033
|
+
fileKey: string;
|
|
1034
|
+
fileName: string;
|
|
1035
|
+
analyzedAt: string;
|
|
1036
|
+
nodeCount: number;
|
|
1037
|
+
issueCount: number;
|
|
1038
|
+
}, conversionJson: {
|
|
1039
|
+
records: Array<{
|
|
1040
|
+
nodeId: string;
|
|
1041
|
+
nodePath: string;
|
|
1042
|
+
difficulty: string;
|
|
1043
|
+
ruleRelatedStruggles: Array<{
|
|
1044
|
+
ruleId: string;
|
|
1045
|
+
description: string;
|
|
1046
|
+
actualImpact: string;
|
|
1047
|
+
}>;
|
|
1048
|
+
uncoveredStruggles: Array<{
|
|
1049
|
+
description: string;
|
|
1050
|
+
suggestedCategory: string;
|
|
1051
|
+
estimatedImpact: string;
|
|
1052
|
+
}>;
|
|
1053
|
+
}>;
|
|
1054
|
+
skippedNodeIds: string[];
|
|
1055
|
+
}, ruleScores: Record<string, {
|
|
1056
|
+
score: number;
|
|
1057
|
+
severity: string;
|
|
1058
|
+
}>): {
|
|
1059
|
+
evaluationOutput: EvaluationAgentOutput;
|
|
1060
|
+
tuningOutput: TuningAgentOutput;
|
|
1061
|
+
report: string;
|
|
1062
|
+
};
|
|
1063
|
+
/**
|
|
1064
|
+
* Run the full calibration pipeline
|
|
1065
|
+
*
|
|
1066
|
+
* Sequence: validate -> load file -> analysis -> node selection -> conversion -> evaluation -> tuning -> report
|
|
1067
|
+
*/
|
|
1068
|
+
declare function runCalibration(config: CalibrationConfig, executor: ConversionExecutor, options?: CalibrationRunOptions): Promise<CalibrationRunResult>;
|
|
1069
|
+
|
|
1070
|
+
interface ActivityStep {
|
|
1071
|
+
step: string;
|
|
1072
|
+
nodePath?: string;
|
|
1073
|
+
result: string;
|
|
1074
|
+
durationMs: number;
|
|
1075
|
+
}
|
|
1076
|
+
declare class ActivityLogger {
|
|
1077
|
+
private logPath;
|
|
1078
|
+
private initialized;
|
|
1079
|
+
constructor(fixturePath?: string, logDir?: string);
|
|
1080
|
+
/**
|
|
1081
|
+
* Ensure the log directory and file header exist
|
|
1082
|
+
*/
|
|
1083
|
+
private ensureInitialized;
|
|
1084
|
+
/**
|
|
1085
|
+
* Log a pipeline step
|
|
1086
|
+
*/
|
|
1087
|
+
logStep(activity: ActivityStep): Promise<void>;
|
|
1088
|
+
/**
|
|
1089
|
+
* Log a summary at pipeline completion
|
|
1090
|
+
*/
|
|
1091
|
+
logSummary(summary: {
|
|
1092
|
+
totalDurationMs: number;
|
|
1093
|
+
nodesAnalyzed: number;
|
|
1094
|
+
nodesConverted: number;
|
|
1095
|
+
mismatches: number;
|
|
1096
|
+
adjustments: number;
|
|
1097
|
+
status: string;
|
|
1098
|
+
}): Promise<void>;
|
|
1099
|
+
getLogPath(): string;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
declare const VERSION = "0.1.0";
|
|
1103
|
+
|
|
1104
|
+
export { ActivityLogger, type AnalysisAgentInput, type AnalysisAgentOutput, type AnalysisFile, AnalysisFileSchema, type AnalysisIssue, type AnalysisNode, AnalysisNodeSchema, type AnalysisNodeType, AnalysisNodeTypeSchema, type AnalysisResult, CATEGORIES, CATEGORY_LABELS, type CalibrationConfig, CalibrationConfigSchema, type CalibrationRun, type CalibrationStatus, CalibrationStatusSchema, type Category, CategorySchema, type CategoryScore, type CategoryScoreResult, CategoryScoreSchema, type Confidence, ConfidenceSchema, type ConversionAgentInput, type ConversionAgentOutput, type ConversionExecutor, type ConversionExecutorResult, type ConversionRecord, ConversionRecordSchema, DEPTH_WEIGHT_CATEGORIES, type Difficulty, DifficultySchema, type EvaluationAgentInput, type EvaluationAgentOutput, FigmaClient, FigmaClientError, type FigmaClientOptions, FigmaFileLoadError, type FigmaUrlInfo, FigmaUrlInfoSchema, FigmaUrlParseError, type Grade, type Issue, IssueSchema, type LayoutAlign, LayoutAlignSchema, type LayoutMode, LayoutModeSchema, type LayoutPositioning, LayoutPositioningSchema, type MismatchCase, MismatchCaseSchema, type MismatchType, MismatchTypeSchema, type NewRuleProposal, NewRuleProposalSchema, type NodeIssueDetail, type NodeIssueSummary, NodeIssueSummarySchema, type Preset, RULE_CONFIGS, type Report, type ReportMetadata, ReportMetadataSchema, ReportSchema, type Rule, type RuleCheckFn, type RuleConfig, RuleConfigSchema, type RuleContext, type RuleDefinition, RuleDefinitionSchema, RuleEngine, type RuleEngineOptions, type RuleId, type RuleRelatedStruggle, RuleRelatedStruggleSchema, type RuleViolation, SEVERITY_LABELS, SEVERITY_WEIGHT, type SamplingStrategy, SamplingStrategySchema, type ScoreAdjustment, ScoreAdjustmentSchema, type ScoreReport, type Severity, SeveritySchema, type TuningAgentInput, type TuningAgentOutput, type UncoveredStruggle, UncoveredStruggleSchema, VERSION, absolutePositionInAutoLayout, ambiguousStructure, analyzeFile, buildConversionPrompt, buildFigmaDeepLink, calculateScores, componentPropertyUnused, createRuleEngine, deepNesting, defaultName, defineRule, detachedInstance, emptyFrame, extractRuleScores, fixedSizeInAutoLayout, fixedWidthInResponsiveContext, formatScoreSummary, generateCalibrationReport, getCategoryLabel, getConfigsWithPreset, getRuleOption, getSeverityLabel, gradeToClassName, groupUsage, hardcodeRisk, imageNoPlaceholder, inconsistentNamingConvention, inconsistentSiblingLayoutDirection, inconsistentSpacing, invisibleLayer, loadFigmaFileFromJson, magicNumberSpacing, missingComponent, missingLayoutHint, missingMaxWidth, missingMinWidth, missingResponsiveBehavior, multipleFillColors, nestedInstanceOverride, noAutoLayout, noDevStatus, nonSemanticName, numericSuffixName, overflowHiddenAbuse, parseFigmaJson, parseFigmaUrl, parseMcpMetadataXml, prototypeLinkInDesign, rawColor, rawFont, rawOpacity, rawShadow, ruleRegistry, runAnalysisAgent, runCalibration, runCalibrationAnalyze, runCalibrationEvaluate, runConversionAgent, runEvaluationAgent, runTuningAgent, singleUseComponent, supportsDepthWeight, textTruncationUnhandled, tooLongName, transformFigmaResponse, variantNotUsed, zIndexDependentLayout };
|