@dowel-ui/cli 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -377,6 +377,55 @@ function findCssEntry(root) {
377
377
  }
378
378
  }
379
379
  /**
380
+ * Strips comments and trailing commas from JSON with extensions, without
381
+ * touching what is inside a string.
382
+ *
383
+ * A regex cannot do this. `tsconfig.json` aliases are written `"@/*"`, which
384
+ * contains `/*`, and the `include` globs are written `"**\/*.ts"`, which
385
+ * contains `*\/` — so a naive block-comment regex treats everything between
386
+ * them as a comment and eats the `paths` block. Every stock Next.js tsconfig
387
+ * has both, which is exactly the project this tool is most often pointed at.
388
+ * The parse then failed, `detectResolve` returned undefined, and `init`
389
+ * either asked for an alias it could already see or, under `--yes`, refused.
390
+ *
391
+ * So this walks the text instead, and only treats `//` and `/*` as comments
392
+ * when they are outside a string.
393
+ */
394
+ function stripJsonComments(text) {
395
+ let out = "";
396
+ let inString = false;
397
+ let escaped = false;
398
+ for (let i = 0; i < text.length; i += 1) {
399
+ const char = text[i] ?? "";
400
+ const next = text[i + 1] ?? "";
401
+ if (inString) {
402
+ out += char;
403
+ if (escaped) escaped = false;
404
+ else if (char === "\\") escaped = true;
405
+ else if (char === "\"") inString = false;
406
+ continue;
407
+ }
408
+ if (char === "\"") {
409
+ inString = true;
410
+ out += char;
411
+ continue;
412
+ }
413
+ if (char === "/" && next === "*") {
414
+ const end = text.indexOf("*/", i + 2);
415
+ i = end === -1 ? text.length : end + 1;
416
+ continue;
417
+ }
418
+ if (char === "/" && next === "/") {
419
+ const end = text.indexOf("\n", i);
420
+ if (end === -1) break;
421
+ i = end - 1;
422
+ continue;
423
+ }
424
+ out += char;
425
+ }
426
+ return out.replace(/,(\s*[}\]])/g, "$1");
427
+ }
428
+ /**
380
429
  * Reads the first wildcard alias out of tsconfig paths.
381
430
  *
382
431
  * `"@/*": ["./src/*"]` becomes `{ prefix: "@/", base: "src" }`. Only the
@@ -389,8 +438,7 @@ function detectResolve(root) {
389
438
  if (!existsSync(path)) continue;
390
439
  let parsed;
391
440
  try {
392
- const raw = readFileSync(path, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1");
393
- parsed = JSON.parse(raw);
441
+ parsed = JSON.parse(stripJsonComments(readFileSync(path, "utf8")));
394
442
  } catch {
395
443
  continue;
396
444
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/branding.ts","../../registry/dist/schema-ByqIpT47.js","../src/lib/errors.ts","../src/lib/config.ts","../src/lib/logger.ts","../src/lib/package-manager.ts","../src/lib/paths.ts","../src/lib/project.ts","../src/lib/registry-client.ts","../src/commands/add.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/remove.ts","../src/commands/update.ts","../src/index.ts"],"sourcesContent":["/**\n * Branding, mirrored from the repository root config.\n *\n * Duplicated deliberately: the published CLI cannot import from the monorepo\n * root, and `pnpm rebrand` rewrites both copies in the same pass.\n */\nexport const branding = {\n libraryName: \"Dowel\",\n cliName: \"dowel\",\n /**\n * The npm package name, which is NOT the command name. npm rejected the\n * unscoped `dowel` as too similar to `del` and `bower` — a rule that runs\n * only at publish time, so a 404 from the registry proves a name is unused,\n * never that it can be claimed. This is what follows `npx`; `cliName` is the\n * binary the package installs.\n */\n cliPackage: \"@dowel-ui/cli\",\n registryUrl: \"https://dowel-eight.vercel.app/r\",\n} as const;\n","import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n//#region src/hash.ts\n/**\n* Content hash used to detect local edits to an installed file.\n*\n* Line endings are normalised before hashing so a Windows checkout does not\n* read as \"every file modified\", which would make `update` useless there.\n*/\nfunction hashContent(content) {\n\tconst normalised = content.replace(/\\r\\n/g, \"\\n\");\n\treturn `sha256:${createHash(\"sha256\").update(normalised, \"utf8\").digest(\"hex\")}`;\n}\n//#endregion\n//#region src/schema.ts\n/**\n* The public registry contract.\n*\n* This is the boundary between the library and every consumer's project, so it\n* is validated on both sides: the build refuses to emit anything that does not\n* satisfy it, and the CLI refuses to install anything that does not parse. A\n* registry that serves malformed data breaks builds in someone else's\n* repository, where it is hardest to diagnose.\n*/\n/** Bumped only for a breaking change to the shape below. */\nconst REGISTRY_VERSION = 1;\nconst registryFileTypeSchema = z.enum([\n\t\"registry:ui\",\n\t\"registry:lib\",\n\t\"registry:hook\",\n\t\"registry:block\",\n\t\"registry:style\"\n]);\nconst registryItemTypeSchema = z.enum([\n\t\"registry:ui\",\n\t\"registry:lib\",\n\t\"registry:hook\",\n\t\"registry:theme\",\n\t\"registry:block\"\n]);\nconst registryFileSchema = z.object({\n\t/**\n\t* Logical path within the registry, e.g. `ui/button.tsx`, `lib/utils.ts`.\n\t*\n\t* The leading segment selects which of the consumer's aliases the file is\n\t* written under. The registry deliberately does not know the destination —\n\t* that depends on a project layout it has never seen.\n\t*/\n\tpath: z.string().min(1),\n\ttype: registryFileTypeSchema,\n\tcontent: z.string(),\n\t/**\n\t* `sha256:<hex>` of `content` as published.\n\t*\n\t* Recorded at install time so `update` can tell an untouched file from one\n\t* the user has edited. This cannot be added later: an install that did not\n\t* record a hash leaves no way to know what it originally wrote.\n\t*/\n\thash: z.string().regex(/^sha256:[0-9a-f]{64}$/)\n});\nconst registryItemSchema = z.object({\n\t$schema: z.string().optional(),\n\tregistryVersion: z.literal(1),\n\tname: z.string().regex(/^[a-z][a-z0-9-]*$/),\n\ttype: registryItemTypeSchema,\n\ttitle: z.string().min(1),\n\tdescription: z.string().min(10),\n\tcategory: z.string().min(1),\n\tstatus: z.enum([\n\t\t\"stable\",\n\t\t\"beta\",\n\t\t\"experimental\"\n\t]),\n\t/** npm packages to install alongside the files. */\n\tdependencies: z.array(z.string()),\n\t/** Other registry items to install first. */\n\tregistryDependencies: z.array(z.string()),\n\tfiles: z.array(registryFileSchema).min(1),\n\ta11y: z.string().optional()\n});\nconst registryIndexEntrySchema = registryItemSchema.pick({\n\tname: true,\n\ttype: true,\n\ttitle: true,\n\tdescription: true,\n\tcategory: true,\n\tstatus: true,\n\tdependencies: true,\n\tregistryDependencies: true\n}).extend({ fileCount: z.number().int().positive() });\nconst registryIndexSchema = z.object({\n\t$schema: z.string().optional(),\n\tregistryVersion: z.literal(1),\n\t/** Version of the package the registry was generated from. */\n\tgeneratedFrom: z.string().min(1),\n\titems: z.array(registryIndexEntrySchema)\n});\n//#endregion\nexport { registryIndexSchema as a, hashContent as c, registryIndexEntrySchema as i, registryFileSchema as n, registryItemSchema as o, registryFileTypeSchema as r, registryItemTypeSchema as s, REGISTRY_VERSION as t };\n\n//# sourceMappingURL=schema-ByqIpT47.js.map","/**\n * An error whose message is written for the person running the command.\n *\n * Anything thrown as a CliError is printed as a clean message with no stack\n * trace; everything else is treated as a bug and printed in full, because a\n * stack trace is exactly what is useful then and exactly what is noise when the\n * problem is \"you have not run init yet\".\n */\nexport class CliError extends Error {\n readonly hint: string | undefined;\n\n constructor(message: string, hint?: string) {\n super(message);\n this.name = \"CliError\";\n this.hint = hint;\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\n\nimport { CliError } from \"./errors\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n/**\n * How the CLI turns an import alias into a directory.\n *\n * Stored as a prefix/base pair taken from the project's tsconfig paths, rather\n * than as absolute directories, so the config stays readable and survives the\n * project being moved or checked out somewhere else.\n */\nexport const resolveSchema = z.object({\n /** Alias prefix, e.g. \"@/\" for `\"@/*\": [\"./src/*\"]`. */\n prefix: z.string().min(1),\n /** Directory the prefix maps to, relative to the project root, e.g. \"src\". */\n base: z.string(),\n});\n\nexport const aliasesSchema = z.object({\n components: z.string().min(1),\n ui: z.string().min(1),\n lib: z.string().min(1),\n hooks: z.string().min(1),\n utils: z.string().min(1),\n /**\n * Where blocks are installed.\n *\n * Optional so a components.json written before blocks existed still parses;\n * `blocksAlias()` derives a sensible default from `components` when it is\n * absent. Silently failing to install a block would be worse than either.\n */\n blocks: z.string().min(1).optional(),\n});\n\nexport const installedItemSchema = z.object({\n /** Registry version the item was installed from. */\n from: z.string(),\n /** Project-relative file path to the hash of the content we wrote. */\n files: z.record(z.string(), z.string()),\n /**\n * Registry entries this one imports.\n *\n * Recorded so `remove` can refuse to delete something another installed\n * component still needs, without having to reach the registry to find out.\n * Optional, because installs made before this existed have no record of it.\n */\n dependsOn: z.array(z.string()).optional(),\n});\n\nexport const configSchema = z.object({\n $schema: z.string().optional(),\n version: z.literal(1),\n typescript: z.boolean(),\n registry: z.string().min(1),\n tailwind: z.object({\n /** Project-relative path to the stylesheet that imports Tailwind. */\n css: z.string().min(1),\n }),\n aliases: aliasesSchema,\n resolve: resolveSchema,\n /**\n * What has been installed, and the hash of what was written.\n *\n * This is what lets `update` tell an untouched file from one the user has\n * edited. It has to be recorded at install time — an install that skipped it\n * leaves no way to ever know what it originally wrote.\n */\n installed: z.record(z.string(), installedItemSchema).default({}),\n});\n\nexport type Config = z.infer<typeof configSchema>;\nexport type Aliases = z.infer<typeof aliasesSchema>;\n\n/** The blocks alias, or a default derived from where components live. */\nexport function blocksAlias(config: Config): string {\n return config.aliases.blocks ?? `${config.aliases.components}/blocks`;\n}\n\nexport function configPath(cwd: string): string {\n return join(cwd, CONFIG_FILE);\n}\n\nexport function configExists(cwd: string): boolean {\n return existsSync(configPath(cwd));\n}\n\nexport function readConfig(cwd: string): Config {\n const path = configPath(cwd);\n\n if (!existsSync(path)) {\n throw new CliError(\n `No ${CONFIG_FILE} found in ${cwd}.`,\n \"Run `init` first to set the project up.\",\n );\n }\n\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n throw new CliError(`${CONFIG_FILE} is not valid JSON.`);\n }\n\n const parsed = configSchema.safeParse(raw);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new CliError(`${CONFIG_FILE} is not valid:\\n${issues}`);\n }\n\n return parsed.data;\n}\n\nexport function writeConfig(cwd: string, config: Config): void {\n writeFileSync(configPath(cwd), `${JSON.stringify(config, null, 2)}\\n`);\n}\n","import pc from \"picocolors\";\n\n/**\n * All CLI output goes through here.\n *\n * A single place to route messages means the format stays consistent, and\n * anything that needs to change later — quiet mode, JSON output, writing to\n * stderr — changes in one file rather than in every command.\n */\nexport const logger = {\n info(message: string) {\n console.log(message);\n },\n success(message: string) {\n console.log(`${pc.green(\"✓\")} ${message}`);\n },\n warn(message: string) {\n console.warn(`${pc.yellow(\"!\")} ${message}`);\n },\n error(message: string) {\n console.error(`${pc.red(\"✕\")} ${message}`);\n },\n step(message: string) {\n console.log(`${pc.dim(\"·\")} ${message}`);\n },\n blank() {\n console.log(\"\");\n },\n};\n\nexport { pc };\n","import { spawnSync } from \"node:child_process\";\n\nimport type { PackageManager } from \"./project\";\nimport { CliError } from \"./errors\";\n\nconst INSTALL_COMMAND: Record<PackageManager, string[]> = {\n pnpm: [\"add\"],\n yarn: [\"add\"],\n bun: [\"add\"],\n npm: [\"install\"],\n};\n\n/** Packages already present are skipped, so re-running `add` installs nothing. */\nexport function missingDependencies(\n installed: Record<string, string>,\n required: string[],\n): string[] {\n return required.filter((dependency) => !(dependency in installed));\n}\n\nexport function installDependencies(\n manager: PackageManager,\n cwd: string,\n dependencies: string[],\n): void {\n if (dependencies.length === 0) return;\n\n const args = [...INSTALL_COMMAND[manager], ...dependencies];\n const result = spawnSync(manager, args, { cwd, stdio: \"inherit\" });\n\n if (result.error) {\n throw new CliError(\n `Could not run ${manager}: ${result.error.message}`,\n `Install these manually: ${dependencies.join(\" \")}`,\n );\n }\n\n if (result.status !== 0) {\n throw new CliError(\n `${manager} ${args.join(\" \")} failed.`,\n \"Fix the install and run the command again — no files were rolled back.\",\n );\n }\n}\n","import { join } from \"node:path\";\n\nimport { blocksAlias, type Config } from \"./config\";\nimport { CliError } from \"./errors\";\n\n/**\n * Maps a registry file path to a destination in the project.\n *\n * The registry publishes logical paths — `ui/button.tsx`, `lib/utils.ts` —\n * because it has never seen the project it is being installed into. The leading\n * segment selects which alias the file belongs under, and the alias is resolved\n * through the project's own tsconfig prefix.\n */\nexport function resolveDestination(config: Config, registryPath: string): string {\n const [group, ...rest] = registryPath.split(\"/\");\n const relative = rest.join(\"/\");\n\n if (!group || relative === \"\") {\n throw new CliError(`Registry path \"${registryPath}\" is not in a recognised group.`);\n }\n\n const alias =\n group === \"ui\"\n ? config.aliases.ui\n : group === \"lib\"\n ? config.aliases.lib\n : group === \"hooks\"\n ? config.aliases.hooks\n : group === \"blocks\"\n ? blocksAlias(config)\n : undefined;\n\n if (!alias) {\n throw new CliError(\n `Registry path \"${registryPath}\" uses unknown group \"${group}\".`,\n \"This usually means the CLI is older than the registry it is reading.\",\n );\n }\n\n return join(aliasToDirectory(config, alias), relative);\n}\n\n/** Turns an import alias such as `@/components/ui` into `src/components/ui`. */\nexport function aliasToDirectory(config: Config, alias: string): string {\n const { prefix, base } = config.resolve;\n\n if (!alias.startsWith(prefix)) {\n throw new CliError(\n `Alias \"${alias}\" does not start with the configured prefix \"${prefix}\".`,\n `Check the \"aliases\" and \"resolve\" entries in components.json.`,\n );\n }\n\n const withoutPrefix = alias.slice(prefix.length);\n return base ? join(base, withoutPrefix) : withoutPrefix;\n}\n\n/**\n * Rewrites the library's own import aliases to the ones the project uses.\n *\n * The published source is written against `@/components/*` and `@/lib/*`. A\n * project that puts its components somewhere else, or uses `~/` instead of\n * `@/`, gets files that import from where they actually live. Getting this\n * wrong is the single most common way a source-first install produces code that\n * does not compile.\n */\nexport function rewriteImports(content: string, config: Config): string {\n const { aliases } = config;\n\n return content\n .replace(\n /([\"'])@\\/lib\\/utils\\1/g,\n (_match, quote: string) => `${quote}${aliases.utils}${quote}`,\n )\n .replace(\n /([\"'])@\\/lib\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.lib}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/components\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.ui}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/hooks\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.hooks}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/blocks\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${blocksAlias(config)}/${rest}${quote}`,\n );\n}\n","import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { CliError } from \"./errors\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface ProjectInfo {\n root: string;\n packageManager: PackageManager;\n packageJson: PackageJson;\n isTypeScript: boolean;\n reactVersion: string | undefined;\n tailwindVersion: string | undefined;\n framework: \"next\" | \"vite\" | \"remix\" | \"unknown\";\n /** Project-relative path to the stylesheet that imports Tailwind, if found. */\n cssEntry: string | undefined;\n /** Alias prefix and base directory taken from tsconfig paths. */\n resolve: { prefix: string; base: string } | undefined;\n}\n\nconst LOCKFILES: [string, PackageManager][] = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"bun.lock\", \"bun\"],\n [\"bun.lockb\", \"bun\"],\n [\"yarn.lock\", \"yarn\"],\n [\"package-lock.json\", \"npm\"],\n];\n\nexport function detectPackageManager(root: string): PackageManager {\n for (const [lockfile, manager] of LOCKFILES) {\n if (existsSync(join(root, lockfile))) return manager;\n }\n return \"npm\";\n}\n\nfunction readPackageJson(root: string): PackageJson {\n const path = join(root, \"package.json\");\n if (!existsSync(path)) {\n throw new CliError(\n `No package.json found in ${root}.`,\n \"Run this from the root of your project.\",\n );\n }\n\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as PackageJson;\n } catch {\n throw new CliError(\"package.json is not valid JSON.\");\n }\n}\n\nfunction versionOf(packageJson: PackageJson, name: string): string | undefined {\n return packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name];\n}\n\n/** Leading integer of a range such as `^4.3.3`, `~4.0.0`, `4.x`. */\nexport function majorVersion(range: string | undefined): number | undefined {\n if (!range) return undefined;\n const match = /(\\d+)/.exec(range);\n return match?.[1] === undefined ? undefined : Number(match[1]);\n}\n\nfunction detectFramework(packageJson: PackageJson): ProjectInfo[\"framework\"] {\n if (versionOf(packageJson, \"next\")) return \"next\";\n if (versionOf(packageJson, \"@remix-run/react\") ?? versionOf(packageJson, \"react-router\")) {\n return \"remix\";\n }\n if (versionOf(packageJson, \"vite\")) return \"vite\";\n return \"unknown\";\n}\n\n/** Directories worth searching for the stylesheet, in the order projects use them. */\nconst CSS_SEARCH_DIRS = [\"app\", \"src/app\", \"src/styles\", \"styles\", \"src\", \".\"];\n\n/**\n * Finds the stylesheet that pulls Tailwind in.\n *\n * Located by content rather than by name: `globals.css`, `index.css`,\n * `app.css` and `main.css` are all common, and guessing at the filename would\n * mean appending tokens to a stylesheet that is never loaded.\n */\nexport function findCssEntry(root: string): string | undefined {\n for (const dir of CSS_SEARCH_DIRS) {\n const absolute = join(root, dir);\n if (!existsSync(absolute) || !statSync(absolute).isDirectory()) continue;\n\n for (const entry of readdirSync(absolute)) {\n if (!entry.endsWith(\".css\")) continue;\n\n const path = join(absolute, entry);\n const content = readFileSync(path, \"utf8\");\n if (/@import\\s+[\"']tailwindcss[\"']/.test(content) || /@tailwind\\s+/.test(content)) {\n return dir === \".\" ? entry : `${dir}/${entry}`;\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Reads the first wildcard alias out of tsconfig paths.\n *\n * `\"@/*\": [\"./src/*\"]` becomes `{ prefix: \"@/\", base: \"src\" }`. Only the\n * wildcard form is understood, which covers how essentially every React project\n * is set up; anything else falls through to a prompt rather than a wrong guess.\n */\nexport function detectResolve(root: string): ProjectInfo[\"resolve\"] {\n for (const file of [\"tsconfig.json\", \"jsconfig.json\"]) {\n const path = join(root, file);\n if (!existsSync(path)) continue;\n\n let parsed: { compilerOptions?: { paths?: Record<string, string[]> } };\n try {\n // Strip comments and trailing commas: tsconfig is JSON with extensions,\n // and real projects use both.\n const raw = readFileSync(path, \"utf8\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\")\n .replace(/(^|[^:])\\/\\/.*$/gm, \"$1\")\n .replace(/,(\\s*[}\\]])/g, \"$1\");\n parsed = JSON.parse(raw) as typeof parsed;\n } catch {\n continue;\n }\n\n const paths = parsed.compilerOptions?.paths;\n if (!paths) continue;\n\n for (const [alias, targets] of Object.entries(paths)) {\n const target = targets[0];\n if (!alias.endsWith(\"/*\") || target === undefined || !target.endsWith(\"/*\")) continue;\n\n return {\n prefix: alias.slice(0, -1),\n base: target.slice(0, -2).replace(/^\\.\\//, \"\").replace(/\\/$/, \"\"),\n };\n }\n }\n\n return undefined;\n}\n\nexport function inspectProject(root: string): ProjectInfo {\n const packageJson = readPackageJson(root);\n\n return {\n root,\n packageManager: detectPackageManager(root),\n packageJson,\n isTypeScript: existsSync(join(root, \"tsconfig.json\")),\n reactVersion: versionOf(packageJson, \"react\"),\n tailwindVersion: versionOf(packageJson, \"tailwindcss\"),\n framework: detectFramework(packageJson),\n cssEntry: findCssEntry(root),\n resolve: detectResolve(root),\n };\n}\n\n/**\n * Refuses to proceed on a project this version cannot support correctly.\n *\n * Every check here fails loudly on purpose. Writing v4 token syntax into a v3\n * project, or TypeScript source into a JavaScript one, produces a project that\n * does not build — and the person debugging it has no reason to suspect the\n * install rather than their own code.\n */\nexport function assertSupported(project: ProjectInfo): void {\n if (!project.reactVersion) {\n throw new CliError(\n \"This does not look like a React project — react is not in package.json.\",\n \"Run this from the root of a React application.\",\n );\n }\n\n if (!project.isTypeScript) {\n throw new CliError(\n \"JavaScript projects are not supported yet.\",\n \"The published components are TypeScript. Add a tsconfig.json, or wait for JS output in a future release.\",\n );\n }\n\n const tailwindMajor = majorVersion(project.tailwindVersion);\n\n if (tailwindMajor === undefined) {\n throw new CliError(\n \"Tailwind CSS is not installed.\",\n \"Install tailwindcss v4 and its plugin for your bundler, then run init again.\",\n );\n }\n\n if (tailwindMajor < 4) {\n throw new CliError(\n `Tailwind CSS v${String(tailwindMajor)} is not supported — v4 or later is required.`,\n \"The design tokens are defined with @theme, which v3 cannot parse. Upgrade to Tailwind v4 first.\",\n );\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n registryIndexSchema,\n registryItemSchema,\n type RegistryIndex,\n type RegistryItem,\n} from \"@dowel-ui/registry\";\n\nimport { CliError } from \"./errors\";\n\n/**\n * Reads the registry over HTTP, or from a directory on disk.\n *\n * The local path form is not a testing shortcut bolted on afterwards — it is\n * how private forks and enterprise mirrors are meant to work, and it is what\n * lets the end-to-end tests run against a registry built in the same commit\n * rather than against whatever happens to be deployed.\n */\nfunction isHttp(baseUrl: string): boolean {\n return baseUrl.startsWith(\"http://\") || baseUrl.startsWith(\"https://\");\n}\n\nfunction localPath(baseUrl: string, file: string): string {\n const root = baseUrl.startsWith(\"file:\") ? fileURLToPath(baseUrl) : baseUrl;\n return join(root, file);\n}\n\nasync function readJson(baseUrl: string, file: string, what: string): Promise<unknown> {\n if (!isHttp(baseUrl)) {\n const path = localPath(baseUrl, file);\n if (!existsSync(path)) {\n throw new CliError(`${what} not found at ${path}.`);\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n throw new CliError(`${what} at ${path} is not valid JSON.`);\n }\n }\n\n const url = `${baseUrl.replace(/\\/$/, \"\")}/${file}`;\n let response: Response;\n try {\n response = await fetch(url);\n } catch (cause) {\n throw new CliError(\n `Could not reach the registry at ${url}.`,\n cause instanceof Error ? cause.message : undefined,\n );\n }\n\n if (response.status === 404) {\n throw new CliError(`${what} not found in the registry.`);\n }\n if (!response.ok) {\n throw new CliError(`Registry returned ${String(response.status)} for ${url}.`);\n }\n\n try {\n return await response.json();\n } catch {\n throw new CliError(`${what} at ${url} is not valid JSON.`);\n }\n}\n\nexport async function fetchIndex(baseUrl: string): Promise<RegistryIndex> {\n const raw = await readJson(baseUrl, \"index.json\", \"Registry index\");\n const parsed = registryIndexSchema.safeParse(raw);\n\n if (!parsed.success) {\n throw new CliError(\n \"The registry index does not match the format this CLI understands.\",\n \"Update the CLI, or point --registry at a compatible registry.\",\n );\n }\n\n return parsed.data;\n}\n\nexport async function fetchItem(baseUrl: string, name: string): Promise<RegistryItem> {\n const raw = await readJson(baseUrl, `${name}.json`, `Component \"${name}\"`);\n const parsed = registryItemSchema.safeParse(raw);\n\n if (!parsed.success) {\n throw new CliError(\n `Registry entry \"${name}\" does not match the format this CLI understands.`,\n \"Update the CLI, or point --registry at a compatible registry.\",\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Resolves items and everything they depend on, dependencies first.\n *\n * Depth-first post-order, so a component is always ordered after the things it\n * imports. A breadth-first walk reversed looks equivalent and is not: if two\n * requested items depend on each other's subtrees it produces the wrong order.\n * The visiting set makes a dependency cycle terminate rather than recurse\n * forever.\n */\nexport async function resolveItems(baseUrl: string, names: string[]): Promise<RegistryItem[]> {\n const cache = new Map<string, RegistryItem>();\n const ordered: RegistryItem[] = [];\n const placed = new Set<string>();\n const visiting = new Set<string>();\n\n async function load(name: string): Promise<RegistryItem> {\n const cached = cache.get(name);\n if (cached) return cached;\n\n const item = await fetchItem(baseUrl, name);\n cache.set(name, item);\n return item;\n }\n\n async function visit(name: string): Promise<void> {\n if (placed.has(name) || visiting.has(name)) return;\n visiting.add(name);\n\n const item = await load(name);\n for (const dependency of item.registryDependencies) {\n await visit(dependency);\n }\n\n visiting.delete(name);\n placed.add(name);\n ordered.push(item);\n }\n\n for (const name of names) {\n await visit(name);\n }\n\n return ordered;\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { hashContent, type RegistryItem } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig, type Config } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { installDependencies, missingDependencies } from \"../lib/package-manager\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { inspectProject } from \"../lib/project\";\nimport { resolveItems } from \"../lib/registry-client\";\n\nexport interface AddOptions {\n cwd: string;\n registry?: string;\n yes: boolean;\n overwrite: boolean;\n skipInstall: boolean;\n}\n\n/** What `add` intends to do with one file, decided before anything is written. */\nexport type FileAction = \"write\" | \"unchanged\" | \"modified\";\n\nexport interface PlannedFile {\n destination: string;\n content: string;\n hash: string;\n action: FileAction;\n}\n\n/**\n * Classifies an existing file against what we previously wrote there.\n *\n * Three outcomes, and the distinction matters. A file whose content still\n * matches what we installed is ours to replace silently, which is what makes\n * re-running `add` a no-op. A file that differs from what we installed has been\n * edited by the user — the entire point of a source-first library — and must\n * never be overwritten without them saying so.\n */\nexport function classifyFile(\n absolutePath: string,\n incomingHash: string,\n recordedHash: string | undefined,\n): FileAction {\n if (!existsSync(absolutePath)) return \"write\";\n\n const currentHash = hashContent(readFileSync(absolutePath, \"utf8\"));\n\n if (currentHash === incomingHash) return \"unchanged\";\n // Still exactly what we last wrote, just superseded upstream: ours to replace.\n if (recordedHash !== undefined && currentHash === recordedHash) return \"write\";\n\n return \"modified\";\n}\n\nexport function planFiles(cwd: string, config: Config, items: RegistryItem[]): PlannedFile[] {\n const planned: PlannedFile[] = [];\n\n for (const item of items) {\n const recorded = config.installed[item.name]?.files ?? {};\n\n for (const file of item.files) {\n if (file.type === \"registry:style\") continue;\n\n const destination = resolveDestination(config, file.path);\n const content = rewriteImports(file.content, config);\n // Hashed after rewriting, because the rewritten text is what actually\n // lands on disk — comparing against the published text would report every\n // file as modified in any project that does not use the `@/` prefix.\n const hash = hashContent(content);\n\n planned.push({\n destination,\n content,\n hash,\n action: classifyFile(join(cwd, destination), hash, recorded[destination]),\n });\n }\n }\n\n return planned;\n}\n\nexport async function add(names: string[], options: AddOptions): Promise<void> {\n if (names.length === 0) {\n throw new CliError(\n \"Name at least one component to add.\",\n \"For example: `add button dialog`.\",\n );\n }\n\n const { cwd, yes, overwrite } = options;\n const config = readConfig(cwd);\n const registry = options.registry ?? config.registry;\n const project = inspectProject(cwd);\n\n const items = await resolveItems(registry, names);\n const requested = new Set(names);\n const pulledIn = items.filter((item) => !requested.has(item.name));\n\n const planned = planFiles(cwd, config, items);\n const toWrite = planned.filter((file) => file.action === \"write\");\n const modified = planned.filter((file) => file.action === \"modified\");\n const unchanged = planned.filter((file) => file.action === \"unchanged\");\n\n if (modified.length > 0 && !overwrite) {\n logger.warn(\"These files have local changes and were left alone:\");\n for (const file of modified) logger.info(` ${file.destination}`);\n logger.blank();\n logger.info(pc.dim(\"Re-run with --overwrite to replace them.\"));\n\n if (toWrite.length === 0) {\n logger.blank();\n logger.info(\"Nothing else to do.\");\n return;\n }\n }\n\n const writable = overwrite ? [...toWrite, ...modified] : toWrite;\n\n if (writable.length === 0) {\n logger.success(unchanged.length > 0 ? \"Already up to date.\" : \"Nothing to write.\");\n return;\n }\n\n const dependencies = [...new Set(items.flatMap((item) => item.dependencies))];\n const missing = missingDependencies(\n { ...project.packageJson.dependencies, ...project.packageJson.devDependencies },\n dependencies,\n );\n\n if (!yes) {\n logger.info(pc.dim(\"Will write:\"));\n for (const file of writable) logger.info(` ${file.destination}`);\n if (pulledIn.length > 0) {\n logger.info(\n pc.dim(`Pulled in as dependencies: ${pulledIn.map((i) => i.name).join(\", \")}`),\n );\n }\n if (missing.length > 0) logger.info(pc.dim(`Will install: ${missing.join(\", \")}`));\n logger.blank();\n\n const proceed = await prompts.confirm({ message: \"Continue?\", initialValue: true });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n for (const file of writable) {\n const absolute = join(cwd, file.destination);\n mkdirSync(dirname(absolute), { recursive: true });\n writeFileSync(absolute, file.content);\n }\n\n // Recorded after writing, and only for files that actually landed, so the\n // config never claims to have installed something it did not.\n const writtenPaths = new Set(writable.map((file) => file.destination));\n for (const item of items) {\n const files: Record<string, string> = { ...config.installed[item.name]?.files };\n\n for (const file of planFiles(cwd, config, [item])) {\n if (writtenPaths.has(file.destination) || file.action === \"unchanged\") {\n files[file.destination] = file.hash;\n }\n }\n\n if (Object.keys(files).length > 0) {\n config.installed[item.name] = {\n from: item.registryVersion.toString(),\n files,\n dependsOn: item.registryDependencies,\n };\n }\n }\n\n writeConfig(cwd, config);\n\n if (missing.length > 0 && !options.skipInstall) {\n installDependencies(project.packageManager, cwd, missing);\n }\n\n logger.blank();\n logger.success(`Added ${items.map((item) => item.name).join(\", \")}`);\n if (missing.length > 0) {\n logger.success(\n options.skipInstall\n ? `Install these yourself: ${missing.join(\" \")}`\n : `Installed ${missing.join(\", \")}`,\n );\n }\n logger.blank();\n logger.info(pc.dim(\"Files:\"));\n for (const file of writable) logger.info(` ${file.destination}`);\n if (unchanged.length > 0) {\n logger.info(pc.dim(` (${String(unchanged.length)} already up to date)`));\n }\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { branding } from \"../branding\";\nimport { configExists, writeConfig, type Config } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { installDependencies, missingDependencies } from \"../lib/package-manager\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { assertSupported, inspectProject } from \"../lib/project\";\nimport { fetchItem } from \"../lib/registry-client\";\n\nexport interface InitOptions {\n cwd: string;\n registry: string;\n yes: boolean;\n skipInstall: boolean;\n}\n\n/** Header the registry puts at the top of the token block. */\nexport const TOKENS_MARKER = \"/* Design tokens. Safe to edit — this is your copy. */\";\n\n/**\n * Appends the design tokens to the project stylesheet.\n *\n * Appended rather than written as a new file, and inserted after the Tailwind\n * import rather than at the top, because `@theme` has to be processed by\n * Tailwind. The existing stylesheet is never rewritten — whatever the project\n * already had stays exactly where it was.\n *\n * Two separate idempotence checks, because they catch different things. The\n * marker survives the user editing their tokens, which they are meant to do —\n * a content check alone would re-insert the whole block over their changes. The\n * content check covers a token block that carries no marker.\n */\nexport function insertTokens(stylesheet: string, tokens: string): string {\n if (stylesheet.includes(TOKENS_MARKER)) return stylesheet;\n if (stylesheet.includes(tokens.trim())) return stylesheet;\n\n const importMatch = /^[^\\n]*@import\\s+[\"']tailwindcss[\"'][^\\n]*$/m.exec(stylesheet);\n\n if (!importMatch) {\n return `${stylesheet.trimEnd()}\\n\\n${tokens.trim()}\\n`;\n }\n\n const insertAt = importMatch.index + importMatch[0].length;\n return `${stylesheet.slice(0, insertAt)}\\n\\n${tokens.trim()}\\n${stylesheet.slice(insertAt)}`;\n}\n\nexport async function init(options: InitOptions): Promise<void> {\n const { cwd, registry, yes } = options;\n\n if (configExists(cwd) && !yes) {\n const overwrite = await prompts.confirm({\n message: \"components.json already exists. Overwrite it?\",\n initialValue: false,\n });\n if (prompts.isCancel(overwrite) || !overwrite) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n const project = inspectProject(cwd);\n assertSupported(project);\n\n logger.step(`Detected ${pc.bold(project.framework)} · ${pc.bold(project.packageManager)}`);\n\n let resolve = project.resolve;\n if (!resolve) {\n if (yes) {\n throw new CliError(\n \"Could not read a path alias from tsconfig.json.\",\n 'Add something like `\"paths\": { \"@/*\": [\"./src/*\"] }` and run init again.',\n );\n }\n\n const prefix = await prompts.text({\n message: \"What import alias do you use?\",\n placeholder: \"@/\",\n initialValue: \"@/\",\n });\n const base = await prompts.text({\n message: \"Which directory does it point at?\",\n placeholder: \"src\",\n initialValue: \"src\",\n });\n\n if (prompts.isCancel(prefix) || prompts.isCancel(base)) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n resolve = { prefix, base };\n }\n\n let cssEntry = project.cssEntry;\n if (!cssEntry) {\n if (yes) {\n throw new CliError(\n \"Could not find a stylesheet that imports Tailwind.\",\n 'Create one containing `@import \"tailwindcss\";` and run init again.',\n );\n }\n\n const answer = await prompts.text({\n message: \"Where is the stylesheet that imports Tailwind?\",\n placeholder: \"src/index.css\",\n });\n if (prompts.isCancel(answer) || !answer) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n cssEntry = answer;\n }\n\n const config: Config = {\n $schema: `${branding.registryUrl}/schema/components.json`,\n version: 1,\n typescript: true,\n registry,\n tailwind: { css: cssEntry },\n aliases: {\n components: `${resolve.prefix}components`,\n ui: `${resolve.prefix}components/ui`,\n lib: `${resolve.prefix}lib`,\n hooks: `${resolve.prefix}hooks`,\n utils: `${resolve.prefix}lib/utils`,\n blocks: `${resolve.prefix}components/blocks`,\n },\n resolve,\n installed: {},\n };\n\n const utils = await fetchItem(registry, \"utils\");\n const theme = await fetchItem(registry, \"theme\");\n\n const written: string[] = [];\n const installedFiles: Record<string, string> = {};\n\n for (const file of utils.files) {\n const destination = resolveDestination(config, file.path);\n const absolute = join(cwd, destination);\n\n if (existsSync(absolute)) {\n logger.step(`${pc.dim(\"skipped\")} ${destination} ${pc.dim(\"(already exists)\")}`);\n continue;\n }\n\n mkdirSync(dirname(absolute), { recursive: true });\n const content = rewriteImports(file.content, config);\n writeFileSync(absolute, content);\n installedFiles[destination] = file.hash;\n written.push(destination);\n }\n\n config.installed.utils = { from: utils.registryVersion.toString(), files: installedFiles };\n\n const stylesheetPath = join(cwd, cssEntry);\n if (!existsSync(stylesheetPath)) {\n throw new CliError(`Stylesheet not found at ${cssEntry}.`);\n }\n\n const tokens = theme.files[0]?.content ?? \"\";\n const stylesheet = readFileSync(stylesheetPath, \"utf8\");\n const updated = insertTokens(stylesheet, tokens);\n\n if (updated === stylesheet) {\n logger.step(`${pc.dim(\"skipped\")} ${cssEntry} ${pc.dim(\"(tokens already present)\")}`);\n } else {\n writeFileSync(stylesheetPath, updated);\n written.push(cssEntry);\n }\n\n config.installed.theme = {\n from: theme.registryVersion.toString(),\n files: { [cssEntry]: theme.files[0]?.hash ?? \"\" },\n };\n\n writeConfig(cwd, config);\n written.unshift(\"components.json\");\n\n const required = [...utils.dependencies];\n const missing = missingDependencies(\n { ...project.packageJson.dependencies, ...project.packageJson.devDependencies },\n required,\n );\n\n if (missing.length > 0 && !options.skipInstall) {\n logger.step(`Installing ${missing.join(\", \")}`);\n installDependencies(project.packageManager, cwd, missing);\n }\n\n logger.blank();\n logger.success(\"Project initialised.\");\n logger.blank();\n logger.info(pc.dim(\"Files:\"));\n for (const file of written) logger.info(` ${file}`);\n if (missing.length > 0) {\n logger.blank();\n logger.info(pc.dim(options.skipInstall ? \"Install manually:\" : \"Dependencies:\"));\n logger.info(` ${missing.join(\" \")}`);\n }\n logger.blank();\n // The npx form rather than the bare binary: whoever ran this through npx\n // has no `dowel` on their PATH, and pointing them at a command they do not\n // have is a poor first impression.\n logger.info(`Next: ${pc.bold(`npx ${branding.cliPackage} add button`)}`);\n}\n","import { configExists, readConfig } from \"../lib/config\";\nimport { logger, pc } from \"../lib/logger\";\nimport { fetchIndex } from \"../lib/registry-client\";\nimport { branding } from \"../branding\";\n\nexport interface ListOptions {\n cwd: string;\n registry?: string;\n category?: string;\n json: boolean;\n}\n\nexport async function list(options: ListOptions): Promise<void> {\n // Usable before init: browsing what exists should not require a project.\n const config = configExists(options.cwd) ? readConfig(options.cwd) : undefined;\n const registry = options.registry ?? config?.registry ?? branding.registryUrl;\n\n const index = await fetchIndex(registry);\n const installed = new Set(Object.keys(config?.installed ?? {}));\n\n const items = index.items\n .filter((item) => item.type === \"registry:ui\")\n .filter((item) => !options.category || item.category === options.category);\n\n if (options.json) {\n logger.info(\n JSON.stringify(\n items.map((item) => ({ ...item, installed: installed.has(item.name) })),\n null,\n 2,\n ),\n );\n return;\n }\n\n if (items.length === 0) {\n logger.warn(\n options.category\n ? `No components in category \"${options.category}\".`\n : \"The registry has no components.\",\n );\n return;\n }\n\n const byCategory = new Map<string, typeof items>();\n for (const item of items) {\n byCategory.set(item.category, [...(byCategory.get(item.category) ?? []), item]);\n }\n\n const width = Math.max(...items.map((item) => item.name.length));\n\n for (const [category, categoryItems] of [...byCategory].sort()) {\n logger.blank();\n logger.info(pc.bold(category));\n for (const item of categoryItems) {\n const mark = installed.has(item.name) ? pc.green(\"✓\") : \" \";\n logger.info(` ${mark} ${item.name.padEnd(width)} ${pc.dim(item.description)}`);\n }\n }\n\n logger.blank();\n logger.info(\n pc.dim(\n `${String(items.length)} components · ${String(installed.size)} installed · ${registry}`,\n ),\n );\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, readFileSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { hashContent } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\n\nexport interface RemoveOptions {\n cwd: string;\n yes: boolean;\n /** Delete files that no longer match what was installed. */\n force: boolean;\n}\n\nexport type RemovalState = \"unchanged\" | \"modified\" | \"missing\";\n\nexport interface PlannedRemoval {\n component: string;\n path: string;\n state: RemovalState;\n}\n\n/**\n * Classifies a file before deleting it.\n *\n * Deleting is the one irreversible thing this CLI does, so it distinguishes a\n * file still exactly as installed — safe to remove — from one that has been\n * edited, which is the user's work and not ours to throw away.\n */\nexport function classifyRemoval(\n absolutePath: string,\n recordedHash: string | undefined,\n): RemovalState {\n if (!existsSync(absolutePath)) return \"missing\";\n if (recordedHash === undefined) return \"modified\";\n return hashContent(readFileSync(absolutePath, \"utf8\")) === recordedHash\n ? \"unchanged\"\n : \"modified\";\n}\n\n/**\n * Components that other installed entries still import.\n *\n * Removing a component something else depends on would break the project, so\n * those are reported and skipped rather than deleted with a warning after the\n * fact.\n */\nexport function findDependents(\n installed: Record<string, { files: Record<string, string> }>,\n registryDependencies: Map<string, string[]>,\n removing: Set<string>,\n): Map<string, string[]> {\n const blockers = new Map<string, string[]>();\n\n for (const name of removing) {\n const dependents = Object.keys(installed).filter(\n (candidate) =>\n !removing.has(candidate) && (registryDependencies.get(candidate) ?? []).includes(name),\n );\n if (dependents.length > 0) blockers.set(name, dependents);\n }\n\n return blockers;\n}\n\nexport async function remove(names: string[], options: RemoveOptions): Promise<void> {\n if (names.length === 0) {\n throw new CliError(\"Name at least one component to remove.\");\n }\n\n const { cwd } = options;\n const config = readConfig(cwd);\n\n const unknown = names.filter((name) => !(name in config.installed));\n if (unknown.length > 0) {\n throw new CliError(\n `Not installed: ${unknown.join(\", \")}.`,\n \"Run `list` to see what is installed.\",\n );\n }\n\n // Dependency edges are read from what was installed, not fetched: removing\n // something should not need the registry to be reachable.\n const registryDependencies = new Map<string, string[]>();\n for (const [name, entry] of Object.entries(config.installed)) {\n registryDependencies.set(name, entry.dependsOn ?? []);\n }\n\n const removing = new Set(names);\n const blockers = findDependents(config.installed, registryDependencies, removing);\n\n if (blockers.size > 0) {\n logger.error(\"These are still needed by something else:\");\n for (const [name, dependents] of blockers) {\n logger.info(` ${name} — required by ${dependents.join(\", \")}`);\n }\n throw new CliError(\"Nothing was removed.\", \"Remove the dependents first, or keep these.\");\n }\n\n const planned: PlannedRemoval[] = [];\n for (const name of names) {\n for (const [path, hash] of Object.entries(config.installed[name]?.files ?? {})) {\n planned.push({ component: name, path, state: classifyRemoval(join(cwd, path), hash) });\n }\n }\n\n const modified = planned.filter((file) => file.state === \"modified\");\n const deletable = planned.filter(\n (file) => file.state === \"unchanged\" || (options.force && file.state === \"modified\"),\n );\n\n if (modified.length > 0 && !options.force) {\n logger.warn(\"These have local changes and will be kept:\");\n for (const file of modified) logger.info(` ${file.path}`);\n logger.blank();\n logger.info(pc.dim(\"Re-run with --force to delete them as well.\"));\n }\n\n if (deletable.length === 0) {\n logger.blank();\n logger.info(\"Nothing to delete.\");\n return;\n }\n\n if (!options.yes) {\n logger.info(pc.dim(\"Will delete:\"));\n for (const file of deletable) logger.info(` ${file.path}`);\n logger.blank();\n\n const proceed = await prompts.confirm({\n message: `Delete ${String(deletable.length)} file(s)?`,\n initialValue: false,\n });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was deleted.\");\n }\n }\n\n for (const file of deletable) {\n rmSync(join(cwd, file.path), { force: true });\n }\n\n // An entry whose files were kept stays recorded, so `update` still knows what\n // it wrote there.\n const deleted = new Set(deletable.map((file) => file.path));\n for (const name of names) {\n const entry = config.installed[name];\n if (!entry) continue;\n\n const remaining = Object.fromEntries(\n Object.entries(entry.files).filter(([path]) => !deleted.has(path)),\n );\n\n if (Object.keys(remaining).length === 0) delete config.installed[name];\n else entry.files = remaining;\n }\n\n writeConfig(cwd, config);\n\n logger.blank();\n logger.success(`Removed ${String(deletable.length)} file(s).`);\n if (modified.length > 0 && !options.force) {\n logger.warn(`${String(modified.length)} locally modified file(s) were kept.`);\n }\n logger.blank();\n logger.info(pc.dim(\"npm packages are left installed — other code may still use them.\"));\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { hashContent } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { fetchItem } from \"../lib/registry-client\";\n\nexport interface UpdateOptions {\n cwd: string;\n registry?: string;\n overwrite: boolean;\n yes: boolean;\n}\n\nexport type UpdateState = \"current\" | \"outdated\" | \"modified\" | \"conflict\" | \"missing\";\n\nexport interface UpdateReport {\n component: string;\n destination: string;\n state: UpdateState;\n content: string;\n hash: string;\n}\n\n/**\n * Compares three versions of a file: what the registry has now, what we\n * installed, and what is on disk.\n *\n * The three-way comparison is why the install hash had to be recorded from the\n * very first release. Without it there is no way to distinguish \"the user\n * edited this\" from \"upstream changed this\", and the only safe behaviour left\n * is to never update anything.\n */\nexport function compareFile(\n absolutePath: string,\n incomingHash: string,\n recordedHash: string | undefined,\n): UpdateState {\n if (!existsSync(absolutePath)) return \"missing\";\n\n const currentHash = hashContent(readFileSync(absolutePath, \"utf8\"));\n\n if (currentHash === incomingHash) return \"current\";\n if (recordedHash === undefined) return \"conflict\";\n if (currentHash === recordedHash) return \"outdated\";\n\n // Changed on both sides. Overwriting would silently discard the user's work,\n // which in a source-first library is the whole thing they were promised.\n return incomingHash === recordedHash ? \"modified\" : \"conflict\";\n}\n\nconst STATE_LABEL: Record<UpdateState, string> = {\n current: \"up to date\",\n outdated: \"update available\",\n modified: \"locally modified\",\n conflict: \"modified, and changed upstream\",\n missing: \"missing\",\n};\n\nexport async function update(names: string[], options: UpdateOptions): Promise<void> {\n const { cwd } = options;\n const config = readConfig(cwd);\n const registry = options.registry ?? config.registry;\n\n const targets = names.length > 0 ? names : Object.keys(config.installed);\n\n if (targets.length === 0) {\n throw new CliError(\"Nothing is installed yet.\", \"Add a component first.\");\n }\n\n const unknown = targets.filter((name) => !(name in config.installed));\n if (unknown.length > 0) {\n throw new CliError(\n `Not installed: ${unknown.join(\", \")}.`,\n \"Run `list` to see what is installed.\",\n );\n }\n\n const reports: UpdateReport[] = [];\n\n for (const name of targets) {\n const item = await fetchItem(registry, name);\n const recorded = config.installed[name]?.files ?? {};\n\n for (const file of item.files) {\n if (file.type === \"registry:style\") continue;\n\n const destination = resolveDestination(config, file.path);\n const content = rewriteImports(file.content, config);\n const hash = hashContent(content);\n\n reports.push({\n component: name,\n destination,\n hash,\n content,\n state: compareFile(join(cwd, destination), hash, recorded[destination]),\n });\n }\n }\n\n const actionable = reports.filter(\n (report) => report.state === \"outdated\" || report.state === \"missing\",\n );\n const conflicts = reports.filter(\n (report) => report.state === \"conflict\" || report.state === \"modified\",\n );\n\n logger.blank();\n for (const report of reports) {\n const colour =\n report.state === \"current\"\n ? pc.dim\n : report.state === \"outdated\" || report.state === \"missing\"\n ? pc.yellow\n : pc.red;\n logger.info(` ${colour(STATE_LABEL[report.state].padEnd(30))} ${report.destination}`);\n }\n logger.blank();\n\n if (actionable.length === 0 && conflicts.length === 0) {\n logger.success(\"Everything is up to date.\");\n return;\n }\n\n const writable = options.overwrite ? [...actionable, ...conflicts] : actionable;\n\n if (writable.length === 0) {\n logger.warn(\"Only locally modified files differ; none were touched.\");\n logger.info(pc.dim(\"Re-run with --overwrite to replace them and lose those edits.\"));\n return;\n }\n\n if (!options.yes) {\n const proceed = await prompts.confirm({\n message: options.overwrite\n ? `Overwrite ${String(writable.length)} file(s), discarding any local changes?`\n : `Update ${String(writable.length)} file(s)?`,\n initialValue: !options.overwrite,\n });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n for (const report of writable) {\n writeFileSync(join(cwd, report.destination), report.content);\n\n const entry = config.installed[report.component];\n if (entry) entry.files[report.destination] = report.hash;\n }\n\n writeConfig(cwd, config);\n\n logger.blank();\n logger.success(`Updated ${String(writable.length)} file(s).`);\n if (!options.overwrite && conflicts.length > 0) {\n logger.warn(`${String(conflicts.length)} locally modified file(s) were left alone.`);\n }\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\n\nimport { Command } from \"commander\";\n\nimport { branding } from \"./branding\";\nimport { add } from \"./commands/add\";\nimport { init } from \"./commands/init\";\nimport { list } from \"./commands/list\";\nimport { remove } from \"./commands/remove\";\nimport { update } from \"./commands/update\";\nimport { CliError } from \"./lib/errors\";\nimport { logger, pc } from \"./lib/logger\";\n\n/**\n * Read from the manifest rather than hardcoded, so `--version` cannot drift\n * away from what was actually published. `src/index.ts` and the built\n * `dist/index.js` both sit one directory below package.json, so this resolves\n * to the same file whether the CLI is run from source or from the tarball.\n */\nconst { version } = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(branding.cliName)\n .description(`Add ${branding.libraryName} components to your project as source you own.`)\n .version(version)\n .option(\"-c, --cwd <path>\", \"project root\", process.cwd())\n .option(\"-r, --registry <url>\", \"registry base URL, or a directory on disk\");\n\ninterface GlobalOptions {\n cwd: string;\n registry?: string;\n}\n\nfunction globals(): GlobalOptions {\n return program.opts<GlobalOptions>();\n}\n\nprogram\n .command(\"init\")\n .description(\"set the project up: config, utilities and design tokens\")\n .option(\"-y, --yes\", \"accept every default and never prompt\", false)\n .option(\"--skip-install\", \"write files but do not install dependencies\", false)\n .action(async (options: { yes: boolean; skipInstall: boolean }) => {\n const { cwd, registry } = globals();\n await init({\n cwd,\n registry: registry ?? branding.registryUrl,\n yes: options.yes,\n skipInstall: options.skipInstall,\n });\n });\n\nprogram\n .command(\"add\")\n .description(\"add one or more components, with everything they depend on\")\n .argument(\"[components...]\", \"component names\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-o, --overwrite\", \"replace files that have local changes\", false)\n .option(\"--skip-install\", \"write files but do not install dependencies\", false)\n .action(\n async (\n components: string[],\n options: { yes: boolean; overwrite: boolean; skipInstall: boolean },\n ) => {\n const { cwd, registry } = globals();\n await add(components, {\n cwd,\n registry,\n yes: options.yes,\n overwrite: options.overwrite,\n skipInstall: options.skipInstall,\n });\n },\n );\n\nprogram\n .command(\"list\")\n .alias(\"ls\")\n .description(\"list everything in the registry, marking what is installed\")\n .option(\"--category <name>\", \"show one category only\")\n .option(\"--json\", \"machine-readable output\", false)\n .action(async (options: { category?: string; json: boolean }) => {\n const { cwd, registry } = globals();\n await list({ cwd, registry, category: options.category, json: options.json });\n });\n\nprogram\n .command(\"remove\")\n .alias(\"rm\")\n .description(\"delete installed components, keeping anything you have edited\")\n .argument(\"[components...]\", \"component names\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-f, --force\", \"delete files that have local changes too\", false)\n .action(async (components: string[], options: { yes: boolean; force: boolean }) => {\n const { cwd } = globals();\n await remove(components, { cwd, yes: options.yes, force: options.force });\n });\n\nprogram\n .command(\"update\")\n .description(\"compare installed components against the registry\")\n .argument(\"[components...]\", \"component names; defaults to everything installed\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-o, --overwrite\", \"replace files that have local changes\", false)\n .action(async (components: string[], options: { yes: boolean; overwrite: boolean }) => {\n const { cwd, registry } = globals();\n await update(components, {\n cwd,\n registry,\n yes: options.yes,\n overwrite: options.overwrite,\n });\n });\n\n/**\n * A CliError is a message for the person running the command; anything else is\n * a bug, and its stack trace is the useful part.\n */\nasync function main(): Promise<void> {\n try {\n await program.parseAsync(process.argv);\n } catch (error) {\n logger.blank();\n if (error instanceof CliError) {\n logger.error(error.message);\n if (error.hint) logger.info(pc.dim(` ${error.hint}`));\n } else {\n logger.error(\"Something went wrong.\");\n logger.info(String(error instanceof Error ? (error.stack ?? error.message) : error));\n }\n logger.blank();\n process.exitCode = 1;\n }\n}\n\nvoid main();\n\nexport { add, init, list, remove, update };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/branding.ts","../../registry/dist/schema-ByqIpT47.js","../src/lib/errors.ts","../src/lib/config.ts","../src/lib/logger.ts","../src/lib/package-manager.ts","../src/lib/paths.ts","../src/lib/project.ts","../src/lib/registry-client.ts","../src/commands/add.ts","../src/commands/init.ts","../src/commands/list.ts","../src/commands/remove.ts","../src/commands/update.ts","../src/index.ts"],"sourcesContent":["/**\n * Branding, mirrored from the repository root config.\n *\n * Duplicated deliberately: the published CLI cannot import from the monorepo\n * root, and `pnpm rebrand` rewrites both copies in the same pass.\n */\nexport const branding = {\n libraryName: \"Dowel\",\n cliName: \"dowel\",\n /**\n * The npm package name, which is NOT the command name. npm rejected the\n * unscoped `dowel` as too similar to `del` and `bower` — a rule that runs\n * only at publish time, so a 404 from the registry proves a name is unused,\n * never that it can be claimed. This is what follows `npx`; `cliName` is the\n * binary the package installs.\n */\n cliPackage: \"@dowel-ui/cli\",\n registryUrl: \"https://dowel-eight.vercel.app/r\",\n} as const;\n","import { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\n//#region src/hash.ts\n/**\n* Content hash used to detect local edits to an installed file.\n*\n* Line endings are normalised before hashing so a Windows checkout does not\n* read as \"every file modified\", which would make `update` useless there.\n*/\nfunction hashContent(content) {\n\tconst normalised = content.replace(/\\r\\n/g, \"\\n\");\n\treturn `sha256:${createHash(\"sha256\").update(normalised, \"utf8\").digest(\"hex\")}`;\n}\n//#endregion\n//#region src/schema.ts\n/**\n* The public registry contract.\n*\n* This is the boundary between the library and every consumer's project, so it\n* is validated on both sides: the build refuses to emit anything that does not\n* satisfy it, and the CLI refuses to install anything that does not parse. A\n* registry that serves malformed data breaks builds in someone else's\n* repository, where it is hardest to diagnose.\n*/\n/** Bumped only for a breaking change to the shape below. */\nconst REGISTRY_VERSION = 1;\nconst registryFileTypeSchema = z.enum([\n\t\"registry:ui\",\n\t\"registry:lib\",\n\t\"registry:hook\",\n\t\"registry:block\",\n\t\"registry:style\"\n]);\nconst registryItemTypeSchema = z.enum([\n\t\"registry:ui\",\n\t\"registry:lib\",\n\t\"registry:hook\",\n\t\"registry:theme\",\n\t\"registry:block\"\n]);\nconst registryFileSchema = z.object({\n\t/**\n\t* Logical path within the registry, e.g. `ui/button.tsx`, `lib/utils.ts`.\n\t*\n\t* The leading segment selects which of the consumer's aliases the file is\n\t* written under. The registry deliberately does not know the destination —\n\t* that depends on a project layout it has never seen.\n\t*/\n\tpath: z.string().min(1),\n\ttype: registryFileTypeSchema,\n\tcontent: z.string(),\n\t/**\n\t* `sha256:<hex>` of `content` as published.\n\t*\n\t* Recorded at install time so `update` can tell an untouched file from one\n\t* the user has edited. This cannot be added later: an install that did not\n\t* record a hash leaves no way to know what it originally wrote.\n\t*/\n\thash: z.string().regex(/^sha256:[0-9a-f]{64}$/)\n});\nconst registryItemSchema = z.object({\n\t$schema: z.string().optional(),\n\tregistryVersion: z.literal(1),\n\tname: z.string().regex(/^[a-z][a-z0-9-]*$/),\n\ttype: registryItemTypeSchema,\n\ttitle: z.string().min(1),\n\tdescription: z.string().min(10),\n\tcategory: z.string().min(1),\n\tstatus: z.enum([\n\t\t\"stable\",\n\t\t\"beta\",\n\t\t\"experimental\"\n\t]),\n\t/** npm packages to install alongside the files. */\n\tdependencies: z.array(z.string()),\n\t/** Other registry items to install first. */\n\tregistryDependencies: z.array(z.string()),\n\tfiles: z.array(registryFileSchema).min(1),\n\ta11y: z.string().optional()\n});\nconst registryIndexEntrySchema = registryItemSchema.pick({\n\tname: true,\n\ttype: true,\n\ttitle: true,\n\tdescription: true,\n\tcategory: true,\n\tstatus: true,\n\tdependencies: true,\n\tregistryDependencies: true\n}).extend({ fileCount: z.number().int().positive() });\nconst registryIndexSchema = z.object({\n\t$schema: z.string().optional(),\n\tregistryVersion: z.literal(1),\n\t/** Version of the package the registry was generated from. */\n\tgeneratedFrom: z.string().min(1),\n\titems: z.array(registryIndexEntrySchema)\n});\n//#endregion\nexport { registryIndexSchema as a, hashContent as c, registryIndexEntrySchema as i, registryFileSchema as n, registryItemSchema as o, registryFileTypeSchema as r, registryItemTypeSchema as s, REGISTRY_VERSION as t };\n\n//# sourceMappingURL=schema-ByqIpT47.js.map","/**\n * An error whose message is written for the person running the command.\n *\n * Anything thrown as a CliError is printed as a clean message with no stack\n * trace; everything else is treated as a bug and printed in full, because a\n * stack trace is exactly what is useful then and exactly what is noise when the\n * problem is \"you have not run init yet\".\n */\nexport class CliError extends Error {\n readonly hint: string | undefined;\n\n constructor(message: string, hint?: string) {\n super(message);\n this.name = \"CliError\";\n this.hint = hint;\n }\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\n\nimport { CliError } from \"./errors\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n/**\n * How the CLI turns an import alias into a directory.\n *\n * Stored as a prefix/base pair taken from the project's tsconfig paths, rather\n * than as absolute directories, so the config stays readable and survives the\n * project being moved or checked out somewhere else.\n */\nexport const resolveSchema = z.object({\n /** Alias prefix, e.g. \"@/\" for `\"@/*\": [\"./src/*\"]`. */\n prefix: z.string().min(1),\n /** Directory the prefix maps to, relative to the project root, e.g. \"src\". */\n base: z.string(),\n});\n\nexport const aliasesSchema = z.object({\n components: z.string().min(1),\n ui: z.string().min(1),\n lib: z.string().min(1),\n hooks: z.string().min(1),\n utils: z.string().min(1),\n /**\n * Where blocks are installed.\n *\n * Optional so a components.json written before blocks existed still parses;\n * `blocksAlias()` derives a sensible default from `components` when it is\n * absent. Silently failing to install a block would be worse than either.\n */\n blocks: z.string().min(1).optional(),\n});\n\nexport const installedItemSchema = z.object({\n /** Registry version the item was installed from. */\n from: z.string(),\n /** Project-relative file path to the hash of the content we wrote. */\n files: z.record(z.string(), z.string()),\n /**\n * Registry entries this one imports.\n *\n * Recorded so `remove` can refuse to delete something another installed\n * component still needs, without having to reach the registry to find out.\n * Optional, because installs made before this existed have no record of it.\n */\n dependsOn: z.array(z.string()).optional(),\n});\n\nexport const configSchema = z.object({\n $schema: z.string().optional(),\n version: z.literal(1),\n typescript: z.boolean(),\n registry: z.string().min(1),\n tailwind: z.object({\n /** Project-relative path to the stylesheet that imports Tailwind. */\n css: z.string().min(1),\n }),\n aliases: aliasesSchema,\n resolve: resolveSchema,\n /**\n * What has been installed, and the hash of what was written.\n *\n * This is what lets `update` tell an untouched file from one the user has\n * edited. It has to be recorded at install time — an install that skipped it\n * leaves no way to ever know what it originally wrote.\n */\n installed: z.record(z.string(), installedItemSchema).default({}),\n});\n\nexport type Config = z.infer<typeof configSchema>;\nexport type Aliases = z.infer<typeof aliasesSchema>;\n\n/** The blocks alias, or a default derived from where components live. */\nexport function blocksAlias(config: Config): string {\n return config.aliases.blocks ?? `${config.aliases.components}/blocks`;\n}\n\nexport function configPath(cwd: string): string {\n return join(cwd, CONFIG_FILE);\n}\n\nexport function configExists(cwd: string): boolean {\n return existsSync(configPath(cwd));\n}\n\nexport function readConfig(cwd: string): Config {\n const path = configPath(cwd);\n\n if (!existsSync(path)) {\n throw new CliError(\n `No ${CONFIG_FILE} found in ${cwd}.`,\n \"Run `init` first to set the project up.\",\n );\n }\n\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n throw new CliError(`${CONFIG_FILE} is not valid JSON.`);\n }\n\n const parsed = configSchema.safeParse(raw);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((issue) => ` ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new CliError(`${CONFIG_FILE} is not valid:\\n${issues}`);\n }\n\n return parsed.data;\n}\n\nexport function writeConfig(cwd: string, config: Config): void {\n writeFileSync(configPath(cwd), `${JSON.stringify(config, null, 2)}\\n`);\n}\n","import pc from \"picocolors\";\n\n/**\n * All CLI output goes through here.\n *\n * A single place to route messages means the format stays consistent, and\n * anything that needs to change later — quiet mode, JSON output, writing to\n * stderr — changes in one file rather than in every command.\n */\nexport const logger = {\n info(message: string) {\n console.log(message);\n },\n success(message: string) {\n console.log(`${pc.green(\"✓\")} ${message}`);\n },\n warn(message: string) {\n console.warn(`${pc.yellow(\"!\")} ${message}`);\n },\n error(message: string) {\n console.error(`${pc.red(\"✕\")} ${message}`);\n },\n step(message: string) {\n console.log(`${pc.dim(\"·\")} ${message}`);\n },\n blank() {\n console.log(\"\");\n },\n};\n\nexport { pc };\n","import { spawnSync } from \"node:child_process\";\n\nimport type { PackageManager } from \"./project\";\nimport { CliError } from \"./errors\";\n\nconst INSTALL_COMMAND: Record<PackageManager, string[]> = {\n pnpm: [\"add\"],\n yarn: [\"add\"],\n bun: [\"add\"],\n npm: [\"install\"],\n};\n\n/** Packages already present are skipped, so re-running `add` installs nothing. */\nexport function missingDependencies(\n installed: Record<string, string>,\n required: string[],\n): string[] {\n return required.filter((dependency) => !(dependency in installed));\n}\n\nexport function installDependencies(\n manager: PackageManager,\n cwd: string,\n dependencies: string[],\n): void {\n if (dependencies.length === 0) return;\n\n const args = [...INSTALL_COMMAND[manager], ...dependencies];\n const result = spawnSync(manager, args, { cwd, stdio: \"inherit\" });\n\n if (result.error) {\n throw new CliError(\n `Could not run ${manager}: ${result.error.message}`,\n `Install these manually: ${dependencies.join(\" \")}`,\n );\n }\n\n if (result.status !== 0) {\n throw new CliError(\n `${manager} ${args.join(\" \")} failed.`,\n \"Fix the install and run the command again — no files were rolled back.\",\n );\n }\n}\n","import { join } from \"node:path\";\n\nimport { blocksAlias, type Config } from \"./config\";\nimport { CliError } from \"./errors\";\n\n/**\n * Maps a registry file path to a destination in the project.\n *\n * The registry publishes logical paths — `ui/button.tsx`, `lib/utils.ts` —\n * because it has never seen the project it is being installed into. The leading\n * segment selects which alias the file belongs under, and the alias is resolved\n * through the project's own tsconfig prefix.\n */\nexport function resolveDestination(config: Config, registryPath: string): string {\n const [group, ...rest] = registryPath.split(\"/\");\n const relative = rest.join(\"/\");\n\n if (!group || relative === \"\") {\n throw new CliError(`Registry path \"${registryPath}\" is not in a recognised group.`);\n }\n\n const alias =\n group === \"ui\"\n ? config.aliases.ui\n : group === \"lib\"\n ? config.aliases.lib\n : group === \"hooks\"\n ? config.aliases.hooks\n : group === \"blocks\"\n ? blocksAlias(config)\n : undefined;\n\n if (!alias) {\n throw new CliError(\n `Registry path \"${registryPath}\" uses unknown group \"${group}\".`,\n \"This usually means the CLI is older than the registry it is reading.\",\n );\n }\n\n return join(aliasToDirectory(config, alias), relative);\n}\n\n/** Turns an import alias such as `@/components/ui` into `src/components/ui`. */\nexport function aliasToDirectory(config: Config, alias: string): string {\n const { prefix, base } = config.resolve;\n\n if (!alias.startsWith(prefix)) {\n throw new CliError(\n `Alias \"${alias}\" does not start with the configured prefix \"${prefix}\".`,\n `Check the \"aliases\" and \"resolve\" entries in components.json.`,\n );\n }\n\n const withoutPrefix = alias.slice(prefix.length);\n return base ? join(base, withoutPrefix) : withoutPrefix;\n}\n\n/**\n * Rewrites the library's own import aliases to the ones the project uses.\n *\n * The published source is written against `@/components/*` and `@/lib/*`. A\n * project that puts its components somewhere else, or uses `~/` instead of\n * `@/`, gets files that import from where they actually live. Getting this\n * wrong is the single most common way a source-first install produces code that\n * does not compile.\n */\nexport function rewriteImports(content: string, config: Config): string {\n const { aliases } = config;\n\n return content\n .replace(\n /([\"'])@\\/lib\\/utils\\1/g,\n (_match, quote: string) => `${quote}${aliases.utils}${quote}`,\n )\n .replace(\n /([\"'])@\\/lib\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.lib}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/components\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.ui}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/hooks\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${aliases.hooks}/${rest}${quote}`,\n )\n .replace(\n /([\"'])@\\/blocks\\/([^\"']+)\\1/g,\n (_match, quote: string, rest: string) => `${quote}${blocksAlias(config)}/${rest}${quote}`,\n );\n}\n","import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { CliError } from \"./errors\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"bun\" | \"npm\";\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface ProjectInfo {\n root: string;\n packageManager: PackageManager;\n packageJson: PackageJson;\n isTypeScript: boolean;\n reactVersion: string | undefined;\n tailwindVersion: string | undefined;\n framework: \"next\" | \"vite\" | \"remix\" | \"unknown\";\n /** Project-relative path to the stylesheet that imports Tailwind, if found. */\n cssEntry: string | undefined;\n /** Alias prefix and base directory taken from tsconfig paths. */\n resolve: { prefix: string; base: string } | undefined;\n}\n\nconst LOCKFILES: [string, PackageManager][] = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"bun.lock\", \"bun\"],\n [\"bun.lockb\", \"bun\"],\n [\"yarn.lock\", \"yarn\"],\n [\"package-lock.json\", \"npm\"],\n];\n\nexport function detectPackageManager(root: string): PackageManager {\n for (const [lockfile, manager] of LOCKFILES) {\n if (existsSync(join(root, lockfile))) return manager;\n }\n return \"npm\";\n}\n\nfunction readPackageJson(root: string): PackageJson {\n const path = join(root, \"package.json\");\n if (!existsSync(path)) {\n throw new CliError(\n `No package.json found in ${root}.`,\n \"Run this from the root of your project.\",\n );\n }\n\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as PackageJson;\n } catch {\n throw new CliError(\"package.json is not valid JSON.\");\n }\n}\n\nfunction versionOf(packageJson: PackageJson, name: string): string | undefined {\n return packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name];\n}\n\n/** Leading integer of a range such as `^4.3.3`, `~4.0.0`, `4.x`. */\nexport function majorVersion(range: string | undefined): number | undefined {\n if (!range) return undefined;\n const match = /(\\d+)/.exec(range);\n return match?.[1] === undefined ? undefined : Number(match[1]);\n}\n\nfunction detectFramework(packageJson: PackageJson): ProjectInfo[\"framework\"] {\n if (versionOf(packageJson, \"next\")) return \"next\";\n if (versionOf(packageJson, \"@remix-run/react\") ?? versionOf(packageJson, \"react-router\")) {\n return \"remix\";\n }\n if (versionOf(packageJson, \"vite\")) return \"vite\";\n return \"unknown\";\n}\n\n/** Directories worth searching for the stylesheet, in the order projects use them. */\nconst CSS_SEARCH_DIRS = [\"app\", \"src/app\", \"src/styles\", \"styles\", \"src\", \".\"];\n\n/**\n * Finds the stylesheet that pulls Tailwind in.\n *\n * Located by content rather than by name: `globals.css`, `index.css`,\n * `app.css` and `main.css` are all common, and guessing at the filename would\n * mean appending tokens to a stylesheet that is never loaded.\n */\nexport function findCssEntry(root: string): string | undefined {\n for (const dir of CSS_SEARCH_DIRS) {\n const absolute = join(root, dir);\n if (!existsSync(absolute) || !statSync(absolute).isDirectory()) continue;\n\n for (const entry of readdirSync(absolute)) {\n if (!entry.endsWith(\".css\")) continue;\n\n const path = join(absolute, entry);\n const content = readFileSync(path, \"utf8\");\n if (/@import\\s+[\"']tailwindcss[\"']/.test(content) || /@tailwind\\s+/.test(content)) {\n return dir === \".\" ? entry : `${dir}/${entry}`;\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Strips comments and trailing commas from JSON with extensions, without\n * touching what is inside a string.\n *\n * A regex cannot do this. `tsconfig.json` aliases are written `\"@/*\"`, which\n * contains `/*`, and the `include` globs are written `\"**\\/*.ts\"`, which\n * contains `*\\/` — so a naive block-comment regex treats everything between\n * them as a comment and eats the `paths` block. Every stock Next.js tsconfig\n * has both, which is exactly the project this tool is most often pointed at.\n * The parse then failed, `detectResolve` returned undefined, and `init`\n * either asked for an alias it could already see or, under `--yes`, refused.\n *\n * So this walks the text instead, and only treats `//` and `/*` as comments\n * when they are outside a string.\n */\nexport function stripJsonComments(text: string): string {\n let out = \"\";\n let inString = false;\n let escaped = false;\n\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i] ?? \"\";\n const next = text[i + 1] ?? \"\";\n\n if (inString) {\n out += char;\n if (escaped) escaped = false;\n else if (char === \"\\\\\") escaped = true;\n else if (char === '\"') inString = false;\n continue;\n }\n\n if (char === '\"') {\n inString = true;\n out += char;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n const end = text.indexOf(\"*/\", i + 2);\n i = end === -1 ? text.length : end + 1;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n const end = text.indexOf(\"\\n\", i);\n if (end === -1) break;\n i = end - 1;\n continue;\n }\n\n out += char;\n }\n\n // Trailing commas are legal in tsconfig and not in JSON. Safe to do with a\n // regex now that no string can contain an unbalanced brace from a comment.\n return out.replace(/,(\\s*[}\\]])/g, \"$1\");\n}\n\n/**\n * Reads the first wildcard alias out of tsconfig paths.\n *\n * `\"@/*\": [\"./src/*\"]` becomes `{ prefix: \"@/\", base: \"src\" }`. Only the\n * wildcard form is understood, which covers how essentially every React project\n * is set up; anything else falls through to a prompt rather than a wrong guess.\n */\nexport function detectResolve(root: string): ProjectInfo[\"resolve\"] {\n for (const file of [\"tsconfig.json\", \"jsconfig.json\"]) {\n const path = join(root, file);\n if (!existsSync(path)) continue;\n\n let parsed: { compilerOptions?: { paths?: Record<string, string[]> } };\n try {\n parsed = JSON.parse(stripJsonComments(readFileSync(path, \"utf8\"))) as typeof parsed;\n } catch {\n continue;\n }\n\n const paths = parsed.compilerOptions?.paths;\n if (!paths) continue;\n\n for (const [alias, targets] of Object.entries(paths)) {\n const target = targets[0];\n if (!alias.endsWith(\"/*\") || target === undefined || !target.endsWith(\"/*\")) continue;\n\n return {\n prefix: alias.slice(0, -1),\n base: target.slice(0, -2).replace(/^\\.\\//, \"\").replace(/\\/$/, \"\"),\n };\n }\n }\n\n return undefined;\n}\n\nexport function inspectProject(root: string): ProjectInfo {\n const packageJson = readPackageJson(root);\n\n return {\n root,\n packageManager: detectPackageManager(root),\n packageJson,\n isTypeScript: existsSync(join(root, \"tsconfig.json\")),\n reactVersion: versionOf(packageJson, \"react\"),\n tailwindVersion: versionOf(packageJson, \"tailwindcss\"),\n framework: detectFramework(packageJson),\n cssEntry: findCssEntry(root),\n resolve: detectResolve(root),\n };\n}\n\n/**\n * Refuses to proceed on a project this version cannot support correctly.\n *\n * Every check here fails loudly on purpose. Writing v4 token syntax into a v3\n * project, or TypeScript source into a JavaScript one, produces a project that\n * does not build — and the person debugging it has no reason to suspect the\n * install rather than their own code.\n */\nexport function assertSupported(project: ProjectInfo): void {\n if (!project.reactVersion) {\n throw new CliError(\n \"This does not look like a React project — react is not in package.json.\",\n \"Run this from the root of a React application.\",\n );\n }\n\n if (!project.isTypeScript) {\n throw new CliError(\n \"JavaScript projects are not supported yet.\",\n \"The published components are TypeScript. Add a tsconfig.json, or wait for JS output in a future release.\",\n );\n }\n\n const tailwindMajor = majorVersion(project.tailwindVersion);\n\n if (tailwindMajor === undefined) {\n throw new CliError(\n \"Tailwind CSS is not installed.\",\n \"Install tailwindcss v4 and its plugin for your bundler, then run init again.\",\n );\n }\n\n if (tailwindMajor < 4) {\n throw new CliError(\n `Tailwind CSS v${String(tailwindMajor)} is not supported — v4 or later is required.`,\n \"The design tokens are defined with @theme, which v3 cannot parse. Upgrade to Tailwind v4 first.\",\n );\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport {\n registryIndexSchema,\n registryItemSchema,\n type RegistryIndex,\n type RegistryItem,\n} from \"@dowel-ui/registry\";\n\nimport { CliError } from \"./errors\";\n\n/**\n * Reads the registry over HTTP, or from a directory on disk.\n *\n * The local path form is not a testing shortcut bolted on afterwards — it is\n * how private forks and enterprise mirrors are meant to work, and it is what\n * lets the end-to-end tests run against a registry built in the same commit\n * rather than against whatever happens to be deployed.\n */\nfunction isHttp(baseUrl: string): boolean {\n return baseUrl.startsWith(\"http://\") || baseUrl.startsWith(\"https://\");\n}\n\nfunction localPath(baseUrl: string, file: string): string {\n const root = baseUrl.startsWith(\"file:\") ? fileURLToPath(baseUrl) : baseUrl;\n return join(root, file);\n}\n\nasync function readJson(baseUrl: string, file: string, what: string): Promise<unknown> {\n if (!isHttp(baseUrl)) {\n const path = localPath(baseUrl, file);\n if (!existsSync(path)) {\n throw new CliError(`${what} not found at ${path}.`);\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n throw new CliError(`${what} at ${path} is not valid JSON.`);\n }\n }\n\n const url = `${baseUrl.replace(/\\/$/, \"\")}/${file}`;\n let response: Response;\n try {\n response = await fetch(url);\n } catch (cause) {\n throw new CliError(\n `Could not reach the registry at ${url}.`,\n cause instanceof Error ? cause.message : undefined,\n );\n }\n\n if (response.status === 404) {\n throw new CliError(`${what} not found in the registry.`);\n }\n if (!response.ok) {\n throw new CliError(`Registry returned ${String(response.status)} for ${url}.`);\n }\n\n try {\n return await response.json();\n } catch {\n throw new CliError(`${what} at ${url} is not valid JSON.`);\n }\n}\n\nexport async function fetchIndex(baseUrl: string): Promise<RegistryIndex> {\n const raw = await readJson(baseUrl, \"index.json\", \"Registry index\");\n const parsed = registryIndexSchema.safeParse(raw);\n\n if (!parsed.success) {\n throw new CliError(\n \"The registry index does not match the format this CLI understands.\",\n \"Update the CLI, or point --registry at a compatible registry.\",\n );\n }\n\n return parsed.data;\n}\n\nexport async function fetchItem(baseUrl: string, name: string): Promise<RegistryItem> {\n const raw = await readJson(baseUrl, `${name}.json`, `Component \"${name}\"`);\n const parsed = registryItemSchema.safeParse(raw);\n\n if (!parsed.success) {\n throw new CliError(\n `Registry entry \"${name}\" does not match the format this CLI understands.`,\n \"Update the CLI, or point --registry at a compatible registry.\",\n );\n }\n\n return parsed.data;\n}\n\n/**\n * Resolves items and everything they depend on, dependencies first.\n *\n * Depth-first post-order, so a component is always ordered after the things it\n * imports. A breadth-first walk reversed looks equivalent and is not: if two\n * requested items depend on each other's subtrees it produces the wrong order.\n * The visiting set makes a dependency cycle terminate rather than recurse\n * forever.\n */\nexport async function resolveItems(baseUrl: string, names: string[]): Promise<RegistryItem[]> {\n const cache = new Map<string, RegistryItem>();\n const ordered: RegistryItem[] = [];\n const placed = new Set<string>();\n const visiting = new Set<string>();\n\n async function load(name: string): Promise<RegistryItem> {\n const cached = cache.get(name);\n if (cached) return cached;\n\n const item = await fetchItem(baseUrl, name);\n cache.set(name, item);\n return item;\n }\n\n async function visit(name: string): Promise<void> {\n if (placed.has(name) || visiting.has(name)) return;\n visiting.add(name);\n\n const item = await load(name);\n for (const dependency of item.registryDependencies) {\n await visit(dependency);\n }\n\n visiting.delete(name);\n placed.add(name);\n ordered.push(item);\n }\n\n for (const name of names) {\n await visit(name);\n }\n\n return ordered;\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { hashContent, type RegistryItem } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig, type Config } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { installDependencies, missingDependencies } from \"../lib/package-manager\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { inspectProject } from \"../lib/project\";\nimport { resolveItems } from \"../lib/registry-client\";\n\nexport interface AddOptions {\n cwd: string;\n registry?: string;\n yes: boolean;\n overwrite: boolean;\n skipInstall: boolean;\n}\n\n/** What `add` intends to do with one file, decided before anything is written. */\nexport type FileAction = \"write\" | \"unchanged\" | \"modified\";\n\nexport interface PlannedFile {\n destination: string;\n content: string;\n hash: string;\n action: FileAction;\n}\n\n/**\n * Classifies an existing file against what we previously wrote there.\n *\n * Three outcomes, and the distinction matters. A file whose content still\n * matches what we installed is ours to replace silently, which is what makes\n * re-running `add` a no-op. A file that differs from what we installed has been\n * edited by the user — the entire point of a source-first library — and must\n * never be overwritten without them saying so.\n */\nexport function classifyFile(\n absolutePath: string,\n incomingHash: string,\n recordedHash: string | undefined,\n): FileAction {\n if (!existsSync(absolutePath)) return \"write\";\n\n const currentHash = hashContent(readFileSync(absolutePath, \"utf8\"));\n\n if (currentHash === incomingHash) return \"unchanged\";\n // Still exactly what we last wrote, just superseded upstream: ours to replace.\n if (recordedHash !== undefined && currentHash === recordedHash) return \"write\";\n\n return \"modified\";\n}\n\nexport function planFiles(cwd: string, config: Config, items: RegistryItem[]): PlannedFile[] {\n const planned: PlannedFile[] = [];\n\n for (const item of items) {\n const recorded = config.installed[item.name]?.files ?? {};\n\n for (const file of item.files) {\n if (file.type === \"registry:style\") continue;\n\n const destination = resolveDestination(config, file.path);\n const content = rewriteImports(file.content, config);\n // Hashed after rewriting, because the rewritten text is what actually\n // lands on disk — comparing against the published text would report every\n // file as modified in any project that does not use the `@/` prefix.\n const hash = hashContent(content);\n\n planned.push({\n destination,\n content,\n hash,\n action: classifyFile(join(cwd, destination), hash, recorded[destination]),\n });\n }\n }\n\n return planned;\n}\n\nexport async function add(names: string[], options: AddOptions): Promise<void> {\n if (names.length === 0) {\n throw new CliError(\n \"Name at least one component to add.\",\n \"For example: `add button dialog`.\",\n );\n }\n\n const { cwd, yes, overwrite } = options;\n const config = readConfig(cwd);\n const registry = options.registry ?? config.registry;\n const project = inspectProject(cwd);\n\n const items = await resolveItems(registry, names);\n const requested = new Set(names);\n const pulledIn = items.filter((item) => !requested.has(item.name));\n\n const planned = planFiles(cwd, config, items);\n const toWrite = planned.filter((file) => file.action === \"write\");\n const modified = planned.filter((file) => file.action === \"modified\");\n const unchanged = planned.filter((file) => file.action === \"unchanged\");\n\n if (modified.length > 0 && !overwrite) {\n logger.warn(\"These files have local changes and were left alone:\");\n for (const file of modified) logger.info(` ${file.destination}`);\n logger.blank();\n logger.info(pc.dim(\"Re-run with --overwrite to replace them.\"));\n\n if (toWrite.length === 0) {\n logger.blank();\n logger.info(\"Nothing else to do.\");\n return;\n }\n }\n\n const writable = overwrite ? [...toWrite, ...modified] : toWrite;\n\n if (writable.length === 0) {\n logger.success(unchanged.length > 0 ? \"Already up to date.\" : \"Nothing to write.\");\n return;\n }\n\n const dependencies = [...new Set(items.flatMap((item) => item.dependencies))];\n const missing = missingDependencies(\n { ...project.packageJson.dependencies, ...project.packageJson.devDependencies },\n dependencies,\n );\n\n if (!yes) {\n logger.info(pc.dim(\"Will write:\"));\n for (const file of writable) logger.info(` ${file.destination}`);\n if (pulledIn.length > 0) {\n logger.info(\n pc.dim(`Pulled in as dependencies: ${pulledIn.map((i) => i.name).join(\", \")}`),\n );\n }\n if (missing.length > 0) logger.info(pc.dim(`Will install: ${missing.join(\", \")}`));\n logger.blank();\n\n const proceed = await prompts.confirm({ message: \"Continue?\", initialValue: true });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n for (const file of writable) {\n const absolute = join(cwd, file.destination);\n mkdirSync(dirname(absolute), { recursive: true });\n writeFileSync(absolute, file.content);\n }\n\n // Recorded after writing, and only for files that actually landed, so the\n // config never claims to have installed something it did not.\n const writtenPaths = new Set(writable.map((file) => file.destination));\n for (const item of items) {\n const files: Record<string, string> = { ...config.installed[item.name]?.files };\n\n for (const file of planFiles(cwd, config, [item])) {\n if (writtenPaths.has(file.destination) || file.action === \"unchanged\") {\n files[file.destination] = file.hash;\n }\n }\n\n if (Object.keys(files).length > 0) {\n config.installed[item.name] = {\n from: item.registryVersion.toString(),\n files,\n dependsOn: item.registryDependencies,\n };\n }\n }\n\n writeConfig(cwd, config);\n\n if (missing.length > 0 && !options.skipInstall) {\n installDependencies(project.packageManager, cwd, missing);\n }\n\n logger.blank();\n logger.success(`Added ${items.map((item) => item.name).join(\", \")}`);\n if (missing.length > 0) {\n logger.success(\n options.skipInstall\n ? `Install these yourself: ${missing.join(\" \")}`\n : `Installed ${missing.join(\", \")}`,\n );\n }\n logger.blank();\n logger.info(pc.dim(\"Files:\"));\n for (const file of writable) logger.info(` ${file.destination}`);\n if (unchanged.length > 0) {\n logger.info(pc.dim(` (${String(unchanged.length)} already up to date)`));\n }\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { branding } from \"../branding\";\nimport { configExists, writeConfig, type Config } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { installDependencies, missingDependencies } from \"../lib/package-manager\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { assertSupported, inspectProject } from \"../lib/project\";\nimport { fetchItem } from \"../lib/registry-client\";\n\nexport interface InitOptions {\n cwd: string;\n registry: string;\n yes: boolean;\n skipInstall: boolean;\n}\n\n/** Header the registry puts at the top of the token block. */\nexport const TOKENS_MARKER = \"/* Design tokens. Safe to edit — this is your copy. */\";\n\n/**\n * Appends the design tokens to the project stylesheet.\n *\n * Appended rather than written as a new file, and inserted after the Tailwind\n * import rather than at the top, because `@theme` has to be processed by\n * Tailwind. The existing stylesheet is never rewritten — whatever the project\n * already had stays exactly where it was.\n *\n * Two separate idempotence checks, because they catch different things. The\n * marker survives the user editing their tokens, which they are meant to do —\n * a content check alone would re-insert the whole block over their changes. The\n * content check covers a token block that carries no marker.\n */\nexport function insertTokens(stylesheet: string, tokens: string): string {\n if (stylesheet.includes(TOKENS_MARKER)) return stylesheet;\n if (stylesheet.includes(tokens.trim())) return stylesheet;\n\n const importMatch = /^[^\\n]*@import\\s+[\"']tailwindcss[\"'][^\\n]*$/m.exec(stylesheet);\n\n if (!importMatch) {\n return `${stylesheet.trimEnd()}\\n\\n${tokens.trim()}\\n`;\n }\n\n const insertAt = importMatch.index + importMatch[0].length;\n return `${stylesheet.slice(0, insertAt)}\\n\\n${tokens.trim()}\\n${stylesheet.slice(insertAt)}`;\n}\n\nexport async function init(options: InitOptions): Promise<void> {\n const { cwd, registry, yes } = options;\n\n if (configExists(cwd) && !yes) {\n const overwrite = await prompts.confirm({\n message: \"components.json already exists. Overwrite it?\",\n initialValue: false,\n });\n if (prompts.isCancel(overwrite) || !overwrite) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n const project = inspectProject(cwd);\n assertSupported(project);\n\n logger.step(`Detected ${pc.bold(project.framework)} · ${pc.bold(project.packageManager)}`);\n\n let resolve = project.resolve;\n if (!resolve) {\n if (yes) {\n throw new CliError(\n \"Could not read a path alias from tsconfig.json.\",\n 'Add something like `\"paths\": { \"@/*\": [\"./src/*\"] }` and run init again.',\n );\n }\n\n const prefix = await prompts.text({\n message: \"What import alias do you use?\",\n placeholder: \"@/\",\n initialValue: \"@/\",\n });\n const base = await prompts.text({\n message: \"Which directory does it point at?\",\n placeholder: \"src\",\n initialValue: \"src\",\n });\n\n if (prompts.isCancel(prefix) || prompts.isCancel(base)) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n resolve = { prefix, base };\n }\n\n let cssEntry = project.cssEntry;\n if (!cssEntry) {\n if (yes) {\n throw new CliError(\n \"Could not find a stylesheet that imports Tailwind.\",\n 'Create one containing `@import \"tailwindcss\";` and run init again.',\n );\n }\n\n const answer = await prompts.text({\n message: \"Where is the stylesheet that imports Tailwind?\",\n placeholder: \"src/index.css\",\n });\n if (prompts.isCancel(answer) || !answer) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n cssEntry = answer;\n }\n\n const config: Config = {\n $schema: `${branding.registryUrl}/schema/components.json`,\n version: 1,\n typescript: true,\n registry,\n tailwind: { css: cssEntry },\n aliases: {\n components: `${resolve.prefix}components`,\n ui: `${resolve.prefix}components/ui`,\n lib: `${resolve.prefix}lib`,\n hooks: `${resolve.prefix}hooks`,\n utils: `${resolve.prefix}lib/utils`,\n blocks: `${resolve.prefix}components/blocks`,\n },\n resolve,\n installed: {},\n };\n\n const utils = await fetchItem(registry, \"utils\");\n const theme = await fetchItem(registry, \"theme\");\n\n const written: string[] = [];\n const installedFiles: Record<string, string> = {};\n\n for (const file of utils.files) {\n const destination = resolveDestination(config, file.path);\n const absolute = join(cwd, destination);\n\n if (existsSync(absolute)) {\n logger.step(`${pc.dim(\"skipped\")} ${destination} ${pc.dim(\"(already exists)\")}`);\n continue;\n }\n\n mkdirSync(dirname(absolute), { recursive: true });\n const content = rewriteImports(file.content, config);\n writeFileSync(absolute, content);\n installedFiles[destination] = file.hash;\n written.push(destination);\n }\n\n config.installed.utils = { from: utils.registryVersion.toString(), files: installedFiles };\n\n const stylesheetPath = join(cwd, cssEntry);\n if (!existsSync(stylesheetPath)) {\n throw new CliError(`Stylesheet not found at ${cssEntry}.`);\n }\n\n const tokens = theme.files[0]?.content ?? \"\";\n const stylesheet = readFileSync(stylesheetPath, \"utf8\");\n const updated = insertTokens(stylesheet, tokens);\n\n if (updated === stylesheet) {\n logger.step(`${pc.dim(\"skipped\")} ${cssEntry} ${pc.dim(\"(tokens already present)\")}`);\n } else {\n writeFileSync(stylesheetPath, updated);\n written.push(cssEntry);\n }\n\n config.installed.theme = {\n from: theme.registryVersion.toString(),\n files: { [cssEntry]: theme.files[0]?.hash ?? \"\" },\n };\n\n writeConfig(cwd, config);\n written.unshift(\"components.json\");\n\n const required = [...utils.dependencies];\n const missing = missingDependencies(\n { ...project.packageJson.dependencies, ...project.packageJson.devDependencies },\n required,\n );\n\n if (missing.length > 0 && !options.skipInstall) {\n logger.step(`Installing ${missing.join(\", \")}`);\n installDependencies(project.packageManager, cwd, missing);\n }\n\n logger.blank();\n logger.success(\"Project initialised.\");\n logger.blank();\n logger.info(pc.dim(\"Files:\"));\n for (const file of written) logger.info(` ${file}`);\n if (missing.length > 0) {\n logger.blank();\n logger.info(pc.dim(options.skipInstall ? \"Install manually:\" : \"Dependencies:\"));\n logger.info(` ${missing.join(\" \")}`);\n }\n logger.blank();\n // The npx form rather than the bare binary: whoever ran this through npx\n // has no `dowel` on their PATH, and pointing them at a command they do not\n // have is a poor first impression.\n logger.info(`Next: ${pc.bold(`npx ${branding.cliPackage} add button`)}`);\n}\n","import { configExists, readConfig } from \"../lib/config\";\nimport { logger, pc } from \"../lib/logger\";\nimport { fetchIndex } from \"../lib/registry-client\";\nimport { branding } from \"../branding\";\n\nexport interface ListOptions {\n cwd: string;\n registry?: string;\n category?: string;\n json: boolean;\n}\n\nexport async function list(options: ListOptions): Promise<void> {\n // Usable before init: browsing what exists should not require a project.\n const config = configExists(options.cwd) ? readConfig(options.cwd) : undefined;\n const registry = options.registry ?? config?.registry ?? branding.registryUrl;\n\n const index = await fetchIndex(registry);\n const installed = new Set(Object.keys(config?.installed ?? {}));\n\n const items = index.items\n .filter((item) => item.type === \"registry:ui\")\n .filter((item) => !options.category || item.category === options.category);\n\n if (options.json) {\n logger.info(\n JSON.stringify(\n items.map((item) => ({ ...item, installed: installed.has(item.name) })),\n null,\n 2,\n ),\n );\n return;\n }\n\n if (items.length === 0) {\n logger.warn(\n options.category\n ? `No components in category \"${options.category}\".`\n : \"The registry has no components.\",\n );\n return;\n }\n\n const byCategory = new Map<string, typeof items>();\n for (const item of items) {\n byCategory.set(item.category, [...(byCategory.get(item.category) ?? []), item]);\n }\n\n const width = Math.max(...items.map((item) => item.name.length));\n\n for (const [category, categoryItems] of [...byCategory].sort()) {\n logger.blank();\n logger.info(pc.bold(category));\n for (const item of categoryItems) {\n const mark = installed.has(item.name) ? pc.green(\"✓\") : \" \";\n logger.info(` ${mark} ${item.name.padEnd(width)} ${pc.dim(item.description)}`);\n }\n }\n\n logger.blank();\n logger.info(\n pc.dim(\n `${String(items.length)} components · ${String(installed.size)} installed · ${registry}`,\n ),\n );\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, readFileSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { hashContent } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\n\nexport interface RemoveOptions {\n cwd: string;\n yes: boolean;\n /** Delete files that no longer match what was installed. */\n force: boolean;\n}\n\nexport type RemovalState = \"unchanged\" | \"modified\" | \"missing\";\n\nexport interface PlannedRemoval {\n component: string;\n path: string;\n state: RemovalState;\n}\n\n/**\n * Classifies a file before deleting it.\n *\n * Deleting is the one irreversible thing this CLI does, so it distinguishes a\n * file still exactly as installed — safe to remove — from one that has been\n * edited, which is the user's work and not ours to throw away.\n */\nexport function classifyRemoval(\n absolutePath: string,\n recordedHash: string | undefined,\n): RemovalState {\n if (!existsSync(absolutePath)) return \"missing\";\n if (recordedHash === undefined) return \"modified\";\n return hashContent(readFileSync(absolutePath, \"utf8\")) === recordedHash\n ? \"unchanged\"\n : \"modified\";\n}\n\n/**\n * Components that other installed entries still import.\n *\n * Removing a component something else depends on would break the project, so\n * those are reported and skipped rather than deleted with a warning after the\n * fact.\n */\nexport function findDependents(\n installed: Record<string, { files: Record<string, string> }>,\n registryDependencies: Map<string, string[]>,\n removing: Set<string>,\n): Map<string, string[]> {\n const blockers = new Map<string, string[]>();\n\n for (const name of removing) {\n const dependents = Object.keys(installed).filter(\n (candidate) =>\n !removing.has(candidate) && (registryDependencies.get(candidate) ?? []).includes(name),\n );\n if (dependents.length > 0) blockers.set(name, dependents);\n }\n\n return blockers;\n}\n\nexport async function remove(names: string[], options: RemoveOptions): Promise<void> {\n if (names.length === 0) {\n throw new CliError(\"Name at least one component to remove.\");\n }\n\n const { cwd } = options;\n const config = readConfig(cwd);\n\n const unknown = names.filter((name) => !(name in config.installed));\n if (unknown.length > 0) {\n throw new CliError(\n `Not installed: ${unknown.join(\", \")}.`,\n \"Run `list` to see what is installed.\",\n );\n }\n\n // Dependency edges are read from what was installed, not fetched: removing\n // something should not need the registry to be reachable.\n const registryDependencies = new Map<string, string[]>();\n for (const [name, entry] of Object.entries(config.installed)) {\n registryDependencies.set(name, entry.dependsOn ?? []);\n }\n\n const removing = new Set(names);\n const blockers = findDependents(config.installed, registryDependencies, removing);\n\n if (blockers.size > 0) {\n logger.error(\"These are still needed by something else:\");\n for (const [name, dependents] of blockers) {\n logger.info(` ${name} — required by ${dependents.join(\", \")}`);\n }\n throw new CliError(\"Nothing was removed.\", \"Remove the dependents first, or keep these.\");\n }\n\n const planned: PlannedRemoval[] = [];\n for (const name of names) {\n for (const [path, hash] of Object.entries(config.installed[name]?.files ?? {})) {\n planned.push({ component: name, path, state: classifyRemoval(join(cwd, path), hash) });\n }\n }\n\n const modified = planned.filter((file) => file.state === \"modified\");\n const deletable = planned.filter(\n (file) => file.state === \"unchanged\" || (options.force && file.state === \"modified\"),\n );\n\n if (modified.length > 0 && !options.force) {\n logger.warn(\"These have local changes and will be kept:\");\n for (const file of modified) logger.info(` ${file.path}`);\n logger.blank();\n logger.info(pc.dim(\"Re-run with --force to delete them as well.\"));\n }\n\n if (deletable.length === 0) {\n logger.blank();\n logger.info(\"Nothing to delete.\");\n return;\n }\n\n if (!options.yes) {\n logger.info(pc.dim(\"Will delete:\"));\n for (const file of deletable) logger.info(` ${file.path}`);\n logger.blank();\n\n const proceed = await prompts.confirm({\n message: `Delete ${String(deletable.length)} file(s)?`,\n initialValue: false,\n });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was deleted.\");\n }\n }\n\n for (const file of deletable) {\n rmSync(join(cwd, file.path), { force: true });\n }\n\n // An entry whose files were kept stays recorded, so `update` still knows what\n // it wrote there.\n const deleted = new Set(deletable.map((file) => file.path));\n for (const name of names) {\n const entry = config.installed[name];\n if (!entry) continue;\n\n const remaining = Object.fromEntries(\n Object.entries(entry.files).filter(([path]) => !deleted.has(path)),\n );\n\n if (Object.keys(remaining).length === 0) delete config.installed[name];\n else entry.files = remaining;\n }\n\n writeConfig(cwd, config);\n\n logger.blank();\n logger.success(`Removed ${String(deletable.length)} file(s).`);\n if (modified.length > 0 && !options.force) {\n logger.warn(`${String(modified.length)} locally modified file(s) were kept.`);\n }\n logger.blank();\n logger.info(pc.dim(\"npm packages are left installed — other code may still use them.\"));\n}\n","import * as prompts from \"@clack/prompts\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { hashContent } from \"@dowel-ui/registry\";\n\nimport { readConfig, writeConfig } from \"../lib/config\";\nimport { CliError } from \"../lib/errors\";\nimport { logger, pc } from \"../lib/logger\";\nimport { resolveDestination, rewriteImports } from \"../lib/paths\";\nimport { fetchItem } from \"../lib/registry-client\";\n\nexport interface UpdateOptions {\n cwd: string;\n registry?: string;\n overwrite: boolean;\n yes: boolean;\n}\n\nexport type UpdateState = \"current\" | \"outdated\" | \"modified\" | \"conflict\" | \"missing\";\n\nexport interface UpdateReport {\n component: string;\n destination: string;\n state: UpdateState;\n content: string;\n hash: string;\n}\n\n/**\n * Compares three versions of a file: what the registry has now, what we\n * installed, and what is on disk.\n *\n * The three-way comparison is why the install hash had to be recorded from the\n * very first release. Without it there is no way to distinguish \"the user\n * edited this\" from \"upstream changed this\", and the only safe behaviour left\n * is to never update anything.\n */\nexport function compareFile(\n absolutePath: string,\n incomingHash: string,\n recordedHash: string | undefined,\n): UpdateState {\n if (!existsSync(absolutePath)) return \"missing\";\n\n const currentHash = hashContent(readFileSync(absolutePath, \"utf8\"));\n\n if (currentHash === incomingHash) return \"current\";\n if (recordedHash === undefined) return \"conflict\";\n if (currentHash === recordedHash) return \"outdated\";\n\n // Changed on both sides. Overwriting would silently discard the user's work,\n // which in a source-first library is the whole thing they were promised.\n return incomingHash === recordedHash ? \"modified\" : \"conflict\";\n}\n\nconst STATE_LABEL: Record<UpdateState, string> = {\n current: \"up to date\",\n outdated: \"update available\",\n modified: \"locally modified\",\n conflict: \"modified, and changed upstream\",\n missing: \"missing\",\n};\n\nexport async function update(names: string[], options: UpdateOptions): Promise<void> {\n const { cwd } = options;\n const config = readConfig(cwd);\n const registry = options.registry ?? config.registry;\n\n const targets = names.length > 0 ? names : Object.keys(config.installed);\n\n if (targets.length === 0) {\n throw new CliError(\"Nothing is installed yet.\", \"Add a component first.\");\n }\n\n const unknown = targets.filter((name) => !(name in config.installed));\n if (unknown.length > 0) {\n throw new CliError(\n `Not installed: ${unknown.join(\", \")}.`,\n \"Run `list` to see what is installed.\",\n );\n }\n\n const reports: UpdateReport[] = [];\n\n for (const name of targets) {\n const item = await fetchItem(registry, name);\n const recorded = config.installed[name]?.files ?? {};\n\n for (const file of item.files) {\n if (file.type === \"registry:style\") continue;\n\n const destination = resolveDestination(config, file.path);\n const content = rewriteImports(file.content, config);\n const hash = hashContent(content);\n\n reports.push({\n component: name,\n destination,\n hash,\n content,\n state: compareFile(join(cwd, destination), hash, recorded[destination]),\n });\n }\n }\n\n const actionable = reports.filter(\n (report) => report.state === \"outdated\" || report.state === \"missing\",\n );\n const conflicts = reports.filter(\n (report) => report.state === \"conflict\" || report.state === \"modified\",\n );\n\n logger.blank();\n for (const report of reports) {\n const colour =\n report.state === \"current\"\n ? pc.dim\n : report.state === \"outdated\" || report.state === \"missing\"\n ? pc.yellow\n : pc.red;\n logger.info(` ${colour(STATE_LABEL[report.state].padEnd(30))} ${report.destination}`);\n }\n logger.blank();\n\n if (actionable.length === 0 && conflicts.length === 0) {\n logger.success(\"Everything is up to date.\");\n return;\n }\n\n const writable = options.overwrite ? [...actionable, ...conflicts] : actionable;\n\n if (writable.length === 0) {\n logger.warn(\"Only locally modified files differ; none were touched.\");\n logger.info(pc.dim(\"Re-run with --overwrite to replace them and lose those edits.\"));\n return;\n }\n\n if (!options.yes) {\n const proceed = await prompts.confirm({\n message: options.overwrite\n ? `Overwrite ${String(writable.length)} file(s), discarding any local changes?`\n : `Update ${String(writable.length)} file(s)?`,\n initialValue: !options.overwrite,\n });\n if (prompts.isCancel(proceed) || !proceed) {\n throw new CliError(\"Cancelled — nothing was changed.\");\n }\n }\n\n for (const report of writable) {\n writeFileSync(join(cwd, report.destination), report.content);\n\n const entry = config.installed[report.component];\n if (entry) entry.files[report.destination] = report.hash;\n }\n\n writeConfig(cwd, config);\n\n logger.blank();\n logger.success(`Updated ${String(writable.length)} file(s).`);\n if (!options.overwrite && conflicts.length > 0) {\n logger.warn(`${String(conflicts.length)} locally modified file(s) were left alone.`);\n }\n}\n","#!/usr/bin/env node\nimport { readFileSync } from \"node:fs\";\n\nimport { Command } from \"commander\";\n\nimport { branding } from \"./branding\";\nimport { add } from \"./commands/add\";\nimport { init } from \"./commands/init\";\nimport { list } from \"./commands/list\";\nimport { remove } from \"./commands/remove\";\nimport { update } from \"./commands/update\";\nimport { CliError } from \"./lib/errors\";\nimport { logger, pc } from \"./lib/logger\";\n\n/**\n * Read from the manifest rather than hardcoded, so `--version` cannot drift\n * away from what was actually published. `src/index.ts` and the built\n * `dist/index.js` both sit one directory below package.json, so this resolves\n * to the same file whether the CLI is run from source or from the tarball.\n */\nconst { version } = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(branding.cliName)\n .description(`Add ${branding.libraryName} components to your project as source you own.`)\n .version(version)\n .option(\"-c, --cwd <path>\", \"project root\", process.cwd())\n .option(\"-r, --registry <url>\", \"registry base URL, or a directory on disk\");\n\ninterface GlobalOptions {\n cwd: string;\n registry?: string;\n}\n\nfunction globals(): GlobalOptions {\n return program.opts<GlobalOptions>();\n}\n\nprogram\n .command(\"init\")\n .description(\"set the project up: config, utilities and design tokens\")\n .option(\"-y, --yes\", \"accept every default and never prompt\", false)\n .option(\"--skip-install\", \"write files but do not install dependencies\", false)\n .action(async (options: { yes: boolean; skipInstall: boolean }) => {\n const { cwd, registry } = globals();\n await init({\n cwd,\n registry: registry ?? branding.registryUrl,\n yes: options.yes,\n skipInstall: options.skipInstall,\n });\n });\n\nprogram\n .command(\"add\")\n .description(\"add one or more components, with everything they depend on\")\n .argument(\"[components...]\", \"component names\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-o, --overwrite\", \"replace files that have local changes\", false)\n .option(\"--skip-install\", \"write files but do not install dependencies\", false)\n .action(\n async (\n components: string[],\n options: { yes: boolean; overwrite: boolean; skipInstall: boolean },\n ) => {\n const { cwd, registry } = globals();\n await add(components, {\n cwd,\n registry,\n yes: options.yes,\n overwrite: options.overwrite,\n skipInstall: options.skipInstall,\n });\n },\n );\n\nprogram\n .command(\"list\")\n .alias(\"ls\")\n .description(\"list everything in the registry, marking what is installed\")\n .option(\"--category <name>\", \"show one category only\")\n .option(\"--json\", \"machine-readable output\", false)\n .action(async (options: { category?: string; json: boolean }) => {\n const { cwd, registry } = globals();\n await list({ cwd, registry, category: options.category, json: options.json });\n });\n\nprogram\n .command(\"remove\")\n .alias(\"rm\")\n .description(\"delete installed components, keeping anything you have edited\")\n .argument(\"[components...]\", \"component names\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-f, --force\", \"delete files that have local changes too\", false)\n .action(async (components: string[], options: { yes: boolean; force: boolean }) => {\n const { cwd } = globals();\n await remove(components, { cwd, yes: options.yes, force: options.force });\n });\n\nprogram\n .command(\"update\")\n .description(\"compare installed components against the registry\")\n .argument(\"[components...]\", \"component names; defaults to everything installed\")\n .option(\"-y, --yes\", \"do not ask for confirmation\", false)\n .option(\"-o, --overwrite\", \"replace files that have local changes\", false)\n .action(async (components: string[], options: { yes: boolean; overwrite: boolean }) => {\n const { cwd, registry } = globals();\n await update(components, {\n cwd,\n registry,\n yes: options.yes,\n overwrite: options.overwrite,\n });\n });\n\n/**\n * A CliError is a message for the person running the command; anything else is\n * a bug, and its stack trace is the useful part.\n */\nasync function main(): Promise<void> {\n try {\n await program.parseAsync(process.argv);\n } catch (error) {\n logger.blank();\n if (error instanceof CliError) {\n logger.error(error.message);\n if (error.hint) logger.info(pc.dim(` ${error.hint}`));\n } else {\n logger.error(\"Something went wrong.\");\n logger.info(String(error instanceof Error ? (error.stack ?? error.message) : error));\n }\n logger.blank();\n process.exitCode = 1;\n }\n}\n\nvoid main();\n\nexport { add, init, list, remove, update };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dowel-ui/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "description": "Installs Dowel components into your project as source you own, with dependencies resolved and imports rewritten to your path aliases.",
6
6
  "keywords": [
@@ -55,8 +55,8 @@
55
55
  "tsx": "4.23.13",
56
56
  "typescript": "6.0.3",
57
57
  "vitest": "4.1.10",
58
- "@dowel-ui/registry": "0.4.0",
59
- "@dowel-ui/config": "0.4.0"
58
+ "@dowel-ui/config": "0.5.0",
59
+ "@dowel-ui/registry": "0.5.0"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "tsdown",