rafters 0.0.5 → 0.0.6

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.
Files changed (3) hide show
  1. package/README.md +130 -0
  2. package/dist/index.js +218 -56
  3. package/package.json +2 -1
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # rafters
2
+
3
+ Design Intelligence CLI. Scaffold tokens, add components, and serve an MCP server so AI agents build UIs with designer-level judgment instead of guessing.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx rafters init
9
+ ```
10
+
11
+ Or install globally:
12
+
13
+ ```bash
14
+ pnpm add -g rafters
15
+ ```
16
+
17
+ ## Commands
18
+
19
+ ### `rafters init`
20
+
21
+ Initialize a project with design tokens. Detects your framework, scaffolds `.rafters/` with a complete token system, and generates output files.
22
+
23
+ ```bash
24
+ rafters init # Interactive setup
25
+ rafters init --force # Regenerate output from existing config
26
+ rafters init --agent # JSON output for CI/machine consumption
27
+ ```
28
+
29
+ **Supported frameworks:** Next.js, Vite, Remix, React Router, Astro
30
+
31
+ **Export formats** (configured during init):
32
+
33
+ | Format | File | Default | Description |
34
+ |--------|------|---------|-------------|
35
+ | Tailwind CSS | `rafters.css` | Yes | CSS custom properties with `@theme` |
36
+ | TypeScript | `rafters.ts` | Yes | Type-safe constants with JSDoc intelligence |
37
+ | DTCG JSON | `rafters.json` | No | W3C Design Tokens standard format |
38
+ | Compiled CSS | `rafters.compiled.css` | No | Pre-processed, no build step needed |
39
+
40
+ Automatically detects and migrates existing shadcn/ui color values. Requires Tailwind v4.
41
+
42
+ ### `rafters add [components...]`
43
+
44
+ Add components from the Rafters registry to your project.
45
+
46
+ ```bash
47
+ rafters add button dialog # Add specific components
48
+ rafters add --list # List all available components
49
+ rafters add --overwrite # Replace existing files
50
+ ```
51
+
52
+ Components include embedded design intelligence: cognitive load ratings (1-7), accessibility requirements, do/never guidance, and trust-building patterns. Dependencies are resolved automatically.
53
+
54
+ ### `rafters studio`
55
+
56
+ Launch Studio for visual token editing.
57
+
58
+ ```bash
59
+ rafters studio
60
+ ```
61
+
62
+ Opens a Vite-powered UI where you design by doing: pick a primary color, explain why, watch the system paint your scale. Every decision is recorded with reasoning so AI agents read intent instead of guessing.
63
+
64
+ ### `rafters mcp`
65
+
66
+ Start the MCP server for AI agent access via stdio transport.
67
+
68
+ ```bash
69
+ rafters mcp
70
+ ```
71
+
72
+ ## MCP Tools
73
+
74
+ Four tools give AI agents complete design system access:
75
+
76
+ ### `rafters_vocabulary`
77
+
78
+ System overview. Colors, spacing, typography, components, cognitive loads, and available patterns. Call this first to orient.
79
+
80
+ ### `rafters_pattern`
81
+
82
+ Deep guidance for specific UI scenarios. Returns which components to use, which tokens to apply, accessibility requirements, and do/never rules.
83
+
84
+ **Available patterns:** `destructive-action`, `form-validation`, `empty-state`, `loading-state`, `navigation-hierarchy`, `data-table`, `modal-dialog`, `tooltip-guidance`, `card-layout`, `dropdown-actions`
85
+
86
+ ### `rafters_component`
87
+
88
+ Full intelligence for a specific component. Cognitive load rating, attention economics, accessibility requirements, trust-building patterns, variants, sizes, and primitives.
89
+
90
+ ### `rafters_token`
91
+
92
+ Token dependency graph, derivation rules, and human override context. Returns how a token is computed, what it depends on, and whether a designer manually overrode it (with their reasoning).
93
+
94
+ **Derivation rules:** `calc()`, `state:hover`, `scale:600`, `contrast:auto`, `invert`
95
+
96
+ ## How It Works
97
+
98
+ Rafters is a Design Intelligence Protocol. AI agents don't have taste - they guess at colors, spacing, hierarchy. Rafters encodes a designer's judgment into queryable data so AI reads decisions instead of guessing.
99
+
100
+ Three layers:
101
+
102
+ - **What** (Components) - 55 React components with embedded intelligence metadata
103
+ - **Where** (Tokens) - 240+ tokens with dependency graph and human override tracking
104
+ - **Why** (Decisions) - Do/never patterns, cognitive load scores, trust patterns, accessibility requirements
105
+
106
+ The token system uses OKLCH color space, modular scales based on musical ratios, and a dependency engine that automatically derives related values. When a designer overrides a computed value, the system records the reason so AI agents respect the intent.
107
+
108
+ ## Project Structure
109
+
110
+ ```
111
+ .rafters/
112
+ config.rafters.json # Framework paths and export settings
113
+ tokens/
114
+ color.rafters.json # Color tokens with OKLCH values
115
+ spacing.rafters.json # Spacing scale
116
+ typography.rafters.json # Type scale
117
+ output/
118
+ rafters.css # Tailwind CSS export
119
+ rafters.ts # TypeScript constants
120
+ ```
121
+
122
+ ## Requirements
123
+
124
+ - Node.js >= 24.12.0
125
+ - Tailwind CSS v4
126
+ - React >= 19.0.0
127
+
128
+ ## License
129
+
130
+ MIT
package/dist/index.js CHANGED
@@ -12730,7 +12730,7 @@ function setAgentMode(agent) {
12730
12730
  }
12731
12731
  function log(event) {
12732
12732
  if (context.agent) {
12733
- console.log(event);
12733
+ console.log(JSON.stringify(event));
12734
12734
  return;
12735
12735
  }
12736
12736
  const eventType = event.event;
@@ -12748,13 +12748,14 @@ function log(event) {
12748
12748
  }
12749
12749
  context.spinner = ora("Generating tokens...").start();
12750
12750
  break;
12751
- case "init:shadcn_detected":
12751
+ case "init:shadcn_detected": {
12752
12752
  context.spinner?.info("Found existing shadcn colors");
12753
12753
  console.log(` Backed up: ${event.backupPath}`);
12754
12754
  const colors = event.colorsFound;
12755
12755
  console.log(` Colors: ${colors.light} light, ${colors.dark} dark`);
12756
12756
  context.spinner = ora("Generating tokens...").start();
12757
12757
  break;
12758
+ }
12758
12759
  case "init:generated":
12759
12760
  context.spinner?.succeed(`Generated ${event.tokenCount} tokens`);
12760
12761
  context.spinner = ora("Saving registry...").start();
@@ -12782,7 +12783,18 @@ function log(event) {
12782
12783
  case "init:colors_imported":
12783
12784
  console.log(` Imported ${event.count} existing colors`);
12784
12785
  break;
12785
- case "init:complete":
12786
+ case "init:exports_default":
12787
+ console.log(" Using default exports (agent mode)");
12788
+ break;
12789
+ case "init:exports_selected":
12790
+ context.spinner = ora("Generating outputs...").start();
12791
+ break;
12792
+ case "init:compiling_css":
12793
+ if (context.spinner) {
12794
+ context.spinner.text = "Compiling CSS with Tailwind...";
12795
+ }
12796
+ break;
12797
+ case "init:complete": {
12786
12798
  context.spinner?.succeed("Done!");
12787
12799
  console.log(`
12788
12800
  Output: ${event.path}`);
@@ -12792,12 +12804,14 @@ function log(event) {
12792
12804
  }
12793
12805
  console.log("");
12794
12806
  break;
12807
+ }
12795
12808
  // Add events
12796
- case "add:start":
12809
+ case "add:start": {
12797
12810
  const components = event.components;
12798
12811
  context.spinner = ora(`Adding ${components.join(", ")}...`).start();
12799
12812
  break;
12800
- case "add:installed":
12813
+ }
12814
+ case "add:installed": {
12801
12815
  context.spinner?.succeed(`Installed ${event.component}`);
12802
12816
  const files = event.files;
12803
12817
  for (const file2 of files) {
@@ -12805,6 +12819,7 @@ function log(event) {
12805
12819
  }
12806
12820
  context.spinner = ora("Installing...").start();
12807
12821
  break;
12822
+ }
12808
12823
  case "add:skip":
12809
12824
  context.spinner?.warn(`Skipped ${event.component} (already exists)`);
12810
12825
  context.spinner = ora("Installing...").start();
@@ -12843,7 +12858,7 @@ function log(event) {
12843
12858
  }
12844
12859
  function error46(message) {
12845
12860
  if (context.agent) {
12846
- console.error({ event: "error", message });
12861
+ console.error(JSON.stringify({ event: "error", message }));
12847
12862
  return;
12848
12863
  }
12849
12864
  context.spinner?.fail(message);
@@ -12932,7 +12947,11 @@ async function loadConfig(cwd) {
12932
12947
  try {
12933
12948
  const content = await readFile(paths.config, "utf-8");
12934
12949
  return JSON.parse(content);
12935
- } catch {
12950
+ } catch (err) {
12951
+ if (existsSync(paths.config)) {
12952
+ const message = err instanceof Error ? err.message : String(err);
12953
+ log({ event: "add:warning", message: `Failed to load config: ${message}` });
12954
+ }
12936
12955
  return null;
12937
12956
  }
12938
12957
  }
@@ -12965,12 +12984,13 @@ function transformFileContent(content, config3) {
12965
12984
  /from\s+['"]\.\/([^'"]+)['"]/g,
12966
12985
  `from '@/${componentsPath}/$1'`
12967
12986
  );
12968
- const libPath = primitivesPath.replace(/\/primitives$/, "");
12987
+ const libPath = dirname(primitivesPath);
12969
12988
  transformed = transformed.replace(
12970
12989
  /from\s+['"]\.\.\/lib\/([^'"]+)['"]/g,
12971
12990
  `from '@/${libPath}/$1'`
12972
12991
  );
12973
- const hooksPath = componentsPath.replace(/components\/ui$/, "hooks");
12992
+ const componentsMatch = componentsPath.match(/^(.*)components\/ui$/);
12993
+ const hooksPath = componentsMatch ? `${componentsMatch[1]}hooks`.replace(/^\//, "") : "hooks";
12974
12994
  transformed = transformed.replace(
12975
12995
  /from\s+['"]\.\.\/hooks\/([^'"]+)['"]/g,
12976
12996
  `from '@/${hooksPath}/$1'`
@@ -13123,9 +13143,10 @@ async function add(components, options) {
13123
13143
  }
13124
13144
 
13125
13145
  // src/commands/init.ts
13126
- import { existsSync as existsSync2 } from "fs";
13146
+ import { checkbox } from "@inquirer/prompts";
13147
+ import { existsSync as existsSync3 } from "fs";
13127
13148
  import { copyFile, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
13128
- import { join as join8, relative } from "path";
13149
+ import { join as join9, relative } from "path";
13129
13150
 
13130
13151
  // ../design-tokens/src/generation-rules.ts
13131
13152
  var GenerationRuleParser = class {
@@ -24155,7 +24176,7 @@ var require_volume = __commonJS({
24155
24176
  var Dir_1 = require_Dir();
24156
24177
  var resolveCrossPlatform = pathModule.resolve;
24157
24178
  var { O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_DIRECTORY, O_SYMLINK, F_OK, COPYFILE_EXCL, COPYFILE_FICLONE_FORCE } = constants_1.constants;
24158
- var { sep: sep2, relative: relative2, join: join11, dirname: dirname4 } = pathModule.posix ? pathModule.posix : pathModule;
24179
+ var { sep: sep2, relative: relative2, join: join12, dirname: dirname4 } = pathModule.posix ? pathModule.posix : pathModule;
24159
24180
  var kMinPoolSpace = 128;
24160
24181
  var EPERM = "EPERM";
24161
24182
  var ENOENT2 = "ENOENT";
@@ -24221,7 +24242,7 @@ var require_volume = __commonJS({
24221
24242
  function flatten(pathPrefix, node) {
24222
24243
  for (const path2 in node) {
24223
24244
  const contentOrNode = node[path2];
24224
- const joinedPath = join11(pathPrefix, path2);
24245
+ const joinedPath = join12(pathPrefix, path2);
24225
24246
  if (typeof contentOrNode === "string" || contentOrNode instanceof buffer_1.Buffer) {
24226
24247
  flatJSON[joinedPath] = contentOrNode;
24227
24248
  } else if (typeof contentOrNode === "object" && contentOrNode !== null && Object.keys(contentOrNode).length > 0) {
@@ -24378,7 +24399,7 @@ var require_volume = __commonJS({
24378
24399
  return null;
24379
24400
  node = curr === null || curr === void 0 ? void 0 : curr.getNode();
24380
24401
  if (resolveSymlinks && node.isSymlink()) {
24381
- const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join11(pathModule.dirname(curr.getPath()), node.symlink);
24402
+ const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join12(pathModule.dirname(curr.getPath()), node.symlink);
24382
24403
  steps = filenameToSteps(resolvedPath).concat(steps.slice(i + 1));
24383
24404
  curr = this.root;
24384
24405
  i = 0;
@@ -49133,7 +49154,7 @@ function tagTokenizer() {
49133
49154
 
49134
49155
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/type.js
49135
49156
  function typeTokenizer(spacing = "compact") {
49136
- const join11 = getJoiner(spacing);
49157
+ const join12 = getJoiner(spacing);
49137
49158
  return (spec) => {
49138
49159
  let curlies = 0;
49139
49160
  let lines = [];
@@ -49176,7 +49197,7 @@ function typeTokenizer(spacing = "compact") {
49176
49197
  }
49177
49198
  parts[0] = parts[0].slice(1);
49178
49199
  parts[parts.length - 1] = parts[parts.length - 1].slice(0, -1);
49179
- spec.type = join11(parts);
49200
+ spec.type = join12(parts);
49180
49201
  return spec;
49181
49202
  };
49182
49203
  }
@@ -49274,9 +49295,9 @@ function nameTokenizer() {
49274
49295
 
49275
49296
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/description.js
49276
49297
  function descriptionTokenizer(spacing = "compact", markers = Markers) {
49277
- const join11 = getJoiner2(spacing);
49298
+ const join12 = getJoiner2(spacing);
49278
49299
  return (spec) => {
49279
- spec.description = join11(spec.source, markers);
49300
+ spec.description = join12(spec.source, markers);
49280
49301
  return spec;
49281
49302
  };
49282
49303
  }
@@ -50132,6 +50153,79 @@ async function detectProject(cwd) {
50132
50153
  };
50133
50154
  }
50134
50155
 
50156
+ // src/utils/exports.ts
50157
+ import { execFileSync } from "child_process";
50158
+ import { existsSync as existsSync2 } from "fs";
50159
+ import { join as join8 } from "path";
50160
+ var DEFAULT_EXPORTS = {
50161
+ tailwind: true,
50162
+ typescript: true,
50163
+ dtcg: false,
50164
+ compiled: false
50165
+ };
50166
+ var EXPORT_CHOICES = [
50167
+ {
50168
+ name: "Tailwind CSS (web projects)",
50169
+ value: "tailwind",
50170
+ checked: true
50171
+ },
50172
+ {
50173
+ name: "TypeScript (type-safe constants)",
50174
+ value: "typescript",
50175
+ checked: true
50176
+ },
50177
+ {
50178
+ name: "DTCG JSON (Figma Tokens, Style Dictionary)",
50179
+ value: "dtcg",
50180
+ checked: false
50181
+ },
50182
+ {
50183
+ name: "Compiled CSS (documentation, no build step)",
50184
+ value: "compiled",
50185
+ checked: false
50186
+ }
50187
+ ];
50188
+ var FUTURE_EXPORTS = [
50189
+ {
50190
+ name: "iOS (Swift/SwiftUI)",
50191
+ value: "tailwind",
50192
+ // placeholder
50193
+ checked: false,
50194
+ disabled: "coming soon"
50195
+ },
50196
+ {
50197
+ name: "Android (Compose)",
50198
+ value: "tailwind",
50199
+ // placeholder
50200
+ checked: false,
50201
+ disabled: "coming soon"
50202
+ }
50203
+ ];
50204
+ async function generateCompiledCss(cwd, inputPath, outputPath) {
50205
+ const nodeModulesBin = join8(cwd, "node_modules", ".bin", "tailwindcss");
50206
+ const hasTailwindCli = existsSync2(nodeModulesBin);
50207
+ const args = ["-i", inputPath, "-o", outputPath, "--minify"];
50208
+ if (hasTailwindCli) {
50209
+ execFileSync(nodeModulesBin, args, { cwd, stdio: "pipe" });
50210
+ } else {
50211
+ try {
50212
+ execFileSync("pnpm", ["exec", "tailwindcss", ...args], { cwd, stdio: "pipe" });
50213
+ } catch {
50214
+ throw new Error(
50215
+ "Tailwind CLI not found. Install it with: pnpm add -D @tailwindcss/cli"
50216
+ );
50217
+ }
50218
+ }
50219
+ }
50220
+ function selectionsToConfig(selections) {
50221
+ return {
50222
+ tailwind: selections.includes("tailwind"),
50223
+ typescript: selections.includes("typescript"),
50224
+ dtcg: selections.includes("dtcg"),
50225
+ compiled: selections.includes("compiled")
50226
+ };
50227
+ }
50228
+
50135
50229
  // src/commands/init.ts
50136
50230
  async function backupCss(cssPath) {
50137
50231
  const backupPath = cssPath.replace(/\.css$/, ".backup.css");
@@ -50157,20 +50251,20 @@ var COMPONENT_PATHS = {
50157
50251
  async function findMainCssFile(cwd, framework) {
50158
50252
  const locations = CSS_LOCATIONS[framework] || CSS_LOCATIONS.unknown;
50159
50253
  for (const location of locations) {
50160
- const fullPath = join8(cwd, location);
50161
- if (existsSync2(fullPath)) {
50254
+ const fullPath = join9(cwd, location);
50255
+ if (existsSync3(fullPath)) {
50162
50256
  return location;
50163
50257
  }
50164
50258
  }
50165
50259
  return null;
50166
50260
  }
50167
50261
  async function updateMainCss(cwd, cssPath, themePath) {
50168
- const fullCssPath = join8(cwd, cssPath);
50262
+ const fullCssPath = join9(cwd, cssPath);
50169
50263
  const cssContent = await readFile4(fullCssPath, "utf-8");
50170
- const cssDir = join8(cwd, cssPath, "..");
50171
- const themeFullPath = join8(cwd, themePath);
50264
+ const cssDir = join9(cwd, cssPath, "..");
50265
+ const themeFullPath = join9(cwd, themePath);
50172
50266
  const relativeThemePath = relative(cssDir, themeFullPath);
50173
- if (cssContent.includes(".rafters/output/theme.css")) {
50267
+ if (cssContent.includes(".rafters/output/rafters.css")) {
50174
50268
  log({ event: "init:css_already_imported", cssPath });
50175
50269
  return;
50176
50270
  }
@@ -50192,8 +50286,66 @@ ${cssContent}`;
50192
50286
  themePath: relativeThemePath
50193
50287
  });
50194
50288
  }
50195
- async function regenerateFromExisting(cwd, paths, shadcn) {
50289
+ async function promptExportFormats(existingConfig) {
50290
+ const choices = EXPORT_CHOICES.map((choice) => ({
50291
+ name: choice.name,
50292
+ value: choice.value,
50293
+ checked: existingConfig ? existingConfig[choice.value] : choice.checked
50294
+ }));
50295
+ const allChoices = [
50296
+ ...choices,
50297
+ ...FUTURE_EXPORTS.map((choice) => ({
50298
+ name: `${choice.name} (${choice.disabled})`,
50299
+ value: choice.value,
50300
+ checked: false,
50301
+ disabled: true
50302
+ }))
50303
+ ];
50304
+ const selections = await checkbox({
50305
+ message: "What would you like to export?",
50306
+ choices: allChoices,
50307
+ required: true
50308
+ });
50309
+ return selectionsToConfig(selections);
50310
+ }
50311
+ async function generateOutputs(cwd, paths, registry2, exports, shadcn) {
50312
+ const outputs = [];
50313
+ if (exports.tailwind) {
50314
+ const tailwindCss = registryToTailwind(registry2, { includeImport: !shadcn });
50315
+ await writeFile3(join9(paths.output, "rafters.css"), tailwindCss);
50316
+ outputs.push("rafters.css");
50317
+ }
50318
+ if (exports.typescript) {
50319
+ const typescriptSrc = registryToTypeScript(registry2, { includeJSDoc: true });
50320
+ await writeFile3(join9(paths.output, "rafters.ts"), typescriptSrc);
50321
+ outputs.push("rafters.ts");
50322
+ }
50323
+ if (exports.dtcg) {
50324
+ const dtcgJson = toDTCG(registry2.list());
50325
+ await writeFile3(join9(paths.output, "rafters.json"), JSON.stringify(dtcgJson, null, 2));
50326
+ outputs.push("rafters.json");
50327
+ }
50328
+ if (exports.compiled) {
50329
+ if (!exports.tailwind) {
50330
+ const tailwindCss = registryToTailwind(registry2, { includeImport: !shadcn });
50331
+ await writeFile3(join9(paths.output, "rafters.css"), tailwindCss);
50332
+ }
50333
+ const inputPath = join9(paths.output, "rafters.css");
50334
+ const outputPath = join9(paths.output, "rafters.compiled.css");
50335
+ log({ event: "init:compiling_css" });
50336
+ await generateCompiledCss(cwd, inputPath, outputPath);
50337
+ outputs.push("rafters.compiled.css");
50338
+ }
50339
+ return outputs;
50340
+ }
50341
+ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode) {
50196
50342
  log({ event: "init:regenerate", cwd });
50343
+ let existingConfig = null;
50344
+ try {
50345
+ const configContent = await readFile4(paths.config, "utf-8");
50346
+ existingConfig = JSON.parse(configContent);
50347
+ } catch {
50348
+ }
50197
50349
  const adapter = new NodePersistenceAdapter(cwd);
50198
50350
  const namespaces = await adapter.listNamespaces();
50199
50351
  if (namespaces.length === 0) {
@@ -50210,21 +50362,27 @@ async function regenerateFromExisting(cwd, paths, shadcn) {
50210
50362
  namespaces
50211
50363
  });
50212
50364
  const registry2 = new TokenRegistry(allTokens);
50213
- const tailwindCss = registryToTailwind(registry2, { includeImport: !shadcn });
50214
- const typescriptSrc = registryToTypeScript(registry2, { includeJSDoc: true });
50215
- const dtcgJson = toDTCG(allTokens);
50365
+ let exports;
50366
+ if (isAgentMode) {
50367
+ exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
50368
+ } else {
50369
+ exports = await promptExportFormats(existingConfig?.exports);
50370
+ }
50216
50371
  await mkdir3(paths.output, { recursive: true });
50217
- await writeFile3(join8(paths.output, "theme.css"), tailwindCss);
50218
- await writeFile3(join8(paths.output, "tokens.ts"), typescriptSrc);
50219
- await writeFile3(join8(paths.output, "tokens.json"), JSON.stringify(dtcgJson, null, 2));
50372
+ const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
50373
+ if (existingConfig) {
50374
+ existingConfig.exports = exports;
50375
+ await writeFile3(paths.config, JSON.stringify(existingConfig, null, 2));
50376
+ }
50220
50377
  log({
50221
50378
  event: "init:complete",
50222
- outputs: ["theme.css", "tokens.ts", "tokens.json"],
50379
+ outputs,
50223
50380
  path: paths.output
50224
50381
  });
50225
50382
  }
50226
50383
  async function init(options) {
50227
50384
  setAgentMode(options.agent ?? false);
50385
+ const isAgentMode = options.agent ?? false;
50228
50386
  const cwd = process.cwd();
50229
50387
  const paths = getRaftersPaths(cwd);
50230
50388
  log({ event: "init:start", cwd });
@@ -50238,19 +50396,19 @@ async function init(options) {
50238
50396
  if (isTailwindV3(tailwindVersion)) {
50239
50397
  throw new Error("Tailwind v3 detected. Rafters requires Tailwind v4.");
50240
50398
  }
50241
- const raftersExists = existsSync2(paths.root);
50399
+ const raftersExists = existsSync3(paths.root);
50242
50400
  if (raftersExists && !options.force) {
50243
50401
  throw new Error(
50244
50402
  ".rafters/ directory already exists. Use --force to regenerate output files from existing config."
50245
50403
  );
50246
50404
  }
50247
50405
  if (raftersExists && options.force) {
50248
- await regenerateFromExisting(cwd, paths, shadcn);
50406
+ await regenerateFromExisting(cwd, paths, shadcn, isAgentMode);
50249
50407
  return;
50250
50408
  }
50251
50409
  let existingColors = null;
50252
50410
  if (shadcn?.tailwind?.css) {
50253
- const cssPath = join8(cwd, shadcn.tailwind.css);
50411
+ const cssPath = join9(cwd, shadcn.tailwind.css);
50254
50412
  try {
50255
50413
  const cssContent = await readFile4(cssPath, "utf-8");
50256
50414
  existingColors = parseCssVariables(cssContent);
@@ -50268,6 +50426,14 @@ async function init(options) {
50268
50426
  log({ event: "init:shadcn_css_error", error: String(err) });
50269
50427
  }
50270
50428
  }
50429
+ let exports;
50430
+ if (isAgentMode) {
50431
+ exports = DEFAULT_EXPORTS;
50432
+ log({ event: "init:exports_default", exports });
50433
+ } else {
50434
+ exports = await promptExportFormats();
50435
+ log({ event: "init:exports_selected", exports });
50436
+ }
50271
50437
  const result = buildColorSystem({
50272
50438
  exports: {
50273
50439
  tailwind: { includeImport: !shadcn },
@@ -50331,21 +50497,16 @@ async function init(options) {
50331
50497
  path: paths.tokens,
50332
50498
  namespaceCount: tokensByNamespace.size
50333
50499
  });
50334
- const tailwindCss = registryToTailwind(registry2, { includeImport: !shadcn });
50335
- const typescriptSrc = registryToTypeScript(registry2, { includeJSDoc: true });
50336
- const dtcgJson = toDTCG(registry2.list());
50337
- await writeFile3(join8(paths.output, "theme.css"), tailwindCss);
50338
- await writeFile3(join8(paths.output, "tokens.ts"), typescriptSrc);
50339
- await writeFile3(join8(paths.output, "tokens.json"), JSON.stringify(dtcgJson, null, 2));
50500
+ const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
50340
50501
  let detectedCssPath = null;
50341
- if (!shadcn) {
50502
+ if (!shadcn && exports.tailwind) {
50342
50503
  detectedCssPath = await findMainCssFile(cwd, framework);
50343
50504
  if (detectedCssPath) {
50344
- await updateMainCss(cwd, detectedCssPath, ".rafters/output/theme.css");
50505
+ await updateMainCss(cwd, detectedCssPath, ".rafters/output/rafters.css");
50345
50506
  } else {
50346
50507
  log({
50347
50508
  event: "init:css_not_found",
50348
- message: 'No main CSS file found. Add @import ".rafters/output/theme.css" manually.',
50509
+ message: 'No main CSS file found. Add @import ".rafters/output/rafters.css" manually.',
50349
50510
  searchedLocations: CSS_LOCATIONS[framework] || CSS_LOCATIONS.unknown
50350
50511
  });
50351
50512
  }
@@ -50357,12 +50518,13 @@ async function init(options) {
50357
50518
  framework,
50358
50519
  componentsPath: frameworkPaths.components,
50359
50520
  primitivesPath: frameworkPaths.primitives,
50360
- cssPath: detectedCssPath
50521
+ cssPath: detectedCssPath,
50522
+ exports
50361
50523
  };
50362
50524
  await writeFile3(paths.config, JSON.stringify(config3, null, 2));
50363
50525
  log({
50364
50526
  event: "init:complete",
50365
- outputs: ["theme.css", "tokens.ts", "tokens.json", "config.rafters.json"],
50527
+ outputs: [...outputs, "config.rafters.json"],
50366
50528
  path: paths.output
50367
50529
  });
50368
50530
  }
@@ -50374,7 +50536,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
50374
50536
 
50375
50537
  // src/mcp/tools.ts
50376
50538
  import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
50377
- import { basename, join as join9 } from "path";
50539
+ import { basename, join as join10 } from "path";
50378
50540
  var DESIGN_PATTERNS = {
50379
50541
  "destructive-action": {
50380
50542
  name: "Destructive Action",
@@ -50924,7 +51086,7 @@ var RaftersToolHandler = class {
50924
51086
  * Get path to UI components directory
50925
51087
  */
50926
51088
  getComponentsPath() {
50927
- const monorepoPath = join9(this.projectRoot, "packages/ui/src/components/ui");
51089
+ const monorepoPath = join10(this.projectRoot, "packages/ui/src/components/ui");
50928
51090
  return monorepoPath;
50929
51091
  }
50930
51092
  /**
@@ -50932,7 +51094,7 @@ var RaftersToolHandler = class {
50932
51094
  */
50933
51095
  async loadComponentMetadata(name2) {
50934
51096
  const componentsPath = this.getComponentsPath();
50935
- const filePath = join9(componentsPath, `${name2}.tsx`);
51097
+ const filePath = join10(componentsPath, `${name2}.tsx`);
50936
51098
  try {
50937
51099
  const source = await readFile5(filePath, "utf-8");
50938
51100
  const intelligence = parseJSDocIntelligence(source);
@@ -51284,22 +51446,22 @@ async function mcp() {
51284
51446
  }
51285
51447
 
51286
51448
  // src/commands/studio.ts
51287
- import { existsSync as existsSync3 } from "fs";
51288
- import { dirname as dirname3, join as join10 } from "path";
51449
+ import { existsSync as existsSync4 } from "fs";
51450
+ import { dirname as dirname3, join as join11 } from "path";
51289
51451
  import { fileURLToPath as fileURLToPath3 } from "url";
51290
51452
  import { execa as execa2 } from "execa";
51291
51453
  var __dirname2 = dirname3(fileURLToPath3(import.meta.url));
51292
51454
  async function studio() {
51293
51455
  const cwd = process.cwd();
51294
51456
  const paths = getRaftersPaths(cwd);
51295
- if (!existsSync3(paths.root)) {
51457
+ if (!existsSync4(paths.root)) {
51296
51458
  console.error('No .rafters/ directory found. Run "rafters init" first.');
51297
51459
  process.exit(1);
51298
51460
  }
51299
- const devStudioPath = join10(__dirname2, "..", "..", "..", "studio");
51300
- const prodStudioPath = join10(__dirname2, "..", "node_modules", "@rafters", "studio");
51301
- const studioPath = existsSync3(devStudioPath) ? devStudioPath : prodStudioPath;
51302
- if (!existsSync3(studioPath)) {
51461
+ const devStudioPath = join11(__dirname2, "..", "..", "..", "studio");
51462
+ const prodStudioPath = join11(__dirname2, "..", "node_modules", "@rafters", "studio");
51463
+ const studioPath = existsSync4(devStudioPath) ? devStudioPath : prodStudioPath;
51464
+ if (!existsSync4(studioPath)) {
51303
51465
  console.error("Studio package not found. Please reinstall @rafters/cli.");
51304
51466
  process.exit(1);
51305
51467
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rafters",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "CLI for Rafters design system - scaffold tokens and add components",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  ],
15
15
  "dependencies": {
16
16
  "@antfu/ni": "^28.1.0",
17
+ "@inquirer/prompts": "^8.2.0",
17
18
  "@modelcontextprotocol/sdk": "^1.25.1",
18
19
  "commander": "^13.0.0",
19
20
  "execa": "^9.6.1",