@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 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 skill + pattern doc set under
30
- `cursor-rules/`, `cursor-skills/`, `patterns/`, and `handbook/`.
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 skills + pattern docs in any consumer
73
+ ## Refresh Cursor / Claude agent bundle in any consumer
59
74
 
60
- The package ships a parallel set of binding rules, skills, and pattern
61
- docs so AI agents in your own repo can read the same guidance the source
62
- repo uses. To install or refresh them in your repo:
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
- This copies `cursor-rules/`, `cursor-skills/`, `patterns/`, and
69
- `handbook/` into your repo root. The next time Cursor opens, every
70
- binding rule + skill is live.
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-ui sync-extras` drops them into your repo so they sit
125
- alongside your source.
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
- const projectName = targetArg === "." ? basename(targetDir) : targetArg
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 ${projectName}/`)
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 ${projectName}/ …`)
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 = projectName.replace(/[^a-z0-9-_]/gi, "-").toLowerCase() || "my-exxat-app"
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 ${projectName} && ${pm.installCmd}`)
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 ./${projectName}/`)
152
+ console.log(`✅ Done! Your Exxat DS app is ready in ${isAbsolute ? targetDir : `./${displayName}/`}`)
121
153
  console.log("")
122
- console.log(` cd ${projectName}`)
154
+ if (targetArg !== ".") console.log(` cd ${cdHint}`)
123
155
  console.log(` ${pm.runCmd} dev # start dev server`)
124
156
  console.log("")
125
- console.log(" Optional refresh Cursor skills + pattern docs:")
126
- console.log(` ${pm.dlxCmd} --package=@exxatdesignux/ui@${selfPkg.version} exxat-ui sync-extras`)
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
  /**
@@ -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
- console.log(`[sync-extras] wrote ${label}/${name}/`)
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
- console.log(`[sync-extras] wrote .cursor/rules/${name}`)
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
- console.log(`[sync-extras] wrote docs/exxat-ds/${name}`)
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
- console.log(`[sync-extras] wrote docs/exxat-ds/handbook/${name}`)
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?: "success" | "warning" | "error" | "info" | "promo" | null | undefined;
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?: "success" | "warning" | "error" | "info" | "promo" | null | undefined;
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.4.2",
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",
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.4.0",
2
+ "version": "0.5.1",
3
3
  "source": "packages/ui/src/globals.css",
4
- "generatedAt": "2026-05-21T18:31:11.351Z",
4
+ "generatedAt": "2026-05-22T04:04:09.308Z",
5
5
  "tokenCount": 197,
6
6
  "themeKeys": [
7
7
  "tailwind-bridge",