Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: release

# Publishes @aestheticfunction/dspack-export to npm when a version tag is
# pushed. Mirrors ds-mcp's release workflow (which mirrors dspack-gen's).
#
# Auth: npm trusted publishing (OIDC) — no NPM_TOKEN secret in the repo.
# One-time setup on npmjs.com (package settings -> Trusted publisher):
# repository aestheticfunction/dspack-export, workflow release.yml.
# Provenance attestations are generated automatically for trusted publishes.
#
# Guards:
# - tag must equal the package.json version (prevents accidental mismatches)
# - full test suite + schema drift check run before publish

on:
push:
tags:
- "v*"

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # OIDC for npm trusted publishing / provenance
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
# Node 24 bundles npm >= 11.5, the minimum for OIDC trusted
# publishing (see dspack-gen v0.1.1's E404 incident).
node-version: 24
cache: npm
registry-url: https://registry.npmjs.org
- name: Verify tag matches package.json version
run: |
pkg="$(node -p "require('./package.json').version")"
tag="${GITHUB_REF_NAME#v}"
if [ "$pkg" != "$tag" ]; then
echo "tag v$tag does not match package.json version $pkg" >&2
exit 1
fi
- run: npm ci
- run: npm run build
- run: npm test
- run: npm run check:sync
- name: Publish (public, with provenance)
run: npm publish --access public
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: test

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
- run: npm test
- name: Vendored-schema drift check
run: npm run check:sync
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
dist/
*.log
.DS_Store
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Changelog

## 0.3.0

The DX-3 bootstrap boundary (dspack `rfc/dx3-bootstrap-design.md`), and the
first npm-published release.

- Snapshots declare the current spec version (**dspack 0.4**) instead of the
hard-coded 0.2; the manual relabel step disappears from the adoption
journey. Populated sections are unchanged — this tool still writes no
governance content, ever.
- Every snapshot carries a **non-semantic `metadata["x-bootstrap"]` ledger**:
the spec version, a content hash per generated section, and the list of
governance surfaces awaiting human authorship. Deleting the ledger marks a
document fully human-owned.
- **Regeneration refusal table**: `generate` refuses to overwrite any file it
cannot prove it owns — no ledger, human-authored sections present, or a
generated section edited by hand — and every refusal explains why. There
is deliberately no force flag. A pure untouched snapshot still
regenerates in place.
- `generate --out <file>` writes the snapshot to an explicit path.
- `validate` now checks against a vendored byte copy of the dspack **v0.4**
schema, guarded by `scripts/check-sync.mjs` (shape gate only; full
contract validation lives in the dspack repository's harness).
- CI (`test.yml`) and tag-triggered OIDC trusted publishing (`release.yml`),
mirroring ds-mcp/dspack-gen.

## 0.2.0-alpha.0

Unpublished baseline: v0.2 snapshot generation (React + Tailwind/shadcn and
Vue 3 + Vuetify 3 adapters, DTCG token import, deterministic output,
round-trip gate against ds-mcp).
40 changes: 28 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# dspack-export

Generate [dspack](https://github.com/aestheticfunction/dspack) v0.2 design-system
snapshots from component codebases — **React + Tailwind/shadcn** and **Vue 3 +
Bootstrap current-spec [dspack](https://github.com/aestheticfunction/dspack)
design-system snapshots from component codebases — **React + Tailwind/shadcn** and **Vue 3 +
Vuetify 3** — ready to serve to AI agents via
[ds-mcp](https://github.com/aestheticfunction/ds-mcp).

> Part of the [dspack ecosystem](https://github.com/aestheticfunction) — the organization profile has the full map of how the repositories fit together.
>
> **Kind:** snapshot tool (CLI, experimental, not yet on npm — install from source) · **Audience:** teams with an existing component codebase who want a starting dspack file · **Neighbors:** produces [dspack](https://github.com/aestheticfunction/dspack) documents; serves them via [ds-mcp](https://github.com/aestheticfunction/ds-mcp); see the governed end-to-end chain in [dspack-studio](https://github.com/aestheticfunction/dspack-studio) ([hosted replay](https://studio.aesthetic-function.com))
> **Kind:** snapshot tool (CLI, experimental, npm `@aestheticfunction/dspack-export`) · **Audience:** teams with an existing component codebase who want a starting dspack file · **Neighbors:** produces [dspack](https://github.com/aestheticfunction/dspack) documents; serves them via [ds-mcp](https://github.com/aestheticfunction/ds-mcp); see the governed end-to-end chain in [dspack-studio](https://github.com/aestheticfunction/dspack-studio) ([hosted replay](https://studio.aesthetic-function.com))
>
> This tool is **step 1** of the adoption journey; what to do with the snapshot it produces — review, governance authoring, validation, serving — is the [adoption guide](https://github.com/aestheticfunction/dspack/blob/main/ADOPTING.md).

Expand All @@ -18,17 +18,33 @@ across frameworks. The active adapter is chosen by an optional `framework` confi
field, or inferred from component file extensions (`.tsx/.jsx` → React, `.vue` →
Vue) with a hard error on ambiguous input.

**Status: experimental** (`0.2.0-alpha.0`). Config format and output details
may still change between versions. Not yet published to npm — install from
source (below). The [handbook](docs/handbook.md) covers the supported stack,
known limitations, and troubleshooting.
**Status: experimental** (`0.3.0`). Config format and output details may
still change between versions. Published to npm as
`@aestheticfunction/dspack-export`. The [handbook](docs/handbook.md) covers
the supported stack, known limitations, and troubleshooting.

The snapshot targets the dspack v0.2 shape. The spec has since added the
governance revisions (v0.3 and v0.4); their rules, intents, and examples are
hand-authored downstream, not extracted, and this tool remains a snapshot
generator.
The snapshot declares the current spec version (v0.4) and populates the
machine-discoverable sections only. The governance layer (categories,
intents, rules, examples, patterns, anti-patterns, and prose guidance) is
hand-authored downstream, never extracted — the output's
`metadata["x-bootstrap"]` ledger records exactly which sections this tool
generated (with content hashes) and which surfaces await authorship. The
ledger is non-semantic: it exists only so regeneration can make safe
decisions, and deleting it marks the document fully human-owned.

## Install (from source)
**Regeneration never destroys human-authored content.** If the output file
contains anything this tool does not own — governance blocks, edited
sections, or no ledger at all — `generate` refuses, explains why, and
points at `--out` for writing a fresh snapshot elsewhere. There is no
force flag.

## Install

```bash
npm install -g @aestheticfunction/dspack-export
```

Or from source:

```bash
git clone https://github.com/aestheticfunction/dspack-export
Expand Down
28 changes: 25 additions & 3 deletions fixtures/dtcg-tokens-demo/dtcg-tokens-demo.dspack.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
{
"dspack": "0.2",
"dspack": "0.4",
"name": "DTCG Tokens Demo",
"description": "Fixture exercising DTCG design-token-file import alongside CSS token extraction.",
"version": "1.0.0",
"metadata": {
"generatedBy": "@aestheticfunction/dspack-export@0.2.0-alpha.0",
"generatedBy": "@aestheticfunction/dspack-export@0.3.0",
"generatedAt": "2026-06-10T00:00:00.000Z",
"source": "fixtures/dtcg-tokens-demo",
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated and will be overwritten on regeneration."
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated; regeneration refuses to overwrite a document containing human-authored content (see metadata[\"x-bootstrap\"]).",
"x-bootstrap": {
"spec": "0.4",
"generated": {
"tokens": "6ff5c3fd63f4ba56337320d79583982bfce66919a3552f4938e95cbd1005326c",
"components": "0c49b4db41e59c849995be828fa8df10a4e10aa39384213f6ddb3801da0e9444",
"frameworkBindings": "9ee9adecbbe7a9a144145507791bebde19e6f4ebda6a47a29beec1497a9faf12",
"themes": "8fec47475f975ca9da6b547d5bd2d8ab5ac0f1c126ce98bb0614c01f39a66dad",
"layout": "84240158ff29a8c25fd428fdf24f3409df36710fabef89086d711704bc0130c2"
},
"awaitingAuthorship": [
"categories",
"intents",
"rules",
"examples",
"patterns",
"antiPatterns",
"components.*.whenToUse",
"components.*.accessibility",
"components.*.composition",
"components.*.constraints"
]
}
},
"tokens": {
"color": {
Expand Down
28 changes: 25 additions & 3 deletions fixtures/shadcn-demo/shadcn-demo.dspack.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
{
"dspack": "0.2",
"dspack": "0.4",
"name": "Shadcn Demo",
"description": "Demo shadcn-style design system used as the dspack-export golden fixture.",
"version": "1.0.0",
"metadata": {
"generatedBy": "@aestheticfunction/dspack-export@0.2.0-alpha.0",
"generatedBy": "@aestheticfunction/dspack-export@0.3.0",
"generatedAt": "2026-06-10T00:00:00.000Z",
"source": "fixtures/shadcn-demo",
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated and will be overwritten on regeneration."
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated; regeneration refuses to overwrite a document containing human-authored content (see metadata[\"x-bootstrap\"]).",
"x-bootstrap": {
"spec": "0.4",
"generated": {
"tokens": "d031a79c0a10556c38b099145be82d26eed263713c60922efab56338aca69f15",
"components": "452923cc85bea76d7cd784299cf28dcd79b853961a0c65aa7d31cd186c9f74cd",
"frameworkBindings": "9dea8ada96c2e74adcbf96dc3234d13994b88c6a3a96f12a7e68ed354d89bd1e",
"themes": "46510dd813828a275bd601d0f0348934b9cd1b8b29b4cc525538472f3958173f",
"layout": "84240158ff29a8c25fd428fdf24f3409df36710fabef89086d711704bc0130c2"
},
"awaitingAuthorship": [
"categories",
"intents",
"rules",
"examples",
"patterns",
"antiPatterns",
"components.*.whenToUse",
"components.*.accessibility",
"components.*.composition",
"components.*.constraints"
]
}
},
"tokens": {
"color": {
Expand Down
28 changes: 25 additions & 3 deletions fixtures/shadcn-v4-demo/shadcn-v4-demo.dspack.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
{
"dspack": "0.2",
"dspack": "0.4",
"name": "Shadcn V4 Demo",
"description": "Tailwind v4 / @theme-style fixture for dspack-export.",
"version": "1.0.0",
"metadata": {
"generatedBy": "@aestheticfunction/dspack-export@0.2.0-alpha.0",
"generatedBy": "@aestheticfunction/dspack-export@0.3.0",
"generatedAt": "2026-06-10T00:00:00.000Z",
"source": "fixtures/shadcn-v4-demo",
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated and will be overwritten on regeneration."
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated; regeneration refuses to overwrite a document containing human-authored content (see metadata[\"x-bootstrap\"]).",
"x-bootstrap": {
"spec": "0.4",
"generated": {
"tokens": "a6f0f842d11f89823929bb7e3df4d40c19357c119dd42a687e0adbd1fa8e58d0",
"components": "84e0bc713f0fd87239cc60a9981d59d49e5c6689874f025a7773b24502ac1976",
"frameworkBindings": "9ee9adecbbe7a9a144145507791bebde19e6f4ebda6a47a29beec1497a9faf12",
"themes": "fafbb44d5be2b3a7954c6cb4fb1590a669e8aa1c84eecb3ad15b421e14a0042b",
"layout": "0b92b1df3e314dcb730718fd0c087a680750c7a3a33f16f2f1c0a6d885c4c585"
},
"awaitingAuthorship": [
"categories",
"intents",
"rules",
"examples",
"patterns",
"antiPatterns",
"components.*.whenToUse",
"components.*.accessibility",
"components.*.composition",
"components.*.constraints"
]
}
},
"tokens": {
"color": {
Expand Down
26 changes: 23 additions & 3 deletions fixtures/vuetify-demo/vuetify-demo.dspack.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
{
"dspack": "0.2",
"dspack": "0.4",
"name": "Vuetify Demo",
"description": "Demo Vue 3 + Vuetify 3 design system used as the dspack-export Vue golden fixture.",
"version": "1.0.0",
"metadata": {
"generatedBy": "@aestheticfunction/dspack-export@0.2.0-alpha.0",
"generatedBy": "@aestheticfunction/dspack-export@0.3.0",
"generatedAt": "2026-06-10T00:00:00.000Z",
"source": "fixtures/vuetify-demo",
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated and will be overwritten on regeneration."
"note": "Generated snapshot. Hand-authored sections (patterns, antiPatterns, whenToUse, accessibility, composition, constraints) are not generated; regeneration refuses to overwrite a document containing human-authored content (see metadata[\"x-bootstrap\"]).",
"x-bootstrap": {
"spec": "0.4",
"generated": {
"tokens": "411ade9c82231a3fcb56a281e79f25d4eb3f8e10001e2c7d06b7ff8dff9bec66",
"components": "7aa04b6cb24b0dd8d580503f82e2b7fc5f9962f2e94bea402f4252ff1f02fb77",
"frameworkBindings": "3d6893c966874d773c2c3ebcfbedbb481b4947ec86f986aa30855ccda7ef970c"
},
"awaitingAuthorship": [
"categories",
"intents",
"rules",
"examples",
"patterns",
"antiPatterns",
"components.*.whenToUse",
"components.*.accessibility",
"components.*.composition",
"components.*.constraints"
]
}
},
"tokens": {
"color": {
Expand Down
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"name": "@aestheticfunction/dspack-export",
"version": "0.2.0-alpha.0",
"private": true,
"description": "Generate dspack v0.2 design-system snapshots from component codebases (React + Tailwind/shadcn, Vue 3 + Vuetify 3) through a framework-adapter layer",
"version": "0.3.0",
"description": "Bootstrap a current-spec dspack design-system snapshot from a component codebase (React + Tailwind/shadcn, Vue 3 + Vuetify 3) through a framework-adapter layer",
"keywords": [
"dspack",
"design-system",
Expand All @@ -20,7 +19,7 @@
"dspack-export": "dist/cli.js"
},
"engines": {
"node": ">=20.0.0"
"node": ">=22.0.0"
},
"author": {
"name": "Ryan Dombrowski"
Expand All @@ -37,7 +36,8 @@
"build": "tsc",
"test": "vitest run",
"generate:fixture": "npm run build && SOURCE_DATE_EPOCH=1781049600 node dist/cli.js generate --config fixtures/shadcn-demo/dspack-export.config.json",
"generate:fixture:vue": "npm run build && SOURCE_DATE_EPOCH=1781049600 node dist/cli.js generate --config fixtures/vuetify-demo/dspack-export.config.json"
"generate:fixture:vue": "npm run build && SOURCE_DATE_EPOCH=1781049600 node dist/cli.js generate --config fixtures/vuetify-demo/dspack-export.config.json",
"check:sync": "node scripts/check-sync.mjs"
},
"dependencies": {
"@babel/parser": "^7.28.5",
Expand All @@ -61,5 +61,11 @@
"tailwind-merge": "^2.6.0",
"vitest": "^3.0.0",
"vue": "^3.5.38"
}
},
"files": [
"dist",
"src/emit/schema",
"README.md",
"LICENSE"
]
}
Loading
Loading