@grampro/kit 2.7.1 → 2.7.3
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/.gbs/skills/gbs-components/SKILL.md +233 -207
- package/.gbs/skills/gbs-components/references/data-grid.md +9 -0
- package/.gbs/skills/gbs-components/references/forms.md +12 -0
- package/.gbs/skills/gbs-components/references/install.md +42 -5
- package/CHANGELOG.md +963 -798
- package/README.md +13 -4
- package/index.cjs +250 -138
- package/package.json +1 -1
- package/source/components/accordion/passport.json +1 -1
- package/source/components/alert/passport.json +1 -1
- package/source/components/avatar/passport.json +1 -1
- package/source/components/badge/passport.json +1 -1
- package/source/components/breadcrumb/passport.json +1 -1
- package/source/components/button/passport.json +1 -1
- package/source/components/card/passport.json +1 -1
- package/source/components/checkbox/passport.json +2 -2
- package/source/components/checkbox/passport.manual.json +1 -1
- package/source/components/checkbox/react/Checkbox.tsx +14 -0
- package/source/components/combobox/passport.json +3 -2
- package/source/components/combobox/passport.manual.json +1 -1
- package/source/components/combobox/react/MultiSelect.tsx +13 -0
- package/source/components/combobox/react/Select.tsx +13 -0
- package/source/components/combobox/react/surface.ts +70 -0
- package/source/components/data-grid/passport.json +6 -6
- package/source/components/data-grid/react/DataGrid.tsx +353 -351
- package/source/components/date-picker/passport.json +3 -2
- package/source/components/date-picker/passport.manual.json +1 -1
- package/source/components/date-picker/react/DatePicker.tsx +16 -2
- package/source/components/date-picker/react/DateRangePicker.tsx +16 -2
- package/source/components/date-picker/react/surface.ts +68 -0
- package/source/components/dialog/passport.json +1 -1
- package/source/components/file-uploader/passport.json +1 -1
- package/source/components/input/passport.json +2 -2
- package/source/components/input/passport.manual.json +1 -1
- package/source/components/input/react/Input.tsx +21 -0
- package/source/components/menu/passport.json +1 -1
- package/source/components/modal/passport.json +1 -1
- package/source/components/number-input/passport.json +2 -2
- package/source/components/number-input/passport.manual.json +1 -1
- package/source/components/number-input/react/NumberInput.tsx +30 -0
- package/source/components/popover/passport.json +1 -1
- package/source/components/progress/passport.json +1 -1
- package/source/components/radio-group/passport.json +2 -2
- package/source/components/radio-group/passport.manual.json +1 -1
- package/source/components/radio-group/react/RadioGroup.tsx +33 -0
- package/source/components/shared/core/agent/field-executors.ts +173 -137
- package/source/components/shared/core/agent/index.ts +21 -0
- package/source/components/shared/core/agent/surface.ts +437 -0
- package/source/components/shared/core/agent/webmcp.ts +332 -328
- package/source/components/shared/core/agent/write.ts +62 -58
- package/source/components/shared/index.ts +7 -0
- package/source/components/shared/react/AgentSurface.tsx +145 -0
- package/source/components/shared/react/agentSurfaceContext.ts +92 -0
- package/source/components/shared/react/useFieldAgent.ts +62 -88
- package/source/components/shared/version.json +4 -4
- package/source/components/shared/version.ts +6 -6
- package/source/components/skeleton/passport.json +1 -1
- package/source/components/spinner/passport.json +1 -1
- package/source/components/switch/passport.json +2 -2
- package/source/components/switch/passport.manual.json +1 -1
- package/source/components/switch/react/Switch.tsx +16 -0
- package/source/components/tabs/passport.json +1 -1
- package/source/components/textarea/passport.json +2 -2
- package/source/components/textarea/passport.manual.json +1 -1
- package/source/components/textarea/react/Textarea.tsx +16 -0
- package/source/components/toaster/passport.json +1 -1
- package/source/components/tooltip/passport.json +1 -1
- package/tools/doctor/baseline.cjs +228 -0
- package/tools/doctor/contract.cjs +252 -0
- package/tools/doctor/format.cjs +160 -0
- package/tools/doctor/index.cjs +246 -0
- package/tools/doctor/usage.cjs +95 -0
- package/tools/jsx-tags.cjs +120 -0
- package/tools/mcp/server.cjs +60 -41
- package/tools/passport/extract.cjs +22 -40
- package/tools/passport/hash.cjs +56 -0
- package/tools/passport/index.cjs +4 -2
- package/tools/passport/typescript.cjs +220 -0
- package/tools/prompt.cjs +205 -0
- package/tools/ui.cjs +67 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,798 +1,963 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 2.7.
|
|
4
|
-
|
|
5
|
-
###
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
it
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
the
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
resolved
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
it
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
The
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
and
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
`
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
was
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
###
|
|
535
|
-
|
|
536
|
-
**
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
`
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
## 2.3
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.7.3
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
**`<AgentSurface>`: a page that describes itself to a browser agent.** Wrap a
|
|
8
|
+
page in it and every form field and data grid inside registers itself — what
|
|
9
|
+
it holds, what it accepts, which operations it supports — from its own props,
|
|
10
|
+
as it is rendered now. In a browser with WebMCP one tool, `operate_page`, is
|
|
11
|
+
registered: `describe` returns that live manifest, `operate` sends intents to
|
|
12
|
+
one component by id. No tool definitions are written and none can drift from
|
|
13
|
+
the UI, because each description is the component's own.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<AgentSurface>
|
|
17
|
+
<Input label="Name" maxLength={80} />
|
|
18
|
+
<Select label="Team" options={teams} />
|
|
19
|
+
<DatePicker label="Due date" min="2026-01-01" max="2026-12-31" />
|
|
20
|
+
<DataGrid aria-label="Customers" data={rows} columns={columns} />
|
|
21
|
+
</AgentSurface>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Every action goes through the targeted component's own validator, with the
|
|
25
|
+
guarantees a single component already had: no repair, no retry, confirmation
|
|
26
|
+
before anything irreversible, refusals named by the layer that made them. The
|
|
27
|
+
surface adds addressing, not a second way in. Password, hidden and file inputs
|
|
28
|
+
are never offered. `useAgentSurface()` hands the same surface to an
|
|
29
|
+
application that runs its own agent loop, so it works without WebMCP too.
|
|
30
|
+
|
|
31
|
+
Input, Textarea, NumberInput, Checkbox, Switch, RadioGroup, Select,
|
|
32
|
+
MultiSelect, DatePicker, DateRangePicker and DataGrid join. A component outside
|
|
33
|
+
a surface pays for one `useContext`; the surface itself is about 7 KB gzip, in
|
|
34
|
+
an application that renders it. The browser test drives the real components
|
|
35
|
+
through the tool and checks the page's own state, not the DOM.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
**An agent's write to a Checkbox or Switch reported success and changed
|
|
40
|
+
nothing.** The field runtime set `checked` and dispatched `change`, but React
|
|
41
|
+
hears a checkbox through `click`, so a controlled box flipped in the DOM while
|
|
42
|
+
the application's state — and `onCheckedChange` — never moved. Checkable
|
|
43
|
+
fields are now clicked when they are not already in the asked state, which is
|
|
44
|
+
what a person does. Found by the new browser test; unit tests could not see it.
|
|
45
|
+
|
|
46
|
+
**A NumberInput written by an agent depended on the field's locale.** The
|
|
47
|
+
number was written into the element as text, so `1.5` became `"1.5"`, which a
|
|
48
|
+
`de-DE` field reads as fifteen. Inside a surface a NumberInput is now written
|
|
49
|
+
as a number through its own commit path, with its `min`, `max` and snapping.
|
|
50
|
+
|
|
51
|
+
**A RadioGroup could not be driven as a group.** Its ref is not a group
|
|
52
|
+
element, so a field agent could reach at most one radio. Inside a surface it
|
|
53
|
+
is one choice among its options.
|
|
54
|
+
|
|
55
|
+
**`shared/` could stay behind after an update.** The installer compared
|
|
56
|
+
versions only, and 2.7.0 changed `shared/` without changing its version, so a
|
|
57
|
+
project that already had shared 1.3.0 kept the old files. It now compares the
|
|
58
|
+
files as well, and `shared/` is 1.4.0.
|
|
59
|
+
|
|
60
|
+
**`passport` on TypeScript 7 needed a manual step.** 2.7.2 fell back to a
|
|
61
|
+
TypeScript 6 installed under an alias, and asked for one otherwise.
|
|
62
|
+
It now works on any TypeScript, or none, with no setup. The project's
|
|
63
|
+
TypeScript is used when it has the compiler API; otherwise the exact version
|
|
64
|
+
the kit is built with (6.0.3) is fetched once and cached per user. The fetch
|
|
65
|
+
goes through the user's own npm, installs one pinned version with install
|
|
66
|
+
scripts disabled, is verified before use, and is moved into the cache only
|
|
67
|
+
once complete; nothing in the project changes. `GRAMPRO_KIT_OFFLINE=1` turns
|
|
68
|
+
it off, and then `doctor` falls back to file-level changes and says why.
|
|
69
|
+
Bundling TypeScript instead would have added 24 MB to every `npx` run, and a
|
|
70
|
+
second, simpler extractor would have disagreed with the first.
|
|
71
|
+
|
|
72
|
+
**`passport --check` failed for every component in a project, edited or not.**
|
|
73
|
+
The source hash was labelled with paths as they sit in the project
|
|
74
|
+
(`src/component-lib/…`) rather than as they sit in the kit, and each passport
|
|
75
|
+
was stamped with the project's own version, so no regenerated passport ever
|
|
76
|
+
matched the one a component shipped with. Both now use the kit's terms — the
|
|
77
|
+
labels through one shared function, the version from the install record — so
|
|
78
|
+
an untouched component passes, an edited one is reported, and the hint names
|
|
79
|
+
`npx @grampro/kit passport` rather than this repository's npm script.
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
|
|
83
|
+
**The interactive picker fits any terminal, and no longer jumps.** It cleared
|
|
84
|
+
the screen on every key and printed all 27 components, so it needed a
|
|
85
|
+
full-screen terminal and flickered as you moved. It now redraws only its own
|
|
86
|
+
lines, shows a scrolling window that fits the terminal, and clips every line to
|
|
87
|
+
its width. Type to search — by name, group or purpose — space to select,
|
|
88
|
+
ctrl+a for everything shown, enter to install, esc or ctrl+c to cancel, which
|
|
89
|
+
the old one ignored. Each row shows the component's group and whether it is
|
|
90
|
+
already installed; the line below shows what the component is for, from its
|
|
91
|
+
passport. `npx @grampro/kit add` with no names now opens it in a terminal, as
|
|
92
|
+
`-i` does. The install log is in colour when it goes to a terminal, and plain
|
|
93
|
+
when piped or when `NO_COLOR` is set. The MCP server's `install_component`,
|
|
94
|
+
which reads that log, runs it with colour off and strips any escape codes, so a
|
|
95
|
+
host that sets `FORCE_COLOR` cannot hide a refused install from the agent.
|
|
96
|
+
|
|
97
|
+
**The skill, `get_guidance` and llms.txt know about `<AgentSurface>`**: the
|
|
98
|
+
forms and data-grid references say when to use it, and the install reference
|
|
99
|
+
says an agent must always name components rather than open the picker.
|
|
100
|
+
|
|
101
|
+
**A DataGrid builds its agent only when something will use it** — the `ai`
|
|
102
|
+
prop, as before, or now an `<AgentSurface>` around it. A grid outside a
|
|
103
|
+
surface and without `ai` is unchanged.
|
|
104
|
+
|
|
105
|
+
## 2.7.2
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
|
|
109
|
+
**`add` overwrote components you had edited, and said it had succeeded.**
|
|
110
|
+
Components are copied into your project so that you can change them, but
|
|
111
|
+
running `add` on one that was already installed replaced the whole folder
|
|
112
|
+
unconditionally. It printed "installed successfully" and the edits were gone.
|
|
113
|
+
The same happened through the MCP server: `install_component` runs `add`, so an
|
|
114
|
+
agent asked to "install Button" in a project with a customised Button
|
|
115
|
+
discarded the customisation.
|
|
116
|
+
|
|
117
|
+
Now every install records what it wrote — a hash of each file and a copy of
|
|
118
|
+
the component's contract, in `.install-manifest.json` beside the component —
|
|
119
|
+
and `add` checks that record first. An untouched component is updated. An
|
|
120
|
+
edited one is left in place: `add` lists the files that changed, prints how to
|
|
121
|
+
see more, and exits 1, while the other components in the same command still
|
|
122
|
+
install. Only `--force` replaces an edited component. `shared/` has worked this
|
|
123
|
+
way since it was introduced; components never did.
|
|
124
|
+
|
|
125
|
+
Components installed before this release have no record. An untouched one is
|
|
126
|
+
recognised from its passport's `sourceHash` — recomputed over your copy with
|
|
127
|
+
the labels the kit hashed it with, which a test holds to the shipped value for
|
|
128
|
+
all 27 — and is updated normally. One that differs from this version cannot be
|
|
129
|
+
told apart from an older untouched copy, so it is kept, not guessed at.
|
|
130
|
+
|
|
131
|
+
**`install_component` told an agent nothing when it was refused.** The
|
|
132
|
+
installer explains a refusal on stderr, and the tool only returned stdout — so
|
|
133
|
+
the agent got "Install failed" followed by stylesheet instructions. It now
|
|
134
|
+
returns what was installed, what was kept and why, and advice not to force it.
|
|
135
|
+
|
|
136
|
+
**`passport` crashed in any project on TypeScript 7.** TypeScript 7 is a
|
|
137
|
+
native rewrite whose npm package does not expose the compiler API passports
|
|
138
|
+
are generated with, and it is what `npm i -D typescript` installs today. The
|
|
139
|
+
command failed with `Cannot read properties of undefined (reading
|
|
140
|
+
'ReactJSX')`. It now checks for the API rather than for the package, falls
|
|
141
|
+
back to a TypeScript 6 installed under an alias, and otherwise says exactly
|
|
142
|
+
that, with the one-line fix.
|
|
143
|
+
|
|
144
|
+
**`validate_usage` invented props from inside expressions.** Attribute names
|
|
145
|
+
were matched anywhere in a tag, so `title={ok ? first : second}` reported
|
|
146
|
+
`first` and `second` as unknown props. The tag scanner now reads names only at
|
|
147
|
+
the top level, outside braces and quotes. It is shared with `doctor`, and stays
|
|
148
|
+
linear on hostile input.
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
**`npx @grampro/kit doctor`** — what you changed in your copies, what the new
|
|
153
|
+
version changes, and which call sites in your code an update would break.
|
|
154
|
+
|
|
155
|
+
It compares three versions of each component: the one you installed, your copy
|
|
156
|
+
now, and the one the CLI carries. It compares them as contracts — props,
|
|
157
|
+
accepted values, handlers, exports, agent operations — because a text diff of
|
|
158
|
+
`Button.tsx` shows which lines moved, not that `variant` stopped accepting
|
|
159
|
+
`"ghost"`. Edits from both sides to the same value set are merged rather than
|
|
160
|
+
called a conflict; a conflict is an incompatible pair, such as you removing a
|
|
161
|
+
prop that upstream changed. Then it scans your source and names the call sites
|
|
162
|
+
that pass something the replacement would not accept.
|
|
163
|
+
|
|
164
|
+
It never writes. `--json` gives the same report to agents and CI. The agent
|
|
165
|
+
skill now tells agents to run it, and never to retry `add` with `--force` on
|
|
166
|
+
someone else's edits. A new docs page, *Updating components*, covers all of it.
|
|
167
|
+
|
|
168
|
+
## 2.7.1
|
|
169
|
+
|
|
170
|
+
### Security
|
|
171
|
+
|
|
172
|
+
**get_guidance could read any .md file on disk.** It appended `.md` to a
|
|
173
|
+
caller-supplied `topic` and joined it onto the references folder with no
|
|
174
|
+
traversal guard, so `topic = "../../../../CHANGELOG"` returned the repo
|
|
175
|
+
CHANGELOG and the same trick reached any `.md` file the server process could
|
|
176
|
+
open. Found by a VAPT pass driving the tool with traversal payloads. The
|
|
177
|
+
server runs with your own authority, so it is a confused-deputy hole rather
|
|
178
|
+
than privilege escalation — but a tool that advertises nine fixed topics
|
|
179
|
+
should not become a file-exfiltration primitive for a prompt-injected agent.
|
|
180
|
+
It now refuses any `topic` that is not one of the shipped guidance names, with
|
|
181
|
+
a resolved-prefix check behind the allowlist. A regression test drives the
|
|
182
|
+
same payloads.
|
|
183
|
+
|
|
184
|
+
**Affected: 2.4.4 through 2.7.0** — every release that has shipped the MCP
|
|
185
|
+
server. Each was checked by running the same payload against its published
|
|
186
|
+
tarball. 2.4.3 and earlier have no MCP server and are not affected. A project
|
|
187
|
+
that installed the package locally needs `npm i -D @grampro/kit@latest`. One
|
|
188
|
+
configured with `npx -y @grampro/kit mcp` may keep running a cached copy; check
|
|
189
|
+
with `npx -y @grampro/kit --version`, and if it is not 2.7.1, run
|
|
190
|
+
`npx -y @grampro/kit@2.7.1 mcp` once to replace it.
|
|
191
|
+
|
|
192
|
+
## 2.7.0
|
|
193
|
+
|
|
194
|
+
### Added
|
|
195
|
+
|
|
196
|
+
**A design read from a URL now names its components.** An instance built
|
|
197
|
+
from a library is the most valuable thing a design can contain — it says
|
|
198
|
+
"this is a Button" instead of leaving an agent to infer it from a layer
|
|
199
|
+
name and a fill. The URL route recorded `instanceOf: "1:234"`, an opaque
|
|
200
|
+
id nothing could be done with, and discarded the maps that name it, which
|
|
201
|
+
Figma sends in the same response.
|
|
202
|
+
|
|
203
|
+
It resolves them now, preferring the component set's name over the
|
|
204
|
+
variant's: a variant is called `Size=md, Variant=primary` and its set is
|
|
205
|
+
called `Button`, and Button is what the agent is going to write. An
|
|
206
|
+
instance whose master is not in the response keeps its id rather than
|
|
207
|
+
guessing.
|
|
208
|
+
|
|
209
|
+
**Every component now says what it is for.** A passport had two halves: the
|
|
210
|
+
derived one, generated from the TypeScript, and the authored one — `purpose`,
|
|
211
|
+
`intentDomains`, `accessibility`, `composition`, `safeMutations`. The generator
|
|
212
|
+
emits empty shells for the authored half because none of it is in the types,
|
|
213
|
+
and only Button and DataGrid had ever been filled in. The other 25 are written
|
|
214
|
+
now.
|
|
215
|
+
|
|
216
|
+
`safeMutations` is the one an agent acts on: which props it may change without
|
|
217
|
+
altering behaviour, and which it may not, with the reason. An agent restyling a
|
|
218
|
+
FileUploader should be free to change `size` and `preview` and nowhere near
|
|
219
|
+
`endpoint`, `headers` or `transport` — that component is the one where a wrong
|
|
220
|
+
prop sends someone's data somewhere. `get_component` now returns all of it;
|
|
221
|
+
until this release it served `purpose` and dropped the rest, so the authored
|
|
222
|
+
half reached nobody.
|
|
223
|
+
|
|
224
|
+
Where no value in the schema's `intentDomains` enum honestly describes a
|
|
225
|
+
component, the list is left empty rather than filled for symmetry. Nine of them
|
|
226
|
+
are presentational, and a wrong routing hint is worse than none.
|
|
227
|
+
|
|
228
|
+
**A field runtime, so nine components are agent-operable instead of one.**
|
|
229
|
+
`setValue`, `clear`, `focus`, and `open`/`close` for the two that have
|
|
230
|
+
something to disclose, on Input, Textarea, NumberInput, Checkbox, Switch,
|
|
231
|
+
RadioGroup, Combobox and DatePicker.
|
|
232
|
+
|
|
233
|
+
The grid earned a runtime of its own because its operations are a language:
|
|
234
|
+
filter, sort, pin, paginate, export. A field has one verb, so the verb lives in
|
|
235
|
+
`shared/core/agent` once rather than eight times, and each component supplies
|
|
236
|
+
only a contract built from its own props. The same five layers rule on it —
|
|
237
|
+
schema, reference, coercion, policy, plausibility — so a write to a read-only
|
|
238
|
+
field is refused by name, an option that does not exist comes back with the
|
|
239
|
+
nearest one that does, and a number outside `min`/`max` is told which bound it
|
|
240
|
+
crossed rather than being silently clamped.
|
|
241
|
+
|
|
242
|
+
The open question was whether the executor abstraction generalised. A grid is
|
|
243
|
+
driven through an imperative API and a field is not, and the architecture notes
|
|
244
|
+
had flagged that as unproven. It holds: Combobox and DatePicker are driven
|
|
245
|
+
through their handles, the other six through the element their ref already
|
|
246
|
+
returns, and nothing above the executor knows which. `setValue` joins
|
|
247
|
+
`ComboboxHandle` and `DatePickerHandle` as a public method; the six that expose
|
|
248
|
+
the DOM element needed no API change at all, because the technique
|
|
249
|
+
`Input.clear()` has always used — the prototype setter plus a real event — is
|
|
250
|
+
the same write with a value in it.
|
|
251
|
+
|
|
252
|
+
`useFieldAgent` binds a contract to a ref. No component grew a prop for this.
|
|
253
|
+
|
|
254
|
+
**The authored passports had no schema of their own.** A `passport.manual.json`
|
|
255
|
+
pointed at `passport-v1.schema.json`, which describes the *merged* passport —
|
|
256
|
+
so an editor validating one reported all eight generated fields as missing
|
|
257
|
+
(`passportVersion`, `identity`, `source`, `props`, `events`, `slots`, `states`,
|
|
258
|
+
`coverage`), and `additionalProperties: false` made errors of the four keys only
|
|
259
|
+
an overlay has: `component`, `propNotes`, `notImplemented`, `$operationsNote`.
|
|
260
|
+
|
|
261
|
+
It was wrong on the two files that had it before and merely quiet; at
|
|
262
|
+
twenty-seven it is the thing that teaches people to ignore squiggles.
|
|
263
|
+
`schema/passport-overlay-v1.schema.json` describes what an overlay may
|
|
264
|
+
actually contain, referencing the merged schema for the fields they share so
|
|
265
|
+
the two cannot drift. A test holds every overlay to it, which also catches a
|
|
266
|
+
mistyped key — previously a silent no-op, since the merge only reads the names
|
|
267
|
+
it knows.
|
|
268
|
+
|
|
269
|
+
### Security
|
|
270
|
+
|
|
271
|
+
**A failed JSON parse quoted the file back.** V8 puts the first ten or so
|
|
272
|
+
characters of its input into the error it throws, so pointing `designFile` at
|
|
273
|
+
something that was not JSON returned a slice of it:
|
|
274
|
+
|
|
275
|
+
That is not JSON: Unexpected token 's', "sk-proj-RE"... is not valid JSON
|
|
276
|
+
|
|
277
|
+
Ten bytes is not an extraction, but it is enough to confirm that a path
|
|
278
|
+
exists and what kind of file sits there, and an agent can be pointed at paths
|
|
279
|
+
in a loop. The server runs with your own authority and the agent could read
|
|
280
|
+
the file directly, so this was hygiene rather than a hole — and it cost
|
|
281
|
+
nothing to close. The three parse sites in `figma.cjs`, `design.cjs` and
|
|
282
|
+
`install.cjs` now name the file and say what was expected, without quoting
|
|
283
|
+
any of it.
|
|
284
|
+
|
|
285
|
+
**The package no longer installs a build toolchain.**
|
|
286
|
+
`@grampro/headless-helpers` declared `rollup`, its plugins and `typescript`
|
|
287
|
+
as runtime dependencies, so installing the kit pulled a compiler and a
|
|
288
|
+
bundler into `node_modules` and carried their advisories — an arbitrary file
|
|
289
|
+
write in Rollup and two ReDoS in picomatch, none of which any of this code
|
|
290
|
+
runs. Requiring `^1.0.22`, which moved them to devDependencies, removes 84
|
|
291
|
+
packages from a clean install and leaves the package at zero advisories.
|
|
292
|
+
|
|
293
|
+
**Mermaid rendered with sanitisation off.** The diagram component ran with
|
|
294
|
+
`securityLevel: "loose"`, which permits HTML in labels and click handlers,
|
|
295
|
+
and its output goes through `dangerouslySetInnerHTML`. Nothing was
|
|
296
|
+
exploitable: the only diagram text comes from our own MDX at build time, and
|
|
297
|
+
in fact no page renders one. But the two together are a trap for whoever
|
|
298
|
+
first renders a diagram from anything else, so it is `"strict"` now.
|
|
299
|
+
|
|
300
|
+
### Changed
|
|
301
|
+
|
|
302
|
+
**The docs lead with the URL route.** Pasting a Figma link is one step;
|
|
303
|
+
the plugin route is five, and every one is a place to stop. The reason it
|
|
304
|
+
was necessary for designs built from a component library is now gone, so
|
|
305
|
+
the page says plainly: use the URL for a screen, and the plugin when you
|
|
306
|
+
want a whole product in one pass, or have no token, or are rate limited.
|
|
307
|
+
|
|
308
|
+
**`figma_frame` describes the URL route first.** Its own description still
|
|
309
|
+
said `designFile` was "the one to use for a whole screen", which was true
|
|
310
|
+
only while the URL route could not resolve component names. An agent reads
|
|
311
|
+
that description before it picks a route, so it was steering towards the long
|
|
312
|
+
way round. It now leads with the URL and keeps the file export for what the
|
|
313
|
+
file export is actually better at: a whole product in one pass, or no usable
|
|
314
|
+
token. The `llms.txt` preamble said nothing about the URL route at all, and
|
|
315
|
+
now says it is the shortest path from a design to a screen.
|
|
316
|
+
|
|
317
|
+
**The components are out of beta.** Only the MCP server still carries the
|
|
318
|
+
label, and it carries it in both places that matter: the docs page and the
|
|
319
|
+
`figma_frame` tool description an agent reads.
|
|
320
|
+
|
|
321
|
+
The one that was doing damage was in the agent skill, which is always in an
|
|
322
|
+
agent's context. It said **"Always pass `--beta`"** and explained that without
|
|
323
|
+
it you get the 1.x set. That had inverted: `--beta` became a no-op that prints
|
|
324
|
+
a deprecation notice, 2.x is what `add` installs, and `--legacy` is what
|
|
325
|
+
reaches 1.x. An agent following the skill was passing a dead flag and being
|
|
326
|
+
told the opposite of what the CLI does. The flag table now documents
|
|
327
|
+
`--legacy` instead, and says plainly that the 1.x set is unmaintained.
|
|
328
|
+
|
|
329
|
+
Also gone from the CLI's own output ("Redesigned beta components" when a name
|
|
330
|
+
does not match), the `llms.txt` preamble, which told every model that read the
|
|
331
|
+
site that the components were beta and their APIs might change, and the README
|
|
332
|
+
and architecture notes. `--beta` is still accepted, because scripts use it.
|
|
333
|
+
|
|
334
|
+
### Fixed
|
|
335
|
+
|
|
336
|
+
**Headings on the translated pages had meaningless ids.** The slugger kept
|
|
337
|
+
only `[a-z0-9\s-]`, which leaves a Malayalam heading with nothing but its
|
|
338
|
+
spaces — so every heading fell through to `section` or to the `-` its spaces
|
|
339
|
+
became, and then took its id from the duplicate counter:
|
|
340
|
+
|
|
341
|
+
id="-" id="--1" id="--2" id="-structured-data" id="section-2"
|
|
342
|
+
|
|
343
|
+
That counter is positional, so adding a heading renumbered every anchor below
|
|
344
|
+
it: no link to one could be relied on, and four prop-table links on
|
|
345
|
+
`ml/breadcrumb` and `ml/button` pointed at the English anchors and had never
|
|
346
|
+
resolved. The class keeps letters, digits and combining marks in any script
|
|
347
|
+
now, so those headings slug to their own text. `\p{M}` matters as much as
|
|
348
|
+
`\p{L}` here: Malayalam vowel signs are combining marks, and dropping them
|
|
349
|
+
mangles the text rather than emptying it. Every ASCII heading slugs to the
|
|
350
|
+
same string as before, so no existing anchor moved.
|
|
351
|
+
|
|
352
|
+
`pnpm check:anchors` in `docs-site` now checks every in-site fragment against
|
|
353
|
+
the headings its target page actually offers, because a dead anchor does not
|
|
354
|
+
404 — the page loads and ignores it.
|
|
355
|
+
|
|
356
|
+
## 2.6.3
|
|
357
|
+
|
|
358
|
+
### Fixed
|
|
359
|
+
|
|
360
|
+
**The text LLMs read was teaching a deprecated command.** `llms.txt` has a
|
|
361
|
+
hand-written preamble, so it lagged behind the CLI: it told every model
|
|
362
|
+
that reached the site to run `npx @grampro/kit -a <Component>`, a spelling
|
|
363
|
+
the CLI itself marks "Deprecated. Use: add". It now says `add`, and names
|
|
364
|
+
the Figma plugin, the whole-design export and `designFile`, none of which
|
|
365
|
+
it mentioned.
|
|
366
|
+
|
|
367
|
+
**The plugin's install link was invisible to every LLM.** It is rendered by
|
|
368
|
+
a component, and the Markdown conversion passed that through verbatim — so
|
|
369
|
+
`llms-full.txt` and every `.md` page carried a dangling `<FigmaPlugin />`
|
|
370
|
+
tag where the URL should have been, and the plugin's address appeared
|
|
371
|
+
nowhere a model could read it. The conversion emits a Markdown link now,
|
|
372
|
+
and the URL lives in one place so the button and the converter cannot
|
|
373
|
+
disagree about it.
|
|
374
|
+
|
|
375
|
+
**The Figma plugin's listing is in review**, which Figma is quoting at a
|
|
376
|
+
few weeks. Every place that links it now says so and gives the interim
|
|
377
|
+
path: clone the repository and import `figma-plugin/manifest.json` through
|
|
378
|
+
**Plugins → Development → Import plugin from manifest...** in the desktop
|
|
379
|
+
app. The build is committed, so there is nothing to compile.
|
|
380
|
+
|
|
381
|
+
**Six links in the docs went nowhere.** `datagrid.mdx` and
|
|
382
|
+
`fileuploader.mdx` pointed at `#column-options`, `#grid-api-ref`,
|
|
383
|
+
`#server-side-pagination`, `#upload-protocol`, `#custom-transport` and
|
|
384
|
+
`#server-implementation` as same-page anchors. Those sections moved to
|
|
385
|
+
child pages when the docs were split and the links were never updated, so
|
|
386
|
+
they had been doing nothing since. They point at the child pages now.
|
|
387
|
+
|
|
388
|
+
### Changed
|
|
389
|
+
|
|
390
|
+
**Every command is listed in one place.** `list` and `passport` appeared
|
|
391
|
+
in no user-facing documentation at all, and the rest were scattered across
|
|
392
|
+
three pages, so there was nowhere to look to find out what the CLI does.
|
|
393
|
+
The README now carries the lot in a table.
|
|
394
|
+
|
|
395
|
+
## 2.6.2
|
|
396
|
+
|
|
397
|
+
### Changed
|
|
398
|
+
|
|
399
|
+
**The agent skill now knows the MCP server exists.** It described the
|
|
400
|
+
component library and never mentioned the server, so an agent holding both
|
|
401
|
+
had nothing to tell it which to trust. The skill is a summary; the server
|
|
402
|
+
answers from passports generated from the source, so where they differ the
|
|
403
|
+
server is right and the skill is stale — and it now says so, along with
|
|
404
|
+
calling `get_component` before writing a component and `validate_usage`
|
|
405
|
+
before reporting back.
|
|
406
|
+
|
|
407
|
+
The only previous mention of "MCP" in the skill was WebMCP, the DataGrid's
|
|
408
|
+
browser-agent surface, which is a different thing entirely.
|
|
409
|
+
|
|
410
|
+
**Neither needs the other, and the docs now say so.** The server carries
|
|
411
|
+
its own copy of the guidance inside the package, so `get_guidance` answers
|
|
412
|
+
in a project with no `.gbs/` folder at all. What they do together is the
|
|
413
|
+
useful part: the skill is always in an agent's context and the server is
|
|
414
|
+
not, so the skill is what tells an agent to ask and the server is what it
|
|
415
|
+
asks.
|
|
416
|
+
|
|
417
|
+
The two pages now read in the order they are used — Theming, Agent skill,
|
|
418
|
+
MCP server.
|
|
419
|
+
|
|
420
|
+
## 2.6.1
|
|
421
|
+
|
|
422
|
+
### Changed
|
|
423
|
+
|
|
424
|
+
**A screen costs about half what it did to read.** Measured on a real
|
|
425
|
+
purchase-orders design: 42.9 KB to 23.9 KB, roughly 13,300 tokens to
|
|
426
|
+
7,400.
|
|
427
|
+
|
|
428
|
+
Eight table rows exported as eight sibling subtrees of identical shape
|
|
429
|
+
whose text differed — 48% of that screen was the same row said seven
|
|
430
|
+
more times. The first is now given in full, because the agent builds from
|
|
431
|
+
its shape, and the rest become `repeatedText`: one array of strings per
|
|
432
|
+
row, which is closer to what a DataGrid's `data` prop wants than the
|
|
433
|
+
subtrees were.
|
|
434
|
+
|
|
435
|
+
Runs are matched on structure rather than appearance. Keyed on style, the
|
|
436
|
+
rows never matched at all: a striped table alternates its background, so
|
|
437
|
+
every consecutive pair looked like a different shape and nothing
|
|
438
|
+
collapsed. Where the fills do vary across a run they come back as
|
|
439
|
+
`repeatedFills`, which is how the striping and the per-status badge
|
|
440
|
+
colours stay legible.
|
|
441
|
+
|
|
442
|
+
Only runs of three or more collapse, and only where there is depth to
|
|
443
|
+
save: two of a thing is a pair, not a list, and a row of labels has
|
|
444
|
+
nothing inside it worth folding.
|
|
445
|
+
|
|
446
|
+
### Fixed
|
|
447
|
+
|
|
448
|
+
**`depth` is honoured on the plugin and file routes.** The tool has always
|
|
449
|
+
offered it — "Lower it if the payload is large" — and only ever applied
|
|
450
|
+
it to a design fetched from a URL. A caller who read the schema and
|
|
451
|
+
lowered it to cut a large payload got the large payload back. The same
|
|
452
|
+
screen at `depth: 3` is now 3.5 KB, and what was dropped says so rather
|
|
453
|
+
than going quiet.
|
|
454
|
+
|
|
455
|
+
**Selecting several frames exports several screens.** It used to produce
|
|
456
|
+
one pseudo-frame called "3 selected nodes" holding all of them, which
|
|
457
|
+
`design` then wrote as a single file under that name — a folder whose
|
|
458
|
+
whole point is one file per screen, with one file for three. The screens
|
|
459
|
+
were in there, but nothing said where one ended and the next began.
|
|
460
|
+
|
|
461
|
+
A selection of several frames now produces the same shape the whole-file
|
|
462
|
+
export does, so the split, the index and `figma_frame` treat them
|
|
463
|
+
identically. One frame selected is still one screen.
|
|
464
|
+
|
|
465
|
+
This is also the scoping the all-screens command lacks: a file with forty
|
|
466
|
+
frames in it need not be exported entire to build two of them. Select the
|
|
467
|
+
screens you want and export those.
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
## 2.6.0
|
|
471
|
+
|
|
472
|
+
### Added
|
|
473
|
+
|
|
474
|
+
**A whole Figma design, exported once and built screen by screen.**
|
|
475
|
+
|
|
476
|
+
In Figma, **Grampro Kit → Export all screens for an agent** walks every page
|
|
477
|
+
and takes each top-level frame. Then:
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
npx @grampro/kit design ./design.json
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
```text
|
|
484
|
+
Wrote 3 screen(s) to design/
|
|
485
|
+
purchase-orders.json Purchase orders (Product) — 22 nodes
|
|
486
|
+
suppliers.json Suppliers (Product) — 16 nodes
|
|
487
|
+
settings.json Settings (Admin) — 12 nodes
|
|
488
|
+
index.json the plan: every screen, shared theme
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
The accuracy is in the theme rather than the convenience. Derived one
|
|
492
|
+
frame at a time it disagrees with itself — a screen that is mostly white
|
|
493
|
+
names a different background from one that is mostly grey — and the agent
|
|
494
|
+
then themes each page differently. Read across every screen, once, it is
|
|
495
|
+
well founded.
|
|
496
|
+
|
|
497
|
+
`index.json` is the plan: every screen with its size, node count and the
|
|
498
|
+
regions whose names repeat, plus that shared theme. It is the cheap place
|
|
499
|
+
to be wrong. A design drawn without the component library names nothing
|
|
500
|
+
directly, so every component is inferred, and a guess that `Action` is a
|
|
501
|
+
Card rather than a Button costs one sentence there and five screens of
|
|
502
|
+
rework later.
|
|
503
|
+
|
|
504
|
+
**`figma_frame` reads a file.** Pass `designFile` with a path instead of
|
|
505
|
+
`design` with the JSON. A chat input caps at around fifty thousand
|
|
506
|
+
characters and a whole screen passes that; and a pasted export sits in the
|
|
507
|
+
conversation twice, once as the argument and again inside the tool call,
|
|
508
|
+
where a file appears only in the answer.
|
|
509
|
+
|
|
510
|
+
**Every prop the library declares now carries a description.** 117 did
|
|
511
|
+
not, and the passports are what an agent reads instead of the source, so
|
|
512
|
+
an undescribed prop is one it guesses at. `DataGrid`'s `columns` and
|
|
513
|
+
`data` had none at all. See 2.5.0's notes — this is that work, reaching
|
|
514
|
+
npm for the first time.
|
|
515
|
+
|
|
516
|
+
### Changed
|
|
517
|
+
|
|
518
|
+
**The Figma export costs a third of what it did.** The copy button takes
|
|
519
|
+
minified JSON: `JSON.parse` cannot tell the difference, and indentation
|
|
520
|
+
was most of the payload. Three fields that said nothing went with it —
|
|
521
|
+
`radius: 0` on every square frame, `padding: [0,0,0,0]` on every frame
|
|
522
|
+
without padding, and `align`/`justify` restating Figma's own defaults —
|
|
523
|
+
along with the child frame Figma wraps around every icon, whose entire
|
|
524
|
+
content was the word "Vector" when the frame's name (`search`, `plus`)
|
|
525
|
+
was the whole signal.
|
|
526
|
+
|
|
527
|
+
**It also says more about what it exports.** Node size and stroke colour
|
|
528
|
+
are now included, because most designs are not built from the kit's Figma
|
|
529
|
+
library and an agent has to infer every component from what it can see. A
|
|
530
|
+
36px pill with a label is a button; the same shape at 200px is a card. A
|
|
531
|
+
white box with a border is a secondary button; without one it is a
|
|
532
|
+
surface. Neither was visible before.
|
|
533
|
+
|
|
534
|
+
### Fixed
|
|
535
|
+
|
|
536
|
+
**The design system generator laid out over itself.** Variant grids were
|
|
537
|
+
placed by column count without measuring whether the row fitted, so 14 of
|
|
538
|
+
38 component sets overflowed the card holding them — Alert reached 2444px
|
|
539
|
+
inside a 1320px section.
|
|
540
|
+
|
|
541
|
+
**Text that was told a width kept its own.** Figma creates a text node
|
|
542
|
+
auto-width, and setting it to fill is quietly ignored, so 23 layers across
|
|
543
|
+
the file measured themselves from their own characters. NumberInput's
|
|
544
|
+
value layer, created empty and filled in later by a component property,
|
|
545
|
+
wrapped one glyph per line.
|
|
546
|
+
|
|
547
|
+
**Alert's coloured edge did not match its card**, being sized before the
|
|
548
|
+
card had any content and never clipped to its rounded corners. Toast drew
|
|
549
|
+
the same edge with the same fault.
|
|
550
|
+
|
|
551
|
+
**The uploader thumbnails and the dialog's intent badge rendered at full
|
|
552
|
+
saturation**, which also hid the icon drawn on them in the same colour.
|
|
553
|
+
|
|
554
|
+
**The plugin's name displayed as mojibake** in Figma's menu, and its
|
|
555
|
+
build was never committed despite its README saying so, so a clone could
|
|
556
|
+
not run it.
|
|
557
|
+
|
|
558
|
+
## 2.5.0
|
|
559
|
+
|
|
560
|
+
### Added
|
|
561
|
+
|
|
562
|
+
**Every prop this library declares now carries a description.**
|
|
563
|
+
|
|
564
|
+
117 did not, and the passports are what an agent reads instead of the
|
|
565
|
+
source, so an undescribed prop is one it has to guess at. The worst of them
|
|
566
|
+
were not obscure: `DataGrid`'s `columns` and `data` had no description at
|
|
567
|
+
all, and `label`, `error`, `description` and `onChange` were bare on
|
|
568
|
+
Checkbox, Switch and RadioGroup.
|
|
569
|
+
|
|
570
|
+
Where reading the code turned up something a type cannot say, that is in
|
|
571
|
+
the description now:
|
|
572
|
+
|
|
573
|
+
- `onCellEdit` fires only when the value actually changed, and returning a
|
|
574
|
+
promise makes the edit optimistic - the cell reverts and shows the
|
|
575
|
+
rejection's message if it fails, so reject with the reason you want read.
|
|
576
|
+
- `CheckboxGroup`'s values accumulate in the order they were checked, not
|
|
577
|
+
the order the options are declared, so sort before comparing selections.
|
|
578
|
+
- `Checkbox.onCheckedChange` never fires with `"indeterminate"`.
|
|
579
|
+
- `FileUploader` treats name, size and last-modified time as a file's
|
|
580
|
+
identity when rejecting duplicates.
|
|
581
|
+
- `NumberInput`'s `min` and `max` apply on blur rather than per keystroke,
|
|
582
|
+
unless `clampBehavior` says otherwise.
|
|
583
|
+
- `DatePicker.onChange` always hands back a `Date` at local midnight, even
|
|
584
|
+
though `value` accepts a string or a number.
|
|
585
|
+
**The Figma token belongs to your operating system now, not to a file in
|
|
586
|
+
your repository.**
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
npx @grampro/kit secret set figma
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
It prompts with the echo off and stores the token where the platform keeps
|
|
593
|
+
credentials: the Data Protection API on Windows, the keychain on macOS, the
|
|
594
|
+
Secret Service on Linux. Anywhere else it falls back to a 0600 file in your
|
|
595
|
+
config directory and says so rather than implying otherwise. The value is
|
|
596
|
+
never passed as an argument, because arguments land in shell history and in
|
|
597
|
+
every process listing on the machine; pipe it instead if you need to script
|
|
598
|
+
it.
|
|
599
|
+
|
|
600
|
+
`secret list` shows what is stored, masked, and names the backend. `secret
|
|
601
|
+
remove figma` deletes it.
|
|
602
|
+
|
|
603
|
+
The old `.env` route still works, so upgrading breaks nothing, but reading
|
|
604
|
+
from one now prints a note telling you to move it. A credential sitting in a
|
|
605
|
+
working tree is one `git add -A` away from being published, which is the
|
|
606
|
+
whole reason for the change.
|
|
607
|
+
|
|
608
|
+
**`mcp install` writes the configuration for you.**
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
npx @grampro/kit mcp install # every agent it knows
|
|
612
|
+
npx @grampro/kit mcp install --for codex
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Claude Code, Codex and Cursor each take the same stdio server and differ
|
|
616
|
+
only in where the configuration lives and what format it is in. This writes
|
|
617
|
+
`.mcp.json`, `.codex/config.toml` and `.cursor/mcp.json` respectively,
|
|
618
|
+
merging into whatever is already there and leaving other servers alone.
|
|
619
|
+
|
|
620
|
+
It is worth preferring over editing those files by hand, which is how this
|
|
621
|
+
goes wrong: PowerShell's `Out-File -Encoding utf8` adds a byte-order mark,
|
|
622
|
+
and every JSON parser then rejects the file with an error naming the first
|
|
623
|
+
character and explaining nothing. This writes UTF-8 without a BOM and with
|
|
624
|
+
LF endings, and strips a BOM from a file that already has one.
|
|
625
|
+
|
|
626
|
+
It writes to the project root — the nearest folder above you with a `.git`
|
|
627
|
+
or a `package.json` — and prints which one it chose. An agent reads these
|
|
628
|
+
files from the folder it has open, so running the command from a
|
|
629
|
+
subdirectory would have written somewhere nothing ever looks while still
|
|
630
|
+
reporting success.
|
|
631
|
+
|
|
632
|
+
It also now says what has to happen next, because writing the file is not
|
|
633
|
+
the same as loading the server. A `.mcp.json` server is project-scoped and
|
|
634
|
+
Claude Code asks before trusting one, so it sits at `Pending approval` until
|
|
635
|
+
you agree; and the configuration is read when a session starts, so an editor
|
|
636
|
+
window that was already open sees nothing until it reloads. Installing at
|
|
637
|
+
user scope — `claude mcp add -s user grampro -- npx -y @grampro/kit mcp` —
|
|
638
|
+
skips both, at the cost of not being shareable through a commit.
|
|
639
|
+
|
|
640
|
+
### Changed
|
|
641
|
+
|
|
642
|
+
**Reading a Figma design no longer downloads the whole file.**
|
|
643
|
+
|
|
644
|
+
Figma charges for file reads by the size of the response, and the frame
|
|
645
|
+
listing was fetching the entire document — 710 KB on the file this was
|
|
646
|
+
tested against — to answer a question about one screen. Two of those in a
|
|
647
|
+
row is what earns a 429, and the lockout is long: a `Retry-After` of 395274
|
|
648
|
+
was observed on a single token.
|
|
649
|
+
|
|
650
|
+
The listing now uses `depth=1`, which returns the document's outline rather
|
|
651
|
+
than its contents, and the chosen frame is fetched by id. A URL that already
|
|
652
|
+
carries a `node-id` — what Figma copies when you right-click a frame — goes
|
|
653
|
+
straight there in one call. Responses are still held for five minutes, so
|
|
654
|
+
the usual list-then-read flow costs one outline and one frame.
|
|
655
|
+
|
|
656
|
+
If a token is already rate limited, the Figma plugin export route still
|
|
657
|
+
works; it reads the scene graph from inside Figma and never calls the API.
|
|
658
|
+
|
|
659
|
+
**The MCP server starts in about the time an empty Node process takes.**
|
|
660
|
+
|
|
661
|
+
An agent spawns the server once per session, and it was loading the CLI's
|
|
662
|
+
own dependencies first — `fs-extra` and `yargs`, roughly 70ms, and of no use
|
|
663
|
+
to a JSON-RPC loop. The `mcp` command is now routed before they load.
|
|
664
|
+
|
|
665
|
+
The passports are also indexed on the first question rather than re-read
|
|
666
|
+
from disk for each one.
|
|
667
|
+
|
|
668
|
+
### Fixed
|
|
669
|
+
|
|
670
|
+
**`Select`'s `closeOnSelect` was documented backwards, in both directions.**
|
|
671
|
+
Its description read "Keep the list open after choosing. Default false."
|
|
672
|
+
while the code defaults it to `true` and closing is what the prop does. An
|
|
673
|
+
agent reading that passport would have had both the behaviour and the
|
|
674
|
+
default inverted - the failure mode that makes a wrong description worse
|
|
675
|
+
than a missing one. MultiSelect's was already right.
|
|
676
|
+
|
|
677
|
+
**Description coverage was measured against a denominator nobody could
|
|
678
|
+
move.** It counted every prop, including the HTML and ARIA attributes that
|
|
679
|
+
arrive through `extends ButtonHTMLAttributes` - 390 of the 507 undescribed
|
|
680
|
+
props were those. So Button sat at 31% with its entire own API documented
|
|
681
|
+
bar one prop, and eleven components stayed under the 40% threshold with
|
|
682
|
+
nothing left to write. A gate that cannot be satisfied by doing the work it
|
|
683
|
+
asks for gets ignored.
|
|
684
|
+
|
|
685
|
+
It now measures the props the library authors, excluding inherited
|
|
686
|
+
attributes and the handful whose meaning is library-wide (`className`,
|
|
687
|
+
`style`, `ref` and friends) rather than restating them 27 times. On that
|
|
688
|
+
measure the library is at 87% and the weakest component at 75%, so the
|
|
689
|
+
threshold moves from 40 to 75 - a floor rather than an aspiration.
|
|
690
|
+
**The rate-limit message no longer promises that waiting a minute will
|
|
691
|
+
help.** It said to try again shortly, which is wrong for a cost-based limit
|
|
692
|
+
whose window runs to tens of minutes or longer. It now passes Figma's own
|
|
693
|
+
`Retry-After` through as given, without asserting a unit — the value has
|
|
694
|
+
been seen in a range where seconds and milliseconds differ by three orders
|
|
695
|
+
of magnitude — and points at the plugin route, which cannot be rate limited.
|
|
696
|
+
|
|
697
|
+
## 2.4.4
|
|
698
|
+
|
|
699
|
+
### Added
|
|
700
|
+
|
|
701
|
+
**An MCP server, so an agent can ask about a component instead of recalling
|
|
702
|
+
it.**
|
|
703
|
+
|
|
704
|
+
```bash
|
|
705
|
+
npx @grampro/kit mcp
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
Seven tools: `list_components`, `get_component`, `get_example`,
|
|
709
|
+
`get_guidance`, `figma_frame`, `install_component` and `validate_usage`. The
|
|
710
|
+
catalogue is 280 KB of passports and a page needs two or three components,
|
|
711
|
+
which is the argument for answering on demand rather than pasting a document
|
|
712
|
+
into the prompt.
|
|
713
|
+
|
|
714
|
+
`validate_usage` is the one that earns its place. A page written from
|
|
715
|
+
passports alone compiled on the first attempt apart from a single prop the
|
|
716
|
+
model had remembered from elsewhere — every type, union value and handler
|
|
717
|
+
signature the passports carried came out right. So the remaining failure
|
|
718
|
+
mode is invention, and that is what this checks.
|
|
719
|
+
|
|
720
|
+
No dependencies: MCP is newline-delimited JSON-RPC over stdio, and a server
|
|
721
|
+
shipped inside a library every consumer installs should not drag an SDK
|
|
722
|
+
along with it.
|
|
723
|
+
|
|
724
|
+
Marked beta — the tools work and are tested, but their names and shapes may
|
|
725
|
+
change.
|
|
726
|
+
|
|
727
|
+
## 2.4.3
|
|
728
|
+
|
|
729
|
+
### Fixed
|
|
730
|
+
|
|
731
|
+
**`passport --check` reported every component as stale on a machine whose
|
|
732
|
+
line endings differed from the one that generated the passport.**
|
|
733
|
+
|
|
734
|
+
A passport records a hash of the source it was derived from, and that hash
|
|
735
|
+
was taken over the file bytes exactly as they sat on disk. A checkout on
|
|
736
|
+
Windows holds CRLF and one on Linux holds LF, so the same unchanged file
|
|
737
|
+
produced two different hashes, and the check announced that all 27
|
|
738
|
+
components had drifted when nothing had changed at all.
|
|
739
|
+
|
|
740
|
+
It now normalises line endings before hashing, so the hash describes the
|
|
741
|
+
content rather than the checkout. If you have been seeing
|
|
742
|
+
|
|
743
|
+
```
|
|
744
|
+
passport stale - source changed since the passport was generated
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
on components you never touched, this is why, and it stops.
|
|
748
|
+
|
|
749
|
+
Running `npm run passport` once after upgrading rewrites the hashes in your
|
|
750
|
+
own copies.
|
|
751
|
+
|
|
752
|
+
## 2.4.2
|
|
753
|
+
|
|
754
|
+
### Fixed
|
|
755
|
+
|
|
756
|
+
**Your own class now beats a component's variant.**
|
|
757
|
+
|
|
758
|
+
Restyling a variant used to fail silently. A rule like
|
|
759
|
+
|
|
760
|
+
```css
|
|
761
|
+
.btn-brand { --bt-fill: #7c3aed; }
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
worked on a plain button and was ignored the moment anyone wrote
|
|
765
|
+
`variant="outline"`, because the shipped rule named two things
|
|
766
|
+
(`.bt-root[data-variant="outline"]`) where yours named one, and the browser
|
|
767
|
+
prefers the more specific selector. No error, nothing in devtools -- the
|
|
768
|
+
colour simply did not apply.
|
|
769
|
+
|
|
770
|
+
Selectors that carry an option you chose -- `variant`, `size`, `orientation`,
|
|
771
|
+
`appearance`, `placement` and the rest -- are now written so they add no
|
|
772
|
+
weight of their own. One class from you is enough, on any variant, in any
|
|
773
|
+
setup:
|
|
774
|
+
|
|
775
|
+
```tsx
|
|
776
|
+
<Button variant="outline" className="btn-brand">Save</Button>
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
**State deliberately still wins.** Disabled, invalid, selected, loading and
|
|
780
|
+
the other runtime states keep their weight, because a brand colour has no
|
|
781
|
+
business painting over a disabled control. To restyle a state, name the
|
|
782
|
+
state: `.btn-brand[data-disabled] { ... }`.
|
|
783
|
+
|
|
784
|
+
215 selectors across 26 stylesheets. Verified by capturing the computed
|
|
785
|
+
styles of 3,716 elements across every demo in light and dark before and
|
|
786
|
+
after: the only differences were opacity on the shimmer and spinner, which
|
|
787
|
+
differ between two runs of the same build because they are mid-animation.
|
|
788
|
+
Nothing else moved.
|
|
789
|
+
|
|
790
|
+
Nothing in your code needs to change. If you had already worked around this
|
|
791
|
+
with a more specific selector, that still wins.
|
|
792
|
+
|
|
793
|
+
## 2.4.1
|
|
794
|
+
|
|
795
|
+
### Fixed
|
|
796
|
+
|
|
797
|
+
**The stylesheet import printed after an install is now one you can paste.**
|
|
798
|
+
|
|
799
|
+
2.4.0 could put the components under `src/`, and printed the path to the
|
|
800
|
+
barrel from the project root -- which is correct from nowhere in particular.
|
|
801
|
+
In a Next.js app it read:
|
|
802
|
+
|
|
803
|
+
```css
|
|
804
|
+
@import "./src/component-lib/gbs.css" layer(components);
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
while the file to edit was `src/app/globals.css`, two directories away. You
|
|
808
|
+
had to work out the `../` yourself.
|
|
809
|
+
|
|
810
|
+
The installer now finds your global stylesheet in the usual places
|
|
811
|
+
(`src/app/globals.css`, `app/globals.css`, `src/styles/globals.css`,
|
|
812
|
+
`src/index.css` and friends), names it, and writes the path from there:
|
|
813
|
+
|
|
814
|
+
```
|
|
815
|
+
Add this to src/app/globals.css:
|
|
816
|
+
|
|
817
|
+
@import "tailwindcss";
|
|
818
|
+
@import "../component-lib/gbs.css" layer(components);
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
Where no stylesheet is found it falls back to the path from the project root,
|
|
822
|
+
as before. The header inside the generated `gbs.css` follows the same rule.
|
|
823
|
+
|
|
824
|
+
Nothing about the installed components changed; this is the installer's
|
|
825
|
+
output only.
|
|
826
|
+
|
|
827
|
+
## 2.4.0
|
|
828
|
+
|
|
829
|
+
The first release published as **`@grampro/kit`**. `gbs-add-block` keeps
|
|
830
|
+
working for now and installs the same components, but new work happens here.
|
|
831
|
+
|
|
832
|
+
### The package has a new name
|
|
833
|
+
|
|
834
|
+
```bash
|
|
835
|
+
npx @grampro/kit add DataGrid
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
`npx gbs-add-block` still resolves, and the `gbs-add-block` binary is still
|
|
839
|
+
installed, so existing scripts keep running. Both will stay for a few
|
|
840
|
+
releases before the old name is deprecated.
|
|
841
|
+
|
|
842
|
+
### Commands read as commands
|
|
843
|
+
|
|
844
|
+
`add`, `list`, `skill` and `passport` are verbs now:
|
|
845
|
+
|
|
846
|
+
```bash
|
|
847
|
+
npx @grampro/kit add Button DataGrid
|
|
848
|
+
npx @grampro/kit list
|
|
849
|
+
npx @grampro/kit skill --for claude
|
|
850
|
+
npx @grampro/kit passport --check
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
The old flag spellings (`-a Button`, `-skill`, `-passport`) still work and
|
|
854
|
+
print the new spelling once. `--legacy` reaches the 1.x component set, which
|
|
855
|
+
is where `--beta` went: it used to opt *in* to the current components, and
|
|
856
|
+
there is nothing left to opt into.
|
|
857
|
+
|
|
858
|
+
### You choose where components land
|
|
859
|
+
|
|
860
|
+
The destination was fixed at `component-lib/` in the directory you ran the
|
|
861
|
+
command from, which put it beside `src/` rather than inside it for most
|
|
862
|
+
projects. Now:
|
|
863
|
+
|
|
864
|
+
- `--dest <path>` puts them wherever you want.
|
|
865
|
+
- Failing that, an install already in the project wins, so a second `add`
|
|
866
|
+
lands beside the first. That is how a custom `--dest` is remembered; no
|
|
867
|
+
config file is written into your project.
|
|
868
|
+
- Failing that, a project with a `src/` folder gets `src/component-lib/`,
|
|
869
|
+
and everything else keeps `component-lib/` at the root.
|
|
870
|
+
|
|
871
|
+
Nothing moves on its own: if you already have `component-lib/`, that is
|
|
872
|
+
still where components go.
|
|
873
|
+
|
|
874
|
+
The stylesheet import printed after an install now names the path the files
|
|
875
|
+
actually landed at, relative to your project root.
|
|
876
|
+
|
|
877
|
+
### Fixed
|
|
878
|
+
|
|
879
|
+
- `add Button --dest app/ui` tried to install a component called `app/ui`.
|
|
880
|
+
A flag's value was being read as a component name; the same was true of
|
|
881
|
+
`--for`.
|
|
882
|
+
|
|
883
|
+
### Internal
|
|
884
|
+
|
|
885
|
+
The library source moved from `source/beta-components` to
|
|
886
|
+
`source/components`, and the 1.x set from `source/components` to
|
|
887
|
+
`source/legacy-components`. This changes nothing for installed components —
|
|
888
|
+
the files you receive and their import paths are identical — but every
|
|
889
|
+
`passport.json` has a new `sourceHash`, because that hash covers
|
|
890
|
+
repo-relative paths.
|
|
891
|
+
|
|
892
|
+
## 2.3.0
|
|
893
|
+
|
|
894
|
+
Published as a minor, but **it contains one breaking change to styling**. Read
|
|
895
|
+
the upgrade note below before updating.
|
|
896
|
+
|
|
897
|
+
### Breaking: component CSS is no longer in a cascade layer
|
|
898
|
+
|
|
899
|
+
Component rules used to live in `@layer gbs`, and 2.1.0 asked Tailwind v4
|
|
900
|
+
projects to add `@layer gbs, utilities;` to their global CSS. Both are gone.
|
|
901
|
+
|
|
902
|
+
A cascade layer loses to *any* unlayered stylesheet regardless of specificity,
|
|
903
|
+
and Tailwind v3's preflight and Bootstrap's Reboot are both unlayered. Measured
|
|
904
|
+
on 2.2.0: under Tailwind v3 the components rendered with `border: 0` and
|
|
905
|
+
`padding-left: 0`; under Bootstrap every button was square. No host-side
|
|
906
|
+
declaration could fix either, because nothing layered can outrank unlayered CSS.
|
|
907
|
+
|
|
908
|
+
Component CSS now ships unlayered and wins on ordinary specificity, so Tailwind
|
|
909
|
+
v3, Bootstrap and framework-free projects work with no setup at all.
|
|
910
|
+
|
|
911
|
+
**What to change:**
|
|
912
|
+
|
|
913
|
+
- Delete any `@layer gbs, utilities;` (or similar) line you added for 2.1.0.
|
|
914
|
+
- Import the generated barrel instead of individual stylesheets:
|
|
915
|
+
`@import "./component-lib/gbs.css";`
|
|
916
|
+
- **Tailwind v4 only** — import it after the framework and into its components
|
|
917
|
+
layer, or utilities stop overriding component rules:
|
|
918
|
+
```css
|
|
919
|
+
@import "tailwindcss";
|
|
920
|
+
@import "./component-lib/gbs.css" layer(components);
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
The installer detects which line you need and prints it.
|
|
924
|
+
|
|
925
|
+
### Added
|
|
926
|
+
|
|
927
|
+
- **`<DataGrid ai />`** — a natural-language input above the grid, driven by an
|
|
928
|
+
adapter the application supplies through `<GramproAIProvider>`. No model is
|
|
929
|
+
bundled, downloaded or named, and with no provider the prop renders nothing.
|
|
930
|
+
- **WebMCP** — `registerGridTool(agent)` exposes one tool, `operate_grid`, to a
|
|
931
|
+
browser agent. Its schema is generated from the live grid. Needs no model.
|
|
932
|
+
- **Generated stylesheet barrel** — the CLI writes `component-lib/gbs.css` on
|
|
933
|
+
every install, so the import list stays correct as you add components.
|
|
934
|
+
- **Thin scrollbars** across every scrolling surface, themeable from `:root`
|
|
935
|
+
via `--gbs-scrollbar-width`, `--gbs-scrollbar-thumb`,
|
|
936
|
+
`--gbs-scrollbar-thumb-hover` and `--gbs-scrollbar-track`. Add
|
|
937
|
+
`class="gbs-scroll"` to your own scroll areas to match. Scroll containers the
|
|
938
|
+
kit does not own are left alone.
|
|
939
|
+
|
|
940
|
+
### Security
|
|
941
|
+
|
|
942
|
+
- Pinned `dompurify` to `^3.4.16` via `overrides`, clearing two DOM XSS
|
|
943
|
+
advisories reachable through `@grampro/headless-helpers → jspdf`. The 2.0 beta
|
|
944
|
+
components never used that chain. `npm audit` is now clean.
|
|
945
|
+
- Removed the `path` dependency. `require("path")` resolves to Node's built-in,
|
|
946
|
+
so the npm package was inert — a deprecated userland shim sitting in the
|
|
947
|
+
dependency tree for no reason.
|
|
948
|
+
|
|
949
|
+
### Documentation
|
|
950
|
+
|
|
951
|
+
- Documented what leaves the page with a remote AI adapter: the runtime contract
|
|
952
|
+
carries real values from low-cardinality columns. Mark personal columns
|
|
953
|
+
`semantics: { email: { pii: true } }` — a PII column is denied *and* never
|
|
954
|
+
summarised — or pass `stats: false`. Note that `policy.denyFilter` governs what
|
|
955
|
+
may be *done* with a column, not whether it may be *described*.
|
|
956
|
+
- Corrected the agent skill's install instructions, which still told agents to
|
|
957
|
+
import each stylesheet individually with no `layer()`.
|
|
958
|
+
|
|
959
|
+
### Packaging
|
|
960
|
+
|
|
961
|
+
- Test files are no longer published (35 files, 233 KB). They were filtered out
|
|
962
|
+
at install time anyway.
|
|
963
|
+
- Added `repository`, `homepage` and `bugs` metadata.
|