gbs-add-block 2.1.0 → 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.
- package/.gbs/skills/gbs-components/SKILL.md +190 -134
- package/.gbs/skills/gbs-components/references/install.md +25 -3
- package/.gbs/skills/gbs-components/references/styling.md +246 -207
- package/CHANGELOG.md +74 -0
- package/README.md +154 -23
- package/index.cjs +212 -3
- package/package.json +41 -10
- package/schema/passport-v1.schema.json +204 -0
- package/source/beta-components/accordion/passport.json +259 -0
- package/source/beta-components/accordion/styles.css +207 -208
- package/source/beta-components/alert/passport.json +250 -0
- package/source/beta-components/alert/styles.css +154 -155
- package/source/beta-components/avatar/passport.json +294 -0
- package/source/beta-components/avatar/styles.css +225 -226
- package/source/beta-components/badge/passport.json +332 -0
- package/source/beta-components/badge/styles.css +203 -204
- package/source/beta-components/breadcrumb/passport.json +243 -0
- package/source/beta-components/breadcrumb/styles.css +138 -140
- package/source/beta-components/button/passport.json +402 -0
- package/source/beta-components/button/passport.manual.json +31 -0
- package/source/beta-components/button/styles.css +232 -234
- package/source/beta-components/card/passport.json +337 -0
- package/source/beta-components/card/styles.css +230 -232
- package/source/beta-components/checkbox/passport.json +456 -0
- package/source/beta-components/checkbox/styles.css +211 -213
- package/source/beta-components/combobox/passport.json +456 -0
- package/source/beta-components/combobox/styles.css +419 -417
- package/source/beta-components/data-grid/agent/coerce.ts +368 -0
- package/source/beta-components/data-grid/agent/contract.ts +410 -0
- package/source/beta-components/data-grid/agent/dataset.ts +92 -0
- package/source/beta-components/data-grid/agent/engine.ts +470 -0
- package/source/beta-components/data-grid/agent/executors.ts +155 -0
- package/source/beta-components/data-grid/agent/index.ts +79 -0
- package/source/beta-components/data-grid/agent/intent.ts +324 -0
- package/source/beta-components/data-grid/agent/operations.ts +335 -0
- package/source/beta-components/data-grid/agent/validate.ts +630 -0
- package/source/beta-components/data-grid/agent/webmcp.ts +107 -0
- package/source/beta-components/data-grid/index.ts +14 -7
- package/source/beta-components/data-grid/passport.json +1051 -0
- package/source/beta-components/data-grid/passport.manual.json +255 -0
- package/source/beta-components/data-grid/react/AskGrid.tsx +164 -0
- package/source/beta-components/data-grid/react/DataGrid.tsx +39 -0
- package/source/beta-components/data-grid/styles.css +874 -716
- package/source/beta-components/date-picker/passport.json +407 -0
- package/source/beta-components/date-picker/styles.css +445 -446
- package/source/beta-components/dialog/passport.json +344 -0
- package/source/beta-components/dialog/styles.css +280 -279
- package/source/beta-components/file-uploader/passport.json +518 -0
- package/source/beta-components/file-uploader/styles.css +394 -396
- package/source/beta-components/input/passport.json +536 -0
- package/source/beta-components/input/styles.css +295 -297
- package/source/beta-components/menu/passport.json +322 -0
- package/source/beta-components/menu/styles.css +224 -223
- package/source/beta-components/modal/passport.json +289 -0
- package/source/beta-components/modal/styles.css +241 -240
- package/source/beta-components/number-input/passport.json +541 -0
- package/source/beta-components/number-input/styles.css +230 -231
- package/source/beta-components/popover/passport.json +238 -0
- package/source/beta-components/popover/styles.css +148 -147
- package/source/beta-components/progress/passport.json +270 -0
- package/source/beta-components/progress/styles.css +200 -201
- package/source/beta-components/radio-group/passport.json +477 -0
- package/source/beta-components/radio-group/styles.css +269 -270
- package/source/beta-components/shared/core/agent/adapter.ts +65 -0
- package/source/beta-components/shared/core/agent/history.ts +120 -0
- package/source/beta-components/shared/core/agent/index.ts +46 -0
- package/source/beta-components/shared/core/agent/numbers.ts +217 -0
- package/source/beta-components/shared/core/agent/schema.ts +180 -0
- package/source/beta-components/shared/core/agent/types.ts +169 -0
- package/source/beta-components/shared/core/agent/webmcp.ts +328 -0
- package/source/beta-components/shared/index.ts +9 -0
- package/source/beta-components/shared/react/GramproAIProvider.tsx +50 -0
- package/source/beta-components/shared/react/useAskAgent.ts +217 -0
- package/source/beta-components/shared/styles.css +79 -0
- package/source/beta-components/shared/version.json +4 -4
- package/source/beta-components/shared/version.ts +6 -6
- package/source/beta-components/skeleton/passport.json +251 -0
- package/source/beta-components/skeleton/styles.css +185 -187
- package/source/beta-components/spinner/passport.json +245 -0
- package/source/beta-components/spinner/styles.css +173 -174
- package/source/beta-components/switch/passport.json +421 -0
- package/source/beta-components/switch/styles.css +227 -229
- package/source/beta-components/tabs/passport.json +315 -0
- package/source/beta-components/tabs/styles.css +263 -264
- package/source/beta-components/textarea/passport.json +382 -0
- package/source/beta-components/textarea/styles.css +158 -160
- package/source/beta-components/toaster/passport.json +221 -0
- package/source/beta-components/toaster/styles.css +282 -282
- package/source/beta-components/tooltip/passport.json +170 -0
- package/source/beta-components/tooltip/styles.css +71 -73
- package/tools/env.cjs +61 -0
- package/tools/passport/cli.cjs +79 -0
- package/tools/passport/extract.cjs +493 -0
- package/tools/passport/index.cjs +185 -0
- package/tools/passport/merge.cjs +131 -0
- package/tools/passport/policy.cjs +65 -0
- package/tools/passport/validate.cjs +277 -0
- package/tools/ts-require.cjs +79 -0
- package/source/beta-components/accordion/__tests__/core.test.ts +0 -58
- package/source/beta-components/alert/__tests__/core.test.ts +0 -17
- package/source/beta-components/avatar/__tests__/core.test.ts +0 -88
- package/source/beta-components/badge/__tests__/core.test.ts +0 -46
- package/source/beta-components/breadcrumb/__tests__/core.test.ts +0 -58
- package/source/beta-components/button/__tests__/core.test.ts +0 -31
- package/source/beta-components/card/__tests__/core.test.ts +0 -57
- package/source/beta-components/checkbox/__tests__/core.test.ts +0 -40
- package/source/beta-components/combobox/__tests__/core.test.ts +0 -134
- package/source/beta-components/data-grid/__tests__/core.test.ts +0 -356
- package/source/beta-components/data-grid/__tests__/export.test.ts +0 -70
- package/source/beta-components/data-grid/__tests__/pdf.test.ts +0 -209
- package/source/beta-components/date-picker/__tests__/core.test.ts +0 -273
- package/source/beta-components/dialog/__tests__/core.test.ts +0 -86
- package/source/beta-components/file-uploader/__tests__/core.test.ts +0 -395
- package/source/beta-components/input/__tests__/core.test.ts +0 -75
- package/source/beta-components/menu/__tests__/core.test.ts +0 -120
- package/source/beta-components/modal/__tests__/core.test.ts +0 -55
- package/source/beta-components/number-input/__tests__/core.test.ts +0 -151
- package/source/beta-components/progress/__tests__/core.test.ts +0 -56
- package/source/beta-components/radio-group/__tests__/core.test.ts +0 -64
- package/source/beta-components/shared/__tests__/boundaries.test.ts +0 -95
- package/source/beta-components/shared/__tests__/core.test.ts +0 -55
- package/source/beta-components/shared/__tests__/position.test.ts +0 -143
- package/source/beta-components/skeleton/__tests__/core.test.ts +0 -41
- package/source/beta-components/spinner/__tests__/core.test.ts +0 -48
- package/source/beta-components/switch/__tests__/core.test.ts +0 -64
- package/source/beta-components/tabs/__tests__/core.test.ts +0 -51
- package/source/beta-components/textarea/__tests__/core.test.ts +0 -38
- package/source/beta-components/toaster/__tests__/core.test.ts +0 -256
- package/source/beta-components/tooltip/__tests__/core.test.ts +0 -42
package/README.md
CHANGED
|
@@ -1,14 +1,92 @@
|
|
|
1
|
-
#
|
|
1
|
+
# GramproKit
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
79
|
+
[kit.gramproindia.com](https://kit.gramproindia.com) — usage and props per
|
|
80
|
+
component.
|
|
8
81
|
|
|
9
|
-
|
|
82
|
+
In this repository:
|
|
10
83
|
|
|
11
|
-
|
|
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,28 +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
|
-
##
|
|
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
|
+
```
|
|
37
158
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
longer declare a global layer order.
|
|
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.
|
|
41
161
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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.
|
|
47
169
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
```
|
|
56
185
|
|
|
57
|
-
|
|
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.
|
|
58
189
|
|
|
59
190
|
## Authors
|
|
60
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://
|
|
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
|
-
"##
|
|
541
|
+
"## GramproKit components",
|
|
438
542
|
"",
|
|
439
|
-
"This project uses
|
|
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.
|
|
4
|
-
"description": "React
|
|
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": "
|
|
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
|
-
"
|
|
43
|
+
"fs-extra": "^11.0.4",
|
|
44
|
+
"tailwind-merge": "^3.6.0",
|
|
45
|
+
"yargs": "^17.7.2"
|
|
29
46
|
},
|
|
30
47
|
"devDependencies": {
|
|
31
|
-
"@
|
|
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
|
}
|