@exxatdesignux/ui 0.4.2 → 0.5.1
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 +78 -0
- package/README.md +28 -11
- package/bin/init.mjs +42 -9
- package/bin/sync-extras.mjs +13 -5
- package/dist/components/ui/banner.d.ts +2 -2
- package/package.json +1 -1
- package/tokens/hooks-index.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,83 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`06bd06a`](https://github.com/ExxatDesign/Exxat-DS-Workspace/commit/06bd06a6ce5ebbe7ee9aba7c16c9329b4f9bdb5f) - **Scaffolded template (`create-exxat-app`) — add `overrides` / `pnpm.overrides` for `postcss` + `ws`**
|
|
8
|
+
|
|
9
|
+
A fresh `pnpm dlx create-exxat-app my-app` (or `npx --package=@exxatdesignux/ui exxat-ui init`) was producing an app that `npm audit` reported as having **4 moderate severity vulnerabilities** on first install:
|
|
10
|
+
|
|
11
|
+
| Advisory | Vulnerable transitive | Pulled in by |
|
|
12
|
+
| ------------------------------------------------------------------- | --------------------- | ------------------------------------------- |
|
|
13
|
+
| GHSA-qx2v-qp2m-jg93 (XSS via unescaped `</style>` in CSS stringify) | `postcss <8.5.10` | `next@16.2.6` (only published 16.x release) |
|
|
14
|
+
| GHSA-58qx-3vcg-4xpx (uninitialized memory disclosure) | `ws@8.0.0 - 8.20.0` | `pm2@^7.0.1` (only published 7.x release) |
|
|
15
|
+
|
|
16
|
+
`npm audit fix --force` would have _downgraded_ `next` to 9.3.3 and `pm2` to 6.0.14 — both major regressions. The actual upstream fixes haven't shipped yet, so the correct mitigation is package-manager overrides that force the resolver to pick a safer version of the transitive dep without touching the parents.
|
|
17
|
+
|
|
18
|
+
Added to `packages/ui/template/package.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
"overrides": {
|
|
22
|
+
"postcss": "$postcss",
|
|
23
|
+
"ws": "^8.20.1"
|
|
24
|
+
},
|
|
25
|
+
"pnpm": {
|
|
26
|
+
"overrides": {
|
|
27
|
+
"postcss@<8.5.10": "^8.5.14",
|
|
28
|
+
"ws@<8.20.1": "^8.20.1"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The `"postcss": "$postcss"` reference uses npm's special syntax that aliases the override to the direct devDep version (`^8.5.14`, already safe), avoiding the `EOVERRIDE` "conflicts with direct dependency" error. pnpm doesn't support `$name`, so we use its semver-range targeting (`@<8.5.10`) which fires only on the vulnerable subset and keeps newer versions unaffected.
|
|
34
|
+
|
|
35
|
+
After the fix: fresh scaffolds report `npm audit: found 0 vulnerabilities` and install ~4s faster from dedup (951 → 947 packages).
|
|
36
|
+
|
|
37
|
+
Workspace-internal apps (`apps/web`) are unaffected — the workspace root `package.json` already carries `pnpm.overrides` for these CVEs. Only the template was leaking them to consumers because scaffolded apps don't inherit workspace overrides.
|
|
38
|
+
|
|
39
|
+
**Existing consumers (already-scaffolded apps):** apply the same `overrides` + `pnpm.overrides` blocks to their `package.json` and re-run `npm install` / `pnpm install`. The shipped `consumer-upgrade-checklist.md` will mention this on the next sync.
|
|
40
|
+
|
|
41
|
+
**New consumers:** get the fix automatically on the next `create-exxat-app` invocation once `@exxatdesignux/ui@0.5.1` is published.
|
|
42
|
+
|
|
43
|
+
## 0.5.0
|
|
44
|
+
|
|
45
|
+
### Minor Changes
|
|
46
|
+
|
|
47
|
+
- `create-exxat-app` now drops the full Cursor + Claude agent bundle into
|
|
48
|
+
the scaffolded repo **automatically** after the dependency install.
|
|
49
|
+
Before this change, a new app shipped with only the 11 binding rules
|
|
50
|
+
that happened to live under `apps/web/.cursor/rules/`; the full curated
|
|
51
|
+
set (29 rules · 16 Cursor skills · 16 Claude skills · 6 pattern docs ·
|
|
52
|
+
4 handbook files) required a second manual `exxat-ui sync-extras` step.
|
|
53
|
+
|
|
54
|
+
What's new for a fresh `pnpm create exxat-app my-app`:
|
|
55
|
+
- After `pnpm install` succeeds, `init.mjs` invokes `sync-extras` in
|
|
56
|
+
`--quiet` mode so the scaffolded repo is one step from "open in
|
|
57
|
+
Cursor and every rule + skill is live".
|
|
58
|
+
- The bundle is namespaced (`exxat-*` files only) so re-syncing on
|
|
59
|
+
upgrade never touches a consumer's own rules, skills, AGENTS.md, or
|
|
60
|
+
product code.
|
|
61
|
+
- Opt out with `create-exxat-app my-app --no-extras` (alias
|
|
62
|
+
`--skip-extras`) — print a "run sync-extras later" hint instead.
|
|
63
|
+
- Final "Done!" message no longer treats `sync-extras` as an optional
|
|
64
|
+
follow-up; it mentions the upgrade-time refresh command instead.
|
|
65
|
+
|
|
66
|
+
Smaller polish in the same release:
|
|
67
|
+
- `--help` now documents `--no-extras`.
|
|
68
|
+
- Project-name normalization handles absolute target paths cleanly
|
|
69
|
+
(no leading-hyphen package names; no `.//absolute/path/` in the
|
|
70
|
+
success message).
|
|
71
|
+
- The `cd <target>` hint is suppressed when the user scaffolded into
|
|
72
|
+
the current directory with `.`.
|
|
73
|
+
- `sync-extras.mjs` learned `--quiet` (and the
|
|
74
|
+
`EXXAT_SYNC_EXTRAS_QUIET=1` env override) so the scaffolder can
|
|
75
|
+
call it without flooding the user with 50+ per-file log lines; the
|
|
76
|
+
final summary line still prints.
|
|
77
|
+
- README updated to describe the auto-extras flow and to clarify the
|
|
78
|
+
`sync-extras` command is now an _upgrade_ refresh, not a required
|
|
79
|
+
first step.
|
|
80
|
+
|
|
3
81
|
## 0.4.2
|
|
4
82
|
|
|
5
83
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -26,8 +26,23 @@ bun create exxat-app my-app
|
|
|
26
26
|
|
|
27
27
|
The scaffolder ships a complete Next.js 16 starter: the reference
|
|
28
28
|
**Library** hub at `/library/all`, the `/columns` cell-catalog showcase,
|
|
29
|
-
typed mock data, the full Cursor
|
|
30
|
-
|
|
29
|
+
typed mock data, plus the full Cursor + Claude agent bundle dropped into
|
|
30
|
+
the right paths **automatically**:
|
|
31
|
+
|
|
32
|
+
- `.cursor/rules/exxat-*.mdc` — 29 binding rules (Cursor reads these as
|
|
33
|
+
always-on / agent-requestable).
|
|
34
|
+
- `.cursor/skills/exxat-*/` and `.claude/skills/exxat-*/` — 16 skill
|
|
35
|
+
bundles (`SKILL.md` + references); same source written to both readers.
|
|
36
|
+
- `docs/exxat-ds/*.md` — 6 pattern docs (data views, command menu,
|
|
37
|
+
drawer-vs-dialog, KPI flat band, …) + the consumer upgrade checklist.
|
|
38
|
+
- `docs/exxat-ds/handbook/*.md` — HANDBOOK · glossary · voice-and-tone ·
|
|
39
|
+
reference-implementations.
|
|
40
|
+
- `AGENTS.md` (root) — the project's AI handbook from the reference app.
|
|
41
|
+
|
|
42
|
+
When you `cd my-app` and open Cursor for the first time, every binding
|
|
43
|
+
rule, skill, and pattern doc is already in place. To opt out, pass
|
|
44
|
+
`--no-extras` to the scaffolder; you can run it later with
|
|
45
|
+
`exxat-ui sync-extras` (see below).
|
|
31
46
|
|
|
32
47
|
## Adding to an existing Next.js app
|
|
33
48
|
|
|
@@ -55,19 +70,21 @@ Mount `KeyMetricsProvider` near the root if you want the "Ask Leo about
|
|
|
55
70
|
these metrics" CTA wired to your AI surface (otherwise the strip just
|
|
56
71
|
hides that button automatically).
|
|
57
72
|
|
|
58
|
-
## Refresh Cursor
|
|
73
|
+
## Refresh Cursor / Claude agent bundle in any consumer
|
|
59
74
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
`pnpm create exxat-app` drops the agent bundle for you on first scaffold.
|
|
76
|
+
When you upgrade `@exxatdesignux/ui` later — or when you want to seed the
|
|
77
|
+
bundle into an **existing** Next.js app that already depends on the DS —
|
|
78
|
+
run:
|
|
63
79
|
|
|
64
80
|
```bash
|
|
65
81
|
pnpm dlx --package=@exxatdesignux/ui@latest exxat-ui sync-extras
|
|
66
82
|
```
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
84
|
+
The command is **namespaced**: it only writes files starting with
|
|
85
|
+
`exxat-` (rules + skills) and only inside `.cursor/`, `.claude/skills/`,
|
|
86
|
+
and `docs/exxat-ds/`. Your own rules, skills, AGENTS.md, and product
|
|
87
|
+
code are never touched.
|
|
71
88
|
|
|
72
89
|
## What's inside
|
|
73
90
|
|
|
@@ -121,8 +138,8 @@ natively.
|
|
|
121
138
|
custom property the DS ships.
|
|
122
139
|
|
|
123
140
|
The full doc set is mirrored under `handbook/` and `patterns/` in this
|
|
124
|
-
package; `exxat-
|
|
125
|
-
|
|
141
|
+
package; `pnpm create exxat-app` drops them at `docs/exxat-ds/` on first
|
|
142
|
+
scaffold, and `exxat-ui sync-extras` re-syncs them in any later upgrade.
|
|
126
143
|
|
|
127
144
|
## Compatibility
|
|
128
145
|
|
package/bin/init.mjs
CHANGED
|
@@ -27,9 +27,17 @@ const flags = new Set(args.filter((a) => a.startsWith("--")))
|
|
|
27
27
|
const positional = args.filter((a) => !a.startsWith("--"))
|
|
28
28
|
const targetArg = positional[0] ?? "."
|
|
29
29
|
const targetDir = resolve(process.cwd(), targetArg)
|
|
30
|
-
|
|
30
|
+
// `displayName` is what we show in messages and use to derive package.json
|
|
31
|
+
// `name`. For "." or an absolute path we just use the basename; for a
|
|
32
|
+
// relative path the user typed (`my-app`, `apps/sandbox`) we keep it as-is.
|
|
33
|
+
const isAbsolute = targetArg.startsWith("/") || /^[a-zA-Z]:\\/.test(targetArg)
|
|
34
|
+
const displayName = targetArg === "." || isAbsolute ? basename(targetDir) : targetArg
|
|
35
|
+
// `cdHint` is what we tell the user to `cd` into. If they passed an
|
|
36
|
+
// absolute path, that's the literal path; otherwise the relative arg.
|
|
37
|
+
const cdHint = isAbsolute ? targetDir : displayName
|
|
31
38
|
const force = flags.has("--force")
|
|
32
39
|
const skipInstall = flags.has("--no-install") || flags.has("--skip-install")
|
|
40
|
+
const skipExtras = flags.has("--no-extras") || flags.has("--skip-extras")
|
|
33
41
|
|
|
34
42
|
if (flags.has("--help") || flags.has("-h")) {
|
|
35
43
|
console.log(`
|
|
@@ -47,6 +55,9 @@ Options:
|
|
|
47
55
|
files are NOT overwritten unless template ships the
|
|
48
56
|
same path).
|
|
49
57
|
--no-install Skip the dependency install step.
|
|
58
|
+
--no-extras Skip auto-syncing Cursor / Claude agent skills, binding
|
|
59
|
+
rules, and pattern docs. You can run them later with
|
|
60
|
+
\`exxat-ui sync-extras\`.
|
|
50
61
|
-h, --help Show this message.
|
|
51
62
|
|
|
52
63
|
Examples:
|
|
@@ -59,7 +70,7 @@ Examples:
|
|
|
59
70
|
|
|
60
71
|
if (!existsSync(targetDir)) {
|
|
61
72
|
mkdirSync(targetDir, { recursive: true })
|
|
62
|
-
console.log(`📁 Created ${
|
|
73
|
+
console.log(`📁 Created ${displayName}/`)
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
const targetStat = statSync(targetDir)
|
|
@@ -86,7 +97,7 @@ if (blockers.length > 0 && !force) {
|
|
|
86
97
|
process.exit(1)
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
console.log(`📦 Copying Exxat DS starter app into ${
|
|
100
|
+
console.log(`📦 Copying Exxat DS starter app into ${displayName}/ …`)
|
|
90
101
|
cpSync(templateDir, targetDir, { recursive: true })
|
|
91
102
|
|
|
92
103
|
// Pin DS to this CLI's published version so `latest` cache drift cannot
|
|
@@ -97,7 +108,7 @@ if (targetPkg.dependencies?.["@exxatdesignux/ui"]) {
|
|
|
97
108
|
targetPkg.dependencies["@exxatdesignux/ui"] = `^${selfPkg.version}`
|
|
98
109
|
}
|
|
99
110
|
// Name the project after the target dir for nicer dev-server / process titles.
|
|
100
|
-
targetPkg.name =
|
|
111
|
+
targetPkg.name = displayName.replace(/[^a-z0-9-_]/gi, "-").toLowerCase() || "my-exxat-app"
|
|
101
112
|
writeFileSync(targetPkgPath, `${JSON.stringify(targetPkg, null, 2)}\n`)
|
|
102
113
|
console.log(`📌 Pinned @exxatdesignux/ui to ^${selfPkg.version} and named the project "${targetPkg.name}".`)
|
|
103
114
|
|
|
@@ -111,19 +122,41 @@ if (skipInstall) {
|
|
|
111
122
|
} catch (err) {
|
|
112
123
|
console.error("")
|
|
113
124
|
console.error(`❌ ${pm.label} install failed. You can retry manually:`)
|
|
114
|
-
console.error(` cd ${
|
|
125
|
+
console.error(` cd ${cdHint} && ${pm.installCmd}`)
|
|
115
126
|
process.exit(1)
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
|
|
130
|
+
// Drop the full curated bundle (Cursor + Claude skills, binding rules,
|
|
131
|
+
// pattern docs, handbook) into the new repo so AI assistants light up on
|
|
132
|
+
// first open. The bundle replaces only `exxat-*` namespaced files — the
|
|
133
|
+
// consumer's own rules/skills/docs are preserved on every re-run.
|
|
134
|
+
if (skipExtras) {
|
|
135
|
+
console.log(`⏭ Skipped agent skills + rules (--no-extras).`)
|
|
136
|
+
} else {
|
|
137
|
+
const syncScript = resolve(__dirname, "sync-extras.mjs")
|
|
138
|
+
if (!existsSync(syncScript)) {
|
|
139
|
+
console.warn(`⚠️ Could not find sync-extras at ${syncScript} — skipping.`)
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`🧠 Installing Cursor + Claude agent skills, binding rules, and pattern docs …`)
|
|
142
|
+
try {
|
|
143
|
+
execSync(`node "${syncScript}" --quiet`, { stdio: "inherit", cwd: targetDir })
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.warn(`⚠️ Agent extras step failed. You can retry manually:`)
|
|
146
|
+
console.warn(` cd ${cdHint} && ${pm.dlxCmd} --package=@exxatdesignux/ui@${selfPkg.version} exxat-ui sync-extras`)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
119
151
|
console.log("")
|
|
120
|
-
console.log(`✅ Done! Your Exxat DS app is ready in
|
|
152
|
+
console.log(`✅ Done! Your Exxat DS app is ready in ${isAbsolute ? targetDir : `./${displayName}/`}`)
|
|
121
153
|
console.log("")
|
|
122
|
-
console.log(` cd ${
|
|
154
|
+
if (targetArg !== ".") console.log(` cd ${cdHint}`)
|
|
123
155
|
console.log(` ${pm.runCmd} dev # start dev server`)
|
|
124
156
|
console.log("")
|
|
125
|
-
console.log("
|
|
126
|
-
console.log(
|
|
157
|
+
console.log(" Cursor / Claude skills, rules, and pattern docs are already in place.")
|
|
158
|
+
console.log(" When you upgrade @exxatdesignux/ui later, refresh them with:")
|
|
159
|
+
console.log(` ${pm.dlxCmd} --package=@exxatdesignux/ui@latest exxat-ui sync-extras`)
|
|
127
160
|
console.log("")
|
|
128
161
|
|
|
129
162
|
/**
|
package/bin/sync-extras.mjs
CHANGED
|
@@ -28,6 +28,14 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
28
28
|
const pkgRoot = resolve(__dirname, "..")
|
|
29
29
|
const cwd = process.cwd()
|
|
30
30
|
|
|
31
|
+
// `--quiet` suppresses the per-file "[sync-extras] wrote …" lines so the
|
|
32
|
+
// scaffolder (`create-exxat-app`) can call us inline without drowning the
|
|
33
|
+
// user in 50+ status lines. The final summary line still prints.
|
|
34
|
+
const QUIET = process.argv.includes("--quiet") || process.env.EXXAT_SYNC_EXTRAS_QUIET === "1"
|
|
35
|
+
function log(...m) {
|
|
36
|
+
if (!QUIET) console.log(...m)
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
const SOURCES = {
|
|
32
40
|
skills: join(pkgRoot, "consumer-extras", "cursor-skills"),
|
|
33
41
|
rules: join(pkgRoot, "consumer-extras", "cursor-rules"),
|
|
@@ -69,7 +77,7 @@ function syncSkillsTo(label, dest) {
|
|
|
69
77
|
if (!statSync(src).isDirectory()) continue
|
|
70
78
|
if (!name.startsWith("exxat-")) continue
|
|
71
79
|
replaceDir(src, join(dest, name))
|
|
72
|
-
|
|
80
|
+
log(`[sync-extras] wrote ${label}/${name}/`)
|
|
73
81
|
wrote++
|
|
74
82
|
}
|
|
75
83
|
}
|
|
@@ -91,7 +99,7 @@ function syncRules() {
|
|
|
91
99
|
if (!statSync(src).isFile()) continue
|
|
92
100
|
if (!name.startsWith("exxat-") || !name.endsWith(".mdc")) continue
|
|
93
101
|
cpSync(src, join(DESTINATIONS.cursorRules, name))
|
|
94
|
-
|
|
102
|
+
log(`[sync-extras] wrote .cursor/rules/${name}`)
|
|
95
103
|
wrote++
|
|
96
104
|
}
|
|
97
105
|
}
|
|
@@ -111,7 +119,7 @@ function syncPatterns() {
|
|
|
111
119
|
const src = join(SOURCES.patterns, name)
|
|
112
120
|
if (!statSync(src).isFile()) continue
|
|
113
121
|
cpSync(src, join(DESTINATIONS.patterns, name))
|
|
114
|
-
|
|
122
|
+
log(`[sync-extras] wrote docs/exxat-ds/${name}`)
|
|
115
123
|
wrote++
|
|
116
124
|
}
|
|
117
125
|
}
|
|
@@ -137,7 +145,7 @@ function syncHandbook() {
|
|
|
137
145
|
const src = join(SOURCES.handbook, name)
|
|
138
146
|
if (!statSync(src).isFile()) continue
|
|
139
147
|
cpSync(src, join(DESTINATIONS.handbook, name))
|
|
140
|
-
|
|
148
|
+
log(`[sync-extras] wrote docs/exxat-ds/handbook/${name}`)
|
|
141
149
|
wrote++
|
|
142
150
|
}
|
|
143
151
|
}
|
|
@@ -149,4 +157,4 @@ syncPatterns()
|
|
|
149
157
|
syncHandbook()
|
|
150
158
|
|
|
151
159
|
console.log(`[sync-extras] Done. ${wrote} files / dirs written; ${skipped} optional sources missing.`)
|
|
152
|
-
console.log("[sync-extras] Product routes and app content were not modified.")
|
|
160
|
+
if (!QUIET) console.log("[sync-extras] Product routes and app content were not modified.")
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const systemBannerVariants: (props?: ({
|
|
7
|
-
variant?: "
|
|
7
|
+
variant?: "error" | "success" | "warning" | "info" | "promo" | null | undefined;
|
|
8
8
|
emphasis?: "prominent" | "subtle" | null | undefined;
|
|
9
9
|
actionPosition?: "inline" | "bottom" | null | undefined;
|
|
10
10
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -32,7 +32,7 @@ interface SystemBannerProps extends React.HTMLAttributes<HTMLDivElement>, Varian
|
|
|
32
32
|
}
|
|
33
33
|
declare function SystemBanner({ children, title, variant, emphasis, dismissible, onDismiss, action, actionPosition, icon, decorativeOverlay, className, style, ...props }: SystemBannerProps): react_jsx_runtime.JSX.Element | null;
|
|
34
34
|
declare const localBannerVariants: (props?: ({
|
|
35
|
-
variant?: "
|
|
35
|
+
variant?: "error" | "success" | "warning" | "info" | "promo" | null | undefined;
|
|
36
36
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
37
37
|
interface LocalBannerProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof localBannerVariants> {
|
|
38
38
|
/** Banner title (optional) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exxatdesignux/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Exxat shared design system (components, hooks, tokens). Monorepo setup: clone repo then pnpm bootstrap at workspace root — see github.com/ExxatDesign/Exxat-DS-Workspace README.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Exxat Design",
|
package/tokens/hooks-index.json
CHANGED