@grampro/kit 2.6.3 → 2.7.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.
Files changed (93) hide show
  1. package/.gbs/skills/gbs-components/SKILL.md +5 -4
  2. package/.gbs/skills/gbs-components/references/install.md +17 -14
  3. package/CHANGELOG.md +164 -0
  4. package/README.md +19 -6
  5. package/index.cjs +59 -59
  6. package/package.json +2 -2
  7. package/schema/passport-overlay-v1.schema.json +67 -0
  8. package/source/components/accordion/passport.json +45 -8
  9. package/source/components/accordion/passport.manual.json +46 -0
  10. package/source/components/alert/passport.json +41 -8
  11. package/source/components/alert/passport.manual.json +42 -0
  12. package/source/components/avatar/passport.json +40 -7
  13. package/source/components/avatar/passport.manual.json +43 -0
  14. package/source/components/badge/passport.json +43 -7
  15. package/source/components/badge/passport.manual.json +46 -0
  16. package/source/components/breadcrumb/passport.json +36 -7
  17. package/source/components/breadcrumb/passport.manual.json +39 -0
  18. package/source/components/button/passport.json +1 -1
  19. package/source/components/button/passport.manual.json +1 -1
  20. package/source/components/card/passport.json +45 -8
  21. package/source/components/card/passport.manual.json +47 -0
  22. package/source/components/checkbox/core/agent.ts +33 -0
  23. package/source/components/checkbox/core/index.ts +2 -0
  24. package/source/components/checkbox/passport.json +83 -10
  25. package/source/components/checkbox/passport.manual.json +82 -0
  26. package/source/components/combobox/core/agent.ts +38 -0
  27. package/source/components/combobox/core/index.ts +2 -0
  28. package/source/components/combobox/passport.json +103 -11
  29. package/source/components/combobox/passport.manual.json +101 -0
  30. package/source/components/combobox/react/props.ts +14 -0
  31. package/source/components/combobox/react/useCombobox.ts +7 -1
  32. package/source/components/data-grid/export/xlsx.ts +9 -2
  33. package/source/components/data-grid/passport.json +2 -2
  34. package/source/components/data-grid/passport.manual.json +1 -1
  35. package/source/components/date-picker/core/agent.ts +42 -0
  36. package/source/components/date-picker/core/index.ts +2 -0
  37. package/source/components/date-picker/passport.json +102 -11
  38. package/source/components/date-picker/passport.manual.json +100 -0
  39. package/source/components/date-picker/react/DatePicker.tsx +6 -0
  40. package/source/components/date-picker/react/DateRangePicker.tsx +4 -0
  41. package/source/components/date-picker/react/props.ts +17 -0
  42. package/source/components/dialog/passport.json +54 -9
  43. package/source/components/dialog/passport.manual.json +54 -0
  44. package/source/components/file-uploader/passport.json +65 -10
  45. package/source/components/file-uploader/passport.manual.json +64 -0
  46. package/source/components/input/core/agent.ts +36 -0
  47. package/source/components/input/core/index.ts +2 -0
  48. package/source/components/input/passport.json +89 -12
  49. package/source/components/input/passport.manual.json +86 -0
  50. package/source/components/menu/passport.json +64 -9
  51. package/source/components/menu/passport.manual.json +64 -0
  52. package/source/components/modal/passport.json +52 -9
  53. package/source/components/modal/passport.manual.json +52 -0
  54. package/source/components/number-input/core/agent.ts +38 -0
  55. package/source/components/number-input/core/index.ts +2 -0
  56. package/source/components/number-input/passport.json +92 -11
  57. package/source/components/number-input/passport.manual.json +90 -0
  58. package/source/components/popover/passport.json +47 -8
  59. package/source/components/popover/passport.manual.json +48 -0
  60. package/source/components/progress/passport.json +37 -8
  61. package/source/components/progress/passport.manual.json +39 -0
  62. package/source/components/radio-group/core/agent.ts +34 -0
  63. package/source/components/radio-group/core/index.ts +2 -0
  64. package/source/components/radio-group/passport.json +77 -10
  65. package/source/components/radio-group/passport.manual.json +76 -0
  66. package/source/components/shared/core/agent/field-agent.ts +101 -0
  67. package/source/components/shared/core/agent/field-executors.ts +137 -0
  68. package/source/components/shared/core/agent/field.ts +649 -0
  69. package/source/components/shared/core/agent/index.ts +30 -0
  70. package/source/components/shared/core/agent/write.ts +58 -0
  71. package/source/components/shared/react/useFieldAgent.ts +88 -0
  72. package/source/components/skeleton/passport.json +37 -6
  73. package/source/components/skeleton/passport.manual.json +39 -0
  74. package/source/components/spinner/passport.json +34 -7
  75. package/source/components/spinner/passport.manual.json +37 -0
  76. package/source/components/switch/core/agent.ts +31 -0
  77. package/source/components/switch/core/index.ts +2 -0
  78. package/source/components/switch/passport.json +68 -10
  79. package/source/components/switch/passport.manual.json +67 -0
  80. package/source/components/tabs/passport.json +50 -9
  81. package/source/components/tabs/passport.manual.json +50 -0
  82. package/source/components/textarea/core/agent.ts +34 -0
  83. package/source/components/textarea/core/index.ts +2 -0
  84. package/source/components/textarea/passport.json +83 -10
  85. package/source/components/textarea/passport.manual.json +82 -0
  86. package/source/components/toaster/passport.json +41 -8
  87. package/source/components/toaster/passport.manual.json +42 -0
  88. package/source/components/tooltip/passport.json +39 -6
  89. package/source/components/tooltip/passport.manual.json +41 -0
  90. package/tools/mcp/design.cjs +6 -1
  91. package/tools/mcp/figma.cjs +49 -9
  92. package/tools/mcp/install.cjs +6 -1
  93. package/tools/mcp/server.cjs +14 -2
@@ -4,7 +4,7 @@ description: Builds UI with the GramproKit component library (@grampro/kit). Use
4
4
  autoAttach: ["src/**/*.tsx", "src/**/*.jsx", "app/**/*.tsx", "components/**/*.tsx"]
5
5
  ---
6
6
 
7
- # GBS components (2.0 beta)
7
+ # GBS components (2.x)
8
8
 
9
9
  ## If the MCP server is connected
10
10
 
@@ -30,8 +30,9 @@ Not an npm dependency — the CLI **copies source into the repo**:
30
30
  npx @grampro/kit add Button,Input,Modal
31
31
  ```
32
32
 
33
- Writes `component-lib/<folder>/` plus `component-lib/shared/`. Always pass
34
- `--beta`. Import the barrel in your component:
33
+ Writes `component-lib/<folder>/` plus `component-lib/shared/`. No flag is
34
+ needed: the 2.x components are the default. Import the barrel in your
35
+ component:
35
36
 
36
37
  ```ts
37
38
  import { Button } from "component-lib/button";
@@ -195,7 +196,7 @@ a bigger model.
195
196
 
196
197
  ## Details (in `references/`)
197
198
 
198
- - `install.md` — CLI flags, folders, 1.x vs beta.
199
+ - `install.md` — CLI flags, folders, 1.x vs 2.x.
199
200
  - `forms.md` — fields, controlled state, form posting.
200
201
  - `pickers.md` — Select, MultiSelect, DatePicker, Uploader.
201
202
  - `overlays.md` — Modal, dialog, Popover, Menu, Tooltip.
@@ -10,7 +10,7 @@ imported from `node_modules` at runtime, and the copied files are yours to edit.
10
10
  `bin: { "@grampro/kit": "index.cjs" }` and `files: ["index.cjs", "source",
11
11
  ".gbs"]`. There is nothing to `import "@grampro/kit"` from.
12
12
 
13
- Peer dependencies: `react@^19` and `react-dom@^19`. The beta components have no
13
+ Peer dependencies: `react@^19` and `react-dom@^19`. The components have no
14
14
  other runtime dependencies.
15
15
 
16
16
  ## Commands
@@ -18,11 +18,11 @@ other runtime dependencies.
18
18
  ```bash
19
19
  npx @grampro/kit add Button # one component
20
20
  npx @grampro/kit add Button,Input,Modal # several
21
- npx @grampro/kit -i --beta # interactive picker
22
- npx @grampro/kit -l --beta # list available
21
+ npx @grampro/kit -i # interactive picker
22
+ npx @grampro/kit -l # list available
23
23
  npx @grampro/kit add Button --force # overwrite edited shared/ files
24
- npx @grampro/kit skill # install this skill
25
- npx @grampro/kit skill --for claude # only the Claude Code copy
24
+ npx @grampro/kit skill # install this skill
25
+ npx @grampro/kit skill --for claude # only the Claude Code copy
26
26
  ```
27
27
 
28
28
  | Flag | Alias | Meaning |
@@ -30,16 +30,19 @@ npx @grampro/kit skill --for claude # only the Claude Code copy
30
30
  | `--add` | `-a` | Component, or comma-separated list. Case-insensitive. |
31
31
  | `--interactive` | `-i` | Pick from a menu. |
32
32
  | `--list` | `-l` | Print available components. |
33
- | `--beta` | — | Install the 2.0 redesigned components. `-beta` also works. |
33
+ | `--legacy` | — | Install from the 1.x set instead. Unmaintained; see below. |
34
34
  | `--skill` | — | Install this skill at the project root. `-skill` and `-a skill` also work. |
35
35
  | `--for` | — | With `--skill`: which agents to write adapters for (`claude`, `codex`, `antigravity`, or `none`). Default: all. |
36
36
  | `--force` | — | Replace files you have edited locally in `shared/` or `.gbs/`. |
37
37
 
38
- **Always pass `--beta`.** Without it you get the 1.x set (`Select`, `SideBar`,
39
- `FormRenderer`, `MaterialInput`, `ContextMenu`, `Navbar`, `Bargraph`,
40
- `DarkMode`, `Toast`, `Uploader`, `UsePaginatedData`, `UseUploader` and others),
41
- which is a different, older API with different props. The two sets are not
42
- interchangeable.
38
+ **Pass no flag.** The 2.x components are what `add` installs. `--beta` used
39
+ to opt in to them and now does nothing but print a notice, so do not pass it.
40
+
41
+ `--legacy` reaches the 1.x set (`Select`, `SideBar`, `FormRenderer`,
42
+ `MaterialInput`, `ContextMenu`, `Navbar`, `Bargraph`, `DarkMode`, `Toast`,
43
+ `Uploader`, `UsePaginatedData`, `UseUploader` and others). That is a different,
44
+ older API with different props, it is no longer maintained, and the two sets
45
+ are not interchangeable. Do not reach for it unless asked to.
43
46
 
44
47
  ## Installing this skill
45
48
 
@@ -78,7 +81,7 @@ CLI from the repo root (or move the folder afterwards and fix the imports).
78
81
 
79
82
  ```
80
83
  component-lib/
81
- shared/ installed with every beta component
84
+ shared/ installed with every component
82
85
  button/
83
86
  data-grid/
84
87
  input/
@@ -105,7 +108,7 @@ Note the mismatch between the install name and the import name for two of them:
105
108
  - Install `Toaster`; import `toast` and `Toaster` from `component-lib/toaster`.
106
109
  - Install `Dialog`; import `dialog` and `DialogHost` from `component-lib/dialog`.
107
110
 
108
- ## Available beta components
111
+ ## Available components
109
112
 
110
113
  `DataGrid`, `Combobox`, `DatePicker`, `Toaster`, `FileUploader`, `Dialog`,
111
114
  `Input`, `Modal`, `Textarea`, `Button`, `Breadcrumb`, `Checkbox`, `Tabs`,
@@ -132,7 +135,7 @@ project has no reason to have.
132
135
 
133
136
  ## The shared folder
134
137
 
135
- Every beta component imports `../../shared`. The CLI installs it alongside
138
+ Every component imports `../../shared`. The CLI installs it alongside
136
139
  whatever you picked, and it is versioned independently (`shared/version.json`).
137
140
 
138
141
  Rules the installer enforces:
package/CHANGELOG.md CHANGED
@@ -1,5 +1,169 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.7.0
4
+
5
+ ### Added
6
+
7
+ **A design read from a URL now names its components.** An instance built
8
+ from a library is the most valuable thing a design can contain — it says
9
+ "this is a Button" instead of leaving an agent to infer it from a layer
10
+ name and a fill. The URL route recorded `instanceOf: "1:234"`, an opaque
11
+ id nothing could be done with, and discarded the maps that name it, which
12
+ Figma sends in the same response.
13
+
14
+ It resolves them now, preferring the component set's name over the
15
+ variant's: a variant is called `Size=md, Variant=primary` and its set is
16
+ called `Button`, and Button is what the agent is going to write. An
17
+ instance whose master is not in the response keeps its id rather than
18
+ guessing.
19
+
20
+ **Every component now says what it is for.** A passport had two halves: the
21
+ derived one, generated from the TypeScript, and the authored one — `purpose`,
22
+ `intentDomains`, `accessibility`, `composition`, `safeMutations`. The generator
23
+ emits empty shells for the authored half because none of it is in the types,
24
+ and only Button and DataGrid had ever been filled in. The other 25 are written
25
+ now.
26
+
27
+ `safeMutations` is the one an agent acts on: which props it may change without
28
+ altering behaviour, and which it may not, with the reason. An agent restyling a
29
+ FileUploader should be free to change `size` and `preview` and nowhere near
30
+ `endpoint`, `headers` or `transport` — that component is the one where a wrong
31
+ prop sends someone's data somewhere. `get_component` now returns all of it;
32
+ until this release it served `purpose` and dropped the rest, so the authored
33
+ half reached nobody.
34
+
35
+ Where no value in the schema's `intentDomains` enum honestly describes a
36
+ component, the list is left empty rather than filled for symmetry. Nine of them
37
+ are presentational, and a wrong routing hint is worse than none.
38
+
39
+ **A field runtime, so nine components are agent-operable instead of one.**
40
+ `setValue`, `clear`, `focus`, and `open`/`close` for the two that have
41
+ something to disclose, on Input, Textarea, NumberInput, Checkbox, Switch,
42
+ RadioGroup, Combobox and DatePicker.
43
+
44
+ The grid earned a runtime of its own because its operations are a language:
45
+ filter, sort, pin, paginate, export. A field has one verb, so the verb lives in
46
+ `shared/core/agent` once rather than eight times, and each component supplies
47
+ only a contract built from its own props. The same five layers rule on it —
48
+ schema, reference, coercion, policy, plausibility — so a write to a read-only
49
+ field is refused by name, an option that does not exist comes back with the
50
+ nearest one that does, and a number outside `min`/`max` is told which bound it
51
+ crossed rather than being silently clamped.
52
+
53
+ The open question was whether the executor abstraction generalised. A grid is
54
+ driven through an imperative API and a field is not, and the architecture notes
55
+ had flagged that as unproven. It holds: Combobox and DatePicker are driven
56
+ through their handles, the other six through the element their ref already
57
+ returns, and nothing above the executor knows which. `setValue` joins
58
+ `ComboboxHandle` and `DatePickerHandle` as a public method; the six that expose
59
+ the DOM element needed no API change at all, because the technique
60
+ `Input.clear()` has always used — the prototype setter plus a real event — is
61
+ the same write with a value in it.
62
+
63
+ `useFieldAgent` binds a contract to a ref. No component grew a prop for this.
64
+
65
+ **The authored passports had no schema of their own.** A `passport.manual.json`
66
+ pointed at `passport-v1.schema.json`, which describes the *merged* passport —
67
+ so an editor validating one reported all eight generated fields as missing
68
+ (`passportVersion`, `identity`, `source`, `props`, `events`, `slots`, `states`,
69
+ `coverage`), and `additionalProperties: false` made errors of the four keys only
70
+ an overlay has: `component`, `propNotes`, `notImplemented`, `$operationsNote`.
71
+
72
+ It was wrong on the two files that had it before and merely quiet; at
73
+ twenty-seven it is the thing that teaches people to ignore squiggles.
74
+ `schema/passport-overlay-v1.schema.json` describes what an overlay may
75
+ actually contain, referencing the merged schema for the fields they share so
76
+ the two cannot drift. A test holds every overlay to it, which also catches a
77
+ mistyped key — previously a silent no-op, since the merge only reads the names
78
+ it knows.
79
+
80
+ ### Security
81
+
82
+ **A failed JSON parse quoted the file back.** V8 puts the first ten or so
83
+ characters of its input into the error it throws, so pointing `designFile` at
84
+ something that was not JSON returned a slice of it:
85
+
86
+ That is not JSON: Unexpected token 's', "sk-proj-RE"... is not valid JSON
87
+
88
+ Ten bytes is not an extraction, but it is enough to confirm that a path
89
+ exists and what kind of file sits there, and an agent can be pointed at paths
90
+ in a loop. The server runs with your own authority and the agent could read
91
+ the file directly, so this was hygiene rather than a hole — and it cost
92
+ nothing to close. The three parse sites in `figma.cjs`, `design.cjs` and
93
+ `install.cjs` now name the file and say what was expected, without quoting
94
+ any of it.
95
+
96
+ **The package no longer installs a build toolchain.**
97
+ `@grampro/headless-helpers` declared `rollup`, its plugins and `typescript`
98
+ as runtime dependencies, so installing the kit pulled a compiler and a
99
+ bundler into `node_modules` and carried their advisories — an arbitrary file
100
+ write in Rollup and two ReDoS in picomatch, none of which any of this code
101
+ runs. Requiring `^1.0.22`, which moved them to devDependencies, removes 84
102
+ packages from a clean install and leaves the package at zero advisories.
103
+
104
+ **Mermaid rendered with sanitisation off.** The diagram component ran with
105
+ `securityLevel: "loose"`, which permits HTML in labels and click handlers,
106
+ and its output goes through `dangerouslySetInnerHTML`. Nothing was
107
+ exploitable: the only diagram text comes from our own MDX at build time, and
108
+ in fact no page renders one. But the two together are a trap for whoever
109
+ first renders a diagram from anything else, so it is `"strict"` now.
110
+
111
+ ### Changed
112
+
113
+ **The docs lead with the URL route.** Pasting a Figma link is one step;
114
+ the plugin route is five, and every one is a place to stop. The reason it
115
+ was necessary for designs built from a component library is now gone, so
116
+ the page says plainly: use the URL for a screen, and the plugin when you
117
+ want a whole product in one pass, or have no token, or are rate limited.
118
+
119
+ **`figma_frame` describes the URL route first.** Its own description still
120
+ said `designFile` was "the one to use for a whole screen", which was true
121
+ only while the URL route could not resolve component names. An agent reads
122
+ that description before it picks a route, so it was steering towards the long
123
+ way round. It now leads with the URL and keeps the file export for what the
124
+ file export is actually better at: a whole product in one pass, or no usable
125
+ token. The `llms.txt` preamble said nothing about the URL route at all, and
126
+ now says it is the shortest path from a design to a screen.
127
+
128
+ **The components are out of beta.** Only the MCP server still carries the
129
+ label, and it carries it in both places that matter: the docs page and the
130
+ `figma_frame` tool description an agent reads.
131
+
132
+ The one that was doing damage was in the agent skill, which is always in an
133
+ agent's context. It said **"Always pass `--beta`"** and explained that without
134
+ it you get the 1.x set. That had inverted: `--beta` became a no-op that prints
135
+ a deprecation notice, 2.x is what `add` installs, and `--legacy` is what
136
+ reaches 1.x. An agent following the skill was passing a dead flag and being
137
+ told the opposite of what the CLI does. The flag table now documents
138
+ `--legacy` instead, and says plainly that the 1.x set is unmaintained.
139
+
140
+ Also gone from the CLI's own output ("Redesigned beta components" when a name
141
+ does not match), the `llms.txt` preamble, which told every model that read the
142
+ site that the components were beta and their APIs might change, and the README
143
+ and architecture notes. `--beta` is still accepted, because scripts use it.
144
+
145
+ ### Fixed
146
+
147
+ **Headings on the translated pages had meaningless ids.** The slugger kept
148
+ only `[a-z0-9\s-]`, which leaves a Malayalam heading with nothing but its
149
+ spaces — so every heading fell through to `section` or to the `-` its spaces
150
+ became, and then took its id from the duplicate counter:
151
+
152
+ id="-" id="--1" id="--2" id="-structured-data" id="section-2"
153
+
154
+ That counter is positional, so adding a heading renumbered every anchor below
155
+ it: no link to one could be relied on, and four prop-table links on
156
+ `ml/breadcrumb` and `ml/button` pointed at the English anchors and had never
157
+ resolved. The class keeps letters, digits and combining marks in any script
158
+ now, so those headings slug to their own text. `\p{M}` matters as much as
159
+ `\p{L}` here: Malayalam vowel signs are combining marks, and dropping them
160
+ mangles the text rather than emptying it. Every ASCII heading slugs to the
161
+ same string as before, so no existing anchor moved.
162
+
163
+ `pnpm check:anchors` in `docs-site` now checks every in-site fragment against
164
+ the headings its target page actually offers, because a dead anchor does not
165
+ 404 — the page loads and ignores it.
166
+
3
167
  ## 2.6.3
4
168
 
5
169
  ### Fixed
package/README.md CHANGED
@@ -197,10 +197,16 @@ have edited is never replaced without `--force`.
197
197
  The 2.x line is in active development and the next release will be a major
198
198
  version. What is built and tested:
199
199
 
200
- - 27 beta components, source-first, zero runtime dependencies
201
- - Passports for all 27, generated and drift-checked
200
+ - 27 components, source-first, zero runtime dependencies
201
+ - Passports for all 27, generated and drift-checked, and all 27 now carry the
202
+ authored half too: what the component is for, what it supplies to assistive
203
+ technology, and which props an agent may change without altering behaviour
202
204
  - The DataGrid agent runtime: 21 operations, five validation layers, snapshot
203
205
  undo, and a frozen 231-case evaluation corpus
206
+ - The field runtime: `setValue`, `clear`, `focus` and, where there is something
207
+ to disclose, `open` and `close` — on Input, Textarea, NumberInput, Checkbox,
208
+ Switch, RadioGroup, Combobox and DatePicker. The same five layers, written
209
+ once in `shared/core/agent` rather than eight times
204
210
  - **`<DataGrid ai />`** — a natural-language box, driven by an adapter the
205
211
  application supplies. No model is bundled, downloaded or named.
206
212
  - **WebMCP** — one tool, `operate_grid`, exposing the same validated boundary to
@@ -211,10 +217,17 @@ Every producer — a model, a browser agent, a form — proposes. The validator
211
217
  authorizes. The executor mutates state. That boundary is the architecture, and
212
218
  it is why no AI path gets a second route into the component.
213
219
 
214
- Still open: operations for DatePicker and Combobox (both are controlled
215
- components with no imperative write API, which the executor abstraction is meant
216
- to solve but has not yet proven), and the remaining authored passport metadata.
217
- The roadmap and its unresolved questions are in
220
+ Nine of the 27 are agent-operable. The executor abstraction was the open
221
+ question — a grid is driven through an imperative API, and a field is not — and
222
+ it is settled: Combobox and DatePicker are driven through their handles,
223
+ Input, Textarea, NumberInput, Checkbox, Switch and RadioGroup through the
224
+ element their ref already hands back. Neither the contract, the schemas, the
225
+ validator nor the refusals know which.
226
+
227
+ Still open: the components whose value is in what they contain rather than what
228
+ they hold — Menu, Tabs, Accordion, Modal, FileUploader — and the question of
229
+ whether a form is better driven field by field or as one composite assembled
230
+ from several passports. The roadmap and its unresolved questions are in
218
231
  [`docs/agent-native-architecture.md`](docs/agent-native-architecture.md).
219
232
 
220
233
  ## Styles