rafters 0.0.68 → 0.0.70

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
@@ -12635,7 +12635,7 @@ var RegistryFileSchema = external_exports.object({
12635
12635
  devDependencies: external_exports.array(external_exports.string()).default([])
12636
12636
  // e.g., ["vitest"] - from @devDependencies JSDoc
12637
12637
  });
12638
- var RegistryItemTypeSchema = external_exports.enum(["ui", "primitive", "composite"]);
12638
+ var RegistryItemTypeSchema = external_exports.enum(["ui", "primitive", "composite", "rule"]);
12639
12639
  var RegistryItemIntelligenceSchema = external_exports.object({
12640
12640
  cognitiveLoad: external_exports.number().optional(),
12641
12641
  attentionEconomics: external_exports.string().optional(),
@@ -12668,134 +12668,94 @@ var RegistryIndexSchema = external_exports.object({
12668
12668
 
12669
12669
  // src/registry/client.ts
12670
12670
  var DEFAULT_REGISTRY_URL = "https://rafters.studio";
12671
+ var REGISTRY_SOURCE = {
12672
+ ui: { folder: "components", label: "Component" },
12673
+ primitive: { folder: "primitives", label: "Primitive" },
12674
+ composite: { folder: "composites", label: "Composite" },
12675
+ rule: { folder: "rules", label: "Rule" }
12676
+ };
12677
+ var FETCH_ORDER = Object.keys(REGISTRY_SOURCE);
12671
12678
  var RegistryClient = class {
12672
12679
  baseUrl;
12673
12680
  cache = /* @__PURE__ */ new Map();
12681
+ fetchByType;
12682
+ /** Typed fetchers -- one shared body, specialized per type. */
12683
+ fetchComponent;
12684
+ fetchPrimitive;
12685
+ fetchComposite;
12686
+ fetchRule;
12674
12687
  constructor(baseUrl = DEFAULT_REGISTRY_URL) {
12675
12688
  this.baseUrl = baseUrl.replace(/\/$/, "");
12689
+ const fetchFrom = (type2) => async (name) => {
12690
+ const { folder, label } = REGISTRY_SOURCE[type2];
12691
+ const cacheKey = `${type2}:${name}`;
12692
+ const cached2 = this.cache.get(cacheKey);
12693
+ if (cached2) return cached2;
12694
+ const response = await fetch(`${this.baseUrl}/registry/${folder}/${name}.json`);
12695
+ if (response.status === 404) {
12696
+ throw new Error(`${label} "${name}" not found`);
12697
+ }
12698
+ if (!response.ok) {
12699
+ throw new Error(
12700
+ `Failed to fetch ${label.toLowerCase()} "${name}": ${response.status} ${response.statusText}`
12701
+ );
12702
+ }
12703
+ const item = RegistryItemSchema.parse(await response.json());
12704
+ this.cache.set(cacheKey, item);
12705
+ return item;
12706
+ };
12707
+ this.fetchByType = {
12708
+ ui: fetchFrom("ui"),
12709
+ primitive: fetchFrom("primitive"),
12710
+ composite: fetchFrom("composite"),
12711
+ rule: fetchFrom("rule")
12712
+ };
12713
+ this.fetchComponent = this.fetchByType.ui;
12714
+ this.fetchPrimitive = this.fetchByType.primitive;
12715
+ this.fetchComposite = this.fetchByType.composite;
12716
+ this.fetchRule = this.fetchByType.rule;
12676
12717
  }
12677
12718
  /**
12678
- * Fetch the registry index
12719
+ * Fetch the registry index.
12679
12720
  */
12680
12721
  async fetchIndex() {
12681
- const url3 = `${this.baseUrl}/registry/index.json`;
12682
- const response = await fetch(url3);
12722
+ const response = await fetch(`${this.baseUrl}/registry/index.json`);
12683
12723
  if (!response.ok) {
12684
12724
  throw new Error(`Failed to fetch registry index: ${response.status} ${response.statusText}`);
12685
12725
  }
12686
- const data = await response.json();
12687
- return RegistryIndexSchema.parse(data);
12688
- }
12689
- /**
12690
- * Fetch a component by name
12691
- */
12692
- async fetchComponent(name) {
12693
- const cacheKey = `component:${name}`;
12694
- const cached2 = this.cache.get(cacheKey);
12695
- if (cached2) {
12696
- return cached2;
12697
- }
12698
- const url3 = `${this.baseUrl}/registry/components/${name}.json`;
12699
- const response = await fetch(url3);
12700
- if (response.status === 404) {
12701
- throw new Error(`Component "${name}" not found`);
12702
- }
12703
- if (!response.ok) {
12704
- throw new Error(
12705
- `Failed to fetch component "${name}": ${response.status} ${response.statusText}`
12706
- );
12707
- }
12708
- const data = await response.json();
12709
- const item = RegistryItemSchema.parse(data);
12710
- this.cache.set(cacheKey, item);
12711
- return item;
12712
- }
12713
- /**
12714
- * Fetch a primitive by name
12715
- */
12716
- async fetchPrimitive(name) {
12717
- const cacheKey = `primitive:${name}`;
12718
- const cached2 = this.cache.get(cacheKey);
12719
- if (cached2) {
12720
- return cached2;
12721
- }
12722
- const url3 = `${this.baseUrl}/registry/primitives/${name}.json`;
12723
- const response = await fetch(url3);
12724
- if (response.status === 404) {
12725
- throw new Error(`Primitive "${name}" not found`);
12726
- }
12727
- if (!response.ok) {
12728
- throw new Error(
12729
- `Failed to fetch primitive "${name}": ${response.status} ${response.statusText}`
12730
- );
12731
- }
12732
- const data = await response.json();
12733
- const item = RegistryItemSchema.parse(data);
12734
- this.cache.set(cacheKey, item);
12735
- return item;
12736
- }
12737
- /**
12738
- * Fetch a composite by name
12739
- */
12740
- async fetchComposite(name) {
12741
- const cacheKey = `composite:${name}`;
12742
- const cached2 = this.cache.get(cacheKey);
12743
- if (cached2) {
12744
- return cached2;
12745
- }
12746
- const url3 = `${this.baseUrl}/registry/composites/${name}.json`;
12747
- const response = await fetch(url3);
12748
- if (response.status === 404) {
12749
- throw new Error(`Composite "${name}" not found`);
12750
- }
12751
- if (!response.ok) {
12752
- throw new Error(
12753
- `Failed to fetch composite "${name}": ${response.status} ${response.statusText}`
12754
- );
12755
- }
12756
- const data = await response.json();
12757
- const item = RegistryItemSchema.parse(data);
12758
- this.cache.set(cacheKey, item);
12759
- return item;
12726
+ return RegistryIndexSchema.parse(await response.json());
12760
12727
  }
12761
12728
  /**
12762
- * Fetch a registry item by name
12763
- * Tries component, then primitive, then composite
12729
+ * Fetch a registry item by name when the type is unknown.
12730
+ * Tries each source in order; a non-"not found" error (network, 5xx) aborts.
12764
12731
  */
12765
12732
  async fetchItem(name) {
12766
- try {
12767
- return await this.fetchComponent(name);
12768
- } catch (err) {
12769
- if (err instanceof Error && err.message.includes("not found")) {
12770
- try {
12771
- return await this.fetchPrimitive(name);
12772
- } catch {
12773
- try {
12774
- return await this.fetchComposite(name);
12775
- } catch {
12776
- throw err;
12777
- }
12778
- }
12733
+ for (const type2 of FETCH_ORDER) {
12734
+ try {
12735
+ return await this.fetchByType[type2](name);
12736
+ } catch (err) {
12737
+ if (err instanceof Error && err.message.includes("not found")) continue;
12738
+ throw err;
12779
12739
  }
12780
- throw err;
12781
12740
  }
12741
+ throw new Error(`"${name}" not found in registry (component, primitive, composite, or rule)`);
12782
12742
  }
12783
12743
  /**
12784
- * List all available components
12744
+ * List all available components.
12785
12745
  */
12786
12746
  async listComponents() {
12787
12747
  const index = await this.fetchIndex();
12788
12748
  return index.components.map((name) => ({ name }));
12789
12749
  }
12790
12750
  /**
12791
- * List all available composites
12751
+ * List all available composites.
12792
12752
  */
12793
12753
  async listComposites() {
12794
12754
  const index = await this.fetchIndex();
12795
12755
  return index.composites.map((name) => ({ name }));
12796
12756
  }
12797
12757
  /**
12798
- * Check if a component exists in the registry
12758
+ * Check if a component exists in the registry.
12799
12759
  */
12800
12760
  async componentExists(name) {
12801
12761
  try {
@@ -12806,7 +12766,7 @@ var RegistryClient = class {
12806
12766
  }
12807
12767
  }
12808
12768
  /**
12809
- * Check if a primitive exists in the registry
12769
+ * Check if a primitive exists in the registry.
12810
12770
  */
12811
12771
  async primitiveExists(name) {
12812
12772
  try {
@@ -12817,20 +12777,17 @@ var RegistryClient = class {
12817
12777
  }
12818
12778
  }
12819
12779
  /**
12820
- * Resolve all dependencies for a component recursively
12821
- * Returns items in installation order (dependencies first)
12780
+ * Resolve all dependencies for an item recursively.
12781
+ * Returns items in installation order (dependencies first).
12822
12782
  */
12823
12783
  async resolveDependencies(name, resolved = /* @__PURE__ */ new Set()) {
12824
- if (resolved.has(name)) {
12825
- return [];
12826
- }
12784
+ if (resolved.has(name)) return [];
12827
12785
  const item = await this.fetchItem(name);
12828
12786
  resolved.add(name);
12829
12787
  const deps = [];
12830
12788
  for (const dep of item.primitives) {
12831
12789
  if (!resolved.has(dep)) {
12832
- const depItems = await this.resolveDependencies(dep, resolved);
12833
- deps.push(...depItems);
12790
+ deps.push(...await this.resolveDependencies(dep, resolved));
12834
12791
  }
12835
12792
  }
12836
12793
  deps.push(item);
@@ -12954,7 +12911,7 @@ var FRAMEWORK_SPECS = {
12954
12911
  components: "components/ui",
12955
12912
  primitives: "lib/primitives",
12956
12913
  composites: "composites",
12957
- rules: "rules"
12914
+ rules: "lib/rules"
12958
12915
  }
12959
12916
  },
12960
12917
  vite: {
@@ -12964,7 +12921,7 @@ var FRAMEWORK_SPECS = {
12964
12921
  components: "src/components/ui",
12965
12922
  primitives: "src/lib/primitives",
12966
12923
  composites: "src/composites",
12967
- rules: "src/rules"
12924
+ rules: "src/lib/rules"
12968
12925
  }
12969
12926
  },
12970
12927
  remix: {
@@ -12974,7 +12931,7 @@ var FRAMEWORK_SPECS = {
12974
12931
  components: "app/components/ui",
12975
12932
  primitives: "app/lib/primitives",
12976
12933
  composites: "app/composites",
12977
- rules: "app/rules"
12934
+ rules: "app/lib/rules"
12978
12935
  }
12979
12936
  },
12980
12937
  "react-router": {
@@ -12984,7 +12941,7 @@ var FRAMEWORK_SPECS = {
12984
12941
  components: "app/components/ui",
12985
12942
  primitives: "app/lib/primitives",
12986
12943
  composites: "app/composites",
12987
- rules: "app/rules"
12944
+ rules: "app/lib/rules"
12988
12945
  }
12989
12946
  },
12990
12947
  astro: {
@@ -12994,7 +12951,7 @@ var FRAMEWORK_SPECS = {
12994
12951
  components: "src/components/ui",
12995
12952
  primitives: "src/lib/primitives",
12996
12953
  composites: "src/composites",
12997
- rules: "src/rules"
12954
+ rules: "src/lib/rules"
12998
12955
  }
12999
12956
  },
13000
12957
  wc: {
@@ -13004,7 +12961,7 @@ var FRAMEWORK_SPECS = {
13004
12961
  components: "src/components/ui",
13005
12962
  primitives: "src/lib/primitives",
13006
12963
  composites: "src/composites",
13007
- rules: "src/rules"
12964
+ rules: "src/lib/rules"
13008
12965
  }
13009
12966
  },
13010
12967
  vanilla: {
@@ -13014,7 +12971,7 @@ var FRAMEWORK_SPECS = {
13014
12971
  components: "src/components/ui",
13015
12972
  primitives: "src/lib/primitives",
13016
12973
  composites: "src/composites",
13017
- rules: "src/rules"
12974
+ rules: "src/lib/rules"
13018
12975
  }
13019
12976
  },
13020
12977
  unknown: {
@@ -13023,7 +12980,7 @@ var FRAMEWORK_SPECS = {
13023
12980
  components: "components/ui",
13024
12981
  primitives: "lib/primitives",
13025
12982
  composites: "composites",
13026
- rules: "rules"
12983
+ rules: "lib/rules"
13027
12984
  }
13028
12985
  }
13029
12986
  };
@@ -13671,6 +13628,9 @@ async function loadConfig(cwd) {
13671
13628
  return null;
13672
13629
  }
13673
13630
  }
13631
+ function resolveRegistryUrl(options, config2) {
13632
+ return options.registryUrl ?? config2?.registryUrl;
13633
+ }
13674
13634
  async function saveConfig(cwd, config2) {
13675
13635
  const paths = getRaftersPaths(cwd);
13676
13636
  await writeFile(paths.config, JSON.stringify(config2, null, 2));
@@ -13709,16 +13669,26 @@ function selectFilesForFramework(files, target) {
13709
13669
  }
13710
13670
  return { files, fallback: false };
13711
13671
  }
13672
+ var TARGET_GATED_COMPOSITE_FILES = [
13673
+ { suffix: "Composite.astro", target: "astro" }
13674
+ ];
13675
+ function selectCompositeFiles(files, target) {
13676
+ return files.filter((file2) => {
13677
+ const gate = TARGET_GATED_COMPOSITE_FILES.find((g2) => file2.path.endsWith(g2.suffix));
13678
+ return gate ? gate.target === target : true;
13679
+ });
13680
+ }
13712
13681
  var FOLDER_NAMES = /* @__PURE__ */ new Set(["composites"]);
13713
13682
  function isAlreadyInstalled(config2, item) {
13714
13683
  if (!config2?.installed) return false;
13715
- if (item.type === "ui") {
13716
- return config2.installed.components.includes(item.name);
13717
- }
13718
- if (item.type === "composite") {
13719
- return (config2.installed.composites ?? []).includes(item.name);
13720
- }
13721
- return config2.installed.primitives.includes(item.name);
13684
+ const { components, primitives, composites: composites2, rules } = config2.installed;
13685
+ const bucketByType = {
13686
+ ui: components,
13687
+ primitive: primitives,
13688
+ composite: composites2 ?? [],
13689
+ rule: rules ?? []
13690
+ };
13691
+ return bucketByType[item.type].includes(item.name);
13722
13692
  }
13723
13693
  function isInstalledOnDisk(config2, item, cwd) {
13724
13694
  if (!isAlreadyInstalled(config2, item)) return false;
@@ -13735,8 +13705,14 @@ function trackInstalled(config2, items) {
13735
13705
  const installed = config2.installed;
13736
13706
  if (!installed.composites) installed.composites = [];
13737
13707
  if (!installed.rules) installed.rules = [];
13708
+ const bucketByType = {
13709
+ ui: installed.components,
13710
+ primitive: installed.primitives,
13711
+ composite: installed.composites,
13712
+ rule: installed.rules
13713
+ };
13738
13714
  for (const item of items) {
13739
- const bucket = item.type === "ui" ? installed.components : item.type === "composite" ? installed.composites : installed.primitives;
13715
+ const bucket = bucketByType[item.type];
13740
13716
  if (!bucket.includes(item.name)) bucket.push(item.name);
13741
13717
  }
13742
13718
  installed.components.sort();
@@ -13753,7 +13729,7 @@ function transformPath(registryPath, config2, cwd) {
13753
13729
  ["components/ui/", config2.componentsPath, "components/ui"],
13754
13730
  ["lib/primitives/", config2.primitivesPath, "lib/primitives"],
13755
13731
  ["composites/", config2.compositesPath, "composites"],
13756
- ["rules/", config2.rulesPath, "rules"]
13732
+ ["rules/", config2.rulesPath, "lib/rules"]
13757
13733
  ];
13758
13734
  for (const [prefix, field, fallback] of replacements) {
13759
13735
  if (registryPath.startsWith(prefix)) {
@@ -13815,6 +13791,8 @@ async function installItem(cwd, item, options, config2) {
13815
13791
  message: `No ${targetToExtension(target)} version available for ${item.name}. Installing React version.`
13816
13792
  });
13817
13793
  }
13794
+ } else if (item.type === "composite") {
13795
+ filesToInstall = selectCompositeFiles(item.files, getComponentTarget(config2));
13818
13796
  }
13819
13797
  for (const file2 of filesToInstall) {
13820
13798
  const projectPath2 = transformPath(file2.path, config2, cwd);
@@ -13846,7 +13824,9 @@ async function installItem(cwd, item, options, config2) {
13846
13824
  async function add(componentArgs, options) {
13847
13825
  setAgentMode(options.agent ?? false);
13848
13826
  let components = componentArgs;
13849
- const client = new RegistryClient(options.registryUrl);
13827
+ const cwd = process.cwd();
13828
+ const config2 = await loadConfig(cwd);
13829
+ const client = new RegistryClient(resolveRegistryUrl(options, config2));
13850
13830
  let folder;
13851
13831
  const firstArg = components[0];
13852
13832
  if (firstArg && FOLDER_NAMES.has(firstArg)) {
@@ -13876,14 +13856,12 @@ async function add(componentArgs, options) {
13876
13856
  }
13877
13857
  return;
13878
13858
  }
13879
- const cwd = process.cwd();
13880
13859
  const initialized = await isInitialized(cwd);
13881
13860
  if (!initialized) {
13882
13861
  error46("Project not initialized. Run `rafters init` first.");
13883
13862
  process.exitCode = 1;
13884
13863
  return;
13885
13864
  }
13886
- const config2 = await loadConfig(cwd);
13887
13865
  if (options.update) {
13888
13866
  options.overwrite = true;
13889
13867
  }
@@ -13988,6 +13966,7 @@ async function add(componentArgs, options) {
13988
13966
  }
13989
13967
  if (result.skipped && !result.installed) {
13990
13968
  skipped.push(item.name);
13969
+ installedItems.push(item);
13991
13970
  }
13992
13971
  } catch (err) {
13993
13972
  if (err instanceof Error) {
@@ -14034,7 +14013,7 @@ async function add(componentArgs, options) {
14034
14013
  componentsPath: "components/ui",
14035
14014
  primitivesPath: "lib/primitives",
14036
14015
  compositesPath: "composites",
14037
- rulesPath: "rules",
14016
+ rulesPath: "lib/rules",
14038
14017
  cssPath: null,
14039
14018
  shadcn: false,
14040
14019
  exports: DEFAULT_EXPORTS,
@@ -21167,12 +21146,23 @@ var SemanticSelectionError = class extends Error {
21167
21146
  this.name = "SemanticSelectionError";
21168
21147
  }
21169
21148
  };
21170
- var STATE_USES = ["hover", "active", "focus", "disabled"];
21149
+ var STATE_USES = [
21150
+ "hover",
21151
+ "active",
21152
+ "focus",
21153
+ "disabled",
21154
+ "border",
21155
+ "ring",
21156
+ "subtle"
21157
+ ];
21171
21158
  var STATE_RANK_STEP = {
21172
21159
  hover: (rank, _l, s) => rank + s,
21173
21160
  active: (rank, _l, s) => rank + 2 * s,
21174
21161
  focus: (rank, _l, s) => rank + s,
21175
- disabled: (_rank, ladder) => closestRankTo(ladder, 5)
21162
+ disabled: (_rank, ladder) => closestRankTo(ladder, 5),
21163
+ border: (rank, _l, s) => rank + 2 * s,
21164
+ ring: (rank) => rank,
21165
+ subtle: (rank, _l, s) => rank - 2 * s
21176
21166
  };
21177
21167
  function partnerForBase(pairs, base) {
21178
21168
  if (!pairs) return void 0;
@@ -22863,142 +22853,12 @@ function registryToTailwind(registry2, options) {
22863
22853
  const tokens = [...registry2.list()];
22864
22854
  return tokensToTailwind(tokens, options, []);
22865
22855
  }
22866
- function generateVarsRootBlock(groups) {
22867
- const lines = [];
22868
- lines.push(":root {");
22869
- if (groups.color.length > 0) {
22870
- for (const token of groups.color) {
22871
- const value = tokenValueToCSS(token);
22872
- if (value === null) continue;
22873
- lines.push(` --rafters-color-${token.name}: ${value};`);
22874
- }
22875
- lines.push("");
22876
- }
22877
- if (groups.spacing.length > 0) {
22878
- for (const token of groups.spacing) {
22879
- const value = tokenValueToCSS(token);
22880
- if (value === null) continue;
22881
- lines.push(` --rafters-${token.name}: ${value};`);
22882
- }
22883
- lines.push("");
22884
- }
22885
- if (groups.typography.length > 0) {
22886
- for (const token of groups.typography) {
22887
- const value = tokenValueToCSS(token);
22888
- if (value === null) continue;
22889
- lines.push(` --rafters-${token.name}: ${value};`);
22890
- if (token.lineHeight) {
22891
- lines.push(` --rafters-${token.name}--line-height: ${token.lineHeight};`);
22892
- }
22893
- }
22894
- lines.push("");
22895
- }
22896
- if (groups.radius.length > 0) {
22897
- for (const token of groups.radius) {
22898
- const value = tokenValueToCSS(token);
22899
- if (value === null) continue;
22900
- lines.push(` --rafters-${token.name}: ${value};`);
22901
- }
22902
- lines.push("");
22903
- }
22904
- if (groups.shadow.length > 0) {
22905
- for (const token of groups.shadow) {
22906
- const value = tokenValueToCSS(token);
22907
- if (value === null) continue;
22908
- lines.push(` --rafters-${token.name}: ${value};`);
22909
- }
22910
- lines.push("");
22911
- }
22912
- if (groups.depth.length > 0) {
22913
- for (const token of groups.depth) {
22914
- const value = tokenValueToCSS(token);
22915
- if (value === null) continue;
22916
- lines.push(` --rafters-${token.name}: ${value};`);
22917
- }
22918
- lines.push("");
22919
- }
22920
- if (groups.motion.length > 0) {
22921
- for (const token of groups.motion) {
22922
- if (token.name.startsWith("motion-duration-") && token.name !== "motion-duration-base")
22923
- continue;
22924
- if (token.name.startsWith("motion-easing-")) continue;
22925
- const value = tokenValueToCSS(token);
22926
- if (value === null) continue;
22927
- lines.push(` --rafters-${token.name}: ${value};`);
22928
- }
22929
- lines.push("");
22930
- }
22931
- if (groups.motion.length > 0) {
22932
- for (const token of groups.motion) {
22933
- if (token.name.startsWith("motion-duration-") && token.name !== "motion-duration-base") {
22934
- const value = tokenValueToCSS(token);
22935
- if (value === null) continue;
22936
- lines.push(` --rafters-${token.name}: ${value};`);
22937
- }
22938
- if (token.name.startsWith("motion-easing-")) {
22939
- const value = tokenValueToCSS(token);
22940
- if (value === null) continue;
22941
- lines.push(` --rafters-${token.name}: ${value};`);
22942
- }
22943
- }
22944
- lines.push("");
22945
- }
22946
- if (groups.breakpoint.length > 0) {
22947
- for (const token of groups.breakpoint) {
22948
- const value = tokenValueToCSS(token);
22949
- if (value === null) continue;
22950
- if (isMediaQueryToken(token)) continue;
22951
- lines.push(` --rafters-${token.name}: ${value};`);
22952
- }
22953
- lines.push("");
22954
- }
22955
- if (groups.focus.length > 0) {
22956
- for (const token of groups.focus) {
22957
- const value = tokenValueToCSS(token);
22958
- if (value === null) continue;
22959
- lines.push(` --rafters-${token.name}: ${value};`);
22960
- }
22961
- lines.push("");
22962
- }
22963
- if (groups.other.length > 0) {
22964
- for (const token of groups.other) {
22965
- const value = tokenValueToCSS(token);
22966
- if (value === null) continue;
22967
- lines.push(` --rafters-${token.name}: ${value};`);
22968
- }
22969
- lines.push("");
22970
- }
22971
- const animationTokens = groups.motion.filter((t) => t.name.startsWith("motion-animation-"));
22972
- if (animationTokens.length > 0) {
22973
- for (const token of animationTokens) {
22974
- const animName = token.animationName || token.name.replace("motion-animation-", "");
22975
- lines.push(` --rafters-animate-${animName}: ${token.value};`);
22976
- }
22977
- lines.push("");
22978
- }
22979
- lines.push("}");
22980
- return lines.join("\n");
22981
- }
22982
- function registryToVars(registry2) {
22983
- const tokens = [...registry2.list()];
22984
- if (tokens.length === 0) {
22985
- throw new Error("Registry is empty");
22986
- }
22987
- const groups = groupTokens(tokens);
22988
- const sections = [];
22989
- const varsBlock = generateVarsRootBlock(groups);
22990
- sections.push(varsBlock);
22991
- sections.push("");
22992
- const rootBlock = generateRootBlock(groups.semantic);
22993
- sections.push(rootBlock);
22994
- return sections.join("\n");
22995
- }
22996
22856
  async function registryToCompiled(registry2, options = {}) {
22997
22857
  const { minify = true, includeImport = true } = options;
22998
22858
  const themeCss = registryToTailwind(registry2, { includeImport });
22999
22859
  const { execFileSync } = await import("child_process");
23000
22860
  const { mkdtempSync, writeFileSync: writeFileSync2, readFileSync: readFileSync3, rmSync } = await import("fs");
23001
- const { join: join13, dirname: dirname4 } = await import("path");
22861
+ const { join: join14, dirname: dirname4 } = await import("path");
23002
22862
  const { createRequire: createRequire2 } = await import("module");
23003
22863
  const require2 = createRequire2(import.meta.url);
23004
22864
  let pkgDir;
@@ -23008,10 +22868,10 @@ async function registryToCompiled(registry2, options = {}) {
23008
22868
  } catch {
23009
22869
  throw new Error("Failed to resolve @tailwindcss/cli");
23010
22870
  }
23011
- const binPath = join13(pkgDir, "dist", "index.mjs");
23012
- const tempDir = mkdtempSync(join13(pkgDir, ".tmp-compile-"));
23013
- const tempInput = join13(tempDir, "input.css");
23014
- const tempOutput = join13(tempDir, "output.css");
22871
+ const binPath = join14(pkgDir, "dist", "index.mjs");
22872
+ const tempDir = mkdtempSync(join14(pkgDir, ".tmp-compile-"));
22873
+ const tempInput = join14(tempDir, "input.css");
22874
+ const tempOutput = join14(tempDir, "output.css");
23015
22875
  try {
23016
22876
  writeFileSync2(tempInput, themeCss);
23017
22877
  const args = [binPath, "-i", tempInput, "-o", tempOutput];
@@ -24363,12 +24223,12 @@ var DEFAULT_SEMANTIC_COLOR_MAPPINGS = {
24363
24223
  never: ["Use for dividers within cards"]
24364
24224
  },
24365
24225
  panel: {
24366
- light: { family: "neutral", position: "100" },
24226
+ light: { family: "neutral", position: "200" },
24367
24227
  dark: { family: "neutral", position: "800" },
24368
- meaning: "Elevated panel surface -- one level above the page",
24228
+ meaning: "Persistent elevated chrome -- headers, docks, fixed toolbars",
24369
24229
  contexts: ["panels", "toolbars", "headers", "docks"],
24370
24230
  do: ["Use for persistent elevated chrome", "Pair with panel-foreground"],
24371
- never: ["Use for page-level backgrounds", "Stack directly on card without a border"]
24231
+ never: ["Use for page-level backgrounds", "Use for transient surfaces"]
24372
24232
  },
24373
24233
  "panel-foreground": {
24374
24234
  light: { family: "neutral", position: "950" },
@@ -24421,12 +24281,12 @@ var DEFAULT_SEMANTIC_COLOR_MAPPINGS = {
24421
24281
  },
24422
24282
  // Generic surface
24423
24283
  surface: {
24424
- light: { family: "neutral", position: "50" },
24284
+ light: { family: "neutral", position: "100" },
24425
24285
  dark: { family: "neutral", position: "900" },
24426
- meaning: "Elevated surface background",
24427
- contexts: ["elevated-elements"],
24428
- do: ["Use for elevated surfaces"],
24429
- never: ["Use for page background"]
24286
+ meaning: "Base chrome surface -- toolbars, app shell, UI frame",
24287
+ contexts: ["chrome", "app-shell", "toolbars"],
24288
+ do: ["Use for application chrome"],
24289
+ never: ["Use for page background", "Use for content containers"]
24430
24290
  },
24431
24291
  "surface-foreground": {
24432
24292
  light: { family: "neutral", position: "950" },
@@ -25511,9 +25371,9 @@ var DEFAULT_SEMANTIC_COLOR_MAPPINGS = {
25511
25371
  // SIDEBAR TOKENS (shadcn compatible + extended)
25512
25372
  // ============================================================================
25513
25373
  sidebar: {
25514
- light: { family: "neutral", position: "50" },
25374
+ light: { family: "neutral", position: "100" },
25515
25375
  dark: { family: "neutral", position: "900" },
25516
- meaning: "Sidebar background",
25376
+ meaning: "Sidebar background -- almost on the surface",
25517
25377
  contexts: ["navigation-sidebar", "side-panels"],
25518
25378
  do: ["Use for sidebar backgrounds"],
25519
25379
  never: ["Use for main content areas"]
@@ -27173,7 +27033,7 @@ function generateRadiusTokens(config2, radiusDefs) {
27173
27033
 
27174
27034
  // ../design-tokens/src/generators/semantic.ts
27175
27035
  var FOREGROUND_SUFFIXES = ["-foreground", "-text", "-contrast"];
27176
- var STATE_SUFFIXES = ["-hover", "-active", "-focus", "-disabled"];
27036
+ var STATE_SUFFIXES = STATE_USES.map((s) => `-${s}`);
27177
27037
  function toColorRef(mapping) {
27178
27038
  return { family: mapping.light.family, position: mapping.light.position };
27179
27039
  }
@@ -28874,7 +28734,7 @@ var scalePlugin = definePlugin({
28874
28734
  });
28875
28735
 
28876
28736
  // ../design-tokens/src/plugins/state.ts
28877
- var StateTypeSchema = external_exports.enum(["hover", "active", "focus", "disabled"]);
28737
+ var StateTypeSchema = external_exports.enum(STATE_USES);
28878
28738
  var StateInputSchema = external_exports.object({
28879
28739
  from: external_exports.string(),
28880
28740
  stateType: StateTypeSchema
@@ -29748,7 +29608,7 @@ async function init(options) {
29748
29608
 
29749
29609
  // src/commands/mcp.ts
29750
29610
  import { existsSync as existsSync6 } from "fs";
29751
- import { basename as basename2, join as join11, resolve as resolve4 } from "path";
29611
+ import { basename as basename2, join as join12, resolve as resolve4 } from "path";
29752
29612
 
29753
29613
  // src/mcp/server.ts
29754
29614
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -29756,8 +29616,8 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
29756
29616
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
29757
29617
 
29758
29618
  // src/mcp/tools.ts
29759
- import { readdir, readFile as readFile5 } from "fs/promises";
29760
- import { join as join10 } from "path";
29619
+ import { readFile as readFile6 } from "fs/promises";
29620
+ import { join as join11 } from "path";
29761
29621
 
29762
29622
  // ../composites/src/built-in-rules/email.ts
29763
29623
  var email3 = external_exports.string().email();
@@ -29786,6 +29646,10 @@ var AppliedRuleSchema = external_exports.union([
29786
29646
  var CompositeBlockSchema = external_exports.object({
29787
29647
  id: external_exports.string().min(1),
29788
29648
  type: external_exports.string().min(1),
29649
+ /** Signatures this block consumes / produces (rule names) -- the typed I/O edges.
29650
+ * Within a composite, an output named X feeds any block input named X. */
29651
+ input: external_exports.array(external_exports.string()).optional(),
29652
+ output: external_exports.array(external_exports.string()).optional(),
29789
29653
  content: external_exports.unknown().optional(),
29790
29654
  children: external_exports.array(external_exports.string()).optional(),
29791
29655
  parentId: external_exports.string().optional(),
@@ -29815,6 +29679,60 @@ var CompositeFileSchema = external_exports.object({
29815
29679
  blocks: external_exports.array(CompositeBlockSchema).min(1)
29816
29680
  });
29817
29681
 
29682
+ // ../composites/src/discovery.ts
29683
+ function discoverComposites(entries) {
29684
+ const registry2 = /* @__PURE__ */ new Map();
29685
+ const errors = [];
29686
+ for (const entry of entries) {
29687
+ let parsed;
29688
+ try {
29689
+ parsed = JSON.parse(entry.raw);
29690
+ } catch (e) {
29691
+ errors.push({
29692
+ source: entry.source,
29693
+ error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`
29694
+ });
29695
+ continue;
29696
+ }
29697
+ const result = CompositeFileSchema.safeParse(parsed);
29698
+ if (!result.success) {
29699
+ errors.push({ source: entry.source, error: result.error.message });
29700
+ continue;
29701
+ }
29702
+ const { id } = result.data.manifest;
29703
+ if (registry2.has(id)) {
29704
+ errors.push({
29705
+ source: entry.source,
29706
+ error: `Duplicate composite id "${id}" (already registered)`
29707
+ });
29708
+ continue;
29709
+ }
29710
+ registry2.set(id, result.data);
29711
+ }
29712
+ reportUnresolvedReferences(registry2, errors);
29713
+ return { registry: registry2, errors };
29714
+ }
29715
+ var COMPOSITE_PREFIX = "composite:";
29716
+ function reportUnresolvedReferences(registry2, errors) {
29717
+ for (const [id, composite] of registry2) {
29718
+ const missing = /* @__PURE__ */ new Set();
29719
+ for (const block of composite.blocks) {
29720
+ if (block.type.startsWith(COMPOSITE_PREFIX)) {
29721
+ const refId = block.type.slice(COMPOSITE_PREFIX.length);
29722
+ if (!registry2.has(refId)) {
29723
+ missing.add(refId);
29724
+ }
29725
+ }
29726
+ }
29727
+ if (missing.size > 0) {
29728
+ errors.push({
29729
+ source: id,
29730
+ error: `Unresolved composite reference(s): ${[...missing].map((m3) => `composite:${m3}`).join(", ")}`
29731
+ });
29732
+ }
29733
+ }
29734
+ }
29735
+
29818
29736
  // ../ui/src/primitives/typeahead.ts
29819
29737
  function fuzzyScore(query, target) {
29820
29738
  if (query.length === 0) return 1;
@@ -29872,17 +29790,56 @@ function search(query) {
29872
29790
  // ../composites/src/to-mdx.ts
29873
29791
  var import_escape_html = __toESM(require_escape_html(), 1);
29874
29792
 
29793
+ // ../composites/src/discovery-node.ts
29794
+ import { readdir, readFile as readFile5 } from "fs/promises";
29795
+ import { join as join8 } from "path";
29796
+ var COMPOSITE_SUFFIX = ".composite.json";
29797
+ async function readDir(directory) {
29798
+ const entries = [];
29799
+ let dirents;
29800
+ try {
29801
+ dirents = await readdir(directory, { withFileTypes: true });
29802
+ } catch {
29803
+ return entries;
29804
+ }
29805
+ for (const dirent of dirents) {
29806
+ const fullPath = join8(directory, dirent.name);
29807
+ if (dirent.isDirectory()) {
29808
+ entries.push(...await readDir(fullPath));
29809
+ continue;
29810
+ }
29811
+ if (dirent.isFile() && dirent.name.endsWith(COMPOSITE_SUFFIX)) {
29812
+ const raw = await readFile5(fullPath, "utf-8");
29813
+ entries.push({ raw, source: fullPath });
29814
+ }
29815
+ }
29816
+ return entries;
29817
+ }
29818
+ function nodeFsAdapter(...directories) {
29819
+ return async () => {
29820
+ const entries = [];
29821
+ for (const directory of directories) {
29822
+ entries.push(...await readDir(directory));
29823
+ }
29824
+ return entries;
29825
+ };
29826
+ }
29827
+ async function discoverFromDirs(...directories) {
29828
+ const adapter = nodeFsAdapter(...directories);
29829
+ return discoverComposites(await adapter());
29830
+ }
29831
+
29875
29832
  // src/utils/workspaces.ts
29876
29833
  import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
29877
- import { basename, dirname as dirname3, join as join9, resolve as resolve3 } from "path";
29834
+ import { basename, dirname as dirname3, join as join10, resolve as resolve3 } from "path";
29878
29835
 
29879
29836
  // src/utils/discover.ts
29880
29837
  import { existsSync as existsSync4 } from "fs";
29881
- import { dirname as dirname2, join as join8, resolve as resolve2 } from "path";
29838
+ import { dirname as dirname2, join as join9, resolve as resolve2 } from "path";
29882
29839
  function discoverProjectRoot(startDir) {
29883
29840
  let current = resolve2(startDir);
29884
29841
  for (; ; ) {
29885
- const configPath = join8(current, ".rafters", "config.rafters.json");
29842
+ const configPath = join9(current, ".rafters", "config.rafters.json");
29886
29843
  if (existsSync4(configPath)) {
29887
29844
  return current;
29888
29845
  }
@@ -29899,14 +29856,14 @@ function findMonorepoRoot(startDir, boundary) {
29899
29856
  let current = resolve3(startDir);
29900
29857
  const stopAt = boundary ? resolve3(boundary) : null;
29901
29858
  for (; ; ) {
29902
- const pnpmWorkspace = join9(current, "pnpm-workspace.yaml");
29859
+ const pnpmWorkspace = join10(current, "pnpm-workspace.yaml");
29903
29860
  if (existsSync5(pnpmWorkspace)) {
29904
29861
  const patterns = parsePnpmWorkspaceYaml(readFileSync2(pnpmWorkspace, "utf-8"));
29905
29862
  if (patterns.length > 0) {
29906
29863
  return { root: current, patterns };
29907
29864
  }
29908
29865
  }
29909
- const pkgJson = join9(current, "package.json");
29866
+ const pkgJson = join10(current, "package.json");
29910
29867
  if (existsSync5(pkgJson)) {
29911
29868
  const patterns = parsePackageJsonWorkspaces(readFileSync2(pkgJson, "utf-8"));
29912
29869
  if (patterns.length > 0) {
@@ -29962,9 +29919,9 @@ function expandPattern(monorepoRoot, pattern) {
29962
29919
  const trimmed = pattern.replace(/\/+$/, "");
29963
29920
  if (trimmed.endsWith("/*")) {
29964
29921
  const parentRel = trimmed.slice(0, -2);
29965
- const parent = join9(monorepoRoot, parentRel);
29922
+ const parent = join10(monorepoRoot, parentRel);
29966
29923
  if (!existsSync5(parent)) return [];
29967
- return readdirSync2(parent).map((entry) => join9(parent, entry)).filter((path) => {
29924
+ return readdirSync2(parent).map((entry) => join10(parent, entry)).filter((path) => {
29968
29925
  try {
29969
29926
  return statSync2(path).isDirectory();
29970
29927
  } catch {
@@ -29972,7 +29929,7 @@ function expandPattern(monorepoRoot, pattern) {
29972
29929
  }
29973
29930
  });
29974
29931
  }
29975
- const literal2 = join9(monorepoRoot, trimmed);
29932
+ const literal2 = join10(monorepoRoot, trimmed);
29976
29933
  if (existsSync5(literal2)) {
29977
29934
  try {
29978
29935
  if (statSync2(literal2).isDirectory()) return [literal2];
@@ -29996,13 +29953,13 @@ function discoverWorkspaces(startDir = process.cwd(), options = {}) {
29996
29953
  for (const dir of expandPattern(layout.root, pattern)) {
29997
29954
  if (seen.has(dir)) continue;
29998
29955
  seen.add(dir);
29999
- const config2 = join9(dir, ".rafters", "config.rafters.json");
29956
+ const config2 = join10(dir, ".rafters", "config.rafters.json");
30000
29957
  if (existsSync5(config2)) {
30001
29958
  workspaces.push({ name: basename(dir), root: dir });
30002
29959
  }
30003
29960
  }
30004
29961
  }
30005
- const rootConfig = join9(layout.root, ".rafters", "config.rafters.json");
29962
+ const rootConfig = join10(layout.root, ".rafters", "config.rafters.json");
30006
29963
  if (existsSync5(rootConfig) && !seen.has(layout.root)) {
30007
29964
  workspaces.unshift({ name: basename(layout.root), root: layout.root });
30008
29965
  }
@@ -30054,29 +30011,6 @@ var TOOL_DEFINITIONS = [
30054
30011
  required: []
30055
30012
  }
30056
30013
  },
30057
- {
30058
- name: "rafters_rule",
30059
- description: "Query validation rules or create new ones. Rules are named validation patterns (required, email, password, etc.) that composites can apply.",
30060
- inputSchema: {
30061
- type: "object",
30062
- properties: {
30063
- ...WORKSPACE_PARAM,
30064
- name: { type: "string", description: "Get a specific rule by name" },
30065
- query: { type: "string", description: "Search rules by name/description" },
30066
- create: {
30067
- type: "object",
30068
- properties: {
30069
- name: { type: "string", description: "Rule name (kebab-case)" },
30070
- description: { type: "string", description: "What this rule validates" },
30071
- zodSchema: { type: "string", description: "Zod schema as a string" }
30072
- },
30073
- required: ["name", "description", "zodSchema"],
30074
- description: "Create a new rule (provide all three fields)"
30075
- }
30076
- },
30077
- required: []
30078
- }
30079
- },
30080
30014
  {
30081
30015
  name: "rafters_pattern",
30082
30016
  description: 'Get design pattern guidance by querying composites. Search by what the pattern solves (e.g., "authentication", "data entry", "navigation") to get do/never rules, cognitive load, and designer intent.',
@@ -30129,20 +30063,22 @@ var RaftersToolHandler = class {
30129
30063
  return this.handleWorkspaces();
30130
30064
  case "rafters_composite":
30131
30065
  return this.handleComposite(args);
30132
- case "rafters_rule":
30133
- return this.handleRule(args);
30134
30066
  case "rafters_pattern":
30135
30067
  return this.handlePattern(args);
30136
30068
  case "rafters_component":
30137
30069
  return this.handleComponent(args.name);
30138
- default: {
30139
- const suggestion = name === "rafters_onboard" ? "rafters_onboard was removed. Token import is now a CLI operation: run `rafters init` (auto-detects and prompts) or `rafters import` (standalone)." : "Available tools: rafters_workspaces, rafters_composite, rafters_rule, rafters_pattern, rafters_component.";
30070
+ default:
30140
30071
  return {
30141
30072
  content: [
30142
- { type: "text", text: JSON.stringify({ error: `Unknown tool: ${name}`, suggestion }) }
30073
+ {
30074
+ type: "text",
30075
+ text: JSON.stringify({
30076
+ error: `Unknown tool: ${name}`,
30077
+ suggestion: "Available tools: rafters_workspaces, rafters_composite, rafters_pattern, rafters_component."
30078
+ })
30079
+ }
30143
30080
  ]
30144
30081
  };
30145
- }
30146
30082
  }
30147
30083
  }
30148
30084
  /**
@@ -30193,42 +30129,30 @@ var RaftersToolHandler = class {
30193
30129
  ]
30194
30130
  };
30195
30131
  }
30196
- async loadCompositesFromDir(dir) {
30197
- try {
30198
- const entries = await readdir(dir);
30199
- const files = entries.filter((f) => f.endsWith(".composite.json"));
30200
- for (const file2 of files) {
30201
- try {
30202
- const { readFile: readFile6 } = await import("fs/promises");
30203
- const raw = await readFile6(join10(dir, file2), "utf-8");
30204
- const parsed = JSON.parse(raw);
30205
- const result = CompositeFileSchema.safeParse(parsed);
30206
- if (result.success) {
30207
- try {
30208
- register2(result.data);
30209
- } catch {
30210
- }
30211
- }
30212
- } catch {
30213
- }
30132
+ /**
30133
+ * Recursively discover composites under the given directories via the shared
30134
+ * discovery core (node-fs adapter), then register each into the in-memory
30135
+ * registry. Duplicate ids -- across this call or against already-registered
30136
+ * composites -- are ignored: the first registration wins.
30137
+ */
30138
+ async loadCompositesFromDirs(...dirs) {
30139
+ const { registry: registry2 } = await discoverFromDirs(...dirs);
30140
+ for (const composite of registry2.values()) {
30141
+ try {
30142
+ register2(composite);
30143
+ } catch {
30214
30144
  }
30215
- } catch {
30216
30145
  }
30217
30146
  }
30218
30147
  async ensureCompositesLoaded(workspace) {
30219
30148
  if (!this.builtInCompositesLoaded) {
30220
- const builtInDirs = ["typography"];
30221
- for (const dir of builtInDirs) {
30222
- await this.loadCompositesFromDir(
30223
- join10(process.cwd(), "node_modules/@rafters/composites/src", dir)
30224
- );
30225
- }
30149
+ await this.loadCompositesFromDirs(
30150
+ join11(process.cwd(), "node_modules/@rafters/composites/src/typography")
30151
+ );
30226
30152
  this.builtInCompositesLoaded = true;
30227
30153
  }
30228
30154
  if (workspace && !this.compositesLoadedFor.has(workspace.root)) {
30229
- for (const dir of await this.compositeReadRoots(workspace.root)) {
30230
- await this.loadCompositesFromDir(dir);
30231
- }
30155
+ await this.loadCompositesFromDirs(...await this.compositeReadRoots(workspace.root));
30232
30156
  this.compositesLoadedFor.add(workspace.root);
30233
30157
  }
30234
30158
  }
@@ -30243,11 +30167,11 @@ var RaftersToolHandler = class {
30243
30167
  const paths = getRaftersPaths(workspaceRoot);
30244
30168
  let config2 = null;
30245
30169
  try {
30246
- config2 = JSON.parse(await readFile5(paths.config, "utf-8"));
30170
+ config2 = JSON.parse(await readFile6(paths.config, "utf-8"));
30247
30171
  } catch {
30248
30172
  }
30249
30173
  if (!config2?.compositesPath) {
30250
- return [join10(paths.root, "composites")];
30174
+ return [join11(paths.root, "composites")];
30251
30175
  }
30252
30176
  return resolveReadSet(config2.compositesPath, workspaceRoot);
30253
30177
  }
@@ -30280,49 +30204,15 @@ var RaftersToolHandler = class {
30280
30204
  usagePatterns: c4.manifest.usagePatterns,
30281
30205
  input: c4.input,
30282
30206
  output: c4.output,
30283
- blockCount: c4.blocks.length
30207
+ blockCount: c4.blocks.length,
30208
+ // Surface which blocks carry which validation rules. Rules compile to
30209
+ // native HTML5 constraint attributes at build, so agents need to see
30210
+ // them to reason about a composite's behavior. Only blocks with rules
30211
+ // are listed -- the array is empty when nothing is constrained.
30212
+ blockRules: c4.blocks.filter((b2) => b2.rules && b2.rules.length > 0).map((b2) => ({ id: b2.id, type: b2.type, rules: b2.rules }))
30284
30213
  }));
30285
30214
  return { content: [{ type: "text", text: JSON.stringify({ composites: result }, null, 2) }] };
30286
30215
  }
30287
- async handleRule(args) {
30288
- const { name, query, create } = args;
30289
- const builtInRules = [
30290
- { name: "required", description: "Field must have a value", source: "registry" },
30291
- { name: "email", description: "Must be a valid email address", source: "registry" },
30292
- {
30293
- name: "password",
30294
- description: "Password strength requirements",
30295
- source: "registry"
30296
- },
30297
- { name: "url", description: "Must be a valid URL", source: "registry" },
30298
- {
30299
- name: "credentials",
30300
- description: "Combined username/password validation",
30301
- source: "registry"
30302
- }
30303
- ];
30304
- if (create) {
30305
- return {
30306
- content: [
30307
- {
30308
- type: "text",
30309
- text: JSON.stringify({
30310
- error: "Rule creation not yet implemented",
30311
- suggestion: "Rules will be written to .rafters/rules/<name>.ts"
30312
- })
30313
- }
30314
- ]
30315
- };
30316
- }
30317
- let rules = builtInRules;
30318
- if (name) {
30319
- rules = rules.filter((r) => r.name === name);
30320
- } else if (query) {
30321
- const q = query.toLowerCase();
30322
- rules = rules.filter((r) => r.name.includes(q) || r.description.toLowerCase().includes(q));
30323
- }
30324
- return { content: [{ type: "text", text: JSON.stringify({ rules }, null, 2) }] };
30325
- }
30326
30216
  async handlePattern(args) {
30327
30217
  const { solves, query, workspace } = args;
30328
30218
  const resolved = this.resolve(workspace);
@@ -30462,7 +30352,7 @@ async function mcp(options) {
30462
30352
  let defaultWorkspace;
30463
30353
  if (options.projectRoot) {
30464
30354
  const explicit = resolve4(options.projectRoot);
30465
- const configPath = join11(explicit, ".rafters", "config.rafters.json");
30355
+ const configPath = join12(explicit, ".rafters", "config.rafters.json");
30466
30356
  if (!existsSync6(configPath)) {
30467
30357
  process.stderr.write(
30468
30358
  `--project-root ${explicit} does not contain .rafters/config.rafters.json
@@ -30488,7 +30378,7 @@ import { resolve as resolve5 } from "path";
30488
30378
 
30489
30379
  // ../studio/src/api/vite-plugin.ts
30490
30380
  import { writeFile as writeFile3 } from "fs/promises";
30491
- import { join as join12 } from "path";
30381
+ import { join as join13 } from "path";
30492
30382
  var REGISTRY_PLUGINS2 = [scalePlugin, contrastPlugin, statePlugin, invertPlugin];
30493
30383
  var STUDIO_REASON_DEFAULT = "studio interactive edit";
30494
30384
  var TokenResponseSchema = external_exports.object({
@@ -30514,7 +30404,7 @@ var ColorBuildOptionsSchema = external_exports.object({
30514
30404
  states: external_exports.record(external_exports.string(), external_exports.string()).optional()
30515
30405
  });
30516
30406
  var projectPath = process.env.RAFTERS_PROJECT_PATH || process.cwd();
30517
- var outputPath = join12(projectPath, ".rafters", "output", "rafters.vars.css");
30407
+ var outputPath = join13(projectPath, ".rafters", "output", "rafters.css");
30518
30408
  var SetTokenMessageSchema = external_exports.object({
30519
30409
  name: external_exports.string().min(1),
30520
30410
  value: external_exports.union([external_exports.string(), ColorValueSchema, ColorReferenceSchema]),
@@ -30884,7 +30774,7 @@ function studioApiPlugin() {
30884
30774
  return {
30885
30775
  name: "rafters-studio-api",
30886
30776
  async configureServer(server) {
30887
- const tokensDir = join12(projectPath, ".rafters", "tokens");
30777
+ const tokensDir = join13(projectPath, ".rafters", "tokens");
30888
30778
  try {
30889
30779
  registry2 = loadRegistryFromDir(tokensDir, REGISTRY_PLUGINS2);
30890
30780
  initialized = true;
@@ -30902,7 +30792,7 @@ function studioApiPlugin() {
30902
30792
  if (initialized) {
30903
30793
  saveRegistryToDir(tokensDir, registry2);
30904
30794
  }
30905
- await writeFile3(outputPath, registryToVars(registry2));
30795
+ await writeFile3(outputPath, registryToTailwind(registry2));
30906
30796
  server.ws.send({ type: "custom", event: "rafters:css-updated" });
30907
30797
  } catch (error47) {
30908
30798
  console.log(`[rafters] CSS regeneration failed: ${error47}`);
@@ -25,6 +25,7 @@ declare const RegistryItemTypeSchema: z.ZodEnum<{
25
25
  ui: "ui";
26
26
  primitive: "primitive";
27
27
  composite: "composite";
28
+ rule: "rule";
28
29
  }>;
29
30
  type RegistryItemType = z.infer<typeof RegistryItemTypeSchema>;
30
31
  /**
@@ -57,6 +58,7 @@ declare const RegistryItemSchema: z.ZodObject<{
57
58
  ui: "ui";
58
59
  primitive: "primitive";
59
60
  composite: "composite";
61
+ rule: "rule";
60
62
  }>;
61
63
  description: z.ZodOptional<z.ZodString>;
62
64
  primitives: z.ZodArray<z.ZodString>;
@@ -8,7 +8,7 @@ var RegistryFileSchema = z.object({
8
8
  devDependencies: z.array(z.string()).default([])
9
9
  // e.g., ["vitest"] - from @devDependencies JSDoc
10
10
  });
11
- var RegistryItemTypeSchema = z.enum(["ui", "primitive", "composite"]);
11
+ var RegistryItemTypeSchema = z.enum(["ui", "primitive", "composite", "rule"]);
12
12
  var RegistryItemIntelligenceSchema = z.object({
13
13
  cognitiveLoad: z.number().optional(),
14
14
  attentionEconomics: z.string().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rafters",
3
- "version": "0.0.68",
3
+ "version": "0.0.70",
4
4
  "description": "Design Intelligence CLI. Scaffold tokens, import existing shadcn/Tailwind v4 sources, add components, and serve an MCP server so AI agents read decisions instead of guessing.",
5
5
  "homepage": "https://rafters.studio",
6
6
  "license": "MIT",