@reference-ui/core
v0.0.43
Published
Reference UI core
Readme
@reference-ui/core
Reference UI CLI – design system build pipeline.
Commands
ref sync (default)
Build and sync the design system. Uses workers and the event bus.
ref clean
Removes the output directory (.reference-ui). Runs in the main thread only. Use before tests for a fresh state.
ref mcp
Runs the Reference UI MCP server.
ref mcpstarts the stdio server used by MCP clients such as VS Code.ref mcp --transport httpstarts the HTTP server for local inspection and debugging.
Standard VS Code setup
Prefer the published npx form for MCP clients:
{
"servers": {
"referenceUi": {
"type": "stdio",
"command": "npx",
"cwd": "${workspaceFolder}",
"args": ["-y", "--package", "@reference-ui/core", "mcp"]
}
}
}If your MCP client supports cwd, set it to the project whose ui.config.ts
should drive MCP output.
For repo-local development, the direct built CLI path is a deterministic fallback:
{
"servers": {
"referenceUi": {
"type": "stdio",
"command": "node",
"cwd": "${workspaceFolder}/packages/reference-docs",
"args": ["${workspaceFolder}/packages/reference-core/dist/cli/index.mjs", "mcp"]
}
}
}Architecture
Workers run in separate threads (Piscina); they communicate via BroadcastChannel. The main thread wires flow; workers map events to handlers.
Principle: Logic in handler functions; worker file is wiring only.
Event registry
src/events.ts – type union of all events. Each domain defines its slice; the event bus imports for typed emit/on.
// events.ts
export type Events = SyncEvents & VirtualEvents & WatchEventsworkers.json ↔ Thread pool
The pool exposes workers (registry of all possible workers). Manifest keys map to dist/cli/${name}/worker.mjs. workerEntries feeds tsup. Keys only – values exist for tsup paths.
Flow
- Main thread bootstraps, wires flow in an events module.
- Module inits spawn workers via
workers.runWorker(name, payload). - Workers subscribe with
on(...), returnKEEP_ALIVEto stay alive. - Events flow via BroadcastChannel; all threads react.
Module pattern
Worker = flat on(event, handler) list. Logic = handler functions in one file. Orchestration = events module (routing, emit).
Layout: init.ts (spawns worker), worker.ts (wiring only), events.ts (module event types).
Worker
Flat list only. No conditionals, no branching. Multiple handlers per event is fine.
import { emit, on } from '../lib/event-bus'
import { KEEP_ALIVE } from '../lib/thread-pool'
import { copyAll } from './copy-all'
export default async function runVirtual(payload: VirtualWorkerPayload): Promise<never> {
const handler = () => {
copyAll(payload).catch(err => console.error('[virtual] Copy failed:', err))
}
on('run:virtual:copy:all', handler)
emit('virtual:ready')
return KEEP_ALIVE
}Logic
Pure handler functions. They receive payloads; they emit events. No on here.
import { emit } from '../lib/event-bus'
export async function copyAll(payload: VirtualWorkerPayload): Promise<void> {
// ... do work ...
emit('virtual:complete')
}Event wiring (orchestration)
on('virtual:ready', () => emit('run:virtual:copy:all'))
on('watch:change', () => emit('run:virtual:copy:all'))
on('virtual:complete', () => emit('sync:complete'))Adding a module
- Add to
workers.json. - Create
worker.ts(flatonlist), logic file (handlers),init.ts(spawn). - Wire init in the command entry point.
- Define new events in registry if needed.
See src/virtual/ for a working example.
