@primeuicom/mcp 1.2.1 → 1.2.3

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
@@ -229,6 +229,7 @@ function buildProjectRootHint() {
229
229
  var primeUiProjectConfigSchema = z2.object({
230
230
  projectId: z2.string().trim().min(1),
231
231
  apiKey: z2.string().trim().min(1),
232
+ apiBaseUrl: z2.string().trim().url().optional(),
232
233
  targetProjectPath: z2.string().trim().regex(/^\.\/.*$/).optional()
233
234
  }).passthrough();
234
235
  var primeUiProjectConfigWithTargetPathSchema = primeUiProjectConfigSchema.superRefine((value, ctx) => {
@@ -519,6 +520,23 @@ async function resolvePrimeUiApiKey(options) {
519
520
  hint: "Set PRIMEUI_API_KEY or ensure apiKey is present in .primeui/project.json."
520
521
  });
521
522
  }
523
+ function resolvePrimeUiApiBaseUrlDetails(options) {
524
+ const envBaseUrl = options.baseUrlFromEnv?.trim();
525
+ const configBaseUrl = options.projectConfig?.apiBaseUrl?.trim();
526
+ const envProvided = Boolean(envBaseUrl);
527
+ const configProvided = Boolean(configBaseUrl);
528
+ const resolvedBaseUrl = envBaseUrl || configBaseUrl;
529
+ return {
530
+ baseUrl: resolvedBaseUrl,
531
+ source: envProvided ? "env" : configProvided ? "config" : "default",
532
+ envProvided,
533
+ configProvided,
534
+ valuesMatch: envProvided && configProvided ? envBaseUrl === configBaseUrl : void 0
535
+ };
536
+ }
537
+ function resolvePrimeUiApiBaseUrl(options) {
538
+ return resolvePrimeUiApiBaseUrlDetails(options).baseUrl;
539
+ }
522
540
 
523
541
  // src/sources/api-provider.ts
524
542
  import { createWriteStream } from "fs";
@@ -529,6 +547,9 @@ import { pipeline } from "stream/promises";
529
547
 
530
548
  // src/lib/api-v1-contract.ts
531
549
  import { z as z3 } from "zod";
550
+ var primeUiPageSlugInputSchema = z3.string().refine((value) => value.trim().length > 0, {
551
+ message: "pageSlug must be a non-empty string"
552
+ });
532
553
  var primeUiExportStatusSchema = z3.enum(
533
554
  ["in_progress", "completed", "failed"]
534
555
  );
@@ -639,6 +660,105 @@ var primeUiPageGenerationTypeSchema = z3.enum([
639
660
  "docs",
640
661
  "legal"
641
662
  ]);
663
+ var primeUiComponentCandidateOperationSchema = z3.discriminatedUnion("type", [
664
+ z3.object({
665
+ type: z3.literal("append")
666
+ }),
667
+ z3.object({
668
+ type: z3.literal("insert"),
669
+ index: z3.number().int()
670
+ }),
671
+ z3.object({
672
+ type: z3.literal("replace"),
673
+ index: z3.number().int()
674
+ })
675
+ ]);
676
+ var primeUiComponentCandidateConstraintsSchema = z3.object({
677
+ spreadDegree: z3.enum(["any-group", "same-group", "same-family"]).optional(),
678
+ allowedGroups: z3.array(z3.string()).optional(),
679
+ excludedGroups: z3.array(z3.string()).optional(),
680
+ excludeComponentIds: z3.array(z3.string()).optional()
681
+ });
682
+ var primeUiComponentCandidatesInputSchema = z3.object({
683
+ pageSlug: primeUiPageSlugInputSchema,
684
+ pageType: primeUiPageGenerationTypeSchema,
685
+ blocks: z3.array(
686
+ z3.object({
687
+ componentId: z3.string()
688
+ })
689
+ ),
690
+ operation: primeUiComponentCandidateOperationSchema,
691
+ count: z3.number().int().positive().optional(),
692
+ constraints: primeUiComponentCandidateConstraintsSchema.optional()
693
+ });
694
+ var primeUiComponentCandidateRequestEchoSchema = z3.object({
695
+ pageSlug: z3.string(),
696
+ pageType: z3.string(),
697
+ operation: primeUiComponentCandidateOperationSchema,
698
+ count: z3.number()
699
+ });
700
+ var requiredUnknownSchema = z3.custom((value) => value !== void 0);
701
+ var primeUiComponentCandidateLayoutObjectSchema = z3.object({
702
+ container: requiredUnknownSchema,
703
+ textAlignment: requiredUnknownSchema,
704
+ bottomWeight: requiredUnknownSchema,
705
+ entryWidth: requiredUnknownSchema,
706
+ exitWidth: requiredUnknownSchema,
707
+ orientation: requiredUnknownSchema,
708
+ structure: requiredUnknownSchema
709
+ });
710
+ var primeUiComponentCandidateLayoutSchema = z3.custom(
711
+ (value) => primeUiComponentCandidateLayoutObjectSchema.safeParse(value).success
712
+ );
713
+ var primeUiComponentCandidateObjectSchema = z3.object({
714
+ componentId: z3.string(),
715
+ name: z3.string(),
716
+ group: z3.string(),
717
+ familyId: z3.string(),
718
+ uxScore: z3.number(),
719
+ insertionScore: z3.number(),
720
+ followingScore: z3.number(),
721
+ layout: primeUiComponentCandidateLayoutSchema,
722
+ defaultProps: requiredUnknownSchema,
723
+ exportReady: z3.boolean(),
724
+ copyHints: z3.object({
725
+ deliveryToolchain: z3.array(z3.string())
726
+ }),
727
+ description: z3.string().nullable().optional(),
728
+ functionality: z3.string().nullable().optional(),
729
+ impression: z3.string().nullable().optional(),
730
+ visualStyle: z3.unknown().optional(),
731
+ compactSchema: z3.string().nullable().optional(),
732
+ jsonSchema: z3.record(z3.unknown()).nullable().optional()
733
+ });
734
+ var primeUiComponentCandidateSchema = z3.custom(
735
+ (value) => primeUiComponentCandidateObjectSchema.safeParse(value).success
736
+ );
737
+ var primeUiComponentCandidatesResponseSchema = z3.object({
738
+ request: primeUiComponentCandidateRequestEchoSchema,
739
+ candidates: z3.array(primeUiComponentCandidateSchema)
740
+ });
741
+ var primeUiComponentPropsValidateInputSchema = z3.object({
742
+ pageSlug: primeUiPageSlugInputSchema,
743
+ componentId: z3.string(),
744
+ props: z3.record(z3.unknown())
745
+ });
746
+ var primeUiComponentPropsValidationErrorSchema = z3.object({
747
+ path: z3.string(),
748
+ message: z3.string()
749
+ });
750
+ var primeUiComponentPropsRenderCheckSchema = z3.object({
751
+ attempted: z3.boolean(),
752
+ passed: z3.boolean(),
753
+ message: z3.string()
754
+ });
755
+ var primeUiComponentPropsValidateResponseSchema = z3.object({
756
+ valid: z3.boolean(),
757
+ normalizedProps: z3.record(z3.unknown()).nullable(),
758
+ errors: z3.array(primeUiComponentPropsValidationErrorSchema),
759
+ hints: z3.array(z3.string()),
760
+ renderCheck: primeUiComponentPropsRenderCheckSchema
761
+ });
642
762
  var primeUiProjectApiWireframeStatusSchema = z3.enum(["pending", "generating", "ready", "error"]);
643
763
  var primeUiProjectApiVariantSummarySchema = z3.object({
644
764
  id: z3.string(),
@@ -1145,6 +1265,20 @@ var ApiProjectDataProvider = class {
1145
1265
  primeUiProjectPageDetailsSchema
1146
1266
  );
1147
1267
  }
1268
+ async getComponentCandidates(input) {
1269
+ return this.requestJson(
1270
+ "component-planning/candidates",
1271
+ primeUiComponentCandidatesResponseSchema,
1272
+ this.buildJsonRequestInit(input)
1273
+ );
1274
+ }
1275
+ async validateComponentProps(input) {
1276
+ return this.requestJson(
1277
+ "component-planning/props/validate",
1278
+ primeUiComponentPropsValidateResponseSchema,
1279
+ this.buildJsonRequestInit(input)
1280
+ );
1281
+ }
1148
1282
  async listExports() {
1149
1283
  const response = await this.requestJson(
1150
1284
  "project/exports",
@@ -1856,19 +1990,23 @@ async function runHealthCheck(options) {
1856
1990
  apiKeyFromEnv: env.PRIMEUI_API_KEY
1857
1991
  });
1858
1992
  const configApiKeyState = resolvedProjectConfig ? "set" : configStatus === "missing" || configStatus === "unresolved" ? "missing" : "unknown";
1859
- const apiBaseUrlSource = env.PRIMEUI_API_BASE_URL?.trim() ? "env" : "default";
1993
+ const apiBaseUrlDetails = resolvePrimeUiApiBaseUrlDetails({
1994
+ projectConfig: resolvedProjectConfig?.projectConfig,
1995
+ baseUrlFromEnv: env.PRIMEUI_API_BASE_URL
1996
+ });
1997
+ const apiBaseUrlSource = apiBaseUrlDetails.source;
1860
1998
  const defaultApiRoot = normalizePrimeUiApiRoot(DEFAULT_API_BASE_URL);
1861
1999
  let apiRoot;
1862
2000
  let projectInfoUrl;
1863
2001
  let apiCheck;
1864
2002
  try {
1865
- apiRoot = normalizePrimeUiApiRoot(env.PRIMEUI_API_BASE_URL);
2003
+ apiRoot = normalizePrimeUiApiRoot(apiBaseUrlDetails.baseUrl);
1866
2004
  projectInfoUrl = buildPrimeUiApiUrl(apiRoot, "project");
1867
2005
  } catch (error) {
1868
2006
  apiCheck = {
1869
2007
  status: "skipped",
1870
2008
  apiBaseUrlSource,
1871
- nonStandardBaseUrl: Boolean(env.PRIMEUI_API_BASE_URL?.trim()),
2009
+ nonStandardBaseUrl: Boolean(apiBaseUrlDetails.baseUrl?.trim()),
1872
2010
  message: error instanceof Error ? error.message : String(error),
1873
2011
  errorKind: "configuration"
1874
2012
  };
@@ -1886,10 +2024,10 @@ async function runHealthCheck(options) {
1886
2024
  } else {
1887
2025
  const provider = options.createProvider?.({
1888
2026
  apiKey: apiKeyDetails.apiKey,
1889
- baseUrl: env.PRIMEUI_API_BASE_URL
2027
+ baseUrl: apiBaseUrlDetails.baseUrl
1890
2028
  }) ?? new ApiProjectDataProvider({
1891
2029
  apiKey: apiKeyDetails.apiKey,
1892
- baseUrl: env.PRIMEUI_API_BASE_URL
2030
+ baseUrl: apiBaseUrlDetails.baseUrl
1893
2031
  });
1894
2032
  try {
1895
2033
  await provider.getProjectInfo();
@@ -3741,6 +3879,15 @@ var PACKAGE_JSON_RELATIVE_PATH2 = "package.json";
3741
3879
  var VIRTUAL_ROUTE_SEGMENT = "__primeui-component-export";
3742
3880
  var COMPONENT_PAGES_PREFIX = "src/components/pages/";
3743
3881
  var COMPONENT_UI_PREFIX = "src/components/ui/";
3882
+ var COMPONENT_SHARED_PREFIX = "src/components/shared/";
3883
+ var NATURAL_SUPPORT_PREFIXES = [
3884
+ COMPONENT_UI_PREFIX,
3885
+ "src/lib/",
3886
+ "src/types/",
3887
+ "src/contexts/"
3888
+ ];
3889
+ var PUBLIC_PREFIX = "public/";
3890
+ var PUBLIC_ASSET_REFERENCE_RE = /["'`(]\/([^"'`()\s]+\.(?:avif|gif|ico|jpeg|jpg|json|mp4|otf|png|svg|ttf|txt|webm|webmanifest|webp|woff|woff2|xml))(?:\?[^"'`()\s]*)?["'`)]/giu;
3744
3891
  function normalizeComponentId(componentId) {
3745
3892
  const trimmed = componentId.trim();
3746
3893
  if (!trimmed) {
@@ -3773,6 +3920,35 @@ function isVirtualRouteFile(relativePath) {
3773
3920
  const segments = relativePath.split("/");
3774
3921
  return segments[0] === "src" && segments[1] === "app" && segments.includes(VIRTUAL_ROUTE_SEGMENT);
3775
3922
  }
3923
+ function getVirtualComponentRelativePath(relativePath, componentId) {
3924
+ const prefix = `${COMPONENT_PAGES_PREFIX}${VIRTUAL_ROUTE_SEGMENT}/${componentId}/`;
3925
+ if (!relativePath.startsWith(prefix)) {
3926
+ return null;
3927
+ }
3928
+ const componentRelativePath = relativePath.slice(prefix.length);
3929
+ return componentRelativePath || null;
3930
+ }
3931
+ function getComponentPageSourceArea(relativePath) {
3932
+ if (!relativePath.startsWith(COMPONENT_PAGES_PREFIX)) {
3933
+ return null;
3934
+ }
3935
+ const rest = relativePath.slice(COMPONENT_PAGES_PREFIX.length);
3936
+ const slashIndex = rest.indexOf("/");
3937
+ if (slashIndex <= 0) {
3938
+ return null;
3939
+ }
3940
+ const sourceArea = rest.slice(0, slashIndex);
3941
+ return sourceArea === VIRTUAL_ROUTE_SEGMENT ? null : sourceArea;
3942
+ }
3943
+ function getSourceAreaComponentRelativePath(relativePath, sourceAreas) {
3944
+ const sourceArea = getComponentPageSourceArea(relativePath);
3945
+ if (!sourceArea || !sourceAreas.has(sourceArea)) {
3946
+ return null;
3947
+ }
3948
+ const prefix = `${COMPONENT_PAGES_PREFIX}${sourceArea}/`;
3949
+ const componentRelativePath = relativePath.slice(prefix.length);
3950
+ return componentRelativePath || null;
3951
+ }
3776
3952
  function isComponentEntryFile(relativePath, componentId) {
3777
3953
  if (!relativePath.startsWith(COMPONENT_PAGES_PREFIX)) {
3778
3954
  return false;
@@ -3788,7 +3964,155 @@ function isComponentEntryFile(relativePath, componentId) {
3788
3964
  return basename === "index" && path13.basename(path13.dirname(relativePath)) === componentId;
3789
3965
  }
3790
3966
  function isManifestSupportFile(relativePath) {
3791
- return relativePath.startsWith(COMPONENT_UI_PREFIX);
3967
+ return NATURAL_SUPPORT_PREFIXES.some(
3968
+ (prefix) => relativePath.startsWith(prefix)
3969
+ );
3970
+ }
3971
+ function isEnvFile(relativePath) {
3972
+ return relativePath === ".env" || relativePath.startsWith(".env.");
3973
+ }
3974
+ function isSearchRuntimeFile(relativePath) {
3975
+ return relativePath.startsWith("src/app/api/search/") || relativePath.startsWith("src/lib/search/") || relativePath.startsWith("src/lib/search-runtime/") || relativePath.startsWith("src/search/");
3976
+ }
3977
+ function isProjectLevelFile(relativePath) {
3978
+ return isEnvFile(relativePath) || isSearchRuntimeFile(relativePath) || relativePath.startsWith("scripts/") || relativePath.startsWith("src/app/") || relativePath.startsWith("src/components/header/") || relativePath.startsWith("src/components/footer/") || relativePath.startsWith("src/components/layout/");
3979
+ }
3980
+ function toComponentSharedTargetPath(componentRelativePath) {
3981
+ return `${COMPONENT_SHARED_PREFIX}${componentRelativePath}`;
3982
+ }
3983
+ function toImportPath(relativePath) {
3984
+ const withoutExtension = relativePath.replace(/\.[cm]?[jt]sx?$/u, "");
3985
+ const withoutIndex = withoutExtension.replace(/\/index$/u, "");
3986
+ return `@/${withoutIndex.replace(/^src\//u, "")}`;
3987
+ }
3988
+ function escapeRegExp(value) {
3989
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
3990
+ }
3991
+ function sourceImportSpecifiers(relativePath) {
3992
+ const withAlias = toImportPath(relativePath);
3993
+ const specifiers = [withAlias];
3994
+ if (withAlias.endsWith("/index")) {
3995
+ specifiers.push(withAlias.replace(/\/index$/u, ""));
3996
+ }
3997
+ return [...new Set(specifiers)];
3998
+ }
3999
+ function rewriteComponentLocalImports(content, transfers) {
4000
+ let updated = content;
4001
+ for (const transfer of transfers) {
4002
+ const targetSpecifier = toImportPath(transfer.targetPath);
4003
+ for (const sourceSpecifier of sourceImportSpecifiers(transfer.sourcePath)) {
4004
+ updated = updated.replace(
4005
+ new RegExp(escapeRegExp(sourceSpecifier), "gu"),
4006
+ targetSpecifier
4007
+ );
4008
+ }
4009
+ }
4010
+ return updated;
4011
+ }
4012
+ function collectReferencedPublicAssetFiles(content) {
4013
+ const referencedFiles = /* @__PURE__ */ new Set();
4014
+ let match = null;
4015
+ PUBLIC_ASSET_REFERENCE_RE.lastIndex = 0;
4016
+ while ((match = PUBLIC_ASSET_REFERENCE_RE.exec(content)) !== null) {
4017
+ const referencedPath = match[1]?.trim();
4018
+ if (referencedPath) {
4019
+ referencedFiles.add(
4020
+ `${PUBLIC_PREFIX}${normalizeManifestFilePath(referencedPath)}`
4021
+ );
4022
+ }
4023
+ }
4024
+ return [...referencedFiles];
4025
+ }
4026
+ function findComponentSourceAreas(relativePaths) {
4027
+ const sourceAreas = /* @__PURE__ */ new Set();
4028
+ for (const relativePath of relativePaths) {
4029
+ const sourceArea = getComponentPageSourceArea(relativePath);
4030
+ if (sourceArea) {
4031
+ sourceAreas.add(sourceArea);
4032
+ }
4033
+ }
4034
+ return sourceAreas;
4035
+ }
4036
+ function getComponentLocalTargetPath(input) {
4037
+ const virtualRelativePath = getVirtualComponentRelativePath(
4038
+ input.relativePath,
4039
+ input.componentId
4040
+ );
4041
+ if (virtualRelativePath) {
4042
+ return toComponentSharedTargetPath(virtualRelativePath);
4043
+ }
4044
+ const sourceAreaRelativePath = getSourceAreaComponentRelativePath(
4045
+ input.relativePath,
4046
+ input.sourceAreas
4047
+ );
4048
+ if (sourceAreaRelativePath) {
4049
+ return toComponentSharedTargetPath(sourceAreaRelativePath);
4050
+ }
4051
+ return null;
4052
+ }
4053
+ function getTransferTargetPath(input) {
4054
+ if (input.relativePath === PACKAGE_JSON_RELATIVE_PATH2 || isVirtualRouteFile(input.relativePath) || isProjectLevelFile(input.relativePath)) {
4055
+ return null;
4056
+ }
4057
+ const componentLocalTargetPath = getComponentLocalTargetPath(input);
4058
+ if (componentLocalTargetPath) {
4059
+ return componentLocalTargetPath;
4060
+ }
4061
+ if (isManifestSupportFile(input.relativePath)) {
4062
+ return input.relativePath;
4063
+ }
4064
+ if (input.relativePath.startsWith(PUBLIC_PREFIX) && input.referencedPublicFiles.has(input.relativePath)) {
4065
+ return input.relativePath;
4066
+ }
4067
+ return null;
4068
+ }
4069
+ async function collectReferencedPublicFiles(input) {
4070
+ const referencedPublicFiles = /* @__PURE__ */ new Set();
4071
+ for (const relativePath of input.graphInternalFiles) {
4072
+ if (!input.manifestFileSet.has(relativePath)) {
4073
+ continue;
4074
+ }
4075
+ const sourcePath = path13.join(input.exportPath, relativePath);
4076
+ let content = "";
4077
+ try {
4078
+ content = await readFile7(sourcePath, "utf-8");
4079
+ } catch {
4080
+ continue;
4081
+ }
4082
+ for (const referencedFile of collectReferencedPublicAssetFiles(content)) {
4083
+ if (input.manifestFileSet.has(referencedFile)) {
4084
+ referencedPublicFiles.add(referencedFile);
4085
+ }
4086
+ }
4087
+ }
4088
+ return referencedPublicFiles;
4089
+ }
4090
+ function buildFileTransfers(input) {
4091
+ const sourceAreas = findComponentSourceAreas([...input.graphInternalFiles]);
4092
+ const transfers = [];
4093
+ const usedTargetPaths = /* @__PURE__ */ new Set();
4094
+ for (const relativePath of input.files) {
4095
+ const isGraphFile = input.graphInternalFiles.has(relativePath);
4096
+ const isReferencedPublicFile = input.referencedPublicFiles.has(relativePath);
4097
+ if (!isGraphFile && !isReferencedPublicFile) {
4098
+ continue;
4099
+ }
4100
+ const targetPath = getTransferTargetPath({
4101
+ relativePath,
4102
+ componentId: input.componentId,
4103
+ sourceAreas,
4104
+ referencedPublicFiles: input.referencedPublicFiles
4105
+ });
4106
+ if (!targetPath || usedTargetPaths.has(targetPath)) {
4107
+ continue;
4108
+ }
4109
+ usedTargetPaths.add(targetPath);
4110
+ transfers.push({
4111
+ sourcePath: relativePath,
4112
+ targetPath
4113
+ });
4114
+ }
4115
+ return transfers.sort((a, b) => a.targetPath.localeCompare(b.targetPath));
3792
4116
  }
3793
4117
  function toSkippedFile(targetPath, reason) {
3794
4118
  return {
@@ -3828,7 +4152,7 @@ function splitManifestFiles(input) {
3828
4152
  };
3829
4153
  }
3830
4154
  async function createConflictReportEntry2(input) {
3831
- const sourceBuffer = await readFile7(input.sourceFilePath);
4155
+ const sourceBuffer = input.sourceBuffer ?? await readFile7(input.sourceFilePath);
3832
4156
  let targetBuffer = null;
3833
4157
  try {
3834
4158
  targetBuffer = await readFile7(input.targetFilePath);
@@ -3896,7 +4220,7 @@ function buildMessage(input) {
3896
4220
  );
3897
4221
  }
3898
4222
  parts.push(
3899
- "The virtual component export page was skipped; manually insert the copied component into a real target page."
4223
+ `The virtual component export page was skipped; manually import ${input.componentImportPath} into a real target page.`
3900
4224
  );
3901
4225
  return parts.join(" ");
3902
4226
  }
@@ -3963,23 +4287,39 @@ async function copyRegistryComponentFromExport(input) {
3963
4287
  (filePath) => toProjectRelative(exportPath, filePath)
3964
4288
  )
3965
4289
  );
3966
- const exportableFileSet = new Set(
3967
- uniqueNormalizedManifestFiles(getSuccessfulExportableFiles(manifest))
4290
+ const referencedPublicFiles = await collectReferencedPublicFiles({
4291
+ exportPath,
4292
+ graphInternalFiles,
4293
+ manifestFileSet
4294
+ });
4295
+ const fileTransfers = buildFileTransfers({
4296
+ files: initialSelection.manifestFiles,
4297
+ componentId: normalizedComponentId,
4298
+ graphInternalFiles,
4299
+ referencedPublicFiles
4300
+ });
4301
+ const copyableSourceFiles = fileTransfers.map(
4302
+ (transfer) => transfer.sourcePath
4303
+ );
4304
+ const copyableFiles = fileTransfers.map((transfer) => transfer.targetPath);
4305
+ const transferBySourcePath = new Map(
4306
+ fileTransfers.map((transfer) => [transfer.sourcePath, transfer])
4307
+ );
4308
+ const componentEntryTransfer = fileTransfers.find(
4309
+ (transfer) => initialSelection.componentEntryFiles.includes(transfer.sourcePath)
4310
+ );
4311
+ const componentImportPath = toImportPath(
4312
+ componentEntryTransfer?.targetPath ?? `${COMPONENT_SHARED_PREFIX}${normalizedComponentId}.tsx`
3968
4313
  );
3969
- const copyableFiles = initialSelection.manifestFiles.filter(
3970
- (relativePath) => graphInternalFiles.has(relativePath) || isManifestSupportFile(relativePath) || exportableFileSet.has(relativePath)
3971
- ).filter(
3972
- (relativePath) => relativePath !== PACKAGE_JSON_RELATIVE_PATH2 && !isVirtualRouteFile(relativePath)
3973
- ).sort((a, b) => a.localeCompare(b));
3974
4314
  const { manifestFiles, skippedFiles } = splitManifestFiles({
3975
4315
  files: initialSelection.manifestFiles,
3976
4316
  componentId: normalizedComponentId,
3977
- copyableFiles
4317
+ copyableFiles: copyableSourceFiles
3978
4318
  });
3979
4319
  const candidateFiles = await resolveManifestCandidateFiles({
3980
4320
  exportPath,
3981
4321
  manifestOwnerLabel: `registry component "${normalizedComponentId}"`,
3982
- files: copyableFiles,
4322
+ files: copyableSourceFiles,
3983
4323
  requireExisting: false
3984
4324
  });
3985
4325
  for (const sourceFilePath of candidateFiles) {
@@ -3989,9 +4329,21 @@ async function copyRegistryComponentFromExport(input) {
3989
4329
  missingManifestFiles.add(relativeToExport);
3990
4330
  continue;
3991
4331
  }
3992
- const targetFilePath = path13.join(input.projectRoot, relativeToExport);
4332
+ const transfer = transferBySourcePath.get(relativeToExport);
4333
+ if (!transfer) {
4334
+ continue;
4335
+ }
4336
+ const targetRelativePath = transfer.targetPath;
4337
+ const targetFilePath = path13.join(input.projectRoot, targetRelativePath);
3993
4338
  ensureSafeTargetPath(input.projectRoot, targetFilePath);
3994
4339
  const sourceBuffer = await readFile7(sourceFilePath);
4340
+ const rewrittenSourceBuffer = isBinaryBuffer(sourceBuffer) ? sourceBuffer : Buffer.from(
4341
+ rewriteComponentLocalImports(
4342
+ sourceBuffer.toString("utf-8"),
4343
+ fileTransfers
4344
+ ),
4345
+ "utf-8"
4346
+ );
3995
4347
  let targetBuffer = null;
3996
4348
  try {
3997
4349
  targetBuffer = await readFile7(targetFilePath);
@@ -4000,19 +4352,20 @@ async function copyRegistryComponentFromExport(input) {
4000
4352
  }
4001
4353
  if (!targetBuffer) {
4002
4354
  await ensureDir(path13.dirname(targetFilePath));
4003
- await writeFile6(targetFilePath, sourceBuffer);
4004
- newFiles.push(relativeToExport);
4355
+ await writeFile6(targetFilePath, rewrittenSourceBuffer);
4356
+ newFiles.push(targetRelativePath);
4005
4357
  continue;
4006
4358
  }
4007
- if (sourceBuffer.equals(targetBuffer)) {
4008
- identicalFiles.push(relativeToExport);
4359
+ if (rewrittenSourceBuffer.equals(targetBuffer)) {
4360
+ identicalFiles.push(targetRelativePath);
4009
4361
  continue;
4010
4362
  }
4011
4363
  const entry = await createConflictReportEntry2({
4012
4364
  sourceFilePath,
4013
4365
  targetFilePath,
4014
4366
  exportPath,
4015
- projectRoot: input.projectRoot
4367
+ projectRoot: input.projectRoot,
4368
+ sourceBuffer: rewrittenSourceBuffer
4016
4369
  });
4017
4370
  if (entry) {
4018
4371
  conflictReportEntries.push(entry);
@@ -4053,6 +4406,7 @@ async function copyRegistryComponentFromExport(input) {
4053
4406
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4054
4407
  exportId,
4055
4408
  componentId: normalizedComponentId,
4409
+ componentImportPath,
4056
4410
  manifestFiles,
4057
4411
  copyableFiles,
4058
4412
  skippedFiles,
@@ -4074,6 +4428,7 @@ async function copyRegistryComponentFromExport(input) {
4074
4428
  status,
4075
4429
  message: buildMessage({
4076
4430
  componentId: normalizedComponentId,
4431
+ componentImportPath,
4077
4432
  status,
4078
4433
  reportPath,
4079
4434
  newFiles: sortedNewFiles,
@@ -4089,6 +4444,7 @@ async function copyRegistryComponentFromExport(input) {
4089
4444
  exportPath,
4090
4445
  manifestPath,
4091
4446
  component: manifest.component,
4447
+ componentImportPath,
4092
4448
  manifestFiles,
4093
4449
  copyableFiles,
4094
4450
  newFiles: sortedNewFiles,
@@ -4111,7 +4467,7 @@ async function copyRegistryComponentFromExport(input) {
4111
4467
  },
4112
4468
  guidance: {
4113
4469
  artifacts: guidanceArtifacts,
4114
- requiredActions: "Do not install the skipped virtual component export page as a route. Manually import the copied component/support files into a real target page, install newly added dependencies, and resolve any reported conflicts or dependency version mismatches before treating the registry component transfer as complete."
4470
+ requiredActions: `Do not install the skipped virtual component export page as a route. Manually import ${componentImportPath} into a real target page, install newly added dependencies, and resolve any reported conflicts or dependency version mismatches before treating the registry component transfer as complete.`
4115
4471
  }
4116
4472
  };
4117
4473
  }
@@ -4294,6 +4650,12 @@ var ProjectSyncService = class {
4294
4650
  notes: guidanceNotes
4295
4651
  };
4296
4652
  }
4653
+ async getComponentCandidates(input, _context) {
4654
+ return this.provider.getComponentCandidates(input);
4655
+ }
4656
+ async validateComponentProps(input, _context) {
4657
+ return this.provider.validateComponentProps(input);
4658
+ }
4297
4659
  async listExports(_context) {
4298
4660
  await this.ensureTempLayout();
4299
4661
  return this.provider.listExports();
@@ -4552,10 +4914,14 @@ var LazyProjectSyncSource = class {
4552
4914
  projectConfig: resolvedProjectConfig.projectConfig,
4553
4915
  apiKeyFromEnv: this.env.PRIMEUI_API_KEY
4554
4916
  });
4917
+ const baseUrl = resolvePrimeUiApiBaseUrl({
4918
+ projectConfig: resolvedProjectConfig.projectConfig,
4919
+ baseUrlFromEnv: this.env.PRIMEUI_API_BASE_URL
4920
+ });
4555
4921
  this.stickyProjectRoot = projectRoot;
4556
4922
  const provider = this.createProvider({
4557
4923
  apiKey,
4558
- baseUrl: this.env.PRIMEUI_API_BASE_URL
4924
+ baseUrl
4559
4925
  });
4560
4926
  return new ProjectSyncService({
4561
4927
  projectRoot,
@@ -4738,6 +5104,24 @@ var LazyProjectSyncSource = class {
4738
5104
  (service) => service.syncSearchEnvironment(environmentSlug, context)
4739
5105
  );
4740
5106
  }
5107
+ async getComponentCandidates(input, context) {
5108
+ return this.withService(
5109
+ context,
5110
+ (service) => service.getComponentCandidates(input, context),
5111
+ {
5112
+ requireTargetProjectRoot: false
5113
+ }
5114
+ );
5115
+ }
5116
+ async validateComponentProps(input, context) {
5117
+ return this.withService(
5118
+ context,
5119
+ (service) => service.validateComponentProps(input, context),
5120
+ {
5121
+ requireTargetProjectRoot: false
5122
+ }
5123
+ );
5124
+ }
4741
5125
  async listExports(context) {
4742
5126
  return this.withService(context, (service) => service.listExports(context));
4743
5127
  }
@@ -5032,7 +5416,8 @@ ${WORKFLOW_SUMMARY}
5032
5416
 
5033
5417
  ADDITIONAL CAPABILITIES:
5034
5418
  - PrimeUI MCP also exposes atomic external API tools for project description, project pages, page variants, active-variant selection, and issue reports.
5035
- - These atomic tools are OPTIONAL additional capabilities for extended scenarios.
5419
+ - PrimeUI MCP also exposes component planning tools such as component_candidates_get and component_props_validate for exported-project page building.
5420
+ - These additional tools are OPTIONAL capabilities for extended scenarios.
5036
5421
  - They are NOT part of the primary import/export workflow above.
5037
5422
  - Do not replace get_project_info/create_export/download_export/copy_* with the additional API tools when the user wants the standard page import/export flow.
5038
5423
 
@@ -5594,10 +5979,12 @@ WHEN TO USE:
5594
5979
  BEHAVIOR:
5595
5980
  - Reads the component sidecar manifest saved by create_component_export.
5596
5981
  - Validates that manifest.component.componentId matches input.componentId.
5597
- - Copies files strictly from page.manifest.files in the component sidecar manifest.
5982
+ - Copies only the selected registry component import graph, narrowly referenced public assets, and safe support files from the component sidecar manifest/export.
5983
+ - Remaps component-local files into src/components/shared/** and returns componentImportPath for manual insertion.
5598
5984
  - Skips virtual route files that include __primeui-component-export, because those are reference/insertion hints and must not be installed as normal app routes.
5985
+ - Skips app/search/layout/header/footer/env/project-shell files instead of copying whole exportable buckets.
5599
5986
  - Never copies package.json directly. package.json is used only to add missing dependency entries and report dependency version conflicts.
5600
- - Preserves export-relative paths for copied files in this first version.
5987
+ - Keeps safe support files on their natural target paths, such as src/components/ui/**, src/lib/**, src/types/**, and src/contexts/**.
5601
5988
  - Never overwrites existing conflicting files.
5602
5989
  - Writes full conflict details to .primeui/temp/exports/[exportId].copy-registry-component-report-[copyId].json.
5603
5990
  - Reports copied files, identical files, conflicts, skipped files, dependency additions, dependency version conflicts, missing manifest files, and manual insertion guidance.
@@ -5628,11 +6015,14 @@ ${WORKFLOW_SUMMARY}`,
5628
6015
  component: componentExportComponentSchema.describe(
5629
6016
  "Component metadata from the validated component sidecar manifest."
5630
6017
  ),
6018
+ componentImportPath: z4.string().describe(
6019
+ "Canonical import path for the copied registry component entrypoint, for example @/components/shared/hero--pricing."
6020
+ ),
5631
6021
  manifestFiles: z4.array(z4.string()).describe(
5632
- "Normalized page.manifest.files from the component sidecar manifest."
6022
+ "Normalized component sidecar manifest files considered by the copy service."
5633
6023
  ),
5634
6024
  copyableFiles: z4.array(z4.string()).describe(
5635
- "Manifest files considered for copying after filtering virtual route files and package.json."
6025
+ "Relative target paths considered for copying after component remapping and safety filtering."
5636
6026
  ),
5637
6027
  newFiles: z4.array(z4.string()).describe("Relative target paths for new files copied."),
5638
6028
  identicalFiles: z4.array(z4.string()).describe("Relative target paths for existing byte-identical files."),
@@ -5821,6 +6211,122 @@ var pageGenerationTypeSchema = z4.enum([
5821
6211
  ]).describe(
5822
6212
  "Supported PrimeUI page type. Must match the external API page type enum."
5823
6213
  );
6214
+ var componentCandidateOperationSchema = z4.discriminatedUnion("type", [
6215
+ z4.object({
6216
+ type: z4.literal("append")
6217
+ }),
6218
+ z4.object({
6219
+ type: z4.literal("insert"),
6220
+ index: z4.number().int().describe("Zero-based insertion index in the ordered blocks list.")
6221
+ }),
6222
+ z4.object({
6223
+ type: z4.literal("replace"),
6224
+ index: z4.number().int().describe("Zero-based index of the block being replaced.")
6225
+ })
6226
+ ]);
6227
+ var componentCandidatesGetInputSchema = z4.object({
6228
+ projectRoot: projectRootInputSchema,
6229
+ pageSlug: z4.string().refine((value) => value.trim().length > 0, {
6230
+ message: "pageSlug must be a non-empty string"
6231
+ }).describe(
6232
+ "Stable PrimeUI page slug used for candidate scoring and automatic diagnostics, for example '/pricing'."
6233
+ ),
6234
+ pageType: pageGenerationTypeSchema,
6235
+ blocks: z4.array(
6236
+ z4.object({
6237
+ componentId: z4.string().describe("PrimeUI component id already present in page order.")
6238
+ })
6239
+ ).describe(
6240
+ "Current ordered page composition before applying the requested operation."
6241
+ ),
6242
+ operation: componentCandidateOperationSchema.optional().default({ type: "append" }).describe(
6243
+ "Candidate placement operation. Omit for the normal append flow."
6244
+ ),
6245
+ count: z4.number().int().positive().optional().describe("Optional maximum candidate count. Studio defaults to 8."),
6246
+ constraints: z4.object({
6247
+ spreadDegree: z4.enum(["any-group", "same-group", "same-family"]).optional().describe("Optional UX scoring spread override."),
6248
+ allowedGroups: z4.array(z4.string()).optional().describe("Optional allow-list of candidate groups."),
6249
+ excludedGroups: z4.array(z4.string()).optional().describe("Optional deny-list of candidate groups."),
6250
+ excludeComponentIds: z4.array(z4.string()).optional().describe("Optional component ids to remove from the candidate pool.")
6251
+ }).optional().describe("Optional advanced candidate pool and spread constraints.")
6252
+ });
6253
+ var componentCandidatesGetValidationSchema = componentCandidatesGetInputSchema;
6254
+ var componentPropsValidateInputSchema = z4.object({
6255
+ projectRoot: projectRootInputSchema,
6256
+ pageSlug: z4.string().refine((value) => value.trim().length > 0, {
6257
+ message: "pageSlug must be a non-empty string"
6258
+ }).describe(
6259
+ "Stable PrimeUI page slug used for validation diagnostics, for example '/pricing'. Use the same pageSlug as candidate retrieval."
6260
+ ),
6261
+ componentId: z4.string().describe("PrimeUI component registry identifier selected by the agent."),
6262
+ props: z4.record(z4.unknown()).describe(
6263
+ "Agent-authored props payload to validate against PrimeUI's registry schema."
6264
+ )
6265
+ });
6266
+ var componentPropsValidateValidationSchema = componentPropsValidateInputSchema;
6267
+ var componentCandidateLayoutSchema = z4.object({
6268
+ container: z4.unknown().describe("Layout container metadata."),
6269
+ textAlignment: z4.unknown().describe("Text alignment metadata."),
6270
+ bottomWeight: z4.unknown().describe("Bottom visual weight metadata."),
6271
+ entryWidth: z4.unknown().describe("Incoming width rhythm metadata."),
6272
+ exitWidth: z4.unknown().describe("Outgoing width rhythm metadata."),
6273
+ orientation: z4.unknown().describe("Optional orientation metadata."),
6274
+ structure: z4.unknown().describe("Optional structure metadata.")
6275
+ });
6276
+ var componentCandidateSchema = z4.object({
6277
+ componentId: z4.string().describe("PrimeUI component registry identifier to choose or export."),
6278
+ name: z4.string().describe("Human-readable component name."),
6279
+ group: z4.string().describe("Component group used by candidate scoring."),
6280
+ familyId: z4.string().describe("Component family identifier from catalog."),
6281
+ uxScore: z4.number().describe("Total UX score used for ranking."),
6282
+ insertionScore: z4.number().describe("Score for inserting this candidate at the requested position."),
6283
+ followingScore: z4.number().describe("Neighbor compatibility score with the following block."),
6284
+ layout: componentCandidateLayoutSchema.describe(
6285
+ "Layout metadata useful for choosing visual rhythm."
6286
+ ),
6287
+ defaultProps: z4.unknown().describe("Registry default props, when available from PrimeUI."),
6288
+ exportReady: z4.boolean().describe("True when the component is expected to be exportable."),
6289
+ copyHints: z4.object({
6290
+ deliveryToolchain: z4.array(z4.string()).describe(
6291
+ "Recommended tool sequence for delivering this registry component locally."
6292
+ )
6293
+ }).describe("Machine-readable delivery hints for the selected candidate."),
6294
+ description: z4.string().nullable().optional(),
6295
+ functionality: z4.string().nullable().optional(),
6296
+ impression: z4.string().nullable().optional(),
6297
+ visualStyle: z4.unknown().optional(),
6298
+ compactSchema: z4.string().nullable().optional(),
6299
+ jsonSchema: z4.record(z4.unknown()).nullable().optional()
6300
+ });
6301
+ var componentCandidatesGetOutputSchema = z4.object({
6302
+ request: z4.object({
6303
+ pageSlug: z4.string(),
6304
+ pageType: z4.string(),
6305
+ operation: componentCandidateOperationSchema,
6306
+ count: z4.number()
6307
+ }).describe("Normalized request echo returned by PrimeUI."),
6308
+ candidates: z4.array(componentCandidateSchema).describe("Ranked rich candidate shortlist returned by PrimeUI.")
6309
+ });
6310
+ var componentPropsValidationErrorSchema = z4.object({
6311
+ path: z4.string().describe("JSON path or root path for the invalid props location."),
6312
+ message: z4.string().describe("Actionable validation message returned by PrimeUI.")
6313
+ });
6314
+ var componentPropsRenderCheckSchema = z4.object({
6315
+ attempted: z4.boolean().describe("True when PrimeUI attempted a render smoke check."),
6316
+ passed: z4.boolean().describe("True when the render smoke check passed."),
6317
+ message: z4.string().describe("Human-readable render check status or skip reason.")
6318
+ });
6319
+ var componentPropsValidateOutputSchema = z4.object({
6320
+ valid: z4.boolean().describe("True when props passed schema validation."),
6321
+ normalizedProps: z4.record(z4.unknown()).nullable().describe(
6322
+ "Props normalized by PrimeUI when valid; null when validation failed."
6323
+ ),
6324
+ errors: z4.array(componentPropsValidationErrorSchema).describe("Structured validation errors for invalid props."),
6325
+ hints: z4.array(z4.string()).describe("Agent-facing guidance for correcting invalid props."),
6326
+ renderCheck: componentPropsRenderCheckSchema.describe(
6327
+ "Optional render-smoke status returned by PrimeUI."
6328
+ )
6329
+ });
5824
6330
  var projectApiPageResourceSchema = z4.object({
5825
6331
  id: z4.string().describe("Stable PrimeUI page identifier."),
5826
6332
  title: z4.string().describe("Human-readable page title."),
@@ -6254,6 +6760,51 @@ WHEN TO USE:
6254
6760
  openWorldHint: true
6255
6761
  }
6256
6762
  };
6763
+ var toolComponentCandidatesGet = {
6764
+ title: "PrimeUI Component Candidates Get",
6765
+ description: `External planning helper. Returns a ranked rich candidate shortlist for adding, inserting, or replacing one PrimeUI component in an exported-project page composition.
6766
+
6767
+ WHEN TO USE:
6768
+ - Use this when building or editing a local exported-project page and you need PrimeUI scoring guidance for which componentId to choose next.
6769
+ - The normal flow is append: pass the current ordered blocks and omit operation, which defaults to { "type": "append" }.
6770
+ - Use insert or replace only when the caller is intentionally editing a specific position in the ordered blocks list.
6771
+ - Use the returned copyHints.deliveryToolchain when the chosen candidate must be delivered locally: create_component_export, download_component_export, then copy_registry_component.
6772
+
6773
+ AFTER CALLING:
6774
+ - Choose from candidates using uxScore, insertionScore, followingScore, group/family/layout rhythm, descriptions, defaults, and schemas.
6775
+ - Do not mutate Prime page state from this tool result. This is planning guidance only.
6776
+ - Keep the same pageSlug across later planning and validation calls so PrimeUI diagnostics stay correlated.`,
6777
+ inputSchema: componentCandidatesGetInputSchema,
6778
+ outputSchema: componentCandidatesGetOutputSchema,
6779
+ annotations: {
6780
+ readOnlyHint: true,
6781
+ destructiveHint: false,
6782
+ idempotentHint: true,
6783
+ openWorldHint: true
6784
+ }
6785
+ };
6786
+ var toolComponentPropsValidate = {
6787
+ title: "PrimeUI Component Props Validate",
6788
+ description: `External planning helper. Validates agent-authored props for one selected PrimeUI component before editing local exported-project files.
6789
+
6790
+ WHEN TO USE:
6791
+ - Use this after choosing a component candidate and drafting props from the user's brief, candidate metadata, defaultProps, compactSchema, or jsonSchema.
6792
+ - Keep pageSlug stable across candidate retrieval and validation so PrimeUI diagnostics stay correlated.
6793
+ - Treat valid: false as actionable feedback, not a transport failure. Fix the props from errors and hints, then call this tool again.
6794
+
6795
+ AFTER CALLING:
6796
+ - If valid is true, use normalizedProps for local page edits.
6797
+ - If valid is false, correct props using errors[].path, errors[].message, and hints before editing local files.
6798
+ - Do not mutate Prime page state from this tool result. This is validation guidance only.`,
6799
+ inputSchema: componentPropsValidateInputSchema,
6800
+ outputSchema: componentPropsValidateOutputSchema,
6801
+ annotations: {
6802
+ readOnlyHint: true,
6803
+ destructiveHint: false,
6804
+ idempotentHint: true,
6805
+ openWorldHint: true
6806
+ }
6807
+ };
6257
6808
  var toolProjectIssueReportSubmit = {
6258
6809
  title: "PrimeUI Project Issue Report Submit",
6259
6810
  description: `Atomic external API helper. Submits an issue report for the scoped PrimeUI project.
@@ -6664,6 +7215,32 @@ function createPrimeUiMcpServer(source) {
6664
7215
  }
6665
7216
  }
6666
7217
  );
7218
+ server.registerTool(
7219
+ "component_candidates_get",
7220
+ toolComponentCandidatesGet,
7221
+ async (args) => {
7222
+ try {
7223
+ const { projectRoot, ...input } = componentCandidatesGetValidationSchema.parse(args);
7224
+ const result = await source.getComponentCandidates(input, { projectRoot });
7225
+ return okResult("component_candidates_get", result);
7226
+ } catch (error) {
7227
+ return errorResult(error);
7228
+ }
7229
+ }
7230
+ );
7231
+ server.registerTool(
7232
+ "component_props_validate",
7233
+ toolComponentPropsValidate,
7234
+ async (args) => {
7235
+ try {
7236
+ const { projectRoot, ...input } = componentPropsValidateValidationSchema.parse(args);
7237
+ const result = await source.validateComponentProps(input, { projectRoot });
7238
+ return okResult("component_props_validate", result);
7239
+ } catch (error) {
7240
+ return errorResult(error);
7241
+ }
7242
+ }
7243
+ );
6667
7244
  server.registerTool(
6668
7245
  "list_exports",
6669
7246
  toolListExports,