@primeuicom/mcp 1.2.2 → 1.2.4

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
  );
@@ -601,6 +622,14 @@ var primeUiComponentExportPageSchema = z3.object({
601
622
  isReadyToExport: z3.boolean(),
602
623
  manifest: primeUiExportPageManifestSchema
603
624
  });
625
+ var primeUiComponentExportSelectedBlockSchema = z3.object({
626
+ blockId: z3.string(),
627
+ componentId: z3.string(),
628
+ contentKey: z3.string(),
629
+ occurrenceIndex: z3.number().int().positive(),
630
+ props: z3.record(z3.unknown()).nullable(),
631
+ slot: z3.string().nullable()
632
+ });
604
633
  var primeUiProjectInfoSchema = z3.object(
605
634
  {
606
635
  projectId: z3.string(),
@@ -639,6 +668,115 @@ var primeUiPageGenerationTypeSchema = z3.enum([
639
668
  "docs",
640
669
  "legal"
641
670
  ]);
671
+ var primeUiComponentCandidateOperationSchema = z3.discriminatedUnion("type", [
672
+ z3.object({
673
+ type: z3.literal("append")
674
+ }),
675
+ z3.object({
676
+ type: z3.literal("insert"),
677
+ index: z3.number().int()
678
+ }),
679
+ z3.object({
680
+ type: z3.literal("replace"),
681
+ index: z3.number().int()
682
+ })
683
+ ]);
684
+ var primeUiComponentCandidateConstraintsSchema = z3.object({
685
+ spreadDegree: z3.enum(["any-group", "same-group", "same-family"]).optional(),
686
+ allowedGroups: z3.array(z3.string()).optional(),
687
+ excludedGroups: z3.array(z3.string()).optional(),
688
+ excludeComponentIds: z3.array(z3.string()).optional()
689
+ });
690
+ var primeUiComponentCandidatesInputSchema = z3.object({
691
+ pageSlug: primeUiPageSlugInputSchema,
692
+ pageType: primeUiPageGenerationTypeSchema,
693
+ blocks: z3.array(
694
+ z3.object({
695
+ componentId: z3.string()
696
+ })
697
+ ),
698
+ operation: primeUiComponentCandidateOperationSchema,
699
+ count: z3.number().int().positive().optional(),
700
+ constraints: primeUiComponentCandidateConstraintsSchema.optional()
701
+ });
702
+ var primeUiComponentCandidateRequestEchoSchema = z3.object({
703
+ pageSlug: z3.string(),
704
+ pageType: z3.string(),
705
+ operation: primeUiComponentCandidateOperationSchema,
706
+ count: z3.number()
707
+ });
708
+ var requiredUnknownSchema = z3.custom((value) => value !== void 0);
709
+ var primeUiComponentCandidateLayoutObjectSchema = z3.object({
710
+ container: requiredUnknownSchema,
711
+ textAlignment: requiredUnknownSchema,
712
+ bottomWeight: requiredUnknownSchema,
713
+ entryWidth: requiredUnknownSchema,
714
+ exitWidth: requiredUnknownSchema,
715
+ orientation: requiredUnknownSchema,
716
+ structure: requiredUnknownSchema
717
+ });
718
+ var primeUiComponentCandidateLayoutSchema = z3.custom(
719
+ (value) => primeUiComponentCandidateLayoutObjectSchema.safeParse(value).success
720
+ );
721
+ var primeUiComponentCandidateObjectSchema = z3.object({
722
+ componentId: z3.string(),
723
+ name: z3.string(),
724
+ group: z3.string(),
725
+ familyId: z3.string(),
726
+ uxScore: z3.number(),
727
+ insertionScore: z3.number(),
728
+ followingScore: z3.number(),
729
+ layout: primeUiComponentCandidateLayoutSchema,
730
+ defaultProps: requiredUnknownSchema,
731
+ exportReady: z3.boolean(),
732
+ copyHints: z3.object({
733
+ deliveryToolchain: z3.array(z3.string())
734
+ }),
735
+ description: z3.string().nullable().optional(),
736
+ functionality: z3.string().nullable().optional(),
737
+ impression: z3.string().nullable().optional(),
738
+ visualStyle: z3.unknown().optional(),
739
+ compactSchema: z3.string().nullable().optional(),
740
+ jsonSchema: z3.record(z3.unknown()).nullable().optional()
741
+ });
742
+ var primeUiComponentCandidateSchema = z3.custom(
743
+ (value) => primeUiComponentCandidateObjectSchema.safeParse(value).success
744
+ );
745
+ var primeUiComponentCandidatesResponseSchema = z3.object({
746
+ request: primeUiComponentCandidateRequestEchoSchema,
747
+ candidates: z3.array(primeUiComponentCandidateSchema)
748
+ });
749
+ var primeUiComponentPropsValidateInputSchema = z3.object({
750
+ blockId: z3.string().refine((value) => value.trim().length > 0, {
751
+ message: "blockId must be a non-empty string"
752
+ }),
753
+ pageSlug: primeUiPageSlugInputSchema,
754
+ componentId: z3.string(),
755
+ props: z3.record(z3.unknown())
756
+ });
757
+ var primeUiComponentPropsValidationErrorSchema = z3.object({
758
+ path: z3.string(),
759
+ message: z3.string()
760
+ });
761
+ var primeUiComponentPropsRenderCheckSchema = z3.object({
762
+ attempted: z3.boolean(),
763
+ passed: z3.boolean(),
764
+ message: z3.string()
765
+ });
766
+ var primeUiComponentPropsValidateResponseSchema = z3.object({
767
+ valid: z3.boolean(),
768
+ normalizedProps: z3.record(z3.unknown()).nullable(),
769
+ propsValidationId: z3.string().nullable(),
770
+ block: z3.object({
771
+ blockId: z3.string(),
772
+ componentId: z3.string(),
773
+ contentKey: z3.string(),
774
+ props: z3.record(z3.unknown())
775
+ }).nullable(),
776
+ errors: z3.array(primeUiComponentPropsValidationErrorSchema),
777
+ hints: z3.array(z3.string()),
778
+ renderCheck: primeUiComponentPropsRenderCheckSchema
779
+ });
642
780
  var primeUiProjectApiWireframeStatusSchema = z3.enum(["pending", "generating", "ready", "error"]);
643
781
  var primeUiProjectApiVariantSummarySchema = z3.object({
644
782
  id: z3.string(),
@@ -867,6 +1005,7 @@ var primeUiExportManifestSchema = primeUiCreateExportResponseSchema;
867
1005
  var primeUiComponentExportResponseSchema = z3.object({
868
1006
  exportId: z3.string(),
869
1007
  export: primeUiPostExportPayloadExportSchema,
1008
+ block: primeUiComponentExportSelectedBlockSchema.optional(),
870
1009
  component: primeUiComponentExportComponentSchema,
871
1010
  page: primeUiComponentExportPageSchema,
872
1011
  pages: z3.array(primeUiComponentExportPageSchema)
@@ -963,6 +1102,16 @@ var normalizePrimeUiApiRoot = (rawBaseUrl) => {
963
1102
  var buildPrimeUiApiUrl = (apiRoot, endpoint) => new URL(endpoint, apiRoot).toString();
964
1103
  var isJsonContentType = (contentType) => contentType.includes("application/json") || contentType.includes("+json");
965
1104
  var isZipContentType = (contentType) => ZIP_CONTENT_TYPES.some((allowedType) => contentType.includes(allowedType));
1105
+ function normalizePropsValidationId(propsValidationId) {
1106
+ if (typeof propsValidationId === "undefined") {
1107
+ return void 0;
1108
+ }
1109
+ const trimmed = propsValidationId.trim();
1110
+ if (!trimmed) {
1111
+ throw new Error("propsValidationId must be a non-empty string.");
1112
+ }
1113
+ return trimmed;
1114
+ }
966
1115
  var looksLikeZipArchive = (buffer) => {
967
1116
  if (buffer.length < 4) {
968
1117
  return false;
@@ -1145,6 +1294,20 @@ var ApiProjectDataProvider = class {
1145
1294
  primeUiProjectPageDetailsSchema
1146
1295
  );
1147
1296
  }
1297
+ async getComponentCandidates(input) {
1298
+ return this.requestJson(
1299
+ "component-planning/candidates",
1300
+ primeUiComponentCandidatesResponseSchema,
1301
+ this.buildJsonRequestInit(input)
1302
+ );
1303
+ }
1304
+ async validateComponentProps(input) {
1305
+ return this.requestJson(
1306
+ "component-planning/props/validate",
1307
+ primeUiComponentPropsValidateResponseSchema,
1308
+ this.buildJsonRequestInit(input)
1309
+ );
1310
+ }
1148
1311
  async listExports() {
1149
1312
  const response = await this.requestJson(
1150
1313
  "project/exports",
@@ -1161,11 +1324,14 @@ var ApiProjectDataProvider = class {
1161
1324
  }
1162
1325
  );
1163
1326
  }
1164
- async createComponentExport(componentId) {
1327
+ async createComponentExport(componentId, options = {}) {
1328
+ const propsValidationId = normalizePropsValidationId(
1329
+ options.propsValidationId
1330
+ );
1165
1331
  return this.requestJson(
1166
1332
  `component-registry/components/${encodeURIComponent(componentId)}/exports`,
1167
1333
  primeUiComponentExportResponseSchema,
1168
- {
1334
+ propsValidationId ? this.buildJsonRequestInit({ propsValidationId }) : {
1169
1335
  method: "POST"
1170
1336
  }
1171
1337
  );
@@ -1856,19 +2022,23 @@ async function runHealthCheck(options) {
1856
2022
  apiKeyFromEnv: env.PRIMEUI_API_KEY
1857
2023
  });
1858
2024
  const configApiKeyState = resolvedProjectConfig ? "set" : configStatus === "missing" || configStatus === "unresolved" ? "missing" : "unknown";
1859
- const apiBaseUrlSource = env.PRIMEUI_API_BASE_URL?.trim() ? "env" : "default";
2025
+ const apiBaseUrlDetails = resolvePrimeUiApiBaseUrlDetails({
2026
+ projectConfig: resolvedProjectConfig?.projectConfig,
2027
+ baseUrlFromEnv: env.PRIMEUI_API_BASE_URL
2028
+ });
2029
+ const apiBaseUrlSource = apiBaseUrlDetails.source;
1860
2030
  const defaultApiRoot = normalizePrimeUiApiRoot(DEFAULT_API_BASE_URL);
1861
2031
  let apiRoot;
1862
2032
  let projectInfoUrl;
1863
2033
  let apiCheck;
1864
2034
  try {
1865
- apiRoot = normalizePrimeUiApiRoot(env.PRIMEUI_API_BASE_URL);
2035
+ apiRoot = normalizePrimeUiApiRoot(apiBaseUrlDetails.baseUrl);
1866
2036
  projectInfoUrl = buildPrimeUiApiUrl(apiRoot, "project");
1867
2037
  } catch (error) {
1868
2038
  apiCheck = {
1869
2039
  status: "skipped",
1870
2040
  apiBaseUrlSource,
1871
- nonStandardBaseUrl: Boolean(env.PRIMEUI_API_BASE_URL?.trim()),
2041
+ nonStandardBaseUrl: Boolean(apiBaseUrlDetails.baseUrl?.trim()),
1872
2042
  message: error instanceof Error ? error.message : String(error),
1873
2043
  errorKind: "configuration"
1874
2044
  };
@@ -1886,10 +2056,10 @@ async function runHealthCheck(options) {
1886
2056
  } else {
1887
2057
  const provider = options.createProvider?.({
1888
2058
  apiKey: apiKeyDetails.apiKey,
1889
- baseUrl: env.PRIMEUI_API_BASE_URL
2059
+ baseUrl: apiBaseUrlDetails.baseUrl
1890
2060
  }) ?? new ApiProjectDataProvider({
1891
2061
  apiKey: apiKeyDetails.apiKey,
1892
- baseUrl: env.PRIMEUI_API_BASE_URL
2062
+ baseUrl: apiBaseUrlDetails.baseUrl
1893
2063
  });
1894
2064
  try {
1895
2065
  await provider.getProjectInfo();
@@ -3782,6 +3952,11 @@ function isVirtualRouteFile(relativePath) {
3782
3952
  const segments = relativePath.split("/");
3783
3953
  return segments[0] === "src" && segments[1] === "app" && segments.includes(VIRTUAL_ROUTE_SEGMENT);
3784
3954
  }
3955
+ function isVirtualComponentExportPageFile(relativePath) {
3956
+ const segments = relativePath.split("/");
3957
+ const virtualRouteIndex = segments.indexOf(VIRTUAL_ROUTE_SEGMENT);
3958
+ return isVirtualRouteFile(relativePath) && virtualRouteIndex >= 0 && segments.length === virtualRouteIndex + 3 && segments[virtualRouteIndex + 2] === "page.tsx";
3959
+ }
3785
3960
  function getVirtualComponentRelativePath(relativePath, componentId) {
3786
3961
  const prefix = `${COMPONENT_PAGES_PREFIX}${VIRTUAL_ROUTE_SEGMENT}/${componentId}/`;
3787
3962
  if (!relativePath.startsWith(prefix)) {
@@ -3847,6 +4022,44 @@ function toImportPath(relativePath) {
3847
4022
  const withoutIndex = withoutExtension.replace(/\/index$/u, "");
3848
4023
  return `@/${withoutIndex.replace(/^src\//u, "")}`;
3849
4024
  }
4025
+ function toPascalComponentName(componentId) {
4026
+ return componentId.split(/[^a-zA-Z0-9]+/u).filter(Boolean).map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
4027
+ }
4028
+ function toVariableName(componentName) {
4029
+ if (!componentName) {
4030
+ return "componentProps";
4031
+ }
4032
+ return `${componentName.charAt(0).toLowerCase()}${componentName.slice(1)}Props`;
4033
+ }
4034
+ function toSafeCamelIdentifier(input, fallback) {
4035
+ const parts = input.trim().split(/[^a-zA-Z0-9]+/u).filter(Boolean);
4036
+ if (parts.length === 0) {
4037
+ return fallback;
4038
+ }
4039
+ const pascalName = parts.map((part) => {
4040
+ const normalizedPart = part.toLowerCase();
4041
+ return `${normalizedPart.charAt(0).toUpperCase()}${normalizedPart.slice(1)}`;
4042
+ }).join("");
4043
+ if (!pascalName) {
4044
+ return fallback;
4045
+ }
4046
+ if (/^[0-9]/u.test(pascalName)) {
4047
+ return `block${pascalName}`;
4048
+ }
4049
+ return `${pascalName.charAt(0).toLowerCase()}${pascalName.slice(1)}`;
4050
+ }
4051
+ function isDefaultComponentExportBlock(selectedBlock) {
4052
+ return selectedBlock.blockId === `component-export:${selectedBlock.componentId}:block`;
4053
+ }
4054
+ function toPropsVariableName(input) {
4055
+ if (isDefaultComponentExportBlock(input.selectedBlock)) {
4056
+ return toVariableName(input.componentName);
4057
+ }
4058
+ return `${toSafeCamelIdentifier(
4059
+ input.selectedBlock.blockId,
4060
+ input.componentName ? toVariableName(input.componentName).replace(/Props$/u, "") : "component"
4061
+ )}Props`;
4062
+ }
3850
4063
  function escapeRegExp(value) {
3851
4064
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
3852
4065
  }
@@ -4086,6 +4299,113 @@ function buildMessage(input) {
4086
4299
  );
4087
4300
  return parts.join(" ");
4088
4301
  }
4302
+ function getDefaultSelectedBlock(manifest) {
4303
+ const componentId = manifest.component.componentId;
4304
+ return {
4305
+ blockId: `component-export:${componentId}:block`,
4306
+ componentId,
4307
+ contentKey: componentId,
4308
+ occurrenceIndex: 1,
4309
+ props: null,
4310
+ slot: null
4311
+ };
4312
+ }
4313
+ function getSelectedBlock(manifest) {
4314
+ return manifest.block ?? getDefaultSelectedBlock(manifest);
4315
+ }
4316
+ function getVirtualRouteFile(manifestFiles) {
4317
+ return manifestFiles.find(isVirtualComponentExportPageFile) ?? manifestFiles.find(isVirtualRouteFile) ?? null;
4318
+ }
4319
+ function readBalancedObjectLiteral(input, startIndex) {
4320
+ if (input[startIndex] !== "{") {
4321
+ return null;
4322
+ }
4323
+ let depth = 0;
4324
+ let quote = null;
4325
+ let escaped = false;
4326
+ for (let index = startIndex; index < input.length; index += 1) {
4327
+ const char = input[index];
4328
+ if (escaped) {
4329
+ escaped = false;
4330
+ continue;
4331
+ }
4332
+ if (quote) {
4333
+ if (char === "\\") {
4334
+ escaped = true;
4335
+ continue;
4336
+ }
4337
+ if (char === quote) {
4338
+ quote = null;
4339
+ }
4340
+ continue;
4341
+ }
4342
+ if (char === '"' || char === "'" || char === "`") {
4343
+ quote = char;
4344
+ continue;
4345
+ }
4346
+ if (char === "{") {
4347
+ depth += 1;
4348
+ continue;
4349
+ }
4350
+ if (char !== "}") {
4351
+ continue;
4352
+ }
4353
+ depth -= 1;
4354
+ if (depth === 0) {
4355
+ return input.slice(startIndex, index + 1);
4356
+ }
4357
+ }
4358
+ return null;
4359
+ }
4360
+ function extractContentDataPropsCode(input) {
4361
+ const contentDataIndex = input.source.indexOf("const contentData");
4362
+ if (contentDataIndex < 0) {
4363
+ return null;
4364
+ }
4365
+ const keyPattern = new RegExp(
4366
+ `["']${escapeRegExp(input.contentKey)}["']\\s*:`,
4367
+ "u"
4368
+ );
4369
+ const keyMatch = keyPattern.exec(input.source.slice(contentDataIndex));
4370
+ if (!keyMatch) {
4371
+ return null;
4372
+ }
4373
+ const valueStartSearchIndex = contentDataIndex + keyMatch.index + keyMatch[0].length;
4374
+ const objectStartIndex = input.source.indexOf("{", valueStartSearchIndex);
4375
+ if (objectStartIndex < 0) {
4376
+ return null;
4377
+ }
4378
+ return readBalancedObjectLiteral(input.source, objectStartIndex);
4379
+ }
4380
+ async function buildRegistryComponentInsertion(input) {
4381
+ const componentName = toPascalComponentName(input.selectedBlock.componentId);
4382
+ const propsVariableName = toPropsVariableName({
4383
+ componentName,
4384
+ selectedBlock: input.selectedBlock
4385
+ });
4386
+ const virtualRouteFile = getVirtualRouteFile(input.manifestFiles);
4387
+ const referenceFiles = virtualRouteFile ? [virtualRouteFile] : [];
4388
+ let materializedPropsCode = input.selectedBlock.props ? JSON.stringify(input.selectedBlock.props, null, 2) : "{}";
4389
+ if (virtualRouteFile) {
4390
+ try {
4391
+ const virtualRouteSource = await readFile7(
4392
+ path13.join(input.exportPath, virtualRouteFile),
4393
+ "utf-8"
4394
+ );
4395
+ materializedPropsCode = extractContentDataPropsCode({
4396
+ source: virtualRouteSource,
4397
+ contentKey: input.selectedBlock.contentKey
4398
+ }) ?? materializedPropsCode;
4399
+ } catch {
4400
+ }
4401
+ }
4402
+ return {
4403
+ imports: [`import ${componentName} from "${input.componentImportPath}";`],
4404
+ propsCode: `const ${propsVariableName} = ${materializedPropsCode};`,
4405
+ jsx: `<${componentName} {...${propsVariableName}} />`,
4406
+ referenceFiles
4407
+ };
4408
+ }
4089
4409
  async function copyRegistryComponentFromExport(input) {
4090
4410
  const normalizedComponentId = normalizeComponentId(input.componentId);
4091
4411
  const { exportId, exportPath } = await resolveSingleExportDirectory(
@@ -4160,7 +4480,9 @@ async function copyRegistryComponentFromExport(input) {
4160
4480
  graphInternalFiles,
4161
4481
  referencedPublicFiles
4162
4482
  });
4163
- const copyableSourceFiles = fileTransfers.map((transfer) => transfer.sourcePath);
4483
+ const copyableSourceFiles = fileTransfers.map(
4484
+ (transfer) => transfer.sourcePath
4485
+ );
4164
4486
  const copyableFiles = fileTransfers.map((transfer) => transfer.targetPath);
4165
4487
  const transferBySourcePath = new Map(
4166
4488
  fileTransfers.map((transfer) => [transfer.sourcePath, transfer])
@@ -4176,6 +4498,13 @@ async function copyRegistryComponentFromExport(input) {
4176
4498
  componentId: normalizedComponentId,
4177
4499
  copyableFiles: copyableSourceFiles
4178
4500
  });
4501
+ const selectedBlock = getSelectedBlock(manifest);
4502
+ const insertion = await buildRegistryComponentInsertion({
4503
+ componentImportPath,
4504
+ exportPath,
4505
+ manifestFiles,
4506
+ selectedBlock
4507
+ });
4179
4508
  const candidateFiles = await resolveManifestCandidateFiles({
4180
4509
  exportPath,
4181
4510
  manifestOwnerLabel: `registry component "${normalizedComponentId}"`,
@@ -4267,8 +4596,10 @@ async function copyRegistryComponentFromExport(input) {
4267
4596
  exportId,
4268
4597
  componentId: normalizedComponentId,
4269
4598
  componentImportPath,
4599
+ insertion,
4270
4600
  manifestFiles,
4271
4601
  copyableFiles,
4602
+ selectedBlock,
4272
4603
  skippedFiles,
4273
4604
  conflicts: sortedConflictEntries,
4274
4605
  missingManifestFiles: missingManifestFileList
@@ -4305,8 +4636,10 @@ async function copyRegistryComponentFromExport(input) {
4305
4636
  manifestPath,
4306
4637
  component: manifest.component,
4307
4638
  componentImportPath,
4639
+ insertion,
4308
4640
  manifestFiles,
4309
4641
  copyableFiles,
4642
+ selectedBlock,
4310
4643
  newFiles: sortedNewFiles,
4311
4644
  identicalFiles: sortedIdenticalFiles,
4312
4645
  conflictFiles: sortedConflictFiles,
@@ -4510,6 +4843,12 @@ var ProjectSyncService = class {
4510
4843
  notes: guidanceNotes
4511
4844
  };
4512
4845
  }
4846
+ async getComponentCandidates(input, _context) {
4847
+ return this.provider.getComponentCandidates(input);
4848
+ }
4849
+ async validateComponentProps(input, _context) {
4850
+ return this.provider.validateComponentProps(input);
4851
+ }
4513
4852
  async listExports(_context) {
4514
4853
  await this.ensureTempLayout();
4515
4854
  return this.provider.listExports();
@@ -4528,9 +4867,11 @@ var ProjectSyncService = class {
4528
4867
  }
4529
4868
  };
4530
4869
  }
4531
- async createComponentExport(componentId, _context) {
4870
+ async createComponentExport(componentId, options = {}, _context) {
4532
4871
  await this.ensureTempLayout();
4533
- const result = await this.provider.createComponentExport(componentId);
4872
+ const result = await this.provider.createComponentExport(componentId, {
4873
+ propsValidationId: options.propsValidationId
4874
+ });
4534
4875
  const manifestPath = buildManifestPath(this.exportsRoot, result.export.id);
4535
4876
  await writeUtf8(manifestPath, `${JSON.stringify(result, null, 2)}
4536
4877
  `);
@@ -4768,10 +5109,14 @@ var LazyProjectSyncSource = class {
4768
5109
  projectConfig: resolvedProjectConfig.projectConfig,
4769
5110
  apiKeyFromEnv: this.env.PRIMEUI_API_KEY
4770
5111
  });
5112
+ const baseUrl = resolvePrimeUiApiBaseUrl({
5113
+ projectConfig: resolvedProjectConfig.projectConfig,
5114
+ baseUrlFromEnv: this.env.PRIMEUI_API_BASE_URL
5115
+ });
4771
5116
  this.stickyProjectRoot = projectRoot;
4772
5117
  const provider = this.createProvider({
4773
5118
  apiKey,
4774
- baseUrl: this.env.PRIMEUI_API_BASE_URL
5119
+ baseUrl
4775
5120
  });
4776
5121
  return new ProjectSyncService({
4777
5122
  projectRoot,
@@ -4954,6 +5299,24 @@ var LazyProjectSyncSource = class {
4954
5299
  (service) => service.syncSearchEnvironment(environmentSlug, context)
4955
5300
  );
4956
5301
  }
5302
+ async getComponentCandidates(input, context) {
5303
+ return this.withService(
5304
+ context,
5305
+ (service) => service.getComponentCandidates(input, context),
5306
+ {
5307
+ requireTargetProjectRoot: false
5308
+ }
5309
+ );
5310
+ }
5311
+ async validateComponentProps(input, context) {
5312
+ return this.withService(
5313
+ context,
5314
+ (service) => service.validateComponentProps(input, context),
5315
+ {
5316
+ requireTargetProjectRoot: false
5317
+ }
5318
+ );
5319
+ }
4957
5320
  async listExports(context) {
4958
5321
  return this.withService(context, (service) => service.listExports(context));
4959
5322
  }
@@ -4963,10 +5326,10 @@ var LazyProjectSyncSource = class {
4963
5326
  (service) => service.createExport(context)
4964
5327
  );
4965
5328
  }
4966
- async createComponentExport(componentId, context) {
5329
+ async createComponentExport(componentId, options, context) {
4967
5330
  return this.withService(
4968
5331
  context,
4969
- (service) => service.createComponentExport(componentId, context)
5332
+ (service) => service.createComponentExport(componentId, options, context)
4970
5333
  );
4971
5334
  }
4972
5335
  async downloadExportById(id, context) {
@@ -5186,6 +5549,16 @@ var copyComponentGuidanceSchema = z4.object({
5186
5549
  requiredActions: z4.array(z4.string()).describe("Concrete next actions for finishing component transfer."),
5187
5550
  notes: z4.array(z4.string()).describe("Important semantics and caveats for this transfer result.")
5188
5551
  });
5552
+ var registryComponentInsertionSchema = z4.object({
5553
+ imports: z4.array(z4.string()).describe("Import statements needed for inserting the copied component."),
5554
+ propsCode: z4.string().describe(
5555
+ "Materialized props source derived from the downloaded virtual component export."
5556
+ ),
5557
+ jsx: z4.string().describe("JSX snippet for rendering the materialized component instance."),
5558
+ referenceFiles: z4.array(z4.string()).describe(
5559
+ "Downloaded export files used as the source of truth for materialized insertion."
5560
+ )
5561
+ });
5189
5562
  var pageDetailsSchema = pageSchema.extend({
5190
5563
  pageInstruction: z4.string().nullable().describe(
5191
5564
  "Current instruction text for the active page variant. Null when no active variant is set."
@@ -5248,7 +5621,8 @@ ${WORKFLOW_SUMMARY}
5248
5621
 
5249
5622
  ADDITIONAL CAPABILITIES:
5250
5623
  - PrimeUI MCP also exposes atomic external API tools for project description, project pages, page variants, active-variant selection, and issue reports.
5251
- - These atomic tools are OPTIONAL additional capabilities for extended scenarios.
5624
+ - PrimeUI MCP also exposes component planning tools such as component_candidates_get and component_props_validate for exported-project page building.
5625
+ - These additional tools are OPTIONAL capabilities for extended scenarios.
5252
5626
  - They are NOT part of the primary import/export workflow above.
5253
5627
  - 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.
5254
5628
 
@@ -5473,6 +5847,7 @@ WHEN TO USE: Use this only for the component-registry import track when the user
5473
5847
  AFTER CALLING:
5474
5848
  - Verify component.componentId matches the requested componentId.
5475
5849
  - Verify component.isReadyToExport is true and page.manifest.files is present.
5850
+ - Pass propsValidationId from component_props_validate when exporting a validated instance. Omit it only for the intentional default-props component export path.
5476
5851
  - Local component sidecar manifest is saved to .primeui/temp/exports/[exportId].manifest.json.
5477
5852
  - Use the returned export ID to call download_component_export.
5478
5853
  - Use copy_registry_component after download_component_export for this component-track manifest. Do not use page copy tools for component-track manifests.
@@ -5481,7 +5856,10 @@ AFTER CALLING:
5481
5856
  ${WORKFLOW_SUMMARY}`,
5482
5857
  inputSchema: {
5483
5858
  projectRoot: projectRootInputSchema,
5484
- componentId: z4.string().min(1).describe("PrimeUI component registry identifier to export.")
5859
+ componentId: z4.string().min(1).describe("PrimeUI component registry identifier to export."),
5860
+ propsValidationId: z4.string().trim().min(1).optional().describe(
5861
+ "Optional props validation handoff id returned by component_props_validate. Omit to export registry defaultProps."
5862
+ )
5485
5863
  },
5486
5864
  outputSchema: z4.object({
5487
5865
  exportId: z4.string().describe(
@@ -5500,6 +5878,9 @@ ${WORKFLOW_SUMMARY}`,
5500
5878
  exportables: z4.array(exportableSchema).describe("Shared exportables included in this export payload.")
5501
5879
  }).describe("Created component export summary."),
5502
5880
  component: componentExportComponentSchema,
5881
+ block: copyComponentSelectedBlockSchema.optional().describe(
5882
+ "Selected virtual component-export block metadata when the export used a propsValidationId handoff."
5883
+ ),
5503
5884
  page: componentExportPageSchema.describe(
5504
5885
  "Virtual page manifest for this component export."
5505
5886
  ),
@@ -5813,6 +6194,7 @@ BEHAVIOR:
5813
6194
  - Copies only the selected registry component import graph, narrowly referenced public assets, and safe support files from the component sidecar manifest/export.
5814
6195
  - Remaps component-local files into src/components/shared/** and returns componentImportPath for manual insertion.
5815
6196
  - Skips virtual route files that include __primeui-component-export, because those are reference/insertion hints and must not be installed as normal app routes.
6197
+ - Returns selectedBlock and insertion artifacts derived from the downloaded virtual component export. Treat insertion.propsCode and insertion.jsx as the materialized instance source of truth.
5816
6198
  - Skips app/search/layout/header/footer/env/project-shell files instead of copying whole exportable buckets.
5817
6199
  - Never copies package.json directly. package.json is used only to add missing dependency entries and report dependency version conflicts.
5818
6200
  - Keeps safe support files on their natural target paths, such as src/components/ui/**, src/lib/**, src/types/**, and src/contexts/**.
@@ -5849,6 +6231,12 @@ ${WORKFLOW_SUMMARY}`,
5849
6231
  componentImportPath: z4.string().describe(
5850
6232
  "Canonical import path for the copied registry component entrypoint, for example @/components/shared/hero--pricing."
5851
6233
  ),
6234
+ selectedBlock: copyComponentSelectedBlockSchema.describe(
6235
+ "Selected virtual component-export block metadata. First-instance contentKey semantics match page export."
6236
+ ),
6237
+ insertion: registryComponentInsertionSchema.describe(
6238
+ "Materialized insertion artifact for adding this component instance to a real local page."
6239
+ ),
5852
6240
  manifestFiles: z4.array(z4.string()).describe(
5853
6241
  "Normalized component sidecar manifest files considered by the copy service."
5854
6242
  ),
@@ -6042,6 +6430,136 @@ var pageGenerationTypeSchema = z4.enum([
6042
6430
  ]).describe(
6043
6431
  "Supported PrimeUI page type. Must match the external API page type enum."
6044
6432
  );
6433
+ var componentCandidateOperationSchema = z4.discriminatedUnion("type", [
6434
+ z4.object({
6435
+ type: z4.literal("append")
6436
+ }),
6437
+ z4.object({
6438
+ type: z4.literal("insert"),
6439
+ index: z4.number().int().describe("Zero-based insertion index in the ordered blocks list.")
6440
+ }),
6441
+ z4.object({
6442
+ type: z4.literal("replace"),
6443
+ index: z4.number().int().describe("Zero-based index of the block being replaced.")
6444
+ })
6445
+ ]);
6446
+ var componentCandidatesGetInputSchema = z4.object({
6447
+ projectRoot: projectRootInputSchema,
6448
+ pageSlug: z4.string().refine((value) => value.trim().length > 0, {
6449
+ message: "pageSlug must be a non-empty string"
6450
+ }).describe(
6451
+ "Stable PrimeUI page slug used for candidate scoring and automatic diagnostics, for example '/pricing'."
6452
+ ),
6453
+ pageType: pageGenerationTypeSchema,
6454
+ blocks: z4.array(
6455
+ z4.object({
6456
+ componentId: z4.string().describe("PrimeUI component id already present in page order.")
6457
+ })
6458
+ ).describe(
6459
+ "Current ordered page composition before applying the requested operation."
6460
+ ),
6461
+ operation: componentCandidateOperationSchema.optional().default({ type: "append" }).describe(
6462
+ "Candidate placement operation. Omit for the normal append flow."
6463
+ ),
6464
+ count: z4.number().int().positive().optional().describe("Optional maximum candidate count. Studio defaults to 8."),
6465
+ constraints: z4.object({
6466
+ spreadDegree: z4.enum(["any-group", "same-group", "same-family"]).optional().describe("Optional UX scoring spread override."),
6467
+ allowedGroups: z4.array(z4.string()).optional().describe("Optional allow-list of candidate groups."),
6468
+ excludedGroups: z4.array(z4.string()).optional().describe("Optional deny-list of candidate groups."),
6469
+ excludeComponentIds: z4.array(z4.string()).optional().describe("Optional component ids to remove from the candidate pool.")
6470
+ }).optional().describe("Optional advanced candidate pool and spread constraints.")
6471
+ });
6472
+ var componentCandidatesGetValidationSchema = componentCandidatesGetInputSchema;
6473
+ var componentPropsValidateInputSchema = z4.object({
6474
+ projectRoot: projectRootInputSchema,
6475
+ pageSlug: z4.string().refine((value) => value.trim().length > 0, {
6476
+ message: "pageSlug must be a non-empty string"
6477
+ }).describe(
6478
+ "Stable PrimeUI page slug used for validation diagnostics, for example '/pricing'. Use the same pageSlug as candidate retrieval."
6479
+ ),
6480
+ componentId: z4.string().describe("PrimeUI component registry identifier selected by the agent."),
6481
+ blockId: z4.string().trim().min(1).describe(
6482
+ "Stable local block identifier for this planned component instance. Required for propsValidationId handoff records."
6483
+ ),
6484
+ props: z4.record(z4.unknown()).describe(
6485
+ "Agent-authored props payload to validate against PrimeUI's registry schema."
6486
+ )
6487
+ });
6488
+ var componentPropsValidateValidationSchema = componentPropsValidateInputSchema;
6489
+ var componentCandidateLayoutSchema = z4.object({
6490
+ container: z4.unknown().describe("Layout container metadata."),
6491
+ textAlignment: z4.unknown().describe("Text alignment metadata."),
6492
+ bottomWeight: z4.unknown().describe("Bottom visual weight metadata."),
6493
+ entryWidth: z4.unknown().describe("Incoming width rhythm metadata."),
6494
+ exitWidth: z4.unknown().describe("Outgoing width rhythm metadata."),
6495
+ orientation: z4.unknown().describe("Optional orientation metadata."),
6496
+ structure: z4.unknown().describe("Optional structure metadata.")
6497
+ });
6498
+ var componentCandidateSchema = z4.object({
6499
+ componentId: z4.string().describe("PrimeUI component registry identifier to choose or export."),
6500
+ name: z4.string().describe("Human-readable component name."),
6501
+ group: z4.string().describe("Component group used by candidate scoring."),
6502
+ familyId: z4.string().describe("Component family identifier from catalog."),
6503
+ uxScore: z4.number().describe("Total UX score used for ranking."),
6504
+ insertionScore: z4.number().describe("Score for inserting this candidate at the requested position."),
6505
+ followingScore: z4.number().describe("Neighbor compatibility score with the following block."),
6506
+ layout: componentCandidateLayoutSchema.describe(
6507
+ "Layout metadata useful for choosing visual rhythm."
6508
+ ),
6509
+ defaultProps: z4.unknown().describe("Registry default props, when available from PrimeUI."),
6510
+ exportReady: z4.boolean().describe("True when the component is expected to be exportable."),
6511
+ copyHints: z4.object({
6512
+ deliveryToolchain: z4.array(z4.string()).describe(
6513
+ "Recommended tool sequence for delivering this registry component locally."
6514
+ )
6515
+ }).describe("Machine-readable delivery hints for the selected candidate."),
6516
+ description: z4.string().nullable().optional(),
6517
+ functionality: z4.string().nullable().optional(),
6518
+ impression: z4.string().nullable().optional(),
6519
+ visualStyle: z4.unknown().optional(),
6520
+ compactSchema: z4.string().nullable().optional(),
6521
+ jsonSchema: z4.record(z4.unknown()).nullable().optional()
6522
+ });
6523
+ var componentCandidatesGetOutputSchema = z4.object({
6524
+ request: z4.object({
6525
+ pageSlug: z4.string(),
6526
+ pageType: z4.string(),
6527
+ operation: componentCandidateOperationSchema,
6528
+ count: z4.number()
6529
+ }).describe("Normalized request echo returned by PrimeUI."),
6530
+ candidates: z4.array(componentCandidateSchema).describe("Ranked rich candidate shortlist returned by PrimeUI.")
6531
+ });
6532
+ var componentPropsValidationErrorSchema = z4.object({
6533
+ path: z4.string().describe("JSON path or root path for the invalid props location."),
6534
+ message: z4.string().describe("Actionable validation message returned by PrimeUI.")
6535
+ });
6536
+ var componentPropsRenderCheckSchema = z4.object({
6537
+ attempted: z4.boolean().describe("True when PrimeUI attempted a render smoke check."),
6538
+ passed: z4.boolean().describe("True when the render smoke check passed."),
6539
+ message: z4.string().describe("Human-readable render check status or skip reason.")
6540
+ });
6541
+ var componentPropsValidateOutputSchema = z4.object({
6542
+ valid: z4.boolean().describe("True when props passed schema validation."),
6543
+ normalizedProps: z4.record(z4.unknown()).nullable().describe(
6544
+ "Props normalized by PrimeUI when valid; null when validation failed."
6545
+ ),
6546
+ propsValidationId: z4.string().nullable().describe(
6547
+ "Durable validation handoff id for create_component_export; null when props are invalid."
6548
+ ),
6549
+ block: z4.object({
6550
+ blockId: z4.string(),
6551
+ componentId: z4.string(),
6552
+ contentKey: z4.string(),
6553
+ props: z4.record(z4.unknown())
6554
+ }).nullable().describe(
6555
+ "Selected validated block identity and normalized props; null when props are invalid."
6556
+ ),
6557
+ errors: z4.array(componentPropsValidationErrorSchema).describe("Structured validation errors for invalid props."),
6558
+ hints: z4.array(z4.string()).describe("Agent-facing guidance for correcting invalid props."),
6559
+ renderCheck: componentPropsRenderCheckSchema.describe(
6560
+ "Optional render-smoke status returned by PrimeUI."
6561
+ )
6562
+ });
6045
6563
  var projectApiPageResourceSchema = z4.object({
6046
6564
  id: z4.string().describe("Stable PrimeUI page identifier."),
6047
6565
  title: z4.string().describe("Human-readable page title."),
@@ -6475,6 +6993,51 @@ WHEN TO USE:
6475
6993
  openWorldHint: true
6476
6994
  }
6477
6995
  };
6996
+ var toolComponentCandidatesGet = {
6997
+ title: "PrimeUI Component Candidates Get",
6998
+ description: `External planning helper. Returns a ranked rich candidate shortlist for adding, inserting, or replacing one PrimeUI component in an exported-project page composition.
6999
+
7000
+ WHEN TO USE:
7001
+ - Use this when building or editing a local exported-project page and you need PrimeUI scoring guidance for which componentId to choose next.
7002
+ - The normal flow is append: pass the current ordered blocks and omit operation, which defaults to { "type": "append" }.
7003
+ - Use insert or replace only when the caller is intentionally editing a specific position in the ordered blocks list.
7004
+ - Use the returned copyHints.deliveryToolchain when the chosen candidate must be delivered locally: create_component_export, download_component_export, then copy_registry_component.
7005
+
7006
+ AFTER CALLING:
7007
+ - Choose from candidates using uxScore, insertionScore, followingScore, group/family/layout rhythm, descriptions, defaults, and schemas.
7008
+ - Do not mutate Prime page state from this tool result. This is planning guidance only.
7009
+ - Keep the same pageSlug across later planning and validation calls so PrimeUI diagnostics stay correlated.`,
7010
+ inputSchema: componentCandidatesGetInputSchema,
7011
+ outputSchema: componentCandidatesGetOutputSchema,
7012
+ annotations: {
7013
+ readOnlyHint: true,
7014
+ destructiveHint: false,
7015
+ idempotentHint: true,
7016
+ openWorldHint: true
7017
+ }
7018
+ };
7019
+ var toolComponentPropsValidate = {
7020
+ title: "PrimeUI Component Props Validate",
7021
+ description: `External planning helper. Validates agent-authored props for one selected PrimeUI component before editing local exported-project files.
7022
+
7023
+ WHEN TO USE:
7024
+ - Use this after choosing a component candidate and drafting props from the user's brief, candidate metadata, defaultProps, compactSchema, or jsonSchema.
7025
+ - Keep pageSlug stable across candidate retrieval and validation so PrimeUI diagnostics stay correlated.
7026
+ - Treat valid: false as actionable feedback, not a transport failure. Fix the props from errors and hints, then call this tool again.
7027
+
7028
+ AFTER CALLING:
7029
+ - If valid is true, pass propsValidationId to create_component_export so copy_registry_component can return materialized insertion artifacts.
7030
+ - If valid is false, correct props using errors[].path, errors[].message, and hints before editing local files.
7031
+ - Do not mutate Prime page state from this tool result. This is validation guidance only.`,
7032
+ inputSchema: componentPropsValidateInputSchema,
7033
+ outputSchema: componentPropsValidateOutputSchema,
7034
+ annotations: {
7035
+ readOnlyHint: true,
7036
+ destructiveHint: false,
7037
+ idempotentHint: true,
7038
+ openWorldHint: true
7039
+ }
7040
+ };
6478
7041
  var toolProjectIssueReportSubmit = {
6479
7042
  title: "PrimeUI Project Issue Report Submit",
6480
7043
  description: `Atomic external API helper. Submits an issue report for the scoped PrimeUI project.
@@ -6885,6 +7448,32 @@ function createPrimeUiMcpServer(source) {
6885
7448
  }
6886
7449
  }
6887
7450
  );
7451
+ server.registerTool(
7452
+ "component_candidates_get",
7453
+ toolComponentCandidatesGet,
7454
+ async (args) => {
7455
+ try {
7456
+ const { projectRoot, ...input } = componentCandidatesGetValidationSchema.parse(args);
7457
+ const result = await source.getComponentCandidates(input, { projectRoot });
7458
+ return okResult("component_candidates_get", result);
7459
+ } catch (error) {
7460
+ return errorResult(error);
7461
+ }
7462
+ }
7463
+ );
7464
+ server.registerTool(
7465
+ "component_props_validate",
7466
+ toolComponentPropsValidate,
7467
+ async (args) => {
7468
+ try {
7469
+ const { projectRoot, ...input } = componentPropsValidateValidationSchema.parse(args);
7470
+ const result = await source.validateComponentProps(input, { projectRoot });
7471
+ return okResult("component_props_validate", result);
7472
+ } catch (error) {
7473
+ return errorResult(error);
7474
+ }
7475
+ }
7476
+ );
6888
7477
  server.registerTool(
6889
7478
  "list_exports",
6890
7479
  toolListExports,
@@ -6918,11 +7507,17 @@ function createPrimeUiMcpServer(source) {
6918
7507
  server.registerTool(
6919
7508
  "create_component_export",
6920
7509
  toolCreateComponentExport,
6921
- async ({ componentId, projectRoot }) => {
7510
+ async ({
7511
+ componentId,
7512
+ projectRoot,
7513
+ propsValidationId
7514
+ }) => {
6922
7515
  try {
6923
- const result = await source.createComponentExport(componentId, {
6924
- projectRoot
6925
- });
7516
+ const result = await source.createComponentExport(
7517
+ componentId,
7518
+ { propsValidationId },
7519
+ { projectRoot }
7520
+ );
6926
7521
  return okResult("create_component_export", result);
6927
7522
  } catch (error) {
6928
7523
  return errorResult(error);