gbs-add-block 2.0.4 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/.gbs/skills/gbs-components/SKILL.md +190 -134
  2. package/.gbs/skills/gbs-components/references/install.md +25 -3
  3. package/.gbs/skills/gbs-components/references/styling.md +246 -201
  4. package/CHANGELOG.md +74 -0
  5. package/README.md +157 -11
  6. package/index.cjs +212 -3
  7. package/package.json +41 -10
  8. package/schema/passport-v1.schema.json +204 -0
  9. package/source/beta-components/accordion/passport.json +259 -0
  10. package/source/beta-components/accordion/styles.css +207 -208
  11. package/source/beta-components/alert/passport.json +250 -0
  12. package/source/beta-components/alert/styles.css +154 -155
  13. package/source/beta-components/avatar/passport.json +294 -0
  14. package/source/beta-components/avatar/styles.css +201 -203
  15. package/source/beta-components/badge/passport.json +332 -0
  16. package/source/beta-components/badge/styles.css +203 -204
  17. package/source/beta-components/breadcrumb/passport.json +243 -0
  18. package/source/beta-components/breadcrumb/styles.css +138 -139
  19. package/source/beta-components/button/passport.json +402 -0
  20. package/source/beta-components/button/passport.manual.json +31 -0
  21. package/source/beta-components/button/styles.css +232 -233
  22. package/source/beta-components/card/passport.json +337 -0
  23. package/source/beta-components/card/styles.css +230 -231
  24. package/source/beta-components/checkbox/passport.json +456 -0
  25. package/source/beta-components/checkbox/styles.css +211 -212
  26. package/source/beta-components/combobox/passport.json +456 -0
  27. package/source/beta-components/combobox/styles.css +419 -417
  28. package/source/beta-components/data-grid/agent/coerce.ts +368 -0
  29. package/source/beta-components/data-grid/agent/contract.ts +410 -0
  30. package/source/beta-components/data-grid/agent/dataset.ts +92 -0
  31. package/source/beta-components/data-grid/agent/engine.ts +470 -0
  32. package/source/beta-components/data-grid/agent/executors.ts +155 -0
  33. package/source/beta-components/data-grid/agent/index.ts +79 -0
  34. package/source/beta-components/data-grid/agent/intent.ts +324 -0
  35. package/source/beta-components/data-grid/agent/operations.ts +335 -0
  36. package/source/beta-components/data-grid/agent/validate.ts +630 -0
  37. package/source/beta-components/data-grid/agent/webmcp.ts +107 -0
  38. package/source/beta-components/data-grid/index.ts +14 -7
  39. package/source/beta-components/data-grid/passport.json +1051 -0
  40. package/source/beta-components/data-grid/passport.manual.json +255 -0
  41. package/source/beta-components/data-grid/react/AskGrid.tsx +164 -0
  42. package/source/beta-components/data-grid/react/DataGrid.tsx +39 -0
  43. package/source/beta-components/data-grid/styles.css +874 -717
  44. package/source/beta-components/date-picker/passport.json +407 -0
  45. package/source/beta-components/date-picker/styles.css +445 -446
  46. package/source/beta-components/dialog/passport.json +344 -0
  47. package/source/beta-components/dialog/styles.css +280 -278
  48. package/source/beta-components/file-uploader/passport.json +518 -0
  49. package/source/beta-components/file-uploader/styles.css +394 -395
  50. package/source/beta-components/input/passport.json +536 -0
  51. package/source/beta-components/input/styles.css +295 -296
  52. package/source/beta-components/menu/passport.json +322 -0
  53. package/source/beta-components/menu/styles.css +224 -222
  54. package/source/beta-components/modal/passport.json +289 -0
  55. package/source/beta-components/modal/styles.css +241 -239
  56. package/source/beta-components/number-input/passport.json +541 -0
  57. package/source/beta-components/number-input/styles.css +230 -231
  58. package/source/beta-components/popover/passport.json +238 -0
  59. package/source/beta-components/popover/styles.css +148 -146
  60. package/source/beta-components/progress/passport.json +270 -0
  61. package/source/beta-components/progress/styles.css +200 -202
  62. package/source/beta-components/radio-group/passport.json +477 -0
  63. package/source/beta-components/radio-group/styles.css +241 -242
  64. package/source/beta-components/shared/core/agent/adapter.ts +65 -0
  65. package/source/beta-components/shared/core/agent/history.ts +120 -0
  66. package/source/beta-components/shared/core/agent/index.ts +46 -0
  67. package/source/beta-components/shared/core/agent/numbers.ts +217 -0
  68. package/source/beta-components/shared/core/agent/schema.ts +180 -0
  69. package/source/beta-components/shared/core/agent/types.ts +169 -0
  70. package/source/beta-components/shared/core/agent/webmcp.ts +328 -0
  71. package/source/beta-components/shared/index.ts +9 -0
  72. package/source/beta-components/shared/react/GramproAIProvider.tsx +50 -0
  73. package/source/beta-components/shared/react/useAskAgent.ts +217 -0
  74. package/source/beta-components/shared/styles.css +79 -0
  75. package/source/beta-components/shared/version.json +4 -4
  76. package/source/beta-components/shared/version.ts +6 -6
  77. package/source/beta-components/skeleton/passport.json +251 -0
  78. package/source/beta-components/skeleton/styles.css +185 -186
  79. package/source/beta-components/spinner/passport.json +245 -0
  80. package/source/beta-components/spinner/styles.css +145 -146
  81. package/source/beta-components/switch/passport.json +421 -0
  82. package/source/beta-components/switch/styles.css +194 -196
  83. package/source/beta-components/tabs/passport.json +315 -0
  84. package/source/beta-components/tabs/styles.css +234 -235
  85. package/source/beta-components/textarea/passport.json +382 -0
  86. package/source/beta-components/textarea/styles.css +158 -159
  87. package/source/beta-components/toaster/passport.json +221 -0
  88. package/source/beta-components/toaster/styles.css +282 -283
  89. package/source/beta-components/tooltip/passport.json +170 -0
  90. package/source/beta-components/tooltip/styles.css +71 -72
  91. package/tools/env.cjs +61 -0
  92. package/tools/passport/cli.cjs +79 -0
  93. package/tools/passport/extract.cjs +493 -0
  94. package/tools/passport/index.cjs +185 -0
  95. package/tools/passport/merge.cjs +131 -0
  96. package/tools/passport/policy.cjs +65 -0
  97. package/tools/passport/validate.cjs +277 -0
  98. package/tools/ts-require.cjs +79 -0
  99. package/source/beta-components/accordion/__tests__/core.test.ts +0 -58
  100. package/source/beta-components/alert/__tests__/core.test.ts +0 -17
  101. package/source/beta-components/avatar/__tests__/core.test.ts +0 -88
  102. package/source/beta-components/badge/__tests__/core.test.ts +0 -46
  103. package/source/beta-components/breadcrumb/__tests__/core.test.ts +0 -58
  104. package/source/beta-components/button/__tests__/core.test.ts +0 -31
  105. package/source/beta-components/card/__tests__/core.test.ts +0 -57
  106. package/source/beta-components/checkbox/__tests__/core.test.ts +0 -40
  107. package/source/beta-components/combobox/__tests__/core.test.ts +0 -134
  108. package/source/beta-components/data-grid/__tests__/core.test.ts +0 -356
  109. package/source/beta-components/data-grid/__tests__/export.test.ts +0 -70
  110. package/source/beta-components/data-grid/__tests__/pdf.test.ts +0 -209
  111. package/source/beta-components/date-picker/__tests__/core.test.ts +0 -273
  112. package/source/beta-components/dialog/__tests__/core.test.ts +0 -86
  113. package/source/beta-components/file-uploader/__tests__/core.test.ts +0 -395
  114. package/source/beta-components/input/__tests__/core.test.ts +0 -75
  115. package/source/beta-components/menu/__tests__/core.test.ts +0 -120
  116. package/source/beta-components/modal/__tests__/core.test.ts +0 -55
  117. package/source/beta-components/number-input/__tests__/core.test.ts +0 -151
  118. package/source/beta-components/progress/__tests__/core.test.ts +0 -56
  119. package/source/beta-components/radio-group/__tests__/core.test.ts +0 -64
  120. package/source/beta-components/shared/__tests__/boundaries.test.ts +0 -95
  121. package/source/beta-components/shared/__tests__/core.test.ts +0 -55
  122. package/source/beta-components/shared/__tests__/position.test.ts +0 -143
  123. package/source/beta-components/skeleton/__tests__/core.test.ts +0 -41
  124. package/source/beta-components/spinner/__tests__/core.test.ts +0 -48
  125. package/source/beta-components/switch/__tests__/core.test.ts +0 -64
  126. package/source/beta-components/tabs/__tests__/core.test.ts +0 -51
  127. package/source/beta-components/textarea/__tests__/core.test.ts +0 -38
  128. package/source/beta-components/toaster/__tests__/core.test.ts +0 -256
  129. package/source/beta-components/tooltip/__tests__/core.test.ts +0 -42
package/README.md CHANGED
@@ -1,14 +1,92 @@
1
- # GBS Building Blocks 2.0 (v2.0.4)
1
+ # GramproKit
2
2
 
3
- Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
3
+ **An agent-native UI runtime for React.**
4
+
5
+ React components you own — styled, dependency-free, and machine-readable. Each
6
+ component arrives in your project as source, with its stylesheet, and with a
7
+ contract describing what it is and what can safely be done to it.
8
+
9
+ ```bash
10
+ npx gbs-add-block@latest -a DataGrid --beta
11
+ ```
12
+
13
+ The source lands in `component-lib/`. There is no runtime package to depend on,
14
+ and nothing to wait for upstream when you need a change.
15
+
16
+ > **Upgrading from 2.1.0 or 2.2.0 — one line to change.** Component CSS no
17
+ > longer lives in a cascade layer, because a layer loses to any unlayered reset
18
+ > and that broke Tailwind v3 and Bootstrap outright. Delete any
19
+ > `@layer gbs, utilities;` you added, and import the generated barrel:
20
+ > `@import "./component-lib/gbs.css";` — with Tailwind v4, after the framework
21
+ > and `layer(components)`. The installer prints the line you need, and
22
+ > [`CHANGELOG.md`](CHANGELOG.md) has the detail.
23
+
24
+ ## What "agent-native" means here
25
+
26
+ Most component libraries are built for a human reading documentation. These are
27
+ built to be operable by a program as well — a coding agent writing your UI, or
28
+ a model driving a grid at runtime — without either one guessing.
29
+
30
+ Three things make that true, and all three ship today:
31
+
32
+ **A passport per component.** `passport.json` is generated from the TypeScript
33
+ source and drift-checked in CI: every prop with its real type, the events, the
34
+ slots, the `data-*` states, and the operations the component actually supports.
35
+ Generated, so it cannot quietly stop being true.
36
+ → [`docs/component-passport.md`](docs/component-passport.md)
37
+
38
+ **A runtime contract.** The passport says what a DataGrid *is*. The runtime
39
+ contract says what *this* grid can do right now: these columns, these operators,
40
+ this state, this many rows. Counts and bounded summaries only — never your data.
41
+ → [`docs/grid-agent-runtime.md`](docs/grid-agent-runtime.md)
42
+
43
+ **A validator between intent and action.** Five layers — schema, reference,
44
+ coercion, policy, plausibility — stand between a requested operation and
45
+ anything happening. `"1 lakh"` becomes `100000` deterministically rather than by
46
+ a model's arithmetic. An operation on a column the host restricted is refused
47
+ with a reason. Nothing that fails validation runs.
48
+
49
+ ### What that buys you with no AI at all
50
+
51
+ The runtime ships no model, and most of it is useful anyway:
52
+
53
+ - **Saved views** and **shareable URLs** — the grid's whole state in a link
54
+ - **Undo and redo** across every operation, by snapshot
55
+ - **An audit trail** of what changed, in readable labels
56
+ - **Confirmation before anything irreversible**, with the affected row count
57
+ computed from a real dry run
58
+
59
+ A model, when one is added, plugs into the front of that pipeline. It produces
60
+ an intent, and the validator treats it exactly as it treats any other untrusted
61
+ input. That is the point of the ordering.
62
+
63
+ ## Not headless — styled, and replaceable
64
+
65
+ An earlier version of this README called these components headless. They are
66
+ not. They ship 27 stylesheets with a default look, theming and dark mode, and
67
+ the word elsewhere in the ecosystem means *no styles at all*.
68
+
69
+ What is true is that the styling gets out of your way at three levels: CSS
70
+ variables, slot classes, and `data-*` state attributes. Nothing is
71
+ `!important`, and nothing needs beating on specificity.
72
+
73
+ Each component also has a **framework-free core** — `createDialogStore()`,
74
+ `createGridEngine()` — with no React imports, usable on a server. That part is
75
+ genuinely headless, and the component READMEs document it under "Headless use".
4
76
 
5
77
  ## Documentation
6
78
 
7
- For detailed documentation on usage and props, Please visit: [Building Block Documentation](https://gramprokit.vercel.app)
79
+ [kit.gramproindia.com](https://kit.gramproindia.com) — usage and props per
80
+ component.
8
81
 
9
- ## Beta Components
82
+ In this repository:
10
83
 
11
- New 2.0.0 beta (current version) is available for testing and feedback, Please visit: [Building Block Documentation v2.0.0 beta](https://gramprokit.vercel.app)
84
+ | | |
85
+ | --- | --- |
86
+ | [`docs/component-passport.md`](docs/component-passport.md) | the generated contract, and why its text is data rather than instructions |
87
+ | [`docs/grid-agent-runtime.md`](docs/grid-agent-runtime.md) | runtime contract, intent schema, the five validation layers, undo, saved views |
88
+ | [`docs/grid-agent-evaluation.md`](docs/grid-agent-evaluation.md) | the 230-case corpus and how a model gets measured against it |
89
+ | [`docs/agent-native-architecture.md`](docs/agent-native-architecture.md) | where this is going, and which parts are still proposal |
12
90
 
13
91
  ## Agent skill
14
92
 
@@ -33,13 +111,81 @@ Pick a subset with `--for claude,codex`, or `--for none` for just `.gbs/`.
33
111
  Commit the result so everyone's agent picks it up. Re-run to update; a file you
34
112
  have edited is never replaced without `--force`.
35
113
 
36
- ## What's New 🎉 (Ver 2.0.4)
114
+ ## Status
115
+
116
+ The 2.x line is in active development and the next release will be a major
117
+ version. What is built and tested:
118
+
119
+ - 27 beta components, source-first, zero runtime dependencies
120
+ - Passports for all 27, generated and drift-checked
121
+ - The DataGrid agent runtime: 21 operations, five validation layers, snapshot
122
+ undo, and a frozen 231-case evaluation corpus
123
+ - **`<DataGrid ai />`** — a natural-language box, driven by an adapter the
124
+ application supplies. No model is bundled, downloaded or named.
125
+ - **WebMCP** — one tool, `operate_grid`, exposing the same validated boundary to
126
+ a browser agent. Needs no model at all.
127
+ - A model evaluation harness, with the measurements that justify both
128
+
129
+ Every producer — a model, a browser agent, a form — proposes. The validator
130
+ authorizes. The executor mutates state. That boundary is the architecture, and
131
+ it is why no AI path gets a second route into the component.
132
+
133
+ Still open: operations for DatePicker and Combobox (both are controlled
134
+ components with no imperative write API, which the executor abstraction is meant
135
+ to solve but has not yet proven), and the remaining authored passport metadata.
136
+ The roadmap and its unresolved questions are in
137
+ [`docs/agent-native-architecture.md`](docs/agent-native-architecture.md).
138
+
139
+ ## Styles
140
+
141
+ Install a component and the CLI writes `gbs.css` next to it, importing every
142
+ component stylesheet you actually installed. Add one line to your global CSS:
143
+
144
+ ```css
145
+ @import "./component-lib/gbs.css";
146
+ ```
147
+
148
+ That is all, for Tailwind v3, Bootstrap, and projects with no CSS framework.
149
+
150
+ **Tailwind v4** is the one exception, because it puts its own utilities in a
151
+ cascade layer. Import ours after the framework, inside Tailwind's components
152
+ layer, so utilities still win:
153
+
154
+ ```css
155
+ @import "tailwindcss";
156
+ @import "./component-lib/gbs.css" layer(components);
157
+ ```
158
+
159
+ The installer detects which of these you need and prints it. `gbs.css` is
160
+ rewritten on every install, so the list stays correct as you add components.
161
+
162
+ **Why it works this way.** Component CSS ships *unlayered*. An unlayered rule
163
+ beats every layered rule regardless of specificity, so a library that puts its
164
+ rules in a cascade layer loses to any unlayered reset — Tailwind v3's preflight
165
+ and Bootstrap's Reboot both qualify. Unlayered, our rules win on ordinary
166
+ specificity (a class beats `*`), and your own CSS and utilities still override
167
+ them the normal way. `layer(components)` on the import is native CSS, and is
168
+ the standard way to place third-party CSS under Tailwind v4.
169
+
170
+ If you forget it on v4, the failure is small and local: the component renders
171
+ correctly, but a utility passed through `className` will not override it.
172
+
173
+ ### Scrollbars
174
+
175
+ Every scrolling surface in the kit is thin by default, using the standard
176
+ `scrollbar-width` / `scrollbar-color` properties. Restyle them all from `:root`:
177
+
178
+ ```css
179
+ :root {
180
+ --gbs-scrollbar-width: auto; /* auto | thin | none */
181
+ --gbs-scrollbar-thumb: var(--gbs-accent); /* defaults to a muted accent */
182
+ --gbs-scrollbar-track: transparent;
183
+ }
184
+ ```
37
185
 
38
- - Agent skill: added guidance for projects that load an unlayered CSS reset
39
- such as Bootstrap or Normalize. Component rules live in the `components`
40
- cascade layer, and an unlayered reset outranks every layered rule whatever
41
- its selectors look like, so Bootstrap's Reboot was restyling the Button.
42
- Importing the reset into its own layer fixes it; the skill now says so.
186
+ Add `class="gbs-scroll"` to your own scrolling areas to match. Scroll containers
187
+ the kit does not own keep the browser default — it never restyles scrollbars it
188
+ was not asked to.
43
189
 
44
190
  ## Authors
45
191
 
package/index.cjs CHANGED
@@ -77,7 +77,7 @@ const CONFIG = {
77
77
  dependencies: {
78
78
  FormRenderer: ["Select", "MultiSelect", "Input", "DatePicker"],
79
79
  },
80
- docs: "https://gramprokit.vercel.app/",
80
+ docs: "https://kit.gramproindia.com/",
81
81
  };
82
82
 
83
83
  const { version: PACKAGE_VERSION } = require("./package.json");
@@ -131,6 +131,7 @@ const MANIFEST_FILE = ".install-manifest.json";
131
131
  * component-lib.
132
132
  */
133
133
  const TESTS_DIR = "__tests__";
134
+
134
135
  const isTestPath = (filePath) => filePath.split(/[\\/]/).includes(TESTS_DIR);
135
136
 
136
137
  const normalizeComponent = (component, availableComponents) =>
@@ -147,6 +148,109 @@ const getSourcePath = (beta = false) => (beta ? BETA_SOURCE_PATH : SOURCE_PATH);
147
148
  const folderFor = (component, beta = false) =>
148
149
  (beta && CONFIG.betaFolders[component]) || component.toLowerCase();
149
150
 
151
+
152
+ /*
153
+ * The stylesheet list, written for the project rather than left to it.
154
+ *
155
+ * Component CSS ships unlayered, which is what makes this boring: unlayered
156
+ * rules beat a framework reset on ordinary specificity, so Tailwind v3,
157
+ * Bootstrap and a project with no framework all need nothing beyond importing
158
+ * the file. Tailwind v4 is the exception, because it puts its own utilities in
159
+ * a cascade layer, and an unlayered rule would outrank them - so a v4 project
160
+ * imports this inside Tailwind's `components` layer, after the framework,
161
+ * which is the standard way to place third-party CSS.
162
+ */
163
+ const writeStyleBarrel = async (destPath, beta) => {
164
+ if (!beta) return null;
165
+
166
+ // Whatever is on disk now, not whatever this run happened to install: the
167
+ // barrel has to stay correct across repeated and partial installs.
168
+ const folders = fs
169
+ .readdirSync(destPath, { withFileTypes: true })
170
+ .filter((entry) => entry.isDirectory())
171
+ .map((entry) => entry.name)
172
+ .filter((folder) => fs.existsSync(path.join(destPath, folder, "styles.css")))
173
+ .sort();
174
+
175
+ const dir = path.basename(destPath);
176
+ const lines = [
177
+ "/*",
178
+ " * Generated by gbs-add-block. Rewritten on every install.",
179
+ " *",
180
+ " * Import this once in your global CSS. With Tailwind v4, import it after",
181
+ " * the framework and inside its components layer:",
182
+ " *",
183
+ ' * @import "tailwindcss";',
184
+ ' * @import "./' + dir + '/gbs.css" layer(components);',
185
+ " *",
186
+ " * With Tailwind v3, Bootstrap, or no framework, the plain import is all",
187
+ " * you need:",
188
+ " *",
189
+ ' * @import "./' + dir + '/gbs.css";',
190
+ " *",
191
+ " * A component with no styles.css is not listed, which is normal - not",
192
+ " * every component ships CSS.",
193
+ " */",
194
+ ...folders.map((folder) => '@import "./' + folder + '/styles.css";'),
195
+ "",
196
+ ];
197
+
198
+ await fs.writeFile(path.join(destPath, "gbs.css"), lines.join(NL));
199
+
200
+ // Read the project's own Tailwind major, so the printed line is the one they
201
+ // actually need rather than both of them with a decision attached.
202
+ let tailwindMajor = null;
203
+ try {
204
+ const pkg = readJson(path.join(process.cwd(), "package.json"));
205
+ const range =
206
+ (pkg && pkg.dependencies && pkg.dependencies.tailwindcss) ||
207
+ (pkg && pkg.devDependencies && pkg.devDependencies.tailwindcss) ||
208
+ null;
209
+ const found = range && String(range).match(/(\d+)/);
210
+ if (found) tailwindMajor = Number(found[1]);
211
+ } catch {
212
+ /* No package.json, or unreadable: fall through to showing both. */
213
+ }
214
+
215
+ return { count: folders.length, dir, tailwindMajor };
216
+ };
217
+
218
+ /** Printed after an install, so the one manual step is impossible to miss. */
219
+ const reportStyleBarrel = (barrel) => {
220
+ if (!barrel) return;
221
+ console.log(
222
+ NL + "Styles: wrote gbs.css, importing " + barrel.count + " stylesheet(s).",
223
+ );
224
+ console.log("Add this to your global CSS:");
225
+
226
+ if (barrel.tailwindMajor === null) {
227
+ console.log(NL + " @import \"./" + barrel.dir + "/gbs.css\";");
228
+ console.log(
229
+ NL + " With Tailwind v4, put it after the framework and in its layer:",
230
+ );
231
+ console.log(" @import \"tailwindcss\";");
232
+ console.log(
233
+ " @import \"./" + barrel.dir + "/gbs.css\" layer(components);",
234
+ );
235
+ return;
236
+ }
237
+
238
+ if (barrel.tailwindMajor >= 4) {
239
+ console.log(NL + " @import \"tailwindcss\";");
240
+ console.log(
241
+ " @import \"./" + barrel.dir + "/gbs.css\" layer(components);",
242
+ );
243
+ console.log(
244
+ NL + " (after the framework, and in its components layer - Tailwind v4" +
245
+ " layers its utilities)",
246
+ );
247
+ return;
248
+ }
249
+
250
+ console.log(NL + " @import \"./" + barrel.dir + "/gbs.css\";");
251
+ console.log(NL + " (Tailwind v" + barrel.tailwindMajor + ": nothing else to do)");
252
+ };
253
+
150
254
  const copyCommonFiles = async (destPath) => {
151
255
  const commonFiles = [
152
256
  { src: ["..", "utils.ts"], dest: "utils.ts" },
@@ -434,9 +538,10 @@ const writeAgentsPointer = async (root) => {
434
538
  const block = [
435
539
  BLOCK_START,
436
540
  "",
437
- "## GBS components",
541
+ "## GramproKit components",
438
542
  "",
439
- "This project uses the GBS headless component library. Before adding or",
543
+ "This project uses GramproKit components (gbs-add-block). They are copied",
544
+ "into the project with their styles, so you own them. Before adding or",
440
545
  "changing UI, read `" + skillPath + "` and follow it.",
441
546
  "",
442
547
  "It covers the import rule (components are copied into `component-lib/`, not",
@@ -600,6 +705,82 @@ const parseSkillTargets = (value) => {
600
705
  return wanted;
601
706
  };
602
707
 
708
+ /* ------------------------------------------------------------- passports */
709
+
710
+ /**
711
+ * Regenerate or verify passports for the components copied into this project.
712
+ *
713
+ * Reads the consumer's own source, so a modified component gets a passport that
714
+ * describes the modification. `passport.local.json` is read as an overlay and
715
+ * never written.
716
+ */
717
+ const runPassport = async ({ check: checkOnly }) => {
718
+ const dest = DEFAULT_DEST_PATH;
719
+
720
+ if (!fs.existsSync(dest)) {
721
+ console.error(
722
+ `No ${path.basename(dest)}/ folder here. Install a component first:` +
723
+ `${NL} npx gbs-add-block -a Button --beta`,
724
+ );
725
+ process.exit(1);
726
+ }
727
+
728
+ let passport;
729
+ try {
730
+ passport = require("./tools/passport/index.cjs");
731
+ } catch {
732
+ console.error(
733
+ "Passport tooling is not available in this installation of the CLI.",
734
+ );
735
+ process.exit(1);
736
+ }
737
+
738
+ const pkgPath = path.join(process.cwd(), "package.json");
739
+ const libraryVersion = fs.existsSync(pkgPath)
740
+ ? readJson(pkgPath, {}).version || "unknown"
741
+ : "unknown";
742
+
743
+ const options = {
744
+ libRoot: dest,
745
+ repoRoot: process.cwd(),
746
+ libraryVersion,
747
+ includeLocal: true,
748
+ coverageThreshold: undefined,
749
+ };
750
+
751
+ try {
752
+ if (checkOnly) {
753
+ const { report, errors, warnings } = passport.check(options);
754
+ for (const row of report) {
755
+ if (row.problems.length === 0) {
756
+ console.log(` ${row.component}: OK`);
757
+ continue;
758
+ }
759
+ for (const issue of row.problems) {
760
+ console.log(` ${issue.level === "error" ? "✗" : "!"} ${issue.component}: ${issue.message}`);
761
+ }
762
+ }
763
+ console.log(`${NL}${report.length} component(s) · ${errors} error(s) · ${warnings} warning(s)`);
764
+ if (errors > 0) process.exit(1);
765
+ return;
766
+ }
767
+
768
+ const { results, written } = passport.generate(options);
769
+ const errors = results.flatMap((r) => r.issues.filter((i) => i.level === "error"));
770
+ for (const issue of errors) console.error(` ✗ ${issue.component}: ${issue.message}`);
771
+ console.log(
772
+ `${NL}✓ ${results.length} passport(s) regenerated · ${written.length} changed`,
773
+ );
774
+ if (errors.length > 0) process.exit(1);
775
+ } catch (error) {
776
+ if (error.code === "ETYPESCRIPT_MISSING" || error.code === "EBADJSON") {
777
+ console.error(error.message);
778
+ process.exit(1);
779
+ }
780
+ throw error;
781
+ }
782
+ };
783
+
603
784
  /** `-a skill` is accepted as well as `--skill`, since both read naturally. */
604
785
  const isSkillWord = (value) =>
605
786
  typeof value === "string" && value.trim().toLowerCase() === "skill";
@@ -637,6 +818,9 @@ const copyComponent = async (component, destPath, beta = false) => {
637
818
  );
638
819
  }
639
820
 
821
+ // The whole folder travels, which includes passport.json and
822
+ // passport.manual.json. The passport is part of the component contract,
823
+ // not an add-on — a contract you opt into is not a contract.
640
824
  await fs.copy(componentSrc, componentDest, {
641
825
  overwrite: true,
642
826
  filter: (source) => !isTestPath(path.relative(componentSrc, source)),
@@ -689,6 +873,8 @@ const installComponentWithDependencies = async (
689
873
  });
690
874
  }
691
875
 
876
+ reportStyleBarrel(await writeStyleBarrel(destPath, beta));
877
+
692
878
  console.log(`\nFor documentation visit: ${CONFIG.docs}`);
693
879
  };
694
880
 
@@ -741,6 +927,8 @@ const installMultipleComponents = async (
741
927
  });
742
928
  }
743
929
 
930
+ reportStyleBarrel(await writeStyleBarrel(destPath, beta));
931
+
744
932
  console.log(`\nFor documentation visit: ${CONFIG.docs}`);
745
933
  };
746
934
 
@@ -869,6 +1057,7 @@ const main = async () => {
869
1057
  const args = hideBin(process.argv).map((arg) => {
870
1058
  if (arg === "-beta") return "--beta";
871
1059
  if (arg === "-skill") return "--skill";
1060
+ if (arg === "-passport") return "--passport";
872
1061
  return arg;
873
1062
  });
874
1063
  const argv = yargs(args)
@@ -904,6 +1093,17 @@ const main = async () => {
904
1093
  "With --skill: which agents to write adapters for (claude, codex, antigravity, or none)",
905
1094
  type: "string",
906
1095
  })
1096
+ .option("passport", {
1097
+ describe:
1098
+ "Regenerate component passports from the source in this project (needs a local typescript)",
1099
+ type: "boolean",
1100
+ default: false,
1101
+ })
1102
+ .option("check", {
1103
+ describe: "With --passport: verify passports match the source; writes nothing",
1104
+ type: "boolean",
1105
+ default: false,
1106
+ })
907
1107
  .option("force", {
908
1108
  describe: "Replace files you have edited locally in shared/ or the skill",
909
1109
  type: "boolean",
@@ -917,6 +1117,8 @@ const main = async () => {
917
1117
  .example("$0 -skill --for claude", "Only the Claude Code copy")
918
1118
  .example("$0 -skill --for none", "Only .gbs/, no adapters")
919
1119
  .example("$0 -a DataGrid -beta -skill", "Install a component and the skill")
1120
+ .example("$0 -passport", "Regenerate passports for your copied components")
1121
+ .example("$0 -passport --check", "Fail if a passport is stale (CI)")
920
1122
  .example("$0 -i", "Interactive selection mode")
921
1123
  .help().argv;
922
1124
 
@@ -965,6 +1167,13 @@ const main = async () => {
965
1167
  return;
966
1168
  }
967
1169
 
1170
+ // Passports are regenerated in place against the project's own copied
1171
+ // source, so a fork's passport describes the fork.
1172
+ if (argv.passport) {
1173
+ await runPassport({ check: argv.check });
1174
+ return;
1175
+ }
1176
+
968
1177
  // The skill goes to the project root, not component-lib, so it is handled
969
1178
  // before anything reaches the component installer.
970
1179
  if (argv.skill || isSkillWord(argv.add)) {
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "2.0.4",
4
- "description": "React Component Library",
3
+ "version": "2.3.0",
4
+ "description": "GramproKit — an agent-native UI runtime for React. Components you own, with a machine-readable contract.",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "index.cjs",
8
8
  "source",
9
- ".gbs"
9
+ ".gbs",
10
+ "tools",
11
+ "schema",
12
+ "!tools/eval",
13
+ "!source/**/__tests__",
14
+ "!**/*.test.ts",
15
+ "!**/*.test.tsx",
16
+ "CHANGELOG.md"
10
17
  ],
11
18
  "engines": {
12
19
  "node": ">=17"
@@ -15,23 +22,47 @@
15
22
  "gbs-add-block": "index.cjs"
16
23
  },
17
24
  "scripts": {
18
- "test": "echo \"Error: no test specified\" && exit 1"
25
+ "test": "pnpm -C demo-showroom test",
26
+ "passport": "node tools/passport/cli.cjs",
27
+ "passport:check": "node tools/passport/cli.cjs --check",
28
+ "eval:grid": "node tools/eval/grid/cli.cjs"
19
29
  },
20
- "keywords": [],
30
+ "keywords": [
31
+ "react",
32
+ "components",
33
+ "agent-native",
34
+ "ui-runtime",
35
+ "copy-in",
36
+ "data-grid",
37
+ "accessibility"
38
+ ],
21
39
  "author": "Anandhu Remanan",
22
40
  "license": "ISC",
23
41
  "dependencies": {
24
- "fs-extra": "^11.0.4",
25
- "path": "^0.12.7",
26
- "yargs": "^17.7.2",
27
42
  "@grampro/headless-helpers": "^1.0.21",
28
- "tailwind-merge": "^3.6.0"
43
+ "fs-extra": "^11.0.4",
44
+ "tailwind-merge": "^3.6.0",
45
+ "yargs": "^17.7.2"
29
46
  },
30
47
  "devDependencies": {
31
- "@types/fs-extra": "^11.0.4"
48
+ "@huggingface/transformers": "^4.3.1",
49
+ "@huggingface/transformers-structured-output": "^4.3.1",
50
+ "@types/fs-extra": "^11.0.4",
51
+ "typescript": "^6.0.3"
32
52
  },
33
53
  "peerDependencies": {
34
54
  "react": "^19.0.0",
35
55
  "react-dom": "^19.0.0"
56
+ },
57
+ "overrides": {
58
+ "dompurify": "^3.4.16"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/anandhuremanan/headless-gbs-components.git"
63
+ },
64
+ "homepage": "https://kit.gramproindia.com",
65
+ "bugs": {
66
+ "url": "https://github.com/anandhuremanan/headless-gbs-components/issues"
36
67
  }
37
68
  }