@bearnie/mcp 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -112,6 +112,17 @@ Add a component to your Astro project. Creates files in `src/components/bearnie/
112
112
 
113
113
  Install components first, then add `barrel` last for `import { Button, Card } from "@/components/bearnie"`.
114
114
 
115
+ ### `add_components`
116
+
117
+ Add multiple components in one step. Resolves registry dependencies and installs `barrel` last when included.
118
+
119
+ **Parameters:**
120
+
121
+ - `names` (string[]): Component names to add
122
+ - `cwd` (string, optional): Working directory
123
+
124
+ **Example prompt:** "Add button, card, and barrel to my project"
125
+
115
126
  ## Environment Variables
116
127
 
117
128
  | Variable | Description |
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -779,10 +779,10 @@ function mergeDefs(...defs) {
779
779
  function cloneDef(schema) {
780
780
  return mergeDefs(schema._zod.def);
781
781
  }
782
- function getElementAtPath(obj, path2) {
783
- if (!path2)
782
+ function getElementAtPath(obj, path3) {
783
+ if (!path3)
784
784
  return obj;
785
- return path2.reduce((acc, key) => acc?.[key], obj);
785
+ return path3.reduce((acc, key) => acc?.[key], obj);
786
786
  }
787
787
  function promiseAllObject(promisesObj) {
788
788
  const keys = Object.keys(promisesObj);
@@ -1165,11 +1165,11 @@ function aborted(x, startIndex = 0) {
1165
1165
  }
1166
1166
  return false;
1167
1167
  }
1168
- function prefixIssues(path2, issues) {
1168
+ function prefixIssues(path3, issues) {
1169
1169
  return issues.map((iss) => {
1170
1170
  var _a2;
1171
1171
  (_a2 = iss).path ?? (_a2.path = []);
1172
- iss.path.unshift(path2);
1172
+ iss.path.unshift(path3);
1173
1173
  return iss;
1174
1174
  });
1175
1175
  }
@@ -1352,7 +1352,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
1352
1352
  }
1353
1353
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
1354
1354
  const result = { errors: [] };
1355
- const processError = (error49, path2 = []) => {
1355
+ const processError = (error49, path3 = []) => {
1356
1356
  var _a2, _b;
1357
1357
  for (const issue2 of error49.issues) {
1358
1358
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -1362,7 +1362,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1362
1362
  } else if (issue2.code === "invalid_element") {
1363
1363
  processError({ issues: issue2.issues }, issue2.path);
1364
1364
  } else {
1365
- const fullpath = [...path2, ...issue2.path];
1365
+ const fullpath = [...path3, ...issue2.path];
1366
1366
  if (fullpath.length === 0) {
1367
1367
  result.errors.push(mapper(issue2));
1368
1368
  continue;
@@ -1394,8 +1394,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1394
1394
  }
1395
1395
  function toDotPath(_path) {
1396
1396
  const segs = [];
1397
- const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1398
- for (const seg of path2) {
1397
+ const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1398
+ for (const seg of path3) {
1399
1399
  if (typeof seg === "number")
1400
1400
  segs.push(`[${seg}]`);
1401
1401
  else if (typeof seg === "symbol")
@@ -13372,13 +13372,13 @@ function resolveRef(ref, ctx) {
13372
13372
  if (!ref.startsWith("#")) {
13373
13373
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
13374
13374
  }
13375
- const path2 = ref.slice(1).split("/").filter(Boolean);
13376
- if (path2.length === 0) {
13375
+ const path3 = ref.slice(1).split("/").filter(Boolean);
13376
+ if (path3.length === 0) {
13377
13377
  return ctx.rootSchema;
13378
13378
  }
13379
13379
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
13380
- if (path2[0] === defsKey) {
13381
- const key = path2[1];
13380
+ if (path3[0] === defsKey) {
13381
+ const key = path3[1];
13382
13382
  if (!key || !ctx.defs[key]) {
13383
13383
  throw new Error(`Reference not found: ${ref}`);
13384
13384
  }
@@ -13781,18 +13781,21 @@ function date4(params) {
13781
13781
  config(en_default());
13782
13782
 
13783
13783
  // src/index.ts
13784
+ import fs2 from "fs-extra";
13785
+ import path2 from "path";
13786
+
13787
+ // src/install.ts
13784
13788
  import fs from "fs-extra";
13785
13789
  import path from "path";
13786
- var __dirname = dirname(fileURLToPath(import.meta.url));
13787
- var pkg = JSON.parse(
13788
- readFileSync(join(__dirname, "../package.json"), "utf-8")
13789
- );
13790
13790
  var REGISTRY_URL = process.env.BEARNIE_REGISTRY_URL || "https://bearnie.dev/registry";
13791
- var REGISTRY_PATH = process.env.BEARNIE_REGISTRY_PATH;
13791
+ function getRegistryPath() {
13792
+ return process.env.BEARNIE_REGISTRY_PATH;
13793
+ }
13792
13794
  async function fetchComponent(name) {
13793
13795
  try {
13794
- if (REGISTRY_PATH) {
13795
- const componentPath = path.join(REGISTRY_PATH, `${name}.json`);
13796
+ const registryPath = getRegistryPath();
13797
+ if (registryPath) {
13798
+ const componentPath = path.join(registryPath, `${name}.json`);
13796
13799
  if (await fs.pathExists(componentPath)) {
13797
13800
  return await fs.readJson(componentPath);
13798
13801
  }
@@ -13807,8 +13810,9 @@ async function fetchComponent(name) {
13807
13810
  }
13808
13811
  async function fetchIndex() {
13809
13812
  try {
13810
- if (REGISTRY_PATH) {
13811
- const indexPath = path.join(REGISTRY_PATH, "index.json");
13813
+ const registryPath = getRegistryPath();
13814
+ if (registryPath) {
13815
+ const indexPath = path.join(registryPath, "index.json");
13812
13816
  if (await fs.pathExists(indexPath)) {
13813
13817
  return await fs.readJson(indexPath);
13814
13818
  }
@@ -13821,16 +13825,6 @@ async function fetchIndex() {
13821
13825
  return null;
13822
13826
  }
13823
13827
  }
13824
- function findProjectRoot(startDir) {
13825
- let dir = startDir;
13826
- while (dir !== path.parse(dir).root) {
13827
- if (fs.existsSync(path.join(dir, "package.json"))) {
13828
- return dir;
13829
- }
13830
- dir = path.dirname(dir);
13831
- }
13832
- return null;
13833
- }
13834
13828
  function resolveInstallPath(projectRoot, file2, registryItem) {
13835
13829
  const relativePath = file2.path || file2.name;
13836
13830
  if (registryItem.type === "utility" || relativePath.startsWith("utils/")) {
@@ -13849,6 +13843,84 @@ function resolveInstallPath(projectRoot, file2, registryItem) {
13849
13843
  }
13850
13844
  return path.join(projectRoot, "src/components/bearnie", relativePath);
13851
13845
  }
13846
+ async function resolveComponentDependencies(names, resolved = /* @__PURE__ */ new Set()) {
13847
+ const result = [];
13848
+ for (const name of names) {
13849
+ if (resolved.has(name)) continue;
13850
+ resolved.add(name);
13851
+ const component = await fetchComponent(name);
13852
+ if (!component) continue;
13853
+ if (component.registryDependencies?.length) {
13854
+ const deps = await resolveComponentDependencies(
13855
+ component.registryDependencies,
13856
+ resolved
13857
+ );
13858
+ result.push(...deps);
13859
+ }
13860
+ result.push(name);
13861
+ }
13862
+ return result;
13863
+ }
13864
+ function orderWithBarrelLast(names) {
13865
+ const unique = [...new Set(names)];
13866
+ const withoutBarrel = unique.filter((name) => name !== "barrel");
13867
+ if (unique.includes("barrel")) {
13868
+ withoutBarrel.push("barrel");
13869
+ }
13870
+ return withoutBarrel;
13871
+ }
13872
+ async function installSingleComponent(projectRoot, componentName) {
13873
+ const component = await fetchComponent(componentName);
13874
+ if (!component) {
13875
+ return {
13876
+ files: [],
13877
+ npmDependencies: [],
13878
+ error: `Component '${componentName}' not found`
13879
+ };
13880
+ }
13881
+ const files = [];
13882
+ const npmDependencies = [...component.dependencies ?? []];
13883
+ const installFiles = async (entry) => {
13884
+ for (const file2 of entry.files) {
13885
+ const filePath = resolveInstallPath(projectRoot, file2, entry);
13886
+ await fs.ensureDir(path.dirname(filePath));
13887
+ await fs.writeFile(filePath, file2.content);
13888
+ files.push(file2.path || file2.name);
13889
+ }
13890
+ };
13891
+ if (component.registryDependencies?.length) {
13892
+ for (const dep of component.registryDependencies) {
13893
+ const depComponent = await fetchComponent(dep);
13894
+ if (depComponent) {
13895
+ await installFiles(depComponent);
13896
+ npmDependencies.push(...depComponent.dependencies ?? []);
13897
+ }
13898
+ }
13899
+ }
13900
+ await installFiles(component);
13901
+ return { files, npmDependencies };
13902
+ }
13903
+ async function installComponents(projectRoot, names) {
13904
+ const resolved = await resolveComponentDependencies(names);
13905
+ const ordered = orderWithBarrelLast(resolved);
13906
+ const installed = [];
13907
+ const npmDependencies = /* @__PURE__ */ new Set();
13908
+ const errors = [];
13909
+ for (const name of ordered) {
13910
+ const result = await installSingleComponent(projectRoot, name);
13911
+ if (result.error) {
13912
+ errors.push(result.error);
13913
+ continue;
13914
+ }
13915
+ installed.push(name);
13916
+ result.npmDependencies.forEach((dep) => npmDependencies.add(dep));
13917
+ }
13918
+ return {
13919
+ installed,
13920
+ npmDependencies: [...npmDependencies],
13921
+ errors
13922
+ };
13923
+ }
13852
13924
  function toPascalCase(name) {
13853
13925
  return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
13854
13926
  }
@@ -13880,6 +13952,22 @@ import ${componentName} from "@/components/bearnie/${component.name}/${component
13880
13952
  <${componentName}>Content</${componentName}>
13881
13953
  \`\`\``;
13882
13954
  }
13955
+
13956
+ // src/index.ts
13957
+ var __dirname = dirname(fileURLToPath(import.meta.url));
13958
+ var pkg = JSON.parse(
13959
+ readFileSync(join(__dirname, "../package.json"), "utf-8")
13960
+ );
13961
+ function findProjectRoot(startDir) {
13962
+ let dir = startDir;
13963
+ while (dir !== path2.parse(dir).root) {
13964
+ if (fs2.existsSync(path2.join(dir, "package.json"))) {
13965
+ return dir;
13966
+ }
13967
+ dir = path2.dirname(dir);
13968
+ }
13969
+ return null;
13970
+ }
13883
13971
  var server = new McpServer({
13884
13972
  name: "bearnie",
13885
13973
  version: pkg.version
@@ -13900,11 +13988,14 @@ server.tool(
13900
13988
  ]
13901
13989
  };
13902
13990
  }
13903
- const grouped = index.components.reduce((acc, comp) => {
13904
- if (!acc[comp.category]) acc[comp.category] = [];
13905
- acc[comp.category].push(comp);
13906
- return acc;
13907
- }, {});
13991
+ const grouped = index.components.reduce(
13992
+ (acc, comp) => {
13993
+ if (!acc[comp.category]) acc[comp.category] = [];
13994
+ acc[comp.category].push(comp);
13995
+ return acc;
13996
+ },
13997
+ {}
13998
+ );
13908
13999
  let output = "# Available Bearnie Components\n\n";
13909
14000
  for (const [category, components] of Object.entries(grouped).sort()) {
13910
14001
  output += `## ${category.charAt(0).toUpperCase() + category.slice(1)}
@@ -13926,7 +14017,7 @@ server.tool(
13926
14017
  "Get detailed information about a specific Bearnie component including its files and dependencies",
13927
14018
  {
13928
14019
  name: external_exports.string().describe(
13929
- "The name of the component (e.g., 'button', 'accordion', 'dialog')"
14020
+ "The name of the component (e.g., 'button', 'accordion', 'dialog', 'barrel')"
13930
14021
  )
13931
14022
  },
13932
14023
  async ({ name }) => {
@@ -14007,61 +14098,98 @@ server.tool(
14007
14098
  ]
14008
14099
  };
14009
14100
  }
14010
- const component = await fetchComponent(name.toLowerCase());
14011
- if (!component) {
14101
+ const result = await installComponents(projectRoot, [name.toLowerCase()]);
14102
+ if (result.errors.length > 0) {
14012
14103
  return {
14013
14104
  content: [
14014
14105
  {
14015
14106
  type: "text",
14016
- text: `Error: Component '${name}' not found. Use list_components to see available components.`
14107
+ text: `Error: ${result.errors.join(", ")}`
14017
14108
  }
14018
14109
  ]
14019
14110
  };
14020
14111
  }
14021
- const results = [];
14022
- if (component.registryDependencies?.length) {
14023
- for (const dep of component.registryDependencies) {
14024
- const depComponent = await fetchComponent(dep);
14025
- if (depComponent) {
14026
- for (const file2 of depComponent.files) {
14027
- const filePath = resolveInstallPath(projectRoot, file2, depComponent);
14028
- await fs.ensureDir(path.dirname(filePath));
14029
- await fs.writeFile(filePath, file2.content);
14030
- results.push(`\u2713 Added dependency: ${file2.path || file2.name}`);
14031
- }
14032
- }
14033
- }
14034
- }
14035
- for (const file2 of component.files) {
14036
- const filePath = resolveInstallPath(projectRoot, file2, component);
14037
- await fs.ensureDir(path.dirname(filePath));
14038
- await fs.writeFile(filePath, file2.content);
14039
- results.push(`\u2713 Added: ${file2.path || file2.name}`);
14040
- }
14041
- let output = `# Added ${component.name}
14112
+ const component = await fetchComponent(name.toLowerCase());
14113
+ let output = `# Added ${name}
14042
14114
 
14043
14115
  `;
14044
- output += results.join("\n") + "\n\n";
14045
- if (component.name === "barrel") {
14116
+ output += result.installed.map((item) => `\u2713 Added: ${item}`).join("\n");
14117
+ output += "\n\n";
14118
+ if (name.toLowerCase() === "barrel") {
14046
14119
  output += "Add components first, then install the barrel for named imports from `@/components/bearnie`.\n\n";
14047
14120
  }
14048
- if (component.dependencies?.length) {
14121
+ if (result.npmDependencies.length > 0) {
14049
14122
  output += `## Required NPM Dependencies
14050
14123
 
14051
- `;
14052
- output += `Run the following command to install required packages:
14053
-
14054
14124
  `;
14055
14125
  output += `\`\`\`bash
14056
- npm install ${component.dependencies.join(" ")}
14126
+ npm install ${result.npmDependencies.join(" ")}
14057
14127
  \`\`\`
14058
14128
 
14059
14129
  `;
14060
14130
  }
14061
- output += `## Usage
14131
+ if (component) {
14132
+ output += `## Usage
14133
+
14134
+ `;
14135
+ output += getUsageExample(component);
14136
+ }
14137
+ return {
14138
+ content: [{ type: "text", text: output }]
14139
+ };
14140
+ }
14141
+ );
14142
+ server.tool(
14143
+ "add_components",
14144
+ "Add multiple Bearnie components to the current Astro project. Resolves registry dependencies and installs barrel last when included.",
14145
+ {
14146
+ names: external_exports.array(external_exports.string()).describe(
14147
+ "Component names to add (e.g., ['button', 'card', 'barrel'])"
14148
+ ),
14149
+ cwd: external_exports.string().optional().describe("The working directory (defaults to current directory)")
14150
+ },
14151
+ async ({ names, cwd }) => {
14152
+ const workingDir = cwd || process.cwd();
14153
+ const projectRoot = findProjectRoot(workingDir);
14154
+ if (!projectRoot) {
14155
+ return {
14156
+ content: [
14157
+ {
14158
+ type: "text",
14159
+ text: "Error: Could not find project root (no package.json found). Make sure you're in an Astro project."
14160
+ }
14161
+ ]
14162
+ };
14163
+ }
14164
+ const normalized = names.map((name) => name.toLowerCase());
14165
+ const result = await installComponents(projectRoot, normalized);
14166
+ let output = `# Added components
14167
+
14168
+ `;
14169
+ if (result.installed.length > 0) {
14170
+ output += result.installed.map((item) => `\u2713 Added: ${item}`).join("\n");
14171
+ output += "\n\n";
14172
+ }
14173
+ if (result.errors.length > 0) {
14174
+ output += `## Errors
14175
+
14176
+ ${result.errors.map((error48) => `- ${error48}`).join("\n")}
14062
14177
 
14063
14178
  `;
14064
- output += getUsageExample(component);
14179
+ }
14180
+ if (normalized.includes("barrel")) {
14181
+ output += "Barrel installed last for named imports from `@/components/bearnie`.\n\n";
14182
+ }
14183
+ if (result.npmDependencies.length > 0) {
14184
+ output += `## Required NPM Dependencies
14185
+
14186
+ `;
14187
+ output += `\`\`\`bash
14188
+ npm install ${result.npmDependencies.join(" ")}
14189
+ \`\`\`
14190
+
14191
+ `;
14192
+ }
14065
14193
  return {
14066
14194
  content: [{ type: "text", text: output }]
14067
14195
  };
@@ -0,0 +1,34 @@
1
+ export interface ComponentFile {
2
+ name: string;
3
+ path: string;
4
+ content: string;
5
+ }
6
+ export interface ComponentRegistry {
7
+ name: string;
8
+ type?: "utility" | "component" | "styles";
9
+ description: string;
10
+ category?: string;
11
+ files: ComponentFile[];
12
+ dependencies?: string[];
13
+ registryDependencies?: string[];
14
+ }
15
+ export interface InstallResult {
16
+ installed: string[];
17
+ npmDependencies: string[];
18
+ errors: string[];
19
+ }
20
+ export interface RegistryIndex {
21
+ components: Array<{
22
+ name: string;
23
+ description: string;
24
+ category: string;
25
+ }>;
26
+ }
27
+ export declare function fetchComponent(name: string): Promise<ComponentRegistry | null>;
28
+ export declare function fetchIndex(): Promise<RegistryIndex | null>;
29
+ export declare function resolveInstallPath(projectRoot: string, file: ComponentFile, registryItem: ComponentRegistry): string;
30
+ export declare function resolveComponentDependencies(names: string[], resolved?: Set<string>): Promise<string[]>;
31
+ export declare function installComponents(projectRoot: string, names: string[]): Promise<InstallResult>;
32
+ export declare function toPascalCase(name: string): string;
33
+ export declare function getUsageExample(component: ComponentRegistry): string;
34
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAiBnC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAiBhE;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,aAAa,EACnB,YAAY,EAAE,iBAAiB,GAC9B,MAAM,CAoBR;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBnB;AAmDD,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,aAAa,CAAC,CAuBxB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM,CA8BpE"}
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "@bearnie/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "MCP server for Bearnie UI components - enables AI assistants to add components to your project",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "bearnie-mcp": "dist/index.js"
9
9
  },
10
+ "types": "dist/index.d.ts",
10
11
  "files": [
11
12
  "dist"
12
13
  ],
13
14
  "scripts": {
14
- "build": "tsup src/index.ts --format esm --clean",
15
+ "build": "tsup src/index.ts --format esm --clean && tsc --emitDeclarationOnly",
15
16
  "dev": "tsup src/index.ts --format esm --watch",
16
17
  "typecheck": "tsc --noEmit"
17
18
  },