rafters 0.0.7 → 0.0.9

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/dist/index.js CHANGED
@@ -9,8 +9,8 @@ import { Command } from "commander";
9
9
 
10
10
  // src/commands/add.ts
11
11
  import { existsSync } from "fs";
12
- import { access, mkdir, readFile, writeFile } from "fs/promises";
13
- import { dirname, join as join2 } from "path";
12
+ import { access, mkdir, readFile as readFile2, writeFile } from "fs/promises";
13
+ import { dirname, join as join3 } from "path";
14
14
 
15
15
  // ../../node_modules/.pnpm/zod@4.1.12/node_modules/zod/v4/classic/external.js
16
16
  var external_exports = {};
@@ -12558,10 +12558,16 @@ config(en_default());
12558
12558
  var RegistryFileSchema = external_exports.object({
12559
12559
  path: external_exports.string(),
12560
12560
  content: external_exports.string(),
12561
- dependencies: external_exports.array(external_exports.string())
12561
+ dependencies: external_exports.array(external_exports.string()),
12562
12562
  // e.g., ["lodash@4.17.21"] - versioned
12563
+ devDependencies: external_exports.array(external_exports.string()).default([])
12564
+ // e.g., ["vitest"] - from @devDependencies JSDoc
12563
12565
  });
12564
- var RegistryItemTypeSchema = external_exports.enum(["registry:ui", "registry:primitive"]);
12566
+ var RegistryItemTypeSchema = external_exports.enum([
12567
+ "registry:ui",
12568
+ "registry:primitive",
12569
+ "registry:composite"
12570
+ ]);
12565
12571
  var RegistryItemSchema = external_exports.object({
12566
12572
  name: external_exports.string(),
12567
12573
  type: RegistryItemTypeSchema,
@@ -12714,18 +12720,64 @@ var RegistryClient = class {
12714
12720
  };
12715
12721
  var registryClient = new RegistryClient();
12716
12722
 
12717
- // src/utils/paths.ts
12718
- import { join } from "path";
12719
- function getRaftersPaths(projectRoot = process.cwd()) {
12720
- const root = join(projectRoot, ".rafters");
12723
+ // src/utils/exports.ts
12724
+ var DEFAULT_EXPORTS = {
12725
+ tailwind: true,
12726
+ typescript: true,
12727
+ dtcg: false,
12728
+ compiled: false
12729
+ };
12730
+ var EXPORT_CHOICES = [
12731
+ {
12732
+ name: "Tailwind CSS (web projects)",
12733
+ value: "tailwind",
12734
+ checked: true
12735
+ },
12736
+ {
12737
+ name: "TypeScript (type-safe constants)",
12738
+ value: "typescript",
12739
+ checked: true
12740
+ },
12741
+ {
12742
+ name: "DTCG JSON (Figma Tokens, Style Dictionary)",
12743
+ value: "dtcg",
12744
+ checked: false
12745
+ },
12746
+ {
12747
+ name: "Standalone CSS (pre-built, no Tailwind required)",
12748
+ value: "compiled",
12749
+ checked: false
12750
+ }
12751
+ ];
12752
+ var FUTURE_EXPORTS = [
12753
+ {
12754
+ name: "iOS (Swift/SwiftUI)",
12755
+ value: "tailwind",
12756
+ // placeholder
12757
+ checked: false,
12758
+ disabled: "coming soon"
12759
+ },
12760
+ {
12761
+ name: "Android (Compose)",
12762
+ value: "tailwind",
12763
+ // placeholder
12764
+ checked: false,
12765
+ disabled: "coming soon"
12766
+ }
12767
+ ];
12768
+ function selectionsToConfig(selections) {
12721
12769
  return {
12722
- root,
12723
- config: join(root, "config.rafters.json"),
12724
- tokens: join(root, "tokens"),
12725
- output: join(root, "output")
12770
+ tailwind: selections.includes("tailwind"),
12771
+ typescript: selections.includes("typescript"),
12772
+ dtcg: selections.includes("dtcg"),
12773
+ compiled: selections.includes("compiled")
12726
12774
  };
12727
12775
  }
12728
12776
 
12777
+ // src/utils/install-registry-deps.ts
12778
+ import { readFile } from "fs/promises";
12779
+ import { join } from "path";
12780
+
12729
12781
  // src/utils/ui.ts
12730
12782
  import ora from "ora";
12731
12783
  var context = {
@@ -12735,6 +12787,9 @@ var context = {
12735
12787
  function setAgentMode(agent) {
12736
12788
  context.agent = agent;
12737
12789
  }
12790
+ function isAgentMode() {
12791
+ return context.agent;
12792
+ }
12738
12793
  function log(event) {
12739
12794
  if (context.agent) {
12740
12795
  console.log(JSON.stringify(event));
@@ -12841,8 +12896,9 @@ function log(event) {
12841
12896
  context.spinner?.succeed("Files written");
12842
12897
  const deps = event.dependencies;
12843
12898
  const devDeps = event.devDependencies;
12899
+ const skippedDeps = event.skipped ?? [];
12844
12900
  if (deps.length > 0 || devDeps.length > 0) {
12845
- console.log(" Dependencies to install:");
12901
+ console.log(" Dependencies installed:");
12846
12902
  for (const dep of deps) {
12847
12903
  console.log(` ${dep}`);
12848
12904
  }
@@ -12850,9 +12906,32 @@ function log(event) {
12850
12906
  console.log(` ${dep} (dev)`);
12851
12907
  }
12852
12908
  }
12853
- context.spinner = ora("Installing dependencies...").start();
12909
+ if (skippedDeps.length > 0) {
12910
+ console.log(" Dependencies skipped (already installed or internal):");
12911
+ for (const dep of skippedDeps) {
12912
+ console.log(` ${dep}`);
12913
+ }
12914
+ }
12915
+ break;
12916
+ }
12917
+ case "add:deps:no-package-json":
12918
+ console.warn(` Warning: ${event.message}`);
12919
+ break;
12920
+ case "add:deps:dry-run": {
12921
+ const dryDeps = event.dependencies;
12922
+ console.log(" [dry-run] Would install:");
12923
+ for (const dep of dryDeps) {
12924
+ console.log(` ${dep}`);
12925
+ }
12854
12926
  break;
12855
12927
  }
12928
+ case "add:deps:install-failed":
12929
+ context.spinner?.fail("Failed to install dependencies");
12930
+ console.log(` ${event.message}`);
12931
+ if (event.suggestion) {
12932
+ console.log(` ${event.suggestion}`);
12933
+ }
12934
+ break;
12856
12935
  case "add:complete":
12857
12936
  context.spinner?.succeed(
12858
12937
  `Added ${event.installed} component${event.installed !== 1 ? "s" : ""}`
@@ -12888,6 +12967,20 @@ function error46(message) {
12888
12967
  context.spinner?.fail(message);
12889
12968
  context.spinner = null;
12890
12969
  }
12970
+ function withErrorHandler(action) {
12971
+ return async (...args) => {
12972
+ try {
12973
+ await action(...args);
12974
+ } catch (err) {
12975
+ const message = err instanceof Error ? err.message : String(err);
12976
+ error46(message);
12977
+ if (process.env.DEBUG && err instanceof Error && err.stack) {
12978
+ console.error(err.stack);
12979
+ }
12980
+ process.exitCode = 1;
12981
+ }
12982
+ };
12983
+ }
12891
12984
 
12892
12985
  // src/utils/update-dependencies.ts
12893
12986
  import { execa } from "execa";
@@ -12956,6 +13049,127 @@ async function installWithPackageManager(packageManager, dependencies, options)
12956
13049
  }
12957
13050
  }
12958
13051
 
13052
+ // src/utils/install-registry-deps.ts
13053
+ function parseDependency(dep) {
13054
+ const trimmed = dep.trim();
13055
+ if (!trimmed) {
13056
+ return { name: "", version: void 0 };
13057
+ }
13058
+ const versionAt = trimmed.lastIndexOf("@");
13059
+ if (versionAt <= 0) {
13060
+ return { name: trimmed, version: void 0 };
13061
+ }
13062
+ return {
13063
+ name: trimmed.slice(0, versionAt),
13064
+ version: trimmed.slice(versionAt + 1)
13065
+ };
13066
+ }
13067
+ async function readInstalledDeps(targetDir) {
13068
+ let raw;
13069
+ try {
13070
+ raw = await readFile(join(targetDir, "package.json"), "utf-8");
13071
+ } catch {
13072
+ return { packageJsonFound: false, installed: /* @__PURE__ */ new Set() };
13073
+ }
13074
+ try {
13075
+ const pkg = JSON.parse(raw);
13076
+ const installed = /* @__PURE__ */ new Set();
13077
+ const depFields = ["dependencies", "devDependencies", "peerDependencies"];
13078
+ for (const field of depFields) {
13079
+ const section = pkg[field];
13080
+ if (section && typeof section === "object") {
13081
+ for (const name2 of Object.keys(section)) {
13082
+ installed.add(name2);
13083
+ }
13084
+ }
13085
+ }
13086
+ return { packageJsonFound: true, installed };
13087
+ } catch {
13088
+ return { packageJsonFound: true, installed: /* @__PURE__ */ new Set() };
13089
+ }
13090
+ }
13091
+ async function installRegistryDependencies(items, targetDir, options = {}) {
13092
+ const result = {
13093
+ installed: [],
13094
+ skipped: [],
13095
+ devInstalled: [],
13096
+ failed: []
13097
+ };
13098
+ const allDeps = new Set(items.flatMap((item) => item.files.flatMap((file2) => file2.dependencies)));
13099
+ if (allDeps.size === 0) {
13100
+ return result;
13101
+ }
13102
+ const externalDeps = [];
13103
+ for (const dep of allDeps) {
13104
+ if (parseDependency(dep).name.startsWith("@rafters/")) {
13105
+ result.skipped.push(dep);
13106
+ } else {
13107
+ externalDeps.push(dep);
13108
+ }
13109
+ }
13110
+ if (externalDeps.length === 0) {
13111
+ return result;
13112
+ }
13113
+ const { packageJsonFound, installed: installedInProject } = await readInstalledDeps(targetDir);
13114
+ const toInstall = [];
13115
+ if (!packageJsonFound) {
13116
+ log({
13117
+ event: "add:deps:no-package-json",
13118
+ message: "No package.json found. Run npm init or pnpm init first.",
13119
+ targetDir
13120
+ });
13121
+ toInstall.push(...externalDeps);
13122
+ } else {
13123
+ for (const dep of externalDeps) {
13124
+ const { name: name2 } = parseDependency(dep);
13125
+ if (installedInProject.has(name2)) {
13126
+ result.skipped.push(dep);
13127
+ } else {
13128
+ toInstall.push(dep);
13129
+ }
13130
+ }
13131
+ }
13132
+ if (toInstall.length === 0) {
13133
+ return result;
13134
+ }
13135
+ if (options.dryRun) {
13136
+ log({
13137
+ event: "add:deps:dry-run",
13138
+ dependencies: toInstall
13139
+ });
13140
+ return result;
13141
+ }
13142
+ try {
13143
+ await updateDependencies(toInstall, [], {
13144
+ cwd: targetDir,
13145
+ silent: options.silent ?? false
13146
+ });
13147
+ result.installed = toInstall;
13148
+ } catch (err) {
13149
+ result.failed = toInstall;
13150
+ const message = err instanceof Error ? err.message : String(err);
13151
+ log({
13152
+ event: "add:deps:install-failed",
13153
+ message: `Failed to install dependencies: ${message}`,
13154
+ dependencies: toInstall,
13155
+ suggestion: `Manually install: ${toInstall.join(" ")}`
13156
+ });
13157
+ }
13158
+ return result;
13159
+ }
13160
+
13161
+ // src/utils/paths.ts
13162
+ import { join as join2 } from "path";
13163
+ function getRaftersPaths(projectRoot = process.cwd()) {
13164
+ const root = join2(projectRoot, ".rafters");
13165
+ return {
13166
+ root,
13167
+ config: join2(root, "config.rafters.json"),
13168
+ tokens: join2(root, "tokens"),
13169
+ output: join2(root, "output")
13170
+ };
13171
+ }
13172
+
12959
13173
  // src/commands/add.ts
12960
13174
  async function isInitialized(cwd) {
12961
13175
  const paths = getRaftersPaths(cwd);
@@ -12969,7 +13183,7 @@ async function isInitialized(cwd) {
12969
13183
  async function loadConfig(cwd) {
12970
13184
  const paths = getRaftersPaths(cwd);
12971
13185
  try {
12972
- const content = await readFile(paths.config, "utf-8");
13186
+ const content = await readFile2(paths.config, "utf-8");
12973
13187
  return JSON.parse(content);
12974
13188
  } catch (err) {
12975
13189
  if (existsSync(paths.config)) {
@@ -12979,6 +13193,40 @@ async function loadConfig(cwd) {
12979
13193
  return null;
12980
13194
  }
12981
13195
  }
13196
+ async function saveConfig(cwd, config3) {
13197
+ const paths = getRaftersPaths(cwd);
13198
+ await writeFile(paths.config, JSON.stringify(config3, null, 2));
13199
+ }
13200
+ function getInstalledNames(config3) {
13201
+ if (!config3?.installed) return [];
13202
+ const names2 = /* @__PURE__ */ new Set([...config3.installed.components, ...config3.installed.primitives]);
13203
+ return [...names2].sort();
13204
+ }
13205
+ function isAlreadyInstalled(config3, item) {
13206
+ if (!config3?.installed) return false;
13207
+ if (item.type === "registry:ui") {
13208
+ return config3.installed.components.includes(item.name);
13209
+ }
13210
+ return config3.installed.primitives.includes(item.name);
13211
+ }
13212
+ function trackInstalled(config3, items) {
13213
+ if (!config3.installed) {
13214
+ config3.installed = { components: [], primitives: [] };
13215
+ }
13216
+ for (const item of items) {
13217
+ if (item.type === "registry:ui") {
13218
+ if (!config3.installed.components.includes(item.name)) {
13219
+ config3.installed.components.push(item.name);
13220
+ }
13221
+ } else {
13222
+ if (!config3.installed.primitives.includes(item.name)) {
13223
+ config3.installed.primitives.push(item.name);
13224
+ }
13225
+ }
13226
+ }
13227
+ config3.installed.components.sort();
13228
+ config3.installed.primitives.sort();
13229
+ }
12982
13230
  function transformPath(registryPath, config3) {
12983
13231
  if (!config3) return registryPath;
12984
13232
  if (registryPath.startsWith("components/ui/")) {
@@ -12990,7 +13238,7 @@ function transformPath(registryPath, config3) {
12990
13238
  return registryPath;
12991
13239
  }
12992
13240
  function fileExists(cwd, relativePath) {
12993
- return existsSync(join2(cwd, relativePath));
13241
+ return existsSync(join3(cwd, relativePath));
12994
13242
  }
12995
13243
  function transformFileContent(content, config3) {
12996
13244
  let transformed = content;
@@ -13030,7 +13278,7 @@ async function installItem(cwd, item, options, config3) {
13030
13278
  let skipped = false;
13031
13279
  for (const file2 of item.files) {
13032
13280
  const projectPath = transformPath(file2.path, config3);
13033
- const targetPath = join2(cwd, projectPath);
13281
+ const targetPath = join3(cwd, projectPath);
13034
13282
  if (fileExists(cwd, projectPath)) {
13035
13283
  if (!options.overwrite) {
13036
13284
  log({
@@ -13054,23 +13302,9 @@ async function installItem(cwd, item, options, config3) {
13054
13302
  files: installedFiles
13055
13303
  };
13056
13304
  }
13057
- function collectDependencies(items) {
13058
- const deps = /* @__PURE__ */ new Set();
13059
- const devDeps = /* @__PURE__ */ new Set();
13060
- for (const item of items) {
13061
- for (const file2 of item.files) {
13062
- for (const dep of file2.dependencies) {
13063
- deps.add(dep);
13064
- }
13065
- }
13066
- }
13067
- return {
13068
- dependencies: [...deps].sort(),
13069
- devDependencies: [...devDeps].sort()
13070
- };
13071
- }
13072
- async function add(components, options) {
13305
+ async function add(componentArgs, options) {
13073
13306
  setAgentMode(options.agent ?? false);
13307
+ let components = componentArgs;
13074
13308
  const client = new RegistryClient(options.registryUrl);
13075
13309
  if (options.list) {
13076
13310
  const availableComponents = await client.listComponents();
@@ -13092,6 +13326,24 @@ async function add(components, options) {
13092
13326
  return;
13093
13327
  }
13094
13328
  const config3 = await loadConfig(cwd);
13329
+ if (options.update) {
13330
+ options.overwrite = true;
13331
+ }
13332
+ if (options.updateAll) {
13333
+ options.overwrite = true;
13334
+ if (!config3) {
13335
+ error46("No rafters config found. Run 'rafters init' first.");
13336
+ process.exitCode = 1;
13337
+ return;
13338
+ }
13339
+ const installedNames = getInstalledNames(config3);
13340
+ if (installedNames.length === 0) {
13341
+ error46("No installed components found. Use 'rafters add <component>' to install first.");
13342
+ process.exitCode = 1;
13343
+ return;
13344
+ }
13345
+ components = installedNames;
13346
+ }
13095
13347
  if (components.length === 0) {
13096
13348
  error46("No components specified. Usage: rafters add <component...>");
13097
13349
  process.exitCode = 1;
@@ -13121,11 +13373,22 @@ async function add(components, options) {
13121
13373
  }
13122
13374
  const installed = [];
13123
13375
  const skipped = [];
13376
+ const installedItems = [];
13124
13377
  for (const item of allItems) {
13378
+ if (!options.overwrite && isAlreadyInstalled(config3, item)) {
13379
+ log({
13380
+ event: "add:skip",
13381
+ component: item.name,
13382
+ reason: "already installed"
13383
+ });
13384
+ skipped.push(item.name);
13385
+ continue;
13386
+ }
13125
13387
  try {
13126
13388
  const result = await installItem(cwd, item, options, config3);
13127
13389
  if (result.installed) {
13128
13390
  installed.push(item.name);
13391
+ installedItems.push(item);
13129
13392
  log({
13130
13393
  event: "add:installed",
13131
13394
  component: item.name,
@@ -13146,22 +13409,47 @@ async function add(components, options) {
13146
13409
  }
13147
13410
  }
13148
13411
  }
13149
- const { dependencies, devDependencies } = collectDependencies(allItems);
13150
- if (dependencies.length > 0 || devDependencies.length > 0) {
13412
+ const emptyDeps = {
13413
+ installed: [],
13414
+ skipped: [],
13415
+ devInstalled: [],
13416
+ failed: []
13417
+ };
13418
+ let depsResult = emptyDeps;
13419
+ try {
13420
+ depsResult = await installRegistryDependencies(allItems, cwd);
13421
+ } catch (err) {
13422
+ const message = err instanceof Error ? err.message : String(err);
13423
+ log({
13424
+ event: "add:deps:install-failed",
13425
+ message: `Failed to process dependencies: ${message}`,
13426
+ dependencies: [],
13427
+ suggestion: "Check package.json and try installing dependencies manually."
13428
+ });
13429
+ }
13430
+ if (depsResult.installed.length > 0 || depsResult.skipped.length > 0) {
13151
13431
  log({
13152
13432
  event: "add:dependencies",
13153
- dependencies,
13154
- devDependencies
13433
+ dependencies: depsResult.installed,
13434
+ devDependencies: depsResult.devInstalled,
13435
+ skipped: depsResult.skipped
13155
13436
  });
13156
- try {
13157
- await updateDependencies(dependencies, devDependencies, { cwd });
13158
- } catch (err) {
13159
- log({
13160
- event: "add:error",
13161
- message: "Failed to install dependencies",
13162
- error: err instanceof Error ? err.message : String(err)
13163
- });
13164
- }
13437
+ }
13438
+ if (installedItems.length > 0 && config3) {
13439
+ trackInstalled(config3, installedItems);
13440
+ await saveConfig(cwd, config3);
13441
+ } else if (installedItems.length > 0 && !config3) {
13442
+ const newConfig = {
13443
+ framework: "unknown",
13444
+ componentsPath: "components/ui",
13445
+ primitivesPath: "lib/primitives",
13446
+ cssPath: null,
13447
+ shadcn: false,
13448
+ exports: DEFAULT_EXPORTS,
13449
+ installed: { components: [], primitives: [] }
13450
+ };
13451
+ trackInstalled(newConfig, installedItems);
13452
+ await saveConfig(cwd, newConfig);
13165
13453
  }
13166
13454
  log({
13167
13455
  event: "add:complete",
@@ -13172,19 +13460,20 @@ async function add(components, options) {
13172
13460
  if (skipped.length > 0 && installed.length === 0) {
13173
13461
  log({
13174
13462
  event: "add:hint",
13175
- message: "Some components were skipped. Use --overwrite to replace existing files.",
13463
+ message: "Some components were skipped. Use --update to re-fetch, or --update-all to refresh everything.",
13176
13464
  skipped
13177
13465
  });
13178
- error46("Component already exists. Use --overwrite to replace.");
13466
+ error46("Component already exists. Use --update to re-fetch from registry.");
13179
13467
  process.exitCode = 1;
13180
13468
  }
13181
13469
  }
13182
13470
 
13183
13471
  // src/commands/init.ts
13184
13472
  import { existsSync as existsSync2 } from "fs";
13185
- import { copyFile, mkdir as mkdir3, readFile as readFile4, rm, writeFile as writeFile3 } from "fs/promises";
13186
- import { join as join8, relative } from "path";
13187
- import { checkbox } from "@inquirer/prompts";
13473
+ import { copyFile, mkdir as mkdir3, readFile as readFile5, rm, writeFile as writeFile3 } from "fs/promises";
13474
+ import { createRequire } from "module";
13475
+ import { join as join9, relative } from "path";
13476
+ import { checkbox, confirm } from "@inquirer/prompts";
13188
13477
 
13189
13478
  // ../design-tokens/src/plugins/scale.ts
13190
13479
  function scale(registry2, tokenName, dependencies) {
@@ -24314,7 +24603,7 @@ var require_volume = __commonJS({
24314
24603
  var Dir_1 = require_Dir();
24315
24604
  var resolveCrossPlatform = pathModule.resolve;
24316
24605
  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;
24317
- var { sep: sep2, relative: relative2, join: join11, dirname: dirname4 } = pathModule.posix ? pathModule.posix : pathModule;
24606
+ var { sep: sep2, relative: relative2, join: join12, dirname: dirname4 } = pathModule.posix ? pathModule.posix : pathModule;
24318
24607
  var kMinPoolSpace = 128;
24319
24608
  var EPERM = "EPERM";
24320
24609
  var ENOENT2 = "ENOENT";
@@ -24380,7 +24669,7 @@ var require_volume = __commonJS({
24380
24669
  function flatten(pathPrefix, node) {
24381
24670
  for (const path2 in node) {
24382
24671
  const contentOrNode = node[path2];
24383
- const joinedPath = join11(pathPrefix, path2);
24672
+ const joinedPath = join12(pathPrefix, path2);
24384
24673
  if (typeof contentOrNode === "string" || contentOrNode instanceof buffer_1.Buffer) {
24385
24674
  flatJSON[joinedPath] = contentOrNode;
24386
24675
  } else if (typeof contentOrNode === "object" && contentOrNode !== null && Object.keys(contentOrNode).length > 0) {
@@ -24537,7 +24826,7 @@ var require_volume = __commonJS({
24537
24826
  return null;
24538
24827
  node = curr === null || curr === void 0 ? void 0 : curr.getNode();
24539
24828
  if (resolveSymlinks && node.isSymlink()) {
24540
- const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join11(pathModule.dirname(curr.getPath()), node.symlink);
24829
+ const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join12(pathModule.dirname(curr.getPath()), node.symlink);
24541
24830
  steps = filenameToSteps(resolvedPath).concat(steps.slice(i + 1));
24542
24831
  curr = this.root;
24543
24832
  i = 0;
@@ -27461,7 +27750,7 @@ var posix = {
27461
27750
 
27462
27751
  // ../../node_modules/.pnpm/path-unified@0.2.0/node_modules/path-unified/src/posix.js
27463
27752
  var resolve = posResolve;
27464
- var join3 = posJoin;
27753
+ var join4 = posJoin;
27465
27754
 
27466
27755
  // ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
27467
27756
  var balanced = (a, b, str) => {
@@ -37360,7 +37649,7 @@ var transforms_default = {
37360
37649
  type: value,
37361
37650
  filter: isAsset,
37362
37651
  transform: function(token, _, options) {
37363
- return join3(process?.cwd() ?? "/", options.usesDtcg ? token.$value : token.value);
37652
+ return join4(process?.cwd() ?? "/", options.usesDtcg ? token.$value : token.value);
37364
37653
  }
37365
37654
  },
37366
37655
  /**
@@ -43560,12 +43849,12 @@ var formats_default = formats2;
43560
43849
  var { androidCopyImages, copyAssets } = actions;
43561
43850
  var { silent } = logVerbosityLevels;
43562
43851
  function getAssetDir(config3) {
43563
- return join3(config3.buildPath ?? "", "android/main/res/drawable-").replace(/\\/g, "/");
43852
+ return join4(config3.buildPath ?? "", "android/main/res/drawable-").replace(/\\/g, "/");
43564
43853
  }
43565
43854
  function getAssetPath(token, imagesDir) {
43566
43855
  const name2 = token.path.slice(2, 4).join("_");
43567
43856
  const dir = `${imagesDir}${token.attributes?.state}`;
43568
- return { file: join3(dir, `${name2}.png`), dir };
43857
+ return { file: join4(dir, `${name2}.png`), dir };
43569
43858
  }
43570
43859
  var actions_default = {
43571
43860
  /**
@@ -43606,7 +43895,7 @@ var actions_default = {
43606
43895
  */
43607
43896
  [copyAssets]: {
43608
43897
  do: async function(_, config3, _options, vol2 = fs2) {
43609
- const assetsPath = join3(config3.buildPath ?? "", "assets");
43898
+ const assetsPath = join4(config3.buildPath ?? "", "assets");
43610
43899
  if (config3.log?.verbosity !== silent) {
43611
43900
  console.log(`Copying assets directory to ${assetsPath}`);
43612
43901
  }
@@ -43620,7 +43909,7 @@ var actions_default = {
43620
43909
  );
43621
43910
  },
43622
43911
  undo: async function(_, config3, _options, vol2 = fs2) {
43623
- const assetsPath = join3(config3.buildPath ?? "", "assets");
43912
+ const assetsPath = join4(config3.buildPath ?? "", "assets");
43624
43913
  if (config3.log?.verbosity !== silent) {
43625
43914
  console.log(`Removing assets directory from ${assetsPath}`);
43626
43915
  }
@@ -44101,8 +44390,14 @@ var DEFAULT_DEPTH_DEFINITIONS = {
44101
44390
  },
44102
44391
  sticky: {
44103
44392
  value: 20,
44104
- meaning: "Sticky elements - headers, navigation",
44105
- contexts: ["sticky-header", "sticky-nav", "floating-actions"],
44393
+ meaning: "Sticky elements - headers, toolbars",
44394
+ contexts: ["sticky-header", "sticky-toolbar", "floating-actions"],
44395
+ stackingContext: true
44396
+ },
44397
+ navigation: {
44398
+ value: 25,
44399
+ meaning: "Navigation panels - sidebars, slide-out nav",
44400
+ contexts: ["sidebar", "navigation-panel", "slide-out-menu"],
44106
44401
  stackingContext: true
44107
44402
  },
44108
44403
  fixed: {
@@ -44128,6 +44423,12 @@ var DEFAULT_DEPTH_DEFINITIONS = {
44128
44423
  meaning: "Tooltips - highest common layer",
44129
44424
  contexts: ["tooltips", "toast-notifications"],
44130
44425
  stackingContext: true
44426
+ },
44427
+ overlay: {
44428
+ value: 70,
44429
+ meaning: "Overlay backdrops - screen-dimming layers behind modals",
44430
+ contexts: ["modal-backdrop", "drawer-backdrop", "sheet-backdrop"],
44431
+ stackingContext: true
44131
44432
  }
44132
44433
  };
44133
44434
  var DEFAULT_SHADOW_DEFINITIONS = {
@@ -46425,6 +46726,78 @@ function generateThemeBlock(groups) {
46425
46726
  lines.push("}");
46426
46727
  return lines.join("\n");
46427
46728
  }
46729
+ var ARTICLE_ELEMENT_STYLES = [
46730
+ // Paragraphs
46731
+ ["p", "leading-relaxed mb-4"],
46732
+ ["p:last-child", "mb-0"],
46733
+ // Headings
46734
+ ["h1", "text-4xl font-bold tracking-tight mb-4 mt-0 text-accent-foreground"],
46735
+ ["h2", "text-3xl font-semibold tracking-tight mb-3 mt-8 text-accent-foreground"],
46736
+ ["h2:first-child", "mt-0"],
46737
+ ["h3", "text-2xl font-semibold mb-2 mt-6 text-accent-foreground"],
46738
+ ["h4", "text-xl font-semibold mb-2 mt-4 text-accent-foreground"],
46739
+ ["h5", "text-lg font-semibold mb-2 mt-4 text-accent-foreground"],
46740
+ ["h6", "text-base font-semibold mb-2 mt-4 text-accent-foreground"],
46741
+ // Lists
46742
+ ["ul", "list-disc pl-6 mb-4"],
46743
+ ["ol", "list-decimal pl-6 mb-4"],
46744
+ ["li", "mb-1"],
46745
+ ["li > ul,\n article li > ol", "mt-1 mb-0"],
46746
+ // Links
46747
+ ["a", "text-primary underline underline-offset-4"],
46748
+ ["a:hover", "text-primary/80"],
46749
+ // Blockquotes
46750
+ ["blockquote", "border-l-4 border-muted pl-4 italic my-4"],
46751
+ // Code
46752
+ ["code", "bg-muted px-1.5 py-0.5 rounded text-sm font-mono"],
46753
+ ["pre", "bg-muted p-4 rounded-lg overflow-x-auto my-4 text-sm font-mono"],
46754
+ ["pre code", "bg-transparent p-0 rounded-none text-[inherit]"],
46755
+ ["kbd", "bg-muted border border-border rounded px-1.5 py-0.5 text-sm font-mono"],
46756
+ // Horizontal rules
46757
+ ["hr", "border-border my-8"],
46758
+ // Media
46759
+ ["img", "rounded-lg my-4 max-w-full h-auto"],
46760
+ ["video", "rounded-lg my-4 max-w-full h-auto"],
46761
+ // Tables
46762
+ ["table", "w-full my-4 border-collapse"],
46763
+ ["caption", "mt-2 text-sm text-muted-foreground text-left"],
46764
+ ["th", "border border-border px-3 py-2 text-left font-semibold"],
46765
+ ["td", "border border-border px-3 py-2"],
46766
+ // Figures
46767
+ ["figure", "my-4"],
46768
+ ["figcaption", "mt-2 text-sm text-muted-foreground"],
46769
+ // Definition lists
46770
+ ["dl", "my-4"],
46771
+ ["dt", "font-semibold mt-2"],
46772
+ ["dd", "pl-4 mb-2"],
46773
+ // Details/Summary
46774
+ ["details", "my-4"],
46775
+ ["summary", "cursor-pointer font-semibold"],
46776
+ // Inline formatting
46777
+ ["strong,\n article b", "font-semibold"],
46778
+ ["mark", "bg-accent text-accent-foreground px-1 rounded"],
46779
+ ["small", "text-sm"],
46780
+ ["sub", "text-xs align-sub"],
46781
+ ["sup", "text-xs align-super"],
46782
+ ["abbr[title]", "underline decoration-dotted underline-offset-4 cursor-help"],
46783
+ ["s,\n article del", "line-through"],
46784
+ ["ins", "underline"]
46785
+ ];
46786
+ function generateArticleBaseLayer() {
46787
+ const lines = [];
46788
+ lines.push("@layer base {");
46789
+ for (const [selector, utilities] of ARTICLE_ELEMENT_STYLES) {
46790
+ if (selector.includes("\n")) {
46791
+ lines.push(` article ${selector} {`);
46792
+ } else {
46793
+ lines.push(` article ${selector} {`);
46794
+ }
46795
+ lines.push(` @apply ${utilities};`);
46796
+ lines.push(" }");
46797
+ }
46798
+ lines.push("}");
46799
+ return lines.join("\n");
46800
+ }
46428
46801
  function generateKeyframes(motionTokens) {
46429
46802
  const keyframeTokens = motionTokens.filter((t2) => t2.name.startsWith("motion-keyframe-"));
46430
46803
  if (keyframeTokens.length === 0) {
@@ -46476,6 +46849,8 @@ function tokensToTailwind(tokens, options = {}) {
46476
46849
  if (keyframes) {
46477
46850
  sections.push(keyframes);
46478
46851
  }
46852
+ sections.push("");
46853
+ sections.push(generateArticleBaseLayer());
46479
46854
  return sections.join("\n");
46480
46855
  }
46481
46856
  function registryToTailwind(registry2, options) {
@@ -46487,9 +46862,9 @@ async function registryToCompiled(registry2, options = {}) {
46487
46862
  const themeCss = registryToTailwind(registry2, { includeImport });
46488
46863
  const { execFileSync } = await import("child_process");
46489
46864
  const { mkdtempSync, writeFileSync, readFileSync, rmSync } = await import("fs");
46490
- const { join: join11, dirname: dirname4 } = await import("path");
46491
- const { createRequire } = await import("module");
46492
- const require2 = createRequire(import.meta.url);
46865
+ const { join: join12, dirname: dirname4 } = await import("path");
46866
+ const { createRequire: createRequire2 } = await import("module");
46867
+ const require2 = createRequire2(import.meta.url);
46493
46868
  let pkgDir;
46494
46869
  try {
46495
46870
  const pkgJsonPath = require2.resolve("@tailwindcss/cli/package.json");
@@ -46497,10 +46872,10 @@ async function registryToCompiled(registry2, options = {}) {
46497
46872
  } catch {
46498
46873
  throw new Error("Failed to resolve @tailwindcss/cli");
46499
46874
  }
46500
- const binPath = join11(pkgDir, "dist", "index.mjs");
46501
- const tempDir = mkdtempSync(join11(pkgDir, ".tmp-compile-"));
46502
- const tempInput = join11(tempDir, "input.css");
46503
- const tempOutput = join11(tempDir, "output.css");
46875
+ const binPath = join12(pkgDir, "dist", "index.mjs");
46876
+ const tempDir = mkdtempSync(join12(pkgDir, ".tmp-compile-"));
46877
+ const tempInput = join12(tempDir, "input.css");
46878
+ const tempOutput = join12(tempDir, "output.css");
46504
46879
  try {
46505
46880
  writeFileSync(tempInput, themeCss);
46506
46881
  const args = [binPath, "-i", tempInput, "-o", tempOutput];
@@ -46779,7 +47154,7 @@ function tagTokenizer() {
46779
47154
 
46780
47155
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/type.js
46781
47156
  function typeTokenizer(spacing = "compact") {
46782
- const join11 = getJoiner(spacing);
47157
+ const join12 = getJoiner(spacing);
46783
47158
  return (spec) => {
46784
47159
  let curlies = 0;
46785
47160
  let lines = [];
@@ -46822,7 +47197,7 @@ function typeTokenizer(spacing = "compact") {
46822
47197
  }
46823
47198
  parts[0] = parts[0].slice(1);
46824
47199
  parts[parts.length - 1] = parts[parts.length - 1].slice(0, -1);
46825
- spec.type = join11(parts);
47200
+ spec.type = join12(parts);
46826
47201
  return spec;
46827
47202
  };
46828
47203
  }
@@ -46920,9 +47295,9 @@ function nameTokenizer() {
46920
47295
 
46921
47296
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/description.js
46922
47297
  function descriptionTokenizer(spacing = "compact", markers = Markers) {
46923
- const join11 = getJoiner2(spacing);
47298
+ const join12 = getJoiner2(spacing);
46924
47299
  return (spec) => {
46925
- spec.description = join11(spec.source, markers);
47300
+ spec.description = join12(spec.source, markers);
46926
47301
  return spec;
46927
47302
  };
46928
47303
  }
@@ -46983,11 +47358,11 @@ function getParser4({ startLine = 0, fence = "```", spacing = "compact", markers
46983
47358
  }
46984
47359
 
46985
47360
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/stringifier/index.js
46986
- function join4(tokens) {
47361
+ function join5(tokens) {
46987
47362
  return tokens.start + tokens.delimiter + tokens.postDelimiter + tokens.tag + tokens.postTag + tokens.type + tokens.postType + tokens.name + tokens.postName + tokens.description + tokens.end + tokens.lineEnd;
46988
47363
  }
46989
47364
  function getStringifier() {
46990
- return (block) => block.source.map(({ tokens }) => join4(tokens)).join("\n");
47365
+ return (block) => block.source.map(({ tokens }) => join5(tokens)).join("\n");
46991
47366
  }
46992
47367
 
46993
47368
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/stringifier/inspect.js
@@ -47156,6 +47531,32 @@ function extractPrimitiveDependencies(source) {
47156
47531
  }
47157
47532
  return primitives;
47158
47533
  }
47534
+ var DEP_TAG_MAP = {
47535
+ dependencies: "runtime",
47536
+ devdependencies: "dev",
47537
+ "internal-dependencies": "internal",
47538
+ internaldependencies: "internal"
47539
+ };
47540
+ function extractJSDocDependencies(source) {
47541
+ const result = { runtime: [], dev: [], internal: [] };
47542
+ const blocks = parse3(source);
47543
+ if (blocks.length === 0) return result;
47544
+ for (const block of blocks) {
47545
+ for (const tag of block.tags) {
47546
+ const field = DEP_TAG_MAP[tag.tag.toLowerCase()];
47547
+ if (!field) continue;
47548
+ const value2 = getTagValue(tag).trim();
47549
+ if (value2) {
47550
+ result[field].push(...value2.split(/\s+/).filter(Boolean));
47551
+ }
47552
+ }
47553
+ }
47554
+ return {
47555
+ runtime: [...new Set(result.runtime)],
47556
+ dev: [...new Set(result.dev)],
47557
+ internal: [...new Set(result.internal)]
47558
+ };
47559
+ }
47159
47560
  function toDisplayName(name2) {
47160
47561
  return name2.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
47161
47562
  }
@@ -48245,10 +48646,12 @@ var DEPTH_LEVELS = [
48245
48646
  "base",
48246
48647
  "dropdown",
48247
48648
  "sticky",
48649
+ "navigation",
48248
48650
  "fixed",
48249
48651
  "modal",
48250
48652
  "popover",
48251
- "tooltip"
48653
+ "tooltip",
48654
+ "overlay"
48252
48655
  ];
48253
48656
  var ELEVATION_LEVELS = [
48254
48657
  "surface",
@@ -50307,14 +50710,14 @@ function buildColorSystem(options = {}) {
50307
50710
  }
50308
50711
 
50309
50712
  // ../design-tokens/src/persistence/node-adapter.ts
50310
- import { mkdir as mkdir2, readdir as readdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
50311
- import { join as join5 } from "path";
50713
+ import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
50714
+ import { join as join6 } from "path";
50312
50715
  var SCHEMA_URL = "https://rafters.studio/schemas/namespace-tokens.json";
50313
50716
  var VERSION = "1.0.0";
50314
50717
  var NodePersistenceAdapter = class {
50315
50718
  tokensDir;
50316
50719
  constructor(projectRoot) {
50317
- this.tokensDir = join5(projectRoot, ".rafters", "tokens");
50720
+ this.tokensDir = join6(projectRoot, ".rafters", "tokens");
50318
50721
  }
50319
50722
  async load() {
50320
50723
  let files;
@@ -50326,7 +50729,7 @@ var NodePersistenceAdapter = class {
50326
50729
  const allTokens = [];
50327
50730
  for (const file2 of files) {
50328
50731
  if (!file2.endsWith(".rafters.json")) continue;
50329
- const content = await readFile2(join5(this.tokensDir, file2), "utf-8");
50732
+ const content = await readFile3(join6(this.tokensDir, file2), "utf-8");
50330
50733
  const data = NamespaceFileSchema.parse(JSON.parse(content));
50331
50734
  allTokens.push(...data.tokens);
50332
50735
  }
@@ -50354,7 +50757,7 @@ var NodePersistenceAdapter = class {
50354
50757
  };
50355
50758
  NamespaceFileSchema.parse(data);
50356
50759
  await writeFile2(
50357
- join5(this.tokensDir, `${namespace}.rafters.json`),
50760
+ join6(this.tokensDir, `${namespace}.rafters.json`),
50358
50761
  JSON.stringify(data, null, 2)
50359
50762
  );
50360
50763
  }
@@ -50363,7 +50766,7 @@ var NodePersistenceAdapter = class {
50363
50766
 
50364
50767
  // ../design-tokens/src/rule-engine.ts
50365
50768
  import { promises as fs3 } from "fs";
50366
- import { join as join6 } from "path";
50769
+ import { join as join7 } from "path";
50367
50770
  var RuleResultSchema = external_exports.union([
50368
50771
  external_exports.string(),
50369
50772
  external_exports.object({
@@ -50379,11 +50782,11 @@ var RuleContextSchema = external_exports.object({
50379
50782
  });
50380
50783
 
50381
50784
  // src/utils/detect.ts
50382
- import { readFile as readFile3 } from "fs/promises";
50383
- import { join as join7 } from "path";
50785
+ import { readFile as readFile4 } from "fs/promises";
50786
+ import { join as join8 } from "path";
50384
50787
  async function detectFramework(cwd) {
50385
50788
  try {
50386
- const content = await readFile3(join7(cwd, "package.json"), "utf-8");
50789
+ const content = await readFile4(join8(cwd, "package.json"), "utf-8");
50387
50790
  const pkg = JSON.parse(content);
50388
50791
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
50389
50792
  if (deps.next) {
@@ -50409,7 +50812,7 @@ async function detectFramework(cwd) {
50409
50812
  }
50410
50813
  async function detectTailwindVersion(cwd) {
50411
50814
  try {
50412
- const content = await readFile3(join7(cwd, "package.json"), "utf-8");
50815
+ const content = await readFile4(join8(cwd, "package.json"), "utf-8");
50413
50816
  const pkg = JSON.parse(content);
50414
50817
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
50415
50818
  const tailwindVersion = deps.tailwindcss;
@@ -50430,7 +50833,7 @@ function isTailwindV3(version2) {
50430
50833
  }
50431
50834
  async function detectShadcn(cwd) {
50432
50835
  try {
50433
- const content = await readFile3(join7(cwd, "components.json"), "utf-8");
50836
+ const content = await readFile4(join8(cwd, "components.json"), "utf-8");
50434
50837
  return JSON.parse(content);
50435
50838
  } catch {
50436
50839
  return null;
@@ -50492,60 +50895,6 @@ async function detectProject(cwd) {
50492
50895
  };
50493
50896
  }
50494
50897
 
50495
- // src/utils/exports.ts
50496
- var DEFAULT_EXPORTS = {
50497
- tailwind: true,
50498
- typescript: true,
50499
- dtcg: false,
50500
- compiled: false
50501
- };
50502
- var EXPORT_CHOICES = [
50503
- {
50504
- name: "Tailwind CSS (web projects)",
50505
- value: "tailwind",
50506
- checked: true
50507
- },
50508
- {
50509
- name: "TypeScript (type-safe constants)",
50510
- value: "typescript",
50511
- checked: true
50512
- },
50513
- {
50514
- name: "DTCG JSON (Figma Tokens, Style Dictionary)",
50515
- value: "dtcg",
50516
- checked: false
50517
- },
50518
- {
50519
- name: "Standalone CSS (pre-built, no Tailwind required)",
50520
- value: "compiled",
50521
- checked: false
50522
- }
50523
- ];
50524
- var FUTURE_EXPORTS = [
50525
- {
50526
- name: "iOS (Swift/SwiftUI)",
50527
- value: "tailwind",
50528
- // placeholder
50529
- checked: false,
50530
- disabled: "coming soon"
50531
- },
50532
- {
50533
- name: "Android (Compose)",
50534
- value: "tailwind",
50535
- // placeholder
50536
- checked: false,
50537
- disabled: "coming soon"
50538
- }
50539
- ];
50540
- function selectionsToConfig(selections) {
50541
- return {
50542
- tailwind: selections.includes("tailwind"),
50543
- typescript: selections.includes("typescript"),
50544
- dtcg: selections.includes("dtcg"),
50545
- compiled: selections.includes("compiled")
50546
- };
50547
- }
50548
-
50549
50898
  // src/commands/init.ts
50550
50899
  async function backupCss(cssPath) {
50551
50900
  const backupPath = cssPath.replace(/\.css$/, ".backup.css");
@@ -50571,7 +50920,7 @@ var COMPONENT_PATHS = {
50571
50920
  async function findMainCssFile(cwd, framework) {
50572
50921
  const locations = CSS_LOCATIONS[framework] || CSS_LOCATIONS.unknown;
50573
50922
  for (const location of locations) {
50574
- const fullPath = join8(cwd, location);
50923
+ const fullPath = join9(cwd, location);
50575
50924
  if (existsSync2(fullPath)) {
50576
50925
  return location;
50577
50926
  }
@@ -50579,10 +50928,10 @@ async function findMainCssFile(cwd, framework) {
50579
50928
  return null;
50580
50929
  }
50581
50930
  async function updateMainCss(cwd, cssPath, themePath) {
50582
- const fullCssPath = join8(cwd, cssPath);
50583
- const cssContent = await readFile4(fullCssPath, "utf-8");
50584
- const cssDir = join8(cwd, cssPath, "..");
50585
- const themeFullPath = join8(cwd, themePath);
50931
+ const fullCssPath = join9(cwd, cssPath);
50932
+ const cssContent = await readFile5(fullCssPath, "utf-8");
50933
+ const cssDir = join9(cwd, cssPath, "..");
50934
+ const themeFullPath = join9(cwd, themePath);
50586
50935
  const relativeThemePath = relative(cssDir, themeFullPath);
50587
50936
  if (cssContent.includes(".rafters/output/rafters.css")) {
50588
50937
  log({ event: "init:css_already_imported", cssPath });
@@ -50634,36 +50983,71 @@ async function promptExportFormats(existingConfig) {
50634
50983
  });
50635
50984
  return selectionsToConfig(selections);
50636
50985
  }
50637
- async function generateOutputs(paths, registry2, exports, shadcn) {
50986
+ function isTailwindCliInstalled() {
50987
+ const require2 = createRequire(import.meta.url);
50988
+ try {
50989
+ require2.resolve("@tailwindcss/cli/package.json");
50990
+ return true;
50991
+ } catch (err) {
50992
+ if (err instanceof Error && "code" in err && err.code === "MODULE_NOT_FOUND") {
50993
+ return false;
50994
+ }
50995
+ throw err;
50996
+ }
50997
+ }
50998
+ async function ensureTailwindCli(cwd) {
50999
+ if (!isInteractive() || isAgentMode()) {
51000
+ throw new Error(
51001
+ "Standalone CSS export requires @tailwindcss/cli. Install it as a dev dependency in your project."
51002
+ );
51003
+ }
51004
+ const shouldInstall = await confirm({
51005
+ message: "Standalone CSS requires @tailwindcss/cli. Install it now?",
51006
+ default: true
51007
+ });
51008
+ if (!shouldInstall) {
51009
+ throw new Error("Standalone CSS export requires @tailwindcss/cli.");
51010
+ }
51011
+ await updateDependencies([], ["@tailwindcss/cli"], { cwd });
51012
+ if (!isTailwindCliInstalled()) {
51013
+ throw new Error(
51014
+ "@tailwindcss/cli was installed but cannot be resolved. Try installing at the workspace root."
51015
+ );
51016
+ }
51017
+ }
51018
+ async function generateOutputs(cwd, paths, registry2, exports, shadcn) {
50638
51019
  const outputs = [];
50639
51020
  if (exports.tailwind) {
50640
51021
  const tailwindCss = registryToTailwind(registry2, { includeImport: !shadcn });
50641
- await writeFile3(join8(paths.output, "rafters.css"), tailwindCss);
51022
+ await writeFile3(join9(paths.output, "rafters.css"), tailwindCss);
50642
51023
  outputs.push("rafters.css");
50643
51024
  }
50644
51025
  if (exports.typescript) {
50645
51026
  const typescriptSrc = registryToTypeScript(registry2, { includeJSDoc: true });
50646
- await writeFile3(join8(paths.output, "rafters.ts"), typescriptSrc);
51027
+ await writeFile3(join9(paths.output, "rafters.ts"), typescriptSrc);
50647
51028
  outputs.push("rafters.ts");
50648
51029
  }
50649
51030
  if (exports.dtcg) {
50650
51031
  const dtcgJson = toDTCG(registry2.list());
50651
- await writeFile3(join8(paths.output, "rafters.json"), JSON.stringify(dtcgJson, null, 2));
51032
+ await writeFile3(join9(paths.output, "rafters.json"), JSON.stringify(dtcgJson, null, 2));
50652
51033
  outputs.push("rafters.json");
50653
51034
  }
50654
51035
  if (exports.compiled) {
51036
+ if (!isTailwindCliInstalled()) {
51037
+ await ensureTailwindCli(cwd);
51038
+ }
50655
51039
  log({ event: "init:compiling_css" });
50656
51040
  const compiledCss = await registryToCompiled(registry2, { includeImport: !shadcn });
50657
- await writeFile3(join8(paths.output, "rafters.standalone.css"), compiledCss);
51041
+ await writeFile3(join9(paths.output, "rafters.standalone.css"), compiledCss);
50658
51042
  outputs.push("rafters.standalone.css");
50659
51043
  }
50660
51044
  return outputs;
50661
51045
  }
50662
- async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode) {
51046
+ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode2) {
50663
51047
  log({ event: "init:regenerate", cwd });
50664
51048
  let existingConfig = null;
50665
51049
  try {
50666
- const configContent = await readFile4(paths.config, "utf-8");
51050
+ const configContent = await readFile5(paths.config, "utf-8");
50667
51051
  existingConfig = JSON.parse(configContent);
50668
51052
  } catch {
50669
51053
  }
@@ -50680,7 +51064,7 @@ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode) {
50680
51064
  });
50681
51065
  const registry2 = new TokenRegistry(allTokens);
50682
51066
  let exports;
50683
- if (isAgentMode) {
51067
+ if (isAgentMode2) {
50684
51068
  exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
50685
51069
  log({ event: "init:exports_default", exports });
50686
51070
  } else {
@@ -50691,7 +51075,7 @@ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode) {
50691
51075
  log({ event: "init:exports_selected", exports });
50692
51076
  }
50693
51077
  await mkdir3(paths.output, { recursive: true });
50694
- const outputs = await generateOutputs(paths, registry2, exports, shadcn);
51078
+ const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
50695
51079
  if (existingConfig) {
50696
51080
  existingConfig.exports = exports;
50697
51081
  await writeFile3(paths.config, JSON.stringify(existingConfig, null, 2));
@@ -50702,11 +51086,11 @@ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode) {
50702
51086
  path: paths.output
50703
51087
  });
50704
51088
  }
50705
- async function resetToDefaults(cwd, paths, shadcn, isAgentMode) {
51089
+ async function resetToDefaults(cwd, paths, shadcn, isAgentMode2) {
50706
51090
  log({ event: "init:reset", cwd });
50707
51091
  let existingConfig = null;
50708
51092
  try {
50709
- const configContent = await readFile4(paths.config, "utf-8");
51093
+ const configContent = await readFile5(paths.config, "utf-8");
50710
51094
  existingConfig = JSON.parse(configContent);
50711
51095
  } catch {
50712
51096
  }
@@ -50726,7 +51110,7 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode) {
50726
51110
  };
50727
51111
  await mkdir3(paths.output, { recursive: true });
50728
51112
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
50729
- const backupPath = join8(paths.output, `reset-${timestamp}.json`);
51113
+ const backupPath = join9(paths.output, `reset-${timestamp}.json`);
50730
51114
  await writeFile3(backupPath, JSON.stringify(backup, null, 2));
50731
51115
  log({
50732
51116
  event: "init:reset_backup",
@@ -50735,7 +51119,7 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode) {
50735
51119
  });
50736
51120
  }
50737
51121
  let exports;
50738
- if (isAgentMode) {
51122
+ if (isAgentMode2) {
50739
51123
  exports = existingConfig?.exports ?? DEFAULT_EXPORTS;
50740
51124
  log({ event: "init:exports_default", exports });
50741
51125
  } else {
@@ -50768,7 +51152,7 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode) {
50768
51152
  namespaceCount
50769
51153
  });
50770
51154
  await mkdir3(paths.output, { recursive: true });
50771
- const outputs = await generateOutputs(paths, registry2, exports, shadcn);
51155
+ const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
50772
51156
  if (existingConfig) {
50773
51157
  existingConfig.exports = exports;
50774
51158
  await writeFile3(paths.config, JSON.stringify(existingConfig, null, 2));
@@ -50781,7 +51165,7 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode) {
50781
51165
  }
50782
51166
  async function init(options) {
50783
51167
  setAgentMode(options.agent ?? false);
50784
- const isAgentMode = options.agent ?? false;
51168
+ const isAgentMode2 = options.agent ?? false;
50785
51169
  const cwd = process.cwd();
50786
51170
  const paths = getRaftersPaths(cwd);
50787
51171
  log({ event: "init:start", cwd });
@@ -50800,7 +51184,7 @@ async function init(options) {
50800
51184
  throw new Error("Nothing to reset. No .rafters/ directory found.");
50801
51185
  }
50802
51186
  if (raftersExists && options.reset) {
50803
- await resetToDefaults(cwd, paths, shadcn, isAgentMode);
51187
+ await resetToDefaults(cwd, paths, shadcn, isAgentMode2);
50804
51188
  return;
50805
51189
  }
50806
51190
  if (raftersExists && !options.rebuild) {
@@ -50809,14 +51193,14 @@ async function init(options) {
50809
51193
  );
50810
51194
  }
50811
51195
  if (raftersExists && options.rebuild) {
50812
- await regenerateFromExisting(cwd, paths, shadcn, isAgentMode);
51196
+ await regenerateFromExisting(cwd, paths, shadcn, isAgentMode2);
50813
51197
  return;
50814
51198
  }
50815
51199
  let existingColors = null;
50816
51200
  if (shadcn?.tailwind?.css) {
50817
- const cssPath = join8(cwd, shadcn.tailwind.css);
51201
+ const cssPath = join9(cwd, shadcn.tailwind.css);
50818
51202
  try {
50819
- const cssContent = await readFile4(cssPath, "utf-8");
51203
+ const cssContent = await readFile5(cssPath, "utf-8");
50820
51204
  existingColors = parseCssVariables(cssContent);
50821
51205
  const backupPath = await backupCss(cssPath);
50822
51206
  log({
@@ -50833,7 +51217,7 @@ async function init(options) {
50833
51217
  }
50834
51218
  }
50835
51219
  let exports;
50836
- if (isAgentMode) {
51220
+ if (isAgentMode2) {
50837
51221
  exports = DEFAULT_EXPORTS;
50838
51222
  log({ event: "init:exports_default", exports });
50839
51223
  } else {
@@ -50899,7 +51283,7 @@ async function init(options) {
50899
51283
  path: paths.tokens,
50900
51284
  namespaceCount
50901
51285
  });
50902
- const outputs = await generateOutputs(paths, registry2, exports, shadcn);
51286
+ const outputs = await generateOutputs(cwd, paths, registry2, exports, shadcn);
50903
51287
  let detectedCssPath = null;
50904
51288
  if (!shadcn && exports.tailwind) {
50905
51289
  detectedCssPath = await findMainCssFile(cwd, framework);
@@ -50922,7 +51306,11 @@ async function init(options) {
50922
51306
  primitivesPath: frameworkPaths.primitives,
50923
51307
  cssPath: detectedCssPath,
50924
51308
  shadcn: !!shadcn,
50925
- exports
51309
+ exports,
51310
+ installed: {
51311
+ components: [],
51312
+ primitives: []
51313
+ }
50926
51314
  };
50927
51315
  await writeFile3(paths.config, JSON.stringify(config3, null, 2));
50928
51316
  log({
@@ -50938,8 +51326,916 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
50938
51326
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
50939
51327
 
50940
51328
  // src/mcp/tools.ts
50941
- import { readdir as readdir3, readFile as readFile5 } from "fs/promises";
50942
- import { basename, join as join9 } from "path";
51329
+ import { existsSync as existsSync3 } from "fs";
51330
+ import { readdir as readdir3, readFile as readFile6 } from "fs/promises";
51331
+ import { basename, join as join10 } from "path";
51332
+
51333
+ // src/mcp/cognitive-load.ts
51334
+ var BUDGET_TIERS = {
51335
+ focused: 15,
51336
+ page: 30,
51337
+ app: 45
51338
+ };
51339
+ var COMPONENT_SCORES = {
51340
+ // Score 0 -- Structural only, no cognitive demand
51341
+ separator: {
51342
+ dimensions: {
51343
+ decisionDemand: 0,
51344
+ informationDensity: 0,
51345
+ interactionComplexity: 0,
51346
+ contextDisruption: 0,
51347
+ learningCurve: 0
51348
+ },
51349
+ primaryCostDriver: "Structural only, no cognitive demand"
51350
+ },
51351
+ container: {
51352
+ dimensions: {
51353
+ decisionDemand: 0,
51354
+ informationDensity: 0,
51355
+ interactionComplexity: 0,
51356
+ contextDisruption: 0,
51357
+ learningCurve: 0
51358
+ },
51359
+ primaryCostDriver: "Structural only, no cognitive demand"
51360
+ },
51361
+ "aspect-ratio": {
51362
+ dimensions: {
51363
+ decisionDemand: 0,
51364
+ informationDensity: 0,
51365
+ interactionComplexity: 0,
51366
+ contextDisruption: 0,
51367
+ learningCurve: 0
51368
+ },
51369
+ primaryCostDriver: "Structural only, no cognitive demand"
51370
+ },
51371
+ // Score 1 -- Display only, minimal information
51372
+ skeleton: {
51373
+ dimensions: {
51374
+ decisionDemand: 0,
51375
+ informationDensity: 1,
51376
+ interactionComplexity: 0,
51377
+ contextDisruption: 0,
51378
+ learningCurve: 0
51379
+ },
51380
+ primaryCostDriver: "Display only, minimal information"
51381
+ },
51382
+ kbd: {
51383
+ dimensions: {
51384
+ decisionDemand: 0,
51385
+ informationDensity: 1,
51386
+ interactionComplexity: 0,
51387
+ contextDisruption: 0,
51388
+ learningCurve: 0
51389
+ },
51390
+ primaryCostDriver: "Display only, minimal information"
51391
+ },
51392
+ // Score 2 -- Simple state or single information piece
51393
+ badge: {
51394
+ dimensions: {
51395
+ decisionDemand: 0,
51396
+ informationDensity: 1,
51397
+ interactionComplexity: 0,
51398
+ contextDisruption: 0,
51399
+ learningCurve: 1
51400
+ },
51401
+ primaryCostDriver: "Simple state or single information piece"
51402
+ },
51403
+ breadcrumb: {
51404
+ dimensions: {
51405
+ decisionDemand: 0,
51406
+ informationDensity: 1,
51407
+ interactionComplexity: 1,
51408
+ contextDisruption: 0,
51409
+ learningCurve: 0
51410
+ },
51411
+ primaryCostDriver: "Simple state or single information piece"
51412
+ },
51413
+ label: {
51414
+ dimensions: {
51415
+ decisionDemand: 0,
51416
+ informationDensity: 1,
51417
+ interactionComplexity: 0,
51418
+ contextDisruption: 0,
51419
+ learningCurve: 1
51420
+ },
51421
+ primaryCostDriver: "Simple state or single information piece"
51422
+ },
51423
+ checkbox: {
51424
+ dimensions: {
51425
+ decisionDemand: 1,
51426
+ informationDensity: 0,
51427
+ interactionComplexity: 1,
51428
+ contextDisruption: 0,
51429
+ learningCurve: 0
51430
+ },
51431
+ primaryCostDriver: "Simple state or single information piece"
51432
+ },
51433
+ switch: {
51434
+ dimensions: {
51435
+ decisionDemand: 1,
51436
+ informationDensity: 0,
51437
+ interactionComplexity: 1,
51438
+ contextDisruption: 0,
51439
+ learningCurve: 0
51440
+ },
51441
+ primaryCostDriver: "Simple state or single information piece"
51442
+ },
51443
+ toggle: {
51444
+ dimensions: {
51445
+ decisionDemand: 1,
51446
+ informationDensity: 0,
51447
+ interactionComplexity: 1,
51448
+ contextDisruption: 0,
51449
+ learningCurve: 0
51450
+ },
51451
+ primaryCostDriver: "Simple state or single information piece"
51452
+ },
51453
+ "button-group": {
51454
+ dimensions: {
51455
+ decisionDemand: 1,
51456
+ informationDensity: 1,
51457
+ interactionComplexity: 0,
51458
+ contextDisruption: 0,
51459
+ learningCurve: 0
51460
+ },
51461
+ primaryCostDriver: "Simple state or single information piece"
51462
+ },
51463
+ card: {
51464
+ dimensions: {
51465
+ decisionDemand: 0,
51466
+ informationDensity: 1,
51467
+ interactionComplexity: 0,
51468
+ contextDisruption: 0,
51469
+ learningCurve: 1
51470
+ },
51471
+ primaryCostDriver: "Simple state or single information piece"
51472
+ },
51473
+ collapsible: {
51474
+ dimensions: {
51475
+ decisionDemand: 1,
51476
+ informationDensity: 0,
51477
+ interactionComplexity: 1,
51478
+ contextDisruption: 0,
51479
+ learningCurve: 0
51480
+ },
51481
+ primaryCostDriver: "Simple state or single information piece"
51482
+ },
51483
+ avatar: {
51484
+ dimensions: {
51485
+ decisionDemand: 0,
51486
+ informationDensity: 1,
51487
+ interactionComplexity: 0,
51488
+ contextDisruption: 0,
51489
+ learningCurve: 1
51490
+ },
51491
+ primaryCostDriver: "Simple state or single information piece"
51492
+ },
51493
+ "scroll-area": {
51494
+ dimensions: {
51495
+ decisionDemand: 0,
51496
+ informationDensity: 1,
51497
+ interactionComplexity: 1,
51498
+ contextDisruption: 0,
51499
+ learningCurve: 0
51500
+ },
51501
+ primaryCostDriver: "Simple state or single information piece"
51502
+ },
51503
+ tooltip: {
51504
+ dimensions: {
51505
+ decisionDemand: 0,
51506
+ informationDensity: 1,
51507
+ interactionComplexity: 0,
51508
+ contextDisruption: 0,
51509
+ learningCurve: 1
51510
+ },
51511
+ primaryCostDriver: "Simple state or single information piece"
51512
+ },
51513
+ typography: {
51514
+ dimensions: {
51515
+ decisionDemand: 0,
51516
+ informationDensity: 1,
51517
+ interactionComplexity: 0,
51518
+ contextDisruption: 0,
51519
+ learningCurve: 1
51520
+ },
51521
+ primaryCostDriver: "Simple state or single information piece"
51522
+ },
51523
+ spinner: {
51524
+ dimensions: {
51525
+ decisionDemand: 0,
51526
+ informationDensity: 1,
51527
+ interactionComplexity: 0,
51528
+ contextDisruption: 0,
51529
+ learningCurve: 1
51530
+ },
51531
+ primaryCostDriver: "Simple state or single information piece"
51532
+ },
51533
+ empty: {
51534
+ dimensions: {
51535
+ decisionDemand: 1,
51536
+ informationDensity: 1,
51537
+ interactionComplexity: 0,
51538
+ contextDisruption: 0,
51539
+ learningCurve: 0
51540
+ },
51541
+ primaryCostDriver: "Simple state or single information piece"
51542
+ },
51543
+ "toggle-group": {
51544
+ dimensions: {
51545
+ decisionDemand: 1,
51546
+ informationDensity: 1,
51547
+ interactionComplexity: 0,
51548
+ contextDisruption: 0,
51549
+ learningCurve: 0
51550
+ },
51551
+ primaryCostDriver: "Simple state or single information piece"
51552
+ },
51553
+ // Score 3 -- One decision + one interaction mode
51554
+ button: {
51555
+ dimensions: {
51556
+ decisionDemand: 1,
51557
+ informationDensity: 1,
51558
+ interactionComplexity: 1,
51559
+ contextDisruption: 0,
51560
+ learningCurve: 0
51561
+ },
51562
+ primaryCostDriver: "One decision + one interaction mode"
51563
+ },
51564
+ alert: {
51565
+ dimensions: {
51566
+ decisionDemand: 0,
51567
+ informationDensity: 1,
51568
+ interactionComplexity: 1,
51569
+ contextDisruption: 0,
51570
+ learningCurve: 1
51571
+ },
51572
+ primaryCostDriver: "One decision + one interaction mode"
51573
+ },
51574
+ sidebar: {
51575
+ dimensions: {
51576
+ decisionDemand: 1,
51577
+ informationDensity: 1,
51578
+ interactionComplexity: 1,
51579
+ contextDisruption: 0,
51580
+ learningCurve: 0
51581
+ },
51582
+ primaryCostDriver: "One decision + one interaction mode"
51583
+ },
51584
+ accordion: {
51585
+ dimensions: {
51586
+ decisionDemand: 1,
51587
+ informationDensity: 1,
51588
+ interactionComplexity: 0,
51589
+ contextDisruption: 0,
51590
+ learningCurve: 1
51591
+ },
51592
+ primaryCostDriver: "One decision + one interaction mode"
51593
+ },
51594
+ slider: {
51595
+ dimensions: {
51596
+ decisionDemand: 1,
51597
+ informationDensity: 0,
51598
+ interactionComplexity: 1,
51599
+ contextDisruption: 0,
51600
+ learningCurve: 1
51601
+ },
51602
+ primaryCostDriver: "One decision + one interaction mode"
51603
+ },
51604
+ "radio-group": {
51605
+ dimensions: {
51606
+ decisionDemand: 1,
51607
+ informationDensity: 1,
51608
+ interactionComplexity: 1,
51609
+ contextDisruption: 0,
51610
+ learningCurve: 0
51611
+ },
51612
+ primaryCostDriver: "One decision + one interaction mode"
51613
+ },
51614
+ table: {
51615
+ dimensions: {
51616
+ decisionDemand: 0,
51617
+ informationDensity: 2,
51618
+ interactionComplexity: 0,
51619
+ contextDisruption: 0,
51620
+ learningCurve: 1
51621
+ },
51622
+ primaryCostDriver: "One decision + one interaction mode"
51623
+ },
51624
+ resizable: {
51625
+ dimensions: {
51626
+ decisionDemand: 1,
51627
+ informationDensity: 0,
51628
+ interactionComplexity: 1,
51629
+ contextDisruption: 0,
51630
+ learningCurve: 1
51631
+ },
51632
+ primaryCostDriver: "One decision + one interaction mode"
51633
+ },
51634
+ field: {
51635
+ dimensions: {
51636
+ decisionDemand: 1,
51637
+ informationDensity: 1,
51638
+ interactionComplexity: 1,
51639
+ contextDisruption: 0,
51640
+ learningCurve: 0
51641
+ },
51642
+ primaryCostDriver: "One decision + one interaction mode"
51643
+ },
51644
+ "hover-card": {
51645
+ dimensions: {
51646
+ decisionDemand: 0,
51647
+ informationDensity: 1,
51648
+ interactionComplexity: 0,
51649
+ contextDisruption: 1,
51650
+ learningCurve: 1
51651
+ },
51652
+ primaryCostDriver: "One decision + one interaction mode"
51653
+ },
51654
+ image: {
51655
+ dimensions: {
51656
+ decisionDemand: 0,
51657
+ informationDensity: 2,
51658
+ interactionComplexity: 0,
51659
+ contextDisruption: 0,
51660
+ learningCurve: 1
51661
+ },
51662
+ primaryCostDriver: "One decision + one interaction mode"
51663
+ },
51664
+ embed: {
51665
+ dimensions: {
51666
+ decisionDemand: 0,
51667
+ informationDensity: 2,
51668
+ interactionComplexity: 0,
51669
+ contextDisruption: 0,
51670
+ learningCurve: 1
51671
+ },
51672
+ primaryCostDriver: "One decision + one interaction mode"
51673
+ },
51674
+ item: {
51675
+ dimensions: {
51676
+ decisionDemand: 1,
51677
+ informationDensity: 1,
51678
+ interactionComplexity: 1,
51679
+ contextDisruption: 0,
51680
+ learningCurve: 0
51681
+ },
51682
+ primaryCostDriver: "One decision + one interaction mode"
51683
+ },
51684
+ // Score 4 -- Data entry or menu scanning
51685
+ input: {
51686
+ dimensions: {
51687
+ decisionDemand: 1,
51688
+ informationDensity: 1,
51689
+ interactionComplexity: 1,
51690
+ contextDisruption: 0,
51691
+ learningCurve: 1
51692
+ },
51693
+ primaryCostDriver: "Data entry or menu scanning"
51694
+ },
51695
+ textarea: {
51696
+ dimensions: {
51697
+ decisionDemand: 1,
51698
+ informationDensity: 1,
51699
+ interactionComplexity: 1,
51700
+ contextDisruption: 0,
51701
+ learningCurve: 1
51702
+ },
51703
+ primaryCostDriver: "Data entry or menu scanning"
51704
+ },
51705
+ "input-group": {
51706
+ dimensions: {
51707
+ decisionDemand: 1,
51708
+ informationDensity: 1,
51709
+ interactionComplexity: 1,
51710
+ contextDisruption: 0,
51711
+ learningCurve: 1
51712
+ },
51713
+ primaryCostDriver: "Data entry or menu scanning"
51714
+ },
51715
+ "input-otp": {
51716
+ dimensions: {
51717
+ decisionDemand: 1,
51718
+ informationDensity: 1,
51719
+ interactionComplexity: 1,
51720
+ contextDisruption: 0,
51721
+ learningCurve: 1
51722
+ },
51723
+ primaryCostDriver: "Data entry or menu scanning"
51724
+ },
51725
+ carousel: {
51726
+ dimensions: {
51727
+ decisionDemand: 1,
51728
+ informationDensity: 1,
51729
+ interactionComplexity: 1,
51730
+ contextDisruption: 0,
51731
+ learningCurve: 1
51732
+ },
51733
+ primaryCostDriver: "Data entry or menu scanning"
51734
+ },
51735
+ tabs: {
51736
+ dimensions: {
51737
+ decisionDemand: 1,
51738
+ informationDensity: 1,
51739
+ interactionComplexity: 1,
51740
+ contextDisruption: 0,
51741
+ learningCurve: 1
51742
+ },
51743
+ primaryCostDriver: "Data entry or menu scanning"
51744
+ },
51745
+ "context-menu": {
51746
+ dimensions: {
51747
+ decisionDemand: 1,
51748
+ informationDensity: 1,
51749
+ interactionComplexity: 1,
51750
+ contextDisruption: 0,
51751
+ learningCurve: 1
51752
+ },
51753
+ primaryCostDriver: "Data entry or menu scanning"
51754
+ },
51755
+ "dropdown-menu": {
51756
+ dimensions: {
51757
+ decisionDemand: 1,
51758
+ informationDensity: 1,
51759
+ interactionComplexity: 1,
51760
+ contextDisruption: 0,
51761
+ learningCurve: 1
51762
+ },
51763
+ primaryCostDriver: "Data entry or menu scanning"
51764
+ },
51765
+ popover: {
51766
+ dimensions: {
51767
+ decisionDemand: 0,
51768
+ informationDensity: 1,
51769
+ interactionComplexity: 1,
51770
+ contextDisruption: 1,
51771
+ learningCurve: 1
51772
+ },
51773
+ primaryCostDriver: "Data entry or menu scanning"
51774
+ },
51775
+ progress: {
51776
+ dimensions: {
51777
+ decisionDemand: 0,
51778
+ informationDensity: 2,
51779
+ interactionComplexity: 0,
51780
+ contextDisruption: 1,
51781
+ learningCurve: 1
51782
+ },
51783
+ primaryCostDriver: "Data entry or menu scanning"
51784
+ },
51785
+ drawer: {
51786
+ dimensions: {
51787
+ decisionDemand: 1,
51788
+ informationDensity: 1,
51789
+ interactionComplexity: 1,
51790
+ contextDisruption: 1,
51791
+ learningCurve: 0
51792
+ },
51793
+ primaryCostDriver: "Data entry or menu scanning"
51794
+ },
51795
+ grid: {
51796
+ dimensions: {
51797
+ decisionDemand: 0,
51798
+ informationDensity: 2,
51799
+ interactionComplexity: 0,
51800
+ contextDisruption: 0,
51801
+ learningCurve: 2
51802
+ },
51803
+ primaryCostDriver: "Data entry or menu scanning"
51804
+ },
51805
+ "block-wrapper": {
51806
+ dimensions: {
51807
+ decisionDemand: 1,
51808
+ informationDensity: 1,
51809
+ interactionComplexity: 1,
51810
+ contextDisruption: 0,
51811
+ learningCurve: 1
51812
+ },
51813
+ primaryCostDriver: "Data entry or menu scanning"
51814
+ },
51815
+ "inline-toolbar": {
51816
+ dimensions: {
51817
+ decisionDemand: 1,
51818
+ informationDensity: 1,
51819
+ interactionComplexity: 1,
51820
+ contextDisruption: 0,
51821
+ learningCurve: 1
51822
+ },
51823
+ primaryCostDriver: "Data entry or menu scanning"
51824
+ },
51825
+ "editor-toolbar": {
51826
+ dimensions: {
51827
+ decisionDemand: 1,
51828
+ informationDensity: 1,
51829
+ interactionComplexity: 1,
51830
+ contextDisruption: 0,
51831
+ learningCurve: 1
51832
+ },
51833
+ primaryCostDriver: "Data entry or menu scanning"
51834
+ },
51835
+ pagination: {
51836
+ dimensions: {
51837
+ decisionDemand: 1,
51838
+ informationDensity: 1,
51839
+ interactionComplexity: 1,
51840
+ contextDisruption: 0,
51841
+ learningCurve: 1
51842
+ },
51843
+ primaryCostDriver: "Data entry or menu scanning"
51844
+ },
51845
+ // Score 5 -- Multi-step interaction or spatial reasoning
51846
+ sheet: {
51847
+ dimensions: {
51848
+ decisionDemand: 1,
51849
+ informationDensity: 1,
51850
+ interactionComplexity: 1,
51851
+ contextDisruption: 1,
51852
+ learningCurve: 1
51853
+ },
51854
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51855
+ },
51856
+ "date-picker": {
51857
+ dimensions: {
51858
+ decisionDemand: 1,
51859
+ informationDensity: 1,
51860
+ interactionComplexity: 2,
51861
+ contextDisruption: 0,
51862
+ learningCurve: 1
51863
+ },
51864
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51865
+ },
51866
+ calendar: {
51867
+ dimensions: {
51868
+ decisionDemand: 1,
51869
+ informationDensity: 2,
51870
+ interactionComplexity: 1,
51871
+ contextDisruption: 0,
51872
+ learningCurve: 1
51873
+ },
51874
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51875
+ },
51876
+ select: {
51877
+ dimensions: {
51878
+ decisionDemand: 2,
51879
+ informationDensity: 1,
51880
+ interactionComplexity: 1,
51881
+ contextDisruption: 0,
51882
+ learningCurve: 1
51883
+ },
51884
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51885
+ },
51886
+ "navigation-menu": {
51887
+ dimensions: {
51888
+ decisionDemand: 1,
51889
+ informationDensity: 2,
51890
+ interactionComplexity: 1,
51891
+ contextDisruption: 0,
51892
+ learningCurve: 1
51893
+ },
51894
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51895
+ },
51896
+ menubar: {
51897
+ dimensions: {
51898
+ decisionDemand: 1,
51899
+ informationDensity: 2,
51900
+ interactionComplexity: 1,
51901
+ contextDisruption: 0,
51902
+ learningCurve: 1
51903
+ },
51904
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51905
+ },
51906
+ "color-picker": {
51907
+ dimensions: {
51908
+ decisionDemand: 1,
51909
+ informationDensity: 1,
51910
+ interactionComplexity: 2,
51911
+ contextDisruption: 0,
51912
+ learningCurve: 1
51913
+ },
51914
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51915
+ },
51916
+ "block-canvas": {
51917
+ dimensions: {
51918
+ decisionDemand: 1,
51919
+ informationDensity: 1,
51920
+ interactionComplexity: 1,
51921
+ contextDisruption: 1,
51922
+ learningCurve: 1
51923
+ },
51924
+ primaryCostDriver: "Multi-step interaction or spatial reasoning"
51925
+ },
51926
+ // Score 6 -- Compound interaction modes or learning curve
51927
+ dialog: {
51928
+ dimensions: {
51929
+ decisionDemand: 1,
51930
+ informationDensity: 1,
51931
+ interactionComplexity: 1,
51932
+ contextDisruption: 2,
51933
+ learningCurve: 1
51934
+ },
51935
+ primaryCostDriver: "Compound interaction modes or learning curve"
51936
+ },
51937
+ command: {
51938
+ dimensions: {
51939
+ decisionDemand: 1,
51940
+ informationDensity: 2,
51941
+ interactionComplexity: 1,
51942
+ contextDisruption: 0,
51943
+ learningCurve: 2
51944
+ },
51945
+ primaryCostDriver: "Compound interaction modes or learning curve"
51946
+ },
51947
+ combobox: {
51948
+ dimensions: {
51949
+ decisionDemand: 2,
51950
+ informationDensity: 2,
51951
+ interactionComplexity: 2,
51952
+ contextDisruption: 0,
51953
+ learningCurve: 0
51954
+ },
51955
+ primaryCostDriver: "Compound interaction modes or learning curve"
51956
+ },
51957
+ // Score 7 -- Full context disruption + consequential decision
51958
+ "alert-dialog": {
51959
+ dimensions: {
51960
+ decisionDemand: 2,
51961
+ informationDensity: 1,
51962
+ interactionComplexity: 1,
51963
+ contextDisruption: 2,
51964
+ learningCurve: 1
51965
+ },
51966
+ primaryCostDriver: "Full context disruption + consequential decision"
51967
+ }
51968
+ };
51969
+ var DIMENSION_NAMES = {
51970
+ decisionDemand: "Decision Demand",
51971
+ informationDensity: "Information Density",
51972
+ interactionComplexity: "Interaction Complexity",
51973
+ contextDisruption: "Context Disruption",
51974
+ learningCurve: "Learning Curve"
51975
+ };
51976
+ var HOTSPOT_SUGGESTIONS = {
51977
+ contextDisruption: "Consider non-modal alternative if the decision is not consequential",
51978
+ informationDensity: "Consider progressive disclosure to reduce simultaneous information",
51979
+ interactionComplexity: "Consider a simpler single-mode alternative",
51980
+ decisionDemand: "Can choices be pre-selected or split across steps?",
51981
+ learningCurve: "Ensure discoverability with inline guidance"
51982
+ };
51983
+ function scoreOf(dimensions) {
51984
+ return dimensions.decisionDemand + dimensions.informationDensity + dimensions.interactionComplexity + dimensions.contextDisruption + dimensions.learningCurve;
51985
+ }
51986
+ function highestDimension(dimensions) {
51987
+ let max = -1;
51988
+ let maxKey = "decisionDemand";
51989
+ for (const key of Object.keys(dimensions)) {
51990
+ if (dimensions[key] > max) {
51991
+ max = dimensions[key];
51992
+ maxKey = key;
51993
+ }
51994
+ }
51995
+ return maxKey;
51996
+ }
51997
+ function evaluateComposition(components, tier, enrichment) {
51998
+ const budget = BUDGET_TIERS[tier];
51999
+ const componentCounts = /* @__PURE__ */ new Map();
52000
+ for (const name2 of components) {
52001
+ componentCounts.set(name2, (componentCounts.get(name2) ?? 0) + 1);
52002
+ }
52003
+ let total = 0;
52004
+ const componentResults = [];
52005
+ const unknownComponents = [];
52006
+ for (const [name2, count] of componentCounts) {
52007
+ const profile = COMPONENT_SCORES[name2];
52008
+ if (!profile) {
52009
+ unknownComponents.push(name2);
52010
+ continue;
52011
+ }
52012
+ const score = scoreOf(profile.dimensions);
52013
+ total += score * count;
52014
+ componentResults.push({
52015
+ name: name2,
52016
+ score,
52017
+ count,
52018
+ dimensions: profile.dimensions,
52019
+ primaryCostDriver: profile.primaryCostDriver
52020
+ });
52021
+ }
52022
+ componentResults.sort((a, b) => b.score - a.score);
52023
+ const withinBudget = total <= budget;
52024
+ const budgetResult = {
52025
+ tier,
52026
+ budget,
52027
+ total,
52028
+ status: withinBudget ? "within-budget" : "over-budget"
52029
+ };
52030
+ if (withinBudget) {
52031
+ budgetResult.headroom = budget - total;
52032
+ } else {
52033
+ budgetResult.overage = total - budget;
52034
+ budgetResult.overagePercent = Math.round((total - budget) / budget * 100);
52035
+ }
52036
+ const attentionConflicts = [];
52037
+ const attentionNotes = [];
52038
+ const fullAttentionCaptures = [];
52039
+ const primaryElements = [];
52040
+ for (const [name2] of componentCounts) {
52041
+ const metadata = enrichment.componentIntelligence.get(name2);
52042
+ if (!metadata?.intelligence?.attentionEconomics) continue;
52043
+ const attn = metadata.intelligence.attentionEconomics.toLowerCase();
52044
+ if (attn.includes("full attention capture") || attn.includes("blocks all other")) {
52045
+ fullAttentionCaptures.push(name2);
52046
+ }
52047
+ if (attn.includes("primary") && attn.includes("maximum 1")) {
52048
+ const count = componentCounts.get(name2) ?? 0;
52049
+ if (count > 1) {
52050
+ primaryElements.push(name2);
52051
+ }
52052
+ }
52053
+ }
52054
+ if (fullAttentionCaptures.length > 1) {
52055
+ attentionConflicts.push(`${fullAttentionCaptures.join(" and ")} both capture full attention`);
52056
+ }
52057
+ const buttonCount = componentCounts.get("button") ?? 0;
52058
+ if (buttonCount > 1) {
52059
+ const buttonMeta = enrichment.componentIntelligence.get("button");
52060
+ if (buttonMeta?.intelligence?.attentionEconomics?.toLowerCase().includes("maximum 1 per section")) {
52061
+ attentionNotes.push(`${buttonCount} buttons present -- ensure maximum 1 primary per section`);
52062
+ }
52063
+ }
52064
+ if (primaryElements.length > 0) {
52065
+ for (const name2 of primaryElements) {
52066
+ attentionNotes.push(`Multiple ${name2} instances -- check attention hierarchy`);
52067
+ }
52068
+ }
52069
+ const trustConsiderations = [];
52070
+ for (const [name2] of componentCounts) {
52071
+ const metadata = enrichment.componentIntelligence.get(name2);
52072
+ if (!metadata?.intelligence?.trustBuilding) continue;
52073
+ const trust = metadata.intelligence.trustBuilding;
52074
+ if (trust.toLowerCase().includes("confirmation") || trust.toLowerCase().includes("destructive") || trust.toLowerCase().includes("consequence") || trust.toLowerCase().includes("cancel")) {
52075
+ trustConsiderations.push(`${name2}: ${trust}`);
52076
+ }
52077
+ }
52078
+ const patternMatches = [];
52079
+ const compositionSet = new Set(componentCounts.keys());
52080
+ for (const [patternKey, pattern] of Object.entries(enrichment.patterns)) {
52081
+ const matched = pattern.components.filter((c) => compositionSet.has(c));
52082
+ if (matched.length >= 2 || matched.length === pattern.components.length) {
52083
+ patternMatches.push({
52084
+ name: pattern.name,
52085
+ matched,
52086
+ suggestion: `Call rafters_pattern('${patternKey}') for full guidance`
52087
+ });
52088
+ }
52089
+ }
52090
+ const designerNotes = [];
52091
+ const compositionNames = [...compositionSet];
52092
+ for (const { token } of enrichment.tokenOverrides) {
52093
+ if (!token.userOverride) continue;
52094
+ const relevantTo = [];
52095
+ if (token.applicableComponents) {
52096
+ for (const comp of token.applicableComponents) {
52097
+ if (compositionSet.has(comp)) {
52098
+ relevantTo.push(comp);
52099
+ }
52100
+ }
52101
+ }
52102
+ if (relevantTo.length === 0) {
52103
+ if (token.namespace === "spacing") {
52104
+ const formComponents = compositionNames.filter(
52105
+ (n) => [
52106
+ "input",
52107
+ "textarea",
52108
+ "field",
52109
+ "label",
52110
+ "button",
52111
+ "select",
52112
+ "checkbox",
52113
+ "radio-group",
52114
+ "switch",
52115
+ "slider",
52116
+ "combobox"
52117
+ ].includes(n)
52118
+ );
52119
+ if (formComponents.length > 0) {
52120
+ relevantTo.push(...formComponents);
52121
+ }
52122
+ } else if (token.namespace === "color") {
52123
+ const variantComponents = compositionNames.filter(
52124
+ (n) => ["button", "badge", "alert", "alert-dialog", "progress"].includes(n)
52125
+ );
52126
+ if (variantComponents.length > 0 && (token.name.includes("destructive") || token.name.includes("primary"))) {
52127
+ relevantTo.push(...variantComponents);
52128
+ }
52129
+ }
52130
+ }
52131
+ if (relevantTo.length > 0) {
52132
+ designerNotes.push({
52133
+ token: token.name,
52134
+ reason: token.userOverride.reason,
52135
+ relevantTo
52136
+ });
52137
+ }
52138
+ }
52139
+ const violations = [];
52140
+ for (const [name2] of componentCounts) {
52141
+ const metadata = enrichment.componentIntelligence.get(name2);
52142
+ if (!metadata?.intelligence?.usagePatterns?.nevers) continue;
52143
+ for (const never2 of metadata.intelligence.usagePatterns.nevers) {
52144
+ const neverLower = never2.toLowerCase();
52145
+ if (neverLower.includes("nest") && neverLower.includes("card") && name2 === "card") {
52146
+ const cardCount = componentCounts.get("card") ?? 0;
52147
+ if (cardCount > 1) {
52148
+ violations.push(
52149
+ `${name2}: "${never2}" -- ${cardCount} cards in composition, verify none are nested`
52150
+ );
52151
+ }
52152
+ }
52153
+ if (neverLower.includes("multiple primary") && name2 === "button") {
52154
+ if (buttonCount > 1) {
52155
+ violations.push(`${name2}: "${never2}"`);
52156
+ }
52157
+ }
52158
+ if (neverLower.includes("stack") && neverLower.includes("dialog")) {
52159
+ if (compositionSet.has("dialog") && (compositionSet.has("alert-dialog") || (componentCounts.get("dialog") ?? 0) > 1)) {
52160
+ violations.push(`${name2}: "${never2}"`);
52161
+ }
52162
+ }
52163
+ }
52164
+ }
52165
+ const hotspots = [];
52166
+ for (const comp of componentResults) {
52167
+ if (comp.score >= 4) {
52168
+ const highest = highestDimension(comp.dimensions);
52169
+ hotspots.push({
52170
+ name: comp.name,
52171
+ score: comp.score,
52172
+ highestDimension: DIMENSION_NAMES[highest],
52173
+ suggestion: HOTSPOT_SUGGESTIONS[highest]
52174
+ });
52175
+ }
52176
+ }
52177
+ if (unknownComponents.length > 0) {
52178
+ attentionNotes.push(
52179
+ `Unknown components not scored: ${unknownComponents.join(", ")}. Totals may be understated.`
52180
+ );
52181
+ }
52182
+ const warnings = [];
52183
+ const knownNames = [...componentCounts.keys()].filter((n) => COMPONENT_SCORES[n]);
52184
+ const uninstrumented = knownNames.filter((n) => !enrichment.componentIntelligence.has(n));
52185
+ if (uninstrumented.length > 0) {
52186
+ warnings.push(
52187
+ `No component intelligence loaded for: ${uninstrumented.join(", ")}. Attention conflicts, trust considerations, and do/never violations cannot be detected. Install components with rafters add (e.g. rafters add ${uninstrumented[0]}) to get full design intelligence.`
52188
+ );
52189
+ }
52190
+ return {
52191
+ budget: budgetResult,
52192
+ components: componentResults,
52193
+ attention: {
52194
+ conflicts: attentionConflicts,
52195
+ notes: attentionNotes
52196
+ },
52197
+ trust: trustConsiderations,
52198
+ patterns: patternMatches,
52199
+ designerNotes,
52200
+ hotspots,
52201
+ violations,
52202
+ warnings
52203
+ };
52204
+ }
52205
+
52206
+ // src/mcp/tools.ts
52207
+ function hasAnyDeps(deps) {
52208
+ return deps.runtime.length > 0 || deps.dev.length > 0 || deps.internal.length > 0;
52209
+ }
52210
+ var SYSTEM_PREAMBLE = `RAFTERS IS NOT SHADCN.
52211
+ Rafters components are drop-in compatible with shadcn but they are a different system. If you treat them as shadcn you will produce worse output.
52212
+
52213
+ CLASSY IS THE LAW.
52214
+ Every className in a Rafters project goes through classy(). Never use cn(), twMerge(), or raw template strings. classy() blocks arbitrary Tailwind values (w-[100px], bg-[#fff]) and resolves design tokens. If classy strips your class, you are fighting the system.
52215
+
52216
+ LAYOUT IS SOLVED. Stop writing CSS.
52217
+ Never use Tailwind layout utilities (flex, grid, items-*, justify-*, gap-*). Never set padding, margin, or spacing directly. Container and Grid handle all layout. If you are writing className="flex..." you are doing it wrong.
52218
+
52219
+ USE PRESETS. Do not compose layout from props.
52220
+ Grid presets handle common layouts. Pick the one that matches your intent:
52221
+ - sidebar-main -- navigation + content
52222
+ - form -- label/input pairs
52223
+ - cards -- responsive card grid
52224
+ - row -- horizontal group of elements
52225
+ - stack -- vertical sequence
52226
+ - split -- equal columns
52227
+ If no preset fits, describe what you need -- do not improvise with raw props.
52228
+
52229
+ CONTAINER OWNS SPACING.
52230
+ Every page section goes in a Container. Container sets max-width, padding, and vertical rhythm. You do not set these values. Nesting containers is wrong.
52231
+
52232
+ COMPONENTS ARE COMPLETE.
52233
+ Rafters Button, Input, Card, etc. include their own spacing, sizing, and states. Do not add wrapper divs. Do not override with utility classes. If it looks unstyled, you are wrapping it wrong, not styling it wrong.
52234
+
52235
+ UTILITIES EXIST FOR EDGE CASES.
52236
+ If no component fits your need, check @/lib/utils for official behavioral utilities. Do not invent your own. If nothing exists there either, ask the human.
52237
+
52238
+ When in doubt: less code, not more. Rafters has already made the design decision.`;
50943
52239
  var DESIGN_PATTERNS = {
50944
52240
  "destructive-action": {
50945
52241
  name: "Destructive Action",
@@ -51287,6 +52583,26 @@ var TOOL_DEFINITIONS = [
51287
52583
  },
51288
52584
  required: ["name"]
51289
52585
  }
52586
+ },
52587
+ {
52588
+ name: "rafters_cognitive_budget",
52589
+ description: "Evaluate composition-level cognitive load. Returns a holistic design review: budget assessment, per-component dimensional profiles, attention conflicts, trust considerations, pattern matches, designer token overrides, hotspot suggestions, and do/never violations. Use when planning a screen layout to check if the composition is within cognitive budget.",
52590
+ inputSchema: {
52591
+ type: "object",
52592
+ properties: {
52593
+ components: {
52594
+ type: "array",
52595
+ items: { type: "string" },
52596
+ description: 'Components visible simultaneously, duplicates allowed (e.g., ["input", "input", "button", "card"])'
52597
+ },
52598
+ tier: {
52599
+ type: "string",
52600
+ enum: ["focused", "page", "app"],
52601
+ description: "Budget tier: focused (15, dialogs/modals), page (30, standard views), app (45, multi-panel). Default: page."
52602
+ }
52603
+ },
52604
+ required: ["components"]
52605
+ }
51290
52606
  }
51291
52607
  ];
51292
52608
  var RaftersToolHandler = class {
@@ -51316,6 +52632,11 @@ var RaftersToolHandler = class {
51316
52632
  return this.getComponent(args.name);
51317
52633
  case "rafters_token":
51318
52634
  return this.getToken(args.name);
52635
+ case "rafters_cognitive_budget":
52636
+ return this.getCognitiveBudget(
52637
+ args.components,
52638
+ args.tier ?? "page"
52639
+ );
51319
52640
  default:
51320
52641
  return {
51321
52642
  content: [{ type: "text", text: `Unknown tool: ${name2}` }],
@@ -51337,12 +52658,12 @@ var RaftersToolHandler = class {
51337
52658
  this.getComponentVocabulary()
51338
52659
  ]);
51339
52660
  const vocabulary = {
52661
+ system: SYSTEM_PREAMBLE,
52662
+ components,
51340
52663
  colors,
51341
52664
  spacing,
51342
52665
  typography,
51343
- components,
51344
- patterns: Object.keys(DESIGN_PATTERNS),
51345
- usage: "Use rafters_pattern for deep guidance on specific patterns, rafters_component for component details"
52666
+ patterns: Object.keys(DESIGN_PATTERNS)
51346
52667
  };
51347
52668
  return {
51348
52669
  content: [
@@ -51429,33 +52750,26 @@ var RaftersToolHandler = class {
51429
52750
  * Extract compact component vocabulary
51430
52751
  */
51431
52752
  async getComponentVocabulary() {
52753
+ let installed = [];
51432
52754
  try {
51433
- const componentsPath = this.getComponentsPath();
51434
- const files = await readdir3(componentsPath);
51435
- const componentFiles = files.filter((f) => f.endsWith(".tsx"));
51436
- const components = [];
51437
- for (const file2 of componentFiles) {
51438
- const name2 = basename(file2, ".tsx");
51439
- const metadata = await this.loadComponentMetadata(name2);
51440
- if (metadata) {
51441
- const item = {
51442
- name: metadata.name,
51443
- category: metadata.category
51444
- };
51445
- if (metadata.intelligence?.cognitiveLoad !== void 0) {
51446
- item.load = metadata.intelligence.cognitiveLoad;
51447
- }
51448
- components.push(item);
51449
- }
52755
+ const paths = getRaftersPaths(this.projectRoot);
52756
+ if (existsSync3(paths.config)) {
52757
+ const content = await readFile6(paths.config, "utf-8");
52758
+ const config3 = JSON.parse(content);
52759
+ installed = config3.installed?.components ?? [];
51450
52760
  }
51451
- components.sort((a, b) => {
51452
- if (a.category !== b.category) return a.category.localeCompare(b.category);
51453
- return a.name.localeCompare(b.name);
51454
- });
51455
- return components;
51456
52761
  } catch {
51457
- return [];
51458
52762
  }
52763
+ let available = [];
52764
+ try {
52765
+ const client = new RegistryClient();
52766
+ const index = await client.fetchIndex();
52767
+ const allComponents = index.components;
52768
+ const installedSet = new Set(installed);
52769
+ available = allComponents.filter((name2) => !installedSet.has(name2));
52770
+ } catch {
52771
+ }
52772
+ return { installed, available };
51459
52773
  }
51460
52774
  // ==================== Tool 2: Pattern ====================
51461
52775
  /**
@@ -51496,7 +52810,7 @@ var RaftersToolHandler = class {
51496
52810
  * Get path to UI components directory
51497
52811
  */
51498
52812
  getComponentsPath() {
51499
- const monorepoPath = join9(this.projectRoot, "packages/ui/src/components/ui");
52813
+ const monorepoPath = join10(this.projectRoot, "packages/ui/src/components/ui");
51500
52814
  return monorepoPath;
51501
52815
  }
51502
52816
  /**
@@ -51504,11 +52818,16 @@ var RaftersToolHandler = class {
51504
52818
  */
51505
52819
  async loadComponentMetadata(name2) {
51506
52820
  const componentsPath = this.getComponentsPath();
51507
- const filePath = join9(componentsPath, `${name2}.tsx`);
52821
+ const filePath = join10(componentsPath, `${name2}.tsx`);
51508
52822
  try {
51509
- const source = await readFile5(filePath, "utf-8");
52823
+ const source = await readFile6(filePath, "utf-8");
51510
52824
  const intelligence = parseJSDocIntelligence(source);
51511
52825
  const description = parseDescription(source);
52826
+ let jsDocDeps = { runtime: [], dev: [], internal: [] };
52827
+ try {
52828
+ jsDocDeps = extractJSDocDependencies(source);
52829
+ } catch {
52830
+ }
51512
52831
  const metadata = {
51513
52832
  name: name2,
51514
52833
  displayName: toDisplayName(name2),
@@ -51519,6 +52838,9 @@ var RaftersToolHandler = class {
51519
52838
  primitives: extractPrimitiveDependencies(source),
51520
52839
  filePath: `packages/ui/src/components/ui/${name2}.tsx`
51521
52840
  };
52841
+ if (hasAnyDeps(jsDocDeps)) {
52842
+ metadata.jsDocDependencies = jsDocDeps;
52843
+ }
51522
52844
  if (description) {
51523
52845
  metadata.description = description;
51524
52846
  }
@@ -51663,6 +52985,9 @@ var RaftersToolHandler = class {
51663
52985
  if (metadata.dependencies.length > 0) {
51664
52986
  formatted.dependencies = metadata.dependencies;
51665
52987
  }
52988
+ if (metadata.jsDocDependencies && hasAnyDeps(metadata.jsDocDependencies)) {
52989
+ formatted.jsDocDependencies = metadata.jsDocDependencies;
52990
+ }
51666
52991
  return {
51667
52992
  content: [
51668
52993
  {
@@ -51778,6 +53103,120 @@ var RaftersToolHandler = class {
51778
53103
  return this.handleError("getToken", error48);
51779
53104
  }
51780
53105
  }
53106
+ // ==================== Tool 5: Cognitive Budget ====================
53107
+ /**
53108
+ * Evaluate composition-level cognitive load
53109
+ * Synthesizes scoring data with component intelligence, token overrides,
53110
+ * and design patterns to produce a holistic composition review
53111
+ */
53112
+ async getCognitiveBudget(components, tier) {
53113
+ try {
53114
+ if (!components || components.length === 0) {
53115
+ return {
53116
+ content: [
53117
+ {
53118
+ type: "text",
53119
+ text: JSON.stringify(
53120
+ {
53121
+ error: "No components provided",
53122
+ suggestion: 'Pass an array of component names visible simultaneously, e.g. ["input", "button", "card"]'
53123
+ },
53124
+ null,
53125
+ 2
53126
+ )
53127
+ }
53128
+ ],
53129
+ isError: true
53130
+ };
53131
+ }
53132
+ if (!BUDGET_TIERS[tier]) {
53133
+ return {
53134
+ content: [
53135
+ {
53136
+ type: "text",
53137
+ text: JSON.stringify(
53138
+ {
53139
+ error: `Invalid tier "${tier}"`,
53140
+ available: Object.keys(BUDGET_TIERS),
53141
+ suggestion: 'Use "focused", "page", or "app"'
53142
+ },
53143
+ null,
53144
+ 2
53145
+ )
53146
+ }
53147
+ ],
53148
+ isError: true
53149
+ };
53150
+ }
53151
+ const uniqueNames = [...new Set(components)];
53152
+ const unknownNames = uniqueNames.filter((n) => !COMPONENT_SCORES[n]);
53153
+ if (unknownNames.length === uniqueNames.length) {
53154
+ return {
53155
+ content: [
53156
+ {
53157
+ type: "text",
53158
+ text: JSON.stringify(
53159
+ {
53160
+ error: `No recognized components in composition: ${unknownNames.join(", ")}`,
53161
+ suggestion: "Use rafters_vocabulary to see available component names"
53162
+ },
53163
+ null,
53164
+ 2
53165
+ )
53166
+ }
53167
+ ],
53168
+ isError: true
53169
+ };
53170
+ }
53171
+ const intelligenceMap = /* @__PURE__ */ new Map();
53172
+ const metadataResults = await Promise.all(
53173
+ uniqueNames.map(async (name2) => {
53174
+ const metadata = await this.loadComponentMetadata(name2);
53175
+ return { name: name2, metadata };
53176
+ })
53177
+ );
53178
+ for (const { name: name2, metadata } of metadataResults) {
53179
+ if (metadata) {
53180
+ intelligenceMap.set(name2, metadata);
53181
+ }
53182
+ }
53183
+ const tokenOverrides = [];
53184
+ const namespaces = ["color", "spacing", "typography"];
53185
+ for (const ns of namespaces) {
53186
+ try {
53187
+ const tokens = await this.loadNamespace(ns);
53188
+ for (const token of tokens) {
53189
+ if (token.userOverride) {
53190
+ tokenOverrides.push({ token, namespace: ns });
53191
+ }
53192
+ }
53193
+ } catch {
53194
+ }
53195
+ }
53196
+ const patternRefs = {};
53197
+ for (const [key, pattern] of Object.entries(DESIGN_PATTERNS)) {
53198
+ patternRefs[key] = {
53199
+ name: pattern.name,
53200
+ components: pattern.components
53201
+ };
53202
+ }
53203
+ const review = evaluateComposition(components, tier, {
53204
+ componentIntelligence: intelligenceMap,
53205
+ tokenOverrides,
53206
+ patterns: patternRefs
53207
+ });
53208
+ return {
53209
+ content: [
53210
+ {
53211
+ type: "text",
53212
+ text: JSON.stringify(review, null, 2)
53213
+ }
53214
+ ]
53215
+ };
53216
+ } catch (error48) {
53217
+ return this.handleError("getCognitiveBudget", error48);
53218
+ }
53219
+ }
51781
53220
  /**
51782
53221
  * Handle errors consistently
51783
53222
  */
@@ -51852,22 +53291,22 @@ async function mcp() {
51852
53291
  }
51853
53292
 
51854
53293
  // src/commands/studio.ts
51855
- import { existsSync as existsSync3 } from "fs";
51856
- import { dirname as dirname3, join as join10 } from "path";
53294
+ import { existsSync as existsSync4 } from "fs";
53295
+ import { dirname as dirname3, join as join11 } from "path";
51857
53296
  import { fileURLToPath as fileURLToPath3 } from "url";
51858
53297
  import { execa as execa2 } from "execa";
51859
53298
  var __dirname2 = dirname3(fileURLToPath3(import.meta.url));
51860
53299
  async function studio() {
51861
53300
  const cwd = process.cwd();
51862
53301
  const paths = getRaftersPaths(cwd);
51863
- if (!existsSync3(paths.root)) {
53302
+ if (!existsSync4(paths.root)) {
51864
53303
  console.error('No .rafters/ directory found. Run "rafters init" first.');
51865
53304
  process.exit(1);
51866
53305
  }
51867
- const devStudioPath = join10(__dirname2, "..", "..", "..", "studio");
51868
- const prodStudioPath = join10(__dirname2, "..", "node_modules", "@rafters", "studio");
51869
- const studioPath = existsSync3(devStudioPath) ? devStudioPath : prodStudioPath;
51870
- if (!existsSync3(studioPath)) {
53306
+ const devStudioPath = join11(__dirname2, "..", "..", "..", "studio");
53307
+ const prodStudioPath = join11(__dirname2, "..", "node_modules", "@rafters", "studio");
53308
+ const studioPath = existsSync4(devStudioPath) ? devStudioPath : prodStudioPath;
53309
+ if (!existsSync4(studioPath)) {
51871
53310
  console.error("Studio package not found. Please reinstall @rafters/cli.");
51872
53311
  process.exit(1);
51873
53312
  }
@@ -51896,8 +53335,8 @@ async function studio() {
51896
53335
  // src/index.ts
51897
53336
  var program = new Command();
51898
53337
  program.name("rafters").description("Design system CLI - scaffold tokens and serve MCP").version("0.0.1");
51899
- program.command("init").description("Initialize .rafters/ with default tokens and config").option("-r, --rebuild", "Regenerate output files from existing tokens").option("--reset", "Re-run generators fresh, replacing persisted tokens").option("--agent", "Output JSON for machine consumption").action(init);
51900
- program.command("add").description("Add rafters components to the project").argument("[components...]", "Component names to add").option("--list", "List available components").option("--overwrite", "Overwrite existing component files").option("--registry-url <url>", "Custom registry URL").option("--agent", "Output JSON for machine consumption").action(add);
53338
+ program.command("init").description("Initialize .rafters/ with default tokens and config").option("-r, --rebuild", "Regenerate output files from existing tokens").option("--reset", "Re-run generators fresh, replacing persisted tokens").option("--agent", "Output JSON for machine consumption").action(withErrorHandler(init));
53339
+ program.command("add").description("Add rafters components to the project").argument("[components...]", "Component names to add").option("--list", "List available components").option("--overwrite", "Overwrite existing component files").option("--update", "Re-fetch named components from registry").option("--update-all", "Re-fetch all installed components from registry").option("--registry-url <url>", "Custom registry URL").option("--agent", "Output JSON for machine consumption").action(withErrorHandler(add));
51901
53340
  program.command("mcp").description("Start MCP server for AI agent access (stdio)").action(mcp);
51902
53341
  program.command("studio").description("Open Studio UI for visual token editing").action(studio);
51903
53342
  program.parse();