@bezel-labs/bezel-kit 0.7.1 → 0.8.0

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/cli.js CHANGED
@@ -2,24 +2,151 @@
2
2
  import {
3
3
  generateVariablesCss,
4
4
  initConfig,
5
+ mergeManagedBlock,
5
6
  readPackageScripts
6
- } from "./chunk-KCAFXZVO.js";
7
+ } from "./chunk-WHESGLCA.js";
7
8
  import {
8
9
  DEFAULT_CONFIG_FILE,
9
10
  DEFAULT_VARIABLES_OUTPUT
10
- } from "./chunk-Z7IFWPRA.js";
11
+ } from "./chunk-DXZXDPQ6.js";
12
+ import {
13
+ AGENT_SKILL
14
+ } from "./chunk-3XU5AUYB.js";
11
15
 
12
16
  // src/cli.ts
13
17
  import { existsSync } from "fs";
14
- import { readFile as readFile2 } from "fs/promises";
18
+ import { readFile as readFile3 } from "fs/promises";
15
19
  import { pathToFileURL } from "url";
16
20
  import { parseArgs } from "util";
17
- import { relative, resolve as resolve2 } from "path";
21
+ import { relative as relative2, resolve as resolve3 } from "path";
18
22
 
19
23
  // src/install-mcp.ts
20
24
  import { spawnSync } from "child_process";
25
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
26
+ import { dirname as dirname2, resolve as resolve2 } from "path";
27
+
28
+ // src/install-skills.ts
21
29
  import { mkdir, readFile, writeFile } from "fs/promises";
22
- import { dirname, resolve } from "path";
30
+ import { dirname, join, relative, resolve } from "path";
31
+ var SKILL_CLIENTS = ["claude-code", "codex", "cursor", "all"];
32
+ var AGENTS_MD_START = "<!-- bezel:start (generated by bezel install-skills \u2014 do not edit) -->";
33
+ var AGENTS_MD_END = "<!-- bezel:end -->";
34
+ var CLAUDE_SKILLS_DIR = ".claude/skills";
35
+ var AGENTS_SKILLS_DIR = ".agents/skills";
36
+ function skillDirectories(client) {
37
+ if (client === "claude-code") return [CLAUDE_SKILLS_DIR];
38
+ if (client === "codex" || client === "cursor") return [AGENTS_SKILLS_DIR];
39
+ return [CLAUDE_SKILLS_DIR, AGENTS_SKILLS_DIR];
40
+ }
41
+ function mergeAgentsMd(existing) {
42
+ return mergeManagedBlock(existing, AGENT_SKILL.agentsMdBlock.split("\n"), {
43
+ start: AGENTS_MD_START,
44
+ end: AGENTS_MD_END
45
+ });
46
+ }
47
+ async function readIfExists(path) {
48
+ try {
49
+ return await readFile(path, "utf8");
50
+ } catch (error) {
51
+ if (error.code === "ENOENT") return void 0;
52
+ throw error;
53
+ }
54
+ }
55
+ async function writeManaged(cwd, path, content, result) {
56
+ const rel = relative(cwd, path);
57
+ const existing = await readIfExists(path);
58
+ if (existing === content) {
59
+ result.unchanged.push(rel);
60
+ return;
61
+ }
62
+ await mkdir(dirname(path), { recursive: true });
63
+ if (existing !== void 0) {
64
+ try {
65
+ await writeFile(`${path}.bezel-backup`, existing, { flag: "wx", mode: 384 });
66
+ result.backedUp.push(rel);
67
+ } catch (error) {
68
+ if (error.code !== "EEXIST") throw error;
69
+ }
70
+ }
71
+ await writeFile(path, content, "utf8");
72
+ result.written.push(rel);
73
+ }
74
+ async function installSkills(options) {
75
+ const cwd = resolve(options.cwd ?? process.cwd());
76
+ const result = { written: [], unchanged: [], backedUp: [], hints: [] };
77
+ for (const dir of skillDirectories(options.client)) {
78
+ for (const [file, content] of Object.entries(AGENT_SKILL.files)) {
79
+ await writeManaged(cwd, join(cwd, dir, AGENT_SKILL.name, file), content, result);
80
+ }
81
+ }
82
+ if (options.agentsMd ?? true) {
83
+ const agentsPath = join(cwd, "AGENTS.md");
84
+ const existing = await readIfExists(agentsPath) ?? "";
85
+ const merged = mergeAgentsMd(existing);
86
+ if (merged === existing) {
87
+ result.unchanged.push("AGENTS.md");
88
+ } else {
89
+ await writeFile(agentsPath, merged, "utf8");
90
+ result.written.push("AGENTS.md");
91
+ }
92
+ const claudeMd = await readIfExists(join(cwd, "CLAUDE.md"));
93
+ if (claudeMd !== void 0 && !claudeMd.includes("@AGENTS.md")) {
94
+ result.hints.push(
95
+ "CLAUDE.md exists and does not include AGENTS.md. Add a line containing `@AGENTS.md` to CLAUDE.md so Claude Code loads the Bezel rules."
96
+ );
97
+ }
98
+ }
99
+ return result;
100
+ }
101
+ function skillClientForMcpClient(client) {
102
+ if (client === "claude-code" || client === "codex" || client === "cursor") return client;
103
+ return "all";
104
+ }
105
+ async function installSkillsCommand(clientName, options = {}) {
106
+ let choice = clientName;
107
+ if (!choice) {
108
+ if (!process.stdin.isTTY) {
109
+ throw new Error(`Choose a client with --client ${SKILL_CLIENTS.join("|")}.`);
110
+ }
111
+ const { default: select } = await import("@inquirer/select");
112
+ try {
113
+ choice = await select({
114
+ message: "Install the Bezel skill for:",
115
+ choices: [
116
+ { name: "Claude Code (.claude/skills)", value: "claude-code" },
117
+ { name: "Codex (.agents/skills)", value: "codex" },
118
+ { name: "Cursor (.agents/skills)", value: "cursor" },
119
+ { name: "All of the above", value: "all" }
120
+ ]
121
+ });
122
+ } catch (error) {
123
+ if (error instanceof Error && error.name === "ExitPromptError") {
124
+ console.log("Setup cancelled.");
125
+ return;
126
+ }
127
+ throw error;
128
+ }
129
+ }
130
+ if (!SKILL_CLIENTS.includes(choice))
131
+ throw new Error(`Unknown client: ${choice}. Choose ${SKILL_CLIENTS.join(", ")}.`);
132
+ const result = await installSkills({
133
+ cwd: options.cwd,
134
+ client: choice,
135
+ agentsMd: options.agentsMd
136
+ });
137
+ reportInstallSkills(result);
138
+ }
139
+ function reportInstallSkills(result) {
140
+ for (const file of result.written) console.log(`Bezel skill: wrote ${file}`);
141
+ for (const file of result.backedUp) console.log(`Bezel skill: backed up ${file}.bezel-backup`);
142
+ if (result.written.length === 0) console.log("Bezel skill: already up to date.");
143
+ for (const hint of result.hints) console.log(`Note: ${hint}`);
144
+ console.log(
145
+ "Next: open this repo in your assistant. The Bezel skill loads automatically when a task touches design tokens."
146
+ );
147
+ }
148
+
149
+ // src/install-mcp.ts
23
150
  var MCP_URL = "https://mcp.bezel.new/mcp";
24
151
  var CLIENTS = ["claude-code", "codex", "cursor", "vscode", "other"];
25
152
  function clientCommand(client) {
@@ -68,7 +195,7 @@ function mergeMcpConfig(raw, client) {
68
195
  return `${JSON.stringify({ ...config, [key]: { ...servers, bezel: entry } }, null, 2)}
69
196
  `;
70
197
  }
71
- async function installMcp(clientName) {
198
+ async function installMcp(clientName, options = {}) {
72
199
  let choice = clientName;
73
200
  if (!choice) {
74
201
  if (!process.stdin.isTTY) {
@@ -124,11 +251,11 @@ async function installMcp(clientName) {
124
251
  );
125
252
  }
126
253
  } else if (client === "cursor" || client === "vscode") {
127
- const path = resolve(client === "cursor" ? ".cursor/mcp.json" : ".vscode/mcp.json");
254
+ const path = resolve2(client === "cursor" ? ".cursor/mcp.json" : ".vscode/mcp.json");
128
255
  let raw = "{}";
129
256
  let exists = false;
130
257
  try {
131
- raw = await readFile(path, "utf8");
258
+ raw = await readFile2(path, "utf8");
132
259
  exists = true;
133
260
  } catch (error) {
134
261
  if (error.code !== "ENOENT") throw error;
@@ -142,9 +269,9 @@ async function installMcp(clientName) {
142
269
  );
143
270
  }
144
271
  if (merged !== raw) {
145
- await mkdir(dirname(path), { recursive: true });
146
- if (exists) await writeFile(`${path}.bezel-backup`, raw, { flag: "wx", mode: 384 });
147
- await writeFile(path, merged, { flag: exists ? "w" : "wx" });
272
+ await mkdir2(dirname2(path), { recursive: true });
273
+ if (exists) await writeFile2(`${path}.bezel-backup`, raw, { flag: "wx", mode: 384 });
274
+ await writeFile2(path, merged, { flag: exists ? "w" : "wx" });
148
275
  }
149
276
  console.log(`Bezel configured in ${path}`);
150
277
  } else {
@@ -159,18 +286,49 @@ Client instructions: https://docs.bezel.new/docs/mcp-server/setup`
159
286
  console.log(
160
287
  '\nThen open your current project in the assistant and ask:\n"Set up Bezel in this project."'
161
288
  );
289
+ if (await wantsSkills(options.skills)) {
290
+ console.log("");
291
+ reportInstallSkills(await installSkills({ client: skillClientForMcpClient(client) }));
292
+ }
293
+ }
294
+ async function wantsSkills(flag) {
295
+ if (flag !== void 0) return flag;
296
+ if (!process.stdin.isTTY) return false;
297
+ const { default: select } = await import("@inquirer/select");
298
+ try {
299
+ return await select({
300
+ message: "Also install the Bezel agent skill into this repo (SKILL.md + AGENTS.md rules)?",
301
+ choices: [
302
+ { name: "Yes (recommended)", value: true },
303
+ { name: "Not now (run `bezel install-skills` later)", value: false }
304
+ ]
305
+ });
306
+ } catch (error) {
307
+ if (error instanceof Error && error.name === "ExitPromptError") return false;
308
+ throw error;
309
+ }
162
310
  }
163
311
 
164
312
  // src/cli.ts
165
313
  var USAGE = `bezel \u2014 convert a W3C Design Tokens (DTCG) file into a scoped variables.css
166
314
 
167
315
  Usage:
168
- bezel install-mcp [--client <name>] Connect claude-code, codex, cursor, vscode, or other
316
+ bezel install-mcp [--client <name>] [--skills]
317
+ Connect claude-code, codex, cursor, vscode, or other
318
+ bezel install-skills [--client <name>] [--no-agents-md]
319
+ Teach claude-code, codex, cursor, or all about Bezel
169
320
  bezel init [options] Create a bezel.json for this project
170
321
  bezel build [options] Generate the outputs (default command)
171
322
 
172
323
  Reads design-tokens.json from the project root (the working directory).
173
324
 
325
+ install-mcp options:
326
+ --skills Also run install-skills for the same client (skips the question)
327
+
328
+ install-skills options:
329
+ --client <name> claude-code | codex | cursor | all (asked when omitted)
330
+ --no-agents-md Only write the skill folder; leave AGENTS.md alone
331
+
174
332
  init options:
175
333
  --dir <path> Directory for all outputs
176
334
  (default: src/bezel, or bezel with no src/)
@@ -207,9 +365,9 @@ TypeScript project unless you pass the paths explicitly.
207
365
  --project and --tokens-version update only their own key in an existing bezel.json; no --force needed.
208
366
  `;
209
367
  async function loadConfig(path) {
210
- const abs = resolve2(process.cwd(), path);
368
+ const abs = resolve3(process.cwd(), path);
211
369
  if (/\.json$/.test(abs)) {
212
- return JSON.parse(await readFile2(abs, "utf8"));
370
+ return JSON.parse(await readFile3(abs, "utf8"));
213
371
  }
214
372
  const mod = await import(pathToFileURL(abs).href);
215
373
  return mod.default ?? mod;
@@ -228,6 +386,8 @@ var OPTIONS = {
228
386
  "tokens-version": { type: "string" },
229
387
  stdout: { type: "boolean" },
230
388
  "no-gitignore": { type: "boolean" },
389
+ "no-agents-md": { type: "boolean" },
390
+ skills: { type: "boolean" },
231
391
  "no-contexts": { type: "boolean" },
232
392
  "no-fonts": { type: "boolean" },
233
393
  force: { type: "boolean", short: "f" },
@@ -251,7 +411,7 @@ async function runInit(values) {
251
411
  projectId: values.project,
252
412
  version: values["tokens-version"]
253
413
  });
254
- const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE;
414
+ const configName = relative2(cwd, result.configPath) || DEFAULT_CONFIG_FILE;
255
415
  if (result.updated) {
256
416
  if (values.project) {
257
417
  const changed = result.previousProjectId && result.previousProjectId !== values.project;
@@ -299,13 +459,16 @@ ${TOKENS_FILE_HINT}
299
459
  if (!scripts["tokens"]) {
300
460
  steps.push('Add "tokens": "bezel build" to your package.json scripts.');
301
461
  }
462
+ if (!skillDirectories("all").some((dir) => existsSync(resolve3(cwd, dir, "bezel")))) {
463
+ steps.push("Teach your AI coding agent about Bezel: npx bezel install-skills");
464
+ }
302
465
  steps.push(`Run the build, then import ${result.config.variablesOutput} in your entry file.`);
303
466
  process.stderr.write("\nNext:\n");
304
467
  steps.forEach((step, i) => process.stderr.write(` ${i + 1}. ${step}
305
468
  `));
306
469
  }
307
470
  async function runBuild(values) {
308
- const configPath = values.config ?? (existsSync(resolve2(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : void 0);
471
+ const configPath = values.config ?? (existsSync(resolve3(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : void 0);
309
472
  const fileConfig = configPath ? await loadConfig(configPath) : {};
310
473
  const options = { ...fileConfig };
311
474
  if (values["variables-output"]) options.variablesOutput = values["variables-output"];
@@ -336,7 +499,11 @@ async function main(argv) {
336
499
  }
337
500
  const command = positionals[0] ?? "build";
338
501
  if (command === "install-mcp") {
339
- await installMcp(values.client);
502
+ await installMcp(values.client, { skills: values.skills });
503
+ return;
504
+ }
505
+ if (command === "install-skills") {
506
+ await installSkillsCommand(values.client, { agentsMd: !values["no-agents-md"] });
340
507
  return;
341
508
  }
342
509
  if (command === "init") {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/install-mcp.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { existsSync } from \"node:fs\"\nimport { readFile } from \"node:fs/promises\"\nimport { pathToFileURL } from \"node:url\"\nimport { parseArgs } from \"node:util\"\nimport { relative, resolve } from \"node:path\"\nimport { generateVariablesCss } from \"./node\"\nimport { installMcp } from \"./install-mcp\"\nimport { initConfig, readPackageScripts } from \"./init\"\nimport type { BezelOptions } from \"./config\"\nimport { DEFAULT_CONFIG_FILE, DEFAULT_VARIABLES_OUTPUT } from \"./defaults\"\n\nconst USAGE = `bezel — convert a W3C Design Tokens (DTCG) file into a scoped variables.css\n\nUsage:\n bezel install-mcp [--client <name>] Connect claude-code, codex, cursor, vscode, or other\n bezel init [options] Create a bezel.json for this project\n bezel build [options] Generate the outputs (default command)\n\nReads design-tokens.json from the project root (the working directory).\n\ninit options:\n --dir <path> Directory for all outputs\n (default: src/bezel, or bezel with no src/)\n --variables-output <path> Override just the CSS path\n --contexts-output <path> Override just the contexts module path\n --fonts-output <path> Override just the fonts module path\n --no-contexts Skip the generated CONTEXTS module\n --no-fonts Skip the generated FONTS module\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\n --project <uuid> Link this repo to a Bezel project (writes projectId)\n --tokens-version <v> Tokens version the Bezel MCP fetches: latest | semver (default: latest)\n -f, --force Overwrite an existing bezel.json\n\nbuild options:\n -c, --config <path> Config file (.json or .js exporting BezelOptions)\n --variables-output <path> Output CSS file (default: ${DEFAULT_VARIABLES_OUTPUT})\n --contexts-output <path> Also write a generated TS module exporting CONTEXTS\n --fonts-output <path> Also write a generated TS module exporting FONTS\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\n --stdout Print CSS to stdout instead of writing the file\n --no-gitignore Don't create/update .gitignore for generated files\n\n -h, --help Show this help\n\nA ${DEFAULT_CONFIG_FILE} file in the working directory is loaded automatically when -c is omitted.\nThe contexts/fonts modules are TypeScript, so init only scaffolds them for a\nTypeScript project unless you pass the paths explicitly.\n--project and --tokens-version update only their own key in an existing bezel.json; no --force needed.\n`\n\n/** Load options from a `.json` or `.js`/`.mjs` config file. */\nasync function loadConfig(path: string): Promise<BezelOptions> {\n const abs = resolve(process.cwd(), path)\n if (/\\.json$/.test(abs)) {\n return JSON.parse(await readFile(abs, \"utf8\")) as BezelOptions\n }\n const mod = (await import(pathToFileURL(abs).href)) as {\n default?: BezelOptions\n } & BezelOptions\n return (mod.default ?? mod) as BezelOptions\n}\n\ntype Values = ReturnType<typeof parseArgs<{ options: typeof OPTIONS }>>[\"values\"]\n\nconst OPTIONS = {\n client: { type: \"string\" },\n config: { type: \"string\", short: \"c\" },\n dir: { type: \"string\" },\n \"variables-output\": { type: \"string\" },\n \"contexts-output\": { type: \"string\" },\n \"fonts-output\": { type: \"string\" },\n color: { type: \"string\" },\n unit: { type: \"string\" },\n \"include-all\": { type: \"boolean\" },\n project: { type: \"string\" },\n \"tokens-version\": { type: \"string\" },\n stdout: { type: \"boolean\" },\n \"no-gitignore\": { type: \"boolean\" },\n \"no-contexts\": { type: \"boolean\" },\n \"no-fonts\": { type: \"boolean\" },\n force: { type: \"boolean\", short: \"f\" },\n help: { type: \"boolean\", short: \"h\" },\n} as const\n\nconst TOKENS_FILE_HINT =\n \"Add design-tokens.json to the project root — ask your AI agent for it via the\\n Bezel MCP, or download it from your project.\"\n\n/** `bezel init` — scaffold a bezel.json, then print what to do next. */\nasync function runInit(values: Values): Promise<void> {\n const cwd = process.cwd()\n const result = await initConfig({\n cwd,\n outputDir: values.dir,\n variablesOutput: values[\"variables-output\"],\n contextsOutput: values[\"contexts-output\"],\n fontsOutput: values[\"fonts-output\"],\n contexts: values[\"no-contexts\"] ? false : undefined,\n fonts: values[\"no-fonts\"] ? false : undefined,\n colorFormat: values.color as BezelOptions[\"colorFormat\"],\n dimensionUnit: values.unit as BezelOptions[\"dimensionUnit\"],\n includeAll: values[\"include-all\"],\n force: values.force,\n projectId: values.project,\n version: values[\"tokens-version\"],\n })\n\n const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE\n\n if (result.updated) {\n if (values.project) {\n const changed = result.previousProjectId && result.previousProjectId !== values.project\n process.stderr.write(\n changed\n ? `bezel: updated projectId in ${configName} (was ${result.previousProjectId})\\n`\n : `bezel: set projectId in ${configName}\\n`,\n )\n }\n if (result.config.version !== result.previousVersion) {\n process.stderr.write(`bezel: set version to ${result.config.version} in ${configName}\\n`)\n }\n if (!result.hasTokensFile) {\n process.stderr.write(`\\n${TOKENS_FILE_HINT}\\n`)\n }\n return\n }\n\n if (!result.written) {\n process.stderr.write(\n `bezel: ${configName} already exists — leaving it alone. Re-run with --force to overwrite, or pass --project <uuid> / --tokens-version <v> to just update the project link.\\n`,\n )\n process.exitCode = 1\n return\n }\n\n const outputs = [\n result.config.variablesOutput,\n result.config.contextsOutput,\n result.config.fontsOutput,\n ].filter((p): p is string => p !== undefined)\n\n process.stderr.write(`bezel: wrote ${configName}\\n`)\n for (const output of outputs) {\n process.stderr.write(`bezel: ${output}\\n`)\n }\n\n const scripts = await readPackageScripts(cwd)\n const steps: string[] = []\n\n if (!result.hasTokensFile) {\n steps.push(TOKENS_FILE_HINT)\n }\n if (!scripts[\"tokens\"]) {\n steps.push('Add \"tokens\": \"bezel build\" to your package.json scripts.')\n }\n steps.push(`Run the build, then import ${result.config.variablesOutput} in your entry file.`)\n\n process.stderr.write(\"\\nNext:\\n\")\n steps.forEach((step, i) => process.stderr.write(` ${i + 1}. ${step}\\n`))\n}\n\n/** `bezel build` — generate the outputs. */\nasync function runBuild(values: Values): Promise<void> {\n const configPath =\n values.config ??\n (existsSync(resolve(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : undefined)\n const fileConfig = configPath ? await loadConfig(configPath) : {}\n\n const options: BezelOptions = { ...fileConfig }\n if (values[\"variables-output\"]) options.variablesOutput = values[\"variables-output\"]\n if (values[\"contexts-output\"]) options.contextsOutput = values[\"contexts-output\"]\n if (values[\"fonts-output\"]) options.fontsOutput = values[\"fonts-output\"]\n if (values.color) options.colorFormat = values.color as BezelOptions[\"colorFormat\"]\n if (values.unit) options.dimensionUnit = values.unit as BezelOptions[\"dimensionUnit\"]\n if (values[\"include-all\"]) options.includeAll = true\n if (values.stdout) options.write = false\n if (values[\"no-gitignore\"]) options.gitignore = false\n\n const css = await generateVariablesCss(options)\n\n if (values.stdout) {\n process.stdout.write(css)\n } else {\n process.stderr.write(`bezel: wrote ${options.variablesOutput ?? DEFAULT_VARIABLES_OUTPUT}\\n`)\n }\n}\n\nasync function main(argv: string[]): Promise<void> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: OPTIONS,\n })\n\n if (values.help || positionals[0] === \"help\") {\n process.stdout.write(USAGE)\n return\n }\n\n const command = positionals[0] ?? \"build\"\n\n if (command === \"install-mcp\") {\n await installMcp(values.client)\n return\n }\n\n if (command === \"init\") {\n await runInit(values)\n return\n }\n\n if (command !== \"build\") {\n process.stderr.write(`bezel: unknown command \"${command}\".\\n\\n${USAGE}`)\n process.exitCode = 1\n return\n }\n\n await runBuild(values)\n}\n\nmain(process.argv.slice(2)).catch((err: unknown) => {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`)\n process.exitCode = 1\n})\n","import { spawnSync } from \"node:child_process\"\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { dirname, resolve } from \"node:path\"\n\nexport const MCP_URL = \"https://mcp.bezel.new/mcp\"\nexport const CLIENTS = [\"claude-code\", \"codex\", \"cursor\", \"vscode\", \"other\"] as const\nexport type McpClient = (typeof CLIENTS)[number]\n\nexport function clientCommand(client: McpClient): { command: string; args: string[] } | undefined {\n if (client === \"claude-code\") {\n return {\n command: \"claude\",\n args: [\"mcp\", \"add\", \"--transport\", \"http\", \"--scope\", \"project\", \"bezel\", MCP_URL],\n }\n }\n if (client === \"codex\") {\n return { command: \"codex\", args: [\"mcp\", \"add\", \"bezel\", \"--url\", MCP_URL] }\n }\n return undefined\n}\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nexport function codexAlreadyConfigured(raw: string): boolean {\n const servers: unknown = JSON.parse(raw)\n if (\n !Array.isArray(servers) ||\n !servers.every((server) => object(server) && typeof server[\"name\"] === \"string\")\n ) {\n throw new Error(\"Could not inspect Codex MCP configuration; no changes made.\")\n }\n const existing = servers.find((server) => server[\"name\"] === \"bezel\")\n if (!existing) return false\n if (\n !object(existing[\"transport\"]) ||\n existing[\"transport\"][\"url\"] !== MCP_URL ||\n existing[\"enabled\"] === false\n ) {\n throw new Error(\n \"An existing or disabled Bezel entry needs attention in Codex; no changes made.\",\n )\n }\n return true\n}\n\n/** Preserve unrelated settings; reject conflicting or malformed configuration. */\nexport function mergeMcpConfig(raw: string, client: \"cursor\" | \"vscode\"): string {\n const config: unknown = JSON.parse(raw)\n if (!object(config)) throw new Error(\"MCP config must be a JSON object; no changes made.\")\n const key = client === \"cursor\" ? \"mcpServers\" : \"servers\"\n const servers = config[key] ?? {}\n if (!object(servers)) throw new Error(`${key} must be a JSON object; no changes made.`)\n const entry = client === \"cursor\" ? { url: MCP_URL } : { type: \"http\", url: MCP_URL }\n if (servers[\"bezel\"] !== undefined) {\n const existing = servers[\"bezel\"]\n if (\n !object(existing) ||\n existing[\"url\"] !== MCP_URL ||\n (existing[\"type\"] !== undefined && existing[\"type\"] !== \"http\") ||\n existing[\"command\"] !== undefined\n ) {\n throw new Error(\"A different bezel server is already configured; no changes made.\")\n }\n return raw\n }\n return `${JSON.stringify({ ...config, [key]: { ...servers, bezel: entry } }, null, 2)}\\n`\n}\n\nexport async function installMcp(clientName?: string): Promise<void> {\n let choice = clientName\n if (!choice) {\n if (!process.stdin.isTTY) {\n throw new Error(`Choose a client with --client ${CLIENTS.join(\"|\")}.`)\n }\n const { default: select } = await import(\"@inquirer/select\")\n try {\n choice = await select<McpClient>({\n message: \"Connect Bezel to your coding tool:\",\n choices: [\n { name: \"Claude Code (this project)\", value: \"claude-code\" },\n { name: \"Codex (your user configuration)\", value: \"codex\" },\n { name: \"Cursor (this project)\", value: \"cursor\" },\n { name: \"VS Code (this project)\", value: \"vscode\" },\n { name: \"Other / hosted tool\", value: \"other\" },\n ],\n })\n } catch (error) {\n if (error instanceof Error && error.name === \"ExitPromptError\") {\n console.log(\"Setup cancelled.\")\n return\n }\n throw error\n }\n }\n if (!CLIENTS.includes(choice as McpClient))\n throw new Error(`Unknown client: ${choice}. Choose ${CLIENTS.join(\", \")}.`)\n const client = choice as McpClient\n const invocation = clientCommand(client)\n if (invocation) {\n console.log(\n client === \"codex\"\n ? \"Adding Bezel to Codex user configuration.\"\n : \"Adding Bezel to this project's Claude Code configuration.\",\n )\n let alreadyConfigured = false\n if (client === \"codex\") {\n const current = spawnSync(\"codex\", [\"mcp\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n shell: false,\n })\n if (current.error || current.status !== 0)\n throw new Error(\n \"Could not inspect Codex MCP configuration. Ensure the Codex CLI is installed; no changes made.\",\n )\n alreadyConfigured = codexAlreadyConfigured(current.stdout)\n }\n const result = alreadyConfigured\n ? { status: 0, error: undefined }\n : spawnSync(invocation.command, invocation.args, {\n stdio: \"inherit\",\n shell: false,\n })\n if (result.error || result.status !== 0) {\n throw new Error(\n `Could not configure ${client}. Ensure its CLI is installed and review any existing bezel entry. No existing server was removed. Manual setup: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n } else if (client === \"cursor\" || client === \"vscode\") {\n const path = resolve(client === \"cursor\" ? \".cursor/mcp.json\" : \".vscode/mcp.json\")\n let raw = \"{}\"\n let exists = false\n try {\n raw = await readFile(path, \"utf8\")\n exists = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n // JSONC is deliberately not rewritten: preserve comments by requesting manual setup.\n let merged: string\n try {\n merged = mergeMcpConfig(raw, client)\n } catch (error) {\n throw new Error(\n `${path}: ${error instanceof Error ? error.message : String(error)} For JSON with comments, add Bezel manually: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n if (merged !== raw) {\n await mkdir(dirname(path), { recursive: true })\n if (exists) await writeFile(`${path}.bezel-backup`, raw, { flag: \"wx\", mode: 0o600 })\n await writeFile(path, merged, { flag: exists ? \"w\" : \"wx\" })\n }\n console.log(`Bezel configured in ${path}`)\n } else {\n console.log(\n `In your tool's MCP/connector settings, add Bezel with URL ${MCP_URL}, Streamable HTTP transport, and OAuth authentication.\\nClient instructions: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n console.log(\n client === \"codex\"\n ? \"Next: run `codex mcp login bezel` and complete browser sign-in.\"\n : client === \"claude-code\"\n ? \"Next: open Claude Code, run /mcp, select bezel, and sign in.\"\n : \"Next: open or reload your coding tool and sign in to Bezel when prompted.\",\n )\n console.log(\n '\\nThen open your current project in the assistant and ask:\\n\"Set up Bezel in this project.\"',\n )\n}\n"],"mappings":"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","names":["readFile","resolve","resolve","readFile"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/install-mcp.ts","../src/install-skills.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { existsSync } from \"node:fs\"\nimport { readFile } from \"node:fs/promises\"\nimport { pathToFileURL } from \"node:url\"\nimport { parseArgs } from \"node:util\"\nimport { relative, resolve } from \"node:path\"\nimport { generateVariablesCss } from \"./node\"\nimport { installMcp } from \"./install-mcp\"\nimport { installSkillsCommand, skillDirectories } from \"./install-skills\"\nimport { initConfig, readPackageScripts } from \"./init\"\nimport type { BezelOptions } from \"./config\"\nimport { DEFAULT_CONFIG_FILE, DEFAULT_VARIABLES_OUTPUT } from \"./defaults\"\n\nconst USAGE = `bezel — convert a W3C Design Tokens (DTCG) file into a scoped variables.css\n\nUsage:\n bezel install-mcp [--client <name>] [--skills]\n Connect claude-code, codex, cursor, vscode, or other\n bezel install-skills [--client <name>] [--no-agents-md]\n Teach claude-code, codex, cursor, or all about Bezel\n bezel init [options] Create a bezel.json for this project\n bezel build [options] Generate the outputs (default command)\n\nReads design-tokens.json from the project root (the working directory).\n\ninstall-mcp options:\n --skills Also run install-skills for the same client (skips the question)\n\ninstall-skills options:\n --client <name> claude-code | codex | cursor | all (asked when omitted)\n --no-agents-md Only write the skill folder; leave AGENTS.md alone\n\ninit options:\n --dir <path> Directory for all outputs\n (default: src/bezel, or bezel with no src/)\n --variables-output <path> Override just the CSS path\n --contexts-output <path> Override just the contexts module path\n --fonts-output <path> Override just the fonts module path\n --no-contexts Skip the generated CONTEXTS module\n --no-fonts Skip the generated FONTS module\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\n --project <uuid> Link this repo to a Bezel project (writes projectId)\n --tokens-version <v> Tokens version the Bezel MCP fetches: latest | semver (default: latest)\n -f, --force Overwrite an existing bezel.json\n\nbuild options:\n -c, --config <path> Config file (.json or .js exporting BezelOptions)\n --variables-output <path> Output CSS file (default: ${DEFAULT_VARIABLES_OUTPUT})\n --contexts-output <path> Also write a generated TS module exporting CONTEXTS\n --fonts-output <path> Also write a generated TS module exporting FONTS\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\n --stdout Print CSS to stdout instead of writing the file\n --no-gitignore Don't create/update .gitignore for generated files\n\n -h, --help Show this help\n\nA ${DEFAULT_CONFIG_FILE} file in the working directory is loaded automatically when -c is omitted.\nThe contexts/fonts modules are TypeScript, so init only scaffolds them for a\nTypeScript project unless you pass the paths explicitly.\n--project and --tokens-version update only their own key in an existing bezel.json; no --force needed.\n`\n\n/** Load options from a `.json` or `.js`/`.mjs` config file. */\nasync function loadConfig(path: string): Promise<BezelOptions> {\n const abs = resolve(process.cwd(), path)\n if (/\\.json$/.test(abs)) {\n return JSON.parse(await readFile(abs, \"utf8\")) as BezelOptions\n }\n const mod = (await import(pathToFileURL(abs).href)) as {\n default?: BezelOptions\n } & BezelOptions\n return (mod.default ?? mod) as BezelOptions\n}\n\ntype Values = ReturnType<typeof parseArgs<{ options: typeof OPTIONS }>>[\"values\"]\n\nconst OPTIONS = {\n client: { type: \"string\" },\n config: { type: \"string\", short: \"c\" },\n dir: { type: \"string\" },\n \"variables-output\": { type: \"string\" },\n \"contexts-output\": { type: \"string\" },\n \"fonts-output\": { type: \"string\" },\n color: { type: \"string\" },\n unit: { type: \"string\" },\n \"include-all\": { type: \"boolean\" },\n project: { type: \"string\" },\n \"tokens-version\": { type: \"string\" },\n stdout: { type: \"boolean\" },\n \"no-gitignore\": { type: \"boolean\" },\n \"no-agents-md\": { type: \"boolean\" },\n skills: { type: \"boolean\" },\n \"no-contexts\": { type: \"boolean\" },\n \"no-fonts\": { type: \"boolean\" },\n force: { type: \"boolean\", short: \"f\" },\n help: { type: \"boolean\", short: \"h\" },\n} as const\n\nconst TOKENS_FILE_HINT =\n \"Add design-tokens.json to the project root — ask your AI agent for it via the\\n Bezel MCP, or download it from your project.\"\n\n/** `bezel init` — scaffold a bezel.json, then print what to do next. */\nasync function runInit(values: Values): Promise<void> {\n const cwd = process.cwd()\n const result = await initConfig({\n cwd,\n outputDir: values.dir,\n variablesOutput: values[\"variables-output\"],\n contextsOutput: values[\"contexts-output\"],\n fontsOutput: values[\"fonts-output\"],\n contexts: values[\"no-contexts\"] ? false : undefined,\n fonts: values[\"no-fonts\"] ? false : undefined,\n colorFormat: values.color as BezelOptions[\"colorFormat\"],\n dimensionUnit: values.unit as BezelOptions[\"dimensionUnit\"],\n includeAll: values[\"include-all\"],\n force: values.force,\n projectId: values.project,\n version: values[\"tokens-version\"],\n })\n\n const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE\n\n if (result.updated) {\n if (values.project) {\n const changed = result.previousProjectId && result.previousProjectId !== values.project\n process.stderr.write(\n changed\n ? `bezel: updated projectId in ${configName} (was ${result.previousProjectId})\\n`\n : `bezel: set projectId in ${configName}\\n`,\n )\n }\n if (result.config.version !== result.previousVersion) {\n process.stderr.write(`bezel: set version to ${result.config.version} in ${configName}\\n`)\n }\n if (!result.hasTokensFile) {\n process.stderr.write(`\\n${TOKENS_FILE_HINT}\\n`)\n }\n return\n }\n\n if (!result.written) {\n process.stderr.write(\n `bezel: ${configName} already exists — leaving it alone. Re-run with --force to overwrite, or pass --project <uuid> / --tokens-version <v> to just update the project link.\\n`,\n )\n process.exitCode = 1\n return\n }\n\n const outputs = [\n result.config.variablesOutput,\n result.config.contextsOutput,\n result.config.fontsOutput,\n ].filter((p): p is string => p !== undefined)\n\n process.stderr.write(`bezel: wrote ${configName}\\n`)\n for (const output of outputs) {\n process.stderr.write(`bezel: ${output}\\n`)\n }\n\n const scripts = await readPackageScripts(cwd)\n const steps: string[] = []\n\n if (!result.hasTokensFile) {\n steps.push(TOKENS_FILE_HINT)\n }\n if (!scripts[\"tokens\"]) {\n steps.push('Add \"tokens\": \"bezel build\" to your package.json scripts.')\n }\n if (!skillDirectories(\"all\").some((dir) => existsSync(resolve(cwd, dir, \"bezel\")))) {\n steps.push(\"Teach your AI coding agent about Bezel: npx bezel install-skills\")\n }\n steps.push(`Run the build, then import ${result.config.variablesOutput} in your entry file.`)\n\n process.stderr.write(\"\\nNext:\\n\")\n steps.forEach((step, i) => process.stderr.write(` ${i + 1}. ${step}\\n`))\n}\n\n/** `bezel build` — generate the outputs. */\nasync function runBuild(values: Values): Promise<void> {\n const configPath =\n values.config ??\n (existsSync(resolve(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : undefined)\n const fileConfig = configPath ? await loadConfig(configPath) : {}\n\n const options: BezelOptions = { ...fileConfig }\n if (values[\"variables-output\"]) options.variablesOutput = values[\"variables-output\"]\n if (values[\"contexts-output\"]) options.contextsOutput = values[\"contexts-output\"]\n if (values[\"fonts-output\"]) options.fontsOutput = values[\"fonts-output\"]\n if (values.color) options.colorFormat = values.color as BezelOptions[\"colorFormat\"]\n if (values.unit) options.dimensionUnit = values.unit as BezelOptions[\"dimensionUnit\"]\n if (values[\"include-all\"]) options.includeAll = true\n if (values.stdout) options.write = false\n if (values[\"no-gitignore\"]) options.gitignore = false\n\n const css = await generateVariablesCss(options)\n\n if (values.stdout) {\n process.stdout.write(css)\n } else {\n process.stderr.write(`bezel: wrote ${options.variablesOutput ?? DEFAULT_VARIABLES_OUTPUT}\\n`)\n }\n}\n\nasync function main(argv: string[]): Promise<void> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: OPTIONS,\n })\n\n if (values.help || positionals[0] === \"help\") {\n process.stdout.write(USAGE)\n return\n }\n\n const command = positionals[0] ?? \"build\"\n\n if (command === \"install-mcp\") {\n await installMcp(values.client, { skills: values.skills })\n return\n }\n\n if (command === \"install-skills\") {\n await installSkillsCommand(values.client, { agentsMd: !values[\"no-agents-md\"] })\n return\n }\n\n if (command === \"init\") {\n await runInit(values)\n return\n }\n\n if (command !== \"build\") {\n process.stderr.write(`bezel: unknown command \"${command}\".\\n\\n${USAGE}`)\n process.exitCode = 1\n return\n }\n\n await runBuild(values)\n}\n\nmain(process.argv.slice(2)).catch((err: unknown) => {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`)\n process.exitCode = 1\n})\n","import { spawnSync } from \"node:child_process\"\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { dirname, resolve } from \"node:path\"\nimport { installSkills, reportInstallSkills, skillClientForMcpClient } from \"./install-skills\"\n\nexport const MCP_URL = \"https://mcp.bezel.new/mcp\"\nexport const CLIENTS = [\"claude-code\", \"codex\", \"cursor\", \"vscode\", \"other\"] as const\nexport type McpClient = (typeof CLIENTS)[number]\n\nexport function clientCommand(client: McpClient): { command: string; args: string[] } | undefined {\n if (client === \"claude-code\") {\n return {\n command: \"claude\",\n args: [\"mcp\", \"add\", \"--transport\", \"http\", \"--scope\", \"project\", \"bezel\", MCP_URL],\n }\n }\n if (client === \"codex\") {\n return { command: \"codex\", args: [\"mcp\", \"add\", \"bezel\", \"--url\", MCP_URL] }\n }\n return undefined\n}\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nexport function codexAlreadyConfigured(raw: string): boolean {\n const servers: unknown = JSON.parse(raw)\n if (\n !Array.isArray(servers) ||\n !servers.every((server) => object(server) && typeof server[\"name\"] === \"string\")\n ) {\n throw new Error(\"Could not inspect Codex MCP configuration; no changes made.\")\n }\n const existing = servers.find((server) => server[\"name\"] === \"bezel\")\n if (!existing) return false\n if (\n !object(existing[\"transport\"]) ||\n existing[\"transport\"][\"url\"] !== MCP_URL ||\n existing[\"enabled\"] === false\n ) {\n throw new Error(\n \"An existing or disabled Bezel entry needs attention in Codex; no changes made.\",\n )\n }\n return true\n}\n\n/** Preserve unrelated settings; reject conflicting or malformed configuration. */\nexport function mergeMcpConfig(raw: string, client: \"cursor\" | \"vscode\"): string {\n const config: unknown = JSON.parse(raw)\n if (!object(config)) throw new Error(\"MCP config must be a JSON object; no changes made.\")\n const key = client === \"cursor\" ? \"mcpServers\" : \"servers\"\n const servers = config[key] ?? {}\n if (!object(servers)) throw new Error(`${key} must be a JSON object; no changes made.`)\n const entry = client === \"cursor\" ? { url: MCP_URL } : { type: \"http\", url: MCP_URL }\n if (servers[\"bezel\"] !== undefined) {\n const existing = servers[\"bezel\"]\n if (\n !object(existing) ||\n existing[\"url\"] !== MCP_URL ||\n (existing[\"type\"] !== undefined && existing[\"type\"] !== \"http\") ||\n existing[\"command\"] !== undefined\n ) {\n throw new Error(\"A different bezel server is already configured; no changes made.\")\n }\n return raw\n }\n return `${JSON.stringify({ ...config, [key]: { ...servers, bezel: entry } }, null, 2)}\\n`\n}\n\nexport interface InstallMcpOptions {\n /**\n * Also install the Bezel agent skill for the same client. `true` installs without\n * asking, `false` skips, and `undefined` asks when stdin is a TTY.\n */\n skills?: boolean\n}\n\nexport async function installMcp(\n clientName?: string,\n options: InstallMcpOptions = {},\n): Promise<void> {\n let choice = clientName\n if (!choice) {\n if (!process.stdin.isTTY) {\n throw new Error(`Choose a client with --client ${CLIENTS.join(\"|\")}.`)\n }\n const { default: select } = await import(\"@inquirer/select\")\n try {\n choice = await select<McpClient>({\n message: \"Connect Bezel to your coding tool:\",\n choices: [\n { name: \"Claude Code (this project)\", value: \"claude-code\" },\n { name: \"Codex (your user configuration)\", value: \"codex\" },\n { name: \"Cursor (this project)\", value: \"cursor\" },\n { name: \"VS Code (this project)\", value: \"vscode\" },\n { name: \"Other / hosted tool\", value: \"other\" },\n ],\n })\n } catch (error) {\n if (error instanceof Error && error.name === \"ExitPromptError\") {\n console.log(\"Setup cancelled.\")\n return\n }\n throw error\n }\n }\n if (!CLIENTS.includes(choice as McpClient))\n throw new Error(`Unknown client: ${choice}. Choose ${CLIENTS.join(\", \")}.`)\n const client = choice as McpClient\n const invocation = clientCommand(client)\n if (invocation) {\n console.log(\n client === \"codex\"\n ? \"Adding Bezel to Codex user configuration.\"\n : \"Adding Bezel to this project's Claude Code configuration.\",\n )\n let alreadyConfigured = false\n if (client === \"codex\") {\n const current = spawnSync(\"codex\", [\"mcp\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n shell: false,\n })\n if (current.error || current.status !== 0)\n throw new Error(\n \"Could not inspect Codex MCP configuration. Ensure the Codex CLI is installed; no changes made.\",\n )\n alreadyConfigured = codexAlreadyConfigured(current.stdout)\n }\n const result = alreadyConfigured\n ? { status: 0, error: undefined }\n : spawnSync(invocation.command, invocation.args, {\n stdio: \"inherit\",\n shell: false,\n })\n if (result.error || result.status !== 0) {\n throw new Error(\n `Could not configure ${client}. Ensure its CLI is installed and review any existing bezel entry. No existing server was removed. Manual setup: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n } else if (client === \"cursor\" || client === \"vscode\") {\n const path = resolve(client === \"cursor\" ? \".cursor/mcp.json\" : \".vscode/mcp.json\")\n let raw = \"{}\"\n let exists = false\n try {\n raw = await readFile(path, \"utf8\")\n exists = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n // JSONC is deliberately not rewritten: preserve comments by requesting manual setup.\n let merged: string\n try {\n merged = mergeMcpConfig(raw, client)\n } catch (error) {\n throw new Error(\n `${path}: ${error instanceof Error ? error.message : String(error)} For JSON with comments, add Bezel manually: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n if (merged !== raw) {\n await mkdir(dirname(path), { recursive: true })\n if (exists) await writeFile(`${path}.bezel-backup`, raw, { flag: \"wx\", mode: 0o600 })\n await writeFile(path, merged, { flag: exists ? \"w\" : \"wx\" })\n }\n console.log(`Bezel configured in ${path}`)\n } else {\n console.log(\n `In your tool's MCP/connector settings, add Bezel with URL ${MCP_URL}, Streamable HTTP transport, and OAuth authentication.\\nClient instructions: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n console.log(\n client === \"codex\"\n ? \"Next: run `codex mcp login bezel` and complete browser sign-in.\"\n : client === \"claude-code\"\n ? \"Next: open Claude Code, run /mcp, select bezel, and sign in.\"\n : \"Next: open or reload your coding tool and sign in to Bezel when prompted.\",\n )\n console.log(\n '\\nThen open your current project in the assistant and ask:\\n\"Set up Bezel in this project.\"',\n )\n\n if (await wantsSkills(options.skills)) {\n console.log(\"\")\n reportInstallSkills(await installSkills({ client: skillClientForMcpClient(client) }))\n }\n}\n\nasync function wantsSkills(flag: boolean | undefined): Promise<boolean> {\n if (flag !== undefined) return flag\n if (!process.stdin.isTTY) return false\n const { default: select } = await import(\"@inquirer/select\")\n try {\n return await select<boolean>({\n message: \"Also install the Bezel agent skill into this repo (SKILL.md + AGENTS.md rules)?\",\n choices: [\n { name: \"Yes (recommended)\", value: true },\n { name: \"Not now (run `bezel install-skills` later)\", value: false },\n ],\n })\n } catch (error) {\n if (error instanceof Error && error.name === \"ExitPromptError\") return false\n throw error\n }\n}\n","/**\n * bezel — `install-skills`: write the Bezel agent skill into a repository.\n *\n * Coding agents (Claude Code, Codex, Cursor) load a `SKILL.md` whose description\n * matches the task at hand, and read `AGENTS.md` on every session. This installs\n * both: the skill folder under `.claude/skills/bezel/` and/or `.agents/skills/bezel/`,\n * and a marked block in `AGENTS.md` with the short rules. Files are only rewritten\n * when their content differs, existing files are backed up once before the first\n * overwrite, and nothing is ever deleted.\n */\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { dirname, join, relative, resolve } from \"node:path\"\nimport { AGENT_SKILL } from \"./agent-skill\"\nimport { mergeManagedBlock } from \"./managed-block\"\n\nexport const SKILL_CLIENTS = [\"claude-code\", \"codex\", \"cursor\", \"all\"] as const\nexport type SkillClient = (typeof SKILL_CLIENTS)[number]\n\n/** Opening marker for the Bezel-managed block in `AGENTS.md`. */\nexport const AGENTS_MD_START = \"<!-- bezel:start (generated by bezel install-skills — do not edit) -->\"\n/** Closing marker for the Bezel-managed block in `AGENTS.md`. */\nexport const AGENTS_MD_END = \"<!-- bezel:end -->\"\n\nconst CLAUDE_SKILLS_DIR = \".claude/skills\"\nconst AGENTS_SKILLS_DIR = \".agents/skills\"\n\nexport interface InstallSkillsOptions {\n /** Repository root the files are written under. Default: `process.cwd()`. */\n cwd?: string\n /** Which agent's skill folder(s) to write. */\n client: SkillClient\n /** Also maintain the managed block in `AGENTS.md`. Default: `true`. */\n agentsMd?: boolean\n}\n\nexport interface InstallSkillsResult {\n /** Files created or updated, relative to `cwd`. */\n written: string[]\n /** Files that already had the right content, relative to `cwd`. */\n unchanged: string[]\n /** Files backed up to `<path>.bezel-backup` before being overwritten, relative to `cwd`. */\n backedUp: string[]\n /** Follow-up notes for the user (for example a `CLAUDE.md` that does not include `AGENTS.md`). */\n hints: string[]\n}\n\n/** Skill folders a client reads, relative to the repo root. */\nexport function skillDirectories(client: SkillClient): string[] {\n if (client === \"claude-code\") return [CLAUDE_SKILLS_DIR]\n if (client === \"codex\" || client === \"cursor\") return [AGENTS_SKILLS_DIR]\n return [CLAUDE_SKILLS_DIR, AGENTS_SKILLS_DIR]\n}\n\n/** Merge the Bezel block into existing `AGENTS.md` contents. */\nexport function mergeAgentsMd(existing: string): string {\n return mergeManagedBlock(existing, AGENT_SKILL.agentsMdBlock.split(\"\\n\"), {\n start: AGENTS_MD_START,\n end: AGENTS_MD_END,\n })\n}\n\nasync function readIfExists(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined\n throw error\n }\n}\n\n/**\n * Write `content` to `path` only when it differs from what is there. An existing file\n * is copied to `<path>.bezel-backup` the first time it is overwritten (the backup is\n * never replaced, so the user's original survives repeated runs).\n */\nasync function writeManaged(\n cwd: string,\n path: string,\n content: string,\n result: InstallSkillsResult,\n): Promise<void> {\n const rel = relative(cwd, path)\n const existing = await readIfExists(path)\n if (existing === content) {\n result.unchanged.push(rel)\n return\n }\n await mkdir(dirname(path), { recursive: true })\n if (existing !== undefined) {\n try {\n await writeFile(`${path}.bezel-backup`, existing, { flag: \"wx\", mode: 0o600 })\n result.backedUp.push(rel)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error\n }\n }\n await writeFile(path, content, \"utf8\")\n result.written.push(rel)\n}\n\n/** Install the Bezel skill (and the `AGENTS.md` block) into a repository. */\nexport async function installSkills(options: InstallSkillsOptions): Promise<InstallSkillsResult> {\n const cwd = resolve(options.cwd ?? process.cwd())\n const result: InstallSkillsResult = { written: [], unchanged: [], backedUp: [], hints: [] }\n\n for (const dir of skillDirectories(options.client)) {\n for (const [file, content] of Object.entries(AGENT_SKILL.files)) {\n await writeManaged(cwd, join(cwd, dir, AGENT_SKILL.name, file), content, result)\n }\n }\n\n if (options.agentsMd ?? true) {\n const agentsPath = join(cwd, \"AGENTS.md\")\n const existing = (await readIfExists(agentsPath)) ?? \"\"\n const merged = mergeAgentsMd(existing)\n if (merged === existing) {\n result.unchanged.push(\"AGENTS.md\")\n } else {\n await writeFile(agentsPath, merged, \"utf8\")\n result.written.push(\"AGENTS.md\")\n }\n\n const claudeMd = await readIfExists(join(cwd, \"CLAUDE.md\"))\n if (claudeMd !== undefined && !claudeMd.includes(\"@AGENTS.md\")) {\n result.hints.push(\n \"CLAUDE.md exists and does not include AGENTS.md. Add a line containing `@AGENTS.md` to CLAUDE.md so Claude Code loads the Bezel rules.\",\n )\n }\n }\n\n return result\n}\n\n/** Map an `install-mcp` client to the skill folders it reads. */\nexport function skillClientForMcpClient(client: string): SkillClient {\n if (client === \"claude-code\" || client === \"codex\" || client === \"cursor\") return client\n return \"all\"\n}\n\n/**\n * The `bezel install-skills` command: pick a client (flag or interactive menu),\n * install, and report what changed.\n */\nexport async function installSkillsCommand(\n clientName: string | undefined,\n options: { agentsMd?: boolean; cwd?: string } = {},\n): Promise<void> {\n let choice = clientName\n if (!choice) {\n if (!process.stdin.isTTY) {\n throw new Error(`Choose a client with --client ${SKILL_CLIENTS.join(\"|\")}.`)\n }\n const { default: select } = await import(\"@inquirer/select\")\n try {\n choice = await select<SkillClient>({\n message: \"Install the Bezel skill for:\",\n choices: [\n { name: \"Claude Code (.claude/skills)\", value: \"claude-code\" },\n { name: \"Codex (.agents/skills)\", value: \"codex\" },\n { name: \"Cursor (.agents/skills)\", value: \"cursor\" },\n { name: \"All of the above\", value: \"all\" },\n ],\n })\n } catch (error) {\n if (error instanceof Error && error.name === \"ExitPromptError\") {\n console.log(\"Setup cancelled.\")\n return\n }\n throw error\n }\n }\n if (!SKILL_CLIENTS.includes(choice as SkillClient))\n throw new Error(`Unknown client: ${choice}. Choose ${SKILL_CLIENTS.join(\", \")}.`)\n\n const result = await installSkills({\n cwd: options.cwd,\n client: choice as SkillClient,\n agentsMd: options.agentsMd,\n })\n reportInstallSkills(result)\n}\n\n/** Print an {@link InstallSkillsResult} the way the CLI does. */\nexport function reportInstallSkills(result: InstallSkillsResult): void {\n for (const file of result.written) console.log(`Bezel skill: wrote ${file}`)\n for (const file of result.backedUp) console.log(`Bezel skill: backed up ${file}.bezel-backup`)\n if (result.written.length === 0) console.log(\"Bezel skill: already up to date.\")\n for (const hint of result.hints) console.log(`Note: ${hint}`)\n console.log(\n \"Next: open this repo in your assistant. The Bezel skill loads automatically when a task touches design tokens.\",\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;AACA,SAAS,kBAAkB;AAC3B,SAAS,YAAAA,iBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,YAAAC,WAAU,WAAAC,gBAAe;;;ACLlC,SAAS,iBAAiB;AAC1B,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,UAAS,WAAAC,gBAAe;;;ACQjC,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,SAAS,MAAM,UAAU,eAAe;AAI1C,IAAM,gBAAgB,CAAC,eAAe,SAAS,UAAU,KAAK;AAI9D,IAAM,kBAAkB;AAExB,IAAM,gBAAgB;AAE7B,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAuBnB,SAAS,iBAAiB,QAA+B;AAC9D,MAAI,WAAW,cAAe,QAAO,CAAC,iBAAiB;AACvD,MAAI,WAAW,WAAW,WAAW,SAAU,QAAO,CAAC,iBAAiB;AACxE,SAAO,CAAC,mBAAmB,iBAAiB;AAC9C;AAGO,SAAS,cAAc,UAA0B;AACtD,SAAO,kBAAkB,UAAU,YAAY,cAAc,MAAM,IAAI,GAAG;AAAA,IACxE,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACH;AAEA,eAAe,aAAa,MAA2C;AACrE,MAAI;AACF,WAAO,MAAM,SAAS,MAAM,MAAM;AAAA,EACpC,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACR;AACF;AAOA,eAAe,aACb,KACA,MACA,SACA,QACe;AACf,QAAM,MAAM,SAAS,KAAK,IAAI;AAC9B,QAAM,WAAW,MAAM,aAAa,IAAI;AACxC,MAAI,aAAa,SAAS;AACxB,WAAO,UAAU,KAAK,GAAG;AACzB;AAAA,EACF;AACA,QAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,MAAI,aAAa,QAAW;AAC1B,QAAI;AACF,YAAM,UAAU,GAAG,IAAI,iBAAiB,UAAU,EAAE,MAAM,MAAM,MAAM,IAAM,CAAC;AAC7E,aAAO,SAAS,KAAK,GAAG;AAAA,IAC1B,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,IAChE;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,MAAM;AACrC,SAAO,QAAQ,KAAK,GAAG;AACzB;AAGA,eAAsB,cAAc,SAA6D;AAC/F,QAAM,MAAM,QAAQ,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAChD,QAAM,SAA8B,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,EAAE;AAE1F,aAAW,OAAO,iBAAiB,QAAQ,MAAM,GAAG;AAClD,eAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,YAAY,KAAK,GAAG;AAC/D,YAAM,aAAa,KAAK,KAAK,KAAK,KAAK,YAAY,MAAM,IAAI,GAAG,SAAS,MAAM;AAAA,IACjF;AAAA,EACF;AAEA,MAAI,QAAQ,YAAY,MAAM;AAC5B,UAAM,aAAa,KAAK,KAAK,WAAW;AACxC,UAAM,WAAY,MAAM,aAAa,UAAU,KAAM;AACrD,UAAM,SAAS,cAAc,QAAQ;AACrC,QAAI,WAAW,UAAU;AACvB,aAAO,UAAU,KAAK,WAAW;AAAA,IACnC,OAAO;AACL,YAAM,UAAU,YAAY,QAAQ,MAAM;AAC1C,aAAO,QAAQ,KAAK,WAAW;AAAA,IACjC;AAEA,UAAM,WAAW,MAAM,aAAa,KAAK,KAAK,WAAW,CAAC;AAC1D,QAAI,aAAa,UAAa,CAAC,SAAS,SAAS,YAAY,GAAG;AAC9D,aAAO,MAAM;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,wBAAwB,QAA6B;AACnE,MAAI,WAAW,iBAAiB,WAAW,WAAW,WAAW,SAAU,QAAO;AAClF,SAAO;AACT;AAMA,eAAsB,qBACpB,YACA,UAAgD,CAAC,GAClC;AACf,MAAI,SAAS;AACb,MAAI,CAAC,QAAQ;AACX,QAAI,CAAC,QAAQ,MAAM,OAAO;AACxB,YAAM,IAAI,MAAM,iCAAiC,cAAc,KAAK,GAAG,CAAC,GAAG;AAAA,IAC7E;AACA,UAAM,EAAE,SAAS,OAAO,IAAI,MAAM,OAAO,kBAAkB;AAC3D,QAAI;AACF,eAAS,MAAM,OAAoB;AAAA,QACjC,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,MAAM,gCAAgC,OAAO,cAAc;AAAA,UAC7D,EAAE,MAAM,0BAA0B,OAAO,QAAQ;AAAA,UACjD,EAAE,MAAM,2BAA2B,OAAO,SAAS;AAAA,UACnD,EAAE,MAAM,oBAAoB,OAAO,MAAM;AAAA,QAC3C;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,MAAM,SAAS,mBAAmB;AAC9D,gBAAQ,IAAI,kBAAkB;AAC9B;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,CAAC,cAAc,SAAS,MAAqB;AAC/C,UAAM,IAAI,MAAM,mBAAmB,MAAM,YAAY,cAAc,KAAK,IAAI,CAAC,GAAG;AAElF,QAAM,SAAS,MAAM,cAAc;AAAA,IACjC,KAAK,QAAQ;AAAA,IACb,QAAQ;AAAA,IACR,UAAU,QAAQ;AAAA,EACpB,CAAC;AACD,sBAAoB,MAAM;AAC5B;AAGO,SAAS,oBAAoB,QAAmC;AACrE,aAAW,QAAQ,OAAO,QAAS,SAAQ,IAAI,sBAAsB,IAAI,EAAE;AAC3E,aAAW,QAAQ,OAAO,SAAU,SAAQ,IAAI,0BAA0B,IAAI,eAAe;AAC7F,MAAI,OAAO,QAAQ,WAAW,EAAG,SAAQ,IAAI,kCAAkC;AAC/E,aAAW,QAAQ,OAAO,MAAO,SAAQ,IAAI,SAAS,IAAI,EAAE;AAC5D,UAAQ;AAAA,IACN;AAAA,EACF;AACF;;;AD1LO,IAAM,UAAU;AAChB,IAAM,UAAU,CAAC,eAAe,SAAS,UAAU,UAAU,OAAO;AAGpE,SAAS,cAAc,QAAoE;AAChG,MAAI,WAAW,eAAe;AAC5B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,CAAC,OAAO,OAAO,eAAe,QAAQ,WAAW,WAAW,SAAS,OAAO;AAAA,IACpF;AAAA,EACF;AACA,MAAI,WAAW,SAAS;AACtB,WAAO,EAAE,SAAS,SAAS,MAAM,CAAC,OAAO,OAAO,SAAS,SAAS,OAAO,EAAE;AAAA,EAC7E;AACA,SAAO;AACT;AAEA,SAAS,OAAO,OAAkD;AAChE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEO,SAAS,uBAAuB,KAAsB;AAC3D,QAAM,UAAmB,KAAK,MAAM,GAAG;AACvC,MACE,CAAC,MAAM,QAAQ,OAAO,KACtB,CAAC,QAAQ,MAAM,CAAC,WAAW,OAAO,MAAM,KAAK,OAAO,OAAO,MAAM,MAAM,QAAQ,GAC/E;AACA,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,QAAM,WAAW,QAAQ,KAAK,CAAC,WAAW,OAAO,MAAM,MAAM,OAAO;AACpE,MAAI,CAAC,SAAU,QAAO;AACtB,MACE,CAAC,OAAO,SAAS,WAAW,CAAC,KAC7B,SAAS,WAAW,EAAE,KAAK,MAAM,WACjC,SAAS,SAAS,MAAM,OACxB;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,eAAe,KAAa,QAAqC;AAC/E,QAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,MAAI,CAAC,OAAO,MAAM,EAAG,OAAM,IAAI,MAAM,oDAAoD;AACzF,QAAM,MAAM,WAAW,WAAW,eAAe;AACjD,QAAM,UAAU,OAAO,GAAG,KAAK,CAAC;AAChC,MAAI,CAAC,OAAO,OAAO,EAAG,OAAM,IAAI,MAAM,GAAG,GAAG,0CAA0C;AACtF,QAAM,QAAQ,WAAW,WAAW,EAAE,KAAK,QAAQ,IAAI,EAAE,MAAM,QAAQ,KAAK,QAAQ;AACpF,MAAI,QAAQ,OAAO,MAAM,QAAW;AAClC,UAAM,WAAW,QAAQ,OAAO;AAChC,QACE,CAAC,OAAO,QAAQ,KAChB,SAAS,KAAK,MAAM,WACnB,SAAS,MAAM,MAAM,UAAa,SAAS,MAAM,MAAM,UACxD,SAAS,SAAS,MAAM,QACxB;AACA,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACpF;AACA,WAAO;AAAA,EACT;AACA,SAAO,GAAG,KAAK,UAAU,EAAE,GAAG,QAAQ,CAAC,GAAG,GAAG,EAAE,GAAG,SAAS,OAAO,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AAAA;AACvF;AAUA,eAAsB,WACpB,YACA,UAA6B,CAAC,GACf;AACf,MAAI,SAAS;AACb,MAAI,CAAC,QAAQ;AACX,QAAI,CAAC,QAAQ,MAAM,OAAO;AACxB,YAAM,IAAI,MAAM,iCAAiC,QAAQ,KAAK,GAAG,CAAC,GAAG;AAAA,IACvE;AACA,UAAM,EAAE,SAAS,OAAO,IAAI,MAAM,OAAO,kBAAkB;AAC3D,QAAI;AACF,eAAS,MAAM,OAAkB;AAAA,QAC/B,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,MAAM,8BAA8B,OAAO,cAAc;AAAA,UAC3D,EAAE,MAAM,mCAAmC,OAAO,QAAQ;AAAA,UAC1D,EAAE,MAAM,yBAAyB,OAAO,SAAS;AAAA,UACjD,EAAE,MAAM,0BAA0B,OAAO,SAAS;AAAA,UAClD,EAAE,MAAM,uBAAuB,OAAO,QAAQ;AAAA,QAChD;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,MAAM,SAAS,mBAAmB;AAC9D,gBAAQ,IAAI,kBAAkB;AAC9B;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,SAAS,MAAmB;AACvC,UAAM,IAAI,MAAM,mBAAmB,MAAM,YAAY,QAAQ,KAAK,IAAI,CAAC,GAAG;AAC5E,QAAM,SAAS;AACf,QAAM,aAAa,cAAc,MAAM;AACvC,MAAI,YAAY;AACd,YAAQ;AAAA,MACN,WAAW,UACP,8CACA;AAAA,IACN;AACA,QAAI,oBAAoB;AACxB,QAAI,WAAW,SAAS;AACtB,YAAM,UAAU,UAAU,SAAS,CAAC,OAAO,QAAQ,QAAQ,GAAG;AAAA,QAC5D,UAAU;AAAA,QACV,OAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ,SAAS,QAAQ,WAAW;AACtC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AACF,0BAAoB,uBAAuB,QAAQ,MAAM;AAAA,IAC3D;AACA,UAAM,SAAS,oBACX,EAAE,QAAQ,GAAG,OAAO,OAAU,IAC9B,UAAU,WAAW,SAAS,WAAW,MAAM;AAAA,MAC7C,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC;AACL,QAAI,OAAO,SAAS,OAAO,WAAW,GAAG;AACvC,YAAM,IAAI;AAAA,QACR,uBAAuB,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,WAAW,WAAW,YAAY,WAAW,UAAU;AACrD,UAAM,OAAOC,SAAQ,WAAW,WAAW,qBAAqB,kBAAkB;AAClF,QAAI,MAAM;AACV,QAAI,SAAS;AACb,QAAI;AACF,YAAM,MAAMC,UAAS,MAAM,MAAM;AACjC,eAAS;AAAA,IACX,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,IAChE;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,eAAe,KAAK,MAAM;AAAA,IACrC,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,GAAG,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACpE;AAAA,IACF;AACA,QAAI,WAAW,KAAK;AAClB,YAAMC,OAAMC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAI,OAAQ,OAAMC,WAAU,GAAG,IAAI,iBAAiB,KAAK,EAAE,MAAM,MAAM,MAAM,IAAM,CAAC;AACpF,YAAMA,WAAU,MAAM,QAAQ,EAAE,MAAM,SAAS,MAAM,KAAK,CAAC;AAAA,IAC7D;AACA,YAAQ,IAAI,uBAAuB,IAAI,EAAE;AAAA,EAC3C,OAAO;AACL,YAAQ;AAAA,MACN,6DAA6D,OAAO;AAAA;AAAA,IACtE;AAAA,EACF;AACA,UAAQ;AAAA,IACN,WAAW,UACP,oEACA,WAAW,gBACT,iEACA;AAAA,EACR;AACA,UAAQ;AAAA,IACN;AAAA,EACF;AAEA,MAAI,MAAM,YAAY,QAAQ,MAAM,GAAG;AACrC,YAAQ,IAAI,EAAE;AACd,wBAAoB,MAAM,cAAc,EAAE,QAAQ,wBAAwB,MAAM,EAAE,CAAC,CAAC;AAAA,EACtF;AACF;AAEA,eAAe,YAAY,MAA6C;AACtE,MAAI,SAAS,OAAW,QAAO;AAC/B,MAAI,CAAC,QAAQ,MAAM,MAAO,QAAO;AACjC,QAAM,EAAE,SAAS,OAAO,IAAI,MAAM,OAAO,kBAAkB;AAC3D,MAAI;AACF,WAAO,MAAM,OAAgB;AAAA,MAC3B,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAM,qBAAqB,OAAO,KAAK;AAAA,QACzC,EAAE,MAAM,8CAA8C,OAAO,MAAM;AAAA,MACrE;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,iBAAiB,SAAS,MAAM,SAAS,kBAAmB,QAAO;AACvE,UAAM;AAAA,EACR;AACF;;;AD/LA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4DAqC8C,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYhF,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAOvB,eAAe,WAAW,MAAqC;AAC7D,QAAM,MAAMC,SAAQ,QAAQ,IAAI,GAAG,IAAI;AACvC,MAAI,UAAU,KAAK,GAAG,GAAG;AACvB,WAAO,KAAK,MAAM,MAAMC,UAAS,KAAK,MAAM,CAAC;AAAA,EAC/C;AACA,QAAM,MAAO,MAAM,OAAO,cAAc,GAAG,EAAE;AAG7C,SAAQ,IAAI,WAAW;AACzB;AAIA,IAAM,UAAU;AAAA,EACd,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,QAAQ,EAAE,MAAM,UAAU,OAAO,IAAI;AAAA,EACrC,KAAK,EAAE,MAAM,SAAS;AAAA,EACtB,oBAAoB,EAAE,MAAM,SAAS;AAAA,EACrC,mBAAmB,EAAE,MAAM,SAAS;AAAA,EACpC,gBAAgB,EAAE,MAAM,SAAS;AAAA,EACjC,OAAO,EAAE,MAAM,SAAS;AAAA,EACxB,MAAM,EAAE,MAAM,SAAS;AAAA,EACvB,eAAe,EAAE,MAAM,UAAU;AAAA,EACjC,SAAS,EAAE,MAAM,SAAS;AAAA,EAC1B,kBAAkB,EAAE,MAAM,SAAS;AAAA,EACnC,QAAQ,EAAE,MAAM,UAAU;AAAA,EAC1B,gBAAgB,EAAE,MAAM,UAAU;AAAA,EAClC,gBAAgB,EAAE,MAAM,UAAU;AAAA,EAClC,QAAQ,EAAE,MAAM,UAAU;AAAA,EAC1B,eAAe,EAAE,MAAM,UAAU;AAAA,EACjC,YAAY,EAAE,MAAM,UAAU;AAAA,EAC9B,OAAO,EAAE,MAAM,WAAW,OAAO,IAAI;AAAA,EACrC,MAAM,EAAE,MAAM,WAAW,OAAO,IAAI;AACtC;AAEA,IAAM,mBACJ;AAGF,eAAe,QAAQ,QAA+B;AACpD,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,SAAS,MAAM,WAAW;AAAA,IAC9B;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,iBAAiB,OAAO,kBAAkB;AAAA,IAC1C,gBAAgB,OAAO,iBAAiB;AAAA,IACxC,aAAa,OAAO,cAAc;AAAA,IAClC,UAAU,OAAO,aAAa,IAAI,QAAQ;AAAA,IAC1C,OAAO,OAAO,UAAU,IAAI,QAAQ;AAAA,IACpC,aAAa,OAAO;AAAA,IACpB,eAAe,OAAO;AAAA,IACtB,YAAY,OAAO,aAAa;AAAA,IAChC,OAAO,OAAO;AAAA,IACd,WAAW,OAAO;AAAA,IAClB,SAAS,OAAO,gBAAgB;AAAA,EAClC,CAAC;AAED,QAAM,aAAaC,UAAS,KAAK,OAAO,UAAU,KAAK;AAEvD,MAAI,OAAO,SAAS;AAClB,QAAI,OAAO,SAAS;AAClB,YAAM,UAAU,OAAO,qBAAqB,OAAO,sBAAsB,OAAO;AAChF,cAAQ,OAAO;AAAA,QACb,UACI,+BAA+B,UAAU,SAAS,OAAO,iBAAiB;AAAA,IAC1E,2BAA2B,UAAU;AAAA;AAAA,MAC3C;AAAA,IACF;AACA,QAAI,OAAO,OAAO,YAAY,OAAO,iBAAiB;AACpD,cAAQ,OAAO,MAAM,yBAAyB,OAAO,OAAO,OAAO,OAAO,UAAU;AAAA,CAAI;AAAA,IAC1F;AACA,QAAI,CAAC,OAAO,eAAe;AACzB,cAAQ,OAAO,MAAM;AAAA,EAAK,gBAAgB;AAAA,CAAI;AAAA,IAChD;AACA;AAAA,EACF;AAEA,MAAI,CAAC,OAAO,SAAS;AACnB,YAAQ,OAAO;AAAA,MACb,UAAU,UAAU;AAAA;AAAA,IACtB;AACA,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,UAAU;AAAA,IACd,OAAO,OAAO;AAAA,IACd,OAAO,OAAO;AAAA,IACd,OAAO,OAAO;AAAA,EAChB,EAAE,OAAO,CAAC,MAAmB,MAAM,MAAS;AAE5C,UAAQ,OAAO,MAAM,gBAAgB,UAAU;AAAA,CAAI;AACnD,aAAW,UAAU,SAAS;AAC5B,YAAQ,OAAO,MAAM,YAAY,MAAM;AAAA,CAAI;AAAA,EAC7C;AAEA,QAAM,UAAU,MAAM,mBAAmB,GAAG;AAC5C,QAAM,QAAkB,CAAC;AAEzB,MAAI,CAAC,OAAO,eAAe;AACzB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AACA,MAAI,CAAC,QAAQ,QAAQ,GAAG;AACtB,UAAM,KAAK,2DAA2D;AAAA,EACxE;AACA,MAAI,CAAC,iBAAiB,KAAK,EAAE,KAAK,CAAC,QAAQ,WAAWF,SAAQ,KAAK,KAAK,OAAO,CAAC,CAAC,GAAG;AAClF,UAAM,KAAK,kEAAkE;AAAA,EAC/E;AACA,QAAM,KAAK,8BAA8B,OAAO,OAAO,eAAe,sBAAsB;AAE5F,UAAQ,OAAO,MAAM,WAAW;AAChC,QAAM,QAAQ,CAAC,MAAM,MAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,CAAC,KAAK,IAAI;AAAA,CAAI,CAAC;AAC1E;AAGA,eAAe,SAAS,QAA+B;AACrD,QAAM,aACJ,OAAO,WACN,WAAWA,SAAQ,QAAQ,IAAI,GAAG,mBAAmB,CAAC,IAAI,sBAAsB;AACnF,QAAM,aAAa,aAAa,MAAM,WAAW,UAAU,IAAI,CAAC;AAEhE,QAAM,UAAwB,EAAE,GAAG,WAAW;AAC9C,MAAI,OAAO,kBAAkB,EAAG,SAAQ,kBAAkB,OAAO,kBAAkB;AACnF,MAAI,OAAO,iBAAiB,EAAG,SAAQ,iBAAiB,OAAO,iBAAiB;AAChF,MAAI,OAAO,cAAc,EAAG,SAAQ,cAAc,OAAO,cAAc;AACvE,MAAI,OAAO,MAAO,SAAQ,cAAc,OAAO;AAC/C,MAAI,OAAO,KAAM,SAAQ,gBAAgB,OAAO;AAChD,MAAI,OAAO,aAAa,EAAG,SAAQ,aAAa;AAChD,MAAI,OAAO,OAAQ,SAAQ,QAAQ;AACnC,MAAI,OAAO,cAAc,EAAG,SAAQ,YAAY;AAEhD,QAAM,MAAM,MAAM,qBAAqB,OAAO;AAE9C,MAAI,OAAO,QAAQ;AACjB,YAAQ,OAAO,MAAM,GAAG;AAAA,EAC1B,OAAO;AACL,YAAQ,OAAO,MAAM,gBAAgB,QAAQ,mBAAmB,wBAAwB;AAAA,CAAI;AAAA,EAC9F;AACF;AAEA,eAAe,KAAK,MAA+B;AACjD,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,SAAS;AAAA,EACX,CAAC;AAED,MAAI,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ;AAC5C,YAAQ,OAAO,MAAM,KAAK;AAC1B;AAAA,EACF;AAEA,QAAM,UAAU,YAAY,CAAC,KAAK;AAElC,MAAI,YAAY,eAAe;AAC7B,UAAM,WAAW,OAAO,QAAQ,EAAE,QAAQ,OAAO,OAAO,CAAC;AACzD;AAAA,EACF;AAEA,MAAI,YAAY,kBAAkB;AAChC,UAAM,qBAAqB,OAAO,QAAQ,EAAE,UAAU,CAAC,OAAO,cAAc,EAAE,CAAC;AAC/E;AAAA,EACF;AAEA,MAAI,YAAY,QAAQ;AACtB,UAAM,QAAQ,MAAM;AACpB;AAAA,EACF;AAEA,MAAI,YAAY,SAAS;AACvB,YAAQ,OAAO,MAAM,2BAA2B,OAAO;AAAA;AAAA,EAAS,KAAK,EAAE;AACvE,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACvB;AAEA,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAiB;AAClD,UAAQ,OAAO,MAAM,GAAG,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAC5E,UAAQ,WAAW;AACrB,CAAC;","names":["readFile","relative","resolve","mkdir","readFile","writeFile","dirname","resolve","resolve","readFile","mkdir","dirname","writeFile","resolve","readFile","relative"]}
@@ -1,3 +1,5 @@
1
+ import './agent-skill.js';
2
+
1
3
  /**
2
4
  * Options for the pure CSS transform ({@link tokensToCss}/{@link emitCss}),
3
5
  * decoupled from any filesystem concern so they work in any environment.
@@ -1,3 +1,5 @@
1
+ import './agent-skill.cjs';
2
+
1
3
  /**
2
4
  * Options for the pure CSS transform ({@link tokensToCss}/{@link emitCss}),
3
5
  * decoupled from any filesystem concern so they work in any environment.
package/dist/index.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AGENT_SKILL: () => AGENT_SKILL,
23
24
  DEFAULT_CONTEXTS: () => DEFAULT_CONTEXTS,
24
25
  DEFAULT_CONTEXT_NAME: () => DEFAULT_CONTEXT_NAME,
25
26
  DEFAULT_NAME_EXTENSION: () => DEFAULT_NAME_EXTENSION,
@@ -401,12 +402,26 @@ export type FontDef = { family: string; weights: number[] }
401
402
  `;
402
403
  }
403
404
 
405
+ // src/agent-skill.ts
406
+ var AGENT_SKILL = {
407
+ name: "bezel",
408
+ description: "Use when the repo has bezel.json or design-tokens.json and the task touches design tokens, theme colors, spacing, typography, radii, CSS variables, dark mode, or files under the Bezel output folder (src/bezel by default). Edit design-tokens.json, never the generated variables.css / contexts.ts / fonts.ts, then run the tokens build. Also covers pulling the latest tokens from the Bezel app and using the Bezel MCP tools.",
409
+ files: {
410
+ "SKILL.md": '---\nname: bezel\ndescription: Use when the repo has bezel.json or design-tokens.json and the task touches design tokens, theme colors, spacing, typography, radii, CSS variables, dark mode, or files under the Bezel output folder (src/bezel by default). Edit design-tokens.json, never the generated variables.css / contexts.ts / fonts.ts, then run the tokens build. Also covers pulling the latest tokens from the Bezel app and using the Bezel MCP tools.\n---\n\n# Bezel in this repository\n\nBezel is a design-token platform. Designers maintain the tokens in the Bezel app; this repo holds an exported copy and generates CSS from it with `@bezel-labs/bezel-kit`.\n\n```\nBezel app (cloud, source of truth)\n -> design-tokens.json DTCG file at the repo root, exported from Bezel\n -> bezel build reads bezel.json for options and output paths\n -> variables.css one CSS scope per context (:root, .dark, .light, ...)\n contexts.ts, fonts.ts optional generated TypeScript modules\n```\n\nNothing in this repo pushes back to Bezel. A change that must survive the next sync belongs in the Bezel app.\n\n## Hard rules\n\n1. Never edit a generated file. They start with `/* Generated by bezel \u2014 do not edit by hand. */` and live at the paths named in `bezel.json` (`variablesOutput`, `contextsOutput`, `fontsOutput`; default folder `src/bezel/`). `bezel build` overwrites them without asking and they are gitignored.\n2. To change a token value or add a variable, edit `design-tokens.json`, then rebuild. Never hand-write the CSS variable.\n3. After any change to `design-tokens.json` or `bezel.json`, run the tokens build: `npm run tokens` when that script exists, otherwise `npx bezel build` (use the repo\'s package manager runner). Confirm the outputs were rewritten before finishing.\n4. Only tokens with an `exportName` become CSS variables unless `bezel.json` sets `"includeAll": true`. Adding a token without an `exportName` produces no variable.\n5. Never pass `--force` to `bezel init`; it discards the existing `bezel.json`. `--project` and `--tokens-version` update their own keys without it.\n6. Do not start dev servers, preview servers, or watchers to verify a change. Rebuild and inspect the generated CSS instead.\n7. Local edits to `design-tokens.json` are overwritten by the next sync from Bezel. Tell the user when a change should be made in the Bezel app instead, and never silently sync over their local edits.\n\n## The tokens file\n\n`design-tokens.json` follows the W3C Design Tokens (DTCG) format. Every token is an object with a `$type` and one `$value` per context:\n\n```json\n"semantic": {\n "color": {\n "primary": {\n "$type": "color",\n "$root": { "$value": "{base.color.green.500}" },\n "dark": { "$value": { "colorSpace": "oklch", "components": [0.85, 0.16, 152] } },\n "$extensions": { "com.bezel.app": { "exportName": ["primary", "ring"] } }\n }\n }\n}\n```\n\n- Context keys (`$root`, `dark`, `light`, or whatever `bezel.json` `contexts` lists) sit inside the token. `$root` is the base; other contexts only need the values that differ.\n- `$value` is either a literal (DTCG color, dimension, font family, ...) or a reference like `{base.color.green.500}`. References are resolved to literal values in the generated CSS.\n- `$extensions["com.bezel.app"].exportName` is the list of CSS variable names the token emits. One token can emit several (`foreground`, `card-foreground`). An empty list means no variable.\n- Groups (`base`, `semantic`, `color`, ...) are plain nesting with no `$type`.\n\n## What to do for common requests\n\n| Request | Edit | Then |\n|---|---|---|\n| Change a color, size, radius, or font value | The token\'s `$value` in the right context key (`$root` for every mode, `dark` for dark mode only) | Rebuild |\n| A value should differ in dark mode | Add or edit the `dark` key on that token | Rebuild |\n| New CSS variable | Add a token with `$type`, `$root.$value`, and an `exportName` (or reference an existing token) | Rebuild |\n| Rename a CSS variable | Change the `exportName` entry; update every consumer of the old `--name` | Rebuild |\n| New theme or brand context | Add the context to `bezel.json` `contexts` (name -> selector) and add that key to the tokens that differ | Rebuild |\n| Change where files are generated | Edit `variablesOutput` / `contextsOutput` / `fontsOutput` in `bezel.json`; update the CSS import | Rebuild, delete the old outputs |\n| "Pull the latest tokens" / "sync from Bezel" | See the next section | Rebuild |\n\nFind the token for an existing variable by searching `design-tokens.json` for its name inside an `exportName` array.\n\n## Pulling the latest tokens from Bezel\n\n`bezel.json` `projectId` and `version` (`"latest"` or a published semver) say which Bezel project and snapshot this repo tracks.\n\nWith the Bezel MCP connected: call `get-design-tokens-file` with that `projectId` and `version`, write the returned `content` string to `design-tokens.json` verbatim (no reformatting), then rebuild. The `sync-project` prompt walks through this, including linking a project when `projectId` is missing. Never pick a project or version yourself; ask when it is ambiguous.\n\nWithout the MCP: ask the user to download `design-tokens.json` from the project in the Bezel app and replace the file at the repo root, then rebuild.\n\nWarn before overwriting a `design-tokens.json` that has local edits.\n\n## With the Bezel MCP connected\n\nPrefer small, targeted calls over reading the whole tokens file:\n\n- `get-project-manifest` first: groups, counts, types, contexts, no values.\n- `query-tokens` to find tokens by group, type, name, or `exportName`; `get-token-by-path` for one token with every context value.\n- `get-token-bundle` for a curated set per task (`theming-setup`, `button`, `card`, `form`, ...).\n- `export-tokens` and `get-framework-overrides` to generate CSS, JS/TS objects, or Tailwind / shadcn / Mantine config from tokens.\n- `contrast-check`, `color-convert`, `color-ramp`, `unit-convert` for deterministic math instead of estimating.\n- `design-review` to check a component description against the tokens.\n\nSee `references/mcp-tools.md` for the full list and `references/bezel-json.md` for every config field.\n\n## Setting up a repo that is not on Bezel yet\n\nRun the `setup-project` tool (or the `/mcp__bezel__setup-project` prompt) and follow it; it installs `@bezel-labs/bezel-kit`, writes `bezel.json`, fetches the tokens, builds, and wires the CSS import. Do not improvise the steps.\n',
411
+ "references/bezel-json.md": '# bezel.json reference\n\n`bezel.json` lives at the repo root (or the working directory `bezel build` runs in). `bezel build` loads it automatically; `bezel init` writes it. The tokens input is always `design-tokens.json` in that same directory and is not configurable.\n\n| Field | Default | Used by | Meaning |\n|---|---|---|---|\n| `projectId` | none | MCP | UUID of the Bezel project this repo tracks. Set with `npx bezel init --project <uuid>`. |\n| `version` | `"latest"` | MCP | Which tokens snapshot to fetch: `"latest"` or a published semver such as `"1.4.0"`. Set with `--tokens-version`. |\n| `variablesOutput` | `"src/bezel/variables.css"` | build | Generated CSS file. Import this from the app entry. |\n| `contextsOutput` | none | build | When set, writes a TypeScript module exporting `CONTEXTS` (the context names). |\n| `fontsOutput` | none | build | When set, writes a TypeScript module exporting `FONTS` (web fonts derived from the tokens). |\n| `contexts` | `{ "$root": ":root", "dark": ".dark", "light": ".light" }` | build | Context name -> CSS selector. The first entry is the base context and is emitted in full; the rest are override-only blocks. |\n| `colorFormat` | `"oklch"` | build | `"oklch"` or `"hex"`. |\n| `dimensionUnit` | `"preserve"` | build | `"preserve"` keeps authored units; `"rem"` converts `px` to `rem`. |\n| `nameExtension` | `"com.bezel.app"` | build | The `$extensions` key that holds `exportName`. Only change for files exported before the 0.3.0 rename. |\n| `includeAll` | `false` | build | Also emit a variable for every token without an `exportName`, named by its kebab-cased path (`--base-color-primary-500`). |\n| `write` | `true` | build | `false` returns the CSS without writing files (programmatic use). |\n| `gitignore` | `true` | build | Maintain a `# bezel:start` ... `# bezel:end` block in `.gitignore` listing the generated outputs. |\n| `gitignorePath` | `".gitignore"` | build | Which `.gitignore` to manage. |\n| `cwd` | process cwd | build | Base directory paths resolve against. |\n\n`projectId` and `version` are ignored by `bezel build`; everything else is ignored by the MCP.\n\n## CLI\n\n```\nbezel init [--project <uuid>] [--tokens-version <v>] [--dir <path>] ... create or update bezel.json\nbezel build [--stdout] [--no-gitignore] ... generate the outputs (default command)\nbezel install-mcp [--client <name>] connect an AI coding tool to the Bezel MCP\nbezel install-skills [--client <name>] [--no-agents-md] install this skill into the repo\n```\n\n`bezel init` on an existing `bezel.json` with `--project` or `--tokens-version` updates only those keys. Any other re-run leaves the file alone unless `--force` is passed, which agents must not do.\n',
412
+ "references/mcp-tools.md": "# Bezel MCP quick reference\n\nRemote server at `https://mcp.bezel.new/mcp` (Streamable HTTP, OAuth). The server returns data and instructions; the coding agent performs every local file edit and command. Project-scoped tools take the `projectId` from `bezel.json` or from `find-project`.\n\n## Guided workflows\n\n| Tool / prompt | Use |\n|---|---|\n| `setup-project` (tool and prompt) | Resumable setup: install bezel-kit, link a project, write `bezel.json`, fetch tokens, build, wire the CSS import, optional Crystal live preview. |\n| `sync-project` (prompt) | Refresh `design-tokens.json` from the linked project and version, then rebuild. |\n| `safe-usage-guide` (prompt) | Context-budget rules: manifest first, targeted queries, cite token paths. |\n| `manifest-first-workflow`, `context-resolution` (prompts) | Recommended reading order and how contexts resolve. |\n| `get-agent-guide` (tool) | Returns this skill's text when the repo has no local copy. |\n\n## Discovery\n\n| Tool | Parameters | Returns |\n|---|---|---|\n| `find-project` | `query?` | All owned projects (name + id), or one project resolved from a name or UUID. |\n| `get-project-manifest` | `projectId` | Groups, token counts, types, contexts. No values. Call this first. |\n\n## Repo sync\n\n| Tool | Parameters | Returns |\n|---|---|---|\n| `get-design-tokens-file` | `projectId`, `version?` | The exact `design-tokens.json` content to write to disk, plus project name and version. Unknown version -> list of available versions. |\n\n## Reading tokens\n\n| Tool | Parameters | Returns |\n|---|---|---|\n| `query-tokens` | `projectId`, `groupPath?`, `tokenType?`, `search?`, `exportName?`, `contextKey?`, `resolveAliases?` | Filtered tokens. |\n| `get-token-by-path` | `projectId`, `tokenPath`, `contextKey?`, `resolveAliases?` | One token with every context value and alias detail. |\n| `get-token-bundle` | `projectId`, `intent` | Curated set: `theming-setup`, `button`, `card`, `input`, `form`, `auth-page`, `dashboard-shell`. |\n| `get-project-contexts` | `projectId` | Context groups and values (theme modes, platforms, brands). |\n| `resolve-context` | `projectId`, `contextGroup`, `contextValue` | Canonical context value or a structured error. |\n\n## Generating code\n\n| Tool | Parameters | Returns |\n|---|---|---|\n| `export-tokens` | `projectId`, `format` (`css-variables`, `js-object`, `ts-object`), filters, `prefix?`, `includeAll?` | Generated code with aliases resolved. |\n| `get-framework-overrides` | `projectId`, `framework` (`tailwind`, `shadcn`, `mantine`), `version?`, filters | Framework config derived from the tokens. |\n\n## Color and unit math (deterministic)\n\n| Tool | Parameters |\n|---|---|\n| `contrast-check` | `foreground`, `background` -> WCAG ratio, grade, recommendations |\n| `color-convert` | `color`, `targetFormat`, `manipulation?`, `mixColor?` |\n| `color-ramp` | `baseColor`, `steps`, `endColor?`, `colorSpace?` |\n| `unit-convert` | `value`, `fromUnit`, `toUnit`, `rootFontSize?`, `parentFontSize?` |\n\n## Review and history\n\n| Tool | Parameters |\n|---|---|\n| `design-review` | `projectId`, `componentDescription`, `tokenPathsUsed?`, `contextKey?` |\n| `get-chat-history` | `projectId` |\n| `search-chat-history` | `projectId`, `query` |\n\n## Resources\n\n- `bezel://projects`: your projects with ids and names.\n- `bezel://agent-guide`: this skill's text.\n"
413
+ },
414
+ agentsMdBlock: '## Bezel design tokens\n\n- `design-tokens.json` at the repo root is the source for every design token. Edit it to change a color, size, font, or radius, or to add a CSS variable (add an `exportName` under `$extensions["com.bezel.app"]`).\n- Files under the Bezel output folder (`variablesOutput`, `contextsOutput`, `fontsOutput` in `bezel.json`; `src/bezel/` by default) are generated. Never edit them; they are overwritten on every build.\n- After changing `design-tokens.json` or `bezel.json`, run `npm run tokens` (or `npx bezel build`) and check the outputs were rewritten.\n- Dark mode and other contexts are keys inside each token (`$root`, `dark`, `light`). Add a value under the context key instead of writing a CSS override.\n- The Bezel app is the source of truth. Local token edits are replaced by the next sync (`get-design-tokens-file` via the Bezel MCP, or a download from the app), so tell the user when a change should be made in Bezel.\n- Never run `bezel init --force`. Never start dev servers to verify token changes.\n- Full guidance: the `bezel` skill in `.claude/skills/bezel/SKILL.md` or `.agents/skills/bezel/SKILL.md`.',
415
+ summary: 'Use when the repo has bezel.json or design-tokens.json and the task touches design tokens, theme colors, spacing, typography, radii, CSS variables, dark mode, or files under the Bezel output folder (src/bezel by default). Edit design-tokens.json, never the generated variables.css / contexts.ts / fonts.ts, then run the tokens build. Also covers pulling the latest tokens from the Bezel app and using the Bezel MCP tools.\n\n## Hard rules\n\n1. Never edit a generated file. They start with `/* Generated by bezel \u2014 do not edit by hand. */` and live at the paths named in `bezel.json` (`variablesOutput`, `contextsOutput`, `fontsOutput`; default folder `src/bezel/`). `bezel build` overwrites them without asking and they are gitignored.\n2. To change a token value or add a variable, edit `design-tokens.json`, then rebuild. Never hand-write the CSS variable.\n3. After any change to `design-tokens.json` or `bezel.json`, run the tokens build: `npm run tokens` when that script exists, otherwise `npx bezel build` (use the repo\'s package manager runner). Confirm the outputs were rewritten before finishing.\n4. Only tokens with an `exportName` become CSS variables unless `bezel.json` sets `"includeAll": true`. Adding a token without an `exportName` produces no variable.\n5. Never pass `--force` to `bezel init`; it discards the existing `bezel.json`. `--project` and `--tokens-version` update their own keys without it.\n6. Do not start dev servers, preview servers, or watchers to verify a change. Rebuild and inspect the generated CSS instead.\n7. Local edits to `design-tokens.json` are overwritten by the next sync from Bezel. Tell the user when a change should be made in the Bezel app instead, and never silently sync over their local edits.'
416
+ };
417
+
404
418
  // src/index.ts
405
419
  function tokensToCss(tokens, options = {}) {
406
420
  return emitCss(tokens, resolveCssOptions(options));
407
421
  }
408
422
  // Annotate the CommonJS export names for ESM import in node:
409
423
  0 && (module.exports = {
424
+ AGENT_SKILL,
410
425
  DEFAULT_CONTEXTS,
411
426
  DEFAULT_CONTEXT_NAME,
412
427
  DEFAULT_NAME_EXTENSION,