@getcoherent/cli 0.6.17 → 0.6.19
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.
|
@@ -623,36 +623,18 @@ function replaceRawColors(classes, colorMap) {
|
|
|
623
623
|
const n = parseInt(shade);
|
|
624
624
|
const isDestructive = color === "red";
|
|
625
625
|
if (prefix === "bg") {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (n
|
|
631
|
-
|
|
632
|
-
return statePrefix + (isDestructive ? "bg-destructive/10" : "bg-primary/10");
|
|
633
|
-
}
|
|
634
|
-
if (n >= 300 && n <= 400) {
|
|
635
|
-
changed = true;
|
|
636
|
-
return statePrefix + (isDestructive ? "bg-destructive/20" : "bg-primary/20");
|
|
637
|
-
}
|
|
638
|
-
if (n >= 800) {
|
|
639
|
-
changed = true;
|
|
640
|
-
return statePrefix + "bg-muted";
|
|
641
|
-
}
|
|
626
|
+
changed = true;
|
|
627
|
+
if (n <= 100) return statePrefix + (isDestructive ? "bg-destructive/10" : "bg-primary/10");
|
|
628
|
+
if (n <= 200) return statePrefix + (isDestructive ? "bg-destructive/10" : "bg-primary/10");
|
|
629
|
+
if (n <= 400) return statePrefix + (isDestructive ? "bg-destructive/20" : "bg-primary/20");
|
|
630
|
+
if (n <= 700) return statePrefix + (isDestructive ? "bg-destructive" : "bg-primary");
|
|
631
|
+
return statePrefix + "bg-muted";
|
|
642
632
|
}
|
|
643
633
|
if (prefix === "text") {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (n >= 100 && n <= 300) {
|
|
649
|
-
changed = true;
|
|
650
|
-
return statePrefix + "text-foreground";
|
|
651
|
-
}
|
|
652
|
-
if (n >= 700) {
|
|
653
|
-
changed = true;
|
|
654
|
-
return statePrefix + "text-foreground";
|
|
655
|
-
}
|
|
634
|
+
changed = true;
|
|
635
|
+
if (n <= 300) return statePrefix + "text-foreground";
|
|
636
|
+
if (n <= 600) return statePrefix + (isDestructive ? "text-destructive" : "text-primary");
|
|
637
|
+
return statePrefix + "text-foreground";
|
|
656
638
|
}
|
|
657
639
|
if (prefix === "border" || prefix === "ring" || prefix === "outline") {
|
|
658
640
|
changed = true;
|
|
@@ -675,24 +657,16 @@ function replaceRawColors(classes, colorMap) {
|
|
|
675
657
|
}
|
|
676
658
|
const n = parseInt(shade);
|
|
677
659
|
if (prefix === "bg") {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if (n >= 100 && n <= 300) {
|
|
683
|
-
changed = true;
|
|
684
|
-
return statePrefix + "bg-muted";
|
|
685
|
-
}
|
|
660
|
+
changed = true;
|
|
661
|
+
if (n <= 300) return statePrefix + "bg-muted";
|
|
662
|
+
if (n <= 700) return statePrefix + "bg-muted";
|
|
663
|
+
return statePrefix + "bg-background";
|
|
686
664
|
}
|
|
687
665
|
if (prefix === "text") {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (n >= 400 && n <= 600) {
|
|
693
|
-
changed = true;
|
|
694
|
-
return statePrefix + "text-muted-foreground";
|
|
695
|
-
}
|
|
666
|
+
changed = true;
|
|
667
|
+
if (n <= 300) return statePrefix + "text-foreground";
|
|
668
|
+
if (n <= 600) return statePrefix + "text-muted-foreground";
|
|
669
|
+
return statePrefix + "text-foreground";
|
|
696
670
|
}
|
|
697
671
|
if (prefix === "border" || prefix === "ring" || prefix === "outline") {
|
|
698
672
|
changed = true;
|
|
@@ -969,15 +943,47 @@ ${selectImport}`
|
|
|
969
943
|
newImport = newImport.replace(new RegExp(`\\b${dup}\\b,?\\s*`), "");
|
|
970
944
|
fixes.push(`removed ${dup} from lucide import (conflicts with UI component import)`);
|
|
971
945
|
}
|
|
946
|
+
const ICON_ALIASES = {
|
|
947
|
+
Github: "ExternalLink",
|
|
948
|
+
GitHub: "ExternalLink",
|
|
949
|
+
Twitter: "MessageCircle",
|
|
950
|
+
Linkedin: "Link2",
|
|
951
|
+
LinkedIn: "Link2",
|
|
952
|
+
Slack: "MessageSquare",
|
|
953
|
+
Discord: "MessageCircle",
|
|
954
|
+
Facebook: "Globe",
|
|
955
|
+
Instagram: "Camera",
|
|
956
|
+
YouTube: "Play",
|
|
957
|
+
Youtube: "Play",
|
|
958
|
+
TikTok: "Music",
|
|
959
|
+
Reddit: "MessageSquare",
|
|
960
|
+
Twitch: "Tv",
|
|
961
|
+
Figma: "Pen",
|
|
962
|
+
Dribbble: "Palette",
|
|
963
|
+
Medium: "FileText",
|
|
964
|
+
WhatsApp: "Phone",
|
|
965
|
+
Telegram: "Send",
|
|
966
|
+
Pinterest: "Pin",
|
|
967
|
+
Spotify: "Music"
|
|
968
|
+
};
|
|
972
969
|
const invalid = iconNames.filter((name) => !lucideExports.has(name) && !nonLucideImports.has(name));
|
|
973
970
|
if (invalid.length > 0) {
|
|
974
|
-
const
|
|
971
|
+
const replacements = [];
|
|
975
972
|
for (const bad of invalid) {
|
|
976
|
-
const
|
|
977
|
-
|
|
978
|
-
|
|
973
|
+
const replacement = ICON_ALIASES[bad] || "Circle";
|
|
974
|
+
if (lucideExports.has(replacement)) {
|
|
975
|
+
const re = new RegExp(`\\b${bad}\\b`, "g");
|
|
976
|
+
newImport = newImport.replace(re, replacement);
|
|
977
|
+
fixed = fixed.replace(re, replacement);
|
|
978
|
+
replacements.push(`${bad}\u2192${replacement}`);
|
|
979
|
+
} else {
|
|
980
|
+
const re = new RegExp(`\\b${bad}\\b`, "g");
|
|
981
|
+
newImport = newImport.replace(re, "Circle");
|
|
982
|
+
fixed = fixed.replace(re, "Circle");
|
|
983
|
+
replacements.push(`${bad}\u2192Circle`);
|
|
984
|
+
}
|
|
979
985
|
}
|
|
980
|
-
fixes.push(`invalid lucide icons
|
|
986
|
+
fixes.push(`invalid lucide icons: ${replacements.join(", ")}`);
|
|
981
987
|
}
|
|
982
988
|
if (duplicates.length > 0 || invalid.length > 0) {
|
|
983
989
|
const importedNames = [
|
|
@@ -1151,6 +1157,27 @@ ${selectImport}`
|
|
|
1151
1157
|
if (fixed !== beforeImgFix) {
|
|
1152
1158
|
fixes.push("placeholder images \u2192 working URLs (picsum/pravatar)");
|
|
1153
1159
|
}
|
|
1160
|
+
const beforePlaceholder = fixed;
|
|
1161
|
+
fixed = fixed.replace(
|
|
1162
|
+
/>(\s*)Lorem ipsum[^<]*/gi,
|
|
1163
|
+
">$1Streamline your workflow with intelligent automation and real-time collaboration tools"
|
|
1164
|
+
);
|
|
1165
|
+
fixed = fixed.replace(/>(\s*)Card content(\s*)</gi, ">$1View details$2<");
|
|
1166
|
+
fixed = fixed.replace(/>(\s*)Your (?:text|content) here(\s*)</gi, ">$1Get started today$2<");
|
|
1167
|
+
fixed = fixed.replace(/>(\s*)Description(\s*)</g, ">$1Overview$2<");
|
|
1168
|
+
fixed = fixed.replace(/>\s*Title\s*</g, ">Page Title<");
|
|
1169
|
+
fixed = fixed.replace(/placeholder\s*text/gi, "contextual content");
|
|
1170
|
+
fixed = fixed.replace(/"John Doe"/g, '"Alex Thompson"');
|
|
1171
|
+
fixed = fixed.replace(/'John Doe'/g, "'Alex Thompson'");
|
|
1172
|
+
fixed = fixed.replace(/"Jane Doe"/g, '"Sarah Chen"');
|
|
1173
|
+
fixed = fixed.replace(/'Jane Doe'/g, "'Sarah Chen'");
|
|
1174
|
+
fixed = fixed.replace(/"user@example\.com"/g, '"alex@company.com"');
|
|
1175
|
+
fixed = fixed.replace(/'user@example\.com'/g, "'alex@company.com'");
|
|
1176
|
+
fixed = fixed.replace(/"test@example\.com"/g, '"team@company.com"');
|
|
1177
|
+
fixed = fixed.replace(/'test@example\.com'/g, "'team@company.com'");
|
|
1178
|
+
if (fixed !== beforePlaceholder) {
|
|
1179
|
+
fixes.push("placeholder content \u2192 contextual content");
|
|
1180
|
+
}
|
|
1154
1181
|
return { code: fixed, fixes };
|
|
1155
1182
|
}
|
|
1156
1183
|
function formatIssues(issues) {
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
formatIssues,
|
|
8
8
|
validatePageQuality,
|
|
9
9
|
verifyIncrementalEdit
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CF4377B7.js";
|
|
11
11
|
import {
|
|
12
12
|
generateArchitecturePlan,
|
|
13
13
|
getPageGroup,
|
|
@@ -6012,8 +6012,29 @@ function buildTieredComponentsPrompt(manifest, pageType) {
|
|
|
6012
6012
|
);
|
|
6013
6013
|
return sections.join("\n");
|
|
6014
6014
|
}
|
|
6015
|
-
function formatPlanSummary(plan) {
|
|
6015
|
+
function formatPlanSummary(plan, forRoute) {
|
|
6016
6016
|
if (plan.groups.length === 0) return "";
|
|
6017
|
+
if (forRoute) {
|
|
6018
|
+
const group = plan.groups.find((g) => g.pages.includes(forRoute));
|
|
6019
|
+
if (!group) return "";
|
|
6020
|
+
const groupLine = ` Group "${group.id}" (layout: ${group.layout}): ${group.pages.join(", ")}`;
|
|
6021
|
+
const relevantComps = plan.sharedComponents.filter((c) => c.usedBy.includes(forRoute));
|
|
6022
|
+
const parts2 = [`ARCHITECTURE PLAN:
|
|
6023
|
+
Your group:
|
|
6024
|
+
${groupLine}`];
|
|
6025
|
+
if (relevantComps.length > 0) {
|
|
6026
|
+
parts2.push(
|
|
6027
|
+
`Shared Components for this page:
|
|
6028
|
+
${relevantComps.map((c) => ` ${c.name} (${c.type}) \u2014 ${c.description}`).join("\n")}`
|
|
6029
|
+
);
|
|
6030
|
+
}
|
|
6031
|
+
const routeKey = forRoute.replace(/^\//, "");
|
|
6032
|
+
const note = plan.pageNotes?.[routeKey];
|
|
6033
|
+
if (note?.sections && note.sections.length > 0) {
|
|
6034
|
+
parts2.push(`Page Sections: ${note.sections.join(", ")}`);
|
|
6035
|
+
}
|
|
6036
|
+
return parts2.join("\n");
|
|
6037
|
+
}
|
|
6017
6038
|
const groupLines = plan.groups.map((g) => ` Group "${g.id}" (layout: ${g.layout}): ${g.pages.join(", ")}`);
|
|
6018
6039
|
const compLines = plan.sharedComponents.map(
|
|
6019
6040
|
(c) => ` ${c.name} (${c.type}) \u2014 ${c.description}; usedBy: ${c.usedBy.join(", ")}`
|
|
@@ -6045,7 +6066,7 @@ function readExistingAppPageForReference(projectRoot, plan) {
|
|
|
6045
6066
|
if (existsSync14(filePath)) {
|
|
6046
6067
|
const code = readFileSync9(filePath, "utf-8");
|
|
6047
6068
|
const lines = code.split("\n");
|
|
6048
|
-
return lines.slice(0,
|
|
6069
|
+
return lines.slice(0, 60).join("\n");
|
|
6049
6070
|
}
|
|
6050
6071
|
}
|
|
6051
6072
|
}
|
|
@@ -6064,7 +6085,7 @@ function readExistingAppPageForReference(projectRoot, plan) {
|
|
|
6064
6085
|
if (existsSync14(pagePath)) {
|
|
6065
6086
|
const code = readFileSync9(pagePath, "utf-8");
|
|
6066
6087
|
const lines = code.split("\n");
|
|
6067
|
-
return lines.slice(0,
|
|
6088
|
+
return lines.slice(0, 60).join("\n");
|
|
6068
6089
|
}
|
|
6069
6090
|
}
|
|
6070
6091
|
}
|
|
@@ -6321,7 +6342,6 @@ async function splitGeneratePages(spinner, message, modCtx, provider, parseOpts)
|
|
|
6321
6342
|
const currentManifest = projectRoot ? await loadManifest5(projectRoot) : null;
|
|
6322
6343
|
const routeNote = `EXISTING ROUTES in this project: ${allRoutes}. All internal links MUST point to one of these routes. If a target doesn't exist, use href="#".`;
|
|
6323
6344
|
const alignmentNote = 'CRITICAL LAYOUT RULE: Every <section> must wrap its content in a container div matching the header width. Use the EXACT same container classes as shown in the style context (e.g. className="container max-w-6xl px-4" or className="max-w-6xl mx-auto px-4"). Inner content can use narrower max-w for text centering, but the outer section container MUST match.';
|
|
6324
|
-
const planSummaryNote = plan ? formatPlanSummary(plan) : "";
|
|
6325
6345
|
const existingAppPageCode = readExistingAppPageForReference(parseOpts?.projectRoot ?? null, plan);
|
|
6326
6346
|
const existingAppPageNote = existingAppPageCode ? `
|
|
6327
6347
|
EXISTING APP PAGE (match these UI patterns for consistency):
|
|
@@ -6398,7 +6418,7 @@ ${existingAppPageCode}
|
|
|
6398
6418
|
routeNote,
|
|
6399
6419
|
alignmentNote,
|
|
6400
6420
|
authNote,
|
|
6401
|
-
|
|
6421
|
+
plan ? formatPlanSummary(plan, route) : "",
|
|
6402
6422
|
pageType !== "auth" ? existingAppPageNote : void 0,
|
|
6403
6423
|
existingPagesContext,
|
|
6404
6424
|
styleContext
|
|
@@ -6407,7 +6427,7 @@ ${existingAppPageCode}
|
|
|
6407
6427
|
const result = await parseModification(prompt, modCtx, provider, parseOpts);
|
|
6408
6428
|
phase5Done++;
|
|
6409
6429
|
spinner.text = `Phase 5/6 \u2014 ${phase5Done}/${remainingPages.length} pages generated...`;
|
|
6410
|
-
|
|
6430
|
+
const codePage = result.requests.find((r) => r.type === "add-page");
|
|
6411
6431
|
if (currentReusePlan && currentReusePlan.reuse.length > 0 && codePage) {
|
|
6412
6432
|
const pageCode = codePage.changes?.pageCode;
|
|
6413
6433
|
if (pageCode) {
|
|
@@ -6417,17 +6437,28 @@ ${existingAppPageCode}
|
|
|
6417
6437
|
chalk8.dim(` \u2713 Reuse verified for "${name}": ${verification.passed.map((p) => p.component).join(", ")}`)
|
|
6418
6438
|
);
|
|
6419
6439
|
}
|
|
6420
|
-
if (verification.missed.length > 0
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
` \u26A0 Missed reuse in "${name}": ${verification.missed.map((m) => m.component).join(", ")} \u2014 retrying...`
|
|
6424
|
-
)
|
|
6425
|
-
);
|
|
6440
|
+
if (verification.missed.length > 0) {
|
|
6441
|
+
const missedNames = verification.missed.map((m) => m.component);
|
|
6442
|
+
console.log(chalk8.yellow(` \u26A0 Missed reuse in "${name}": ${missedNames.join(", ")} \u2014 patching...`));
|
|
6426
6443
|
try {
|
|
6427
|
-
const
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6444
|
+
const ai = await createAIProvider(provider);
|
|
6445
|
+
if (ai.editPageCode) {
|
|
6446
|
+
const patchLines = verification.missed.map((m) => {
|
|
6447
|
+
const importPath = m.importPath || `@/components/shared/${m.component.replace(/([A-Z])/g, (_, c, i) => (i ? "-" : "") + c.toLowerCase()).replace(/^-/, "")}`;
|
|
6448
|
+
return `- Add: import { ${m.component} } from '${importPath}'
|
|
6449
|
+
Then find any inline implementation of ${m.component} and replace with <${m.component} />`;
|
|
6450
|
+
});
|
|
6451
|
+
const patchInstruction = `Add these shared components to this page:
|
|
6452
|
+
${patchLines.join("\n")}
|
|
6453
|
+
|
|
6454
|
+
Keep all existing functionality. Only add imports and replace inline duplicates.`;
|
|
6455
|
+
const patched = await ai.editPageCode(pageCode, patchInstruction, name);
|
|
6456
|
+
if (patched && patched.length > 100 && /export\s+(default\s+)?function/.test(patched)) {
|
|
6457
|
+
;
|
|
6458
|
+
codePage.changes.pageCode = patched;
|
|
6459
|
+
console.log(chalk8.dim(` \u2713 Patched ${missedNames.join(", ")} into "${name}"`));
|
|
6460
|
+
}
|
|
6461
|
+
}
|
|
6431
6462
|
} catch {
|
|
6432
6463
|
}
|
|
6433
6464
|
}
|
|
@@ -8472,7 +8503,7 @@ async function chatCommand(message, options) {
|
|
|
8472
8503
|
spinner.start(`Creating shared component: ${componentName}...`);
|
|
8473
8504
|
const { createAIProvider: createAIProvider2 } = await import("./ai-provider-CGSIYFZT.js");
|
|
8474
8505
|
const { generateSharedComponent: generateSharedComponent7 } = await import("@getcoherent/core");
|
|
8475
|
-
const { autoFixCode: autoFixCode2 } = await import("./quality-validator-
|
|
8506
|
+
const { autoFixCode: autoFixCode2 } = await import("./quality-validator-BX3T5X6Z.js");
|
|
8476
8507
|
const { extractPropsInterface, extractDependencies } = await import("./component-extractor-VYJLT5NR.js");
|
|
8477
8508
|
const aiProvider = await createAIProvider2(provider ?? "auto");
|
|
8478
8509
|
const prompt = `Generate a React component called "${componentName}". Description: ${message}.
|