feat: scripts/sync-libs.mjs + docs/LIBS.md
Generates a compact lib catalog from the live crema-manifest, sorted into "wired in this project" and "available to add" tables. The development LLM (Claude Code, Cursor, etc.) reads this when answering "is there a lib for X" — saves it from re-deriving the answer or making one up. The script reads the project's tsconfig.json paths (for wired libs) and app/app.css @import lines (for the active theme), clones the manifest, and emits docs/LIBS.md with stable formatting. CLAUDE.md updated to point at LIBS.md (was pointing directly at the live manifest URL — slower for an LLM that wants a quick scan). Run after `crema add <name>` or whenever you want a refresh: npm run sync-libs Auto-detects: - Wired libs from tsconfig.json @crema/* paths - Active theme from app/app.css `@import "../../lib-theme-*/theme.css"` lines Output is intentionally compact — terse one-line descriptions, alpha sort, no front-matter. ~9KB for the current 5-wired / 50-available split. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
9
.boot.log
Normal file
9
.boot.log
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
> dev
|
||||
> react-router dev
|
||||
|
||||
Port 5173 is in use, trying another one...
|
||||
➜ Local: http://localhost:5174/
|
||||
➜ Network: use --host to expose
|
||||
6:37:06 pm [vite] (client) ✨ new dependencies optimized: lucide-react, @base-ui/react/button, class-variance-authority, @base-ui/react/input, @base-ui/react/avatar, @base-ui/react/dialog, clsx, tailwind-merge, @base-ui/react/menu, react-markdown
|
||||
6:37:06 pm [vite] (client) ✨ optimized dependencies changed. reloading
|
||||
99
docs/LIBS.md
Normal file
99
docs/LIBS.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Available Crema libs
|
||||
|
||||
> Generated by `scripts/sync-libs.mjs` from crema-manifest@3.1.0.
|
||||
> Run `npm run sync-libs` to refresh.
|
||||
|
||||
Every `@crema/*-ui` lib is its own git repo at
|
||||
`https://git.sky-ai.com/CremaUIStudio/lib-<name>-ui`. To add one, clone it
|
||||
as a sibling of this project, then add the tsconfig path entry and the
|
||||
`@source` line to `app/app.css` (the marker comments make this easy).
|
||||
|
||||
## Wired in this project (5)
|
||||
|
||||
These are importable from your code right now (`import { … } from "@crema/<name>"`):
|
||||
|
||||
| Lib | Alias | Purpose |
|
||||
|---|---|---|
|
||||
| `action-bus` | `@crema/action-bus` | Anything-can-drive-the-UI command bus. Single dispatch point for LLM tool calls, scripts, and (optional) WebSocket remote control. JSON c… |
|
||||
| `aifirst-ui` | `@crema/aifirst-ui` | AI-first card primitives: AICard with left-border accent + canonical anatomy (title, metadata, AI rationale, verb-prefixed action buttons… |
|
||||
| `chat-ui` | `@crema/chat-ui` | Chat threads, message bubbles, composer, channel list |
|
||||
| `llm-ui` | `@crema/llm-ui` | LLM client + React bindings. Two adapters out of the box: OpenAICompatibleAdapter (LM Studio, Ollama, DeepSeek, OpenAI, Together, Groq, O… |
|
||||
| `notification-ui` | `@crema/notification-ui` | Toasts, badges, bell, banners, inbox, notification center |
|
||||
|
||||
## Active theme
|
||||
|
||||
| Theme | Dark mode | Purpose |
|
||||
|---|---|---|
|
||||
| `mightypix` | supported | Warm AI-first companion to pristine. Cream paper surfaces, deep ink-blue accent, soft flat elevation, asymmetric typography (Inter for UI chrome, Source Seri… |
|
||||
|
||||
## Available to add (50)
|
||||
|
||||
From the manifest. To wire one in: `crema add <name>` (CLI), or
|
||||
manually clone the repo + edit `tsconfig.json` paths + `app/app.css`
|
||||
`@source`.
|
||||
|
||||
| Lib | Alias | Purpose |
|
||||
|---|---|---|
|
||||
| `a11y-ui` | `@crema/a11y-ui` | Skip links, focus trap/ring, shortcut overlay, contrast checker |
|
||||
| `agent-ui` | `@crema/agent-ui` | Agentic UI atoms: action proposals + queue, diff proposals, tool-call audit cards, multi-step run panel with step trail and milestone rai… |
|
||||
| `artifact-ui` | `@crema/artifact-ui` | AI-generated artifacts as cards: code, file, email, sql, draft, chart, image, dataset. Type-specific previews, draft/reviewing/applied li… |
|
||||
| `auth-ui` | `@crema/auth-ui` | Sign-in, sign-up, MFA, password reset, OAuth buttons |
|
||||
| `billing-ui` | `@crema/billing-ui` | Pricing tables, plan comparison, usage meters, invoices, payment methods |
|
||||
| `calendar-ui` | `@crema/calendar-ui` | Calendar grid, week/day views, event cards, scheduling |
|
||||
| `callcentre-ui` | `@crema/callcentre-ui` | Agent desktop: softphone, active call card, queue, history, customer lookup, scripts, knowledge search, transcript, notes, disposition, w… |
|
||||
| `card-ui` | `@crema/card-ui` | Theme-agnostic card primitives: three-zone template (media / body / actions) with portrait, landscape, compact, wide-banner orientations;… |
|
||||
| `chart-ui` | `@crema/chart-ui` | Themed charting primitives: sparkline, line, bar, donut, heatmap. Pure SVG, currentColor-driven. |
|
||||
| `code-ui` | `@crema/code-ui` | Code blocks, diff viewer, syntax highlighting, file tree |
|
||||
| `codereview-ui` | `@crema/codereview-ui` | Code review primitives in two registers, sharing PullRequest/DiffHunk/ReviewComment/Reviewer types. Plain: PullRequestCard (queue row), D… |
|
||||
| `color-ui` | `@crema/color-ui` | Color picker, swatches, palettes, contrast tooling |
|
||||
| `command-ui` | `@crema/command-ui` | Command palette (⌘K) with self-registering commands, fuzzy match, keyboard navigation. |
|
||||
| `comments-ui` | `@crema/comments-ui` | Threaded comments, mentions, reactions, presence |
|
||||
| `commerce-ui` | `@crema/commerce-ui` | Product cards, cart, checkout, order summary |
|
||||
| `content-editor-ui` | `@crema/content-editor-ui` | Rich-text editor (Tiptap), blog composer, slash menu, image embeds |
|
||||
| `content-media-ui` | `@crema/content-media-ui` | Media library, image gallery, video/audio players, lightbox |
|
||||
| `content-ui` | `@crema/content-ui` | Article display, prose styles, table of contents, callouts |
|
||||
| `crm-ui` | `@crema/crm-ui` | CRM-domain primitives in two registers sharing the same Deal/Contact/Company/Activity types (Deal includes probability for forecasting; C… |
|
||||
| `dashboard-ui` | `@crema/dashboard-ui` | Stat cards, KPI tiles, gauges, sparklines, heatmap calendar |
|
||||
| `data-ui` | `@crema/data-ui` | Lists, key-value, definition rows, descriptive blocks |
|
||||
| `diagram-ui` | `@crema/diagram-ui` | Node graphs, flow diagrams, swimlanes, sequence diagrams |
|
||||
| `ehr-ui` | `@crema/ehr-ui` | EHR primitives in two registers, sharing Patient/Vital/Medication/Allergy/LabResult/Order/ProblemListItem/Encounter types. Plain: Patient… |
|
||||
| `eval-ui` | `@crema/eval-ui` | Eval result UI: score cards, A/B comparison rows, run grids, score distributions. |
|
||||
| `feedback-ui` | `@crema/feedback-ui` | Alerts, banners, empty states, error boundaries |
|
||||
| `file-ui` | `@crema/file-ui` | Dropzone, file grid/list, previewers, upload progress, browser |
|
||||
| `fleetops-ui` | `@crema/fleetops-ui` | Air traffic / fleet ops: radar map, flight strips, status badges, schedule gantt, weather, runway load, aircraft health, crew |
|
||||
| `flow-ui` | `@crema/flow-ui` | Workflow / state-machine canvas: drag nodes, draw edges, execute with branching decisions. |
|
||||
| `form-ui` | `@crema/form-ui` | Forms, fields, validation, multi-step wizards |
|
||||
| `futurecafe-ui` | `@crema/futurecafe-ui` | Near-future café barista dashboard: AI↔AI handshake summary, customer card with mood/vibe, pedestrian approach map, arrival countdown, or… |
|
||||
| `inflight-aurora-ui` | `@crema/inflight-aurora-ui` | Near-future supersonic cabin UI (second theme): glassmorphism aurora aesthetic — flight arc globe, trip timeline, ETA, altitude strip, ov… |
|
||||
| `inflight-ui` | `@crema/inflight-ui` | Near-future luxury inflight passenger UI: flight map arc, trip timeline, ETA, altitude strip, gourmet menu, order tray, cabin mood, windo… |
|
||||
| `kanban-ui` | `@crema/kanban-ui` | Kanban board, draggable cards, columns, swimlanes |
|
||||
| `layout-ui` | `@crema/layout-ui` | Grids, stacks, dividers, sidebars, scroll areas |
|
||||
| `log-ui` | `@crema/log-ui` | Streamed log viewer: level filter, structured-field expansion, follow-mode auto-scroll, pause/resume/clear. |
|
||||
| `map-ui` | `@crema/map-ui` | SVG maps (world, US states), choropleth, spatial primitives, game grid |
|
||||
| `morph-ui` | `@crema/morph-ui` | Shared-element container primitive: tiles with icon/card/workspace states, FLIP transitions, body-portaled workspace with grid-centered l… |
|
||||
| `motorsport-ui` | `@crema/motorsport-ui` | F1 / motorsport: animated track map, telemetry cluster, tyre + sector badges, lap timing tower, race control, stint chart, pit stop seque… |
|
||||
| `onboarding-ui` | `@crema/onboarding-ui` | Welcome cards, checklists, wizards, coachmarks, product tours |
|
||||
| `presence-ui` | `@crema/presence-ui` | Human + agent presence layer: avatars, ambient strips, rails, workspace panel, proposals with voting, interrupt dock, inline threads, cro… |
|
||||
| `print-ui` | `@crema/print-ui` | Print provider, page sizes, invoice/receipt/label/badge templates |
|
||||
| `prompt-ui` | `@crema/prompt-ui` | Prompt + template authoring: variable highlighting, token estimation, version diff. |
|
||||
| `property-man-ui` | `@crema/property-man-ui` | Real estate listings, property cards, gallery, filter facets, mortgage calculator, agent cards |
|
||||
| `rag-ui` | `@crema/rag-ui` | Retrieval result UI: ranked chunks with highlighted spans, source attribution, retriever comparison. |
|
||||
| `search-ui` | `@crema/search-ui` | Search input, command palette, facets, query tokens |
|
||||
| `settings-ui` | `@crema/settings-ui` | Settings shell, preferences, profile, API keys, danger zone |
|
||||
| `status-ui` | `@crema/status-ui` | System status board: components with uptime grids, incident timeline, maintenance windows. Renders subgrid-aligned bars across rows. |
|
||||
| `table-ui` | `@crema/table-ui` | Sortable tables, row selection, pagination, sticky headers |
|
||||
| `tool-ui` | `@crema/tool-ui` | Agentic tool catalog, schema editor, and mock-execution preview. Pairs with agent-ui (single-call display) as the management surface for … |
|
||||
| `typography-ui` | `@crema/typography-ui` | Type scale, font specimens, prose blocks |
|
||||
|
||||
## Other themes (5)
|
||||
|
||||
Swap by changing the `@import "../../lib-theme-<name>/theme.css"` line at the top of `app/app.css`.
|
||||
|
||||
| Theme | Dark mode | Purpose |
|
||||
|---|---|---|
|
||||
| `arcade` | dark-only | Gaming-shell theme: dark-first cobalt canvas, electric-cyan CTA, neon burst accents, sharper radii, snappier motion. For app surfaces around a game (lobby, s… |
|
||||
| `caffe-florian` | supported | Editorial theme for content-first apps — cream parchment surfaces, Venetian red accent, Libre Baskerville display + DM Sans body. Generous line-heights, soft… |
|
||||
| `otium` | supported | Pristine UI's Apple-inspired glass aesthetic with generous, spacious typography. Sharp clean translucent surfaces, hairline borders, vibrancy stack. More rel… |
|
||||
| `pristine` | supported | Apple-inspired glass design system with translucent surfaces, spring motion, and SF/Inter typography. |
|
||||
| `swish` | supported | Touchscreen Apple-feel theme for shared surfaces (inflight seatback, automotive passenger, kiosks). Saturated-and-serene sky canvas with opaque matte chiclet… |
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"build": "react-router build",
|
||||
"dev": "react-router dev",
|
||||
"start": "react-router-serve ./build/server/index.js",
|
||||
"typecheck": "react-router typegen && tsc"
|
||||
"typecheck": "react-router typegen && tsc",
|
||||
"sync-libs": "node scripts/sync-libs.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.4.0",
|
||||
|
||||
212
scripts/sync-libs.mjs
Normal file
212
scripts/sync-libs.mjs
Normal file
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env node
|
||||
// Refresh docs/LIBS.md from the live crema-manifest. Reads this project's
|
||||
// tsconfig.json + app.css to figure out which libs/themes are "wired in",
|
||||
// clones the manifest, and emits a markdown table for each (wired vs
|
||||
// available). Run after `crema add <lib>`, or whenever you want a fresh
|
||||
// catalog snapshot for the development LLM to consult.
|
||||
//
|
||||
// Usage: npm run sync-libs
|
||||
//
|
||||
// The output is intentionally compact — terse one-line descriptions, alpha
|
||||
// sort, no front-matter. CLAUDE.md points at LIBS.md so the LLM finds it.
|
||||
|
||||
import { execSync } from "node:child_process"
|
||||
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join, resolve, dirname } from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
||||
const MANIFEST_REPO = "https://git.sky-ai.com/CremaUIStudio/crema-manifest.git"
|
||||
|
||||
function readJson(path) {
|
||||
return JSON.parse(readFileSync(path, "utf8"))
|
||||
}
|
||||
|
||||
function readJsonc(path) {
|
||||
// tsconfig.json sometimes has // and /* */ comments. Strip them, but only
|
||||
// outside strings (so https:// URLs inside string values survive).
|
||||
const raw = readFileSync(path, "utf8")
|
||||
let out = ""
|
||||
let i = 0
|
||||
let inString = false
|
||||
while (i < raw.length) {
|
||||
const c = raw[i]
|
||||
const c2 = raw[i + 1]
|
||||
if (inString) {
|
||||
out += c
|
||||
if (c === "\\" && i + 1 < raw.length) {
|
||||
out += raw[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if (c === '"') inString = false
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (c === '"') {
|
||||
inString = true
|
||||
out += c
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (c === "/" && c2 === "/") {
|
||||
while (i < raw.length && raw[i] !== "\n") i++
|
||||
continue
|
||||
}
|
||||
if (c === "/" && c2 === "*") {
|
||||
i += 2
|
||||
while (i < raw.length - 1 && !(raw[i] === "*" && raw[i + 1] === "/")) i++
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
out += c
|
||||
i++
|
||||
}
|
||||
return JSON.parse(out)
|
||||
}
|
||||
|
||||
function cloneManifest() {
|
||||
const dir = mkdtempSync(join(tmpdir(), "crema-manifest-"))
|
||||
execSync(`git clone --depth 1 --quiet ${MANIFEST_REPO} ${dir}`, {
|
||||
stdio: "ignore",
|
||||
})
|
||||
return readJson(join(dir, "manifest.json"))
|
||||
}
|
||||
|
||||
function detectWiredLibs(tsconfigPath) {
|
||||
const ts = readJsonc(tsconfigPath)
|
||||
const paths = ts?.compilerOptions?.paths ?? {}
|
||||
const wired = new Set()
|
||||
for (const key of Object.keys(paths)) {
|
||||
const m = /^@crema\/([a-z0-9-]+)$/.exec(key)
|
||||
if (m) wired.add(m[1])
|
||||
}
|
||||
return [...wired].sort()
|
||||
}
|
||||
|
||||
function detectWiredThemes(cssPath) {
|
||||
const css = readFileSync(cssPath, "utf8")
|
||||
const re = /@import\s+["']\.\.\/\.\.\/lib-theme-([a-z0-9-]+)\/theme\.css["']/g
|
||||
const wired = new Set()
|
||||
let m
|
||||
while ((m = re.exec(css)) !== null) wired.add(m[1])
|
||||
return [...wired].sort()
|
||||
}
|
||||
|
||||
function row(entry) {
|
||||
const desc = (entry.description ?? "").replace(/\s+/g, " ").trim()
|
||||
const oneline = desc.length > 140 ? desc.slice(0, 137) + "…" : desc
|
||||
return `| \`${entry.name}\` | \`${entry.alias ?? `@crema/${entry.name}`}\` | ${oneline} |`
|
||||
}
|
||||
|
||||
function themeRow(entry) {
|
||||
const desc = (entry.description ?? "").replace(/\s+/g, " ").trim()
|
||||
const oneline = desc.length > 160 ? desc.slice(0, 157) + "…" : desc
|
||||
return `| \`${entry.name}\` | ${entry.darkMode ?? "—"} | ${oneline} |`
|
||||
}
|
||||
|
||||
function buildMarkdown(manifest, wiredLibs, wiredThemes) {
|
||||
const libs = [...(manifest.libs ?? [])].sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
)
|
||||
const themes = [...(manifest.themes ?? [])].sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
)
|
||||
|
||||
const wiredSet = new Set(wiredLibs)
|
||||
const wiredThemeSet = new Set(wiredThemes)
|
||||
|
||||
const wiredLibEntries = libs.filter((l) => wiredSet.has(l.name))
|
||||
const availableLibEntries = libs.filter((l) => !wiredSet.has(l.name))
|
||||
const wiredThemeEntries = themes.filter((t) => wiredThemeSet.has(t.name))
|
||||
const availableThemeEntries = themes.filter((t) => !wiredThemeSet.has(t.name))
|
||||
|
||||
const wiredOnlyNotInManifest = wiredLibs.filter(
|
||||
(n) => !libs.some((l) => l.name === n),
|
||||
)
|
||||
|
||||
const lines = []
|
||||
lines.push(
|
||||
`# Available Crema libs`,
|
||||
``,
|
||||
`> Generated by \`scripts/sync-libs.mjs\` from crema-manifest@${manifest.version}.`,
|
||||
`> Run \`npm run sync-libs\` to refresh.`,
|
||||
``,
|
||||
`Every \`@crema/*-ui\` lib is its own git repo at`,
|
||||
`\`https://git.sky-ai.com/CremaUIStudio/lib-<name>-ui\`. To add one, clone it`,
|
||||
`as a sibling of this project, then add the tsconfig path entry and the`,
|
||||
`\`@source\` line to \`app/app.css\` (the marker comments make this easy).`,
|
||||
``,
|
||||
`## Wired in this project (${wiredLibEntries.length})`,
|
||||
``,
|
||||
`These are importable from your code right now (\`import { … } from "@crema/<name>"\`):`,
|
||||
``,
|
||||
`| Lib | Alias | Purpose |`,
|
||||
`|---|---|---|`,
|
||||
...wiredLibEntries.map(row),
|
||||
``,
|
||||
)
|
||||
|
||||
if (wiredOnlyNotInManifest.length) {
|
||||
lines.push(
|
||||
`> ⚠ Wired in tsconfig but not in the manifest catalog: ${wiredOnlyNotInManifest.map((n) => `\`${n}\``).join(", ")}. Probably an internal or experimental lib.`,
|
||||
``,
|
||||
)
|
||||
}
|
||||
|
||||
lines.push(
|
||||
`## Active theme${wiredThemeEntries.length === 1 ? "" : "s"}`,
|
||||
``,
|
||||
`| Theme | Dark mode | Purpose |`,
|
||||
`|---|---|---|`,
|
||||
...(wiredThemeEntries.length
|
||||
? wiredThemeEntries.map(themeRow)
|
||||
: ["| (none detected) | — | — |"]),
|
||||
``,
|
||||
`## Available to add (${availableLibEntries.length})`,
|
||||
``,
|
||||
`From the manifest. To wire one in: \`crema add <name>\` (CLI), or`,
|
||||
`manually clone the repo + edit \`tsconfig.json\` paths + \`app/app.css\``,
|
||||
`\`@source\`.`,
|
||||
``,
|
||||
`| Lib | Alias | Purpose |`,
|
||||
`|---|---|---|`,
|
||||
...availableLibEntries.map(row),
|
||||
``,
|
||||
)
|
||||
|
||||
if (availableThemeEntries.length) {
|
||||
lines.push(
|
||||
`## Other themes (${availableThemeEntries.length})`,
|
||||
``,
|
||||
`Swap by changing the \`@import "../../lib-theme-<name>/theme.css"\` line at the top of \`app/app.css\`.`,
|
||||
``,
|
||||
`| Theme | Dark mode | Purpose |`,
|
||||
`|---|---|---|`,
|
||||
...availableThemeEntries.map(themeRow),
|
||||
``,
|
||||
)
|
||||
}
|
||||
|
||||
return lines.join("\n")
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log("→ cloning manifest…")
|
||||
const manifest = cloneManifest()
|
||||
console.log(` manifest@${manifest.version} (${(manifest.libs ?? []).length} libs, ${(manifest.themes ?? []).length} themes)`)
|
||||
|
||||
const wiredLibs = detectWiredLibs(join(ROOT, "tsconfig.json"))
|
||||
console.log(`→ wired libs: ${wiredLibs.length} (${wiredLibs.join(", ") || "(none)"})`)
|
||||
|
||||
const wiredThemes = detectWiredThemes(join(ROOT, "app", "app.css"))
|
||||
console.log(`→ wired themes: ${wiredThemes.length} (${wiredThemes.join(", ") || "(none)"})`)
|
||||
|
||||
const md = buildMarkdown(manifest, wiredLibs, wiredThemes)
|
||||
const outPath = join(ROOT, "docs", "LIBS.md")
|
||||
writeFileSync(outPath, md + "\n")
|
||||
console.log(`→ wrote ${outPath} (${md.length} chars)`)
|
||||
}
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user