rafters 0.0.16 → 0.0.20

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 +140 -90
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -18924,8 +18924,8 @@ var require_util = __commonJS({
18924
18924
  }
18925
18925
  function fn() {
18926
18926
  var promiseResolve, promiseReject;
18927
- var promise2 = new Promise(function(resolve4, reject) {
18928
- promiseResolve = resolve4;
18927
+ var promise2 = new Promise(function(resolve6, reject) {
18928
+ promiseResolve = resolve6;
18929
18929
  promiseReject = reject;
18930
18930
  });
18931
18931
  var args = [];
@@ -22889,7 +22889,7 @@ var require_events = __commonJS({
22889
22889
  return ret;
22890
22890
  }
22891
22891
  function once(emitter, name2) {
22892
- return new Promise(function(resolve4, reject) {
22892
+ return new Promise(function(resolve6, reject) {
22893
22893
  function errorListener(err) {
22894
22894
  emitter.removeListener(name2, resolver);
22895
22895
  reject(err);
@@ -22898,7 +22898,7 @@ var require_events = __commonJS({
22898
22898
  if (typeof emitter.removeListener === "function") {
22899
22899
  emitter.removeListener("error", errorListener);
22900
22900
  }
22901
- resolve4([].slice.call(arguments));
22901
+ resolve6([].slice.call(arguments));
22902
22902
  }
22903
22903
  ;
22904
22904
  eventTargetAgnosticAddListener(emitter, name2, resolver, { once: true });
@@ -23608,11 +23608,11 @@ var require_util3 = __commonJS({
23608
23608
  var queueMicrotask_1 = require_queueMicrotask();
23609
23609
  exports.isWin = process2.platform === "win32";
23610
23610
  function promisify(fs22, fn, getResult = (input) => input) {
23611
- return (...args) => new Promise((resolve4, reject) => {
23611
+ return (...args) => new Promise((resolve6, reject) => {
23612
23612
  fs22[fn].bind(fs22)(...args, (error48, result) => {
23613
23613
  if (error48)
23614
23614
  return reject(error48);
23615
- return resolve4(getResult(result));
23615
+ return resolve6(getResult(result));
23616
23616
  });
23617
23617
  });
23618
23618
  }
@@ -23768,9 +23768,9 @@ var require_util3 = __commonJS({
23768
23768
  }
23769
23769
  function streamToBuffer(stream2) {
23770
23770
  const chunks = [];
23771
- return new Promise((resolve4, reject) => {
23771
+ return new Promise((resolve6, reject) => {
23772
23772
  stream2.on("data", (chunk) => chunks.push(chunk));
23773
- stream2.on("end", () => resolve4(buffer_1.Buffer.concat(chunks)));
23773
+ stream2.on("end", () => resolve6(buffer_1.Buffer.concat(chunks)));
23774
23774
  stream2.on("error", reject);
23775
23775
  });
23776
23776
  }
@@ -24151,11 +24151,11 @@ function __metadata(metadataKey, metadataValue) {
24151
24151
  }
24152
24152
  function __awaiter(thisArg, _arguments, P, generator) {
24153
24153
  function adopt(value2) {
24154
- return value2 instanceof P ? value2 : new P(function(resolve4) {
24155
- resolve4(value2);
24154
+ return value2 instanceof P ? value2 : new P(function(resolve6) {
24155
+ resolve6(value2);
24156
24156
  });
24157
24157
  }
24158
- return new (P || (P = Promise))(function(resolve4, reject) {
24158
+ return new (P || (P = Promise))(function(resolve6, reject) {
24159
24159
  function fulfilled(value2) {
24160
24160
  try {
24161
24161
  step(generator.next(value2));
@@ -24171,7 +24171,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
24171
24171
  }
24172
24172
  }
24173
24173
  function step(result) {
24174
- result.done ? resolve4(result.value) : adopt(result.value).then(fulfilled, rejected);
24174
+ result.done ? resolve6(result.value) : adopt(result.value).then(fulfilled, rejected);
24175
24175
  }
24176
24176
  step((generator = generator.apply(thisArg, _arguments || [])).next());
24177
24177
  });
@@ -24354,14 +24354,14 @@ function __asyncValues(o) {
24354
24354
  }, i);
24355
24355
  function verb(n) {
24356
24356
  i[n] = o[n] && function(v) {
24357
- return new Promise(function(resolve4, reject) {
24358
- v = o[n](v), settle(resolve4, reject, v.done, v.value);
24357
+ return new Promise(function(resolve6, reject) {
24358
+ v = o[n](v), settle(resolve6, reject, v.done, v.value);
24359
24359
  });
24360
24360
  };
24361
24361
  }
24362
- function settle(resolve4, reject, d, v) {
24362
+ function settle(resolve6, reject, d, v) {
24363
24363
  Promise.resolve(v).then(function(v2) {
24364
- resolve4({ value: v2, done: d });
24364
+ resolve6({ value: v2, done: d });
24365
24365
  }, reject);
24366
24366
  }
24367
24367
  }
@@ -24779,12 +24779,12 @@ var require_Dir = __commonJS({
24779
24779
  return typeof x === "function";
24780
24780
  }
24781
24781
  promisify(obj, fn) {
24782
- return (...args) => new Promise((resolve4, reject) => {
24782
+ return (...args) => new Promise((resolve6, reject) => {
24783
24783
  if (this.isFunction(obj[fn])) {
24784
24784
  obj[fn].bind(obj)(...args, (error48, result) => {
24785
24785
  if (error48)
24786
24786
  reject(error48);
24787
- resolve4(result);
24787
+ resolve6(result);
24788
24788
  });
24789
24789
  } else {
24790
24790
  reject("Not a function");
@@ -24908,7 +24908,7 @@ var require_volume = __commonJS({
24908
24908
  var Dir_1 = require_Dir();
24909
24909
  var resolveCrossPlatform = pathModule.resolve;
24910
24910
  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;
24911
- var { sep: sep2, relative: relative3, join: join12, dirname: dirname4 } = pathModule.posix ? pathModule.posix : pathModule;
24911
+ var { sep: sep2, relative: relative3, join: join14, dirname: dirname5 } = pathModule.posix ? pathModule.posix : pathModule;
24912
24912
  var kMinPoolSpace = 128;
24913
24913
  var EPERM = "EPERM";
24914
24914
  var ENOENT2 = "ENOENT";
@@ -24923,13 +24923,13 @@ var require_volume = __commonJS({
24923
24923
  var ENOSYS = "ENOSYS";
24924
24924
  var ERR_FS_EISDIR = "ERR_FS_EISDIR";
24925
24925
  var ERR_OUT_OF_RANGE = "ERR_OUT_OF_RANGE";
24926
- var resolve4 = (filename, base = process_1.default.cwd()) => resolveCrossPlatform(base, filename);
24926
+ var resolve6 = (filename, base = process_1.default.cwd()) => resolveCrossPlatform(base, filename);
24927
24927
  if (util_1.isWin) {
24928
- const _resolve = resolve4;
24929
- resolve4 = (filename, base) => (0, util_1.unixify)(_resolve(filename, base));
24928
+ const _resolve = resolve6;
24929
+ resolve6 = (filename, base) => (0, util_1.unixify)(_resolve(filename, base));
24930
24930
  }
24931
24931
  function filenameToSteps(filename, base) {
24932
- const fullPath = resolve4(filename, base);
24932
+ const fullPath = resolve6(filename, base);
24933
24933
  const fullPathSansSlash = fullPath.substring(1);
24934
24934
  if (!fullPathSansSlash)
24935
24935
  return [];
@@ -24974,7 +24974,7 @@ var require_volume = __commonJS({
24974
24974
  function flatten(pathPrefix, node) {
24975
24975
  for (const path2 in node) {
24976
24976
  const contentOrNode = node[path2];
24977
- const joinedPath = join12(pathPrefix, path2);
24977
+ const joinedPath = join14(pathPrefix, path2);
24978
24978
  if (typeof contentOrNode === "string" || contentOrNode instanceof buffer_1.Buffer) {
24979
24979
  flatJSON[joinedPath] = contentOrNode;
24980
24980
  } else if (typeof contentOrNode === "object" && contentOrNode !== null && Object.keys(contentOrNode).length > 0) {
@@ -25131,7 +25131,7 @@ var require_volume = __commonJS({
25131
25131
  return null;
25132
25132
  node = curr === null || curr === void 0 ? void 0 : curr.getNode();
25133
25133
  if (resolveSymlinks && node.isSymlink()) {
25134
- const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join12(pathModule.dirname(curr.getPath()), node.symlink);
25134
+ const resolvedPath = pathModule.isAbsolute(node.symlink) ? node.symlink : join14(pathModule.dirname(curr.getPath()), node.symlink);
25135
25135
  steps = filenameToSteps(resolvedPath).concat(steps.slice(i + 1));
25136
25136
  curr = this.root;
25137
25137
  i = 0;
@@ -25290,9 +25290,9 @@ var require_volume = __commonJS({
25290
25290
  fromJSON(json3, cwd = process_1.default.cwd()) {
25291
25291
  for (let filename in json3) {
25292
25292
  const data = json3[filename];
25293
- filename = resolve4(filename, cwd);
25293
+ filename = resolve6(filename, cwd);
25294
25294
  if (typeof data === "string" || data instanceof buffer_1.Buffer) {
25295
- const dir = dirname4(filename);
25295
+ const dir = dirname5(filename);
25296
25296
  this.mkdirpBase(
25297
25297
  dir,
25298
25298
  511
@@ -31771,10 +31771,10 @@ var Minipass = class extends EventEmitter {
31771
31771
  * Return a void Promise that resolves once the stream ends.
31772
31772
  */
31773
31773
  async promise() {
31774
- return new Promise((resolve4, reject) => {
31774
+ return new Promise((resolve6, reject) => {
31775
31775
  this.on(DESTROYED, () => reject(new Error("stream destroyed")));
31776
31776
  this.on("error", (er) => reject(er));
31777
- this.on("end", () => resolve4());
31777
+ this.on("end", () => resolve6());
31778
31778
  });
31779
31779
  }
31780
31780
  /**
@@ -31798,7 +31798,7 @@ var Minipass = class extends EventEmitter {
31798
31798
  return Promise.resolve({ done: false, value: res });
31799
31799
  if (this[EOF])
31800
31800
  return stop();
31801
- let resolve4;
31801
+ let resolve6;
31802
31802
  let reject;
31803
31803
  const onerr = (er) => {
31804
31804
  this.off("data", ondata);
@@ -31812,19 +31812,19 @@ var Minipass = class extends EventEmitter {
31812
31812
  this.off("end", onend);
31813
31813
  this.off(DESTROYED, ondestroy);
31814
31814
  this.pause();
31815
- resolve4({ value: value2, done: !!this[EOF] });
31815
+ resolve6({ value: value2, done: !!this[EOF] });
31816
31816
  };
31817
31817
  const onend = () => {
31818
31818
  this.off("error", onerr);
31819
31819
  this.off("data", ondata);
31820
31820
  this.off(DESTROYED, ondestroy);
31821
31821
  stop();
31822
- resolve4({ done: true, value: void 0 });
31822
+ resolve6({ done: true, value: void 0 });
31823
31823
  };
31824
31824
  const ondestroy = () => onerr(new Error("stream destroyed"));
31825
31825
  return new Promise((res2, rej) => {
31826
31826
  reject = rej;
31827
- resolve4 = res2;
31827
+ resolve6 = res2;
31828
31828
  this.once(DESTROYED, ondestroy);
31829
31829
  this.once("error", onerr);
31830
31830
  this.once("end", onend);
@@ -32796,9 +32796,9 @@ var PathBase = class {
32796
32796
  if (this.#asyncReaddirInFlight) {
32797
32797
  await this.#asyncReaddirInFlight;
32798
32798
  } else {
32799
- let resolve4 = () => {
32799
+ let resolve6 = () => {
32800
32800
  };
32801
- this.#asyncReaddirInFlight = new Promise((res) => resolve4 = res);
32801
+ this.#asyncReaddirInFlight = new Promise((res) => resolve6 = res);
32802
32802
  try {
32803
32803
  for (const e of await this.#fs.promises.readdir(fullpath, {
32804
32804
  withFileTypes: true
@@ -32811,7 +32811,7 @@ var PathBase = class {
32811
32811
  children.provisional = 0;
32812
32812
  }
32813
32813
  this.#asyncReaddirInFlight = void 0;
32814
- resolve4();
32814
+ resolve6();
32815
32815
  }
32816
32816
  return children.slice(0, children.provisional);
32817
32817
  }
@@ -36066,7 +36066,7 @@ function toBase64(buffer) {
36066
36066
  if (isNode) {
36067
36067
  return buffer.toString("base64");
36068
36068
  } else {
36069
- return new Promise((resolve4, reject) => {
36069
+ return new Promise((resolve6, reject) => {
36070
36070
  const blob = new Blob([buffer], { type: "application/octet-stream" });
36071
36071
  const reader = new FileReader();
36072
36072
  reader.onloadend = () => {
@@ -36074,7 +36074,7 @@ function toBase64(buffer) {
36074
36074
  /** @type {string } */
36075
36075
  reader.result.split(",")[1]
36076
36076
  );
36077
- resolve4(base64String);
36077
+ resolve6(base64String);
36078
36078
  };
36079
36079
  reader.onerror = reject;
36080
36080
  reader.readAsDataURL(blob);
@@ -39687,7 +39687,7 @@ var AESDecryptionStream = class extends TransformStream {
39687
39687
  super({
39688
39688
  start() {
39689
39689
  Object.assign(this, {
39690
- ready: new Promise((resolve4) => this.resolveReady = resolve4),
39690
+ ready: new Promise((resolve6) => this.resolveReady = resolve6),
39691
39691
  password: encodePassword(password, rawPassword),
39692
39692
  signed,
39693
39693
  strength: encryptionStrength - 1,
@@ -39755,7 +39755,7 @@ var AESEncryptionStream = class extends TransformStream {
39755
39755
  super({
39756
39756
  start() {
39757
39757
  Object.assign(this, {
39758
- ready: new Promise((resolve4) => this.resolveReady = resolve4),
39758
+ ready: new Promise((resolve6) => this.resolveReady = resolve6),
39759
39759
  password: encodePassword(password, rawPassword),
39760
39760
  strength: encryptionStrength - 1,
39761
39761
  pending: new Uint8Array()
@@ -47181,20 +47181,20 @@ async function registryToCompiled(registry2, options = {}) {
47181
47181
  const themeCss = registryToTailwind(registry2, { includeImport });
47182
47182
  const { execFileSync } = await import("child_process");
47183
47183
  const { mkdtempSync, writeFileSync, readFileSync, rmSync } = await import("fs");
47184
- const { join: join12, dirname: dirname4 } = await import("path");
47184
+ const { join: join14, dirname: dirname5 } = await import("path");
47185
47185
  const { createRequire: createRequire2 } = await import("module");
47186
47186
  const require2 = createRequire2(import.meta.url);
47187
47187
  let pkgDir;
47188
47188
  try {
47189
47189
  const pkgJsonPath = require2.resolve("@tailwindcss/cli/package.json");
47190
- pkgDir = dirname4(pkgJsonPath);
47190
+ pkgDir = dirname5(pkgJsonPath);
47191
47191
  } catch {
47192
47192
  throw new Error("Failed to resolve @tailwindcss/cli");
47193
47193
  }
47194
- const binPath = join12(pkgDir, "dist", "index.mjs");
47195
- const tempDir = mkdtempSync(join12(pkgDir, ".tmp-compile-"));
47196
- const tempInput = join12(tempDir, "input.css");
47197
- const tempOutput = join12(tempDir, "output.css");
47194
+ const binPath = join14(pkgDir, "dist", "index.mjs");
47195
+ const tempDir = mkdtempSync(join14(pkgDir, ".tmp-compile-"));
47196
+ const tempInput = join14(tempDir, "input.css");
47197
+ const tempOutput = join14(tempDir, "output.css");
47198
47198
  try {
47199
47199
  writeFileSync(tempInput, themeCss);
47200
47200
  const args = [binPath, "-i", tempInput, "-o", tempOutput];
@@ -47476,7 +47476,7 @@ function tagTokenizer() {
47476
47476
 
47477
47477
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/type.js
47478
47478
  function typeTokenizer(spacing = "compact") {
47479
- const join12 = getJoiner(spacing);
47479
+ const join14 = getJoiner(spacing);
47480
47480
  return (spec) => {
47481
47481
  let curlies = 0;
47482
47482
  let lines = [];
@@ -47519,7 +47519,7 @@ function typeTokenizer(spacing = "compact") {
47519
47519
  }
47520
47520
  parts[0] = parts[0].slice(1);
47521
47521
  parts[parts.length - 1] = parts[parts.length - 1].slice(0, -1);
47522
- spec.type = join12(parts);
47522
+ spec.type = join14(parts);
47523
47523
  return spec;
47524
47524
  };
47525
47525
  }
@@ -47617,9 +47617,9 @@ function nameTokenizer() {
47617
47617
 
47618
47618
  // ../../node_modules/.pnpm/comment-parser@1.4.1/node_modules/comment-parser/es6/parser/tokenizers/description.js
47619
47619
  function descriptionTokenizer(spacing = "compact", markers = Markers) {
47620
- const join12 = getJoiner2(spacing);
47620
+ const join14 = getJoiner2(spacing);
47621
47621
  return (spec) => {
47622
- spec.description = join12(spec.source, markers);
47622
+ spec.description = join14(spec.source, markers);
47623
47623
  return spec;
47624
47624
  };
47625
47625
  }
@@ -51558,6 +51558,10 @@ async function init(options) {
51558
51558
  });
51559
51559
  }
51560
51560
 
51561
+ // src/commands/mcp.ts
51562
+ import { existsSync as existsSync6 } from "fs";
51563
+ import { join as join12, resolve as resolve5 } from "path";
51564
+
51561
51565
  // src/mcp/server.ts
51562
51566
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
51563
51567
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -52873,17 +52877,21 @@ var TOOL_DEFINITIONS = [
52873
52877
  }
52874
52878
  }
52875
52879
  ];
52880
+ var NO_PROJECT_ERROR = "No .rafters/ config found. Run `pnpm dlx rafters init` in your project first. If the MCP server was launched from a different directory, pass --project-root <path>.";
52881
+ var PROJECT_INDEPENDENT_TOOLS = /* @__PURE__ */ new Set(["rafters_pattern"]);
52876
52882
  var RaftersToolHandler = class {
52877
52883
  adapter;
52878
52884
  projectRoot;
52879
- constructor(projectRoot = process.cwd()) {
52885
+ cachedConfig;
52886
+ constructor(projectRoot) {
52880
52887
  this.projectRoot = projectRoot;
52881
- this.adapter = new NodePersistenceAdapter(projectRoot);
52888
+ this.adapter = projectRoot ? new NodePersistenceAdapter(projectRoot) : null;
52882
52889
  }
52883
52890
  /**
52884
52891
  * Load tokens for a specific namespace
52885
52892
  */
52886
52893
  async loadNamespace(namespace) {
52894
+ if (!this.adapter) return [];
52887
52895
  const allTokens = await this.adapter.load();
52888
52896
  return allTokens.filter((t2) => t2.namespace === namespace);
52889
52897
  }
@@ -52891,6 +52899,9 @@ var RaftersToolHandler = class {
52891
52899
  * Handle a tool call from MCP
52892
52900
  */
52893
52901
  async handleToolCall(name2, args) {
52902
+ if (!this.projectRoot && !PROJECT_INDEPENDENT_TOOLS.has(name2)) {
52903
+ return { content: [{ type: "text", text: NO_PROJECT_ERROR }], isError: true };
52904
+ }
52894
52905
  switch (name2) {
52895
52906
  case "rafters_vocabulary":
52896
52907
  return this.getVocabulary();
@@ -53057,37 +53068,38 @@ var RaftersToolHandler = class {
53057
53068
  * Returns null when no config exists or when it cannot be parsed.
53058
53069
  */
53059
53070
  async loadConfig() {
53071
+ if (this.cachedConfig !== void 0) return this.cachedConfig;
53072
+ if (!this.projectRoot) {
53073
+ this.cachedConfig = null;
53074
+ return null;
53075
+ }
53076
+ const paths = getRaftersPaths(this.projectRoot);
53077
+ if (!existsSync4(paths.config)) {
53078
+ this.cachedConfig = null;
53079
+ return null;
53080
+ }
53081
+ const content = await readFile6(paths.config, "utf-8");
53060
53082
  try {
53061
- const paths = getRaftersPaths(this.projectRoot);
53062
- if (!existsSync4(paths.config)) {
53063
- return null;
53064
- }
53065
- const content = await readFile6(paths.config, "utf-8");
53066
- return JSON.parse(content);
53083
+ this.cachedConfig = JSON.parse(content);
53067
53084
  } catch {
53068
- return null;
53085
+ throw new Error(`Malformed JSON in ${paths.config}. Check the file for syntax errors.`);
53069
53086
  }
53087
+ return this.cachedConfig;
53070
53088
  }
53071
53089
  /**
53072
53090
  * Extract compact component vocabulary
53073
53091
  */
53074
53092
  async getComponentVocabulary() {
53075
- let installed = [];
53076
- try {
53077
- const config3 = await this.loadConfig();
53078
- if (config3) {
53079
- installed = config3.installed?.components ?? [];
53080
- }
53081
- } catch {
53082
- }
53083
- let available = [];
53093
+ const config3 = await this.loadConfig();
53094
+ const installed = config3?.installed?.components ?? [];
53095
+ let available;
53084
53096
  try {
53085
- const client = new RegistryClient();
53086
- const index = await client.fetchIndex();
53087
- const allComponents = index.components;
53097
+ const index = await registryClient.fetchIndex();
53088
53098
  const installedSet = new Set(installed);
53089
- available = allComponents.filter((name2) => !installedSet.has(name2));
53090
- } catch {
53099
+ available = index.components.filter((name2) => !installedSet.has(name2));
53100
+ } catch (error48) {
53101
+ const msg = error48 instanceof Error ? error48.message : "unknown error";
53102
+ available = [`(registry unreachable: ${msg})`];
53091
53103
  }
53092
53104
  return { installed, available };
53093
53105
  }
@@ -53132,6 +53144,7 @@ var RaftersToolHandler = class {
53132
53144
  * falls back to the monorepo layout for local development.
53133
53145
  */
53134
53146
  async getComponentsPath() {
53147
+ if (!this.projectRoot) return null;
53135
53148
  const config3 = await this.loadConfig();
53136
53149
  if (config3?.componentsPath) {
53137
53150
  return join10(this.projectRoot, config3.componentsPath);
@@ -53143,6 +53156,7 @@ var RaftersToolHandler = class {
53143
53156
  */
53144
53157
  async loadComponentMetadata(name2) {
53145
53158
  const componentsPath = await this.getComponentsPath();
53159
+ if (!componentsPath) return null;
53146
53160
  const filePath = join10(componentsPath, `${name2}.tsx`);
53147
53161
  try {
53148
53162
  const source = await readFile6(filePath, "utf-8");
@@ -53161,6 +53175,7 @@ var RaftersToolHandler = class {
53161
53175
  sizes: extractSizes(source),
53162
53176
  dependencies: extractDependencies(source),
53163
53177
  primitives: extractPrimitiveDependencies(source),
53178
+ // projectRoot is guaranteed non-null here: handleToolCall guards it
53164
53179
  filePath: relative2(this.projectRoot, join10(componentsPath, `${name2}.tsx`))
53165
53180
  };
53166
53181
  if (hasAnyDeps(jsDocDeps)) {
@@ -53255,10 +53270,12 @@ var RaftersToolHandler = class {
53255
53270
  if (!metadata) {
53256
53271
  const componentsPath = await this.getComponentsPath();
53257
53272
  let available = [];
53258
- try {
53259
- const files = await readdir3(componentsPath);
53260
- available = files.filter((f) => f.endsWith(".tsx")).map((f) => basename(f, ".tsx")).filter((n) => n.includes(name2) || name2.includes(n)).slice(0, 5);
53261
- } catch {
53273
+ if (componentsPath) {
53274
+ try {
53275
+ const files = await readdir3(componentsPath);
53276
+ available = files.filter((f) => f.endsWith(".tsx")).map((f) => basename(f, ".tsx")).filter((n) => n.includes(name2) || name2.includes(n)).slice(0, 5);
53277
+ } catch {
53278
+ }
53262
53279
  }
53263
53280
  return {
53264
53281
  content: [
@@ -53568,8 +53585,7 @@ var RaftersToolHandler = class {
53568
53585
  };
53569
53586
 
53570
53587
  // src/mcp/server.ts
53571
- async function startMcpServer() {
53572
- const projectRoot = process.cwd();
53588
+ async function startMcpServer(projectRoot) {
53573
53589
  const toolHandler = new RaftersToolHandler(projectRoot);
53574
53590
  const server = new Server(
53575
53591
  {
@@ -53610,28 +53626,62 @@ async function startMcpServer() {
53610
53626
  });
53611
53627
  }
53612
53628
 
53629
+ // src/utils/discover.ts
53630
+ import { existsSync as existsSync5 } from "fs";
53631
+ import { dirname as dirname3, join as join11, resolve as resolve4 } from "path";
53632
+ function discoverProjectRoot(startDir) {
53633
+ let current = resolve4(startDir);
53634
+ for (; ; ) {
53635
+ const configPath = join11(current, ".rafters", "config.rafters.json");
53636
+ if (existsSync5(configPath)) {
53637
+ return current;
53638
+ }
53639
+ const parent = dirname3(current);
53640
+ if (parent === current) {
53641
+ return null;
53642
+ }
53643
+ current = parent;
53644
+ }
53645
+ }
53646
+
53613
53647
  // src/commands/mcp.ts
53614
- async function mcp() {
53615
- await startMcpServer();
53648
+ async function mcp(options) {
53649
+ let projectRoot;
53650
+ if (options.projectRoot) {
53651
+ const explicit = resolve5(options.projectRoot);
53652
+ const configPath = join12(explicit, ".rafters", "config.rafters.json");
53653
+ if (!existsSync6(configPath)) {
53654
+ process.stderr.write(
53655
+ `--project-root ${explicit} does not contain .rafters/config.rafters.json
53656
+ `
53657
+ );
53658
+ projectRoot = null;
53659
+ } else {
53660
+ projectRoot = explicit;
53661
+ }
53662
+ } else {
53663
+ projectRoot = discoverProjectRoot(process.cwd());
53664
+ }
53665
+ await startMcpServer(projectRoot);
53616
53666
  }
53617
53667
 
53618
53668
  // src/commands/studio.ts
53619
- import { existsSync as existsSync5 } from "fs";
53620
- import { dirname as dirname3, join as join11 } from "path";
53669
+ import { existsSync as existsSync7 } from "fs";
53670
+ import { dirname as dirname4, join as join13 } from "path";
53621
53671
  import { fileURLToPath as fileURLToPath3 } from "url";
53622
53672
  import { execa as execa2 } from "execa";
53623
- var __dirname2 = dirname3(fileURLToPath3(import.meta.url));
53673
+ var __dirname2 = dirname4(fileURLToPath3(import.meta.url));
53624
53674
  async function studio() {
53625
53675
  const cwd = process.cwd();
53626
53676
  const paths = getRaftersPaths(cwd);
53627
- if (!existsSync5(paths.root)) {
53677
+ if (!existsSync7(paths.root)) {
53628
53678
  console.error('No .rafters/ directory found. Run "rafters init" first.');
53629
53679
  process.exit(1);
53630
53680
  }
53631
- const devStudioPath = join11(__dirname2, "..", "..", "..", "studio");
53632
- const prodStudioPath = join11(__dirname2, "..", "node_modules", "@rafters", "studio");
53633
- const studioPath = existsSync5(devStudioPath) ? devStudioPath : prodStudioPath;
53634
- if (!existsSync5(studioPath)) {
53681
+ const devStudioPath = join13(__dirname2, "..", "..", "..", "studio");
53682
+ const prodStudioPath = join13(__dirname2, "..", "node_modules", "@rafters", "studio");
53683
+ const studioPath = existsSync7(devStudioPath) ? devStudioPath : prodStudioPath;
53684
+ if (!existsSync7(studioPath)) {
53635
53685
  console.error("Studio package not found. Please reinstall @rafters/cli.");
53636
53686
  process.exit(1);
53637
53687
  }
@@ -53662,7 +53712,7 @@ var program = new Command();
53662
53712
  program.name("rafters").description("Design system CLI - scaffold tokens and serve MCP").version("0.0.1");
53663
53713
  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));
53664
53714
  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));
53665
- program.command("mcp").description("Start MCP server for AI agent access (stdio)").action(mcp);
53715
+ program.command("mcp").description("Start MCP server for AI agent access (stdio)").option("--project-root <path>", "Explicit project root (skips .rafters/ discovery)").action(mcp);
53666
53716
  program.command("studio").description("Open Studio UI for visual token editing").action(studio);
53667
53717
  program.parse();
53668
53718
  /*! Bundled license information:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rafters",
3
- "version": "0.0.16",
3
+ "version": "0.0.20",
4
4
  "description": "CLI for Rafters design system - scaffold tokens and add components",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,6 +24,7 @@
24
24
  "test": "pnpm run test:bdd && pnpm run test:unit",
25
25
  "test:bdd": "bddgen && playwright test",
26
26
  "test:unit": "vitest run",
27
+ "test:integration": "vitest run --config vitest.integration.config.ts",
27
28
  "test:watch": "vitest",
28
29
  "typecheck": "tsc --noEmit",
29
30
  "clean": "rm -rf dist .turbo"
@@ -50,7 +51,7 @@
50
51
  },
51
52
  "repository": {
52
53
  "type": "git",
53
- "url": "git+https://github.com/ezmode-games/rafters.git",
54
+ "url": "git+https://github.com/rafters-studio/rafters.git",
54
55
  "directory": "packages/cli"
55
56
  },
56
57
  "publishConfig": {