@qlucent/fishi-core 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +63 -1
- package/dist/index.js +320 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -643,10 +643,72 @@ declare function startDevServer(projectDir: string, config: DevServerConfig): Ch
|
|
|
643
643
|
*/
|
|
644
644
|
declare function getVibeModeConfig(enabled: boolean): string;
|
|
645
645
|
|
|
646
|
+
interface DesignTokens {
|
|
647
|
+
colors: Record<string, string>;
|
|
648
|
+
typography: {
|
|
649
|
+
fontFamilies: string[];
|
|
650
|
+
scale: Record<string, string>;
|
|
651
|
+
};
|
|
652
|
+
spacing: Record<string, string>;
|
|
653
|
+
borderRadius: Record<string, string>;
|
|
654
|
+
shadows: Record<string, string>;
|
|
655
|
+
darkMode: boolean;
|
|
656
|
+
}
|
|
657
|
+
interface ComponentEntry {
|
|
658
|
+
name: string;
|
|
659
|
+
path: string;
|
|
660
|
+
type: 'ui' | 'layout' | 'form' | 'data' | 'navigation' | 'other';
|
|
661
|
+
}
|
|
662
|
+
interface ComponentRegistry {
|
|
663
|
+
components: ComponentEntry[];
|
|
664
|
+
library: string | null;
|
|
665
|
+
framework: string | null;
|
|
666
|
+
}
|
|
667
|
+
interface BrandGuardianIssue {
|
|
668
|
+
file: string;
|
|
669
|
+
line: number;
|
|
670
|
+
severity: 'error' | 'warning' | 'info';
|
|
671
|
+
rule: string;
|
|
672
|
+
message: string;
|
|
673
|
+
fix?: string;
|
|
674
|
+
}
|
|
675
|
+
interface BrandGuardianReport {
|
|
676
|
+
issues: BrandGuardianIssue[];
|
|
677
|
+
passed: boolean;
|
|
678
|
+
stats: {
|
|
679
|
+
errors: number;
|
|
680
|
+
warnings: number;
|
|
681
|
+
infos: number;
|
|
682
|
+
filesScanned: number;
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Detect design tokens from a project's config files.
|
|
687
|
+
* Checks: tailwind.config, CSS custom properties, theme files.
|
|
688
|
+
*/
|
|
689
|
+
declare function detectDesignTokens(projectDir: string): DesignTokens;
|
|
690
|
+
/**
|
|
691
|
+
* Generate default design tokens for a new project.
|
|
692
|
+
*/
|
|
693
|
+
declare function generateDefaultTokens(): DesignTokens;
|
|
694
|
+
/**
|
|
695
|
+
* Detect component library and registry from a project.
|
|
696
|
+
*/
|
|
697
|
+
declare function detectComponentRegistry(projectDir: string): ComponentRegistry;
|
|
698
|
+
/**
|
|
699
|
+
* Run Brand Guardian validation on project files.
|
|
700
|
+
* Checks for hardcoded colors, inconsistent spacing, missing a11y, etc.
|
|
701
|
+
*/
|
|
702
|
+
declare function runBrandGuardian(projectDir: string, tokens: DesignTokens): BrandGuardianReport;
|
|
703
|
+
/**
|
|
704
|
+
* Generate a design system config file for the project.
|
|
705
|
+
*/
|
|
706
|
+
declare function generateDesignSystemConfig(tokens: DesignTokens, registry: ComponentRegistry): string;
|
|
707
|
+
|
|
646
708
|
declare function getSandboxPolicyTemplate(): string;
|
|
647
709
|
|
|
648
710
|
declare function getDockerfileTemplate(): string;
|
|
649
711
|
|
|
650
712
|
declare function getDashboardHtml(): string;
|
|
651
713
|
|
|
652
|
-
export { type AgentDefinition, type AgentRole, type AgentTemplate, type BackupManifest, type BrownfieldAnalysisData, type ClaudeMdOptions, type CommandTemplate, type ConflictCategory, type ConflictMap, type ConflictResolution, type CostMode, type DetectionCheck, type DetectionResult, type DevServerConfig, type DynamicAgent, type DynamicAgentConfig, type ExecutionConfig, type FileConflict, type FileResolutionMap, type FishiConfig, type FishiYamlOptions, type GateConfig, type GateStatus, type GitConfig, type HookTemplate, type InitOptions, type McpConfig, type McpServerConfig, type ModelRoutingConfig, type ModelTier, type MonitorEvent, type MonitorState, type MonitorSummary, type ProjectConfig, type ProjectType, type ProjectYamlOptions, type SandboxConfig, type SandboxMode, type SandboxPolicy, type SandboxRunResult, type ScaffoldOptions, type ScaffoldResult, type SkillTemplate, type StateConfig, type TaskStatus, type TaskboardConfig, type TemplateContext, architectAgentTemplate, backendAgentTemplate, buildSandboxEnv, createBackup, detectConflicts, detectDevServer, detectDocker, devLeadTemplate, devopsAgentTemplate, docsAgentTemplate, emitEvent, frontendAgentTemplate, fullstackAgentTemplate, generateScaffold, getAdaptiveTaskGraphSkill, getAgentCompleteHook, getAgentFactoryTemplate, getAgentRegistryTemplate, getAgentSummary, getApiDesignSkill, getAutoCheckpointHook, getBoardCommand, getBrainstormingSkill, getBrownfieldAnalysisSkill, getBrownfieldDiscoverySkill, getClaudeMdTemplate, getCodeGenSkill, getCoordinatorFactoryTemplate, getDashboardHtml, getDebuggingSkill, getDeploymentSkill, getDocCheckerScript, getDockerfileTemplate, getDocumentationSkill, getFishiYamlTemplate, getGateCommand, getGateManagerScript, getGitignoreAdditions, getInitCommand, getLearningsManagerScript, getMasterOrchestratorTemplate, getMcpJsonTemplate, getMemoryManagerScript, getModelRoutingReference, getMonitorEmitterScript, getPhaseRunnerScript, getPostEditHook, getPrdCommand, getPrdSkill, getProjectYamlTemplate, getResetCommand, getResumeCommand, getSafetyCheckHook, getSandboxPolicyTemplate, getSessionStartHook, getSettingsJsonTemplate, getSprintCommand, getStatusCommand, getTaskboardOpsSkill, getTaskboardUpdateHook, getTestingSkill, getTodoManagerScript, getValidateScaffoldScript, getVibeModeConfig, getWorktreeManagerScript, getWorktreeSetupHook, marketingAgentTemplate, mergeClaudeMd, mergeClaudeMdTop, mergeGitignore, mergeMcpJson, mergeSettingsJson, opsLeadTemplate, planningAgentTemplate, planningLeadTemplate, qualityLeadTemplate, readMonitorState, readSandboxConfig, readSandboxPolicy, researchAgentTemplate, runInDockerSandbox, runInProcessSandbox, runInSandbox, securityAgentTemplate, startDevServer, testingAgentTemplate, uiuxAgentTemplate, writingAgentTemplate };
|
|
714
|
+
export { type AgentDefinition, type AgentRole, type AgentTemplate, type BackupManifest, type BrandGuardianIssue, type BrandGuardianReport, type BrownfieldAnalysisData, type ClaudeMdOptions, type CommandTemplate, type ComponentEntry, type ComponentRegistry, type ConflictCategory, type ConflictMap, type ConflictResolution, type CostMode, type DesignTokens, type DetectionCheck, type DetectionResult, type DevServerConfig, type DynamicAgent, type DynamicAgentConfig, type ExecutionConfig, type FileConflict, type FileResolutionMap, type FishiConfig, type FishiYamlOptions, type GateConfig, type GateStatus, type GitConfig, type HookTemplate, type InitOptions, type McpConfig, type McpServerConfig, type ModelRoutingConfig, type ModelTier, type MonitorEvent, type MonitorState, type MonitorSummary, type ProjectConfig, type ProjectType, type ProjectYamlOptions, type SandboxConfig, type SandboxMode, type SandboxPolicy, type SandboxRunResult, type ScaffoldOptions, type ScaffoldResult, type SkillTemplate, type StateConfig, type TaskStatus, type TaskboardConfig, type TemplateContext, architectAgentTemplate, backendAgentTemplate, buildSandboxEnv, createBackup, detectComponentRegistry, detectConflicts, detectDesignTokens, detectDevServer, detectDocker, devLeadTemplate, devopsAgentTemplate, docsAgentTemplate, emitEvent, frontendAgentTemplate, fullstackAgentTemplate, generateDefaultTokens, generateDesignSystemConfig, generateScaffold, getAdaptiveTaskGraphSkill, getAgentCompleteHook, getAgentFactoryTemplate, getAgentRegistryTemplate, getAgentSummary, getApiDesignSkill, getAutoCheckpointHook, getBoardCommand, getBrainstormingSkill, getBrownfieldAnalysisSkill, getBrownfieldDiscoverySkill, getClaudeMdTemplate, getCodeGenSkill, getCoordinatorFactoryTemplate, getDashboardHtml, getDebuggingSkill, getDeploymentSkill, getDocCheckerScript, getDockerfileTemplate, getDocumentationSkill, getFishiYamlTemplate, getGateCommand, getGateManagerScript, getGitignoreAdditions, getInitCommand, getLearningsManagerScript, getMasterOrchestratorTemplate, getMcpJsonTemplate, getMemoryManagerScript, getModelRoutingReference, getMonitorEmitterScript, getPhaseRunnerScript, getPostEditHook, getPrdCommand, getPrdSkill, getProjectYamlTemplate, getResetCommand, getResumeCommand, getSafetyCheckHook, getSandboxPolicyTemplate, getSessionStartHook, getSettingsJsonTemplate, getSprintCommand, getStatusCommand, getTaskboardOpsSkill, getTaskboardUpdateHook, getTestingSkill, getTodoManagerScript, getValidateScaffoldScript, getVibeModeConfig, getWorktreeManagerScript, getWorktreeSetupHook, marketingAgentTemplate, mergeClaudeMd, mergeClaudeMdTop, mergeGitignore, mergeMcpJson, mergeSettingsJson, opsLeadTemplate, planningAgentTemplate, planningLeadTemplate, qualityLeadTemplate, readMonitorState, readSandboxConfig, readSandboxPolicy, researchAgentTemplate, runBrandGuardian, runInDockerSandbox, runInProcessSandbox, runInSandbox, securityAgentTemplate, startDevServer, testingAgentTemplate, uiuxAgentTemplate, writingAgentTemplate };
|
package/dist/index.js
CHANGED
|
@@ -11111,7 +11111,7 @@ async function createBackup(targetDir, conflictingFiles) {
|
|
|
11111
11111
|
manifestFiles.push({ path: relPath, size: stat.size });
|
|
11112
11112
|
}
|
|
11113
11113
|
}
|
|
11114
|
-
const fishiVersion = "0.
|
|
11114
|
+
const fishiVersion = "0.9.0";
|
|
11115
11115
|
const manifest = {
|
|
11116
11116
|
timestamp: now.toISOString(),
|
|
11117
11117
|
fishi_version: fishiVersion,
|
|
@@ -11466,6 +11466,320 @@ vibe_mode:
|
|
|
11466
11466
|
`;
|
|
11467
11467
|
}
|
|
11468
11468
|
|
|
11469
|
+
// src/generators/design-system.ts
|
|
11470
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, readdirSync } from "fs";
|
|
11471
|
+
import { join as join7 } from "path";
|
|
11472
|
+
function detectDesignTokens(projectDir) {
|
|
11473
|
+
const tokens = {
|
|
11474
|
+
colors: {},
|
|
11475
|
+
typography: { fontFamilies: [], scale: {} },
|
|
11476
|
+
spacing: {},
|
|
11477
|
+
borderRadius: {},
|
|
11478
|
+
shadows: {},
|
|
11479
|
+
darkMode: false
|
|
11480
|
+
};
|
|
11481
|
+
const tailwindFiles = ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs", "tailwind.config.cjs"];
|
|
11482
|
+
for (const file of tailwindFiles) {
|
|
11483
|
+
const p = join7(projectDir, file);
|
|
11484
|
+
if (existsSync7(p)) {
|
|
11485
|
+
const content = readFileSync4(p, "utf-8");
|
|
11486
|
+
const colorMatches = content.matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]?(#[0-9a-fA-F]{3,8})['"]?/g);
|
|
11487
|
+
for (const m of colorMatches) {
|
|
11488
|
+
tokens.colors[m[1]] = m[2];
|
|
11489
|
+
}
|
|
11490
|
+
if (content.includes("darkMode")) tokens.darkMode = true;
|
|
11491
|
+
break;
|
|
11492
|
+
}
|
|
11493
|
+
}
|
|
11494
|
+
const cssFiles = findFiles(projectDir, ["src", "styles", "app"], [".css"]);
|
|
11495
|
+
for (const file of cssFiles.slice(0, 10)) {
|
|
11496
|
+
try {
|
|
11497
|
+
const content = readFileSync4(file, "utf-8");
|
|
11498
|
+
const varMatches = content.matchAll(/--(\w[\w-]*)\s*:\s*([^;]+)/g);
|
|
11499
|
+
for (const m of varMatches) {
|
|
11500
|
+
const name = m[1];
|
|
11501
|
+
const value = m[2].trim();
|
|
11502
|
+
if (name.includes("color") || name.includes("bg") || value.startsWith("#") || value.startsWith("rgb") || value.startsWith("hsl")) {
|
|
11503
|
+
tokens.colors[name] = value;
|
|
11504
|
+
} else if (name.includes("font")) {
|
|
11505
|
+
if (name.includes("size")) tokens.typography.scale[name] = value;
|
|
11506
|
+
else if (name.includes("family")) tokens.typography.fontFamilies.push(value);
|
|
11507
|
+
} else if (name.includes("spacing") || name.includes("gap") || name.includes("padding") || name.includes("margin")) {
|
|
11508
|
+
tokens.spacing[name] = value;
|
|
11509
|
+
} else if (name.includes("radius")) {
|
|
11510
|
+
tokens.borderRadius[name] = value;
|
|
11511
|
+
} else if (name.includes("shadow")) {
|
|
11512
|
+
tokens.shadows[name] = value;
|
|
11513
|
+
}
|
|
11514
|
+
}
|
|
11515
|
+
if (content.includes("prefers-color-scheme: dark") || content.includes(".dark")) {
|
|
11516
|
+
tokens.darkMode = true;
|
|
11517
|
+
}
|
|
11518
|
+
} catch {
|
|
11519
|
+
}
|
|
11520
|
+
}
|
|
11521
|
+
const themeFiles = ["theme.ts", "theme.js", "theme.json", "src/theme.ts", "src/theme.js", "src/styles/theme.ts"];
|
|
11522
|
+
for (const file of themeFiles) {
|
|
11523
|
+
if (existsSync7(join7(projectDir, file))) {
|
|
11524
|
+
try {
|
|
11525
|
+
const content = readFileSync4(join7(projectDir, file), "utf-8");
|
|
11526
|
+
const colorMatches = content.matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]?(#[0-9a-fA-F]{3,8})['"]?/g);
|
|
11527
|
+
for (const m of colorMatches) {
|
|
11528
|
+
tokens.colors[m[1]] = m[2];
|
|
11529
|
+
}
|
|
11530
|
+
} catch {
|
|
11531
|
+
}
|
|
11532
|
+
break;
|
|
11533
|
+
}
|
|
11534
|
+
}
|
|
11535
|
+
return tokens;
|
|
11536
|
+
}
|
|
11537
|
+
function generateDefaultTokens() {
|
|
11538
|
+
return {
|
|
11539
|
+
colors: {
|
|
11540
|
+
"brand-50": "#f0f7ff",
|
|
11541
|
+
"brand-100": "#e0efff",
|
|
11542
|
+
"brand-200": "#b8d9ff",
|
|
11543
|
+
"brand-500": "#0066cc",
|
|
11544
|
+
"brand-600": "#0052a3",
|
|
11545
|
+
"brand-700": "#003d7a",
|
|
11546
|
+
"brand-900": "#001f3f",
|
|
11547
|
+
"gray-50": "#f9fafb",
|
|
11548
|
+
"gray-100": "#f3f4f6",
|
|
11549
|
+
"gray-200": "#e5e7eb",
|
|
11550
|
+
"gray-500": "#6b7280",
|
|
11551
|
+
"gray-700": "#374151",
|
|
11552
|
+
"gray-900": "#111827",
|
|
11553
|
+
"success": "#22c55e",
|
|
11554
|
+
"warning": "#f59e0b",
|
|
11555
|
+
"error": "#ef4444"
|
|
11556
|
+
},
|
|
11557
|
+
typography: {
|
|
11558
|
+
fontFamilies: ['-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'],
|
|
11559
|
+
scale: {
|
|
11560
|
+
"xs": "0.75rem",
|
|
11561
|
+
"sm": "0.875rem",
|
|
11562
|
+
"base": "1rem",
|
|
11563
|
+
"lg": "1.125rem",
|
|
11564
|
+
"xl": "1.25rem",
|
|
11565
|
+
"2xl": "1.5rem",
|
|
11566
|
+
"3xl": "1.875rem",
|
|
11567
|
+
"4xl": "2.25rem"
|
|
11568
|
+
}
|
|
11569
|
+
},
|
|
11570
|
+
spacing: {
|
|
11571
|
+
"xs": "0.25rem",
|
|
11572
|
+
"sm": "0.5rem",
|
|
11573
|
+
"md": "1rem",
|
|
11574
|
+
"lg": "1.5rem",
|
|
11575
|
+
"xl": "2rem",
|
|
11576
|
+
"2xl": "3rem",
|
|
11577
|
+
"3xl": "4rem"
|
|
11578
|
+
},
|
|
11579
|
+
borderRadius: {
|
|
11580
|
+
"sm": "0.25rem",
|
|
11581
|
+
"md": "0.375rem",
|
|
11582
|
+
"lg": "0.5rem",
|
|
11583
|
+
"xl": "0.75rem",
|
|
11584
|
+
"full": "9999px"
|
|
11585
|
+
},
|
|
11586
|
+
shadows: {
|
|
11587
|
+
"sm": "0 1px 2px rgba(0,0,0,0.05)",
|
|
11588
|
+
"md": "0 4px 6px rgba(0,0,0,0.1)",
|
|
11589
|
+
"lg": "0 10px 15px rgba(0,0,0,0.1)"
|
|
11590
|
+
},
|
|
11591
|
+
darkMode: true
|
|
11592
|
+
};
|
|
11593
|
+
}
|
|
11594
|
+
function detectComponentRegistry(projectDir) {
|
|
11595
|
+
const registry = {
|
|
11596
|
+
components: [],
|
|
11597
|
+
library: null,
|
|
11598
|
+
framework: null
|
|
11599
|
+
};
|
|
11600
|
+
const pkgPath = join7(projectDir, "package.json");
|
|
11601
|
+
if (existsSync7(pkgPath)) {
|
|
11602
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
11603
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
11604
|
+
if (deps["@shadcn/ui"] || existsSync7(join7(projectDir, "components.json"))) registry.library = "shadcn";
|
|
11605
|
+
else if (deps["@radix-ui/react-dialog"] || deps["@radix-ui/themes"]) registry.library = "radix";
|
|
11606
|
+
else if (deps["@mui/material"]) registry.library = "mui";
|
|
11607
|
+
else if (deps["antd"]) registry.library = "antd";
|
|
11608
|
+
else if (deps["@chakra-ui/react"]) registry.library = "chakra";
|
|
11609
|
+
else if (deps["@headlessui/react"]) registry.library = "headlessui";
|
|
11610
|
+
if (deps["react"] || deps["react-dom"]) registry.framework = "react";
|
|
11611
|
+
else if (deps["vue"]) registry.framework = "vue";
|
|
11612
|
+
else if (deps["svelte"]) registry.framework = "svelte";
|
|
11613
|
+
else if (deps["@angular/core"]) registry.framework = "angular";
|
|
11614
|
+
}
|
|
11615
|
+
const componentDirs = ["src/components", "components", "src/ui", "app/components", "src/components/ui"];
|
|
11616
|
+
for (const dir of componentDirs) {
|
|
11617
|
+
const fullDir = join7(projectDir, dir);
|
|
11618
|
+
if (existsSync7(fullDir)) {
|
|
11619
|
+
try {
|
|
11620
|
+
scanComponents(fullDir, dir, registry.components);
|
|
11621
|
+
} catch {
|
|
11622
|
+
}
|
|
11623
|
+
}
|
|
11624
|
+
}
|
|
11625
|
+
return registry;
|
|
11626
|
+
}
|
|
11627
|
+
function scanComponents(dir, relBase, components) {
|
|
11628
|
+
try {
|
|
11629
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
11630
|
+
for (const entry of entries) {
|
|
11631
|
+
if (entry.isDirectory()) {
|
|
11632
|
+
scanComponents(join7(dir, entry.name), `${relBase}/${entry.name}`, components);
|
|
11633
|
+
} else if (entry.name.match(/\.(tsx|jsx|vue|svelte)$/)) {
|
|
11634
|
+
const name = entry.name.replace(/\.(tsx|jsx|vue|svelte)$/, "");
|
|
11635
|
+
if (name === "index") continue;
|
|
11636
|
+
const type = classifyComponent(name);
|
|
11637
|
+
components.push({ name, path: `${relBase}/${entry.name}`, type });
|
|
11638
|
+
}
|
|
11639
|
+
}
|
|
11640
|
+
} catch {
|
|
11641
|
+
}
|
|
11642
|
+
}
|
|
11643
|
+
function classifyComponent(name) {
|
|
11644
|
+
const lower = name.toLowerCase();
|
|
11645
|
+
if (/button|badge|avatar|icon|tag|chip|tooltip/i.test(lower)) return "ui";
|
|
11646
|
+
if (/layout|header|footer|sidebar|menu/i.test(lower)) return "layout";
|
|
11647
|
+
if (/input|form|select|checkbox|radio|textarea|switch|slider/i.test(lower)) return "form";
|
|
11648
|
+
if (/table|list|card|grid|chart|graph|stat/i.test(lower)) return "data";
|
|
11649
|
+
if (/link|breadcrumb|tab|pagination|stepper|nav|navbar/i.test(lower)) return "navigation";
|
|
11650
|
+
return "other";
|
|
11651
|
+
}
|
|
11652
|
+
function runBrandGuardian(projectDir, tokens) {
|
|
11653
|
+
const issues = [];
|
|
11654
|
+
let filesScanned = 0;
|
|
11655
|
+
const files = findFiles(projectDir, ["src", "app", "pages", "components"], [".tsx", ".jsx", ".vue", ".svelte", ".css"]);
|
|
11656
|
+
for (const file of files.slice(0, 100)) {
|
|
11657
|
+
try {
|
|
11658
|
+
const content = readFileSync4(file, "utf-8");
|
|
11659
|
+
const lines = content.split("\n");
|
|
11660
|
+
const relPath = file.replace(projectDir, "").replace(/\\/g, "/").replace(/^\//, "");
|
|
11661
|
+
filesScanned++;
|
|
11662
|
+
for (let i = 0; i < lines.length; i++) {
|
|
11663
|
+
const line = lines[i];
|
|
11664
|
+
const lineNum = i + 1;
|
|
11665
|
+
if (file.match(/\.(tsx|jsx|vue|svelte)$/)) {
|
|
11666
|
+
const hexMatches = line.matchAll(/#[0-9a-fA-F]{3,8}\b/g);
|
|
11667
|
+
for (const m of hexMatches) {
|
|
11668
|
+
if (line.trimStart().startsWith("//") || line.trimStart().startsWith("*")) continue;
|
|
11669
|
+
if (line.includes("--")) continue;
|
|
11670
|
+
issues.push({
|
|
11671
|
+
file: relPath,
|
|
11672
|
+
line: lineNum,
|
|
11673
|
+
severity: "warning",
|
|
11674
|
+
rule: "no-hardcoded-colors",
|
|
11675
|
+
message: `Hardcoded color ${m[0]} \u2014 use design tokens instead`,
|
|
11676
|
+
fix: "Replace with a CSS variable or Tailwind class from your design system"
|
|
11677
|
+
});
|
|
11678
|
+
}
|
|
11679
|
+
}
|
|
11680
|
+
if (line.includes("style=") && line.match(/\d+px/)) {
|
|
11681
|
+
issues.push({
|
|
11682
|
+
file: relPath,
|
|
11683
|
+
line: lineNum,
|
|
11684
|
+
severity: "warning",
|
|
11685
|
+
rule: "no-inline-px",
|
|
11686
|
+
message: "Inline px values \u2014 use spacing tokens or Tailwind classes",
|
|
11687
|
+
fix: "Replace px values with spacing scale (xs, sm, md, lg, xl)"
|
|
11688
|
+
});
|
|
11689
|
+
}
|
|
11690
|
+
if (line.match(/<img\b/) && !line.includes("alt=") && !line.includes("alt =")) {
|
|
11691
|
+
issues.push({
|
|
11692
|
+
file: relPath,
|
|
11693
|
+
line: lineNum,
|
|
11694
|
+
severity: "error",
|
|
11695
|
+
rule: "img-alt-text",
|
|
11696
|
+
message: "Image missing alt attribute \u2014 accessibility violation",
|
|
11697
|
+
fix: 'Add alt="descriptive text" or alt="" for decorative images'
|
|
11698
|
+
});
|
|
11699
|
+
}
|
|
11700
|
+
if (line.includes("onClick") && !line.includes("onKeyDown") && !line.includes("onKeyUp") && !line.includes("onKeyPress")) {
|
|
11701
|
+
if (line.includes("<div") || line.includes("<span")) {
|
|
11702
|
+
issues.push({
|
|
11703
|
+
file: relPath,
|
|
11704
|
+
line: lineNum,
|
|
11705
|
+
severity: "warning",
|
|
11706
|
+
rule: "keyboard-accessible",
|
|
11707
|
+
message: "Click handler on non-interactive element without keyboard support",
|
|
11708
|
+
fix: 'Add onKeyDown handler and role="button" tabIndex={0}, or use <button>'
|
|
11709
|
+
});
|
|
11710
|
+
}
|
|
11711
|
+
}
|
|
11712
|
+
if (line.match(/font-size:\s*\d+px/) && !line.includes("--")) {
|
|
11713
|
+
issues.push({
|
|
11714
|
+
file: relPath,
|
|
11715
|
+
line: lineNum,
|
|
11716
|
+
severity: "info",
|
|
11717
|
+
rule: "use-typography-scale",
|
|
11718
|
+
message: "Hardcoded font-size \u2014 use typography scale tokens",
|
|
11719
|
+
fix: "Replace with typography scale class (text-xs, text-sm, text-base, etc.)"
|
|
11720
|
+
});
|
|
11721
|
+
}
|
|
11722
|
+
if (line.match(/<html\b/) && !line.includes("lang=")) {
|
|
11723
|
+
issues.push({
|
|
11724
|
+
file: relPath,
|
|
11725
|
+
line: lineNum,
|
|
11726
|
+
severity: "error",
|
|
11727
|
+
rule: "html-lang",
|
|
11728
|
+
message: "HTML element missing lang attribute \u2014 accessibility violation",
|
|
11729
|
+
fix: 'Add lang="en" (or appropriate language code) to <html>'
|
|
11730
|
+
});
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11733
|
+
} catch {
|
|
11734
|
+
}
|
|
11735
|
+
}
|
|
11736
|
+
const errors = issues.filter((i) => i.severity === "error").length;
|
|
11737
|
+
const warnings = issues.filter((i) => i.severity === "warning").length;
|
|
11738
|
+
const infos = issues.filter((i) => i.severity === "info").length;
|
|
11739
|
+
return {
|
|
11740
|
+
issues,
|
|
11741
|
+
passed: errors === 0,
|
|
11742
|
+
stats: { errors, warnings, infos, filesScanned }
|
|
11743
|
+
};
|
|
11744
|
+
}
|
|
11745
|
+
function generateDesignSystemConfig(tokens, registry) {
|
|
11746
|
+
return JSON.stringify({
|
|
11747
|
+
version: "1.0",
|
|
11748
|
+
tokens,
|
|
11749
|
+
components: {
|
|
11750
|
+
library: registry.library,
|
|
11751
|
+
framework: registry.framework,
|
|
11752
|
+
count: registry.components.length,
|
|
11753
|
+
entries: registry.components
|
|
11754
|
+
}
|
|
11755
|
+
}, null, 2) + "\n";
|
|
11756
|
+
}
|
|
11757
|
+
function findFiles(base, dirs, extensions) {
|
|
11758
|
+
const files = [];
|
|
11759
|
+
for (const dir of dirs) {
|
|
11760
|
+
const fullDir = join7(base, dir);
|
|
11761
|
+
if (existsSync7(fullDir)) {
|
|
11762
|
+
walkDir(fullDir, extensions, files);
|
|
11763
|
+
}
|
|
11764
|
+
}
|
|
11765
|
+
return files;
|
|
11766
|
+
}
|
|
11767
|
+
function walkDir(dir, extensions, result) {
|
|
11768
|
+
try {
|
|
11769
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
11770
|
+
for (const entry of entries) {
|
|
11771
|
+
const full = join7(dir, entry.name);
|
|
11772
|
+
if (entry.isDirectory()) {
|
|
11773
|
+
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist" || entry.name === ".git") continue;
|
|
11774
|
+
walkDir(full, extensions, result);
|
|
11775
|
+
} else if (extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
11776
|
+
result.push(full);
|
|
11777
|
+
}
|
|
11778
|
+
}
|
|
11779
|
+
} catch {
|
|
11780
|
+
}
|
|
11781
|
+
}
|
|
11782
|
+
|
|
11469
11783
|
// src/templates/configs/sandbox-policy.ts
|
|
11470
11784
|
function getSandboxPolicyTemplate() {
|
|
11471
11785
|
return `# FISHI Sandbox Policy
|
|
@@ -11862,7 +12176,9 @@ export {
|
|
|
11862
12176
|
backendAgentTemplate,
|
|
11863
12177
|
buildSandboxEnv,
|
|
11864
12178
|
createBackup,
|
|
12179
|
+
detectComponentRegistry,
|
|
11865
12180
|
detectConflicts,
|
|
12181
|
+
detectDesignTokens,
|
|
11866
12182
|
detectDevServer,
|
|
11867
12183
|
detectDocker,
|
|
11868
12184
|
devLeadTemplate,
|
|
@@ -11871,6 +12187,8 @@ export {
|
|
|
11871
12187
|
emitEvent,
|
|
11872
12188
|
frontendAgentTemplate,
|
|
11873
12189
|
fullstackAgentTemplate,
|
|
12190
|
+
generateDefaultTokens,
|
|
12191
|
+
generateDesignSystemConfig,
|
|
11874
12192
|
generateScaffold,
|
|
11875
12193
|
getAdaptiveTaskGraphSkill,
|
|
11876
12194
|
getAgentCompleteHook,
|
|
@@ -11938,6 +12256,7 @@ export {
|
|
|
11938
12256
|
readSandboxConfig,
|
|
11939
12257
|
readSandboxPolicy,
|
|
11940
12258
|
researchAgentTemplate,
|
|
12259
|
+
runBrandGuardian,
|
|
11941
12260
|
runInDockerSandbox,
|
|
11942
12261
|
runInProcessSandbox,
|
|
11943
12262
|
runInSandbox,
|