rafters 0.0.52 → 0.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +331 -164
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -241,6 +241,18 @@ var registryClient = new RegistryClient();
241
241
  import { existsSync } from "fs";
242
242
  import { readFile } from "fs/promises";
243
243
  import { join } from "path";
244
+ var SELECTABLE_FRAMEWORKS = [
245
+ "next",
246
+ "vite",
247
+ "remix",
248
+ "react-router",
249
+ "astro",
250
+ "wc",
251
+ "vanilla"
252
+ ];
253
+ function isSelectableFramework(value2) {
254
+ return SELECTABLE_FRAMEWORKS.includes(value2);
255
+ }
244
256
  var CONFIG_FILE_FRAMEWORKS = [
245
257
  { files: ["astro.config.mjs", "astro.config.ts", "astro.config.js"], framework: "astro" },
246
258
  { files: ["next.config.mjs", "next.config.ts", "next.config.js"], framework: "next" },
@@ -313,6 +325,7 @@ async function detectShadcn(cwd) {
313
325
  }
314
326
  function frameworkToTarget(framework) {
315
327
  if (framework === "astro") return "astro";
328
+ if (framework === "wc") return "wc";
316
329
  return "react";
317
330
  }
318
331
  function targetToExtension(target) {
@@ -320,7 +333,8 @@ function targetToExtension(target) {
320
333
  react: ".tsx",
321
334
  astro: ".astro",
322
335
  vue: ".vue",
323
- svelte: ".svelte"
336
+ svelte: ".svelte",
337
+ wc: ".element.ts"
324
338
  };
325
339
  return map[target];
326
340
  }
@@ -849,7 +863,8 @@ async function installRegistryDependencies(items, targetDir, options = {}) {
849
863
  }
850
864
 
851
865
  // src/utils/paths.ts
852
- import { join as join3 } from "path";
866
+ import { realpathSync } from "fs";
867
+ import { isAbsolute, join as join3, relative, resolve } from "path";
853
868
  function getRaftersPaths(projectRoot = process.cwd()) {
854
869
  const root = join3(projectRoot, ".rafters");
855
870
  return {
@@ -860,6 +875,63 @@ function getRaftersPaths(projectRoot = process.cwd()) {
860
875
  importPending: join3(root, "import-pending.json")
861
876
  };
862
877
  }
878
+ var PathEntrySchema = external_exports.union([
879
+ external_exports.string(),
880
+ external_exports.object({ path: external_exports.string(), root: external_exports.literal(true).optional() })
881
+ ]);
882
+ var PathFieldSchema = external_exports.union([external_exports.string(), external_exports.array(PathEntrySchema)]);
883
+ function entryPath(entry) {
884
+ return typeof entry === "string" ? entry : entry.path;
885
+ }
886
+ function entryHasExplicitRoot(entry) {
887
+ return typeof entry === "object" && entry.root === true;
888
+ }
889
+ function tryRealpath(absPath) {
890
+ try {
891
+ return realpathSync(absPath);
892
+ } catch {
893
+ return absPath;
894
+ }
895
+ }
896
+ function isInsideCwd(absPath, cwdReal) {
897
+ const rel = relative(cwdReal, absPath);
898
+ return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
899
+ }
900
+ function resolveRoot(field, cwd, fallback) {
901
+ const cwdReal = tryRealpath(resolve(cwd));
902
+ if (typeof field === "string") {
903
+ return field;
904
+ }
905
+ for (const entry of field) {
906
+ if (entryHasExplicitRoot(entry)) {
907
+ return entryPath(entry);
908
+ }
909
+ }
910
+ for (const entry of field) {
911
+ const p2 = entryPath(entry);
912
+ const abs = isAbsolute(p2) ? p2 : resolve(cwdReal, p2);
913
+ if (isInsideCwd(tryRealpath(abs), cwdReal)) return p2;
914
+ }
915
+ return fallback;
916
+ }
917
+ function resolveReadSet(field, cwd, fallback) {
918
+ const cwdReal = tryRealpath(resolve(cwd));
919
+ const entries = typeof field === "string" ? [field] : field.map(entryPath);
920
+ const root = resolveRoot(field, cwd, fallback ?? entries[0] ?? "");
921
+ const ordered = [root, ...entries.filter((e) => e !== root)];
922
+ const seen = /* @__PURE__ */ new Set();
923
+ const out = [];
924
+ for (const entry of ordered) {
925
+ if (!entry) continue;
926
+ const abs = isAbsolute(entry) ? entry : resolve(cwdReal, entry);
927
+ const real = tryRealpath(abs);
928
+ if (!seen.has(real)) {
929
+ seen.add(real);
930
+ out.push(real);
931
+ }
932
+ }
933
+ return out;
934
+ }
863
935
 
864
936
  // src/commands/add.ts
865
937
  async function isInitialized(cwd) {
@@ -935,50 +1007,45 @@ function isAlreadyInstalled(config2, item) {
935
1007
  }
936
1008
  function trackInstalled(config2, items) {
937
1009
  if (!config2.installed) {
938
- config2.installed = { components: [], primitives: [], composites: [] };
939
- }
940
- if (!config2.installed.composites) {
941
- config2.installed.composites = [];
1010
+ config2.installed = { components: [], primitives: [], composites: [], rules: [] };
942
1011
  }
1012
+ const installed = config2.installed;
1013
+ if (!installed.composites) installed.composites = [];
1014
+ if (!installed.rules) installed.rules = [];
943
1015
  for (const item of items) {
944
- if (item.type === "ui") {
945
- if (!config2.installed.components.includes(item.name)) {
946
- config2.installed.components.push(item.name);
947
- }
948
- } else if (item.type === "composite") {
949
- if (!config2.installed.composites.includes(item.name)) {
950
- config2.installed.composites.push(item.name);
951
- }
952
- } else {
953
- if (!config2.installed.primitives.includes(item.name)) {
954
- config2.installed.primitives.push(item.name);
955
- }
956
- }
1016
+ const bucket = item.type === "ui" ? installed.components : item.type === "composite" ? installed.composites : installed.primitives;
1017
+ if (!bucket.includes(item.name)) bucket.push(item.name);
957
1018
  }
958
- config2.installed.components.sort();
959
- config2.installed.primitives.sort();
960
- config2.installed.composites.sort();
1019
+ installed.components.sort();
1020
+ installed.primitives.sort();
1021
+ installed.composites.sort();
1022
+ installed.rules.sort();
1023
+ }
1024
+ function rootFor(field, cwd, fallback) {
1025
+ return field === void 0 ? fallback : resolveRoot(field, cwd, fallback);
961
1026
  }
962
- function transformPath(registryPath, config2) {
1027
+ function transformPath(registryPath, config2, cwd) {
963
1028
  if (!config2) return registryPath;
964
- if (registryPath.startsWith("components/ui/")) {
965
- return registryPath.replace("components/ui/", `${config2.componentsPath}/`);
966
- }
967
- if (registryPath.startsWith("lib/primitives/")) {
968
- return registryPath.replace("lib/primitives/", `${config2.primitivesPath}/`);
969
- }
970
- if (registryPath.startsWith("composites/")) {
971
- return registryPath.replace("composites/", `${config2.compositesPath}/`);
1029
+ const replacements = [
1030
+ ["components/ui/", config2.componentsPath, "components/ui"],
1031
+ ["lib/primitives/", config2.primitivesPath, "lib/primitives"],
1032
+ ["composites/", config2.compositesPath, "composites"],
1033
+ ["rules/", config2.rulesPath, "rules"]
1034
+ ];
1035
+ for (const [prefix, field, fallback] of replacements) {
1036
+ if (registryPath.startsWith(prefix)) {
1037
+ return registryPath.replace(prefix, `${rootFor(field, cwd, fallback)}/`);
1038
+ }
972
1039
  }
973
1040
  return registryPath;
974
1041
  }
975
1042
  function fileExists(cwd, relativePath) {
976
1043
  return existsSync2(join4(cwd, relativePath));
977
1044
  }
978
- function transformFileContent(content, config2, fileType = "component") {
1045
+ function transformFileContent(content, config2, fileType = "component", cwd = process.cwd()) {
979
1046
  let transformed = content;
980
- const componentsPath = config2?.componentsPath ?? "components/ui";
981
- const primitivesPath = config2?.primitivesPath ?? "lib/primitives";
1047
+ const componentsPath = rootFor(config2?.componentsPath, cwd, "components/ui");
1048
+ const primitivesPath = rootFor(config2?.primitivesPath, cwd, "lib/primitives");
982
1049
  const stripSourceRoot = (p2) => p2.replace(/^(src|app)\//, "");
983
1050
  const aliasComponents = stripSourceRoot(componentsPath);
984
1051
  const aliasPrimitives = stripSourceRoot(primitivesPath);
@@ -1027,7 +1094,7 @@ async function installItem(cwd, item, options, config2) {
1027
1094
  }
1028
1095
  }
1029
1096
  for (const file of filesToInstall) {
1030
- const projectPath2 = transformPath(file.path, config2);
1097
+ const projectPath2 = transformPath(file.path, config2, cwd);
1031
1098
  const targetPath = join4(cwd, projectPath2);
1032
1099
  if (fileExists(cwd, projectPath2)) {
1033
1100
  if (!options.overwrite) {
@@ -1043,7 +1110,7 @@ async function installItem(cwd, item, options, config2) {
1043
1110
  }
1044
1111
  await mkdir(dirname(targetPath), { recursive: true });
1045
1112
  const fileType = item.type === "primitive" ? "primitive" : "component";
1046
- const transformedContent = transformFileContent(file.content, config2, fileType);
1113
+ const transformedContent = transformFileContent(file.content, config2, fileType, cwd);
1047
1114
  await writeFile(targetPath, transformedContent, "utf-8");
1048
1115
  installedFiles.push(projectPath2);
1049
1116
  }
@@ -1228,10 +1295,11 @@ async function add(componentArgs, options) {
1228
1295
  componentsPath: "components/ui",
1229
1296
  primitivesPath: "lib/primitives",
1230
1297
  compositesPath: "composites",
1298
+ rulesPath: "rules",
1231
1299
  cssPath: null,
1232
1300
  shadcn: false,
1233
1301
  exports: DEFAULT_EXPORTS,
1234
- installed: { components: [], primitives: [], composites: [] }
1302
+ installed: { components: [], primitives: [], composites: [], rules: [] }
1235
1303
  };
1236
1304
  trackInstalled(newConfig, installedItems);
1237
1305
  await saveConfig(cwd, newConfig);
@@ -1256,7 +1324,7 @@ async function add(componentArgs, options) {
1256
1324
  // src/commands/import.ts
1257
1325
  import { existsSync as existsSync3 } from "fs";
1258
1326
  import { rename as rename2 } from "fs/promises";
1259
- import { relative as relative2 } from "path";
1327
+ import { relative as relative3 } from "path";
1260
1328
 
1261
1329
  // src/onboard/importers/generic-css.ts
1262
1330
  import { readFile as readFile4 } from "fs/promises";
@@ -2148,13 +2216,13 @@ async function previewOnboard(projectPath2) {
2148
2216
 
2149
2217
  // src/onboard/writer.ts
2150
2218
  import { mkdir as mkdir2, rename, writeFile as writeFile2 } from "fs/promises";
2151
- import { dirname as dirname2, relative } from "path";
2219
+ import { dirname as dirname2, relative as relative2 } from "path";
2152
2220
  function toImportPending(result, projectRoot, now = /* @__PURE__ */ new Date()) {
2153
2221
  if (!result.source) {
2154
2222
  throw new Error("Cannot build ImportPending from a failed onboard result");
2155
2223
  }
2156
2224
  const [primarySource, ...additionalSources] = result.sourcePaths.map(
2157
- (p2) => relative(projectRoot, p2)
2225
+ (p2) => relative2(projectRoot, p2)
2158
2226
  );
2159
2227
  const tokens = result.tokens.map((token) => {
2160
2228
  if (typeof token.value !== "string") {
@@ -2220,7 +2288,7 @@ async function importCommand(options) {
2220
2288
  if (!options.force) {
2221
2289
  log({
2222
2290
  event: "import:pending_exists",
2223
- path: relative2(cwd, paths.importPending),
2291
+ path: relative3(cwd, paths.importPending),
2224
2292
  message: "An import-pending.json already exists. Use --force to overwrite (previous file will be backed up)."
2225
2293
  });
2226
2294
  process.exitCode = 1;
@@ -2230,7 +2298,7 @@ async function importCommand(options) {
2230
2298
  await rename2(paths.importPending, backupPath);
2231
2299
  log({
2232
2300
  event: "import:pending_backed_up",
2233
- backup: relative2(cwd, backupPath)
2301
+ backup: relative3(cwd, backupPath)
2234
2302
  });
2235
2303
  }
2236
2304
  log({ event: "import:scanning" });
@@ -2258,7 +2326,7 @@ async function importCommand(options) {
2258
2326
  await writeImportPending(paths.importPending, doc);
2259
2327
  log({
2260
2328
  event: "import:complete",
2261
- path: relative2(cwd, paths.importPending),
2329
+ path: relative3(cwd, paths.importPending),
2262
2330
  source: result.source,
2263
2331
  confidence: result.confidence,
2264
2332
  tokensCreated: result.stats.tokensCreated,
@@ -2271,7 +2339,7 @@ async function importCommand(options) {
2271
2339
  import { existsSync as existsSync4 } from "fs";
2272
2340
  import { copyFile, mkdir as mkdir4, readFile as readFile8, rm, writeFile as writeFile4 } from "fs/promises";
2273
2341
  import { createRequire } from "module";
2274
- import { join as join10, relative as relative3 } from "path";
2342
+ import { join as join10, relative as relative4 } from "path";
2275
2343
  import { checkbox, confirm, select } from "@inquirer/prompts";
2276
2344
 
2277
2345
  // ../design-tokens/src/dependencies.ts
@@ -7100,8 +7168,8 @@ var require_util = __commonJS({
7100
7168
  }
7101
7169
  function fn() {
7102
7170
  var promiseResolve, promiseReject;
7103
- var promise = new Promise(function(resolve8, reject) {
7104
- promiseResolve = resolve8;
7171
+ var promise = new Promise(function(resolve9, reject) {
7172
+ promiseResolve = resolve9;
7105
7173
  promiseReject = reject;
7106
7174
  });
7107
7175
  var args = [];
@@ -10247,7 +10315,7 @@ var require_path = __commonJS({
10247
10315
  } else if (!path2) {
10248
10316
  continue;
10249
10317
  }
10250
- var result = win32StatPath(path2), device = result.device, isUnc = result.isUnc, isAbsolute = result.isAbsolute, tail = result.tail;
10318
+ var result = win32StatPath(path2), device = result.device, isUnc = result.isUnc, isAbsolute2 = result.isAbsolute, tail = result.tail;
10251
10319
  if (device && resolvedDevice && device.toLowerCase() !== resolvedDevice.toLowerCase()) {
10252
10320
  continue;
10253
10321
  }
@@ -10256,7 +10324,7 @@ var require_path = __commonJS({
10256
10324
  }
10257
10325
  if (!resolvedAbsolute) {
10258
10326
  resolvedTail = tail + "\\" + resolvedTail;
10259
- resolvedAbsolute = isAbsolute;
10327
+ resolvedAbsolute = isAbsolute2;
10260
10328
  }
10261
10329
  if (resolvedDevice && resolvedAbsolute) {
10262
10330
  break;
@@ -10272,9 +10340,9 @@ var require_path = __commonJS({
10272
10340
  return resolvedDevice + (resolvedAbsolute ? "\\" : "") + resolvedTail || ".";
10273
10341
  };
10274
10342
  win323.normalize = function(path2) {
10275
- var result = win32StatPath(path2), device = result.device, isUnc = result.isUnc, isAbsolute = result.isAbsolute, tail = result.tail, trailingSlash = /[\\\/]$/.test(tail);
10276
- tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute).join("\\");
10277
- if (!tail && !isAbsolute) {
10343
+ var result = win32StatPath(path2), device = result.device, isUnc = result.isUnc, isAbsolute2 = result.isAbsolute, tail = result.tail, trailingSlash = /[\\\/]$/.test(tail);
10344
+ tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute2).join("\\");
10345
+ if (!tail && !isAbsolute2) {
10278
10346
  tail = ".";
10279
10347
  }
10280
10348
  if (tail && trailingSlash) {
@@ -10283,7 +10351,7 @@ var require_path = __commonJS({
10283
10351
  if (isUnc) {
10284
10352
  device = normalizeUNCRoot(device);
10285
10353
  }
10286
- return device + (isAbsolute ? "\\" : "") + tail;
10354
+ return device + (isAbsolute2 ? "\\" : "") + tail;
10287
10355
  };
10288
10356
  win323.isAbsolute = function(path2) {
10289
10357
  return win32StatPath(path2).isAbsolute;
@@ -10431,15 +10499,15 @@ var require_path = __commonJS({
10431
10499
  return (resolvedAbsolute ? "/" : "") + resolvedPath || ".";
10432
10500
  };
10433
10501
  posix3.normalize = function(path2) {
10434
- var isAbsolute = posix3.isAbsolute(path2), trailingSlash = path2 && path2[path2.length - 1] === "/";
10435
- path2 = normalizeArray(path2.split("/"), !isAbsolute).join("/");
10436
- if (!path2 && !isAbsolute) {
10502
+ var isAbsolute2 = posix3.isAbsolute(path2), trailingSlash = path2 && path2[path2.length - 1] === "/";
10503
+ path2 = normalizeArray(path2.split("/"), !isAbsolute2).join("/");
10504
+ if (!path2 && !isAbsolute2) {
10437
10505
  path2 = ".";
10438
10506
  }
10439
10507
  if (path2 && trailingSlash) {
10440
10508
  path2 += "/";
10441
10509
  }
10442
- return (isAbsolute ? "/" : "") + path2;
10510
+ return (isAbsolute2 ? "/" : "") + path2;
10443
10511
  };
10444
10512
  posix3.isAbsolute = function(path2) {
10445
10513
  return path2.charAt(0) === "/";
@@ -11065,7 +11133,7 @@ var require_events = __commonJS({
11065
11133
  return ret;
11066
11134
  }
11067
11135
  function once(emitter, name2) {
11068
- return new Promise(function(resolve8, reject) {
11136
+ return new Promise(function(resolve9, reject) {
11069
11137
  function errorListener(err) {
11070
11138
  emitter.removeListener(name2, resolver);
11071
11139
  reject(err);
@@ -11074,7 +11142,7 @@ var require_events = __commonJS({
11074
11142
  if (typeof emitter.removeListener === "function") {
11075
11143
  emitter.removeListener("error", errorListener);
11076
11144
  }
11077
- resolve8([].slice.call(arguments));
11145
+ resolve9([].slice.call(arguments));
11078
11146
  }
11079
11147
  ;
11080
11148
  eventTargetAgnosticAddListener(emitter, name2, resolver, { once: true });
@@ -11784,11 +11852,11 @@ var require_util3 = __commonJS({
11784
11852
  var queueMicrotask_1 = require_queueMicrotask();
11785
11853
  exports.isWin = process2.platform === "win32";
11786
11854
  function promisify(fs22, fn, getResult = (input) => input) {
11787
- return (...args) => new Promise((resolve8, reject) => {
11855
+ return (...args) => new Promise((resolve9, reject) => {
11788
11856
  fs22[fn].bind(fs22)(...args, (error3, result) => {
11789
11857
  if (error3)
11790
11858
  return reject(error3);
11791
- return resolve8(getResult(result));
11859
+ return resolve9(getResult(result));
11792
11860
  });
11793
11861
  });
11794
11862
  }
@@ -11944,9 +12012,9 @@ var require_util3 = __commonJS({
11944
12012
  }
11945
12013
  function streamToBuffer(stream2) {
11946
12014
  const chunks = [];
11947
- return new Promise((resolve8, reject) => {
12015
+ return new Promise((resolve9, reject) => {
11948
12016
  stream2.on("data", (chunk) => chunks.push(chunk));
11949
- stream2.on("end", () => resolve8(buffer_1.Buffer.concat(chunks)));
12017
+ stream2.on("end", () => resolve9(buffer_1.Buffer.concat(chunks)));
11950
12018
  stream2.on("error", reject);
11951
12019
  });
11952
12020
  }
@@ -12327,11 +12395,11 @@ function __metadata(metadataKey, metadataValue) {
12327
12395
  }
12328
12396
  function __awaiter(thisArg, _arguments, P, generator) {
12329
12397
  function adopt(value2) {
12330
- return value2 instanceof P ? value2 : new P(function(resolve8) {
12331
- resolve8(value2);
12398
+ return value2 instanceof P ? value2 : new P(function(resolve9) {
12399
+ resolve9(value2);
12332
12400
  });
12333
12401
  }
12334
- return new (P || (P = Promise))(function(resolve8, reject) {
12402
+ return new (P || (P = Promise))(function(resolve9, reject) {
12335
12403
  function fulfilled(value2) {
12336
12404
  try {
12337
12405
  step(generator.next(value2));
@@ -12347,7 +12415,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
12347
12415
  }
12348
12416
  }
12349
12417
  function step(result) {
12350
- result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
12418
+ result.done ? resolve9(result.value) : adopt(result.value).then(fulfilled, rejected);
12351
12419
  }
12352
12420
  step((generator = generator.apply(thisArg, _arguments || [])).next());
12353
12421
  });
@@ -12530,14 +12598,14 @@ function __asyncValues(o) {
12530
12598
  }, i);
12531
12599
  function verb(n2) {
12532
12600
  i[n2] = o[n2] && function(v) {
12533
- return new Promise(function(resolve8, reject) {
12534
- v = o[n2](v), settle(resolve8, reject, v.done, v.value);
12601
+ return new Promise(function(resolve9, reject) {
12602
+ v = o[n2](v), settle(resolve9, reject, v.done, v.value);
12535
12603
  });
12536
12604
  };
12537
12605
  }
12538
- function settle(resolve8, reject, d2, v) {
12606
+ function settle(resolve9, reject, d2, v) {
12539
12607
  Promise.resolve(v).then(function(v2) {
12540
- resolve8({ value: v2, done: d2 });
12608
+ resolve9({ value: v2, done: d2 });
12541
12609
  }, reject);
12542
12610
  }
12543
12611
  }
@@ -12955,12 +13023,12 @@ var require_Dir = __commonJS({
12955
13023
  return typeof x === "function";
12956
13024
  }
12957
13025
  promisify(obj, fn) {
12958
- return (...args) => new Promise((resolve8, reject) => {
13026
+ return (...args) => new Promise((resolve9, reject) => {
12959
13027
  if (this.isFunction(obj[fn])) {
12960
13028
  obj[fn].bind(obj)(...args, (error3, result) => {
12961
13029
  if (error3)
12962
13030
  reject(error3);
12963
- resolve8(result);
13031
+ resolve9(result);
12964
13032
  });
12965
13033
  } else {
12966
13034
  reject("Not a function");
@@ -13084,7 +13152,7 @@ var require_volume = __commonJS({
13084
13152
  var Dir_1 = require_Dir();
13085
13153
  var resolveCrossPlatform = pathModule.resolve;
13086
13154
  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;
13087
- var { sep: sep2, relative: relative4, join: join16, dirname: dirname6 } = pathModule.posix ? pathModule.posix : pathModule;
13155
+ var { sep: sep2, relative: relative5, join: join16, dirname: dirname6 } = pathModule.posix ? pathModule.posix : pathModule;
13088
13156
  var kMinPoolSpace = 128;
13089
13157
  var EPERM = "EPERM";
13090
13158
  var ENOENT2 = "ENOENT";
@@ -13099,13 +13167,13 @@ var require_volume = __commonJS({
13099
13167
  var ENOSYS = "ENOSYS";
13100
13168
  var ERR_FS_EISDIR = "ERR_FS_EISDIR";
13101
13169
  var ERR_OUT_OF_RANGE = "ERR_OUT_OF_RANGE";
13102
- var resolve8 = (filename, base = process_1.default.cwd()) => resolveCrossPlatform(base, filename);
13170
+ var resolve9 = (filename, base = process_1.default.cwd()) => resolveCrossPlatform(base, filename);
13103
13171
  if (util_1.isWin) {
13104
- const _resolve = resolve8;
13105
- resolve8 = (filename, base) => (0, util_1.unixify)(_resolve(filename, base));
13172
+ const _resolve = resolve9;
13173
+ resolve9 = (filename, base) => (0, util_1.unixify)(_resolve(filename, base));
13106
13174
  }
13107
13175
  function filenameToSteps(filename, base) {
13108
- const fullPath = resolve8(filename, base);
13176
+ const fullPath = resolve9(filename, base);
13109
13177
  const fullPathSansSlash = fullPath.substring(1);
13110
13178
  if (!fullPathSansSlash)
13111
13179
  return [];
@@ -13427,7 +13495,7 @@ var require_volume = __commonJS({
13427
13495
  if (node.isFile()) {
13428
13496
  let filename = child.getPath();
13429
13497
  if (path2)
13430
- filename = relative4(path2, filename);
13498
+ filename = relative5(path2, filename);
13431
13499
  json2[filename] = asBuffer ? node.getBuffer() : node.getString();
13432
13500
  } else if (node.isDirectory()) {
13433
13501
  this._toJSON(child, json2, path2, asBuffer);
@@ -13435,7 +13503,7 @@ var require_volume = __commonJS({
13435
13503
  }
13436
13504
  let dirPath = link.getPath();
13437
13505
  if (path2)
13438
- dirPath = relative4(path2, dirPath);
13506
+ dirPath = relative5(path2, dirPath);
13439
13507
  if (dirPath && isEmpty) {
13440
13508
  json2[dirPath] = null;
13441
13509
  }
@@ -13466,7 +13534,7 @@ var require_volume = __commonJS({
13466
13534
  fromJSON(json2, cwd = process_1.default.cwd()) {
13467
13535
  for (let filename in json2) {
13468
13536
  const data = json2[filename];
13469
- filename = resolve8(filename, cwd);
13537
+ filename = resolve9(filename, cwd);
13470
13538
  if (typeof data === "string" || data instanceof buffer_1.Buffer) {
13471
13539
  const dir = dirname6(filename);
13472
13540
  this.mkdirpBase(
@@ -14913,7 +14981,7 @@ var require_volume = __commonJS({
14913
14981
  const filepath = link.getPath();
14914
14982
  const node = link.getNode();
14915
14983
  const onNodeChange = () => {
14916
- let filename = relative4(this._filename, filepath);
14984
+ let filename = relative5(this._filename, filepath);
14917
14985
  if (!filename) {
14918
14986
  filename = this._getName();
14919
14987
  }
@@ -14928,7 +14996,7 @@ var require_volume = __commonJS({
14928
14996
  var _a;
14929
14997
  const node = link.getNode();
14930
14998
  const onLinkChildAdd = (l) => {
14931
- this.emit("change", "rename", relative4(this._filename, l.getPath()));
14999
+ this.emit("change", "rename", relative5(this._filename, l.getPath()));
14932
15000
  setTimeout(() => {
14933
15001
  watchLinkNodeChanged(l);
14934
15002
  watchLinkChildrenChanged(l);
@@ -14949,7 +15017,7 @@ var require_volume = __commonJS({
14949
15017
  }
14950
15018
  };
14951
15019
  removeLinkNodeListeners(l);
14952
- this.emit("change", "rename", relative4(this._filename, l.getPath()));
15020
+ this.emit("change", "rename", relative5(this._filename, l.getPath()));
14953
15021
  };
14954
15022
  for (const [name2, childLink] of link.children.entries()) {
14955
15023
  if (childLink && name2 !== "." && name2 !== "..") {
@@ -15416,15 +15484,15 @@ function winResolve(...args) {
15416
15484
  const len = path2.length;
15417
15485
  let rootEnd = 0;
15418
15486
  let device = "";
15419
- let isAbsolute = false;
15487
+ let isAbsolute2 = false;
15420
15488
  const code = path2.charCodeAt(0);
15421
15489
  if (len === 1) {
15422
15490
  if (isPathSeparator(code)) {
15423
15491
  rootEnd = 1;
15424
- isAbsolute = true;
15492
+ isAbsolute2 = true;
15425
15493
  }
15426
15494
  } else if (isPathSeparator(code)) {
15427
- isAbsolute = true;
15495
+ isAbsolute2 = true;
15428
15496
  if (isPathSeparator(path2.charCodeAt(1))) {
15429
15497
  let j = 2;
15430
15498
  let last2 = j;
@@ -15455,7 +15523,7 @@ function winResolve(...args) {
15455
15523
  device = path2.slice(0, 2);
15456
15524
  rootEnd = 2;
15457
15525
  if (len > 2 && isPathSeparator(path2.charCodeAt(2))) {
15458
- isAbsolute = true;
15526
+ isAbsolute2 = true;
15459
15527
  rootEnd = 3;
15460
15528
  }
15461
15529
  }
@@ -15471,8 +15539,8 @@ function winResolve(...args) {
15471
15539
  if (resolvedDevice.length > 0) break;
15472
15540
  } else {
15473
15541
  resolvedTail = `${path2.slice(rootEnd)}\\${resolvedTail}`;
15474
- resolvedAbsolute = isAbsolute;
15475
- if (isAbsolute && resolvedDevice.length > 0) {
15542
+ resolvedAbsolute = isAbsolute2;
15543
+ if (isAbsolute2 && resolvedDevice.length > 0) {
15476
15544
  break;
15477
15545
  }
15478
15546
  }
@@ -15486,13 +15554,13 @@ function winNormalize(path2) {
15486
15554
  if (len === 0) return ".";
15487
15555
  let rootEnd = 0;
15488
15556
  let device;
15489
- let isAbsolute = false;
15557
+ let isAbsolute2 = false;
15490
15558
  const code = path2.charCodeAt(0);
15491
15559
  if (len === 1) {
15492
15560
  return isPosixPathSeparator(code) ? "\\" : path2;
15493
15561
  }
15494
15562
  if (isPathSeparator(code)) {
15495
- isAbsolute = true;
15563
+ isAbsolute2 = true;
15496
15564
  if (isPathSeparator(path2.charCodeAt(1))) {
15497
15565
  let j = 2;
15498
15566
  let last2 = j;
@@ -15526,17 +15594,17 @@ function winNormalize(path2) {
15526
15594
  device = path2.slice(0, 2);
15527
15595
  rootEnd = 2;
15528
15596
  if (len > 2 && isPathSeparator(path2.charCodeAt(2))) {
15529
- isAbsolute = true;
15597
+ isAbsolute2 = true;
15530
15598
  rootEnd = 3;
15531
15599
  }
15532
15600
  }
15533
- let tail = rootEnd < len ? normalizeString(path2.slice(rootEnd), !isAbsolute, "\\", isPathSeparator) : "";
15534
- if (tail.length === 0 && !isAbsolute) tail = ".";
15601
+ let tail = rootEnd < len ? normalizeString(path2.slice(rootEnd), !isAbsolute2, "\\", isPathSeparator) : "";
15602
+ if (tail.length === 0 && !isAbsolute2) tail = ".";
15535
15603
  if (tail.length > 0 && isPathSeparator(path2.charCodeAt(len - 1))) tail += "\\";
15536
15604
  if (device === void 0) {
15537
- return isAbsolute ? `\\${tail}` : tail;
15605
+ return isAbsolute2 ? `\\${tail}` : tail;
15538
15606
  }
15539
- return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`;
15607
+ return isAbsolute2 ? `${device}\\${tail}` : `${device}${tail}`;
15540
15608
  }
15541
15609
  function winIsAbsolute(path2) {
15542
15610
  validateString(path2, "path");
@@ -15948,15 +16016,15 @@ function posResolve(...args) {
15948
16016
  function posNormalize(path2) {
15949
16017
  validateString(path2, "path");
15950
16018
  if (path2.length === 0) return ".";
15951
- const isAbsolute = path2.charCodeAt(0) === CHAR_FORWARD_SLASH;
16019
+ const isAbsolute2 = path2.charCodeAt(0) === CHAR_FORWARD_SLASH;
15952
16020
  const trailingSeparator = path2.charCodeAt(path2.length - 1) === CHAR_FORWARD_SLASH;
15953
- path2 = normalizeString(path2, !isAbsolute, "/", isPosixPathSeparator);
16021
+ path2 = normalizeString(path2, !isAbsolute2, "/", isPosixPathSeparator);
15954
16022
  if (path2.length === 0) {
15955
- if (isAbsolute) return "/";
16023
+ if (isAbsolute2) return "/";
15956
16024
  return trailingSeparator ? "./" : ".";
15957
16025
  }
15958
16026
  if (trailingSeparator) path2 += "/";
15959
- return isAbsolute ? `/${path2}` : path2;
16027
+ return isAbsolute2 ? `/${path2}` : path2;
15960
16028
  }
15961
16029
  function posIsAbsolute(path2) {
15962
16030
  validateString(path2, "path");
@@ -16134,9 +16202,9 @@ function posParse(path2) {
16134
16202
  validateString(path2, "path");
16135
16203
  const ret = { root: "", dir: "", base: "", ext: "", name: "" };
16136
16204
  if (path2.length === 0) return ret;
16137
- const isAbsolute = path2.charCodeAt(0) === CHAR_FORWARD_SLASH;
16205
+ const isAbsolute2 = path2.charCodeAt(0) === CHAR_FORWARD_SLASH;
16138
16206
  let start;
16139
- if (isAbsolute) {
16207
+ if (isAbsolute2) {
16140
16208
  ret.root = "/";
16141
16209
  start = 1;
16142
16210
  } else {
@@ -16169,7 +16237,7 @@ function posParse(path2) {
16169
16237
  }
16170
16238
  }
16171
16239
  if (end !== -1) {
16172
- const start2 = startPart === 0 && isAbsolute ? 1 : startPart;
16240
+ const start2 = startPart === 0 && isAbsolute2 ? 1 : startPart;
16173
16241
  if (startDot === -1 || // We saw a non-dot character immediately before the dot
16174
16242
  preDotState === 0 || // The (right-most) trimmed path component is exactly '..'
16175
16243
  preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
@@ -16181,7 +16249,7 @@ function posParse(path2) {
16181
16249
  }
16182
16250
  }
16183
16251
  if (startPart > 0) ret.dir = path2.slice(0, startPart - 1);
16184
- else if (isAbsolute) ret.dir = "/";
16252
+ else if (isAbsolute2) ret.dir = "/";
16185
16253
  return ret;
16186
16254
  }
16187
16255
  var posSep = "/";
@@ -16230,7 +16298,7 @@ var posix = {
16230
16298
  };
16231
16299
 
16232
16300
  // ../../node_modules/.pnpm/path-unified@0.2.0/node_modules/path-unified/src/posix.js
16233
- var resolve = posResolve;
16301
+ var resolve2 = posResolve;
16234
16302
  var join8 = posJoin;
16235
16303
 
16236
16304
  // ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
@@ -19947,10 +20015,10 @@ var Minipass = class extends EventEmitter {
19947
20015
  * Return a void Promise that resolves once the stream ends.
19948
20016
  */
19949
20017
  async promise() {
19950
- return new Promise((resolve8, reject) => {
20018
+ return new Promise((resolve9, reject) => {
19951
20019
  this.on(DESTROYED, () => reject(new Error("stream destroyed")));
19952
20020
  this.on("error", (er) => reject(er));
19953
- this.on("end", () => resolve8());
20021
+ this.on("end", () => resolve9());
19954
20022
  });
19955
20023
  }
19956
20024
  /**
@@ -19974,7 +20042,7 @@ var Minipass = class extends EventEmitter {
19974
20042
  return Promise.resolve({ done: false, value: res });
19975
20043
  if (this[EOF])
19976
20044
  return stop();
19977
- let resolve8;
20045
+ let resolve9;
19978
20046
  let reject;
19979
20047
  const onerr = (er) => {
19980
20048
  this.off("data", ondata);
@@ -19988,19 +20056,19 @@ var Minipass = class extends EventEmitter {
19988
20056
  this.off("end", onend);
19989
20057
  this.off(DESTROYED, ondestroy);
19990
20058
  this.pause();
19991
- resolve8({ value: value2, done: !!this[EOF] });
20059
+ resolve9({ value: value2, done: !!this[EOF] });
19992
20060
  };
19993
20061
  const onend = () => {
19994
20062
  this.off("error", onerr);
19995
20063
  this.off("data", ondata);
19996
20064
  this.off(DESTROYED, ondestroy);
19997
20065
  stop();
19998
- resolve8({ done: true, value: void 0 });
20066
+ resolve9({ done: true, value: void 0 });
19999
20067
  };
20000
20068
  const ondestroy = () => onerr(new Error("stream destroyed"));
20001
20069
  return new Promise((res2, rej) => {
20002
20070
  reject = rej;
20003
- resolve8 = res2;
20071
+ resolve9 = res2;
20004
20072
  this.once(DESTROYED, ondestroy);
20005
20073
  this.once("error", onerr);
20006
20074
  this.once("end", onend);
@@ -20097,13 +20165,13 @@ var Minipass = class extends EventEmitter {
20097
20165
  };
20098
20166
 
20099
20167
  // ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
20100
- var realpathSync = rps.native;
20168
+ var realpathSync2 = rps.native;
20101
20169
  var defaultFS = {
20102
20170
  lstatSync,
20103
20171
  readdir: readdirCB,
20104
20172
  readdirSync,
20105
20173
  readlinkSync,
20106
- realpathSync,
20174
+ realpathSync: realpathSync2,
20107
20175
  promises: {
20108
20176
  lstat,
20109
20177
  readdir,
@@ -20972,9 +21040,9 @@ var PathBase = class {
20972
21040
  if (this.#asyncReaddirInFlight) {
20973
21041
  await this.#asyncReaddirInFlight;
20974
21042
  } else {
20975
- let resolve8 = () => {
21043
+ let resolve9 = () => {
20976
21044
  };
20977
- this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
21045
+ this.#asyncReaddirInFlight = new Promise((res) => resolve9 = res);
20978
21046
  try {
20979
21047
  for (const e of await this.#fs.promises.readdir(fullpath, {
20980
21048
  withFileTypes: true
@@ -20987,7 +21055,7 @@ var PathBase = class {
20987
21055
  children.provisional = 0;
20988
21056
  }
20989
21057
  this.#asyncReaddirInFlight = void 0;
20990
- resolve8();
21058
+ resolve9();
20991
21059
  }
20992
21060
  return children.slice(0, children.provisional);
20993
21061
  }
@@ -22049,10 +22117,10 @@ var Ignore = class {
22049
22117
  ignored(p2) {
22050
22118
  const fullpath = p2.fullpath();
22051
22119
  const fullpaths = `${fullpath}/`;
22052
- const relative4 = p2.relative() || ".";
22053
- const relatives = `${relative4}/`;
22120
+ const relative5 = p2.relative() || ".";
22121
+ const relatives = `${relative5}/`;
22054
22122
  for (const m3 of this.relative) {
22055
- if (m3.match(relative4) || m3.match(relatives))
22123
+ if (m3.match(relative5) || m3.match(relatives))
22056
22124
  return true;
22057
22125
  }
22058
22126
  for (const m3 of this.absolute) {
@@ -22063,9 +22131,9 @@ var Ignore = class {
22063
22131
  }
22064
22132
  childrenIgnored(p2) {
22065
22133
  const fullpath = p2.fullpath() + "/";
22066
- const relative4 = (p2.relative() || ".") + "/";
22134
+ const relative5 = (p2.relative() || ".") + "/";
22067
22135
  for (const m3 of this.relativeChildren) {
22068
- if (m3.match(relative4))
22136
+ if (m3.match(relative5))
22069
22137
  return true;
22070
22138
  }
22071
22139
  for (const m3 of this.absoluteChildren) {
@@ -22885,20 +22953,20 @@ var glob = Object.assign(glob_, {
22885
22953
  glob.glob = glob;
22886
22954
 
22887
22955
  // ../../node_modules/.pnpm/path-unified@0.2.0/node_modules/path-unified/src/win32.js
22888
- var resolve2 = winResolve;
22956
+ var resolve3 = winResolve;
22889
22957
 
22890
22958
  // ../../node_modules/.pnpm/style-dictionary@5.1.1/node_modules/style-dictionary/lib/utils/isNode.js
22891
22959
  var isNode = typeof window === "undefined";
22892
22960
 
22893
22961
  // ../../node_modules/.pnpm/style-dictionary@5.1.1/node_modules/style-dictionary/lib/resolve.js
22894
- var resolve3 = (path2, customVolumeUsed = false) => {
22962
+ var resolve4 = (path2, customVolumeUsed = false) => {
22895
22963
  if (customVolumeUsed) {
22896
22964
  return path2;
22897
22965
  }
22898
22966
  if (isNode && process?.platform === "win32") {
22899
- return resolve2(path2);
22967
+ return resolve3(path2);
22900
22968
  }
22901
- return resolve(path2);
22969
+ return resolve2(path2);
22902
22970
  };
22903
22971
 
22904
22972
  // ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
@@ -24242,7 +24310,7 @@ function toBase64(buffer) {
24242
24310
  if (isNode) {
24243
24311
  return buffer.toString("base64");
24244
24312
  } else {
24245
- return new Promise((resolve8, reject) => {
24313
+ return new Promise((resolve9, reject) => {
24246
24314
  const blob = new Blob([buffer], { type: "application/octet-stream" });
24247
24315
  const reader = new FileReader();
24248
24316
  reader.onloadend = () => {
@@ -24250,7 +24318,7 @@ function toBase64(buffer) {
24250
24318
  /** @type {string } */
24251
24319
  reader.result.split(",")[1]
24252
24320
  );
24253
- resolve8(base64String);
24321
+ resolve9(base64String);
24254
24322
  };
24255
24323
  reader.onerror = reject;
24256
24324
  reader.readAsDataURL(blob);
@@ -24261,7 +24329,7 @@ async function convertToBase64(filePath, vol2 = fs2) {
24261
24329
  if (typeof filePath !== "string") throw new Error("Token filePath name must be a string");
24262
24330
  const body = (
24263
24331
  /** @type {Buffer} */
24264
- vol2.readFileSync(resolve3(filePath, vol2.__custom_fs__))
24332
+ vol2.readFileSync(resolve4(filePath, vol2.__custom_fs__))
24265
24333
  );
24266
24334
  return toBase64(body);
24267
24335
  }
@@ -27863,7 +27931,7 @@ var AESDecryptionStream = class extends TransformStream {
27863
27931
  super({
27864
27932
  start() {
27865
27933
  Object.assign(this, {
27866
- ready: new Promise((resolve8) => this.resolveReady = resolve8),
27934
+ ready: new Promise((resolve9) => this.resolveReady = resolve9),
27867
27935
  password: encodePassword(password2, rawPassword),
27868
27936
  signed,
27869
27937
  strength: encryptionStrength - 1,
@@ -27931,7 +27999,7 @@ var AESEncryptionStream = class extends TransformStream {
27931
27999
  super({
27932
28000
  start() {
27933
28001
  Object.assign(this, {
27934
- ready: new Promise((resolve8) => this.resolveReady = resolve8),
28002
+ ready: new Promise((resolve9) => this.resolveReady = resolve9),
27935
28003
  password: encodePassword(password2, rawPassword),
27936
28004
  strength: encryptionStrength - 1,
27937
28005
  pending: new Uint8Array()
@@ -46273,31 +46341,68 @@ var CSS_LOCATIONS = {
46273
46341
  vite: ["src/index.css", "src/main.css", "src/styles.css", "src/app.css"],
46274
46342
  remix: ["app/styles/global.css", "app/globals.css", "app/root.css"],
46275
46343
  "react-router": ["app/app.css", "app/root.css", "app/styles.css", "app/globals.css"],
46344
+ wc: ["src/index.css", "src/main.css", "src/styles.css", "styles/global.css"],
46345
+ vanilla: ["src/index.css", "src/main.css", "src/styles.css", "styles/global.css"],
46276
46346
  unknown: ["src/styles/global.css", "src/index.css", "styles/globals.css"]
46277
46347
  };
46278
46348
  var COMPONENT_PATHS = {
46279
46349
  astro: {
46280
46350
  components: "src/components/ui",
46281
46351
  primitives: "src/lib/primitives",
46282
- composites: "src/composites"
46352
+ composites: "src/composites",
46353
+ rules: "src/rules"
46354
+ },
46355
+ next: {
46356
+ components: "components/ui",
46357
+ primitives: "lib/primitives",
46358
+ composites: "composites",
46359
+ rules: "rules"
46283
46360
  },
46284
- next: { components: "components/ui", primitives: "lib/primitives", composites: "composites" },
46285
46361
  vite: {
46286
46362
  components: "src/components/ui",
46287
46363
  primitives: "src/lib/primitives",
46288
- composites: "src/composites"
46364
+ composites: "src/composites",
46365
+ rules: "src/rules"
46289
46366
  },
46290
46367
  remix: {
46291
46368
  components: "app/components/ui",
46292
46369
  primitives: "app/lib/primitives",
46293
- composites: "app/composites"
46370
+ composites: "app/composites",
46371
+ rules: "app/rules"
46294
46372
  },
46295
46373
  "react-router": {
46296
46374
  components: "app/components/ui",
46297
46375
  primitives: "app/lib/primitives",
46298
- composites: "app/composites"
46376
+ composites: "app/composites",
46377
+ rules: "app/rules"
46378
+ },
46379
+ wc: {
46380
+ components: "src/components/ui",
46381
+ primitives: "src/lib/primitives",
46382
+ composites: "src/composites",
46383
+ rules: "src/rules"
46299
46384
  },
46300
- unknown: { components: "components/ui", primitives: "lib/primitives", composites: "composites" }
46385
+ vanilla: {
46386
+ components: "src/components/ui",
46387
+ primitives: "src/lib/primitives",
46388
+ composites: "src/composites",
46389
+ rules: "src/rules"
46390
+ },
46391
+ unknown: {
46392
+ components: "components/ui",
46393
+ primitives: "lib/primitives",
46394
+ composites: "composites",
46395
+ rules: "rules"
46396
+ }
46397
+ };
46398
+ var FRAMEWORK_PROMPT_LABELS = {
46399
+ next: "Next.js",
46400
+ vite: "Vite",
46401
+ remix: "Remix",
46402
+ "react-router": "React Router v7",
46403
+ astro: "Astro",
46404
+ wc: "Web Components (custom elements, shadow DOM)",
46405
+ vanilla: "Vanilla (plain HTML/TS, no framework)"
46301
46406
  };
46302
46407
  async function findMainCssFile(cwd, framework) {
46303
46408
  const locations = CSS_LOCATIONS[framework] || CSS_LOCATIONS.unknown;
@@ -46314,7 +46419,7 @@ async function updateMainCss(cwd, cssPath, themePath) {
46314
46419
  const cssContent = await readFile8(fullCssPath, "utf-8");
46315
46420
  const cssDir = join10(cwd, cssPath, "..");
46316
46421
  const themeFullPath = join10(cwd, themePath);
46317
- const relativeThemePath = relative3(cssDir, themeFullPath);
46422
+ const relativeThemePath = relative4(cssDir, themeFullPath);
46318
46423
  if (cssContent.includes(".rafters/output/rafters.css")) {
46319
46424
  log({ event: "init:css_already_imported", cssPath });
46320
46425
  return;
@@ -46340,6 +46445,26 @@ ${cssContent}`;
46340
46445
  function isInteractive() {
46341
46446
  return Boolean(process.stdin.isTTY && process.stdout.isTTY);
46342
46447
  }
46448
+ async function resolveFramework(detected, flag, agentMode) {
46449
+ if (flag) {
46450
+ if (!isSelectableFramework(flag)) {
46451
+ throw new Error(
46452
+ `Unknown --framework "${flag}". Valid values: ${SELECTABLE_FRAMEWORKS.join(", ")}.`
46453
+ );
46454
+ }
46455
+ return flag;
46456
+ }
46457
+ if (detected !== "unknown") return detected;
46458
+ if (agentMode || !isInteractive()) return "unknown";
46459
+ const picked = await select({
46460
+ message: "Couldn't auto-detect your framework. Which one is this?",
46461
+ choices: SELECTABLE_FRAMEWORKS.map((value2) => ({
46462
+ name: FRAMEWORK_PROMPT_LABELS[value2],
46463
+ value: value2
46464
+ }))
46465
+ });
46466
+ return picked;
46467
+ }
46343
46468
  async function promptExportFormats(existingConfig) {
46344
46469
  if (!isInteractive()) {
46345
46470
  return existingConfig ?? DEFAULT_EXPORTS;
@@ -46440,6 +46565,7 @@ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode2, framewor
46440
46565
  existingConfig.componentsPath = frameworkPaths.components;
46441
46566
  existingConfig.primitivesPath = frameworkPaths.primitives;
46442
46567
  existingConfig.compositesPath = frameworkPaths.composites;
46568
+ existingConfig.rulesPath = frameworkPaths.rules;
46443
46569
  }
46444
46570
  const adapter = new NodePersistenceAdapter(cwd);
46445
46571
  const allTokens = await adapter.load();
@@ -46476,10 +46602,11 @@ async function regenerateFromExisting(cwd, paths, shadcn, isAgentMode2, framewor
46476
46602
  componentsPath: frameworkPaths.components,
46477
46603
  primitivesPath: frameworkPaths.primitives,
46478
46604
  compositesPath: frameworkPaths.composites,
46605
+ rulesPath: frameworkPaths.rules,
46479
46606
  cssPath: null,
46480
46607
  shadcn: !!shadcn,
46481
46608
  exports,
46482
- installed: { components: [], primitives: [], composites: [] }
46609
+ installed: { components: [], primitives: [], composites: [], rules: [] }
46483
46610
  };
46484
46611
  await writeFile4(paths.config, JSON.stringify(newConfig, null, 2));
46485
46612
  }
@@ -46503,6 +46630,7 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode2, framework) {
46503
46630
  existingConfig.componentsPath = frameworkPaths.components;
46504
46631
  existingConfig.primitivesPath = frameworkPaths.primitives;
46505
46632
  existingConfig.compositesPath = frameworkPaths.composites;
46633
+ existingConfig.rulesPath = frameworkPaths.rules;
46506
46634
  }
46507
46635
  const adapter = new NodePersistenceAdapter(cwd);
46508
46636
  const existingTokens = await adapter.load();
@@ -46573,10 +46701,11 @@ async function resetToDefaults(cwd, paths, shadcn, isAgentMode2, framework) {
46573
46701
  componentsPath: frameworkPaths.components,
46574
46702
  primitivesPath: frameworkPaths.primitives,
46575
46703
  compositesPath: frameworkPaths.composites,
46704
+ rulesPath: frameworkPaths.rules,
46576
46705
  cssPath: null,
46577
46706
  shadcn: !!shadcn,
46578
46707
  exports,
46579
- installed: { components: [], primitives: [], composites: [] }
46708
+ installed: { components: [], primitives: [], composites: [], rules: [] }
46580
46709
  };
46581
46710
  await writeFile4(paths.config, JSON.stringify(newConfig, null, 2));
46582
46711
  }
@@ -46677,13 +46806,26 @@ async function init(options) {
46677
46806
  const cwd = process.cwd();
46678
46807
  const paths = getRaftersPaths(cwd);
46679
46808
  log({ event: "init:start", cwd });
46680
- const { framework, shadcn, tailwindVersion } = await detectProject(cwd);
46809
+ const { framework: detectedFramework, shadcn, tailwindVersion } = await detectProject(cwd);
46681
46810
  log({
46682
46811
  event: "init:detected",
46683
- framework,
46812
+ framework: detectedFramework,
46684
46813
  tailwindVersion,
46685
46814
  hasShadcn: !!shadcn
46686
46815
  });
46816
+ const framework = await resolveFramework(
46817
+ detectedFramework,
46818
+ options.framework,
46819
+ isAgentMode2
46820
+ );
46821
+ if (framework !== detectedFramework) {
46822
+ log({
46823
+ event: "init:framework_resolved",
46824
+ detected: detectedFramework,
46825
+ resolved: framework,
46826
+ source: options.framework ? "flag" : "prompt"
46827
+ });
46828
+ }
46687
46829
  if (isTailwindV3(tailwindVersion)) {
46688
46830
  throw new Error("Tailwind v3 detected. Rafters requires Tailwind v4.");
46689
46831
  }
@@ -46780,13 +46922,15 @@ async function init(options) {
46780
46922
  componentsPath: frameworkPaths.components,
46781
46923
  primitivesPath: frameworkPaths.primitives,
46782
46924
  compositesPath: frameworkPaths.composites,
46925
+ rulesPath: frameworkPaths.rules,
46783
46926
  cssPath: detectedCssPath,
46784
46927
  shadcn: !!shadcn,
46785
46928
  exports,
46786
46929
  installed: {
46787
46930
  components: [],
46788
46931
  primitives: [],
46789
- composites: []
46932
+ composites: [],
46933
+ rules: []
46790
46934
  }
46791
46935
  };
46792
46936
  await writeFile4(paths.config, JSON.stringify(config2, null, 2));
@@ -46822,7 +46966,7 @@ async function maybeOnboardExisting(cwd, importPendingPath) {
46822
46966
  event: "import:existing_detected",
46823
46967
  source: best.importer,
46824
46968
  confidence: best.confidence,
46825
- sourcePaths: best.sourcePaths.map((p2) => relative3(cwd, p2)).join(", "),
46969
+ sourcePaths: best.sourcePaths.map((p2) => relative4(cwd, p2)).join(", "),
46826
46970
  nextStep: "Run `rafters import` to convert these tokens into pending review."
46827
46971
  });
46828
46972
  return;
@@ -46831,7 +46975,7 @@ async function maybeOnboardExisting(cwd, importPendingPath) {
46831
46975
  event: "import:existing_detected",
46832
46976
  source: best.importer,
46833
46977
  confidence: best.confidence,
46834
- sourcePaths: best.sourcePaths.map((p2) => relative3(cwd, p2)).join(", ")
46978
+ sourcePaths: best.sourcePaths.map((p2) => relative4(cwd, p2)).join(", ")
46835
46979
  });
46836
46980
  let shouldImport;
46837
46981
  try {
@@ -46857,7 +47001,7 @@ async function maybeOnboardExisting(cwd, importPendingPath) {
46857
47001
  await writeImportPending(importPendingPath, doc);
46858
47002
  log({
46859
47003
  event: "import:complete",
46860
- path: relative3(cwd, importPendingPath),
47004
+ path: relative4(cwd, importPendingPath),
46861
47005
  source: result.source,
46862
47006
  confidence: result.confidence,
46863
47007
  tokensCreated: result.stats.tokensCreated,
@@ -46868,7 +47012,7 @@ async function maybeOnboardExisting(cwd, importPendingPath) {
46868
47012
 
46869
47013
  // src/commands/mcp.ts
46870
47014
  import { existsSync as existsSync7 } from "fs";
46871
- import { basename as basename4, join as join14, resolve as resolve6 } from "path";
47015
+ import { basename as basename4, join as join14, resolve as resolve7 } from "path";
46872
47016
 
46873
47017
  // src/mcp/server.ts
46874
47018
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -46876,7 +47020,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
46876
47020
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
46877
47021
 
46878
47022
  // src/mcp/tools.ts
46879
- import { readdir as readdir3 } from "fs/promises";
47023
+ import { readdir as readdir3, readFile as readFile9 } from "fs/promises";
46880
47024
  import { join as join13 } from "path";
46881
47025
 
46882
47026
  // ../composites/src/built-in-rules/email.ts
@@ -46991,13 +47135,13 @@ function search(query) {
46991
47135
 
46992
47136
  // src/utils/workspaces.ts
46993
47137
  import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync, statSync } from "fs";
46994
- import { basename as basename3, dirname as dirname5, join as join12, resolve as resolve5 } from "path";
47138
+ import { basename as basename3, dirname as dirname5, join as join12, resolve as resolve6 } from "path";
46995
47139
 
46996
47140
  // src/utils/discover.ts
46997
47141
  import { existsSync as existsSync5 } from "fs";
46998
- import { dirname as dirname4, join as join11, resolve as resolve4 } from "path";
47142
+ import { dirname as dirname4, join as join11, resolve as resolve5 } from "path";
46999
47143
  function discoverProjectRoot(startDir) {
47000
- let current = resolve4(startDir);
47144
+ let current = resolve5(startDir);
47001
47145
  for (; ; ) {
47002
47146
  const configPath = join11(current, ".rafters", "config.rafters.json");
47003
47147
  if (existsSync5(configPath)) {
@@ -47013,8 +47157,8 @@ function discoverProjectRoot(startDir) {
47013
47157
 
47014
47158
  // src/utils/workspaces.ts
47015
47159
  function findMonorepoRoot(startDir, boundary) {
47016
- let current = resolve5(startDir);
47017
- const stopAt = boundary ? resolve5(boundary) : null;
47160
+ let current = resolve6(startDir);
47161
+ const stopAt = boundary ? resolve6(boundary) : null;
47018
47162
  for (; ; ) {
47019
47163
  const pnpmWorkspace = join12(current, "pnpm-workspace.yaml");
47020
47164
  if (existsSync6(pnpmWorkspace)) {
@@ -47104,7 +47248,7 @@ function discoverWorkspaces(startDir = process.cwd(), options = {}) {
47104
47248
  if (!layout) {
47105
47249
  const single = discoverProjectRoot(startDir);
47106
47250
  if (!single) return [];
47107
- if (options.boundary && !single.startsWith(resolve5(options.boundary))) return [];
47251
+ if (options.boundary && !single.startsWith(resolve6(options.boundary))) return [];
47108
47252
  return [{ name: basename3(single), root: single }];
47109
47253
  }
47110
47254
  const seen = /* @__PURE__ */ new Set();
@@ -47127,7 +47271,7 @@ function discoverWorkspaces(startDir = process.cwd(), options = {}) {
47127
47271
  }
47128
47272
  function pickDefaultWorkspace(workspaces, startDir = process.cwd()) {
47129
47273
  if (workspaces.length === 0) return null;
47130
- const cwd = resolve5(startDir);
47274
+ const cwd = resolve6(startDir);
47131
47275
  const containing = workspaces.find((ws) => cwd === ws.root || cwd.startsWith(`${ws.root}/`));
47132
47276
  if (containing) return containing;
47133
47277
  if (workspaces.length === 1) return workspaces[0] ?? null;
@@ -47316,8 +47460,8 @@ var RaftersToolHandler = class {
47316
47460
  const files = entries.filter((f) => f.endsWith(".composite.json"));
47317
47461
  for (const file of files) {
47318
47462
  try {
47319
- const { readFile: readFile9 } = await import("fs/promises");
47320
- const raw = await readFile9(join13(dir, file), "utf-8");
47463
+ const { readFile: readFile10 } = await import("fs/promises");
47464
+ const raw = await readFile10(join13(dir, file), "utf-8");
47321
47465
  const parsed = JSON.parse(raw);
47322
47466
  const result = CompositeFileSchema.safeParse(parsed);
47323
47467
  if (result.success) {
@@ -47343,11 +47487,31 @@ var RaftersToolHandler = class {
47343
47487
  this.builtInCompositesLoaded = true;
47344
47488
  }
47345
47489
  if (workspace && !this.compositesLoadedFor.has(workspace.root)) {
47346
- const paths = getRaftersPaths(workspace.root);
47347
- await this.loadCompositesFromDir(join13(paths.root, "composites"));
47490
+ for (const dir of await this.compositeReadRoots(workspace.root)) {
47491
+ await this.loadCompositesFromDir(dir);
47492
+ }
47348
47493
  this.compositesLoadedFor.add(workspace.root);
47349
47494
  }
47350
47495
  }
47496
+ /**
47497
+ * Resolve the set of folders to scan for composite manifests in a workspace.
47498
+ * Reads `.rafters/config.rafters.json` and applies the workspace's
47499
+ * `compositesPath` (which may be a string or an array of entries to support
47500
+ * shared packages like `@shingle/shared`). Falls back to `.rafters/composites`
47501
+ * when no config or compositesPath is set.
47502
+ */
47503
+ async compositeReadRoots(workspaceRoot) {
47504
+ const paths = getRaftersPaths(workspaceRoot);
47505
+ let config2 = null;
47506
+ try {
47507
+ config2 = JSON.parse(await readFile9(paths.config, "utf-8"));
47508
+ } catch {
47509
+ }
47510
+ if (!config2?.compositesPath) {
47511
+ return [join13(paths.root, "composites")];
47512
+ }
47513
+ return resolveReadSet(config2.compositesPath, workspaceRoot);
47514
+ }
47351
47515
  async handleComposite(args) {
47352
47516
  const { id, query, category, workspace } = args;
47353
47517
  const resolved = this.resolve(workspace);
@@ -47549,7 +47713,7 @@ async function mcp(options) {
47549
47713
  let workspaces;
47550
47714
  let defaultWorkspace;
47551
47715
  if (options.projectRoot) {
47552
- const explicit = resolve6(options.projectRoot);
47716
+ const explicit = resolve7(options.projectRoot);
47553
47717
  const configPath = join14(explicit, ".rafters", "config.rafters.json");
47554
47718
  if (!existsSync7(configPath)) {
47555
47719
  process.stderr.write(
@@ -47572,7 +47736,7 @@ async function mcp(options) {
47572
47736
 
47573
47737
  // src/commands/studio.ts
47574
47738
  import { existsSync as existsSync8 } from "fs";
47575
- import { resolve as resolve7 } from "path";
47739
+ import { resolve as resolve8 } from "path";
47576
47740
 
47577
47741
  // ../studio/src/api/vite-plugin.ts
47578
47742
  import { writeFile as writeFile5 } from "fs/promises";
@@ -47719,7 +47883,7 @@ function getNamespacePatchSchema(namespace) {
47719
47883
  }
47720
47884
  var MAX_BODY_SIZE = 1024 * 1024;
47721
47885
  function readJsonBody(req) {
47722
- return new Promise((resolve8, reject) => {
47886
+ return new Promise((resolve9, reject) => {
47723
47887
  let body = "";
47724
47888
  let size = 0;
47725
47889
  req.on("data", (chunk) => {
@@ -47732,7 +47896,7 @@ function readJsonBody(req) {
47732
47896
  });
47733
47897
  req.on("end", () => {
47734
47898
  try {
47735
- resolve8(body ? JSON.parse(body) : {});
47899
+ resolve9(body ? JSON.parse(body) : {});
47736
47900
  } catch {
47737
47901
  reject(new Error("Invalid JSON body"));
47738
47902
  }
@@ -48202,7 +48366,7 @@ async function studio() {
48202
48366
  },
48203
48367
  resolve: {
48204
48368
  alias: {
48205
- "@rafters-output": resolve7(cwd, ".rafters", "output")
48369
+ "@rafters-output": resolve8(cwd, ".rafters", "output")
48206
48370
  }
48207
48371
  }
48208
48372
  });
@@ -48213,7 +48377,10 @@ async function studio() {
48213
48377
  // src/index.ts
48214
48378
  var program = new Command();
48215
48379
  program.name("rafters").description("Design system CLI - scaffold tokens and serve MCP").version("0.0.1");
48216
- 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));
48380
+ 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(
48381
+ "--framework <name>",
48382
+ "Override framework detection (next|vite|remix|react-router|astro|wc|vanilla)"
48383
+ ).option("--agent", "Output JSON for machine consumption").action(withErrorHandler(init));
48217
48384
  program.command("import").description("Import existing design tokens (Tailwind v4, shadcn, generic CSS)").option("--force", "Overwrite existing .rafters/import-pending.json").option("--importer <id>", "Force a specific importer (tailwind-v4, shadcn, generic-css)").option("--agent", "Output JSON for machine consumption").action(withErrorHandler(importCommand));
48218
48385
  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));
48219
48386
  program.command("mcp").description("Start MCP server for AI agent access (stdio)").option("--project-root <path>", "Explicit project root (skips .rafters/ discovery)").action(mcp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rafters",
3
- "version": "0.0.52",
3
+ "version": "0.0.54",
4
4
  "description": "CLI for Rafters design system - scaffold tokens and add components",
5
5
  "license": "MIT",
6
6
  "type": "module",