uilint 0.2.45 → 0.2.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-KNZVCCXM.js → chunk-5536ROOI.js} +3 -3
- package/dist/{chunk-KNZVCCXM.js.map → chunk-5536ROOI.js.map} +1 -1
- package/dist/{chunk-TWUDB36F.js → chunk-VSBVUS56.js} +3 -3
- package/dist/chunk-VSBVUS56.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/{install-ui-5KY5YGLX.js → init-ui-RQKFF33G.js} +31 -31
- package/dist/init-ui-RQKFF33G.js.map +1 -0
- package/dist/{plan-N453UW4O.js → plan-ZWGKTWQ3.js} +3 -3
- package/dist/plan-ZWGKTWQ3.js.map +1 -0
- package/package.json +5 -5
- package/skills/ui-consistency-enforcer/references/REGISTRY-ENTRY.md +2 -2
- package/dist/chunk-TWUDB36F.js.map +0 -1
- package/dist/install-ui-5KY5YGLX.js.map +0 -1
- package/dist/plan-N453UW4O.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/init/versioning.ts","../src/commands/init/constants.ts","../src/utils/skill-loader.ts"],"sourcesContent":["import { createRequire } from \"module\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\n\nconst require = createRequire(import.meta.url);\n\nexport interface ToInstallSpecifierOptions {\n /**\n * When true, prefer pnpm workspace protocol for internal packages so local\n * monorepo installs always link the latest workspace version.\n */\n preferWorkspaceProtocol?: boolean;\n /** Workspace root (used for pnpm-workspace detection) */\n workspaceRoot?: string;\n /** Target project path (used to ensure target is within workspace) */\n targetProjectPath?: string;\n}\n\nfunction isWithinDir(childPath: string, parentPath: string): boolean {\n const parent = parentPath.endsWith(\"/\") ? parentPath : parentPath + \"/\";\n return childPath === parentPath || childPath.startsWith(parent);\n}\n\nfunction isPnpmWorkspaceRoot(dir: string | undefined): boolean {\n if (!dir) return false;\n return existsSync(join(dir, \"pnpm-workspace.yaml\"));\n}\n\nfunction workspaceHasPackage(\n workspaceRoot: string | undefined,\n pkgName: string\n): boolean {\n if (!workspaceRoot) return false;\n // In this repo, workspace packages live under /packages/<name>/package.json\n return existsSync(join(workspaceRoot, \"packages\", pkgName, \"package.json\"));\n}\n\nfunction tryReadInstalledVersion(pkgName: string): string | null {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const depPkg = require(`${pkgName}/package.json`) as Record<\n string,\n unknown\n >;\n const v = depPkg?.version;\n return typeof v === \"string\" ? v : null;\n } catch {\n // Fallback: try filesystem relative to this package (best-effort)\n try {\n const p = require.resolve(`${pkgName}/package.json`);\n const raw = readFileSync(p, \"utf-8\");\n const parsed = JSON.parse(raw) as { version?: string };\n return typeof parsed.version === \"string\" ? parsed.version : null;\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Get the version range for a dependency from uilint's package.json\n *\n * Note: We also check devDependencies so we can expose install-time version\n * ranges (e.g. for uilint-react) without forcing them to be runtime deps of the CLI.\n */\nexport function getSelfDependencyVersionRange(pkgName: string): string | null {\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const pkgJson = require(\"uilint/package.json\") as Record<string, unknown>;\n const deps = pkgJson?.dependencies as Record<string, string> | undefined;\n const optDeps = pkgJson?.optionalDependencies as\n | Record<string, string>\n | undefined;\n const peerDeps = pkgJson?.peerDependencies as\n | Record<string, string>\n | undefined;\n const devDeps = pkgJson?.devDependencies as\n | Record<string, string>\n | undefined;\n\n const v =\n deps?.[pkgName] ??\n optDeps?.[pkgName] ??\n peerDeps?.[pkgName] ??\n devDeps?.[pkgName];\n return typeof v === \"string\" ? v : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Convert package name to install specifier with version (when possible)\n */\nexport function toInstallSpecifier(\n pkgName: string,\n options: ToInstallSpecifierOptions = {}\n): string {\n const { preferWorkspaceProtocol, workspaceRoot, targetProjectPath } = options;\n\n // Local monorepo: force workspace protocol for internal packages.\n if (\n preferWorkspaceProtocol &&\n isPnpmWorkspaceRoot(workspaceRoot) &&\n typeof targetProjectPath === \"string\" &&\n isWithinDir(targetProjectPath, workspaceRoot || \"\") &&\n workspaceHasPackage(workspaceRoot, pkgName)\n ) {\n return `${pkgName}@workspace:*`;\n }\n\n const range = getSelfDependencyVersionRange(pkgName);\n if (!range) return pkgName;\n if (range.startsWith(\"workspace:\")) {\n // In published builds, pnpm usually rewrites workspace: to a semver range.\n // But if it doesn't, fall back to the actually installed dependency version.\n const installed = tryReadInstalledVersion(pkgName);\n return installed ? `${pkgName}@^${installed}` : pkgName;\n }\n if (range.startsWith(\"file:\")) return pkgName;\n if (range.startsWith(\"link:\")) return pkgName;\n return `${pkgName}@${range}`;\n}\n","/**\n * Constants for the install command\n *\n * Contains file content templates for commands.\n */\n\n// ============================================================================\n// Cursor Commands\n// ============================================================================\n\nexport const GENSTYLEGUIDE_COMMAND_MD = `# React Style Guide Generator\n\nAnalyze the React UI codebase to produce a **prescriptive, semantic** style guide. Focus on consistency, intent, and relationships—not specific values.\n\n## Philosophy\n\n1. **Identify the intended architecture** from the best patterns in use\n2. **Prescribe semantic rules** — about consistency and relationships, not pixels\n3. **Stay general** — \"primary buttons should be visually consistent\" not \"buttons use px-4\"\n4. **Focus on intent** — what should FEEL the same, not what values to use\n\n## Analysis Steps\n\n### 1. Detect the Stack\n- Framework: Next.js (App Router? Pages?), Vite, CRA\n- Component system: shadcn, MUI, Chakra, Radix, custom\n- Styling: Tailwind, CSS Modules, styled-components\n- Forms: react-hook-form, Formik, native\n- State: React context, Zustand, Redux, Jotai\n\n### 2. Identify Best Patterns\nExamine the **best-written** components. Look at:\n- \\`components/ui/*\\` — the design system\n- Recently modified files — current standards\n- Shared layouts — structural patterns\n\n### 3. Infer Visual Hierarchy & Intent\nUnderstand the design language:\n- What distinguishes primary vs secondary actions?\n- How is visual hierarchy established?\n- What creates consistency across similar elements?\n\n## Output Format\n\nGenerate at \\`<nextjs app root>/.uilint/styleguide.md\\`:\n\\`\\`\\`yaml\n# Stack\nframework: \nstyling: \ncomponents: \ncomponent_path: \nforms: \n\n# Component Usage (MUST use these)\nuse:\n buttons: \n inputs: \n modals: \n cards: \n feedback: \n icons: \n links: \n\n# Semantic Rules (consistency & relationships)\nsemantics:\n hierarchy:\n - <e.g., \"primary actions must be visually distinct from secondary\">\n - <e.g., \"destructive actions should be visually cautionary\">\n - <e.g., \"page titles should be visually heavier than section titles\">\n consistency:\n - <e.g., \"all primary buttons should share the same visual weight\">\n - <e.g., \"form inputs should have uniform height and padding\">\n - <e.g., \"card padding should be consistent across the app\">\n - <e.g., \"interactive elements should have consistent hover/focus states\">\n spacing:\n - <e.g., \"use the spacing scale — no arbitrary values\">\n - <e.g., \"related elements should be closer than unrelated\">\n - <e.g., \"section spacing should be larger than element spacing\">\n layout:\n - <e.g., \"use gap for sibling spacing, not margin\">\n - <e.g., \"containers should have consistent max-width and padding\">\n\n# Patterns (structural, not values)\npatterns:\n forms: <e.g., \"FormField + Controller + zod schema\">\n conditionals: <e.g., \"cn() for class merging\">\n loading: <e.g., \"Skeleton for content, Spinner for actions\">\n errors: <e.g., \"ErrorBoundary at route, inline for forms\">\n responsive: <e.g., \"mobile-first, standard breakpoints only\">\n\n# Component Authoring\nauthoring:\n - <e.g., \"forwardRef for interactive components\">\n - <e.g., \"variants via CVA or component props, not className overrides\">\n - <e.g., \"extract when used 2+ times\">\n - <e.g., \"'use client' only when needed\">\n\n# Forbidden\nforbidden:\n - <e.g., \"inline style={{}}\">\n - <e.g., \"raw HTML elements when component exists\">\n - <e.g., \"arbitrary values — use scale\">\n - <e.g., \"className overrides that break visual consistency\">\n - <e.g., \"one-off spacing that doesn't match siblings\">\n\n# Legacy (if migration in progress)\nlegacy:\n - <e.g., \"old: CSS modules → new: Tailwind\">\n - <e.g., \"old: Formik → new: react-hook-form\">\n\n# Conventions\nconventions:\n - \n - \n - \n\\`\\`\\`\n\n## Rules\n\n- **Semantic over specific**: \"consistent padding\" not \"p-4\"\n- **Relationships over absolutes**: \"heavier than\" not \"font-bold\"\n- **Intent over implementation**: \"visually distinct\" not \"blue background\"\n- **Prescriptive**: Define target state, not current state\n- **Terse**: No prose. Fragments and short phrases only.\n- **Actionable**: Every rule should be human-verifiable\n- **Omit if N/A**: Skip sections that don't apply\n- **Max 5 items** per section — highest impact only\n`;\n\n","/**\n * Skill Loader Utility\n *\n * Loads Agent Skill files from the bundled skills directory for installation\n * into user projects. Skills follow the Agent Skills specification\n * (agentskills.io).\n */\n\nimport { readFileSync, readdirSync, statSync, existsSync } from \"fs\";\nimport { join, dirname, relative } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Represents a file in a skill directory\n */\nexport interface SkillFile {\n /** Relative path within the skill directory */\n relativePath: string;\n /** File content */\n content: string;\n}\n\n/**\n * Represents a complete skill ready for installation\n */\nexport interface Skill {\n /** Skill name (directory name) */\n name: string;\n /** All files in the skill */\n files: SkillFile[];\n}\n\n/**\n * Get the path to the bundled skills directory\n */\nfunction getSkillsDir(): string {\n // In development: packages/uilint/skills/\n // In production (installed): node_modules/uilint/dist/ -> ../skills/\n const devPath = join(__dirname, \"..\", \"..\", \"skills\");\n const prodPath = join(__dirname, \"..\", \"skills\");\n\n if (existsSync(devPath)) {\n return devPath;\n }\n if (existsSync(prodPath)) {\n return prodPath;\n }\n\n throw new Error(\n \"Could not find skills directory. This is a bug in uilint installation.\"\n );\n}\n\n/**\n * Recursively collect all files in a directory\n */\nfunction collectFiles(dir: string, baseDir: string): SkillFile[] {\n const files: SkillFile[] = [];\n const entries = readdirSync(dir);\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n files.push(...collectFiles(fullPath, baseDir));\n } else if (stat.isFile()) {\n const relativePath = relative(baseDir, fullPath);\n const content = readFileSync(fullPath, \"utf-8\");\n files.push({ relativePath, content });\n }\n }\n\n return files;\n}\n\n/**\n * Load a specific skill by name\n */\nexport function loadSkill(name: string): Skill {\n const skillsDir = getSkillsDir();\n const skillDir = join(skillsDir, name);\n\n if (!existsSync(skillDir)) {\n throw new Error(`Skill \"${name}\" not found in ${skillsDir}`);\n }\n\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (!existsSync(skillMdPath)) {\n throw new Error(`Skill \"${name}\" is missing SKILL.md`);\n }\n\n const files = collectFiles(skillDir, skillDir);\n\n return { name, files };\n}\n\n/**\n * Load all available skills\n */\nexport function loadAllSkills(): Skill[] {\n const skillsDir = getSkillsDir();\n const entries = readdirSync(skillsDir);\n const skills: Skill[] = [];\n\n for (const entry of entries) {\n const skillDir = join(skillsDir, entry);\n const stat = statSync(skillDir);\n\n if (stat.isDirectory()) {\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (existsSync(skillMdPath)) {\n skills.push(loadSkill(entry));\n }\n }\n }\n\n return skills;\n}\n\n/**\n * Get the list of available skill names\n */\nexport function getAvailableSkillNames(): string[] {\n const skillsDir = getSkillsDir();\n const entries = readdirSync(skillsDir);\n const names: string[] = [];\n\n for (const entry of entries) {\n const skillDir = join(skillsDir, entry);\n const stat = statSync(skillDir);\n\n if (stat.isDirectory()) {\n const skillMdPath = join(skillDir, \"SKILL.md\");\n if (existsSync(skillMdPath)) {\n names.push(entry);\n }\n }\n }\n\n return names;\n}\n"],"mappings":"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","names":["require","readFileSync","existsSync","join"]}
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
readRuleConfigsFromConfig,
|
|
10
10
|
updateRuleConfigInConfig,
|
|
11
11
|
updateRuleSeverityInConfig
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5536ROOI.js";
|
|
13
13
|
import {
|
|
14
14
|
createSpinner,
|
|
15
15
|
intro,
|
|
@@ -3644,9 +3644,9 @@ program.command("update").description("Update existing style guide with new styl
|
|
|
3644
3644
|
llm: options.llm
|
|
3645
3645
|
});
|
|
3646
3646
|
});
|
|
3647
|
-
program.command("
|
|
3648
|
-
const {
|
|
3649
|
-
await
|
|
3647
|
+
program.command("init").description("Initialize UILint integration").option("--force", "Overwrite existing configuration files").action(async (options) => {
|
|
3648
|
+
const { initUI } = await import("./init-ui-RQKFF33G.js");
|
|
3649
|
+
await initUI({ force: options.force });
|
|
3650
3650
|
});
|
|
3651
3651
|
program.command("serve").description("Start WebSocket server for real-time UI linting").option("-p, --port <number>", "Port to listen on", "9234").action(async (options) => {
|
|
3652
3652
|
await serve({
|