@primeuicom/mcp 0.1.17 → 0.1.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.
- package/dist/service.js +311 -51
- package/dist/service.js.map +1 -1
- package/package.json +1 -1
package/dist/service.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/service.ts
|
|
4
|
-
import
|
|
4
|
+
import path8 from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
7
|
|
|
@@ -86,6 +86,9 @@ function toUniqueResolvedDirs(directories) {
|
|
|
86
86
|
}
|
|
87
87
|
return [...resolved];
|
|
88
88
|
}
|
|
89
|
+
function buildPrimeUiProjectSearchRoots(options) {
|
|
90
|
+
return toUniqueResolvedDirs([options.cwd, ...options.fallbackCwds ?? []]);
|
|
91
|
+
}
|
|
89
92
|
async function resolvePrimeUiProjectConfig(options) {
|
|
90
93
|
const envProjectRoot = options.projectRootFromEnv?.trim();
|
|
91
94
|
let projectConfigPath;
|
|
@@ -95,10 +98,10 @@ async function resolvePrimeUiProjectConfig(options) {
|
|
|
95
98
|
PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH
|
|
96
99
|
);
|
|
97
100
|
} else {
|
|
98
|
-
const searchRoots =
|
|
99
|
-
options.cwd,
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
const searchRoots = buildPrimeUiProjectSearchRoots({
|
|
102
|
+
cwd: options.cwd,
|
|
103
|
+
fallbackCwds: options.fallbackCwds
|
|
104
|
+
});
|
|
102
105
|
for (const searchRoot of searchRoots) {
|
|
103
106
|
const foundProjectConfigPath = await findPrimeUiProjectConfigPath(searchRoot);
|
|
104
107
|
if (foundProjectConfigPath) {
|
|
@@ -265,6 +268,33 @@ var inspectPageReportRowSchema = z2.object({
|
|
|
265
268
|
title: z2.string().nullable().describe("Title extracted by MCP from component props."),
|
|
266
269
|
description: z2.string().nullable().describe("Description extracted by MCP from component props.")
|
|
267
270
|
});
|
|
271
|
+
var healthOptionSchema = z2.object({
|
|
272
|
+
key: z2.string().describe("Environment variable or diagnostic option name."),
|
|
273
|
+
description: z2.string().describe("Human-readable explanation of what this option controls."),
|
|
274
|
+
currentValue: z2.string().nullable().describe(
|
|
275
|
+
"Current effective value for this option. Null when not set or intentionally hidden."
|
|
276
|
+
)
|
|
277
|
+
});
|
|
278
|
+
var healthRuntimeSchema = z2.object({
|
|
279
|
+
cwd: z2.string().describe("process.cwd() observed by the MCP server process."),
|
|
280
|
+
initCwd: z2.string().nullable().describe("INIT_CWD environment value, if provided by the client runtime."),
|
|
281
|
+
pwd: z2.string().nullable().describe("PWD environment value, if provided by the client runtime."),
|
|
282
|
+
searchRoots: z2.array(z2.string()).describe(
|
|
283
|
+
"Resolved directories used when searching for .primeui/project.json."
|
|
284
|
+
),
|
|
285
|
+
rootsListFallbackCwds: z2.array(z2.string()).describe(
|
|
286
|
+
"File-system roots derived from MCP roots/list and used as search fallbacks."
|
|
287
|
+
)
|
|
288
|
+
});
|
|
289
|
+
var healthConfigSchema = z2.object({
|
|
290
|
+
found: z2.boolean().describe("True when .primeui/project.json was found and parsed successfully."),
|
|
291
|
+
projectRoot: z2.string().nullable().describe("Resolved PrimeUI project root directory (parent of .primeui)."),
|
|
292
|
+
projectConfigPath: z2.string().nullable().describe("Absolute path to .primeui/project.json when found."),
|
|
293
|
+
targetProjectPath: z2.string().nullable().describe("targetProjectPath value loaded from project config."),
|
|
294
|
+
targetProjectRoot: z2.string().nullable().describe("Absolute target project root derived from targetProjectPath."),
|
|
295
|
+
source: z2.enum(["env.PRIMEUI_PROJECT_ROOT", "search"]).describe("How project config lookup was resolved."),
|
|
296
|
+
error: z2.string().nullable().describe("Human-readable resolution error when config is not available.")
|
|
297
|
+
});
|
|
268
298
|
var TRIGGER_PHRASES = [
|
|
269
299
|
"import page from PrimeUI",
|
|
270
300
|
"add page from PrimeUI",
|
|
@@ -295,6 +325,7 @@ ${WORKFLOW_SUMMARY}
|
|
|
295
325
|
|
|
296
326
|
CRITICAL RULES FOR PAGE IMPORT:
|
|
297
327
|
- Import is PAGE-BY-PAGE only. Never import the entire project at once.
|
|
328
|
+
- Use health_check to inspect runtime path/config resolution when setup issues occur.
|
|
298
329
|
- Always call clear_temp at the very beginning of a new import flow to avoid stale export state.
|
|
299
330
|
- After get_project_info, always compare PrimeUI pages against the user's existing local project pages before proposing imports.
|
|
300
331
|
- Reconciliation report MUST include: page presence match, slug/pagePath/componentsPath path match, and proposed action per page.
|
|
@@ -325,6 +356,34 @@ CRITICAL RULES FOR PAGE IMPORT:
|
|
|
325
356
|
- If integration pattern is obvious, apply it and explicitly mark it in the report with "\u26A0 integration update".
|
|
326
357
|
- If integration pattern is unclear, ask the user before editing integration files.
|
|
327
358
|
`.trim();
|
|
359
|
+
var toolHealthCheck = {
|
|
360
|
+
title: "PrimeUI Health Check",
|
|
361
|
+
description: `Diagnostic tool for MCP runtime setup. This tool MUST NOT fail: it always returns structured diagnostics even when project config is missing.
|
|
362
|
+
|
|
363
|
+
WHEN TO USE:
|
|
364
|
+
- Use this first when PrimeUI MCP tools fail due to project path/config issues.
|
|
365
|
+
- Use this to verify cwd/env/roots behavior in different MCP clients (Codex, Claude Code, Inspector).
|
|
366
|
+
|
|
367
|
+
RETURNS:
|
|
368
|
+
- Runtime paths (cwd, INIT_CWD, PWD, search roots),
|
|
369
|
+
- roots/list fallback paths from client (if available),
|
|
370
|
+
- Whether .primeui/project.json was found and parsed,
|
|
371
|
+
- Effective resolved project root/config path (when available),
|
|
372
|
+
- Current option values and fallback guidance.`,
|
|
373
|
+
inputSchema: {},
|
|
374
|
+
outputSchema: {
|
|
375
|
+
status: z2.enum(["ok", "degraded"]).describe("Overall setup health. 'degraded' means config is unresolved."),
|
|
376
|
+
runtime: healthRuntimeSchema,
|
|
377
|
+
config: healthConfigSchema,
|
|
378
|
+
options: z2.array(healthOptionSchema).describe("Environment and runtime options relevant for configuration.")
|
|
379
|
+
},
|
|
380
|
+
annotations: {
|
|
381
|
+
readOnlyHint: true,
|
|
382
|
+
destructiveHint: false,
|
|
383
|
+
idempotentHint: true,
|
|
384
|
+
openWorldHint: false
|
|
385
|
+
}
|
|
386
|
+
};
|
|
328
387
|
var toolGetProjectInfo = {
|
|
329
388
|
title: "PrimeUI Project Info",
|
|
330
389
|
description: `ENTRY POINT for all PrimeUI import operations. Always start here. Returns project metadata and the full list of available pages.
|
|
@@ -652,6 +711,38 @@ function createPrimeUiMcpServer(source) {
|
|
|
652
711
|
instructions: initialInstructions
|
|
653
712
|
}
|
|
654
713
|
);
|
|
714
|
+
server.registerTool(
|
|
715
|
+
"health_check",
|
|
716
|
+
toolHealthCheck,
|
|
717
|
+
async () => {
|
|
718
|
+
try {
|
|
719
|
+
const health = await source.healthCheck();
|
|
720
|
+
return okResult("health_check", health);
|
|
721
|
+
} catch (error) {
|
|
722
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
723
|
+
return okResult("health_check", {
|
|
724
|
+
status: "degraded",
|
|
725
|
+
runtime: {
|
|
726
|
+
cwd: process.cwd(),
|
|
727
|
+
initCwd: process.env.INIT_CWD?.trim() || null,
|
|
728
|
+
pwd: process.env.PWD?.trim() || null,
|
|
729
|
+
searchRoots: [process.cwd()],
|
|
730
|
+
rootsListFallbackCwds: []
|
|
731
|
+
},
|
|
732
|
+
config: {
|
|
733
|
+
found: false,
|
|
734
|
+
projectRoot: null,
|
|
735
|
+
projectConfigPath: null,
|
|
736
|
+
targetProjectPath: null,
|
|
737
|
+
targetProjectRoot: null,
|
|
738
|
+
source: "search",
|
|
739
|
+
error: `health_check fallback: ${message}`
|
|
740
|
+
},
|
|
741
|
+
options: []
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
);
|
|
655
746
|
server.registerTool(
|
|
656
747
|
"get_project_info",
|
|
657
748
|
toolGetProjectInfo,
|
|
@@ -742,13 +833,118 @@ function createPrimeUiMcpServer(source) {
|
|
|
742
833
|
return server;
|
|
743
834
|
}
|
|
744
835
|
|
|
836
|
+
// src/services/health-check-service.ts
|
|
837
|
+
import path2 from "path";
|
|
838
|
+
function normalizeOptional(value) {
|
|
839
|
+
const trimmed = value?.trim();
|
|
840
|
+
return trimmed ? trimmed : null;
|
|
841
|
+
}
|
|
842
|
+
function buildHealthOptions(input) {
|
|
843
|
+
return [
|
|
844
|
+
{
|
|
845
|
+
key: "PRIMEUI_PROJECT_ROOT",
|
|
846
|
+
description: "Optional absolute root containing .primeui/project.json. Use as explicit override.",
|
|
847
|
+
currentValue: input.projectRootFromEnv
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
key: "PRIMEUI_API_BASE_URL",
|
|
851
|
+
description: "Optional PrimeUI API base URL override.",
|
|
852
|
+
currentValue: input.apiBaseUrlFromEnv
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
key: "PRIMEUI_API_KEY",
|
|
856
|
+
description: "Optional API key override. If missing, MCP uses apiKey from .primeui/project.json.",
|
|
857
|
+
currentValue: input.apiKeyFromEnv ? "set" : null
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
key: "Fallback search",
|
|
861
|
+
description: "When PRIMEUI_PROJECT_ROOT is not set, MCP searches from roots/list file roots, INIT_CWD, PWD, then process.cwd().",
|
|
862
|
+
currentValue: null
|
|
863
|
+
}
|
|
864
|
+
];
|
|
865
|
+
}
|
|
866
|
+
async function runPrimeUiHealthCheck(input) {
|
|
867
|
+
const projectRootFromEnv = normalizeOptional(input.projectRootFromEnv);
|
|
868
|
+
const apiBaseUrlFromEnv = normalizeOptional(input.apiBaseUrlFromEnv);
|
|
869
|
+
const apiKeyFromEnv = normalizeOptional(input.apiKeyFromEnv);
|
|
870
|
+
const initCwd = normalizeOptional(input.initCwd);
|
|
871
|
+
const pwd = normalizeOptional(input.pwd);
|
|
872
|
+
const rootsListFallbackCwds = (input.rootsListFallbackCwds ?? []).map((value) => value.trim()).filter(Boolean).map((value) => path2.resolve(value));
|
|
873
|
+
const fallbackCwds = (input.fallbackCwds ?? []).map((value) => value.trim()).filter(Boolean);
|
|
874
|
+
const searchRoots = buildPrimeUiProjectSearchRoots({
|
|
875
|
+
cwd: input.cwd,
|
|
876
|
+
fallbackCwds
|
|
877
|
+
});
|
|
878
|
+
try {
|
|
879
|
+
const resolvedProjectConfig = await resolvePrimeUiProjectConfig({
|
|
880
|
+
cwd: input.cwd,
|
|
881
|
+
projectRootFromEnv: projectRootFromEnv ?? void 0,
|
|
882
|
+
fallbackCwds
|
|
883
|
+
});
|
|
884
|
+
const targetProjectPath = resolvedProjectConfig.projectConfig.targetProjectPath;
|
|
885
|
+
return {
|
|
886
|
+
status: "ok",
|
|
887
|
+
runtime: {
|
|
888
|
+
cwd: path2.resolve(input.cwd),
|
|
889
|
+
initCwd,
|
|
890
|
+
pwd,
|
|
891
|
+
searchRoots,
|
|
892
|
+
rootsListFallbackCwds
|
|
893
|
+
},
|
|
894
|
+
config: {
|
|
895
|
+
found: true,
|
|
896
|
+
projectRoot: resolvedProjectConfig.projectRoot,
|
|
897
|
+
projectConfigPath: resolvedProjectConfig.projectConfigPath,
|
|
898
|
+
targetProjectPath,
|
|
899
|
+
targetProjectRoot: path2.resolve(
|
|
900
|
+
resolvedProjectConfig.projectRoot,
|
|
901
|
+
targetProjectPath
|
|
902
|
+
),
|
|
903
|
+
source: projectRootFromEnv ? "env.PRIMEUI_PROJECT_ROOT" : "search",
|
|
904
|
+
error: null
|
|
905
|
+
},
|
|
906
|
+
options: buildHealthOptions({
|
|
907
|
+
projectRootFromEnv,
|
|
908
|
+
apiBaseUrlFromEnv,
|
|
909
|
+
apiKeyFromEnv
|
|
910
|
+
})
|
|
911
|
+
};
|
|
912
|
+
} catch (error) {
|
|
913
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
914
|
+
return {
|
|
915
|
+
status: "degraded",
|
|
916
|
+
runtime: {
|
|
917
|
+
cwd: path2.resolve(input.cwd),
|
|
918
|
+
initCwd,
|
|
919
|
+
pwd,
|
|
920
|
+
searchRoots,
|
|
921
|
+
rootsListFallbackCwds
|
|
922
|
+
},
|
|
923
|
+
config: {
|
|
924
|
+
found: false,
|
|
925
|
+
projectRoot: null,
|
|
926
|
+
projectConfigPath: null,
|
|
927
|
+
targetProjectPath: null,
|
|
928
|
+
targetProjectRoot: null,
|
|
929
|
+
source: projectRootFromEnv ? "env.PRIMEUI_PROJECT_ROOT" : "search",
|
|
930
|
+
error: message
|
|
931
|
+
},
|
|
932
|
+
options: buildHealthOptions({
|
|
933
|
+
projectRootFromEnv,
|
|
934
|
+
apiBaseUrlFromEnv,
|
|
935
|
+
apiKeyFromEnv
|
|
936
|
+
})
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
745
941
|
// src/services/project-sync-service.ts
|
|
746
|
-
import
|
|
942
|
+
import path6 from "path";
|
|
747
943
|
import { readFile as readFile4 } from "fs/promises";
|
|
748
944
|
|
|
749
945
|
// src/lib/fs.ts
|
|
750
946
|
import { mkdir, rm, writeFile } from "fs/promises";
|
|
751
|
-
import
|
|
947
|
+
import path3 from "path";
|
|
752
948
|
import extractZipArchive from "extract-zip";
|
|
753
949
|
async function ensureDir(dirPath) {
|
|
754
950
|
await mkdir(dirPath, { recursive: true });
|
|
@@ -758,7 +954,7 @@ async function resetDir(dirPath) {
|
|
|
758
954
|
await mkdir(dirPath, { recursive: true });
|
|
759
955
|
}
|
|
760
956
|
async function writeUtf8(filePath, content) {
|
|
761
|
-
await ensureDir(
|
|
957
|
+
await ensureDir(path3.dirname(filePath));
|
|
762
958
|
await writeFile(filePath, content, "utf-8");
|
|
763
959
|
}
|
|
764
960
|
async function extractZip(zipPath, targetDir) {
|
|
@@ -773,12 +969,12 @@ async function extractZip(zipPath, targetDir) {
|
|
|
773
969
|
|
|
774
970
|
// src/services/page-copy-service.ts
|
|
775
971
|
import { readFile as readFile3, readdir, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
776
|
-
import
|
|
972
|
+
import path5 from "path";
|
|
777
973
|
|
|
778
974
|
// src/lib/import-graph.ts
|
|
779
975
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
780
976
|
import { builtinModules } from "module";
|
|
781
|
-
import
|
|
977
|
+
import path4 from "path";
|
|
782
978
|
var INTERNAL_EXTENSIONS = [
|
|
783
979
|
".ts",
|
|
784
980
|
".tsx",
|
|
@@ -854,7 +1050,7 @@ async function pathExists(filePath) {
|
|
|
854
1050
|
}
|
|
855
1051
|
}
|
|
856
1052
|
async function resolveFileCandidate(candidateBase) {
|
|
857
|
-
const ext =
|
|
1053
|
+
const ext = path4.extname(candidateBase);
|
|
858
1054
|
if (ext) {
|
|
859
1055
|
if (await pathExists(candidateBase)) {
|
|
860
1056
|
return candidateBase;
|
|
@@ -874,7 +1070,7 @@ async function resolveFileCandidate(candidateBase) {
|
|
|
874
1070
|
}
|
|
875
1071
|
if (stats.isDirectory()) {
|
|
876
1072
|
for (const extension of INTERNAL_EXTENSIONS) {
|
|
877
|
-
const indexCandidate =
|
|
1073
|
+
const indexCandidate = path4.join(candidateBase, `index${extension}`);
|
|
878
1074
|
if (await pathExists(indexCandidate)) {
|
|
879
1075
|
return indexCandidate;
|
|
880
1076
|
}
|
|
@@ -896,13 +1092,13 @@ async function resolveImportToFile(projectRoot, importerFilePath, specifier) {
|
|
|
896
1092
|
}
|
|
897
1093
|
let candidateBase = null;
|
|
898
1094
|
if (specifier.startsWith("@/")) {
|
|
899
|
-
candidateBase =
|
|
1095
|
+
candidateBase = path4.join(projectRoot, "src", specifier.slice(2));
|
|
900
1096
|
} else if (specifier.startsWith("@root/")) {
|
|
901
|
-
candidateBase =
|
|
1097
|
+
candidateBase = path4.join(projectRoot, specifier.slice(6));
|
|
902
1098
|
} else if (specifier.startsWith(".")) {
|
|
903
|
-
candidateBase =
|
|
1099
|
+
candidateBase = path4.resolve(path4.dirname(importerFilePath), specifier);
|
|
904
1100
|
} else if (specifier.startsWith("/")) {
|
|
905
|
-
candidateBase =
|
|
1101
|
+
candidateBase = path4.join(projectRoot, specifier.slice(1));
|
|
906
1102
|
} else {
|
|
907
1103
|
return { kind: "unknown" };
|
|
908
1104
|
}
|
|
@@ -916,12 +1112,12 @@ async function resolveImportToFile(projectRoot, importerFilePath, specifier) {
|
|
|
916
1112
|
};
|
|
917
1113
|
}
|
|
918
1114
|
function shouldParseFile(filePath) {
|
|
919
|
-
return PARSEABLE_EXTENSIONS.has(
|
|
1115
|
+
return PARSEABLE_EXTENSIONS.has(path4.extname(filePath).toLowerCase());
|
|
920
1116
|
}
|
|
921
1117
|
async function buildImportGraph(input) {
|
|
922
1118
|
const shouldFollowInternalImports = input.followInternalImports ?? true;
|
|
923
|
-
const projectRoot =
|
|
924
|
-
const queue = input.entryFiles.map((filePath) =>
|
|
1119
|
+
const projectRoot = path4.resolve(input.projectRoot);
|
|
1120
|
+
const queue = input.entryFiles.map((filePath) => path4.resolve(filePath));
|
|
925
1121
|
const visited = /* @__PURE__ */ new Set();
|
|
926
1122
|
const internalFiles = /* @__PURE__ */ new Set();
|
|
927
1123
|
const externalPackages = /* @__PURE__ */ new Set();
|
|
@@ -1174,10 +1370,10 @@ function normalizeSlug2(slug) {
|
|
|
1174
1370
|
return withLeadingSlash.replace(/\/+$/, "") || "/";
|
|
1175
1371
|
}
|
|
1176
1372
|
function toPosixPath(value) {
|
|
1177
|
-
return value.split(
|
|
1373
|
+
return value.split(path5.sep).join("/");
|
|
1178
1374
|
}
|
|
1179
1375
|
function toProjectRelative(rootPath, absolutePath) {
|
|
1180
|
-
return toPosixPath(
|
|
1376
|
+
return toPosixPath(path5.relative(rootPath, absolutePath));
|
|
1181
1377
|
}
|
|
1182
1378
|
function escapeRegExp(value) {
|
|
1183
1379
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1234,7 +1430,7 @@ function buildPlannedSourceBuffer(sourceBuffer, sourceFilePath, importRewritePla
|
|
|
1234
1430
|
if (!importRewritePlan) {
|
|
1235
1431
|
return sourceBuffer;
|
|
1236
1432
|
}
|
|
1237
|
-
const extension =
|
|
1433
|
+
const extension = path5.extname(sourceFilePath).toLowerCase();
|
|
1238
1434
|
if (!REWRITABLE_IMPORT_EXTENSIONS.has(extension)) {
|
|
1239
1435
|
return sourceBuffer;
|
|
1240
1436
|
}
|
|
@@ -1336,9 +1532,9 @@ async function resolveManifestCandidateFiles(input) {
|
|
|
1336
1532
|
);
|
|
1337
1533
|
}
|
|
1338
1534
|
const normalizedRelative = toPosixPath(trimmed).replace(/^\.\/+/, "");
|
|
1339
|
-
const absolutePath =
|
|
1340
|
-
const relative =
|
|
1341
|
-
if (relative.startsWith("..") ||
|
|
1535
|
+
const absolutePath = path5.resolve(input.exportPath, normalizedRelative);
|
|
1536
|
+
const relative = path5.relative(input.exportPath, absolutePath);
|
|
1537
|
+
if (relative.startsWith("..") || path5.isAbsolute(relative)) {
|
|
1342
1538
|
throw new Error(
|
|
1343
1539
|
`Export manifest for page "${input.pageSlug}" contains path outside export root: ${trimmed}`
|
|
1344
1540
|
);
|
|
@@ -1369,12 +1565,12 @@ async function resolveSingleExportDirectory(exportsRoot) {
|
|
|
1369
1565
|
const exportId = exportDirectories[0] ?? "";
|
|
1370
1566
|
return {
|
|
1371
1567
|
exportId,
|
|
1372
|
-
exportPath:
|
|
1568
|
+
exportPath: path5.join(exportsRoot, exportId)
|
|
1373
1569
|
};
|
|
1374
1570
|
}
|
|
1375
1571
|
function ensureSafeTargetPath(projectRoot, targetPath) {
|
|
1376
|
-
const relative =
|
|
1377
|
-
if (relative.startsWith("..") ||
|
|
1572
|
+
const relative = path5.relative(projectRoot, targetPath);
|
|
1573
|
+
if (relative.startsWith("..") || path5.isAbsolute(relative)) {
|
|
1378
1574
|
throw new Error(
|
|
1379
1575
|
`Refusing to write outside project root. Computed target: ${targetPath}`
|
|
1380
1576
|
);
|
|
@@ -1432,19 +1628,19 @@ function resolveTargetFilePath(input) {
|
|
|
1432
1628
|
if (sourceFilePath === sourcePagePath) {
|
|
1433
1629
|
return targetPagePath;
|
|
1434
1630
|
}
|
|
1435
|
-
const componentsPrefix = `${sourceComponentsPath}${
|
|
1631
|
+
const componentsPrefix = `${sourceComponentsPath}${path5.sep}`;
|
|
1436
1632
|
if (sourceFilePath === sourceComponentsPath || sourceFilePath.startsWith(componentsPrefix)) {
|
|
1437
|
-
const relativeToComponents =
|
|
1633
|
+
const relativeToComponents = path5.relative(
|
|
1438
1634
|
sourceComponentsPath,
|
|
1439
1635
|
sourceFilePath
|
|
1440
1636
|
);
|
|
1441
|
-
return
|
|
1637
|
+
return path5.join(targetComponentsPath, relativeToComponents);
|
|
1442
1638
|
}
|
|
1443
|
-
const relativeToExport =
|
|
1444
|
-
if (relativeToExport.startsWith("..") ||
|
|
1639
|
+
const relativeToExport = path5.relative(exportRoot, sourceFilePath);
|
|
1640
|
+
if (relativeToExport.startsWith("..") || path5.isAbsolute(relativeToExport)) {
|
|
1445
1641
|
throw new Error(`Source file is outside export root: ${sourceFilePath}`);
|
|
1446
1642
|
}
|
|
1447
|
-
return
|
|
1643
|
+
return path5.join(projectRoot, relativeToExport);
|
|
1448
1644
|
}
|
|
1449
1645
|
async function copyPageFromExport(input) {
|
|
1450
1646
|
const normalizedOriginSlug = normalizeSlug2(input.originPageSlug);
|
|
@@ -1455,7 +1651,7 @@ async function copyPageFromExport(input) {
|
|
|
1455
1651
|
const { exportId, exportPath } = await resolveSingleExportDirectory(
|
|
1456
1652
|
input.exportsRoot
|
|
1457
1653
|
);
|
|
1458
|
-
const manifestPath =
|
|
1654
|
+
const manifestPath = path5.join(
|
|
1459
1655
|
input.exportsRoot,
|
|
1460
1656
|
`${exportId}.manifest.json`
|
|
1461
1657
|
);
|
|
@@ -1478,8 +1674,8 @@ async function copyPageFromExport(input) {
|
|
|
1478
1674
|
`Page not found in manifest for slug: ${normalizedOriginSlug}`
|
|
1479
1675
|
);
|
|
1480
1676
|
}
|
|
1481
|
-
const sourcePagePath =
|
|
1482
|
-
const sourceComponentsPath =
|
|
1677
|
+
const sourcePagePath = path5.join(exportPath, page.pagePath);
|
|
1678
|
+
const sourceComponentsPath = path5.join(exportPath, page.componentsPath);
|
|
1483
1679
|
const sourcePageStats = await stat3(sourcePagePath).catch(() => null);
|
|
1484
1680
|
if (!sourcePageStats?.isFile()) {
|
|
1485
1681
|
throw new Error(`Source page file not found: ${sourcePagePath}`);
|
|
@@ -1499,8 +1695,8 @@ async function copyPageFromExport(input) {
|
|
|
1499
1695
|
pageType: page.pageType,
|
|
1500
1696
|
slug: normalizedActualSlug
|
|
1501
1697
|
});
|
|
1502
|
-
const targetPagePath =
|
|
1503
|
-
const targetComponentsPath =
|
|
1698
|
+
const targetPagePath = path5.join(input.projectRoot, targetPaths.pagePath);
|
|
1699
|
+
const targetComponentsPath = path5.join(
|
|
1504
1700
|
input.projectRoot,
|
|
1505
1701
|
targetPaths.componentsPath
|
|
1506
1702
|
);
|
|
@@ -1546,7 +1742,7 @@ async function copyPageFromExport(input) {
|
|
|
1546
1742
|
const sourceRelative = toProjectRelative(exportPath, sourceFilePath);
|
|
1547
1743
|
const targetRelative = toProjectRelative(input.projectRoot, targetFilePath);
|
|
1548
1744
|
if (!targetBuffer) {
|
|
1549
|
-
await ensureDir(
|
|
1745
|
+
await ensureDir(path5.dirname(targetFilePath));
|
|
1550
1746
|
await writeFile2(targetFilePath, plannedSourceBuffer);
|
|
1551
1747
|
newFiles.push({
|
|
1552
1748
|
sourcePath: sourceRelative,
|
|
@@ -1575,8 +1771,8 @@ async function copyPageFromExport(input) {
|
|
|
1575
1771
|
isBinary
|
|
1576
1772
|
});
|
|
1577
1773
|
}
|
|
1578
|
-
const exportPackageJsonPath =
|
|
1579
|
-
const userPackageJsonPath =
|
|
1774
|
+
const exportPackageJsonPath = path5.join(exportPath, "package.json");
|
|
1775
|
+
const userPackageJsonPath = path5.join(input.projectRoot, "package.json");
|
|
1580
1776
|
if (!await fileExists2(exportPackageJsonPath)) {
|
|
1581
1777
|
throw new Error(`Export package.json not found: ${exportPackageJsonPath}`);
|
|
1582
1778
|
}
|
|
@@ -1782,7 +1978,7 @@ function isExportPage(value) {
|
|
|
1782
1978
|
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);
|
|
1783
1979
|
}
|
|
1784
1980
|
function buildManifestPath(exportsRoot, exportId) {
|
|
1785
|
-
return
|
|
1981
|
+
return path6.join(exportsRoot, `${exportId}.manifest.json`);
|
|
1786
1982
|
}
|
|
1787
1983
|
function parseExportManifest(value) {
|
|
1788
1984
|
if (!value || typeof value !== "object") {
|
|
@@ -1826,9 +2022,9 @@ var ProjectSyncService = class {
|
|
|
1826
2022
|
this.projectRoot = options.projectRoot;
|
|
1827
2023
|
this.targetProjectRoot = options.targetProjectRoot;
|
|
1828
2024
|
this.provider = options.provider;
|
|
1829
|
-
this.primeUiRoot =
|
|
1830
|
-
this.tempRoot =
|
|
1831
|
-
this.exportsRoot =
|
|
2025
|
+
this.primeUiRoot = path6.join(this.projectRoot, ".primeui");
|
|
2026
|
+
this.tempRoot = path6.join(this.primeUiRoot, "temp");
|
|
2027
|
+
this.exportsRoot = path6.join(this.tempRoot, "exports");
|
|
1832
2028
|
}
|
|
1833
2029
|
async getProjectInfo() {
|
|
1834
2030
|
await this.ensureTempLayout();
|
|
@@ -1853,8 +2049,8 @@ var ProjectSyncService = class {
|
|
|
1853
2049
|
if (!selected) {
|
|
1854
2050
|
throw new Error(`Export not found: ${id}`);
|
|
1855
2051
|
}
|
|
1856
|
-
const targetZipPath =
|
|
1857
|
-
const targetProjectPath =
|
|
2052
|
+
const targetZipPath = path6.join(this.exportsRoot, `${id}.zip`);
|
|
2053
|
+
const targetProjectPath = path6.join(this.exportsRoot, id);
|
|
1858
2054
|
const manifestPath = buildManifestPath(this.exportsRoot, id);
|
|
1859
2055
|
let manifest;
|
|
1860
2056
|
try {
|
|
@@ -1907,6 +2103,47 @@ var ProjectSyncService = class {
|
|
|
1907
2103
|
await resetDir(this.tempRoot);
|
|
1908
2104
|
await ensureDir(this.exportsRoot);
|
|
1909
2105
|
}
|
|
2106
|
+
async healthCheck() {
|
|
2107
|
+
return {
|
|
2108
|
+
status: "ok",
|
|
2109
|
+
runtime: {
|
|
2110
|
+
cwd: process.cwd(),
|
|
2111
|
+
initCwd: process.env.INIT_CWD?.trim() || null,
|
|
2112
|
+
pwd: process.env.PWD?.trim() || null,
|
|
2113
|
+
searchRoots: [process.cwd()],
|
|
2114
|
+
rootsListFallbackCwds: []
|
|
2115
|
+
},
|
|
2116
|
+
config: {
|
|
2117
|
+
found: true,
|
|
2118
|
+
projectRoot: this.projectRoot,
|
|
2119
|
+
projectConfigPath: path6.join(this.projectRoot, ".primeui", "project.json"),
|
|
2120
|
+
targetProjectPath: path6.relative(
|
|
2121
|
+
this.projectRoot,
|
|
2122
|
+
this.targetProjectRoot
|
|
2123
|
+
).startsWith(".") ? "./" : `./${path6.relative(this.projectRoot, this.targetProjectRoot)}`,
|
|
2124
|
+
targetProjectRoot: this.targetProjectRoot,
|
|
2125
|
+
source: process.env.PRIMEUI_PROJECT_ROOT?.trim() ? "env.PRIMEUI_PROJECT_ROOT" : "search",
|
|
2126
|
+
error: null
|
|
2127
|
+
},
|
|
2128
|
+
options: [
|
|
2129
|
+
{
|
|
2130
|
+
key: "PRIMEUI_PROJECT_ROOT",
|
|
2131
|
+
description: "Optional absolute root containing .primeui/project.json. Use as explicit override.",
|
|
2132
|
+
currentValue: process.env.PRIMEUI_PROJECT_ROOT?.trim() || null
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
key: "PRIMEUI_API_BASE_URL",
|
|
2136
|
+
description: "Optional PrimeUI API base URL override.",
|
|
2137
|
+
currentValue: process.env.PRIMEUI_API_BASE_URL?.trim() || null
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
key: "PRIMEUI_API_KEY",
|
|
2141
|
+
description: "Optional API key override. If missing, MCP uses apiKey from .primeui/project.json.",
|
|
2142
|
+
currentValue: process.env.PRIMEUI_API_KEY?.trim() ? "set" : null
|
|
2143
|
+
}
|
|
2144
|
+
]
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
1910
2147
|
async ensureTempLayout() {
|
|
1911
2148
|
await ensureDir(this.primeUiRoot);
|
|
1912
2149
|
await ensureDir(this.tempRoot);
|
|
@@ -1917,7 +2154,7 @@ var ProjectSyncService = class {
|
|
|
1917
2154
|
// src/sources/api-provider.ts
|
|
1918
2155
|
import { createWriteStream } from "fs";
|
|
1919
2156
|
import { unlink } from "fs/promises";
|
|
1920
|
-
import
|
|
2157
|
+
import path7 from "path";
|
|
1921
2158
|
import { Readable, Transform } from "stream";
|
|
1922
2159
|
import { pipeline } from "stream/promises";
|
|
1923
2160
|
import { z as z3 } from "zod";
|
|
@@ -2141,7 +2378,7 @@ var ApiProjectDataProvider = class {
|
|
|
2141
2378
|
if (!response.body) {
|
|
2142
2379
|
throw new PrimeUiApiContractError(endpoint, "response body is empty");
|
|
2143
2380
|
}
|
|
2144
|
-
await ensureDir(
|
|
2381
|
+
await ensureDir(path7.dirname(destinationPath));
|
|
2145
2382
|
const zipStream = Readable.fromWeb(
|
|
2146
2383
|
response.body
|
|
2147
2384
|
);
|
|
@@ -2238,7 +2475,7 @@ async function createProjectSyncService(rootsFallbackCwds) {
|
|
|
2238
2475
|
fallbackCwds: [...getProjectConfigFallbackCwds(), ...rootsFallbackCwds]
|
|
2239
2476
|
});
|
|
2240
2477
|
const projectRoot = resolvedProjectConfig.projectRoot;
|
|
2241
|
-
const targetProjectRoot =
|
|
2478
|
+
const targetProjectRoot = path8.resolve(
|
|
2242
2479
|
projectRoot,
|
|
2243
2480
|
resolvedProjectConfig.projectConfig.targetProjectPath
|
|
2244
2481
|
);
|
|
@@ -2292,6 +2529,29 @@ var LazyProjectSyncSource = class {
|
|
|
2292
2529
|
async clearTemp() {
|
|
2293
2530
|
return this.withService((service) => service.clearTemp());
|
|
2294
2531
|
}
|
|
2532
|
+
async healthCheck() {
|
|
2533
|
+
const rootsFallbackCwds = this.getRootsFallbackCwds();
|
|
2534
|
+
const result = await runPrimeUiHealthCheck({
|
|
2535
|
+
cwd: process.cwd(),
|
|
2536
|
+
initCwd: process.env.INIT_CWD,
|
|
2537
|
+
pwd: process.env.PWD,
|
|
2538
|
+
projectRootFromEnv: process.env.PRIMEUI_PROJECT_ROOT,
|
|
2539
|
+
apiBaseUrlFromEnv: process.env.PRIMEUI_API_BASE_URL,
|
|
2540
|
+
apiKeyFromEnv: process.env.PRIMEUI_API_KEY,
|
|
2541
|
+
fallbackCwds: [...getProjectConfigFallbackCwds(), ...rootsFallbackCwds],
|
|
2542
|
+
rootsListFallbackCwds: rootsFallbackCwds
|
|
2543
|
+
});
|
|
2544
|
+
if (result.config.found) {
|
|
2545
|
+
console.error("[primeui-mcp] RESOLVED_PROJECT_ROOT:", result.config.projectRoot);
|
|
2546
|
+
console.error(
|
|
2547
|
+
"[primeui-mcp] RESOLVED_PROJECT_CONFIG:",
|
|
2548
|
+
result.config.projectConfigPath
|
|
2549
|
+
);
|
|
2550
|
+
} else {
|
|
2551
|
+
console.error("[primeui-mcp] RESOLUTION_FAILED:", result.config.error);
|
|
2552
|
+
}
|
|
2553
|
+
return result;
|
|
2554
|
+
}
|
|
2295
2555
|
};
|
|
2296
2556
|
function toFileRootPath(rootUri) {
|
|
2297
2557
|
try {
|