@kondeio/kdf 0.1.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/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +57 -0
- package/LICENSE +21 -0
- package/README.md +374 -0
- package/SECURITY.md +53 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +58 -0
- package/dist/css-generator.d.ts +17 -0
- package/dist/css-generator.js +59 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +62 -0
- package/dist/plugin.d.ts +30 -0
- package/dist/plugin.js +40 -0
- package/dist/postinstall.d.ts +1 -0
- package/dist/postinstall.js +48 -0
- package/dist/resolver.d.ts +11 -0
- package/dist/resolver.js +184 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +1 -0
- package/docs/kdf-doc.md +653 -0
- package/docs/kdf-skill.md +374 -0
- package/example/bootstrap/globals.css +12 -0
- package/example/bootstrap/hero-section.tsx +38 -0
- package/example/bootstrap/kdf/homepage.json +35 -0
- package/example/bootstrap/kdf/shared/button.json +10 -0
- package/example/bootstrap/kdf/shared/card.json +4 -0
- package/example/bootstrap/kdf/shared/color.json +17 -0
- package/example/bootstrap/kdf/shared/layout.json +7 -0
- package/example/bootstrap/kdf/shared/typography.json +8 -0
- package/example/bootstrap/konde-server.css +3 -0
- package/example/bootstrap/konde.css +3 -0
- package/example/preview.ts +428 -0
- package/example/pure-css/hero-section.tsx +40 -0
- package/example/pure-css/kdf/homepage.json +20 -0
- package/example/pure-css/kdf/shared/button.json +10 -0
- package/example/pure-css/kdf/shared/card.json +4 -0
- package/example/pure-css/kdf/shared/color.json +11 -0
- package/example/pure-css/kdf/shared/typography.json +8 -0
- package/example/pure-css/konde-server.css +3 -0
- package/example/pure-css/konde.css +3 -0
- package/example/pure-css/styles.css +34 -0
- package/example/sample-pages/about.json +30 -0
- package/example/sample-pages/dashboard.json +12 -0
- package/example/sample-pages/pricing.json +28 -0
- package/example/shadcn/globals.css +15 -0
- package/example/shadcn/hero-section.tsx +34 -0
- package/example/shadcn/konde-server.css +3 -0
- package/example/shadcn/konde.css +3 -0
- package/example/tailwind/globals.css +5 -0
- package/example/tailwind/hero-section.tsx +34 -0
- package/example/tailwind/konde-server.css +3 -0
- package/example/tailwind/konde.css +3 -0
- package/kdf/homepage.json +25 -0
- package/kdf/shared/button.json +10 -0
- package/kdf/shared/card.json +4 -0
- package/kdf/shared/color.json +17 -0
- package/kdf/shared/layout.json +7 -0
- package/kdf/shared/typography.json +8 -0
- package/package.json +77 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to KDF are documented here. Format loosely follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com); versions follow semver.
|
|
5
|
+
|
|
6
|
+
## [0.1.0] - 2026-06-18
|
|
7
|
+
|
|
8
|
+
Initial public release candidate.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Class composition is now UI-library agnostic.** `cn()` / `cx()` /
|
|
12
|
+
`composeClasses()` normalize and dedupe exact duplicate classes by default,
|
|
13
|
+
while `createClassComposer({ merge })` allows app-defined semantic merge
|
|
14
|
+
rules without adding framework-specific runtime dependencies to KDF.
|
|
15
|
+
- Package scope renamed `@konde/kdf` → `@kondeio/kdf`.
|
|
16
|
+
- `package.json` description clarified: KDF is a Node/server-side package with
|
|
17
|
+
an optional Next.js plugin and UI-library agnostic class composition.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- `dedupeClasses()`, `composeClasses()`, `cx()`, and
|
|
21
|
+
`createClassComposer({ merge })`.
|
|
22
|
+
- Documented the **server-only** constraint (resolver uses Node `fs`) across
|
|
23
|
+
README, `docs/kdf-doc.md`, and `docs/kdf-skill.md`, with the
|
|
24
|
+
resolve-on-server / pass-className-as-prop pattern.
|
|
25
|
+
- `CONTRIBUTING.md`, `SECURITY.md`, `CHANGELOG.md`.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- `@ref` component names are validated against `^[A-Za-z0-9_-]+$` — path-traversal
|
|
29
|
+
references (`..`, separators) are rejected instead of resolving to arbitrary
|
|
30
|
+
`.json` files.
|
|
31
|
+
- Corrected the plugin "auto-inject CSS" claim: `withKDF()` only exposes paths
|
|
32
|
+
via env (`KDF_DIR`, `KDF_SERVER_CSS`, `KDF_CLIENT_CSS`); the host app wires the
|
|
33
|
+
stylesheet.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Contributing to KDF
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving the Konde Design Framework.
|
|
4
|
+
|
|
5
|
+
## Local setup
|
|
6
|
+
|
|
7
|
+
KDF builds with [Bun](https://bun.sh) (Node 18+ also works for running `dist`).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/KondeIO/kdf.git
|
|
11
|
+
cd kdf
|
|
12
|
+
bun install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Build & verify
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun run build # tsc -> dist/
|
|
19
|
+
bun run typecheck # tsc --noEmit
|
|
20
|
+
bun run test # unit tests
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A change is ready for review when `typecheck` and `test` pass and `dist/` has
|
|
24
|
+
been rebuilt (the published artifact lives in `dist/`).
|
|
25
|
+
|
|
26
|
+
## Project layout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
src/ TypeScript source (authoritative)
|
|
30
|
+
dist/ Build output (tsc) — published to npm
|
|
31
|
+
kdf/ Starter design tokens shipped to consumers
|
|
32
|
+
example/ Reference usage
|
|
33
|
+
docs/ Concept, agent skill, and license docs
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Pull requests
|
|
37
|
+
|
|
38
|
+
- Branch off `main`; keep PRs focused on one change.
|
|
39
|
+
- Keep the core **UI-library agnostic** — do not add framework-specific runtime
|
|
40
|
+
dependencies. Class conflict rules belong in app-level
|
|
41
|
+
`createClassComposer({ merge })` integrations.
|
|
42
|
+
- The resolver is **server-only** (Node `fs`). Do not introduce browser/DOM
|
|
43
|
+
assumptions into `src/resolver.ts`.
|
|
44
|
+
- Update `CHANGELOG.md` under `## Unreleased`.
|
|
45
|
+
- Run `bun run build` before committing so `src` and `dist` stay in sync.
|
|
46
|
+
|
|
47
|
+
## Conventions
|
|
48
|
+
|
|
49
|
+
- ESM only; internal imports use explicit `.js` extensions (`./resolver.js`).
|
|
50
|
+
- Match the existing code style (no new formatter configs in a PR).
|
|
51
|
+
- Add or update docs in `docs/` when behavior changes.
|
|
52
|
+
|
|
53
|
+
## Reporting bugs
|
|
54
|
+
|
|
55
|
+
Open an issue at https://github.com/KondeIO/kdf/issues with a minimal repro.
|
|
56
|
+
For security issues, see [SECURITY.md](./SECURITY.md) — do **not** open a public
|
|
57
|
+
issue.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 konde.io
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# @kondeio/kdf - Konde Design Framework
|
|
2
|
+
|
|
3
|
+
Agent-first design consistency for Node-powered web apps.
|
|
4
|
+
|
|
5
|
+
KDF gives AI agents a JSON source of truth for layout, spacing, typography, and
|
|
6
|
+
component styling. Agents can build or update UI from that source in
|
|
7
|
+
server-side JavaScript apps instead of rediscovering design rules across
|
|
8
|
+
components, pages, and previous sessions.
|
|
9
|
+
|
|
10
|
+
Think of it like i18n for design: one page maps to one JSON file, and each
|
|
11
|
+
rendered element can point back to its exact design key with `data-kdf`. Users
|
|
12
|
+
stay in the approval loop and adjust the source only when intent or product
|
|
13
|
+
direction changes.
|
|
14
|
+
|
|
15
|
+
## Why
|
|
16
|
+
|
|
17
|
+
Styling drifts when class names live only inside `.tsx` files:
|
|
18
|
+
|
|
19
|
+
- the same button slowly gets five different variants
|
|
20
|
+
- spacing changes page by page
|
|
21
|
+
- colors and typography become inconsistent
|
|
22
|
+
- each new AI session has to rediscover the design rules
|
|
23
|
+
- users spend time correcting visual drift through chat
|
|
24
|
+
|
|
25
|
+
KDF moves repeatable styling into JSON:
|
|
26
|
+
|
|
27
|
+
- agents apply tokens before changing UI
|
|
28
|
+
- users can review and adjust the source when needed
|
|
29
|
+
- `data-kdf` maps every DOM element back to its exact JSON path
|
|
30
|
+
- the same design key can be scanned, tested, reviewed, and edited later
|
|
31
|
+
|
|
32
|
+
KDF works with your existing styling stack: plain CSS, CSS modules, utility CSS,
|
|
33
|
+
Bootstrap, shadcn, or a custom design system. It is not a component library and
|
|
34
|
+
not a CSS engine.
|
|
35
|
+
|
|
36
|
+
## Runtime Support
|
|
37
|
+
|
|
38
|
+
KDF core runs in Node/server-side JavaScript environments because it reads JSON
|
|
39
|
+
from disk with Node `fs`.
|
|
40
|
+
|
|
41
|
+
- Works with server-rendered Next.js, Astro, Hono, or similar Node runtimes.
|
|
42
|
+
- The included `@kondeio/kdf/plugin` export is the official Next.js integration.
|
|
43
|
+
- Next.js plugin target: App Router, Next.js 14+ (`next >=14`).
|
|
44
|
+
- `getDesign()`, `d()`, and `d.css()` are server-only. Browser/client
|
|
45
|
+
components cannot call them directly; resolve classes server-side and pass
|
|
46
|
+
class names down when needed.
|
|
47
|
+
|
|
48
|
+
| Framework | Status | How KDF is used |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| Next.js | Tested | Core API in server-rendered code, plus the official `@kondeio/kdf/plugin` integration. |
|
|
51
|
+
| Astro | Tested | Core API in server-rendered code. |
|
|
52
|
+
| Hono | Tested | Core API in server handlers. |
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
Install the package:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install @kondeio/kdf
|
|
60
|
+
pnpm add @kondeio/kdf
|
|
61
|
+
bun add @kondeio/kdf
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
By default, install also scaffolds a starter `kdf/` folder when one does not
|
|
65
|
+
already exist. Existing files are never overwritten.
|
|
66
|
+
|
|
67
|
+
To install the dependency without running the initializer:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install @kondeio/kdf --ignore-scripts
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run initialization manually later:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx kdf init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`npx kdf init` uses the local package binary when `@kondeio/kdf` is already
|
|
80
|
+
installed in the project.
|
|
81
|
+
|
|
82
|
+
Initialize a custom design directory:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
KDF_DIR=./designs npx kdf init
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## File Structure
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
kdf/
|
|
92
|
+
shared/ <- shared defaults (button, typography, layout, card)
|
|
93
|
+
homepage.json <- starter page design
|
|
94
|
+
konde-server.css <- critical project overrides
|
|
95
|
+
konde.css <- non-critical project overrides
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The package repository also keeps additional page JSON examples under
|
|
99
|
+
`example/sample-pages/`. They are reference material only and are not copied by
|
|
100
|
+
`postinstall` or `kdf init`.
|
|
101
|
+
|
|
102
|
+
Typical app structure:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
my-app/
|
|
106
|
+
app/
|
|
107
|
+
page.tsx
|
|
108
|
+
pricing/page.tsx
|
|
109
|
+
components/
|
|
110
|
+
hero.tsx
|
|
111
|
+
pricing-table.tsx
|
|
112
|
+
kdf/
|
|
113
|
+
shared/
|
|
114
|
+
button.json
|
|
115
|
+
card.json
|
|
116
|
+
color.json
|
|
117
|
+
layout.json
|
|
118
|
+
typography.json
|
|
119
|
+
homepage.json
|
|
120
|
+
konde-server.css
|
|
121
|
+
konde.css
|
|
122
|
+
next.config.ts
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Custom Design Directory
|
|
126
|
+
|
|
127
|
+
The default design directory is `./kdf`.
|
|
128
|
+
|
|
129
|
+
Use `./designs` or `./design` through `KDF_DIR` in any Node/server-side runtime:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
KDF_DIR=./designs npm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { getDesign } from "@kondeio/kdf";
|
|
137
|
+
|
|
138
|
+
const d = getDesign("homepage");
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
In Next.js, the optional plugin sets `KDF_DIR` for the app:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
// next.config.ts
|
|
145
|
+
import withKDF from "@kondeio/kdf/plugin";
|
|
146
|
+
|
|
147
|
+
export default withKDF({ dir: "./designs" })(nextConfig);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
With that config, KDF reads:
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
designs/
|
|
154
|
+
shared/
|
|
155
|
+
homepage.json
|
|
156
|
+
konde-server.css
|
|
157
|
+
konde.css
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Example token:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"$layout": ["hero", "features", "footer"],
|
|
165
|
+
"hero": {
|
|
166
|
+
"wrapper": "mx-auto max-w-6xl px-6 py-20",
|
|
167
|
+
"title": "@typography.h1",
|
|
168
|
+
"cta": "@button.cta"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Usage
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { getDesign } from "@kondeio/kdf";
|
|
177
|
+
|
|
178
|
+
const d = getDesign("homepage");
|
|
179
|
+
|
|
180
|
+
<h1 data-kdf="hero.title" className={d("hero.title")}>
|
|
181
|
+
{t("hero.headline")}
|
|
182
|
+
</h1>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Class Composition
|
|
186
|
+
|
|
187
|
+
KDF includes small class composition helpers that work with any UI library:
|
|
188
|
+
|
|
189
|
+
| Helper | Purpose |
|
|
190
|
+
| --- | --- |
|
|
191
|
+
| `cn()` | Joins conditional classes, drops falsy values, normalizes whitespace, and removes exact duplicates. |
|
|
192
|
+
| `cx()` | Alias of `cn()`. |
|
|
193
|
+
| `composeClasses()` | Same default composer with a more explicit name. |
|
|
194
|
+
| `dedupeClasses()` | Removes exact duplicates from an existing class string. |
|
|
195
|
+
| `createClassComposer({ merge })` | Creates a composer with an app-defined merge step. |
|
|
196
|
+
|
|
197
|
+
The default behavior is intentionally universal. It normalizes whitespace and
|
|
198
|
+
dedupes exact class names, but does not interpret semantic conflicts such as
|
|
199
|
+
color, spacing, variant, or framework-specific utility groups.
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import { cn, getDesign } from "@kondeio/kdf";
|
|
203
|
+
|
|
204
|
+
const d = getDesign("homepage");
|
|
205
|
+
|
|
206
|
+
<button
|
|
207
|
+
data-kdf="hero.cta"
|
|
208
|
+
className={cn(d("hero.cta"), isActive && d("hero.cta-active"), className)}
|
|
209
|
+
>
|
|
210
|
+
Start
|
|
211
|
+
</button>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Remove exact duplicates:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { dedupeClasses } from "@kondeio/kdf";
|
|
218
|
+
|
|
219
|
+
dedupeClasses("btn btn btn-primary");
|
|
220
|
+
// "btn btn-primary"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Add project-specific merge rules:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { createClassComposer } from "@kondeio/kdf";
|
|
227
|
+
|
|
228
|
+
const cn = createClassComposer({
|
|
229
|
+
merge(className) {
|
|
230
|
+
// Example: apply project-specific class rules here.
|
|
231
|
+
return className;
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Server-only
|
|
237
|
+
|
|
238
|
+
`getDesign()`, `d()`, and `d.css()` read JSON from disk via Node `fs`, so they
|
|
239
|
+
run on the **server only**: Next.js Server Components, Astro server rendering,
|
|
240
|
+
Hono handlers, or equivalent Node/server-rendered code. They do **not** work
|
|
241
|
+
inside browser-only code or a Next.js Client Component (`"use client"`), which
|
|
242
|
+
has no filesystem.
|
|
243
|
+
|
|
244
|
+
For client components, resolve on the server and pass the resulting className
|
|
245
|
+
string down as a prop:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
// Server Component
|
|
249
|
+
const d = getDesign("homepage");
|
|
250
|
+
return <ClientThing className={d("hero.cta")} />;
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## References
|
|
254
|
+
|
|
255
|
+
Reference shared tokens from shared/:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{ "hero": { "cta": "@button.cta" } }
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Extend with extra classes:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{ "hero": { "cta": "@button.cta shadow-xl text-lg" } }
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Multiple refs:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{ "hero": { "login": "@button.base @button.ghost @button.sm" } }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## `data-kdf`
|
|
274
|
+
|
|
275
|
+
Every element using `d()` should have matching `data-kdf`:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
<div data-kdf="hero.wrapper" className={d("hero.wrapper")}>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
This makes the rendered UI traceable for agent scanning, visual editing, and
|
|
282
|
+
Playwright checks.
|
|
283
|
+
|
|
284
|
+
## Cache Behavior
|
|
285
|
+
|
|
286
|
+
KDF caches design JSON files by default. In development it revalidates with
|
|
287
|
+
file `mtime`/`size` checks so repeated `d()` calls do not create disk-read
|
|
288
|
+
storms during HMR.
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
const d = getDesign("homepage", { cache: "auto", maxAgeMs: 250 });
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Use `clearKdfCache()` for explicit invalidation in custom tooling.
|
|
295
|
+
|
|
296
|
+
## CSS Custom Properties
|
|
297
|
+
|
|
298
|
+
For values not expressible as reusable classes:
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"hero": {
|
|
303
|
+
"title": {
|
|
304
|
+
"className": "text-3xl",
|
|
305
|
+
"css": { "--kdf-accent": "oklch(0.546 0.245 262)" }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Generated CSS can live in `konde.css`. The plugin exposes its path via env
|
|
312
|
+
(`KDF_CLIENT_CSS`); wire the `<link>`/import in your app (e.g. last in
|
|
313
|
+
`globals.css`) — the plugin does not inject it for you.
|
|
314
|
+
|
|
315
|
+
## Commands
|
|
316
|
+
|
|
317
|
+
- `kdf init` - scaffold the starter `kdf/` folder and generated CSS files.
|
|
318
|
+
- `bun example/preview.ts [tailwind|shadcn|bootstrap|pure-css]` - run the local
|
|
319
|
+
KDF example preview. Use `PORT=4410` to avoid port conflicts and
|
|
320
|
+
`KDF_PREVIEW_OPEN=0` for test/CI runs without opening a browser.
|
|
321
|
+
|
|
322
|
+
## Next.js Config
|
|
323
|
+
|
|
324
|
+
Default KDF directory (`./kdf`):
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
// next.config.ts
|
|
328
|
+
import withKDF from "@kondeio/kdf/plugin";
|
|
329
|
+
|
|
330
|
+
export default withKDF()(nextConfig);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Custom KDF directory (`./my-design`):
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
// next.config.ts
|
|
337
|
+
import withKDF from "@kondeio/kdf/plugin";
|
|
338
|
+
|
|
339
|
+
export default withKDF({ dir: "./my-design" })(nextConfig);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Key Symbols
|
|
343
|
+
|
|
344
|
+
| Symbol | Purpose | Example |
|
|
345
|
+
| --- | --- | --- |
|
|
346
|
+
| `$` | Component binding | `"$": "Button"` |
|
|
347
|
+
| `@` | Shared style reference | `"@button.cta"` |
|
|
348
|
+
| `$layout` | Page section order | `["hero", "footer"]` |
|
|
349
|
+
|
|
350
|
+
## Documentation and Skills
|
|
351
|
+
|
|
352
|
+
- [`docs/kdf-doc.md`](./docs/kdf-doc.md) - KDF concept, architecture, conventions, and operating model.
|
|
353
|
+
- [`docs/kdf-skill.md`](./docs/kdf-skill.md) - agent-facing implementation and review checklist.
|
|
354
|
+
|
|
355
|
+
## Contributing
|
|
356
|
+
|
|
357
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for local setup, build/test commands,
|
|
358
|
+
and PR conventions. Keep the core UI-library agnostic and the resolver
|
|
359
|
+
server-only.
|
|
360
|
+
|
|
361
|
+
## Security
|
|
362
|
+
|
|
363
|
+
`@kondeio/kdf` runs a `postinstall` script that scaffolds a starter `kdf/`
|
|
364
|
+
folder into your project (never overwrites, no network calls). To skip it:
|
|
365
|
+
`npm install @kondeio/kdf --ignore-scripts` or `KDF_SKIP_INIT=1`. Full details
|
|
366
|
+
and vulnerability reporting in [SECURITY.md](./SECURITY.md).
|
|
367
|
+
|
|
368
|
+
## Changelog
|
|
369
|
+
|
|
370
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
371
|
+
|
|
372
|
+
## License
|
|
373
|
+
|
|
374
|
+
MIT. See [`LICENSE`](./LICENSE) for the full license text.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please report security issues **privately** — do not open a public GitHub issue.
|
|
6
|
+
|
|
7
|
+
Email: **security@konde.io** (or open a private security advisory on the
|
|
8
|
+
GitHub repository).
|
|
9
|
+
|
|
10
|
+
Include a description, affected version, and a minimal reproduction if possible.
|
|
11
|
+
We aim to acknowledge reports within a few business days.
|
|
12
|
+
|
|
13
|
+
## Install-time behavior (`postinstall`)
|
|
14
|
+
|
|
15
|
+
KDF runs a `postinstall` script that **scaffolds a starter `kdf/` folder** into
|
|
16
|
+
the consuming project so the package works out of the box. You should know
|
|
17
|
+
exactly what it does:
|
|
18
|
+
|
|
19
|
+
- **What it writes:** a `kdf/` folder at the project root (`INIT_CWD`) containing
|
|
20
|
+
starter design JSON (`shared/*.json`, `homepage.json`) and generated CSS files
|
|
21
|
+
(`konde-server.css`, `konde.css`).
|
|
22
|
+
- **What it never does:** it never overwrites an existing `kdf/` folder, never
|
|
23
|
+
touches files outside `kdf/`, makes no network calls, and reads/writes no
|
|
24
|
+
secrets or credentials.
|
|
25
|
+
- **When it is skipped:** it does nothing if `kdf/` already exists.
|
|
26
|
+
|
|
27
|
+
### Opting out
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Skip all install scripts (npm):
|
|
31
|
+
npm install @kondeio/kdf --ignore-scripts
|
|
32
|
+
|
|
33
|
+
# Or disable just KDF scaffolding:
|
|
34
|
+
KDF_SKIP_INIT=1 npm install @kondeio/kdf
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
You can scaffold manually later with:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx kdf init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Reference resolution safety
|
|
44
|
+
|
|
45
|
+
`@ref` component names (e.g. `@button.cta` → `shared/button.json`) are validated
|
|
46
|
+
against `^[A-Za-z0-9_-]+$`. References containing path separators or `..` are
|
|
47
|
+
rejected, so a ref cannot read files outside the `shared/` folder. Design JSON is
|
|
48
|
+
authored by developers (trusted input); this is defense-in-depth.
|
|
49
|
+
|
|
50
|
+
## Supported versions
|
|
51
|
+
|
|
52
|
+
KDF is pre-1.0 (`0.x`). Security fixes target the latest published `0.x`
|
|
53
|
+
release.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdirSync, existsSync, copyFileSync, readdirSync } from "fs";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { writeKondeCSS } from "./css-generator.js";
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const TEMPLATES_DIR = join(__dirname, "..", "kdf");
|
|
8
|
+
const commands = {
|
|
9
|
+
init: cmdInit,
|
|
10
|
+
};
|
|
11
|
+
function cmdInit() {
|
|
12
|
+
const targetDir = join(process.cwd(), process.env.KDF_DIR || "kdf");
|
|
13
|
+
if (existsSync(targetDir)) {
|
|
14
|
+
console.log("kdf/ directory already exists. Skipping init.");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Create kdf/ and kdf/shared/
|
|
18
|
+
mkdirSync(join(targetDir, "shared"), { recursive: true });
|
|
19
|
+
// Copy shared token files
|
|
20
|
+
const sharedDir = join(TEMPLATES_DIR, "shared");
|
|
21
|
+
if (existsSync(sharedDir)) {
|
|
22
|
+
for (const file of readdirSync(sharedDir).filter((f) => f.endsWith(".json"))) {
|
|
23
|
+
copyFileSync(join(sharedDir, file), join(targetDir, "shared", file));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Copy homepage.json as starter
|
|
27
|
+
const homepageSrc = join(TEMPLATES_DIR, "homepage.json");
|
|
28
|
+
if (existsSync(homepageSrc)) {
|
|
29
|
+
copyFileSync(homepageSrc, join(targetDir, "homepage.json"));
|
|
30
|
+
}
|
|
31
|
+
// Generate empty CSS files inside kdf/ folder
|
|
32
|
+
writeKondeCSS(targetDir);
|
|
33
|
+
console.log("Initialized:");
|
|
34
|
+
console.log("");
|
|
35
|
+
console.log(" kdf/");
|
|
36
|
+
console.log(" shared/");
|
|
37
|
+
console.log(" button.json");
|
|
38
|
+
console.log(" card.json");
|
|
39
|
+
console.log(" color.json");
|
|
40
|
+
console.log(" layout.json");
|
|
41
|
+
console.log(" typography.json");
|
|
42
|
+
console.log(" homepage.json");
|
|
43
|
+
console.log(" konde-server.css (critical overrides — import in layout.tsx)");
|
|
44
|
+
console.log(" konde.css (non-critical overrides — <link> last in <head>)");
|
|
45
|
+
}
|
|
46
|
+
// --- Main ---
|
|
47
|
+
const command = process.argv[2];
|
|
48
|
+
if (!command || !commands[command]) {
|
|
49
|
+
console.log("@kondeio/kdf - Design-as-JSON for agent-assisted UI");
|
|
50
|
+
console.log("");
|
|
51
|
+
console.log("Commands:");
|
|
52
|
+
console.log(" init Scaffold kdf/ folder + konde.css");
|
|
53
|
+
console.log("");
|
|
54
|
+
console.log("Usage:");
|
|
55
|
+
console.log(" npx @kondeio/kdf init");
|
|
56
|
+
process.exit(command ? 1 : 0);
|
|
57
|
+
}
|
|
58
|
+
commands[command]();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate empty konde-server.css scaffold.
|
|
3
|
+
* Server-side loaded (import in layout.tsx) — inlined in HTML, no FOUC.
|
|
4
|
+
* For critical overrides that must be present on first paint.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateKondeServerCSS(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Generate empty konde.css scaffold.
|
|
9
|
+
* Client-side loaded (<link> last in <head>) — highest specificity.
|
|
10
|
+
* For non-critical overrides, experiments, CSS hacks.
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateKondeCSS(): string;
|
|
13
|
+
/**
|
|
14
|
+
* Write CSS files to disk — only if file doesn't exist.
|
|
15
|
+
* Safe to call multiple times; never overwrites user edits.
|
|
16
|
+
*/
|
|
17
|
+
export declare function writeKondeCSS(outputDir?: string): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { writeFileSync, existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Generate empty konde-server.css scaffold.
|
|
5
|
+
* Server-side loaded (import in layout.tsx) — inlined in HTML, no FOUC.
|
|
6
|
+
* For critical overrides that must be present on first paint.
|
|
7
|
+
*/
|
|
8
|
+
export function generateKondeServerCSS() {
|
|
9
|
+
return `/* konde-server.css — Critical design overrides (server-rendered) */
|
|
10
|
+
/* Imported in layout.tsx — inlined in HTML, no FOUC */
|
|
11
|
+
/* Edit freely — KDF will never overwrite this file */
|
|
12
|
+
|
|
13
|
+
/* Use for:
|
|
14
|
+
- Critical layout fixes that cause visual shift
|
|
15
|
+
- CSS custom properties needed on first paint
|
|
16
|
+
- Override shared component visibility per page
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
:root { --kdf-primary: #4F46E5; }
|
|
20
|
+
[data-kdf="hero.slider"] { display: none; }
|
|
21
|
+
*/
|
|
22
|
+
`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate empty konde.css scaffold.
|
|
26
|
+
* Client-side loaded (<link> last in <head>) — highest specificity.
|
|
27
|
+
* For non-critical overrides, experiments, CSS hacks.
|
|
28
|
+
*/
|
|
29
|
+
export function generateKondeCSS() {
|
|
30
|
+
return `/* konde.css — Custom design overrides (client-side) */
|
|
31
|
+
/* Loaded LAST in <head> via <link> — highest specificity */
|
|
32
|
+
/* Edit freely — KDF will never overwrite this file */
|
|
33
|
+
|
|
34
|
+
/* Use for:
|
|
35
|
+
- Fine-tune padding/margin/width
|
|
36
|
+
- Non-critical visual tweaks
|
|
37
|
+
- Quick experiments and CSS hacks
|
|
38
|
+
|
|
39
|
+
Examples:
|
|
40
|
+
[data-kdf="hero.title"] { letter-spacing: -0.02em; }
|
|
41
|
+
[data-kdf="hero.wrapper"] { gap: 3rem; }
|
|
42
|
+
*/
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write CSS files to disk — only if file doesn't exist.
|
|
47
|
+
* Safe to call multiple times; never overwrites user edits.
|
|
48
|
+
*/
|
|
49
|
+
export function writeKondeCSS(outputDir) {
|
|
50
|
+
const dir = outputDir || process.cwd();
|
|
51
|
+
const serverCss = join(dir, "konde-server.css");
|
|
52
|
+
const clientCss = join(dir, "konde.css");
|
|
53
|
+
if (!existsSync(serverCss)) {
|
|
54
|
+
writeFileSync(serverCss, generateKondeServerCSS(), "utf-8");
|
|
55
|
+
}
|
|
56
|
+
if (!existsSync(clientCss)) {
|
|
57
|
+
writeFileSync(clientCss, generateKondeCSS(), "utf-8");
|
|
58
|
+
}
|
|
59
|
+
}
|