@primeuicom/mcp 0.1.27 → 0.1.29
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 +2 -2
- package/dist/service.js +254 -466
- package/dist/service.js.map +1 -1
- package/package.json +1 -1
package/dist/service.js
CHANGED
|
@@ -485,42 +485,13 @@ import { unlink } from "fs/promises";
|
|
|
485
485
|
import path5 from "path";
|
|
486
486
|
import { Readable, Transform } from "stream";
|
|
487
487
|
import { pipeline } from "stream/promises";
|
|
488
|
-
import { z as z3 } from "zod";
|
|
489
|
-
|
|
490
|
-
// src/lib/fs.ts
|
|
491
|
-
import { mkdir, rm, writeFile } from "fs/promises";
|
|
492
|
-
import path4 from "path";
|
|
493
|
-
import extractZipArchive from "extract-zip";
|
|
494
|
-
async function ensureDir(dirPath) {
|
|
495
|
-
await mkdir(dirPath, { recursive: true });
|
|
496
|
-
}
|
|
497
|
-
async function resetDir(dirPath) {
|
|
498
|
-
await rm(dirPath, { recursive: true, force: true });
|
|
499
|
-
await mkdir(dirPath, { recursive: true });
|
|
500
|
-
}
|
|
501
|
-
async function writeUtf8(filePath, content) {
|
|
502
|
-
await ensureDir(path4.dirname(filePath));
|
|
503
|
-
await writeFile(filePath, content, "utf-8");
|
|
504
|
-
}
|
|
505
|
-
async function extractZip(zipPath, targetDir) {
|
|
506
|
-
await ensureDir(targetDir);
|
|
507
|
-
try {
|
|
508
|
-
await extractZipArchive(zipPath, { dir: targetDir });
|
|
509
|
-
} catch (error) {
|
|
510
|
-
const details = error instanceof Error ? error.message : String(error);
|
|
511
|
-
throw new Error(`Failed to extract zip at "${zipPath}". ${details}`);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
488
|
|
|
515
|
-
// src/
|
|
516
|
-
|
|
517
|
-
var
|
|
518
|
-
"
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
];
|
|
522
|
-
var exportStatusSchema = z3.enum(["in_progress", "completed", "failed"]);
|
|
523
|
-
var projectPageObjectSchema = z3.object({
|
|
489
|
+
// src/lib/api-v1-contract.ts
|
|
490
|
+
import { z as z3 } from "zod";
|
|
491
|
+
var primeUiExportStatusSchema = z3.enum(
|
|
492
|
+
["in_progress", "completed", "failed"]
|
|
493
|
+
);
|
|
494
|
+
var primeUiProjectPageObjectSchema = z3.object({
|
|
524
495
|
id: z3.string(),
|
|
525
496
|
title: z3.string(),
|
|
526
497
|
slug: z3.string(),
|
|
@@ -529,24 +500,33 @@ var projectPageObjectSchema = z3.object({
|
|
|
529
500
|
pagePath: z3.string(),
|
|
530
501
|
componentsPath: z3.string()
|
|
531
502
|
});
|
|
532
|
-
var
|
|
533
|
-
var
|
|
503
|
+
var primeUiProjectPageSchema = primeUiProjectPageObjectSchema;
|
|
504
|
+
var primeUiProjectExportableSchema = z3.object({
|
|
505
|
+
key: z3.string(),
|
|
506
|
+
description: z3.string(),
|
|
507
|
+
isReadyToExport: z3.boolean()
|
|
508
|
+
});
|
|
509
|
+
var primeUiExportSummarySchema = z3.object({
|
|
534
510
|
total: z3.number(),
|
|
535
511
|
successful: z3.number(),
|
|
536
512
|
failed: z3.number()
|
|
537
513
|
});
|
|
538
|
-
var
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
files: z3.array(z3.string())
|
|
542
|
-
|
|
514
|
+
var primeUiExportableManifestSchema = z3.object({
|
|
515
|
+
success: z3.boolean(),
|
|
516
|
+
message: z3.string(),
|
|
517
|
+
files: z3.array(z3.string())
|
|
518
|
+
});
|
|
519
|
+
var primeUiExportedExportableSchema = z3.object({
|
|
520
|
+
key: z3.string(),
|
|
521
|
+
isReadyToExport: z3.boolean(),
|
|
522
|
+
manifest: primeUiExportableManifestSchema
|
|
543
523
|
});
|
|
544
|
-
var
|
|
524
|
+
var primeUiExportPageManifestSchema = z3.object({
|
|
545
525
|
success: z3.boolean(),
|
|
546
526
|
message: z3.string(),
|
|
547
527
|
files: z3.array(z3.string())
|
|
548
528
|
});
|
|
549
|
-
var
|
|
529
|
+
var primeUiExportPageSchema = z3.object({
|
|
550
530
|
id: z3.string(),
|
|
551
531
|
title: z3.string().optional(),
|
|
552
532
|
slug: z3.string(),
|
|
@@ -554,51 +534,107 @@ var exportPageSchema = z3.object({
|
|
|
554
534
|
isReadyToExport: z3.literal(true),
|
|
555
535
|
pagePath: z3.string(),
|
|
556
536
|
componentsPath: z3.string(),
|
|
557
|
-
manifest:
|
|
558
|
-
});
|
|
559
|
-
var projectInfoSchema = z3.object({
|
|
560
|
-
projectId: z3.string(),
|
|
561
|
-
projectName: z3.string(),
|
|
562
|
-
metadata: z3.record(z3.unknown()),
|
|
563
|
-
pages: z3.array(projectPageSchema)
|
|
537
|
+
manifest: primeUiExportPageManifestSchema
|
|
564
538
|
});
|
|
565
|
-
var
|
|
539
|
+
var primeUiProjectInfoSchema = z3.object(
|
|
540
|
+
{
|
|
541
|
+
projectId: z3.string(),
|
|
542
|
+
projectName: z3.string(),
|
|
543
|
+
metadata: z3.record(z3.unknown()),
|
|
544
|
+
exportables: z3.array(primeUiProjectExportableSchema),
|
|
545
|
+
pages: z3.array(primeUiProjectPageSchema)
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
var primeUiProjectPageComponentSchema = z3.object({
|
|
566
549
|
blockId: z3.string(),
|
|
567
550
|
componentId: z3.string(),
|
|
568
551
|
componentGroup: z3.string(),
|
|
569
552
|
slot: z3.string().nullable(),
|
|
570
553
|
props: z3.record(z3.unknown()).nullable()
|
|
571
554
|
});
|
|
572
|
-
var
|
|
573
|
-
page:
|
|
555
|
+
var primeUiProjectPageDetailsSchema = z3.object({
|
|
556
|
+
page: primeUiProjectPageObjectSchema.extend({
|
|
574
557
|
pageInstruction: z3.string().nullable()
|
|
575
558
|
}),
|
|
576
559
|
variant: z3.object({
|
|
577
560
|
id: z3.string(),
|
|
578
561
|
name: z3.string()
|
|
579
562
|
}).nullable(),
|
|
580
|
-
components: z3.array(
|
|
563
|
+
components: z3.array(primeUiProjectPageComponentSchema).nullable()
|
|
581
564
|
});
|
|
582
|
-
var
|
|
565
|
+
var primeUiExportsResponseSchema = z3.object({
|
|
583
566
|
exports: z3.array(
|
|
584
567
|
z3.object({
|
|
585
568
|
id: z3.string(),
|
|
586
|
-
status:
|
|
569
|
+
status: primeUiExportStatusSchema,
|
|
587
570
|
createdAt: z3.string().datetime({ offset: true })
|
|
588
571
|
})
|
|
589
572
|
)
|
|
590
573
|
});
|
|
591
|
-
var
|
|
574
|
+
var primeUiCreateExportResponseSchema = z3.object({
|
|
592
575
|
export: z3.object({
|
|
593
576
|
id: z3.string(),
|
|
594
|
-
status:
|
|
577
|
+
status: primeUiExportStatusSchema,
|
|
595
578
|
createdAt: z3.string().datetime({ offset: true }),
|
|
596
579
|
expiresAt: z3.string().datetime({ offset: true }).nullable(),
|
|
597
|
-
summary:
|
|
598
|
-
|
|
580
|
+
summary: primeUiExportSummarySchema,
|
|
581
|
+
exportables: z3.array(primeUiExportedExportableSchema)
|
|
599
582
|
}),
|
|
600
|
-
pages: z3.array(
|
|
583
|
+
pages: z3.array(primeUiExportPageSchema)
|
|
601
584
|
});
|
|
585
|
+
var primeUiExportManifestSchema = primeUiCreateExportResponseSchema;
|
|
586
|
+
function parsePrimeUiExportManifest(value) {
|
|
587
|
+
if (!value || typeof value !== "object") {
|
|
588
|
+
throw new Error("Export manifest is invalid.");
|
|
589
|
+
}
|
|
590
|
+
const maybe = value;
|
|
591
|
+
if (!maybe.export || typeof maybe.export !== "object") {
|
|
592
|
+
throw new Error("Export manifest export payload is invalid.");
|
|
593
|
+
}
|
|
594
|
+
const parsed = primeUiExportManifestSchema.safeParse(value);
|
|
595
|
+
if (!parsed.success) {
|
|
596
|
+
const hasPageIssue = parsed.error.issues.some(
|
|
597
|
+
(issue) => issue.path[0] === "pages"
|
|
598
|
+
);
|
|
599
|
+
throw new Error(
|
|
600
|
+
hasPageIssue ? "Export manifest pages payload is invalid." : "Export manifest does not match expected schema."
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
return parsed.data;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/lib/fs.ts
|
|
607
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
608
|
+
import path4 from "path";
|
|
609
|
+
import extractZipArchive from "extract-zip";
|
|
610
|
+
async function ensureDir(dirPath) {
|
|
611
|
+
await mkdir(dirPath, { recursive: true });
|
|
612
|
+
}
|
|
613
|
+
async function resetDir(dirPath) {
|
|
614
|
+
await rm(dirPath, { recursive: true, force: true });
|
|
615
|
+
await mkdir(dirPath, { recursive: true });
|
|
616
|
+
}
|
|
617
|
+
async function writeUtf8(filePath, content) {
|
|
618
|
+
await ensureDir(path4.dirname(filePath));
|
|
619
|
+
await writeFile(filePath, content, "utf-8");
|
|
620
|
+
}
|
|
621
|
+
async function extractZip(zipPath, targetDir) {
|
|
622
|
+
await ensureDir(targetDir);
|
|
623
|
+
try {
|
|
624
|
+
await extractZipArchive(zipPath, { dir: targetDir });
|
|
625
|
+
} catch (error) {
|
|
626
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
627
|
+
throw new Error(`Failed to extract zip at "${zipPath}". ${details}`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/sources/api-provider.ts
|
|
632
|
+
var DEFAULT_API_BASE_URL = "https://app.primeui.com/";
|
|
633
|
+
var ZIP_CONTENT_TYPES = [
|
|
634
|
+
"application/zip",
|
|
635
|
+
"application/octet-stream",
|
|
636
|
+
"application/x-zip-compressed"
|
|
637
|
+
];
|
|
602
638
|
var PrimeUiApiContractError = class extends Error {
|
|
603
639
|
constructor(endpoint, details) {
|
|
604
640
|
super(`PrimeUI API contract mismatch for "${endpoint}": ${details}`);
|
|
@@ -683,26 +719,30 @@ var ApiProjectDataProvider = class {
|
|
|
683
719
|
this.apiRoot = normalizePrimeUiApiRoot(options.baseUrl);
|
|
684
720
|
}
|
|
685
721
|
async getProjectInfo() {
|
|
686
|
-
return this.requestJson("project",
|
|
722
|
+
return this.requestJson("project", primeUiProjectInfoSchema);
|
|
687
723
|
}
|
|
688
724
|
async getProjectPageBySlug(slug) {
|
|
689
725
|
const encodedSlug = encodeURIComponent(slug);
|
|
690
726
|
return this.requestJson(
|
|
691
727
|
`project/page?slug=${encodedSlug}`,
|
|
692
|
-
|
|
728
|
+
primeUiProjectPageDetailsSchema
|
|
693
729
|
);
|
|
694
730
|
}
|
|
695
731
|
async listExports() {
|
|
696
732
|
const response = await this.requestJson(
|
|
697
733
|
"project/exports",
|
|
698
|
-
|
|
734
|
+
primeUiExportsResponseSchema
|
|
699
735
|
);
|
|
700
736
|
return response.exports;
|
|
701
737
|
}
|
|
702
738
|
async createExport() {
|
|
703
|
-
return this.requestJson(
|
|
704
|
-
|
|
705
|
-
|
|
739
|
+
return this.requestJson(
|
|
740
|
+
"project/exports",
|
|
741
|
+
primeUiCreateExportResponseSchema,
|
|
742
|
+
{
|
|
743
|
+
method: "POST"
|
|
744
|
+
}
|
|
745
|
+
);
|
|
706
746
|
}
|
|
707
747
|
/**
|
|
708
748
|
* Consumer-side runtime contract for GET /api/v1/project/exports/:exportId/download.
|
|
@@ -1702,104 +1742,6 @@ async function buildImportGraph(input) {
|
|
|
1702
1742
|
};
|
|
1703
1743
|
}
|
|
1704
1744
|
|
|
1705
|
-
// src/lib/page-paths.ts
|
|
1706
|
-
var WEBSITE_APP_ROOT = "src/app/(website)";
|
|
1707
|
-
var PAGE_COMPONENTS_ROOT = "src/components/pages";
|
|
1708
|
-
var normalizeSlug = (slug) => {
|
|
1709
|
-
const trimmed = slug.trim();
|
|
1710
|
-
if (!trimmed || trimmed === "/") {
|
|
1711
|
-
return "/";
|
|
1712
|
-
}
|
|
1713
|
-
const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
1714
|
-
const withoutTrailingSlash = withLeadingSlash.replace(/\/+$/, "");
|
|
1715
|
-
return withoutTrailingSlash || "/";
|
|
1716
|
-
};
|
|
1717
|
-
var slugToFolderPath = (normalizedSlug) => {
|
|
1718
|
-
if (normalizedSlug === "/") {
|
|
1719
|
-
return "";
|
|
1720
|
-
}
|
|
1721
|
-
return normalizedSlug.slice(1);
|
|
1722
|
-
};
|
|
1723
|
-
var toPathSegment = (value) => {
|
|
1724
|
-
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9/-]+/g, "-");
|
|
1725
|
-
const compact = normalized.replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1726
|
-
return compact || "page";
|
|
1727
|
-
};
|
|
1728
|
-
var buildWebsitePagePath = (normalizedSlug) => {
|
|
1729
|
-
if (normalizedSlug === "/") {
|
|
1730
|
-
return `${WEBSITE_APP_ROOT}/page.tsx`;
|
|
1731
|
-
}
|
|
1732
|
-
return `${WEBSITE_APP_ROOT}${normalizedSlug}/page.tsx`;
|
|
1733
|
-
};
|
|
1734
|
-
var buildComponentsPath = (folderPath) => `${PAGE_COMPONENTS_ROOT}/${folderPath}`;
|
|
1735
|
-
var resolveBlogSectionRoot = (slugFolderPath) => {
|
|
1736
|
-
if (!slugFolderPath) {
|
|
1737
|
-
return "blog";
|
|
1738
|
-
}
|
|
1739
|
-
const segments = slugFolderPath.split("/").filter(Boolean);
|
|
1740
|
-
if (segments.length <= 1) {
|
|
1741
|
-
return "blog";
|
|
1742
|
-
}
|
|
1743
|
-
return segments.slice(0, -1).join("/");
|
|
1744
|
-
};
|
|
1745
|
-
function resolvePrimeUiPageExportPaths({
|
|
1746
|
-
pageType,
|
|
1747
|
-
slug
|
|
1748
|
-
}) {
|
|
1749
|
-
const normalizedSlug = normalizeSlug(slug);
|
|
1750
|
-
const slugFolderPath = slugToFolderPath(normalizedSlug);
|
|
1751
|
-
switch (pageType) {
|
|
1752
|
-
case "landing": {
|
|
1753
|
-
const componentsFolder = slugFolderPath || "home";
|
|
1754
|
-
return {
|
|
1755
|
-
pagePath: buildWebsitePagePath(normalizedSlug),
|
|
1756
|
-
componentsPath: buildComponentsPath(componentsFolder)
|
|
1757
|
-
};
|
|
1758
|
-
}
|
|
1759
|
-
case "pricing":
|
|
1760
|
-
case "contact-us": {
|
|
1761
|
-
const componentsFolder = slugFolderPath || pageType;
|
|
1762
|
-
return {
|
|
1763
|
-
pagePath: buildWebsitePagePath(normalizedSlug),
|
|
1764
|
-
componentsPath: buildComponentsPath(componentsFolder)
|
|
1765
|
-
};
|
|
1766
|
-
}
|
|
1767
|
-
case "docs": {
|
|
1768
|
-
const docsFolder = slugFolderPath || "docs";
|
|
1769
|
-
return {
|
|
1770
|
-
pagePath: `${WEBSITE_APP_ROOT}/${docsFolder}/[[...slug]]/page.tsx`,
|
|
1771
|
-
componentsPath: buildComponentsPath("docs")
|
|
1772
|
-
};
|
|
1773
|
-
}
|
|
1774
|
-
case "blogIndex": {
|
|
1775
|
-
const blogFolder = slugFolderPath || "blog";
|
|
1776
|
-
return {
|
|
1777
|
-
pagePath: `${WEBSITE_APP_ROOT}/${blogFolder}/page.tsx`,
|
|
1778
|
-
componentsPath: buildComponentsPath("blog")
|
|
1779
|
-
};
|
|
1780
|
-
}
|
|
1781
|
-
case "blogPost": {
|
|
1782
|
-
const blogSectionRoot = resolveBlogSectionRoot(slugFolderPath);
|
|
1783
|
-
return {
|
|
1784
|
-
pagePath: `${WEBSITE_APP_ROOT}/${blogSectionRoot}/[slug]/page.tsx`,
|
|
1785
|
-
componentsPath: buildComponentsPath("blog")
|
|
1786
|
-
};
|
|
1787
|
-
}
|
|
1788
|
-
case "legal":
|
|
1789
|
-
return {
|
|
1790
|
-
pagePath: buildWebsitePagePath(normalizedSlug),
|
|
1791
|
-
componentsPath: buildComponentsPath("legal")
|
|
1792
|
-
};
|
|
1793
|
-
default: {
|
|
1794
|
-
const fallbackFolder = slugFolderPath || toPathSegment(pageType);
|
|
1795
|
-
return {
|
|
1796
|
-
pagePath: buildWebsitePagePath(normalizedSlug),
|
|
1797
|
-
componentsPath: buildComponentsPath(fallbackFolder)
|
|
1798
|
-
};
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
1745
|
// src/lib/text-diff.ts
|
|
1804
1746
|
var DEFAULT_MAX_DIFF_CHARS = 16e3;
|
|
1805
1747
|
var MAX_LCS_CELLS = 2e6;
|
|
@@ -1894,15 +1836,7 @@ var DEPENDENCY_SECTIONS = [
|
|
|
1894
1836
|
"devDependencies",
|
|
1895
1837
|
"peerDependencies"
|
|
1896
1838
|
];
|
|
1897
|
-
|
|
1898
|
-
".ts",
|
|
1899
|
-
".tsx",
|
|
1900
|
-
".js",
|
|
1901
|
-
".jsx",
|
|
1902
|
-
".mjs",
|
|
1903
|
-
".cjs"
|
|
1904
|
-
]);
|
|
1905
|
-
function normalizeSlug2(slug) {
|
|
1839
|
+
function normalizeSlug(slug) {
|
|
1906
1840
|
const trimmed = slug.trim();
|
|
1907
1841
|
if (!trimmed || trimmed === "/") {
|
|
1908
1842
|
return "/";
|
|
@@ -1916,9 +1850,6 @@ function toPosixPath(value) {
|
|
|
1916
1850
|
function toProjectRelative(rootPath, absolutePath) {
|
|
1917
1851
|
return toPosixPath(path9.relative(rootPath, absolutePath));
|
|
1918
1852
|
}
|
|
1919
|
-
function escapeRegExp(value) {
|
|
1920
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1921
|
-
}
|
|
1922
1853
|
function isBinaryBuffer(buffer) {
|
|
1923
1854
|
const limit = Math.min(buffer.length, 8e3);
|
|
1924
1855
|
for (let index = 0; index < limit; index += 1) {
|
|
@@ -1928,66 +1859,6 @@ function isBinaryBuffer(buffer) {
|
|
|
1928
1859
|
}
|
|
1929
1860
|
return false;
|
|
1930
1861
|
}
|
|
1931
|
-
function stripSrcPrefix(relativePath) {
|
|
1932
|
-
return relativePath.replace(/^src\//, "");
|
|
1933
|
-
}
|
|
1934
|
-
function buildImportRewritePlan(sourceComponentsPath, targetComponentsPath) {
|
|
1935
|
-
const normalizedSource = toPosixPath(sourceComponentsPath);
|
|
1936
|
-
const normalizedTarget = toPosixPath(targetComponentsPath);
|
|
1937
|
-
if (normalizedSource === normalizedTarget) {
|
|
1938
|
-
return null;
|
|
1939
|
-
}
|
|
1940
|
-
const sourceAtAliasPrefix = `@/${stripSrcPrefix(normalizedSource)}`;
|
|
1941
|
-
const targetAtAliasPrefix = `@/${stripSrcPrefix(normalizedTarget)}`;
|
|
1942
|
-
const sourceRootAliasPrefix = `@root/${normalizedSource}`;
|
|
1943
|
-
const targetRootAliasPrefix = `@root/${normalizedTarget}`;
|
|
1944
|
-
return {
|
|
1945
|
-
sourceAtAliasPrefix,
|
|
1946
|
-
targetAtAliasPrefix,
|
|
1947
|
-
sourceRootAliasPrefix,
|
|
1948
|
-
targetRootAliasPrefix
|
|
1949
|
-
};
|
|
1950
|
-
}
|
|
1951
|
-
function replaceAliasPrefixInImportStrings(content, sourcePrefix, targetPrefix) {
|
|
1952
|
-
const pattern = new RegExp(
|
|
1953
|
-
`(["'\`])${escapeRegExp(sourcePrefix)}(?=\\/|\\1)`,
|
|
1954
|
-
"g"
|
|
1955
|
-
);
|
|
1956
|
-
return content.replace(pattern, `$1${targetPrefix}`);
|
|
1957
|
-
}
|
|
1958
|
-
function rewriteImportsForRemappedSlug(content, plan) {
|
|
1959
|
-
const afterAtAlias = replaceAliasPrefixInImportStrings(
|
|
1960
|
-
content,
|
|
1961
|
-
plan.sourceAtAliasPrefix,
|
|
1962
|
-
plan.targetAtAliasPrefix
|
|
1963
|
-
);
|
|
1964
|
-
return replaceAliasPrefixInImportStrings(
|
|
1965
|
-
afterAtAlias,
|
|
1966
|
-
plan.sourceRootAliasPrefix,
|
|
1967
|
-
plan.targetRootAliasPrefix
|
|
1968
|
-
);
|
|
1969
|
-
}
|
|
1970
|
-
function buildPlannedSourceBuffer(sourceBuffer, sourceFilePath, importRewritePlan) {
|
|
1971
|
-
if (!importRewritePlan) {
|
|
1972
|
-
return sourceBuffer;
|
|
1973
|
-
}
|
|
1974
|
-
const extension = path9.extname(sourceFilePath).toLowerCase();
|
|
1975
|
-
if (!REWRITABLE_IMPORT_EXTENSIONS.has(extension)) {
|
|
1976
|
-
return sourceBuffer;
|
|
1977
|
-
}
|
|
1978
|
-
if (isBinaryBuffer(sourceBuffer)) {
|
|
1979
|
-
return sourceBuffer;
|
|
1980
|
-
}
|
|
1981
|
-
const sourceText = sourceBuffer.toString("utf-8");
|
|
1982
|
-
const rewritten = rewriteImportsForRemappedSlug(
|
|
1983
|
-
sourceText,
|
|
1984
|
-
importRewritePlan
|
|
1985
|
-
);
|
|
1986
|
-
if (rewritten === sourceText) {
|
|
1987
|
-
return sourceBuffer;
|
|
1988
|
-
}
|
|
1989
|
-
return Buffer.from(rewritten, "utf-8");
|
|
1990
|
-
}
|
|
1991
1862
|
async function readJsonFile(filePath) {
|
|
1992
1863
|
const content = await readFile3(filePath, "utf-8");
|
|
1993
1864
|
return JSON.parse(content);
|
|
@@ -2000,68 +1871,15 @@ async function fileExists2(filePath) {
|
|
|
2000
1871
|
return false;
|
|
2001
1872
|
}
|
|
2002
1873
|
}
|
|
2003
|
-
function isExportPageManifestRecord(value) {
|
|
2004
|
-
if (!value || typeof value !== "object") {
|
|
2005
|
-
return false;
|
|
2006
|
-
}
|
|
2007
|
-
const maybe = value;
|
|
2008
|
-
return typeof maybe.success === "boolean" && typeof maybe.message === "string" && Array.isArray(maybe.files) && maybe.files.every((item) => typeof item === "string");
|
|
2009
|
-
}
|
|
2010
|
-
function isExportStatus(value) {
|
|
2011
|
-
return value === "in_progress" || value === "completed" || value === "failed";
|
|
2012
|
-
}
|
|
2013
|
-
function isExportSummaryRecord(value) {
|
|
2014
|
-
if (!value || typeof value !== "object") {
|
|
2015
|
-
return false;
|
|
2016
|
-
}
|
|
2017
|
-
const maybe = value;
|
|
2018
|
-
return typeof maybe.total === "number" && typeof maybe.successful === "number" && typeof maybe.failed === "number";
|
|
2019
|
-
}
|
|
2020
|
-
function isExportedComponentRecord(value) {
|
|
2021
|
-
if (!value || typeof value !== "object") {
|
|
2022
|
-
return false;
|
|
2023
|
-
}
|
|
2024
|
-
const maybe = value;
|
|
2025
|
-
return typeof maybe.componentKey === "string" && typeof maybe.enabled === "boolean" && Array.isArray(maybe.files) && maybe.files.every((item) => typeof item === "string") && typeof maybe.message === "string";
|
|
2026
|
-
}
|
|
2027
|
-
function isExportPageRecord(value) {
|
|
2028
|
-
if (!value || typeof value !== "object") {
|
|
2029
|
-
return false;
|
|
2030
|
-
}
|
|
2031
|
-
const maybe = value;
|
|
2032
|
-
const title = maybe.title;
|
|
2033
|
-
return typeof maybe.id === "string" && (typeof title === "string" || typeof title === "undefined") && typeof maybe.slug === "string" && typeof maybe.pageType === "string" && maybe.isReadyToExport === true && typeof maybe.pagePath === "string" && typeof maybe.componentsPath === "string" && isExportPageManifestRecord(maybe.manifest);
|
|
2034
|
-
}
|
|
2035
1874
|
function parseManifest(value) {
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
throw
|
|
2043
|
-
}
|
|
2044
|
-
const exportObject = exportPayload;
|
|
2045
|
-
const status = exportObject.status;
|
|
2046
|
-
const summary = exportObject.summary;
|
|
2047
|
-
const components = exportObject.components;
|
|
2048
|
-
if (typeof exportObject.id !== "string" || !isExportStatus(status) || typeof exportObject.createdAt !== "string" || !("expiresAt" in exportObject) || !(typeof exportObject.expiresAt === "string" || exportObject.expiresAt === null) || !isExportSummaryRecord(summary) || !Array.isArray(components) || !components.every(isExportedComponentRecord) || !Array.isArray(maybe.pages)) {
|
|
2049
|
-
throw new Error("Export manifest does not match expected schema.");
|
|
2050
|
-
}
|
|
2051
|
-
if (!maybe.pages.every(isExportPageRecord)) {
|
|
2052
|
-
throw new Error("Export manifest pages payload is invalid.");
|
|
1875
|
+
try {
|
|
1876
|
+
return parsePrimeUiExportManifest(value);
|
|
1877
|
+
} catch (error) {
|
|
1878
|
+
if (error instanceof Error && error.message === "Export manifest is invalid.") {
|
|
1879
|
+
throw new Error("Invalid export manifest format.");
|
|
1880
|
+
}
|
|
1881
|
+
throw error;
|
|
2053
1882
|
}
|
|
2054
|
-
return {
|
|
2055
|
-
export: {
|
|
2056
|
-
id: exportObject.id,
|
|
2057
|
-
status,
|
|
2058
|
-
createdAt: exportObject.createdAt,
|
|
2059
|
-
expiresAt: exportObject.expiresAt,
|
|
2060
|
-
summary,
|
|
2061
|
-
components
|
|
2062
|
-
},
|
|
2063
|
-
pages: maybe.pages
|
|
2064
|
-
};
|
|
2065
1883
|
}
|
|
2066
1884
|
async function resolveManifestCandidateFiles(input) {
|
|
2067
1885
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -2109,6 +1927,9 @@ async function resolveSingleExportDirectory(exportsRoot) {
|
|
|
2109
1927
|
exportPath: path9.join(exportsRoot, exportId)
|
|
2110
1928
|
};
|
|
2111
1929
|
}
|
|
1930
|
+
function createCopyId() {
|
|
1931
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1932
|
+
}
|
|
2112
1933
|
function ensureSafeTargetPath(projectRoot, targetPath) {
|
|
2113
1934
|
const relative = path9.relative(projectRoot, targetPath);
|
|
2114
1935
|
if (relative.startsWith("..") || path9.isAbsolute(relative)) {
|
|
@@ -2184,11 +2005,7 @@ function resolveTargetFilePath(input) {
|
|
|
2184
2005
|
return path9.join(projectRoot, relativeToExport);
|
|
2185
2006
|
}
|
|
2186
2007
|
async function copyPageFromExport(input) {
|
|
2187
|
-
const normalizedOriginSlug =
|
|
2188
|
-
const normalizedActualSlug = normalizeSlug2(
|
|
2189
|
-
input.actualPageSlug ?? input.originPageSlug
|
|
2190
|
-
);
|
|
2191
|
-
const isSlugRemapped = normalizedActualSlug !== normalizedOriginSlug;
|
|
2008
|
+
const normalizedOriginSlug = normalizeSlug(input.originPageSlug);
|
|
2192
2009
|
const { exportId, exportPath } = await resolveSingleExportDirectory(
|
|
2193
2010
|
input.exportsRoot
|
|
2194
2011
|
);
|
|
@@ -2208,7 +2025,7 @@ async function copyPageFromExport(input) {
|
|
|
2208
2025
|
);
|
|
2209
2026
|
}
|
|
2210
2027
|
const page = manifest.pages.find(
|
|
2211
|
-
(item) =>
|
|
2028
|
+
(item) => normalizeSlug(item.slug) === normalizedOriginSlug
|
|
2212
2029
|
);
|
|
2213
2030
|
if (!page) {
|
|
2214
2031
|
throw new Error(
|
|
@@ -2229,19 +2046,11 @@ async function copyPageFromExport(input) {
|
|
|
2229
2046
|
`Source components folder not found: ${sourceComponentsPath}`
|
|
2230
2047
|
);
|
|
2231
2048
|
}
|
|
2232
|
-
const
|
|
2233
|
-
pagePath: page.pagePath,
|
|
2234
|
-
componentsPath: page.componentsPath
|
|
2235
|
-
} : resolvePrimeUiPageExportPaths({
|
|
2236
|
-
pageType: page.pageType,
|
|
2237
|
-
slug: normalizedActualSlug
|
|
2238
|
-
});
|
|
2239
|
-
const targetPagePath = path9.join(input.projectRoot, targetPaths.pagePath);
|
|
2049
|
+
const targetPagePath = path9.join(input.projectRoot, page.pagePath);
|
|
2240
2050
|
const targetComponentsPath = path9.join(
|
|
2241
2051
|
input.projectRoot,
|
|
2242
|
-
|
|
2052
|
+
page.componentsPath
|
|
2243
2053
|
);
|
|
2244
|
-
const importRewritePlan = isSlugRemapped ? buildImportRewritePlan(page.componentsPath, targetPaths.componentsPath) : null;
|
|
2245
2054
|
ensureSafeTargetPath(input.projectRoot, targetPagePath);
|
|
2246
2055
|
ensureSafeTargetPath(input.projectRoot, targetComponentsPath);
|
|
2247
2056
|
const candidateFiles = await resolveManifestCandidateFiles({
|
|
@@ -2257,6 +2066,7 @@ async function copyPageFromExport(input) {
|
|
|
2257
2066
|
const newFiles = [];
|
|
2258
2067
|
const identicalFiles = [];
|
|
2259
2068
|
const conflictFiles = [];
|
|
2069
|
+
const conflictReportEntries = [];
|
|
2260
2070
|
for (const sourceFilePath of candidateFiles) {
|
|
2261
2071
|
const targetFilePath = resolveTargetFilePath({
|
|
2262
2072
|
sourceFilePath,
|
|
@@ -2269,11 +2079,7 @@ async function copyPageFromExport(input) {
|
|
|
2269
2079
|
});
|
|
2270
2080
|
ensureSafeTargetPath(input.projectRoot, targetFilePath);
|
|
2271
2081
|
const sourceBuffer = await readFile3(sourceFilePath);
|
|
2272
|
-
const plannedSourceBuffer =
|
|
2273
|
-
sourceBuffer,
|
|
2274
|
-
sourceFilePath,
|
|
2275
|
-
importRewritePlan
|
|
2276
|
-
);
|
|
2082
|
+
const plannedSourceBuffer = sourceBuffer;
|
|
2277
2083
|
let targetBuffer = null;
|
|
2278
2084
|
try {
|
|
2279
2085
|
targetBuffer = await readFile3(targetFilePath);
|
|
@@ -2285,17 +2091,11 @@ async function copyPageFromExport(input) {
|
|
|
2285
2091
|
if (!targetBuffer) {
|
|
2286
2092
|
await ensureDir(path9.dirname(targetFilePath));
|
|
2287
2093
|
await writeFile2(targetFilePath, plannedSourceBuffer);
|
|
2288
|
-
newFiles.push(
|
|
2289
|
-
sourcePath: sourceRelative,
|
|
2290
|
-
targetPath: targetRelative
|
|
2291
|
-
});
|
|
2094
|
+
newFiles.push(targetRelative);
|
|
2292
2095
|
continue;
|
|
2293
2096
|
}
|
|
2294
2097
|
if (plannedSourceBuffer.equals(targetBuffer)) {
|
|
2295
|
-
identicalFiles.push(
|
|
2296
|
-
sourcePath: sourceRelative,
|
|
2297
|
-
targetPath: targetRelative
|
|
2298
|
-
});
|
|
2098
|
+
identicalFiles.push(targetRelative);
|
|
2299
2099
|
continue;
|
|
2300
2100
|
}
|
|
2301
2101
|
const isBinary = isBinaryBuffer(plannedSourceBuffer) || isBinaryBuffer(targetBuffer);
|
|
@@ -2305,7 +2105,7 @@ async function copyPageFromExport(input) {
|
|
|
2305
2105
|
oldLabel: `user/${targetRelative}`,
|
|
2306
2106
|
newLabel: `export/${sourceRelative}`
|
|
2307
2107
|
});
|
|
2308
|
-
|
|
2108
|
+
conflictReportEntries.push({
|
|
2309
2109
|
sourcePath: sourceRelative,
|
|
2310
2110
|
targetPath: targetRelative,
|
|
2311
2111
|
diff,
|
|
@@ -2366,24 +2166,74 @@ async function copyPageFromExport(input) {
|
|
|
2366
2166
|
"utf-8"
|
|
2367
2167
|
);
|
|
2368
2168
|
}
|
|
2169
|
+
const sortedAddedDependencies = addedDependencies.sort(
|
|
2170
|
+
(a, b) => a.packageName.localeCompare(b.packageName)
|
|
2171
|
+
);
|
|
2172
|
+
const sortedDependenciesVersionConflicts = dependenciesVersionConflicts.sort(
|
|
2173
|
+
(a, b) => a.packageName.localeCompare(b.packageName)
|
|
2174
|
+
);
|
|
2175
|
+
const sortedConflictReportEntries = conflictReportEntries.sort(
|
|
2176
|
+
(a, b) => a.targetPath.localeCompare(b.targetPath)
|
|
2177
|
+
);
|
|
2178
|
+
for (const entry of sortedConflictReportEntries) {
|
|
2179
|
+
conflictFiles.push({
|
|
2180
|
+
targetPath: entry.targetPath,
|
|
2181
|
+
isBinary: entry.isBinary
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
const copyId = createCopyId();
|
|
2185
|
+
const reportPath = path9.join(
|
|
2186
|
+
input.exportsRoot,
|
|
2187
|
+
`${exportId}.copy-report-${copyId}.json`
|
|
2188
|
+
);
|
|
2189
|
+
const report = {
|
|
2190
|
+
reportPath,
|
|
2191
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2192
|
+
exportId,
|
|
2193
|
+
originPageSlug: normalizedOriginSlug,
|
|
2194
|
+
sourcePagePath: page.pagePath,
|
|
2195
|
+
sourceComponentsPath: page.componentsPath,
|
|
2196
|
+
conflicts: sortedConflictReportEntries
|
|
2197
|
+
};
|
|
2198
|
+
await writeFile2(reportPath, `${JSON.stringify(report, null, 2)}
|
|
2199
|
+
`, "utf-8");
|
|
2200
|
+
const hasFileConflicts = conflictFiles.length > 0;
|
|
2201
|
+
const hasDependencyVersionConflicts = sortedDependenciesVersionConflicts.length > 0;
|
|
2202
|
+
const needsReview = hasFileConflicts || hasDependencyVersionConflicts;
|
|
2203
|
+
const status = needsReview ? "needs_review" : "completed";
|
|
2204
|
+
const messageParts = [];
|
|
2205
|
+
if (hasFileConflicts) {
|
|
2206
|
+
messageParts.push(
|
|
2207
|
+
`Conflicts detected. Manual resolution is required before any follow-up integration steps. Review ${reportPath} for full diffs and resolve conflicts based on the target project behavior, the imported page functionality, and the possibility that MCP may run against third-party projects not generated by PrimeUI.`
|
|
2208
|
+
);
|
|
2209
|
+
} else if (hasDependencyVersionConflicts) {
|
|
2210
|
+
messageParts.push(
|
|
2211
|
+
`Dependency version conflicts detected. Manual resolution is required before any follow-up integration steps. Review ${reportPath} for full local report details, inspect dependenciesVersionConflicts in this response, and resolve versions based on the target project behavior and the imported page functionality.`
|
|
2212
|
+
);
|
|
2213
|
+
} else {
|
|
2214
|
+
messageParts.push(
|
|
2215
|
+
`Copy completed with no file conflicts or dependency version conflicts. Review ${reportPath} for full local details if needed.`
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
if (sortedAddedDependencies.length > 0) {
|
|
2219
|
+
messageParts.push(
|
|
2220
|
+
"Missing dependencies were added to package.json but are NOT installed yet. Run dependency installation manually with the package manager used by the target project."
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2369
2223
|
return {
|
|
2224
|
+
status,
|
|
2225
|
+
message: messageParts.join(" "),
|
|
2226
|
+
reportPath,
|
|
2370
2227
|
exportId,
|
|
2371
2228
|
exportPath,
|
|
2372
2229
|
originPageSlug: normalizedOriginSlug,
|
|
2373
|
-
actualPageSlug: normalizedActualSlug,
|
|
2374
2230
|
sourcePagePath: page.pagePath,
|
|
2375
|
-
targetPagePath: targetPaths.pagePath,
|
|
2376
2231
|
sourceComponentsPath: page.componentsPath,
|
|
2377
|
-
targetComponentsPath: targetPaths.componentsPath,
|
|
2378
2232
|
newFiles,
|
|
2379
2233
|
identicalFiles,
|
|
2380
2234
|
conflictFiles,
|
|
2381
|
-
addedDependencies:
|
|
2382
|
-
|
|
2383
|
-
),
|
|
2384
|
-
dependenciesVersionConflicts: dependenciesVersionConflicts.sort(
|
|
2385
|
-
(a, b) => a.packageName.localeCompare(b.packageName)
|
|
2386
|
-
),
|
|
2235
|
+
addedDependencies: sortedAddedDependencies,
|
|
2236
|
+
dependenciesVersionConflicts: sortedDependenciesVersionConflicts,
|
|
2387
2237
|
summary: {
|
|
2388
2238
|
totalCandidateFiles: candidateFiles.length,
|
|
2389
2239
|
copiedFiles: newFiles.length,
|
|
@@ -2486,72 +2336,9 @@ function buildInspectPageReport(input) {
|
|
|
2486
2336
|
}
|
|
2487
2337
|
|
|
2488
2338
|
// src/services/project-sync-service.ts
|
|
2489
|
-
function isExportStatus2(value) {
|
|
2490
|
-
return value === "in_progress" || value === "completed" || value === "failed";
|
|
2491
|
-
}
|
|
2492
|
-
function isExportSummary(value) {
|
|
2493
|
-
if (!value || typeof value !== "object") {
|
|
2494
|
-
return false;
|
|
2495
|
-
}
|
|
2496
|
-
const maybe = value;
|
|
2497
|
-
return typeof maybe.total === "number" && typeof maybe.successful === "number" && typeof maybe.failed === "number";
|
|
2498
|
-
}
|
|
2499
|
-
function isExportedComponent(value) {
|
|
2500
|
-
if (!value || typeof value !== "object") {
|
|
2501
|
-
return false;
|
|
2502
|
-
}
|
|
2503
|
-
const maybe = value;
|
|
2504
|
-
return typeof maybe.componentKey === "string" && typeof maybe.enabled === "boolean" && Array.isArray(maybe.files) && maybe.files.every((item) => typeof item === "string") && typeof maybe.message === "string";
|
|
2505
|
-
}
|
|
2506
|
-
function isExportPageManifest(value) {
|
|
2507
|
-
if (!value || typeof value !== "object") {
|
|
2508
|
-
return false;
|
|
2509
|
-
}
|
|
2510
|
-
const maybe = value;
|
|
2511
|
-
return typeof maybe.success === "boolean" && typeof maybe.message === "string" && Array.isArray(maybe.files) && maybe.files.every((item) => typeof item === "string");
|
|
2512
|
-
}
|
|
2513
|
-
function isExportPage(value) {
|
|
2514
|
-
if (!value || typeof value !== "object") {
|
|
2515
|
-
return false;
|
|
2516
|
-
}
|
|
2517
|
-
const maybe = value;
|
|
2518
|
-
const title = maybe.title;
|
|
2519
|
-
return typeof maybe.id === "string" && (typeof title === "string" || typeof title === "undefined") && typeof maybe.slug === "string" && typeof maybe.pageType === "string" && maybe.isReadyToExport === true && typeof maybe.pagePath === "string" && typeof maybe.componentsPath === "string" && isExportPageManifest(maybe.manifest);
|
|
2520
|
-
}
|
|
2521
2339
|
function buildManifestPath(exportsRoot, exportId) {
|
|
2522
2340
|
return path10.join(exportsRoot, `${exportId}.manifest.json`);
|
|
2523
2341
|
}
|
|
2524
|
-
function parseExportManifest(value) {
|
|
2525
|
-
if (!value || typeof value !== "object") {
|
|
2526
|
-
throw new Error("Export manifest is invalid.");
|
|
2527
|
-
}
|
|
2528
|
-
const maybe = value;
|
|
2529
|
-
const exportPayload = maybe.export;
|
|
2530
|
-
if (!exportPayload || typeof exportPayload !== "object") {
|
|
2531
|
-
throw new Error("Export manifest export payload is invalid.");
|
|
2532
|
-
}
|
|
2533
|
-
const exportObject = exportPayload;
|
|
2534
|
-
const status = exportObject.status;
|
|
2535
|
-
const summary = exportObject.summary;
|
|
2536
|
-
const components = exportObject.components;
|
|
2537
|
-
if (typeof exportObject.id !== "string" || !isExportStatus2(status) || typeof exportObject.createdAt !== "string" || !("expiresAt" in exportObject) || !(typeof exportObject.expiresAt === "string" || exportObject.expiresAt === null) || !isExportSummary(summary) || !Array.isArray(components) || !components.every(isExportedComponent) || !Array.isArray(maybe.pages)) {
|
|
2538
|
-
throw new Error("Export manifest does not match expected schema.");
|
|
2539
|
-
}
|
|
2540
|
-
if (!maybe.pages.every(isExportPage)) {
|
|
2541
|
-
throw new Error("Export manifest pages payload is invalid.");
|
|
2542
|
-
}
|
|
2543
|
-
return {
|
|
2544
|
-
export: {
|
|
2545
|
-
id: exportObject.id,
|
|
2546
|
-
status,
|
|
2547
|
-
createdAt: exportObject.createdAt,
|
|
2548
|
-
expiresAt: exportObject.expiresAt,
|
|
2549
|
-
summary,
|
|
2550
|
-
components
|
|
2551
|
-
},
|
|
2552
|
-
pages: maybe.pages
|
|
2553
|
-
};
|
|
2554
|
-
}
|
|
2555
2342
|
var ProjectSyncService = class {
|
|
2556
2343
|
provider;
|
|
2557
2344
|
projectRoot;
|
|
@@ -2595,7 +2382,7 @@ var ProjectSyncService = class {
|
|
|
2595
2382
|
const manifestPath = buildManifestPath(this.exportsRoot, id);
|
|
2596
2383
|
let manifest;
|
|
2597
2384
|
try {
|
|
2598
|
-
manifest =
|
|
2385
|
+
manifest = parsePrimeUiExportManifest(
|
|
2599
2386
|
JSON.parse(await readFile4(manifestPath, "utf-8"))
|
|
2600
2387
|
);
|
|
2601
2388
|
} catch (error) {
|
|
@@ -2613,12 +2400,10 @@ var ProjectSyncService = class {
|
|
|
2613
2400
|
await this.provider.downloadExportArchive(id, targetZipPath);
|
|
2614
2401
|
await resetDir(targetProjectPath);
|
|
2615
2402
|
await extractZip(targetZipPath, targetProjectPath);
|
|
2616
|
-
const pages = manifest.pages;
|
|
2617
2403
|
return {
|
|
2618
2404
|
exportId: id,
|
|
2619
2405
|
projectPath: targetProjectPath,
|
|
2620
|
-
manifestPath
|
|
2621
|
-
pages
|
|
2406
|
+
manifestPath
|
|
2622
2407
|
};
|
|
2623
2408
|
}
|
|
2624
2409
|
async inspectPage(slug, _context) {
|
|
@@ -2631,13 +2416,12 @@ var ProjectSyncService = class {
|
|
|
2631
2416
|
reportRows: reportPayload.reportRows
|
|
2632
2417
|
};
|
|
2633
2418
|
}
|
|
2634
|
-
async copyPage(originPageSlug,
|
|
2419
|
+
async copyPage(originPageSlug, _context) {
|
|
2635
2420
|
await this.ensureTempLayout();
|
|
2636
2421
|
return copyPageFromExport({
|
|
2637
2422
|
projectRoot: this.targetProjectRoot,
|
|
2638
2423
|
exportsRoot: this.exportsRoot,
|
|
2639
|
-
originPageSlug
|
|
2640
|
-
actualPageSlug
|
|
2424
|
+
originPageSlug
|
|
2641
2425
|
});
|
|
2642
2426
|
}
|
|
2643
2427
|
async clearTemp(_context) {
|
|
@@ -2727,10 +2511,10 @@ var LazyProjectSyncSource = class {
|
|
|
2727
2511
|
(service) => service.inspectPage(slug, context)
|
|
2728
2512
|
);
|
|
2729
2513
|
}
|
|
2730
|
-
async copyPage(originPageSlug,
|
|
2514
|
+
async copyPage(originPageSlug, context) {
|
|
2731
2515
|
return this.withMutationService(
|
|
2732
2516
|
context,
|
|
2733
|
-
(service) => service.copyPage(originPageSlug,
|
|
2517
|
+
(service) => service.copyPage(originPageSlug, context)
|
|
2734
2518
|
);
|
|
2735
2519
|
}
|
|
2736
2520
|
async clearTemp(context) {
|
|
@@ -2771,35 +2555,48 @@ var pageSchema = z4.object({
|
|
|
2771
2555
|
}).describe(
|
|
2772
2556
|
"PrimeUI page descriptor used by project and export tools. Paths are always relative to export project root."
|
|
2773
2557
|
);
|
|
2774
|
-
var
|
|
2558
|
+
var exportStatusSchema = z4.enum(["in_progress", "completed", "failed"]).describe(
|
|
2775
2559
|
"Export lifecycle state. Use 'completed' before calling download_export."
|
|
2776
2560
|
);
|
|
2777
2561
|
var exportItemSchema = z4.object({
|
|
2778
2562
|
id: z4.string().describe(
|
|
2779
2563
|
"Export identifier. Pass this value to download_export input.id."
|
|
2780
2564
|
),
|
|
2781
|
-
status:
|
|
2565
|
+
status: exportStatusSchema,
|
|
2782
2566
|
createdAt: z4.string().describe("Export creation timestamp in ISO-8601 UTC format.")
|
|
2783
2567
|
}).describe("Single export record from PrimeUI export history.");
|
|
2784
|
-
var
|
|
2568
|
+
var exportSummarySchema = z4.object({
|
|
2785
2569
|
total: z4.number().describe("Total pages processed in this export run."),
|
|
2786
2570
|
successful: z4.number().describe("Number of pages exported successfully."),
|
|
2787
2571
|
failed: z4.number().describe("Number of pages that failed export.")
|
|
2788
2572
|
});
|
|
2789
|
-
var
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
files: z4.array(z4.string()).describe("
|
|
2793
|
-
message: z4.string().describe("Export status message for this global component.")
|
|
2573
|
+
var exportManifestSchema = z4.object({
|
|
2574
|
+
success: z4.boolean().describe("True when export processing succeeded for this item."),
|
|
2575
|
+
message: z4.string().describe("Export status message for this item."),
|
|
2576
|
+
files: z4.array(z4.string()).describe("Authoritative exported file list for this item.")
|
|
2794
2577
|
});
|
|
2795
|
-
var
|
|
2796
|
-
|
|
2797
|
-
|
|
2578
|
+
var exportableSchema = z4.object({
|
|
2579
|
+
key: z4.string().describe("Shared exportable key from export manifest."),
|
|
2580
|
+
isReadyToExport: z4.boolean().describe("True when this shared exportable was eligible for export."),
|
|
2581
|
+
manifest: exportManifestSchema.describe(
|
|
2582
|
+
"Export manifest for this shared exportable, aligned with page manifest shape."
|
|
2583
|
+
)
|
|
2584
|
+
});
|
|
2585
|
+
var projectExportableSchema = z4.object({
|
|
2586
|
+
key: z4.string().describe("Stable shared exportable key from PrimeUI project info."),
|
|
2587
|
+
description: z4.string().describe(
|
|
2588
|
+
"Agent-oriented summary of what this shared exportable provides."
|
|
2589
|
+
),
|
|
2590
|
+
isReadyToExport: z4.boolean().describe(
|
|
2591
|
+
"Best-effort readiness snapshot for whether this shared exportable can be included in export now."
|
|
2592
|
+
)
|
|
2593
|
+
});
|
|
2594
|
+
var exportPageManifestSchema = exportManifestSchema.extend({
|
|
2798
2595
|
files: z4.array(z4.string()).describe(
|
|
2799
2596
|
"Authoritative list of page-related files from PrimeUI export manifest, including shared project files required by this page."
|
|
2800
2597
|
)
|
|
2801
2598
|
});
|
|
2802
|
-
var
|
|
2599
|
+
var exportPageSchema = z4.object({
|
|
2803
2600
|
id: z4.string().describe("Stable PrimeUI page identifier for this export entry."),
|
|
2804
2601
|
title: z4.string().optional().describe(
|
|
2805
2602
|
"Optional page title from export manifest. Can be undefined for some legacy records."
|
|
@@ -2809,17 +2606,7 @@ var exportPageSchema2 = z4.object({
|
|
|
2809
2606
|
isReadyToExport: z4.literal(true).describe("Always true for pages included in export payload."),
|
|
2810
2607
|
pagePath: z4.string().describe("Page source file path relative to export root."),
|
|
2811
2608
|
componentsPath: z4.string().describe("Page components directory path relative to export root."),
|
|
2812
|
-
manifest:
|
|
2813
|
-
});
|
|
2814
|
-
var fileTransferSchema = z4.object({
|
|
2815
|
-
sourcePath: z4.string().describe("Relative source file path inside downloaded export root."),
|
|
2816
|
-
targetPath: z4.string().describe("Relative target file path inside user project root.")
|
|
2817
|
-
});
|
|
2818
|
-
var conflictFileSchema = fileTransferSchema.extend({
|
|
2819
|
-
diff: z4.string().describe(
|
|
2820
|
-
"Unified diff between user file and export file. For binary files the diff contains a plain message."
|
|
2821
|
-
),
|
|
2822
|
-
isBinary: z4.boolean().describe("True if conflict comparison was treated as binary data.")
|
|
2609
|
+
manifest: exportPageManifestSchema
|
|
2823
2610
|
});
|
|
2824
2611
|
var dependencySectionSchema = z4.enum([
|
|
2825
2612
|
"dependencies",
|
|
@@ -2841,6 +2628,10 @@ var dependencyVersionConflictSchema = z4.object({
|
|
|
2841
2628
|
exportVersion: z4.string().describe("Version found in exported project's package.json."),
|
|
2842
2629
|
userVersion: z4.string().describe("Version currently present in user's package.json.")
|
|
2843
2630
|
});
|
|
2631
|
+
var conflictFileSchema = z4.object({
|
|
2632
|
+
targetPath: z4.string().describe("Relative conflict target path inside user project root."),
|
|
2633
|
+
isBinary: z4.boolean().describe("True if conflict comparison was treated as binary data.")
|
|
2634
|
+
});
|
|
2844
2635
|
var pageDetailsSchema = pageSchema.extend({
|
|
2845
2636
|
pageInstruction: z4.string().nullable().describe(
|
|
2846
2637
|
"Current instruction text for the active page variant. Null when no active variant is set."
|
|
@@ -2889,7 +2680,7 @@ WORKFLOW ORDER (always follow this sequence):
|
|
|
2889
2680
|
2. get_project_info -> discover PrimeUI pages
|
|
2890
2681
|
3. Reconcile PrimeUI pages with local project pages/routes/paths, then confirm target pages with user
|
|
2891
2682
|
4. inspect_page -> inspect selected page components and produce a structured comparison table
|
|
2892
|
-
5. create_export -> generate export snapshot and local manifest with page file lists +
|
|
2683
|
+
5. create_export -> generate export snapshot and local manifest with page file lists + shared exportables
|
|
2893
2684
|
6. download_export -> download to temp directory
|
|
2894
2685
|
7. copy_page -> copy one page safely (repeat for each selected page)
|
|
2895
2686
|
8. Reconcile integration points and resolve reported conflicts, if any
|
|
@@ -2917,7 +2708,7 @@ CRITICAL RULES FOR PAGE IMPORT:
|
|
|
2917
2708
|
- Before creating export, ask user which pages to add/update (specific pages or all missing pages) and keep that choice in thread context.
|
|
2918
2709
|
- create_export response includes:
|
|
2919
2710
|
- page-level manifest files per page ('pages[].manifest.files'),
|
|
2920
|
-
-
|
|
2711
|
+
- shared exportables list ('export.exportables').
|
|
2921
2712
|
Mention both to user after create_export, because this is the source of truth for copy decisions.
|
|
2922
2713
|
- The downloaded export in .primeui/temp/ contains a full standalone Next.js project.
|
|
2923
2714
|
Do NOT copy it wholesale.
|
|
@@ -2935,7 +2726,7 @@ CRITICAL RULES FOR PAGE IMPORT:
|
|
|
2935
2726
|
`.trim();
|
|
2936
2727
|
var toolGetProjectInfo = {
|
|
2937
2728
|
title: "PrimeUI Project Info",
|
|
2938
|
-
description: `ENTRY POINT for all PrimeUI import operations. Always start here. Returns project metadata
|
|
2729
|
+
description: `ENTRY POINT for all PrimeUI import operations. Always start here. Returns project metadata plus a lightweight inventory of pages and shared exportables you can reason about before export.
|
|
2939
2730
|
|
|
2940
2731
|
WHEN TO USE: Call this FIRST when user wants to import, add, sync, pull, or transfer a page from PrimeUI. Intent examples (semantic intent, not exact phrase matching): ${TRIGGER_PHRASES}.
|
|
2941
2732
|
|
|
@@ -2964,6 +2755,9 @@ ${WORKFLOW_SUMMARY}`,
|
|
|
2964
2755
|
metadata: z4.record(z4.unknown()).describe(
|
|
2965
2756
|
"Additional project metadata from PrimeUI. May include project-description and other context fields."
|
|
2966
2757
|
),
|
|
2758
|
+
exportables: z4.array(projectExportableSchema).describe(
|
|
2759
|
+
"Lightweight inventory of shared exportables (for example logo, cookie banner, announcement banner, theme, image assets). Use description + isReadyToExport to plan imports before create_export."
|
|
2760
|
+
),
|
|
2967
2761
|
pages: z4.array(pageSchema).describe(
|
|
2968
2762
|
"All pages visible for this project context. Filter by user request and isReadyToExport before creating export."
|
|
2969
2763
|
)
|
|
@@ -3050,7 +2844,7 @@ ${WORKFLOW_SUMMARY}`,
|
|
|
3050
2844
|
};
|
|
3051
2845
|
var toolCreateExport = {
|
|
3052
2846
|
title: "PrimeUI Create Export",
|
|
3053
|
-
description: `Create a new export snapshot from the current PrimeUI project state and wait for completion. Returns strict export manifest payload from API, including page-level file manifests and
|
|
2847
|
+
description: `Create a new export snapshot from the current PrimeUI project state and wait for completion. Returns strict export manifest payload from API, including page-level file manifests and shared exportables.
|
|
3054
2848
|
|
|
3055
2849
|
WHEN TO USE: Call this AFTER the user has confirmed which pages they want to import via get_project_info. This tool is REQUIRED before download_export, unless the user explicitly and directly asked to download a specific previous export.
|
|
3056
2850
|
|
|
@@ -3058,7 +2852,7 @@ AFTER CALLING:
|
|
|
3058
2852
|
- Verify that all user-selected pages are present in the export result AND have isReadyToExport: true.
|
|
3059
2853
|
- If path mismatch pages were flagged during project-info reconciliation, ensure they are included for deeper comparison after download.
|
|
3060
2854
|
- If any required page is missing or not ready, report and pause for user decision before proceeding.
|
|
3061
|
-
- Mention that
|
|
2855
|
+
- Mention that shared exportables are available in export.exportables and can be transferred separately if needed.
|
|
3062
2856
|
- Local sidecar manifest is saved to .primeui/temp/exports/[exportId].manifest.json from this API payload.
|
|
3063
2857
|
- Use the returned export ID to call download_export.
|
|
3064
2858
|
|
|
@@ -3069,19 +2863,19 @@ ${WORKFLOW_SUMMARY}`,
|
|
|
3069
2863
|
id: z4.string().describe(
|
|
3070
2864
|
"Freshly created export identifier. Use this as download_export input.id."
|
|
3071
2865
|
),
|
|
3072
|
-
status:
|
|
2866
|
+
status: exportStatusSchema,
|
|
3073
2867
|
createdAt: z4.string().describe("Export creation timestamp in ISO-8601 UTC format."),
|
|
3074
2868
|
expiresAt: z4.string().nullable().describe(
|
|
3075
2869
|
"Export expiration timestamp in ISO-8601 UTC format, or null when export has no explicit expiration."
|
|
3076
2870
|
),
|
|
3077
|
-
summary:
|
|
2871
|
+
summary: exportSummarySchema.describe(
|
|
3078
2872
|
"Export run summary with total/successful/failed counters."
|
|
3079
2873
|
),
|
|
3080
|
-
|
|
3081
|
-
"
|
|
2874
|
+
exportables: z4.array(exportableSchema).describe(
|
|
2875
|
+
"Shared exportable manifest. These entries are independent from page-level manifests."
|
|
3082
2876
|
)
|
|
3083
2877
|
}).describe("Created export summary."),
|
|
3084
|
-
pages: z4.array(
|
|
2878
|
+
pages: z4.array(exportPageSchema).describe(
|
|
3085
2879
|
"Strict page payload associated with this export, including per-page manifest files list."
|
|
3086
2880
|
)
|
|
3087
2881
|
}),
|
|
@@ -3107,9 +2901,8 @@ NOTE:
|
|
|
3107
2901
|
AFTER DOWNLOAD:
|
|
3108
2902
|
- Use manifestPath from this response as the contract for page slug/path mapping and manifest file lists in copy operations.
|
|
3109
2903
|
- For each selected page, call copy_page with:
|
|
3110
|
-
- originPageSlug (required)
|
|
3111
|
-
|
|
3112
|
-
- If there are unresolved conflicts in copy report, stop and ask the user.
|
|
2904
|
+
- originPageSlug (required).
|
|
2905
|
+
- Treat conflicts as normal and expected. If copy_page returns needs_review, stop follow-up integration and resolve manually first.
|
|
3113
2906
|
- Do not force cleanup at flow end; keep downloaded export files available for validation and follow-up checks.
|
|
3114
2907
|
|
|
3115
2908
|
${WORKFLOW_SUMMARY}`,
|
|
@@ -3128,9 +2921,6 @@ AFTER DOWNLOAD:
|
|
|
3128
2921
|
),
|
|
3129
2922
|
manifestPath: z4.string().describe(
|
|
3130
2923
|
"Absolute path to sidecar export manifest file (.primeui/temp/exports/[exportId].manifest.json) saved by create_export and required by copy_page."
|
|
3131
|
-
),
|
|
3132
|
-
pages: z4.array(exportPageSchema2).describe(
|
|
3133
|
-
"Page descriptors loaded from local sidecar export manifest for import decisions."
|
|
3134
2924
|
)
|
|
3135
2925
|
}),
|
|
3136
2926
|
annotations: {
|
|
@@ -3147,46 +2937,46 @@ var toolCopyPage = {
|
|
|
3147
2937
|
WHEN TO USE:
|
|
3148
2938
|
- Call this AFTER download_export.
|
|
3149
2939
|
- Call once per selected page.
|
|
3150
|
-
- Use actualPageSlug only when user wants to remap route during import.
|
|
3151
2940
|
|
|
3152
2941
|
BEHAVIOR:
|
|
3153
2942
|
- Reads export sidecar manifest to resolve originPageSlug -> pagePath/componentsPath.
|
|
3154
2943
|
- Copies and validates files strictly from pages[].manifest.files for the selected page.
|
|
3155
2944
|
- Never overwrites existing conflicting files.
|
|
2945
|
+
- Writes full conflict diffs to a local report file in .primeui/temp/exports/[exportId].copy-report-[copyId].json.
|
|
3156
2946
|
- Reports:
|
|
3157
|
-
a) copied new files,
|
|
3158
|
-
b) identical existing files,
|
|
3159
|
-
c) conflicting files
|
|
2947
|
+
a) copied new files (relative target paths),
|
|
2948
|
+
b) identical existing files (relative target paths),
|
|
2949
|
+
c) conflicting files as lightweight metadata (relative target paths + binary flag, no inline diff),
|
|
3160
2950
|
d) missing dependencies added to package.json,
|
|
3161
2951
|
e) dependency version conflicts (report-only, no auto upgrade).
|
|
3162
2952
|
- Adds only missing dependencies to package.json (dependencies/devDependencies/peerDependencies).
|
|
3163
2953
|
- Never updates existing dependency versions and never runs install commands.
|
|
2954
|
+
- If status is needs_review, page import is NOT complete and manual review is required before continuing. This can be caused by file conflicts or dependency version conflicts.
|
|
3164
2955
|
|
|
3165
2956
|
${WORKFLOW_SUMMARY}`,
|
|
3166
2957
|
inputSchema: {
|
|
3167
2958
|
projectRoot: projectRootInputSchema,
|
|
3168
2959
|
originPageSlug: z4.string().describe(
|
|
3169
2960
|
"Source page slug from PrimeUI project pages list, for example '/', '/pricing', '/docs'."
|
|
3170
|
-
),
|
|
3171
|
-
actualPageSlug: z4.string().optional().describe(
|
|
3172
|
-
"Optional destination slug in user's project. If omitted, originPageSlug is used."
|
|
3173
2961
|
)
|
|
3174
2962
|
},
|
|
3175
2963
|
outputSchema: z4.object({
|
|
2964
|
+
status: z4.enum(["completed", "needs_review"]).describe(
|
|
2965
|
+
"Decision state for next step. needs_review means manual review is required before follow-up integration because of file conflicts or dependency version conflicts."
|
|
2966
|
+
),
|
|
2967
|
+
message: z4.string().describe(
|
|
2968
|
+
"Decision-oriented summary that includes resolved reportPath and manual follow-up instructions when needed."
|
|
2969
|
+
),
|
|
2970
|
+
reportPath: z4.string().describe(
|
|
2971
|
+
"Absolute path to saved local report with full conflict diffs and details."
|
|
2972
|
+
),
|
|
3176
2973
|
exportId: z4.string().describe("Resolved local export identifier used for copy operation."),
|
|
3177
2974
|
exportPath: z4.string().describe("Absolute path to local extracted export project root."),
|
|
3178
2975
|
originPageSlug: z4.string().describe("Normalized source page slug requested for copy."),
|
|
3179
|
-
actualPageSlug: z4.string().describe("Normalized destination slug used for target route paths."),
|
|
3180
2976
|
sourcePagePath: z4.string().describe("Source page path relative to export root."),
|
|
3181
|
-
targetPagePath: z4.string().describe("Destination page path relative to user project root."),
|
|
3182
2977
|
sourceComponentsPath: z4.string().describe("Source components directory relative to export root."),
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
),
|
|
3186
|
-
newFiles: z4.array(fileTransferSchema).describe("New files copied into user project without conflicts."),
|
|
3187
|
-
identicalFiles: z4.array(fileTransferSchema).describe(
|
|
3188
|
-
"Existing files in user project that are byte-identical to export files."
|
|
3189
|
-
),
|
|
2978
|
+
newFiles: z4.array(z4.string()).describe("Relative target paths for new files copied into user project."),
|
|
2979
|
+
identicalFiles: z4.array(z4.string()).describe("Relative target paths for existing byte-identical files."),
|
|
3190
2980
|
conflictFiles: z4.array(conflictFileSchema).describe(
|
|
3191
2981
|
"Files that already exist and differ from export version. Never overwritten."
|
|
3192
2982
|
),
|
|
@@ -3399,13 +3189,11 @@ function createPrimeUiMcpServer(source) {
|
|
|
3399
3189
|
toolCopyPage,
|
|
3400
3190
|
async ({
|
|
3401
3191
|
originPageSlug,
|
|
3402
|
-
actualPageSlug,
|
|
3403
3192
|
projectRoot
|
|
3404
3193
|
}) => {
|
|
3405
3194
|
try {
|
|
3406
3195
|
const result = await source.copyPage(
|
|
3407
3196
|
originPageSlug,
|
|
3408
|
-
actualPageSlug,
|
|
3409
3197
|
{ projectRoot }
|
|
3410
3198
|
);
|
|
3411
3199
|
return okResult("copy_page", result);
|