@primeuicom/mcp 0.1.11 → 0.1.12

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 CHANGED
@@ -1,77 +1,178 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/service.ts
4
+ import path7 from "path";
4
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
6
 
7
+ // src/lib/project-link-config.ts
8
+ import { readFile, stat } from "fs/promises";
9
+ import path from "path";
10
+ import { z } from "zod";
11
+ var PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH = ".primeui/project.json";
12
+ var primeUiProjectConfigSchema = z.object({
13
+ projectId: z.string().trim().min(1),
14
+ apiKey: z.string().trim().min(1),
15
+ targetProjectPath: z.string().trim().regex(/^\.\/.*$/)
16
+ }).passthrough();
17
+ async function fileExists(filePath) {
18
+ try {
19
+ const fileStats = await stat(filePath);
20
+ return fileStats.isFile();
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+ function ancestors(startPath) {
26
+ const resolvedStartPath = path.resolve(startPath);
27
+ const directories = [];
28
+ let currentPath = resolvedStartPath;
29
+ while (true) {
30
+ directories.push(currentPath);
31
+ const parentPath = path.dirname(currentPath);
32
+ if (parentPath === currentPath) {
33
+ break;
34
+ }
35
+ currentPath = parentPath;
36
+ }
37
+ return directories;
38
+ }
39
+ async function findPrimeUiProjectConfigPath(startPath) {
40
+ for (const currentPath of ancestors(startPath)) {
41
+ const candidatePath = path.join(
42
+ currentPath,
43
+ PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH
44
+ );
45
+ if (await fileExists(candidatePath)) {
46
+ return candidatePath;
47
+ }
48
+ }
49
+ return void 0;
50
+ }
51
+ async function readPrimeUiProjectConfig(projectConfigPath) {
52
+ let projectConfigRaw;
53
+ try {
54
+ projectConfigRaw = await readFile(projectConfigPath, "utf-8");
55
+ } catch (error) {
56
+ throw new Error(
57
+ `[primeui-mcp] failed to read ${PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH}: ${error instanceof Error ? error.message : String(error)}`
58
+ );
59
+ }
60
+ let projectConfigJson;
61
+ try {
62
+ projectConfigJson = JSON.parse(projectConfigRaw);
63
+ } catch (error) {
64
+ throw new Error(
65
+ `[primeui-mcp] invalid JSON in ${PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH}: ${error instanceof Error ? error.message : String(error)}`
66
+ );
67
+ }
68
+ const parsedConfig = primeUiProjectConfigSchema.safeParse(projectConfigJson);
69
+ if (!parsedConfig.success) {
70
+ const details = parsedConfig.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`).join("; ");
71
+ throw new Error(
72
+ `[primeui-mcp] invalid ${PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH} format: ${details}`
73
+ );
74
+ }
75
+ return parsedConfig.data;
76
+ }
77
+ async function resolvePrimeUiProjectConfig(options) {
78
+ const envProjectRoot = options.projectRootFromEnv?.trim();
79
+ const projectConfigPath = envProjectRoot ? path.join(path.resolve(envProjectRoot), PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH) : await findPrimeUiProjectConfigPath(options.cwd);
80
+ if (!projectConfigPath) {
81
+ throw new Error(
82
+ `[primeui-mcp] ${PRIMEUI_PROJECT_CONFIG_RELATIVE_PATH} not found from cwd (${options.cwd}).`
83
+ );
84
+ }
85
+ const projectRoot = path.dirname(path.dirname(projectConfigPath));
86
+ const projectConfig = await readPrimeUiProjectConfig(projectConfigPath);
87
+ return {
88
+ projectRoot,
89
+ projectConfigPath,
90
+ projectConfig
91
+ };
92
+ }
93
+ async function resolvePrimeUiApiKey(options) {
94
+ const envApiKey = options.apiKeyFromEnv?.trim();
95
+ if (envApiKey) {
96
+ return envApiKey;
97
+ }
98
+ const projectConfigApiKey = options.projectConfig.apiKey.trim();
99
+ if (!projectConfigApiKey) {
100
+ throw new Error(
101
+ "[primeui-mcp] PRIMEUI_API_KEY is missing in env and .primeui/project.json"
102
+ );
103
+ }
104
+ return projectConfigApiKey;
105
+ }
106
+
6
107
  // src/server.ts
7
108
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
109
 
9
110
  // src/instructions.ts
10
- import { z } from "zod/v3";
11
- var pageSchema = z.object({
12
- id: z.string().describe(
111
+ import { z as z2 } from "zod/v3";
112
+ var pageSchema = z2.object({
113
+ id: z2.string().describe(
13
114
  "Stable PrimeUI page identifier. Use this to match the same page across tool responses."
14
115
  ),
15
- title: z.string().describe(
116
+ title: z2.string().describe(
16
117
  "Human-readable page title. Show this to the user when confirming which pages to import."
17
118
  ),
18
- slug: z.string().describe(
119
+ slug: z2.string().describe(
19
120
  "PrimeUI route slug, for example '/', '/pricing', '/docs/getting-started'. Use to match user intent."
20
121
  ),
21
- pageType: z.string().describe(
122
+ pageType: z2.string().describe(
22
123
  "PrimeUI page type classification (for example landing, docs, pricing, blogIndex, legal)."
23
124
  ),
24
- isReadyToExport: z.boolean().describe(
125
+ isReadyToExport: z2.boolean().describe(
25
126
  "True when this page has an active export-ready variant. Only ready pages are expected in export output."
26
127
  ),
27
- pagePath: z.string().describe(
128
+ pagePath: z2.string().describe(
28
129
  "Relative file path to the page source inside downloaded export root. Copy page code from this exact path."
29
130
  ),
30
- componentsPath: z.string().describe(
131
+ componentsPath: z2.string().describe(
31
132
  "Relative directory path inside downloaded export root where page-level components live. Use as dependency copy start."
32
133
  )
33
134
  }).describe(
34
135
  "PrimeUI page descriptor used by project and export tools. Paths are always relative to export project root."
35
136
  );
36
- var exportStatusSchema = z.enum(["in_progress", "completed", "failed"]).describe(
137
+ var exportStatusSchema = z2.enum(["in_progress", "completed", "failed"]).describe(
37
138
  "Export lifecycle state. Use 'completed' before calling primeui_download_export."
38
139
  );
39
- var exportItemSchema = z.object({
40
- id: z.string().describe(
140
+ var exportItemSchema = z2.object({
141
+ id: z2.string().describe(
41
142
  "Export identifier. Pass this value to primeui_download_export input.id."
42
143
  ),
43
144
  status: exportStatusSchema,
44
- createdAt: z.string().describe("Export creation timestamp in ISO-8601 UTC format.")
145
+ createdAt: z2.string().describe("Export creation timestamp in ISO-8601 UTC format.")
45
146
  }).describe("Single export record from PrimeUI export history.");
46
- var fileTransferSchema = z.object({
47
- sourcePath: z.string().describe("Relative source file path inside downloaded export root."),
48
- targetPath: z.string().describe("Relative target file path inside user project root.")
147
+ var fileTransferSchema = z2.object({
148
+ sourcePath: z2.string().describe("Relative source file path inside downloaded export root."),
149
+ targetPath: z2.string().describe("Relative target file path inside user project root.")
49
150
  });
50
151
  var conflictFileSchema = fileTransferSchema.extend({
51
- diff: z.string().describe(
152
+ diff: z2.string().describe(
52
153
  "Unified diff between user file and export file. For binary files the diff contains a plain message."
53
154
  ),
54
- isBinary: z.boolean().describe("True if conflict comparison was treated as binary data.")
155
+ isBinary: z2.boolean().describe("True if conflict comparison was treated as binary data.")
55
156
  });
56
- var dependencySectionSchema = z.enum([
157
+ var dependencySectionSchema = z2.enum([
57
158
  "dependencies",
58
159
  "devDependencies",
59
160
  "peerDependencies"
60
161
  ]);
61
- var dependencyToAddSchema = z.object({
62
- packageName: z.string().describe("Dependency package name that was missing in user package.json."),
63
- version: z.string().describe("Version from exported project's package.json."),
162
+ var dependencyToAddSchema = z2.object({
163
+ packageName: z2.string().describe("Dependency package name that was missing in user package.json."),
164
+ version: z2.string().describe("Version from exported project's package.json."),
64
165
  section: dependencySectionSchema.describe(
65
166
  "package.json section where dependency should be added."
66
167
  )
67
168
  });
68
- var dependencyVersionConflictSchema = z.object({
69
- packageName: z.string().describe("Dependency package name with version mismatch."),
169
+ var dependencyVersionConflictSchema = z2.object({
170
+ packageName: z2.string().describe("Dependency package name with version mismatch."),
70
171
  section: dependencySectionSchema.describe(
71
172
  "Section where export expects this dependency."
72
173
  ),
73
- exportVersion: z.string().describe("Version found in exported project's package.json."),
74
- userVersion: z.string().describe("Version currently present in user's package.json.")
174
+ exportVersion: z2.string().describe("Version found in exported project's package.json."),
175
+ userVersion: z2.string().describe("Version currently present in user's package.json.")
75
176
  });
76
177
  var TRIGGER_PHRASES = [
77
178
  "import page from PrimeUI",
@@ -145,16 +246,16 @@ AFTER CALLING:
145
246
  ${WORKFLOW_SUMMARY}`,
146
247
  inputSchema: {},
147
248
  outputSchema: {
148
- projectId: z.string().describe(
249
+ projectId: z2.string().describe(
149
250
  "PrimeUI project identifier associated with the API key and current import session context."
150
251
  ),
151
- projectName: z.string().describe(
252
+ projectName: z2.string().describe(
152
253
  "Human-readable PrimeUI project name for confirmations in chat."
153
254
  ),
154
- metadata: z.record(z.unknown()).describe(
255
+ metadata: z2.record(z2.unknown()).describe(
155
256
  "Additional project metadata from PrimeUI. May include project-description and other context fields."
156
257
  ),
157
- pages: z.array(pageSchema).describe(
258
+ pages: z2.array(pageSchema).describe(
158
259
  "All pages visible for this project context. Filter by user request and isReadyToExport before creating export."
159
260
  )
160
261
  },
@@ -181,7 +282,7 @@ Do NOT use this tool as a substitute for primeui_create_export. Always create a
181
282
  ${WORKFLOW_SUMMARY}`,
182
283
  inputSchema: {},
183
284
  outputSchema: {
184
- exports: z.array(exportItemSchema).describe(
285
+ exports: z2.array(exportItemSchema).describe(
185
286
  "Available exports sorted by API policy. Use item.id to download a specific prior export if user asks."
186
287
  )
187
288
  },
@@ -207,13 +308,13 @@ AFTER CALLING:
207
308
  ${WORKFLOW_SUMMARY}`,
208
309
  inputSchema: {},
209
310
  outputSchema: {
210
- export: z.object({
211
- id: z.string().describe(
311
+ export: z2.object({
312
+ id: z2.string().describe(
212
313
  "Freshly created export identifier. Use this as primeui_download_export input.id."
213
314
  ),
214
315
  status: exportStatusSchema
215
316
  }).describe("Created export summary."),
216
- pages: z.array(pageSchema).describe(
317
+ pages: z2.array(pageSchema).describe(
217
318
  "Page snapshot associated with this export operation. Validate requested pages here before download/import."
218
319
  )
219
320
  },
@@ -246,21 +347,21 @@ AFTER DOWNLOAD:
246
347
 
247
348
  ${WORKFLOW_SUMMARY}`,
248
349
  inputSchema: {
249
- id: z.string().describe(
350
+ id: z2.string().describe(
250
351
  "Export identifier to download. Prefer export.id from primeui_create_export; use primeui_list_exports only on explicit user request."
251
352
  )
252
353
  },
253
354
  outputSchema: {
254
- exportId: z.string().describe(
355
+ exportId: z2.string().describe(
255
356
  "Downloaded export identifier. Should match the requested input.id for traceability."
256
357
  ),
257
- projectPath: z.string().describe(
358
+ projectPath: z2.string().describe(
258
359
  "Absolute local path to extracted export root in .primeui/temp/exports/[exportId]. Read files from here only."
259
360
  ),
260
- manifestPath: z.string().describe(
361
+ manifestPath: z2.string().describe(
261
362
  "Absolute path to sidecar export manifest file (.primeui/temp/exports/[exportId].manifest.json). primeui_copy_page depends on this file."
262
363
  ),
263
- pages: z.array(pageSchema).describe(
364
+ pages: z2.array(pageSchema).describe(
264
365
  "Page descriptors for import decisions. Use pagePath/componentsPath from each item when copying code into user project."
265
366
  )
266
367
  },
@@ -295,44 +396,44 @@ BEHAVIOR:
295
396
 
296
397
  ${WORKFLOW_SUMMARY}`,
297
398
  inputSchema: {
298
- originPageSlug: z.string().describe(
399
+ originPageSlug: z2.string().describe(
299
400
  "Source page slug from PrimeUI project pages list, for example '/', '/pricing', '/docs'."
300
401
  ),
301
- actualPageSlug: z.string().optional().describe(
402
+ actualPageSlug: z2.string().optional().describe(
302
403
  "Optional destination slug in user's project. If omitted, originPageSlug is used."
303
404
  )
304
405
  },
305
406
  outputSchema: {
306
- exportId: z.string().describe("Resolved local export identifier used for copy operation."),
307
- exportPath: z.string().describe("Absolute path to local extracted export project root."),
308
- originPageSlug: z.string().describe("Normalized source page slug requested for copy."),
309
- actualPageSlug: z.string().describe("Normalized destination slug used for target route paths."),
310
- sourcePagePath: z.string().describe("Source page path relative to export root."),
311
- targetPagePath: z.string().describe("Destination page path relative to user project root."),
312
- sourceComponentsPath: z.string().describe("Source components directory relative to export root."),
313
- targetComponentsPath: z.string().describe(
407
+ exportId: z2.string().describe("Resolved local export identifier used for copy operation."),
408
+ exportPath: z2.string().describe("Absolute path to local extracted export project root."),
409
+ originPageSlug: z2.string().describe("Normalized source page slug requested for copy."),
410
+ actualPageSlug: z2.string().describe("Normalized destination slug used for target route paths."),
411
+ sourcePagePath: z2.string().describe("Source page path relative to export root."),
412
+ targetPagePath: z2.string().describe("Destination page path relative to user project root."),
413
+ sourceComponentsPath: z2.string().describe("Source components directory relative to export root."),
414
+ targetComponentsPath: z2.string().describe(
314
415
  "Destination components directory relative to user project root."
315
416
  ),
316
- newFiles: z.array(fileTransferSchema).describe("New files copied into user project without conflicts."),
317
- identicalFiles: z.array(fileTransferSchema).describe(
417
+ newFiles: z2.array(fileTransferSchema).describe("New files copied into user project without conflicts."),
418
+ identicalFiles: z2.array(fileTransferSchema).describe(
318
419
  "Existing files in user project that are byte-identical to export files."
319
420
  ),
320
- conflictFiles: z.array(conflictFileSchema).describe(
421
+ conflictFiles: z2.array(conflictFileSchema).describe(
321
422
  "Files that already exist and differ from export version. Never overwritten."
322
423
  ),
323
- addedDependencies: z.array(dependencyToAddSchema).describe(
424
+ addedDependencies: z2.array(dependencyToAddSchema).describe(
324
425
  "Dependencies that were missing and have been added to user's package.json."
325
426
  ),
326
- dependenciesVersionConflicts: z.array(dependencyVersionConflictSchema).describe(
427
+ dependenciesVersionConflicts: z2.array(dependencyVersionConflictSchema).describe(
327
428
  "Dependencies with version mismatch between export and user project. Report only."
328
429
  ),
329
- summary: z.object({
330
- totalCandidateFiles: z.number().describe("Total number of candidate files considered for page copy."),
331
- copiedFiles: z.number().describe("Number of files copied as new."),
332
- identicalFiles: z.number().describe("Number of files detected as identical."),
333
- conflictFiles: z.number().describe("Number of conflicting files not copied."),
334
- addedDependencies: z.number().describe("Count of dependencies added to package.json."),
335
- dependenciesVersionConflicts: z.number().describe("Count of dependency version mismatches reported.")
430
+ summary: z2.object({
431
+ totalCandidateFiles: z2.number().describe("Total number of candidate files considered for page copy."),
432
+ copiedFiles: z2.number().describe("Number of files copied as new."),
433
+ identicalFiles: z2.number().describe("Number of files detected as identical."),
434
+ conflictFiles: z2.number().describe("Number of conflicting files not copied."),
435
+ addedDependencies: z2.number().describe("Count of dependencies added to package.json."),
436
+ dependenciesVersionConflicts: z2.number().describe("Count of dependency version mismatches reported.")
336
437
  })
337
438
  },
338
439
  annotations: {
@@ -355,7 +456,7 @@ Safe to call multiple times. Only affects .primeui/temp/ directory - never touch
355
456
  ${WORKFLOW_SUMMARY}`,
356
457
  inputSchema: {},
357
458
  outputSchema: {
358
- success: z.boolean().describe(
459
+ success: z2.boolean().describe(
359
460
  "True when temp cleanup completed and baseline temp structure was recreated."
360
461
  )
361
462
  },
@@ -470,12 +571,12 @@ function createPrimeUiMcpServer(source) {
470
571
  }
471
572
 
472
573
  // src/services/project-sync-service.ts
473
- import path4 from "path";
474
- import { readFile as readFile3 } from "fs/promises";
574
+ import path5 from "path";
575
+ import { readFile as readFile4 } from "fs/promises";
475
576
 
476
577
  // src/lib/fs.ts
477
578
  import { mkdir, rm, writeFile } from "fs/promises";
478
- import path from "path";
579
+ import path2 from "path";
479
580
  import extractZipArchive from "extract-zip";
480
581
  async function ensureDir(dirPath) {
481
582
  await mkdir(dirPath, { recursive: true });
@@ -485,7 +586,7 @@ async function resetDir(dirPath) {
485
586
  await mkdir(dirPath, { recursive: true });
486
587
  }
487
588
  async function writeUtf8(filePath, content) {
488
- await ensureDir(path.dirname(filePath));
589
+ await ensureDir(path2.dirname(filePath));
489
590
  await writeFile(filePath, content, "utf-8");
490
591
  }
491
592
  async function extractZip(zipPath, targetDir) {
@@ -499,13 +600,13 @@ async function extractZip(zipPath, targetDir) {
499
600
  }
500
601
 
501
602
  // src/services/page-copy-service.ts
502
- import { readFile as readFile2, readdir, stat as stat2, writeFile as writeFile2 } from "fs/promises";
503
- import path3 from "path";
603
+ import { readFile as readFile3, readdir, stat as stat3, writeFile as writeFile2 } from "fs/promises";
604
+ import path4 from "path";
504
605
 
505
606
  // src/lib/import-graph.ts
506
- import { readFile, stat } from "fs/promises";
607
+ import { readFile as readFile2, stat as stat2 } from "fs/promises";
507
608
  import { builtinModules } from "module";
508
- import path2 from "path";
609
+ import path3 from "path";
509
610
  var INTERNAL_EXTENSIONS = [
510
611
  ".ts",
511
612
  ".tsx",
@@ -574,14 +675,14 @@ function getExternalPackageName(specifier) {
574
675
  }
575
676
  async function pathExists(filePath) {
576
677
  try {
577
- await stat(filePath);
678
+ await stat2(filePath);
578
679
  return true;
579
680
  } catch {
580
681
  return false;
581
682
  }
582
683
  }
583
684
  async function resolveFileCandidate(candidateBase) {
584
- const ext = path2.extname(candidateBase);
685
+ const ext = path3.extname(candidateBase);
585
686
  if (ext) {
586
687
  if (await pathExists(candidateBase)) {
587
688
  return candidateBase;
@@ -595,13 +696,13 @@ async function resolveFileCandidate(candidateBase) {
595
696
  }
596
697
  }
597
698
  if (await pathExists(candidateBase)) {
598
- const stats = await stat(candidateBase);
699
+ const stats = await stat2(candidateBase);
599
700
  if (stats.isFile()) {
600
701
  return candidateBase;
601
702
  }
602
703
  if (stats.isDirectory()) {
603
704
  for (const extension of INTERNAL_EXTENSIONS) {
604
- const indexCandidate = path2.join(candidateBase, `index${extension}`);
705
+ const indexCandidate = path3.join(candidateBase, `index${extension}`);
605
706
  if (await pathExists(indexCandidate)) {
606
707
  return indexCandidate;
607
708
  }
@@ -623,13 +724,13 @@ async function resolveImportToFile(projectRoot, importerFilePath, specifier) {
623
724
  }
624
725
  let candidateBase = null;
625
726
  if (specifier.startsWith("@/")) {
626
- candidateBase = path2.join(projectRoot, "src", specifier.slice(2));
727
+ candidateBase = path3.join(projectRoot, "src", specifier.slice(2));
627
728
  } else if (specifier.startsWith("@root/")) {
628
- candidateBase = path2.join(projectRoot, specifier.slice(6));
729
+ candidateBase = path3.join(projectRoot, specifier.slice(6));
629
730
  } else if (specifier.startsWith(".")) {
630
- candidateBase = path2.resolve(path2.dirname(importerFilePath), specifier);
731
+ candidateBase = path3.resolve(path3.dirname(importerFilePath), specifier);
631
732
  } else if (specifier.startsWith("/")) {
632
- candidateBase = path2.join(projectRoot, specifier.slice(1));
733
+ candidateBase = path3.join(projectRoot, specifier.slice(1));
633
734
  } else {
634
735
  return { kind: "unknown" };
635
736
  }
@@ -643,11 +744,11 @@ async function resolveImportToFile(projectRoot, importerFilePath, specifier) {
643
744
  };
644
745
  }
645
746
  function shouldParseFile(filePath) {
646
- return PARSEABLE_EXTENSIONS.has(path2.extname(filePath).toLowerCase());
747
+ return PARSEABLE_EXTENSIONS.has(path3.extname(filePath).toLowerCase());
647
748
  }
648
749
  async function buildImportGraph(input) {
649
- const projectRoot = path2.resolve(input.projectRoot);
650
- const queue = input.entryFiles.map((filePath) => path2.resolve(filePath));
750
+ const projectRoot = path3.resolve(input.projectRoot);
751
+ const queue = input.entryFiles.map((filePath) => path3.resolve(filePath));
651
752
  const visited = /* @__PURE__ */ new Set();
652
753
  const internalFiles = /* @__PURE__ */ new Set();
653
754
  const externalPackages = /* @__PURE__ */ new Set();
@@ -663,7 +764,7 @@ async function buildImportGraph(input) {
663
764
  }
664
765
  let content = "";
665
766
  try {
666
- content = await readFile(currentFilePath, "utf-8");
767
+ content = await readFile2(currentFilePath, "utf-8");
667
768
  } catch {
668
769
  continue;
669
770
  }
@@ -900,10 +1001,10 @@ function normalizeSlug2(slug) {
900
1001
  return withLeadingSlash.replace(/\/+$/, "") || "/";
901
1002
  }
902
1003
  function toPosixPath(value) {
903
- return value.split(path3.sep).join("/");
1004
+ return value.split(path4.sep).join("/");
904
1005
  }
905
1006
  function toProjectRelative(rootPath, absolutePath) {
906
- return toPosixPath(path3.relative(rootPath, absolutePath));
1007
+ return toPosixPath(path4.relative(rootPath, absolutePath));
907
1008
  }
908
1009
  function escapeRegExp(value) {
909
1010
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -960,7 +1061,7 @@ function buildPlannedSourceBuffer(sourceBuffer, sourceFilePath, importRewritePla
960
1061
  if (!importRewritePlan) {
961
1062
  return sourceBuffer;
962
1063
  }
963
- const extension = path3.extname(sourceFilePath).toLowerCase();
1064
+ const extension = path4.extname(sourceFilePath).toLowerCase();
964
1065
  if (!REWRITABLE_IMPORT_EXTENSIONS.has(extension)) {
965
1066
  return sourceBuffer;
966
1067
  }
@@ -968,19 +1069,22 @@ function buildPlannedSourceBuffer(sourceBuffer, sourceFilePath, importRewritePla
968
1069
  return sourceBuffer;
969
1070
  }
970
1071
  const sourceText = sourceBuffer.toString("utf-8");
971
- const rewritten = rewriteImportsForRemappedSlug(sourceText, importRewritePlan);
1072
+ const rewritten = rewriteImportsForRemappedSlug(
1073
+ sourceText,
1074
+ importRewritePlan
1075
+ );
972
1076
  if (rewritten === sourceText) {
973
1077
  return sourceBuffer;
974
1078
  }
975
1079
  return Buffer.from(rewritten, "utf-8");
976
1080
  }
977
1081
  async function readJsonFile(filePath) {
978
- const content = await readFile2(filePath, "utf-8");
1082
+ const content = await readFile3(filePath, "utf-8");
979
1083
  return JSON.parse(content);
980
1084
  }
981
- async function fileExists(filePath) {
1085
+ async function fileExists2(filePath) {
982
1086
  try {
983
- await stat2(filePath);
1087
+ await stat3(filePath);
984
1088
  return true;
985
1089
  } catch {
986
1090
  return false;
@@ -1022,7 +1126,7 @@ async function listFilesRecursively(dirPath) {
1022
1126
  }
1023
1127
  const entries = await readdir(current, { withFileTypes: true });
1024
1128
  for (const entry of entries) {
1025
- const absolutePath = path3.join(current, entry.name);
1129
+ const absolutePath = path4.join(current, entry.name);
1026
1130
  if (entry.isDirectory()) {
1027
1131
  stack.push(absolutePath);
1028
1132
  continue;
@@ -1050,12 +1154,12 @@ async function resolveSingleExportDirectory(exportsRoot) {
1050
1154
  const exportId = exportDirectories[0] ?? "";
1051
1155
  return {
1052
1156
  exportId,
1053
- exportPath: path3.join(exportsRoot, exportId)
1157
+ exportPath: path4.join(exportsRoot, exportId)
1054
1158
  };
1055
1159
  }
1056
1160
  function ensureSafeTargetPath(projectRoot, targetPath) {
1057
- const relative = path3.relative(projectRoot, targetPath);
1058
- if (relative.startsWith("..") || path3.isAbsolute(relative)) {
1161
+ const relative = path4.relative(projectRoot, targetPath);
1162
+ if (relative.startsWith("..") || path4.isAbsolute(relative)) {
1059
1163
  throw new Error(
1060
1164
  `Refusing to write outside project root. Computed target: ${targetPath}`
1061
1165
  );
@@ -1113,19 +1217,19 @@ function resolveTargetFilePath(input) {
1113
1217
  if (sourceFilePath === sourcePagePath) {
1114
1218
  return targetPagePath;
1115
1219
  }
1116
- const componentsPrefix = `${sourceComponentsPath}${path3.sep}`;
1220
+ const componentsPrefix = `${sourceComponentsPath}${path4.sep}`;
1117
1221
  if (sourceFilePath === sourceComponentsPath || sourceFilePath.startsWith(componentsPrefix)) {
1118
- const relativeToComponents = path3.relative(
1222
+ const relativeToComponents = path4.relative(
1119
1223
  sourceComponentsPath,
1120
1224
  sourceFilePath
1121
1225
  );
1122
- return path3.join(targetComponentsPath, relativeToComponents);
1226
+ return path4.join(targetComponentsPath, relativeToComponents);
1123
1227
  }
1124
- const relativeToExport = path3.relative(exportRoot, sourceFilePath);
1125
- if (relativeToExport.startsWith("..") || path3.isAbsolute(relativeToExport)) {
1228
+ const relativeToExport = path4.relative(exportRoot, sourceFilePath);
1229
+ if (relativeToExport.startsWith("..") || path4.isAbsolute(relativeToExport)) {
1126
1230
  throw new Error(`Source file is outside export root: ${sourceFilePath}`);
1127
1231
  }
1128
- return path3.join(projectRoot, relativeToExport);
1232
+ return path4.join(projectRoot, relativeToExport);
1129
1233
  }
1130
1234
  async function copyPageFromExport(input) {
1131
1235
  const normalizedOriginSlug = normalizeSlug2(input.originPageSlug);
@@ -1136,11 +1240,11 @@ async function copyPageFromExport(input) {
1136
1240
  const { exportId, exportPath } = await resolveSingleExportDirectory(
1137
1241
  input.exportsRoot
1138
1242
  );
1139
- const manifestPath = path3.join(
1243
+ const manifestPath = path4.join(
1140
1244
  input.exportsRoot,
1141
1245
  `${exportId}.manifest.json`
1142
1246
  );
1143
- if (!await fileExists(manifestPath)) {
1247
+ if (!await fileExists2(manifestPath)) {
1144
1248
  throw new Error(
1145
1249
  `Export manifest is missing at ${manifestPath}. Run primeui_download_export to regenerate it.`
1146
1250
  );
@@ -1159,13 +1263,13 @@ async function copyPageFromExport(input) {
1159
1263
  `Page not found in manifest for slug: ${normalizedOriginSlug}`
1160
1264
  );
1161
1265
  }
1162
- const sourcePagePath = path3.join(exportPath, page.pagePath);
1163
- const sourceComponentsPath = path3.join(exportPath, page.componentsPath);
1164
- const sourcePageStats = await stat2(sourcePagePath).catch(() => null);
1266
+ const sourcePagePath = path4.join(exportPath, page.pagePath);
1267
+ const sourceComponentsPath = path4.join(exportPath, page.componentsPath);
1268
+ const sourcePageStats = await stat3(sourcePagePath).catch(() => null);
1165
1269
  if (!sourcePageStats?.isFile()) {
1166
1270
  throw new Error(`Source page file not found: ${sourcePagePath}`);
1167
1271
  }
1168
- const sourceComponentsStats = await stat2(sourceComponentsPath).catch(
1272
+ const sourceComponentsStats = await stat3(sourceComponentsPath).catch(
1169
1273
  () => null
1170
1274
  );
1171
1275
  if (!sourceComponentsStats?.isDirectory()) {
@@ -1180,8 +1284,8 @@ async function copyPageFromExport(input) {
1180
1284
  pageType: page.pageType,
1181
1285
  slug: normalizedActualSlug
1182
1286
  });
1183
- const targetPagePath = path3.join(input.projectRoot, targetPaths.pagePath);
1184
- const targetComponentsPath = path3.join(
1287
+ const targetPagePath = path4.join(input.projectRoot, targetPaths.pagePath);
1288
+ const targetComponentsPath = path4.join(
1185
1289
  input.projectRoot,
1186
1290
  targetPaths.componentsPath
1187
1291
  );
@@ -1211,7 +1315,7 @@ async function copyPageFromExport(input) {
1211
1315
  projectRoot: input.projectRoot
1212
1316
  });
1213
1317
  ensureSafeTargetPath(input.projectRoot, targetFilePath);
1214
- const sourceBuffer = await readFile2(sourceFilePath);
1318
+ const sourceBuffer = await readFile3(sourceFilePath);
1215
1319
  const plannedSourceBuffer = buildPlannedSourceBuffer(
1216
1320
  sourceBuffer,
1217
1321
  sourceFilePath,
@@ -1219,14 +1323,14 @@ async function copyPageFromExport(input) {
1219
1323
  );
1220
1324
  let targetBuffer = null;
1221
1325
  try {
1222
- targetBuffer = await readFile2(targetFilePath);
1326
+ targetBuffer = await readFile3(targetFilePath);
1223
1327
  } catch {
1224
1328
  targetBuffer = null;
1225
1329
  }
1226
1330
  const sourceRelative = toProjectRelative(exportPath, sourceFilePath);
1227
1331
  const targetRelative = toProjectRelative(input.projectRoot, targetFilePath);
1228
1332
  if (!targetBuffer) {
1229
- await ensureDir(path3.dirname(targetFilePath));
1333
+ await ensureDir(path4.dirname(targetFilePath));
1230
1334
  await writeFile2(targetFilePath, plannedSourceBuffer);
1231
1335
  newFiles.push({
1232
1336
  sourcePath: sourceRelative,
@@ -1255,12 +1359,12 @@ async function copyPageFromExport(input) {
1255
1359
  isBinary
1256
1360
  });
1257
1361
  }
1258
- const exportPackageJsonPath = path3.join(exportPath, "package.json");
1259
- const userPackageJsonPath = path3.join(input.projectRoot, "package.json");
1260
- if (!await fileExists(exportPackageJsonPath)) {
1362
+ const exportPackageJsonPath = path4.join(exportPath, "package.json");
1363
+ const userPackageJsonPath = path4.join(input.projectRoot, "package.json");
1364
+ if (!await fileExists2(exportPackageJsonPath)) {
1261
1365
  throw new Error(`Export package.json not found: ${exportPackageJsonPath}`);
1262
1366
  }
1263
- if (!await fileExists(userPackageJsonPath)) {
1367
+ if (!await fileExists2(userPackageJsonPath)) {
1264
1368
  throw new Error(`User package.json not found: ${userPackageJsonPath}`);
1265
1369
  }
1266
1370
  const exportPackageJson = await readJsonFile(
@@ -1347,7 +1451,7 @@ function isProjectPage(value) {
1347
1451
  return typeof maybe.id === "string" && typeof maybe.title === "string" && typeof maybe.slug === "string" && typeof maybe.pageType === "string" && typeof maybe.isReadyToExport === "boolean" && typeof maybe.pagePath === "string" && typeof maybe.componentsPath === "string";
1348
1452
  }
1349
1453
  function buildPagesSnapshotPath(exportsRoot, exportId) {
1350
- return path4.join(exportsRoot, `${exportId}.pages.snapshot.json`);
1454
+ return path5.join(exportsRoot, `${exportId}.pages.snapshot.json`);
1351
1455
  }
1352
1456
  function parsePagesSnapshot(value) {
1353
1457
  if (!value || typeof value !== "object") {
@@ -1376,9 +1480,9 @@ var ProjectSyncService = class {
1376
1480
  constructor(options) {
1377
1481
  this.projectRoot = options.projectRoot;
1378
1482
  this.provider = options.provider;
1379
- this.primeUiRoot = path4.join(this.projectRoot, ".primeui");
1380
- this.tempRoot = path4.join(this.primeUiRoot, "temp");
1381
- this.exportsRoot = path4.join(this.tempRoot, "exports");
1483
+ this.primeUiRoot = path5.join(this.projectRoot, ".primeui");
1484
+ this.tempRoot = path5.join(this.primeUiRoot, "temp");
1485
+ this.exportsRoot = path5.join(this.tempRoot, "exports");
1382
1486
  }
1383
1487
  async getProjectInfo() {
1384
1488
  await this.ensureTempLayout();
@@ -1415,8 +1519,8 @@ var ProjectSyncService = class {
1415
1519
  if (!selected) {
1416
1520
  throw new Error(`Export not found: ${id}`);
1417
1521
  }
1418
- const targetZipPath = path4.join(this.exportsRoot, `${id}.zip`);
1419
- const targetProjectPath = path4.join(this.exportsRoot, id);
1522
+ const targetZipPath = path5.join(this.exportsRoot, `${id}.zip`);
1523
+ const targetProjectPath = path5.join(this.exportsRoot, id);
1420
1524
  await ensureDir(this.exportsRoot);
1421
1525
  await this.provider.downloadExportArchive(id, targetZipPath);
1422
1526
  await resetDir(targetProjectPath);
@@ -1425,7 +1529,7 @@ var ProjectSyncService = class {
1425
1529
  let pagesSnapshot;
1426
1530
  try {
1427
1531
  const snapshotRaw = JSON.parse(
1428
- await readFile3(pagesSnapshotPath, "utf-8")
1532
+ await readFile4(pagesSnapshotPath, "utf-8")
1429
1533
  );
1430
1534
  pagesSnapshot = parsePagesSnapshot(snapshotRaw);
1431
1535
  } catch (error) {
@@ -1440,7 +1544,7 @@ var ProjectSyncService = class {
1440
1544
  );
1441
1545
  }
1442
1546
  const pages = pagesSnapshot.pages;
1443
- const manifestPath = path4.join(this.exportsRoot, `${id}.manifest.json`);
1547
+ const manifestPath = path5.join(this.exportsRoot, `${id}.manifest.json`);
1444
1548
  const manifest = {
1445
1549
  schemaVersion: 1,
1446
1550
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1468,61 +1572,61 @@ var ProjectSyncService = class {
1468
1572
  }
1469
1573
  async clearTemp() {
1470
1574
  await resetDir(this.tempRoot);
1471
- await writeUtf8(path4.join(this.tempRoot, ".gitkeep"), "");
1575
+ await writeUtf8(path5.join(this.tempRoot, ".gitkeep"), "");
1472
1576
  await ensureDir(this.exportsRoot);
1473
1577
  }
1474
1578
  async ensureTempLayout() {
1475
1579
  await ensureDir(this.primeUiRoot);
1476
1580
  await ensureDir(this.tempRoot);
1477
1581
  await ensureDir(this.exportsRoot);
1478
- await writeUtf8(path4.join(this.tempRoot, ".gitkeep"), "");
1582
+ await writeUtf8(path5.join(this.tempRoot, ".gitkeep"), "");
1479
1583
  }
1480
1584
  };
1481
1585
 
1482
1586
  // src/sources/api-provider.ts
1483
1587
  import { createWriteStream } from "fs";
1484
1588
  import { unlink } from "fs/promises";
1485
- import path5 from "path";
1589
+ import path6 from "path";
1486
1590
  import { Readable, Transform } from "stream";
1487
1591
  import { pipeline } from "stream/promises";
1488
- import { z as z2 } from "zod";
1592
+ import { z as z3 } from "zod";
1489
1593
  var DEFAULT_API_BASE_URL = "https://app.primeui.com/";
1490
1594
  var ZIP_CONTENT_TYPES = [
1491
1595
  "application/zip",
1492
1596
  "application/octet-stream",
1493
1597
  "application/x-zip-compressed"
1494
1598
  ];
1495
- var exportStatusSchema2 = z2.enum(["in_progress", "completed", "failed"]);
1496
- var projectPageSchema = z2.object({
1497
- id: z2.string(),
1498
- title: z2.string(),
1499
- slug: z2.string(),
1500
- pageType: z2.string(),
1501
- isReadyToExport: z2.boolean(),
1502
- pagePath: z2.string(),
1503
- componentsPath: z2.string()
1599
+ var exportStatusSchema2 = z3.enum(["in_progress", "completed", "failed"]);
1600
+ var projectPageSchema = z3.object({
1601
+ id: z3.string(),
1602
+ title: z3.string(),
1603
+ slug: z3.string(),
1604
+ pageType: z3.string(),
1605
+ isReadyToExport: z3.boolean(),
1606
+ pagePath: z3.string(),
1607
+ componentsPath: z3.string()
1504
1608
  });
1505
- var projectInfoSchema = z2.object({
1506
- projectId: z2.string(),
1507
- projectName: z2.string(),
1508
- metadata: z2.record(z2.unknown()),
1509
- pages: z2.array(projectPageSchema)
1609
+ var projectInfoSchema = z3.object({
1610
+ projectId: z3.string(),
1611
+ projectName: z3.string(),
1612
+ metadata: z3.record(z3.unknown()),
1613
+ pages: z3.array(projectPageSchema)
1510
1614
  });
1511
- var exportsResponseSchema = z2.object({
1512
- exports: z2.array(
1513
- z2.object({
1514
- id: z2.string(),
1615
+ var exportsResponseSchema = z3.object({
1616
+ exports: z3.array(
1617
+ z3.object({
1618
+ id: z3.string(),
1515
1619
  status: exportStatusSchema2,
1516
- createdAt: z2.string().datetime({ offset: true })
1620
+ createdAt: z3.string().datetime({ offset: true })
1517
1621
  })
1518
1622
  )
1519
1623
  });
1520
- var createExportResponseSchema = z2.object({
1521
- export: z2.object({
1522
- id: z2.string(),
1624
+ var createExportResponseSchema = z3.object({
1625
+ export: z3.object({
1626
+ id: z3.string(),
1523
1627
  status: exportStatusSchema2
1524
1628
  }),
1525
- pages: z2.array(projectPageSchema)
1629
+ pages: z3.array(projectPageSchema)
1526
1630
  });
1527
1631
  var PrimeUiApiContractError = class extends Error {
1528
1632
  constructor(endpoint, details) {
@@ -1651,7 +1755,7 @@ var ApiProjectDataProvider = class {
1651
1755
  if (!response.body) {
1652
1756
  throw new PrimeUiApiContractError(endpoint, "response body is empty");
1653
1757
  }
1654
- await ensureDir(path5.dirname(destinationPath));
1758
+ await ensureDir(path6.dirname(destinationPath));
1655
1759
  const zipStream = Readable.fromWeb(
1656
1760
  response.body
1657
1761
  );
@@ -1739,22 +1843,30 @@ var ApiProjectDataProvider = class {
1739
1843
 
1740
1844
  // src/service.ts
1741
1845
  async function main() {
1742
- const projectRoot = process.env.PRIMEUI_PROJECT_ROOT || process.cwd();
1743
- const apiKey = process.env.PRIMEUI_API_KEY;
1846
+ const resolvedProjectConfig = await resolvePrimeUiProjectConfig({
1847
+ cwd: process.cwd(),
1848
+ projectRootFromEnv: process.env.PRIMEUI_PROJECT_ROOT
1849
+ });
1850
+ const projectRoot = resolvedProjectConfig.projectRoot;
1851
+ const targetProjectRoot = path7.resolve(
1852
+ projectRoot,
1853
+ resolvedProjectConfig.projectConfig.targetProjectPath
1854
+ );
1855
+ const apiKey = await resolvePrimeUiApiKey({
1856
+ projectConfig: resolvedProjectConfig.projectConfig,
1857
+ apiKeyFromEnv: process.env.PRIMEUI_API_KEY
1858
+ });
1744
1859
  const provider = new ApiProjectDataProvider({
1745
1860
  apiKey,
1746
1861
  baseUrl: process.env.PRIMEUI_API_BASE_URL
1747
1862
  });
1748
- if (!apiKey) {
1749
- console.error(
1750
- "[primeui-mcp] warning: PRIMEUI_API_KEY is not set; API-backed tools will fail until it is configured."
1751
- );
1752
- }
1753
1863
  const syncService = new ProjectSyncService({ projectRoot, provider });
1754
1864
  const server = createPrimeUiMcpServer(syncService);
1755
1865
  const transport = new StdioServerTransport();
1756
1866
  await server.connect(transport);
1757
- console.error(`[primeui-mcp] running for root: ${projectRoot}`);
1867
+ console.error(
1868
+ `[primeui-mcp] running for root: ${projectRoot}; target project: ${targetProjectRoot}`
1869
+ );
1758
1870
  }
1759
1871
  main().catch((error) => {
1760
1872
  console.error("[primeui-mcp] failed to start", error);