uilint 0.2.149 → 0.2.151
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/{chunk-VKI3SQMQ.js → chunk-EBGFEMCH.js} +15 -7
- package/dist/chunk-EBGFEMCH.js.map +1 -0
- package/dist/{chunk-5QUW7BNW.js → chunk-GFJDTSYD.js} +2 -2
- package/dist/chunk-GFJDTSYD.js.map +1 -0
- package/dist/{chunk-OW7Y4RTR.js → chunk-WB2QAJRH.js} +13 -13
- package/dist/chunk-WB2QAJRH.js.map +1 -0
- package/dist/index.js +22 -10
- package/dist/index.js.map +1 -1
- package/dist/{init-ui-QQXIZSKI.js → init-ui-CIK6YKOZ.js} +5 -5
- package/dist/{plan-ZJSVJL5X.js → plan-4E2RJB64.js} +3 -3
- package/dist/{plugin-loader-LUIV7MLR.js → plugin-loader-V5CAMTYQ.js} +2 -2
- package/dist/{upgrade-2UKW3SIQ.js → upgrade-WP6U3LEO.js} +3 -3
- package/package.json +12 -8
- package/dist/chunk-5QUW7BNW.js.map +0 -1
- package/dist/chunk-OW7Y4RTR.js.map +0 -1
- package/dist/chunk-VKI3SQMQ.js.map +0 -1
- /package/dist/{init-ui-QQXIZSKI.js.map → init-ui-CIK6YKOZ.js.map} +0 -0
- /package/dist/{plan-ZJSVJL5X.js.map → plan-4E2RJB64.js.map} +0 -0
- /package/dist/{plugin-loader-LUIV7MLR.js.map → plugin-loader-V5CAMTYQ.js.map} +0 -0
- /package/dist/{upgrade-2UKW3SIQ.js.map → upgrade-WP6U3LEO.js.map} +0 -0
|
@@ -79,11 +79,7 @@ var EXPORTED_UTILITIES = [
|
|
|
79
79
|
"styleguide-loader",
|
|
80
80
|
"import-graph",
|
|
81
81
|
"component-parser",
|
|
82
|
-
"export-resolver"
|
|
83
|
-
"coverage-aggregator",
|
|
84
|
-
"dependency-graph",
|
|
85
|
-
"file-categorizer",
|
|
86
|
-
"jsx-coverage-analyzer"
|
|
82
|
+
"export-resolver"
|
|
87
83
|
];
|
|
88
84
|
var EXPORT_RENAMES = {
|
|
89
85
|
"import-graph:clearCache": "clearImportGraphCache"
|
|
@@ -250,10 +246,22 @@ function loadRule(ruleId, options = { typescript: true }) {
|
|
|
250
246
|
}
|
|
251
247
|
}
|
|
252
248
|
function loadSelectedRules(ruleIds, options = { typescript: true }) {
|
|
253
|
-
|
|
249
|
+
const results = [];
|
|
250
|
+
for (const id of ruleIds) {
|
|
251
|
+
try {
|
|
252
|
+
results.push(loadRule(id, options));
|
|
253
|
+
} catch (e) {
|
|
254
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
255
|
+
if (msg.includes("not found at")) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
throw e;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return results;
|
|
254
262
|
}
|
|
255
263
|
|
|
256
264
|
export {
|
|
257
265
|
loadSelectedRules
|
|
258
266
|
};
|
|
259
|
-
//# sourceMappingURL=chunk-
|
|
267
|
+
//# sourceMappingURL=chunk-EBGFEMCH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/rule-loader.ts"],"sourcesContent":["/**\n * Rule Loader Utility\n *\n * Loads ESLint rule source files from the uilint-eslint package for installation\n * into user projects. Rules are copied to .uilint/rules/ in the target project.\n */\n\nimport { readFileSync, existsSync, readdirSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { createRequire } from \"module\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst require = createRequire(import.meta.url);\n\nfunction findNodeModulesPackageRoot(\n pkgName: string,\n startDir: string\n): string | null {\n let dir = startDir;\n while (true) {\n const candidate = join(dir, \"node_modules\", pkgName);\n if (existsSync(join(candidate, \"package.json\"))) return candidate;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction getUilintEslintPackageRoot(): string {\n // Prefer a filesystem-based lookup first. This avoids Node resolution edge\n // cases with package.json \"exports\" (especially ESM-only packages), and works\n // well for monorepos + pnpm where node_modules contains symlinks.\n //\n // Search upwards from process.cwd() (the user's project) and from this file\n // location (for test/dev environments).\n const fromCwd = findNodeModulesPackageRoot(\"uilint-eslint\", process.cwd());\n if (fromCwd) return fromCwd;\n\n const fromHere = findNodeModulesPackageRoot(\"uilint-eslint\", __dirname);\n if (fromHere) return fromHere;\n\n // Last resort: try resolver-based lookup.\n try {\n const entry = require.resolve(\"uilint-eslint\"); // typically .../dist/index.js\n const entryDir = dirname(entry); // typically .../dist\n return dirname(entryDir); // package root\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(\n `Unable to locate uilint-eslint in node_modules (searched upwards from cwd and uilint's install path).\\n` +\n `Resolver error: ${msg}\\n` +\n `Fix: ensure uilint-eslint is installed in the target project (or workspace) and try again.`\n );\n }\n}\n\n/**\n * Represents a file for a rule (implementation or test)\n */\nexport interface RuleFile {\n /** Relative path within the rules directory (e.g., \"consistent-dark-mode.ts\") */\n relativePath: string;\n /** File content */\n content: string;\n}\n\n/**\n * Represents a complete rule ready for installation\n */\nexport interface RuleFiles {\n /** Rule identifier (e.g., \"consistent-dark-mode\") */\n ruleId: string;\n /** Implementation file (main entry point - index.ts for directory rules, or single file) */\n implementation: RuleFile;\n /** Additional files for directory-based rules (lib/ utilities, etc.) */\n additionalFiles?: RuleFile[];\n /** Test file (if exists) */\n test?: RuleFile;\n}\n\n/**\n * Get the path to the uilint-eslint package source directory\n */\nfunction getUilintEslintSrcDir(): string {\n // In development: packages/uilint-eslint/src/\n // In production (installed): node_modules/uilint-eslint/src/\n\n // Try workspace/dev path first (repo layout)\n const devPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n \"uilint-eslint\",\n \"src\"\n );\n if (existsSync(devPath)) return devPath;\n\n // Try from installed package root (works with \"exports\")\n const pkgRoot = getUilintEslintPackageRoot();\n const srcPath = join(pkgRoot, \"src\");\n if (existsSync(srcPath)) return srcPath;\n\n throw new Error(\n 'Could not find uilint-eslint \"src/\" directory. If you are using a published install of uilint-eslint, ensure it includes source files, or run a JS-only rules install.'\n );\n}\n\n/**\n * Get the path to the uilint-eslint package dist directory\n */\nfunction getUilintEslintDistDir(): string {\n // In development: packages/uilint-eslint/dist/\n // In production (installed): node_modules/uilint-eslint/dist/\n\n // Try workspace/dev path first (repo layout)\n const devPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n \"uilint-eslint\",\n \"dist\"\n );\n if (existsSync(devPath)) return devPath;\n\n // Try from installed package root (works with \"exports\")\n const pkgRoot = getUilintEslintPackageRoot();\n const distPath = join(pkgRoot, \"dist\");\n if (existsSync(distPath)) return distPath;\n\n throw new Error(\n 'Could not find uilint-eslint \"dist/\" directory. This is a bug in uilint installation.'\n );\n}\n\n/**\n * All utilities that are exported from uilint-eslint and can be imported.\n * When adding a new utility to uilint-eslint that rules may import,\n * add it here AND export it from uilint-eslint/src/index.ts.\n *\n * Rules can also declare their dependencies via the `internalDependencies`\n * field in defineRuleMeta() - this serves as documentation and can be\n * used for validation.\n */\nconst EXPORTED_UTILITIES = [\n \"create-rule\",\n \"cache\",\n \"styleguide-loader\",\n \"import-graph\",\n \"component-parser\",\n \"export-resolver\",\n];\n\n/**\n * Maps internal export names to their uilint-eslint export names.\n * Some exports are renamed when re-exported from the main package\n * to avoid naming conflicts.\n *\n * Format: \"utilFile:internalName\" -> \"externalName\"\n */\nconst EXPORT_RENAMES: Record<string, string> = {\n \"import-graph:clearCache\": \"clearImportGraphCache\",\n};\n\n/**\n * Transform an import specifier, applying any necessary renames.\n * Handles both simple imports (foo) and aliased imports (foo as bar).\n */\nfunction transformImportSpecifier(specifier: string, utilFile: string): string {\n const trimmed = specifier.trim();\n\n // Check for aliased import: \"localName as alias\"\n const aliasMatch = trimmed.match(/^(\\w+)\\s+as\\s+(\\w+)$/);\n if (aliasMatch) {\n const [, localName, alias] = aliasMatch;\n const renameKey = `${utilFile}:${localName}`;\n const externalName = EXPORT_RENAMES[renameKey];\n if (externalName) {\n // If the alias matches the external name, simplify to just the name\n if (alias === externalName) {\n return externalName;\n }\n // Otherwise, use the external name with the original alias\n return `${externalName} as ${alias}`;\n }\n // No rename needed, keep original\n return trimmed;\n }\n\n // Simple import: check if it needs renaming\n const renameKey = `${utilFile}:${trimmed}`;\n const externalName = EXPORT_RENAMES[renameKey];\n if (externalName) {\n return externalName;\n }\n\n return trimmed;\n}\n\n/**\n * External packages that are re-exported from uilint-eslint.\n * When rules import these packages directly, transform them to import from uilint-eslint instead.\n * This ensures the dependencies are resolved correctly when rules are copied to user projects.\n */\nconst REEXPORTED_PACKAGES: Record<string, string[]> = {\n \"oxc-resolver\": [\"ResolverFactory\"],\n};\n\n/**\n * Transform rule content to fix imports for copied location\n * Changes imports from \"../utils/...\" or \"../../utils/...\" to \"uilint-eslint\"\n * Also transforms external package imports that are re-exported from uilint-eslint\n */\nfunction transformRuleContent(content: string): string {\n let transformed = content;\n\n // Replace all relative utility imports with uilint-eslint imports\n // Pattern: import { ... } from \"../utils/create-rule.js\" or \"../../utils/create-rule.js\"\n // This handles any combination of imports like { createRule, defineRuleMeta }\n transformed = transformed.replace(\n /import\\s+{([^}]+)}\\s+from\\s+[\"'](?:\\.\\.\\/)+utils\\/([^\"']+)\\.js[\"'];?/g,\n (match, imports, utilFile) => {\n if (EXPORTED_UTILITIES.includes(utilFile)) {\n // Transform each import specifier\n const specifiers = imports.split(\",\").map((s: string) =>\n transformImportSpecifier(s, utilFile)\n );\n return `import { ${specifiers.join(\", \")} } from \"uilint-eslint\";`;\n }\n return match; // Keep original if not a known utility\n }\n );\n\n // Also handle default imports: import createRule from \"../utils/create-rule.js\"\n transformed = transformed.replace(\n /import\\s+(\\w+)\\s+from\\s+[\"'](?:\\.\\.\\/)+utils\\/([^\"']+)\\.js[\"'];?/g,\n (match, importName, utilFile) => {\n if (EXPORTED_UTILITIES.includes(utilFile)) {\n return `import { ${importName} } from \"uilint-eslint\";`;\n }\n return match;\n }\n );\n\n // Transform external package imports that are re-exported from uilint-eslint\n // Pattern: import { ResolverFactory } from \"oxc-resolver\"\n for (const [pkgName, exports] of Object.entries(REEXPORTED_PACKAGES)) {\n const escapedPkgName = pkgName.replace(/-/g, \"\\\\-\");\n const regex = new RegExp(\n `import\\\\s+{([^}]+)}\\\\s+from\\\\s+[\"']${escapedPkgName}[\"'];?`,\n \"g\"\n );\n transformed = transformed.replace(regex, (match, imports) => {\n const importNames = imports.split(\",\").map((s: string) => s.trim());\n // Only transform if all imported names are re-exported from uilint-eslint\n const allReexported = importNames.every((name: string) => {\n // Handle \"Foo as Bar\" syntax - extract the original name\n const originalName = name.split(/\\s+as\\s+/)[0].trim();\n return exports.includes(originalName);\n });\n if (allReexported) {\n return `import { ${imports} } from \"uilint-eslint\";`;\n }\n return match;\n });\n }\n\n return transformed;\n}\n\n/**\n * Check if a rule is directory-based (has index.ts/index.js) or single-file\n */\nfunction isDirectoryBasedRule(rulesDir: string, ruleId: string): boolean {\n const ruleDir = join(rulesDir, ruleId);\n return existsSync(ruleDir) && existsSync(join(ruleDir, \"index.ts\"));\n}\n\n/**\n * Load all files from a directory-based rule\n */\nfunction loadDirectoryRule(\n rulesDir: string,\n ruleId: string\n): { files: RuleFile[]; testFile?: RuleFile } {\n const ruleDir = join(rulesDir, ruleId);\n const files: RuleFile[] = [];\n let testFile: RuleFile | undefined;\n\n function collectFiles(dir: string, relativeTo: string): void {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n const relativePath = join(relativeTo, entry.name);\n\n if (entry.isDirectory()) {\n collectFiles(fullPath, relativePath);\n } else if (entry.name.endsWith(\".ts\")) {\n if (entry.name.endsWith(\".test.ts\")) {\n // Handle test file separately\n testFile = {\n relativePath,\n content: transformRuleContent(readFileSync(fullPath, \"utf-8\")),\n };\n } else {\n files.push({\n relativePath,\n content: transformRuleContent(readFileSync(fullPath, \"utf-8\")),\n });\n }\n }\n }\n }\n\n collectFiles(ruleDir, ruleId);\n return { files, testFile };\n}\n\n/**\n * Load a specific rule by ID\n */\nexport function loadRule(\n ruleId: string,\n options: { typescript: boolean } = { typescript: true }\n): RuleFiles {\n const { typescript } = options;\n const _extension = typescript ? \".ts\" : \".js\";\n\n if (typescript) {\n // Load TypeScript source files\n const rulesDir = join(getUilintEslintSrcDir(), \"rules\");\n\n // Check if this is a directory-based rule\n if (isDirectoryBasedRule(rulesDir, ruleId)) {\n const { files, testFile } = loadDirectoryRule(rulesDir, ruleId);\n\n if (files.length === 0) {\n throw new Error(`Rule \"${ruleId}\" directory exists but contains no TypeScript files`);\n }\n\n // Find the index.ts as the main implementation\n const indexFile = files.find((f) => f.relativePath === join(ruleId, \"index.ts\"));\n if (!indexFile) {\n throw new Error(`Rule \"${ruleId}\" directory missing index.ts`);\n }\n\n return {\n ruleId,\n implementation: indexFile,\n additionalFiles: files.filter((f) => f !== indexFile),\n test: testFile,\n };\n }\n\n // Single-file rule\n const implPath = join(rulesDir, `${ruleId}.ts`);\n const testPath = join(rulesDir, `${ruleId}.test.ts`);\n\n if (!existsSync(implPath)) {\n throw new Error(`Rule \"${ruleId}\" not found at ${implPath}`);\n }\n\n const rawContent = readFileSync(implPath, \"utf-8\");\n const transformedContent = transformRuleContent(rawContent);\n\n const implementation: RuleFile = {\n relativePath: `${ruleId}.ts`,\n content: transformedContent,\n };\n\n const test: RuleFile | undefined = existsSync(testPath)\n ? {\n relativePath: `${ruleId}.test.ts`,\n content: transformRuleContent(readFileSync(testPath, \"utf-8\")),\n }\n : undefined;\n\n return {\n ruleId,\n implementation,\n test,\n };\n } else {\n // Load compiled JavaScript files\n const rulesDir = join(getUilintEslintDistDir(), \"rules\");\n const implPath = join(rulesDir, `${ruleId}.js`);\n\n if (!existsSync(implPath)) {\n throw new Error(\n `Rule \"${ruleId}\" not found at ${implPath}. ` +\n `For JavaScript-only projects, uilint-eslint must be built to include compiled rule files in dist/rules/. ` +\n `If you're developing uilint-eslint, run 'pnpm build' in packages/uilint-eslint. ` +\n `If you're using a published package, ensure it includes the dist/ directory.`\n );\n }\n\n // Compiled JS files don't need transformation - they already use uilint-eslint imports\n const content = readFileSync(implPath, \"utf-8\");\n\n const implementation: RuleFile = {\n relativePath: `${ruleId}.js`,\n content,\n };\n\n // Test files are not compiled, so we don't copy them for JS projects\n return {\n ruleId,\n implementation,\n };\n }\n}\n\n/**\n * Load multiple rules by their IDs.\n * Rules that cannot be found on disk are silently skipped — this handles\n * plugin-contributed rules that may still appear in the ID list when filters\n * don't fully exclude them (e.g. dual-package instance issues).\n */\nexport function loadSelectedRules(\n ruleIds: string[],\n options: { typescript: boolean } = { typescript: true }\n): RuleFiles[] {\n const results: RuleFiles[] = [];\n for (const id of ruleIds) {\n try {\n results.push(loadRule(id, options));\n } catch (e) {\n // Log but don't crash — the rule may be a plugin-contributed rule\n // that isn't present in uilint-eslint's source/dist directories.\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes(\"not found at\")) {\n // Skip silently — external plugin rule\n continue;\n }\n throw e;\n }\n }\n return results;\n}\n\n/**\n * Get the list of available rule IDs from the registry\n */\nexport function getAvailableRuleIds(): string[] {\n try {\n // Import the rule registry from uilint-eslint\n const { ruleRegistry } = require(\"uilint-eslint\");\n return ruleRegistry.map((rule: { id: string }) => rule.id);\n } catch {\n // Fallback: try to read from filesystem\n const rulesDir = join(getUilintEslintSrcDir(), \"rules\");\n if (!existsSync(rulesDir)) {\n return [];\n }\n\n // This is a fallback - ideally we'd use the registry\n // But if we can't import it, we can at least try to list files\n const files = readdirSync(rulesDir);\n return files\n .filter((f: string) => f.endsWith(\".ts\") && !f.endsWith(\".test.ts\"))\n .map((f: string) => f.replace(\".ts\", \"\"));\n }\n}\n"],"mappings":"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","names":["require","renameKey","externalName"]}
|
|
@@ -8,7 +8,7 @@ import { createRequire } from "module";
|
|
|
8
8
|
import { existsSync, readFileSync } from "fs";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { pathToFileURL } from "url";
|
|
11
|
-
var KNOWN_PLUGIN_PACKAGES = ["uilint-vision", "uilint-semantic", "uilint-duplicates"];
|
|
11
|
+
var KNOWN_PLUGIN_PACKAGES = ["uilint-vision", "uilint-semantic", "uilint-duplicates", "uilint-coverage"];
|
|
12
12
|
async function importFromProject(specifier, projectPath) {
|
|
13
13
|
try {
|
|
14
14
|
const req = createRequire(join(projectPath, "package.json"));
|
|
@@ -77,4 +77,4 @@ export {
|
|
|
77
77
|
discoverPlugins,
|
|
78
78
|
loadPluginESLintRules
|
|
79
79
|
};
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-GFJDTSYD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/plugin-loader.ts"],"sourcesContent":["/**\n * Dynamic plugin loader for the CLI.\n *\n * Probes known plugin package names for a `cli-manifest` subpath export.\n * Each manifest describes the CLI flag, help text, and registration entry\n * point, keeping the core CLI free of plugin-specific knowledge.\n */\n\nimport { createRequire } from \"module\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { pathToFileURL } from \"url\";\nimport { logInfo } from \"./prompts.js\";\n\n/**\n * Metadata a plugin exposes via its `<pkg>/cli-manifest` subpath export.\n * Plugins define a plain object matching this shape — no shared type import needed.\n */\nexport interface PluginCLIManifest {\n /** npm package name, e.g. \"uilint-vision\" */\n packageName: string;\n /** CLI flag name (without --), e.g. \"vision\" */\n cliFlag: string;\n /** Description shown in --help */\n cliDescription: string;\n /** Import specifier for the register module, e.g. \"uilint-vision/eslint-rules/register\" */\n registerSpecifier: string;\n /** Display name shown in the interactive install UI, e.g. \"Vision Analysis\" */\n displayName: string;\n /** Description shown in the interactive install UI */\n displayDescription: string;\n /** Emoji icon for the interactive install UI, e.g. \"👁️\" */\n displayIcon: string;\n}\n\n/** Package names to probe for CLI manifests */\nconst KNOWN_PLUGIN_PACKAGES = [\"uilint-vision\", \"uilint-semantic\", \"uilint-duplicates\", \"uilint-coverage\"];\n\n/**\n * Resolve and import a package subpath specifier from a given project directory.\n *\n * First tries CJS `createRequire().resolve()`, which works for packages with\n * a `\"require\"` export condition. If that fails (e.g. the package only defines\n * `\"import\"`), falls back to manually reading the package's `exports` map and\n * constructing a file URL.\n */\nasync function importFromProject(\n specifier: string,\n projectPath: string,\n): Promise<unknown> {\n // Try CJS resolution first (fast path)\n try {\n const req = createRequire(join(projectPath, \"package.json\"));\n const resolved = req.resolve(specifier);\n return await import(resolved);\n } catch {\n // CJS resolution failed — try ESM-only export resolution\n }\n\n // Parse \"pkg/subpath\" → [\"pkg\", \"./subpath\"]\n const slashIdx = specifier.indexOf(\"/\");\n if (slashIdx === -1) return undefined;\n const pkgName = specifier.slice(0, slashIdx);\n const subpath = `./${specifier.slice(slashIdx + 1)}`;\n\n const pkgDir = join(projectPath, \"node_modules\", pkgName);\n const pkgJsonPath = join(pkgDir, \"package.json\");\n if (!existsSync(pkgJsonPath)) return undefined;\n\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf8\"));\n const exportEntry = pkgJson.exports?.[subpath];\n if (!exportEntry) return undefined;\n\n const importPath =\n typeof exportEntry === \"string\"\n ? exportEntry\n : exportEntry.import ?? exportEntry.default;\n if (!importPath) return undefined;\n\n const fullPath = join(pkgDir, importPath);\n if (!existsSync(fullPath)) return undefined;\n\n return await import(pathToFileURL(fullPath).href);\n}\n\n/**\n * Discover available plugin manifests by probing `<pkg>/cli-manifest`.\n *\n * @param resolveFrom - Optional project path to resolve plugins from.\n * When provided, resolves plugins from the project's node_modules\n * so plugins installed in the project can be found.\n * @returns Array of discovered plugin manifests\n */\nexport async function discoverPlugins(\n resolveFrom?: string,\n): Promise<PluginCLIManifest[]> {\n const manifests: PluginCLIManifest[] = [];\n\n for (const pkg of KNOWN_PLUGIN_PACKAGES) {\n const specifier = `${pkg}/cli-manifest`;\n try {\n let mod: { cliManifest?: PluginCLIManifest } | undefined;\n if (resolveFrom) {\n mod = (await importFromProject(specifier, resolveFrom)) as typeof mod;\n } else {\n mod = (await import(specifier)) as typeof mod;\n }\n if (mod?.cliManifest) {\n manifests.push(mod.cliManifest);\n }\n } catch {\n // Plugin not installed — skip silently\n }\n }\n\n return manifests;\n}\n\n/**\n * Load ESLint rules from discovered plugins by importing their register modules.\n *\n * The register modules call `registerRuleMeta()` from `uilint-eslint`, which\n * mutates the shared `ruleRegistry` array. To avoid the dual-package problem\n * (project-resolved plugin getting a different `uilint-eslint` instance), we\n * always try a bare `import()` first — this resolves from the CLI's own\n * context so both the CLI and the plugin share the same `ruleRegistry`.\n * Only falls back to project-scoped resolution when the bare import fails\n * (e.g. when running via `npx` where plugins aren't alongside the CLI).\n *\n * @param manifests - Plugin manifests (from discoverPlugins)\n * @param resolveFrom - Optional project path to resolve plugins from.\n * @returns Array of loaded plugin package names\n */\nexport async function loadPluginESLintRules(\n manifests: PluginCLIManifest[],\n resolveFrom?: string,\n): Promise<string[]> {\n const loaded: string[] = [];\n\n for (const manifest of manifests) {\n try {\n // Prefer bare import so the register module shares the CLI's uilint-eslint\n await import(manifest.registerSpecifier);\n loaded.push(manifest.packageName);\n } catch {\n // Bare import failed — try from consumer project if a path was provided\n if (resolveFrom) {\n try {\n await importFromProject(manifest.registerSpecifier, resolveFrom);\n loaded.push(manifest.packageName);\n } catch {\n // Plugin register module not available — skip silently\n }\n }\n }\n }\n\n if (loaded.length > 0) {\n logInfo(`Loaded plugin rules: ${loaded.join(\", \")}`);\n }\n\n return loaded;\n}\n"],"mappings":";;;;;;AAQA,SAAS,qBAAqB;AAC9B,SAAS,YAAY,oBAAoB;AACzC,SAAS,YAAY;AACrB,SAAS,qBAAqB;AAyB9B,IAAM,wBAAwB,CAAC,iBAAiB,mBAAmB,qBAAqB,iBAAiB;AAUzG,eAAe,kBACb,WACA,aACkB;AAElB,MAAI;AACF,UAAM,MAAM,cAAc,KAAK,aAAa,cAAc,CAAC;AAC3D,UAAM,WAAW,IAAI,QAAQ,SAAS;AACtC,WAAO,MAAM,OAAO;AAAA,EACtB,QAAQ;AAAA,EAER;AAGA,QAAM,WAAW,UAAU,QAAQ,GAAG;AACtC,MAAI,aAAa,GAAI,QAAO;AAC5B,QAAM,UAAU,UAAU,MAAM,GAAG,QAAQ;AAC3C,QAAM,UAAU,KAAK,UAAU,MAAM,WAAW,CAAC,CAAC;AAElD,QAAM,SAAS,KAAK,aAAa,gBAAgB,OAAO;AACxD,QAAM,cAAc,KAAK,QAAQ,cAAc;AAC/C,MAAI,CAAC,WAAW,WAAW,EAAG,QAAO;AAErC,QAAM,UAAU,KAAK,MAAM,aAAa,aAAa,MAAM,CAAC;AAC5D,QAAM,cAAc,QAAQ,UAAU,OAAO;AAC7C,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,aACJ,OAAO,gBAAgB,WACnB,cACA,YAAY,UAAU,YAAY;AACxC,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAElC,SAAO,MAAM,OAAO,cAAc,QAAQ,EAAE;AAC9C;AAUA,eAAsB,gBACpB,aAC8B;AAC9B,QAAM,YAAiC,CAAC;AAExC,aAAW,OAAO,uBAAuB;AACvC,UAAM,YAAY,GAAG,GAAG;AACxB,QAAI;AACF,UAAI;AACJ,UAAI,aAAa;AACf,cAAO,MAAM,kBAAkB,WAAW,WAAW;AAAA,MACvD,OAAO;AACL,cAAO,MAAM,OAAO;AAAA,MACtB;AACA,UAAI,KAAK,aAAa;AACpB,kBAAU,KAAK,IAAI,WAAW;AAAA,MAChC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAiBA,eAAsB,sBACpB,WACA,aACmB;AACnB,QAAM,SAAmB,CAAC;AAE1B,aAAW,YAAY,WAAW;AAChC,QAAI;AAEF,YAAM,OAAO,SAAS;AACtB,aAAO,KAAK,SAAS,WAAW;AAAA,IAClC,QAAQ;AAEN,UAAI,aAAa;AACf,YAAI;AACF,gBAAM,kBAAkB,SAAS,mBAAmB,WAAW;AAC/D,iBAAO,KAAK,SAAS,WAAW;AAAA,QAClC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,YAAQ,wBAAwB,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,EACrD;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-JWSZKDZY.js";
|
|
7
7
|
import {
|
|
8
8
|
loadSelectedRules
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EBGFEMCH.js";
|
|
10
10
|
import {
|
|
11
11
|
detectPackageManager
|
|
12
12
|
} from "./chunk-EKZZVYPF.js";
|
|
@@ -156,7 +156,7 @@ function createPlan(state, choices, options = {}) {
|
|
|
156
156
|
type: "create_directory",
|
|
157
157
|
path: rulesDir
|
|
158
158
|
});
|
|
159
|
-
const localRules = selectedRules.filter((r) => !r.eslintImport);
|
|
159
|
+
const localRules = selectedRules.filter((r) => !r.eslintImport && !r.plugin);
|
|
160
160
|
const isTypeScriptConfig = pkgInfo?.eslintConfigPath?.endsWith(".ts") ?? false;
|
|
161
161
|
const ruleFiles = loadSelectedRules(
|
|
162
162
|
localRules.map((r) => r.id),
|
|
@@ -211,25 +211,25 @@ function createPlan(state, choices, options = {}) {
|
|
|
211
211
|
}),
|
|
212
212
|
"typescript-eslint"
|
|
213
213
|
];
|
|
214
|
-
|
|
215
|
-
(r) => r.id === "require-test-coverage"
|
|
216
|
-
);
|
|
217
|
-
if (hasCoverageRule) {
|
|
218
|
-
packagesToInstall.push("@vitest/coverage-v8");
|
|
219
|
-
actions.push({
|
|
220
|
-
type: "inject_vitest_coverage",
|
|
221
|
-
projectPath: pkgPath
|
|
222
|
-
});
|
|
223
|
-
}
|
|
214
|
+
let needsVitestCoverage = false;
|
|
224
215
|
for (const rule of selectedRules) {
|
|
225
216
|
if (rule.npmDependencies) {
|
|
226
217
|
for (const dep of rule.npmDependencies) {
|
|
227
218
|
if (!packagesToInstall.includes(dep)) {
|
|
228
219
|
packagesToInstall.push(dep);
|
|
229
220
|
}
|
|
221
|
+
if (dep === "@vitest/coverage-v8") {
|
|
222
|
+
needsVitestCoverage = true;
|
|
223
|
+
}
|
|
230
224
|
}
|
|
231
225
|
}
|
|
232
226
|
}
|
|
227
|
+
if (needsVitestCoverage) {
|
|
228
|
+
actions.push({
|
|
229
|
+
type: "inject_vitest_coverage",
|
|
230
|
+
projectPath: pkgPath
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
233
|
const externalPkgs = /* @__PURE__ */ new Set();
|
|
234
234
|
for (const rule of selectedRules) {
|
|
235
235
|
if (rule.eslintImport) {
|
|
@@ -294,4 +294,4 @@ export {
|
|
|
294
294
|
createPlan,
|
|
295
295
|
getMissingRules
|
|
296
296
|
};
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
297
|
+
//# sourceMappingURL=chunk-WB2QAJRH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/init/plan.ts"],"sourcesContent":["/**\n * Plan phase - pure function generating InstallPlan from state + choices\n *\n * This function has NO I/O whatsoever. It takes the analyzed ProjectState,\n * user choices, and options, then returns an InstallPlan describing exactly\n * what actions to take.\n */\n\nimport { join } from \"path\";\nimport type { RuleMetadata } from \"uilint-eslint\";\nimport type {\n ProjectState,\n UserChoices,\n InstallPlan,\n InstallAction,\n DependencyInstall,\n PlanOptions,\n} from \"./types.js\";\nimport { GENSTYLEGUIDE_COMMAND_MD } from \"./constants.js\";\nimport { toInstallSpecifier } from \"./versioning.js\";\nimport { loadSkill } from \"../../utils/skill-loader.js\";\nimport { loadSelectedRules } from \"../../utils/rule-loader.js\";\nimport { detectPackageManager } from \"../../utils/package-manager.js\";\n\n/**\n * Create the install plan from project state and user choices\n *\n * @param state - The analyzed project state\n * @param choices - User's installation choices\n * @param options - Planning options (force, etc.)\n * @returns InstallPlan with all actions and dependencies\n */\nexport function createPlan(\n state: ProjectState,\n choices: UserChoices,\n options: PlanOptions = {}\n): InstallPlan {\n const actions: InstallAction[] = [];\n const dependencies: DependencyInstall[] = [];\n\n const { force: _force = false } = options;\n const { items } = choices;\n\n // Ensure .cursor directory exists if needed\n const needsCursorDir =\n items.includes(\"genstyleguide\") || items.includes(\"skill\");\n\n if (needsCursorDir && !state.cursorDir.exists) {\n actions.push({\n type: \"create_directory\",\n path: state.cursorDir.path,\n });\n }\n\n // =========================================================================\n // Genstyleguide Command\n // =========================================================================\n if (items.includes(\"genstyleguide\")) {\n const commandsDir = join(state.cursorDir.path, \"commands\");\n\n actions.push({\n type: \"create_directory\",\n path: commandsDir,\n });\n\n actions.push({\n type: \"create_file\",\n path: join(commandsDir, \"genstyleguide.md\"),\n content: GENSTYLEGUIDE_COMMAND_MD,\n });\n }\n\n // =========================================================================\n // Agent Skill Installation\n // =========================================================================\n if (items.includes(\"skill\")) {\n const skillsDir = join(state.cursorDir.path, \"skills\");\n\n // Create skills directory\n actions.push({\n type: \"create_directory\",\n path: skillsDir,\n });\n\n // Load and install the ui-consistency-enforcer skill\n try {\n const skill = loadSkill(\"ui-consistency-enforcer\");\n const skillDir = join(skillsDir, skill.name);\n\n // Create skill directory\n actions.push({\n type: \"create_directory\",\n path: skillDir,\n });\n\n // Create all skill files\n for (const file of skill.files) {\n const filePath = join(skillDir, file.relativePath);\n\n // Ensure subdirectories exist (e.g., references/)\n const fileDir = join(\n skillDir,\n file.relativePath.split(\"/\").slice(0, -1).join(\"/\")\n );\n if (fileDir !== skillDir && file.relativePath.includes(\"/\")) {\n actions.push({\n type: \"create_directory\",\n path: fileDir,\n });\n }\n\n actions.push({\n type: \"create_file\",\n path: filePath,\n content: file.content,\n });\n }\n } catch {\n // Skill not found - skip silently (shouldn't happen in normal install)\n }\n }\n\n // =========================================================================\n // Next.js Overlay Installation\n // =========================================================================\n if (items.includes(\"next\") && choices.next) {\n const { projectPath, detection, targetFile, createProviders } =\n choices.next;\n\n // Install Next.js routes\n actions.push({\n type: \"install_next_routes\",\n projectPath,\n appRoot: detection.appRoot,\n });\n\n // Install React overlay dependencies using the package manager for this specific target\n dependencies.push({\n packagePath: projectPath,\n packageManager: detectPackageManager(projectPath),\n packages: [\n toInstallSpecifier(\"uilint-react\", {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: projectPath,\n }),\n toInstallSpecifier(\"uilint-core\", {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: projectPath,\n }),\n \"jsx-loc-plugin\",\n ],\n });\n\n // Inject <uilint-devtools /> web component into React\n // Use targetFile or createProviders if specified by the user\n actions.push({\n type: \"inject_react\",\n projectPath,\n appRoot: detection.appRoot,\n targetFile,\n createProviders,\n });\n\n // Inject jsx-loc-plugin into next.config\n actions.push({\n type: \"inject_next_config\",\n projectPath,\n });\n\n // Add uilint-react/devtools to tsconfig.json types for TypeScript support\n actions.push({\n type: \"inject_tsconfig\",\n projectPath,\n addDevtoolsTypes: true,\n });\n }\n\n // =========================================================================\n // Vite Overlay Installation\n // =========================================================================\n if (items.includes(\"vite\") && choices.vite) {\n const { projectPath, detection } = choices.vite;\n\n // Install React overlay dependencies using the package manager for this specific target\n dependencies.push({\n packagePath: projectPath,\n packageManager: detectPackageManager(projectPath),\n packages: [\n toInstallSpecifier(\"uilint-react\", {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: projectPath,\n }),\n toInstallSpecifier(\"uilint-core\", {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: projectPath,\n }),\n \"jsx-loc-plugin\",\n ],\n });\n\n // Inject <uilint-devtools /> web component into React entry\n actions.push({\n type: \"inject_react\",\n projectPath,\n appRoot: detection.entryRoot,\n mode: \"vite\",\n });\n\n // Inject jsx-loc-plugin into vite.config\n actions.push({\n type: \"inject_vite_config\",\n projectPath,\n });\n\n // Add uilint-react/devtools to tsconfig.json types for TypeScript support\n actions.push({\n type: \"inject_tsconfig\",\n projectPath,\n addDevtoolsTypes: true,\n });\n }\n\n // =========================================================================\n // ESLint Plugin Installation\n // =========================================================================\n if (items.includes(\"eslint\") && choices.eslint) {\n const { packagePaths, selectedRules } = choices.eslint;\n\n for (const pkgPath of packagePaths) {\n const pkgInfo = state.packages.find((p) => p.path === pkgPath);\n\n // Create .uilint/rules directory alongside the target app (not at workspace root)\n const rulesDir = join(pkgPath, \".uilint\", \"rules\");\n actions.push({\n type: \"create_directory\",\n path: rulesDir,\n });\n\n // Load and copy rule files into this target package\n // Use TypeScript rule files if the ESLint config is TypeScript (.ts)\n // This ensures the imports match the actual rule files being copied\n // Skip externally-registered plugin rules (e.g. vision, semantic, coverage) —\n // their implementations live in their own npm packages, not in uilint-eslint.\n // Rules with `eslintImport` or `plugin` are imported from their package by the config injector.\n const localRules = selectedRules.filter((r) => !r.eslintImport && !r.plugin);\n const isTypeScriptConfig =\n pkgInfo?.eslintConfigPath?.endsWith(\".ts\") ?? false;\n const ruleFiles = loadSelectedRules(\n localRules.map((r) => r.id),\n {\n typescript: isTypeScriptConfig,\n }\n );\n for (const ruleFile of ruleFiles) {\n // For directory-based rules, create the directory structure first\n if (ruleFile.additionalFiles && ruleFile.additionalFiles.length > 0) {\n // Create rule directory (e.g., .uilint/rules/no-mixed-component-libraries/)\n const ruleDir = join(rulesDir, ruleFile.ruleId);\n actions.push({\n type: \"create_directory\",\n path: ruleDir,\n });\n\n // Create lib/ subdirectory if any files are in lib/\n const hasLibFiles = ruleFile.additionalFiles.some((f) =>\n f.relativePath.includes(\"/lib/\")\n );\n if (hasLibFiles) {\n actions.push({\n type: \"create_directory\",\n path: join(ruleDir, \"lib\"),\n });\n }\n }\n\n // Copy implementation file\n actions.push({\n type: \"create_file\",\n path: join(rulesDir, ruleFile.implementation.relativePath),\n content: ruleFile.implementation.content,\n });\n\n // Copy additional files for directory-based rules\n if (ruleFile.additionalFiles) {\n for (const additionalFile of ruleFile.additionalFiles) {\n actions.push({\n type: \"create_file\",\n path: join(rulesDir, additionalFile.relativePath),\n content: additionalFile.content,\n });\n }\n }\n\n // Copy test file if it exists (only for TypeScript configs)\n if (ruleFile.test && isTypeScriptConfig) {\n actions.push({\n type: \"create_file\",\n path: join(rulesDir, ruleFile.test.relativePath),\n content: ruleFile.test.content,\n });\n }\n }\n\n // Install dependencies using the package manager for this specific target\n const packagesToInstall = [\n toInstallSpecifier(\"uilint-eslint\", {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: pkgPath,\n }),\n \"typescript-eslint\",\n ];\n\n // Collect npm dependencies declared by selected rules\n let needsVitestCoverage = false;\n for (const rule of selectedRules) {\n if (rule.npmDependencies) {\n for (const dep of rule.npmDependencies) {\n if (!packagesToInstall.includes(dep)) {\n packagesToInstall.push(dep);\n }\n if (dep === \"@vitest/coverage-v8\") {\n needsVitestCoverage = true;\n }\n }\n }\n }\n\n // If any rule needs vitest coverage, inject the coverage config\n if (needsVitestCoverage) {\n actions.push({\n type: \"inject_vitest_coverage\",\n projectPath: pkgPath,\n });\n }\n\n // Install plugin packages for external rules (e.g. uilint-vision, uilint-semantic)\n const externalPkgs = new Set<string>();\n for (const rule of selectedRules) {\n if (rule.eslintImport) {\n // Extract package name from import specifier (e.g. \"uilint-vision/eslint-rules/...\")\n const pkgName = rule.eslintImport.split(\"/\").slice(0, 1).join(\"/\");\n externalPkgs.add(pkgName);\n }\n }\n for (const pkg of externalPkgs) {\n const specifier = toInstallSpecifier(pkg, {\n preferWorkspaceProtocol: state.packageManager === \"pnpm\",\n workspaceRoot: state.workspaceRoot,\n targetProjectPath: pkgPath,\n });\n if (!packagesToInstall.includes(specifier)) {\n packagesToInstall.push(specifier);\n }\n }\n\n dependencies.push({\n packagePath: pkgPath,\n packageManager: detectPackageManager(pkgPath),\n packages: packagesToInstall,\n });\n\n // Inject ESLint rules (will reference local .uilint/rules/ files)\n if (pkgInfo?.eslintConfigPath) {\n actions.push({\n type: \"inject_eslint\",\n packagePath: pkgPath,\n configPath: pkgInfo.eslintConfigPath,\n rules: selectedRules,\n hasExistingRules: pkgInfo.hasUilintRules,\n });\n }\n\n // Add .uilint to tsconfig.json exclude to prevent build errors\n // The rule files are loaded by ESLint at runtime, not compiled with the app\n actions.push({\n type: \"inject_tsconfig\",\n projectPath: pkgPath,\n });\n\n // Update manifest with installed rule versions\n const ruleVersions: Record<string, string> = {};\n for (const rule of selectedRules) {\n // Use version from RuleMeta, default to \"1.0.0\" if not specified\n ruleVersions[rule.id] = rule.version ?? \"1.0.0\";\n }\n actions.push({\n type: \"update_manifest\",\n projectPath: pkgPath,\n rules: ruleVersions,\n });\n }\n\n // Add .uilint/.cache to .gitignore at workspace root\n const gitignorePath = join(state.workspaceRoot, \".gitignore\");\n actions.push({\n type: \"append_to_file\",\n path: gitignorePath,\n content: \"\\n# UILint cache\\n.uilint/.cache\\n\",\n ifNotContains: \".uilint/.cache\",\n });\n }\n\n return { actions, dependencies };\n}\n\n/**\n * Get the list of rules that are missing from a package's ESLint config\n */\nexport function getMissingRules(\n configuredRuleIds: string[],\n selectedRules: RuleMetadata[]\n): RuleMetadata[] {\n const configuredSet = new Set(configuredRuleIds);\n return selectedRules.filter((rule) => !configuredSet.has(rule.id));\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
discoverPlugins,
|
|
18
18
|
loadPluginESLintRules
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-GFJDTSYD.js";
|
|
20
20
|
import {
|
|
21
21
|
createSpinner,
|
|
22
22
|
intro,
|
|
@@ -3597,17 +3597,23 @@ function isCoverageRuleEnabled(appRoot) {
|
|
|
3597
3597
|
async function buildCoverageData(appRoot) {
|
|
3598
3598
|
if (isPreparingCoverage) return;
|
|
3599
3599
|
isPreparingCoverage = true;
|
|
3600
|
+
setPluginStatus("coverage", "processing", "Checking coverage setup...");
|
|
3600
3601
|
try {
|
|
3601
3602
|
if (!isCoverageRuleEnabled(appRoot)) {
|
|
3602
3603
|
logServerInfo("Coverage rule not enabled, skipping preparation");
|
|
3604
|
+
setPluginStatus("coverage", "complete", "Rule not enabled");
|
|
3605
|
+
setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
|
|
3603
3606
|
return;
|
|
3604
3607
|
}
|
|
3605
3608
|
const setup = detectCoverageSetup(appRoot);
|
|
3606
3609
|
if (!needsCoveragePreparation(setup)) {
|
|
3607
3610
|
logServerInfo("Coverage data is up-to-date");
|
|
3611
|
+
setPluginStatus("coverage", "complete", "Coverage data up-to-date");
|
|
3612
|
+
setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
|
|
3608
3613
|
return;
|
|
3609
3614
|
}
|
|
3610
3615
|
startBackgroundTask("coverage-prep", "Coverage Prep", "Starting...");
|
|
3616
|
+
setPluginStatus("coverage", "processing", "Starting coverage preparation...");
|
|
3611
3617
|
broadcast({ type: "coverage:setup:start" });
|
|
3612
3618
|
const skipPackageInstall = process.env.UILINT_SKIP_COVERAGE_INSTALL === "1";
|
|
3613
3619
|
const skipTests = process.env.UILINT_SKIP_COVERAGE_TESTS === "1";
|
|
@@ -3624,21 +3630,24 @@ async function buildCoverageData(appRoot) {
|
|
|
3624
3630
|
void 0,
|
|
3625
3631
|
message
|
|
3626
3632
|
);
|
|
3633
|
+
setPluginStatus("coverage", "processing", message);
|
|
3627
3634
|
broadcast({ type: "coverage:setup:progress", message, phase });
|
|
3628
3635
|
}
|
|
3629
3636
|
});
|
|
3630
3637
|
if (result.error) {
|
|
3631
3638
|
completeBackgroundTask("coverage-prep", void 0, result.error);
|
|
3639
|
+
setPluginStatus("coverage", "error", result.error);
|
|
3640
|
+
setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
|
|
3632
3641
|
} else {
|
|
3633
3642
|
const parts = [];
|
|
3634
3643
|
if (result.packageAdded) parts.push("package installed");
|
|
3635
3644
|
if (result.configModified) parts.push("config modified");
|
|
3636
3645
|
if (result.testsRan) parts.push("tests ran");
|
|
3637
3646
|
if (result.coverageGenerated) parts.push("coverage generated");
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
);
|
|
3647
|
+
const successMsg = `Coverage prepared: ${parts.join(", ")} in ${(result.duration / 1e3).toFixed(1)}s`;
|
|
3648
|
+
completeBackgroundTask("coverage-prep", successMsg);
|
|
3649
|
+
setPluginStatus("coverage", "complete", successMsg);
|
|
3650
|
+
setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
|
|
3642
3651
|
}
|
|
3643
3652
|
broadcast({
|
|
3644
3653
|
type: "coverage:setup:complete",
|
|
@@ -3647,6 +3656,8 @@ async function buildCoverageData(appRoot) {
|
|
|
3647
3656
|
} catch (error) {
|
|
3648
3657
|
const msg = error instanceof Error ? error.message : String(error);
|
|
3649
3658
|
completeBackgroundTask("coverage-prep", void 0, msg);
|
|
3659
|
+
setPluginStatus("coverage", "error", msg);
|
|
3660
|
+
setTimeout(() => setPluginStatus("coverage", "idle"), 3e3);
|
|
3650
3661
|
broadcast({ type: "coverage:setup:error", error: msg });
|
|
3651
3662
|
} finally {
|
|
3652
3663
|
isPreparingCoverage = false;
|
|
@@ -3719,6 +3730,7 @@ async function serve(options) {
|
|
|
3719
3730
|
registerPlugin("semantic", "Semantic", "qwen3-vl:8b-instruct");
|
|
3720
3731
|
registerPlugin("vision", "Vision", "qwen3-vl:8b-instruct");
|
|
3721
3732
|
registerPlugin("duplicates", "Duplicates", "nomic-embed-text");
|
|
3733
|
+
registerPlugin("coverage", "Coverage", "vitest");
|
|
3722
3734
|
} else {
|
|
3723
3735
|
disableDashboard();
|
|
3724
3736
|
}
|
|
@@ -6031,7 +6043,7 @@ program.command("update").description("Update existing style guide with new styl
|
|
|
6031
6043
|
llm: options.llm
|
|
6032
6044
|
});
|
|
6033
6045
|
});
|
|
6034
|
-
var initCommand = program.command("init").description("Initialize UILint integration").option("--force", "Overwrite existing configuration files").option("--react", "Install React DevTool (non-interactive)").option("--eslint", "Install ESLint rules (non-interactive)").option("--genstyleguide", "Generate styleguide (non-interactive)").option("--skill", "Install Claude skill (non-interactive)").option("--vision", "Install Vision Analysis plugin").option("--semantic", "Install Semantic Analysis plugin").option("--duplicates", "Install Duplicates Detection plugin");
|
|
6046
|
+
var initCommand = program.command("init").description("Initialize UILint integration").option("--force", "Overwrite existing configuration files").option("--react", "Install React DevTool (non-interactive)").option("--eslint", "Install ESLint rules (non-interactive)").option("--genstyleguide", "Generate styleguide (non-interactive)").option("--skill", "Install Claude skill (non-interactive)").option("--vision", "Install Vision Analysis plugin").option("--semantic", "Install Semantic Analysis plugin").option("--duplicates", "Install Duplicates Detection plugin").option("--coverage", "Install test coverage rules");
|
|
6035
6047
|
program.command("remove").description("Remove UILint components from your project").option("--dry-run", "Preview changes without removing anything").option("-y, --yes", "Skip confirmation prompt").action(async (options) => {
|
|
6036
6048
|
const { removeUI } = await import("./remove-ui-GZRFA2AC.js");
|
|
6037
6049
|
await removeUI({ dryRun: options.dryRun, yes: options.yes });
|
|
@@ -6090,7 +6102,7 @@ program.addCommand(createDuplicatesCommand());
|
|
|
6090
6102
|
program.addCommand(createManifestCommand());
|
|
6091
6103
|
program.addCommand(createSocketCommand());
|
|
6092
6104
|
program.command("upgrade").description("Update installed ESLint rules to latest versions").option("--check", "Show available updates without applying").option("-y, --yes", "Auto-confirm all updates").option("--dry-run", "Show what would change without modifying files").option("--rule <id>", "Upgrade only a specific rule").action(async (options) => {
|
|
6093
|
-
const { upgrade } = await import("./upgrade-
|
|
6105
|
+
const { upgrade } = await import("./upgrade-WP6U3LEO.js");
|
|
6094
6106
|
await upgrade({
|
|
6095
6107
|
check: options.check,
|
|
6096
6108
|
yes: options.yes,
|
|
@@ -6099,9 +6111,9 @@ program.command("upgrade").description("Update installed ESLint rules to latest
|
|
|
6099
6111
|
});
|
|
6100
6112
|
});
|
|
6101
6113
|
async function main() {
|
|
6102
|
-
const { discoverPlugins: discoverPlugins2 } = await import("./plugin-loader-
|
|
6114
|
+
const { discoverPlugins: discoverPlugins2 } = await import("./plugin-loader-V5CAMTYQ.js");
|
|
6103
6115
|
const pluginManifests = await discoverPlugins2();
|
|
6104
|
-
const KNOWN_PLUGIN_FLAGS = ["vision", "semantic", "duplicates"];
|
|
6116
|
+
const KNOWN_PLUGIN_FLAGS = ["vision", "semantic", "duplicates", "coverage"];
|
|
6105
6117
|
for (const manifest of pluginManifests) {
|
|
6106
6118
|
if (!KNOWN_PLUGIN_FLAGS.includes(manifest.cliFlag)) {
|
|
6107
6119
|
initCommand.option(`--${manifest.cliFlag}`, manifest.cliDescription);
|
|
@@ -6113,7 +6125,7 @@ async function main() {
|
|
|
6113
6125
|
...pluginManifests.map((m) => m.cliFlag)
|
|
6114
6126
|
]);
|
|
6115
6127
|
const plugins = [...allFlags].filter((flag) => options[flag]);
|
|
6116
|
-
const { initUI } = await import("./init-ui-
|
|
6128
|
+
const { initUI } = await import("./init-ui-CIK6YKOZ.js");
|
|
6117
6129
|
await initUI({
|
|
6118
6130
|
force: options.force,
|
|
6119
6131
|
react: options.react,
|