@ikas/code-components-mcp 1.4.0-beta.5 → 1.4.0-beta.7

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-05-11T12:29:24.468Z",
2
+ "generatedAt": "2026-05-12T09:27:14.491Z",
3
3
  "functions": [
4
4
  {
5
5
  "name": "fbp_initAdvancedMatching",
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-05-11T12:29:24.493Z",
2
+ "generatedAt": "2026-05-12T09:27:14.516Z",
3
3
  "types": [
4
4
  {
5
5
  "name": "IkasProductAttributeDetail",
package/dist/index.js CHANGED
@@ -571,8 +571,9 @@ function generateMigrationPlan(theme, projectName, oldSourceDir) {
571
571
  parts.push(`> 1. **Tick checkboxes** as you finish work. Use \`[~]\` for in-progress and \`[x]\` for done. Edit the file directly with your file-editing tools.`);
572
572
  parts.push(`> 2. **theme.json is incomplete.** Atomic components (Button, Input, Card, icons, etc.) often live only in \`src/\` and are NOT referenced from theme.json. Before you start section migration, scan the old source directory and ADD entries to this file for anything the initial scan missed — list them under \`## Source Code Analysis\` and add shared ones to \`### Shared Sub-Components\`.`);
573
573
  parts.push(`> 3. **Custom data types are NOT pre-converted.** For each customData entry used by a section, decide enum-vs-component when you migrate that section. Log every decision in \`## Custom Data Decisions\` with reasoning. See \`get_migration_guide("custom-data-conversion")\` for the heuristic.`);
574
- parts.push(`> 4. **Per-section work:** call \`get_section_migration_plan({theme_json_path, section_name, project_name: "${projectName}"})\` for each section. The MCP returns concrete CLI commands and flags any customData-referencing props with a "Decide: enum or component?" callout.`);
575
- parts.push(`> 5. **If you discover new shared sub-components mid-migration**, add them under \`### Shared Sub-Components\` and any notes under \`## Notes\`.`);
574
+ parts.push(`> 4. **Preserve feature parity. Do NOT silently simplify or drop features.** If an old prop has richer fields than a new built-in prop type can carry (e.g. a navigation link with a per-link image), the answer is to build a child component — never to flatten and "add it later." Later doesn't come. If the user explicitly wants a feature removed, log that as an explicit decision in \`## Notes\`; otherwise migrate to functional parity.`);
575
+ parts.push(`> 5. **Per-section work:** call \`get_section_migration_plan({theme_json_path, section_name, project_name: "${projectName}"})\` for each section. The MCP returns concrete CLI commands and flags any customData-referencing props with a "Decide: enum or component?" callout.`);
576
+ parts.push(`> 6. **If you discover new shared sub-components mid-migration**, add them under \`### Shared Sub-Components\` and any notes under \`## Notes\`.`);
576
577
  parts.push(`>`);
577
578
  parts.push(`> Status legend: \`[ ]\` not started · \`[~]\` in progress · \`[x]\` complete.`);
578
579
  parts.push("");
@@ -727,22 +728,14 @@ function generateMigrationPlan(theme, projectName, oldSourceDir) {
727
728
  parts.push("");
728
729
  parts.push(`> **Before starting section migration**, scan the old \`src/\` for components NOT listed above. theme.json does not see atomic primitives — buttons, inputs, cards, icon wrappers, layout helpers, etc. — that are imported by sections but never appear as theme components. Add them here, then decide which become shared sub-components vs which collapse into section bodies.`);
729
730
  parts.push("");
730
- parts.push(`<!-- Example: list each atomic component you find here.`);
731
- parts.push(`- \`Button\` — found in src/atoms/Button/. Used by ~all sections. → add as Shared Sub-Component.`);
732
- parts.push(`- \`PriceLabel\` — found in src/atoms/. Used only by ProductCard. → inline into ProductCard during migration.`);
733
- parts.push(`- \`Icon\` — found in src/atoms/Icon/. Used everywhere; replace with inline SVG per section.`);
734
- parts.push(`-->`);
731
+ parts.push(`<!-- Example: \`- Button (src/atoms/Button/) used by ~all sections → promote to Shared Sub-Component\` -->`);
735
732
  parts.push("");
736
733
  // Custom Data Decisions — append-only log the LLM fills as it makes per-section decisions
737
734
  parts.push(`## Custom Data Decisions`);
738
735
  parts.push("");
739
736
  parts.push(`> Log each customData enum-vs-component decision here as you encounter it during section migration. Format: \`- \\\`<CustomDataName>\\\` → enum/component \\\`<target name>\\\` (YYYY-MM-DD) — reasoning\`.`);
740
737
  parts.push("");
741
- parts.push(`<!-- Example entries:`);
742
- parts.push(`- \`SlideData\` → component \`hero-slide\` (2026-05-11) — structured record {image, link, title} repeated per slide; wired into HeroSlider via COMPONENT_LIST.`);
743
- parts.push(`- \`Position\` → enum \`Position\` (2026-05-11) — flat scalar set left/right/center; enumId: enm_abc123.`);
744
- parts.push(`- \`MenuItemData\` → component \`menu-item\` (2026-05-12) — mega-menu links with image + title fields; LIST_OF_LINK would have dropped the image.`);
745
- parts.push(`-->`);
738
+ parts.push(`<!-- Example: \`- SlideData → component \\\`hero-slide\\\` (2026-05-11) — structured record {image,link,title}; LIST_OF_LINK would drop the image\` -->`);
746
739
  parts.push("");
747
740
  // Known Environmental Issues (agents fill in during work)
748
741
  parts.push(`## Known Environmental Issues`);
@@ -751,44 +744,22 @@ function generateMigrationPlan(theme, projectName, oldSourceDir) {
751
744
  parts.push("");
752
745
  parts.push(`- [ ] _(none recorded yet)_`);
753
746
  parts.push("");
754
- // Usage section
755
- parts.push(`## Per-Section Usage`);
756
- parts.push("");
757
- parts.push(`Once the Foundation is complete, for each section above:`);
758
- parts.push("");
759
- parts.push(`1. Find the first unchecked \`[ ]\` section (start with Simple).`);
760
- parts.push(`2. Call \`get_section_migration_plan({theme_json_path, section_name: "<old section name>", project_name: "${projectName}"})\`.`);
761
- parts.push(`3. Read the old source files listed in the plan.`);
762
- parts.push(`4. Make any customData enum-vs-component decisions surfaced in the plan and log them under \`## Custom Data Decisions\` above.`);
763
- parts.push(`5. Run the CLI commands in the plan (they create parent + children with auto-generated types.ts).`);
764
- parts.push(`6. Write \`index.tsx\` and \`styles.css\` using the patterns in the plan. DO NOT manually edit types.ts.`);
765
- parts.push(`7. Mark the section \`[x]\` when it builds cleanly. Append a short note to the **Notes** section below (what libraries you replaced, any ad-hoc props you had to add, the actual folder name the CLI created if different from the name you passed).`);
766
- parts.push("");
767
747
  // Notes — append-only log for decisions not captured elsewhere
768
748
  parts.push(`## Notes`);
769
749
  parts.push("");
770
- parts.push(`_Append a bullet after completing work. Format: \`- [YYYY-MM-DD] <section-id>: <brief note>\`. This is how future sessions learn about decisions not encoded in the plan structure (library swaps, ad-hoc props, CLI folder-name oddities, etc.)._`);
750
+ parts.push(`_Append a bullet after completing work — library swaps, ad-hoc props, CLI folder-name oddities, user-approved feature drops, etc. Format: \`- [YYYY-MM-DD] <section-id>: <brief note>\`._`);
771
751
  parts.push("");
772
- parts.push(`<!-- Examples:`);
773
- parts.push(`- [2026-04-15] Foundation: built Input, SubmitButton, Modal, SectionHeader, StarRating. Skipped: GoogleCaptcha (needs investigation), BlogCard, Pagination (low priority).`);
774
- parts.push(`- [2026-04-15] ${projectName}-footer: swapped react-hot-toast for inline status text; newsletter uses form-model pattern (getNewsletterSubscriptionForm). CLI created folder as "Footer/" as expected.`);
775
- parts.push(`-->`);
752
+ parts.push(`<!-- Example: \`- [2026-04-15] ${projectName}-footer: swapped react-hot-toast for inline status text; CLI created Footer/ as expected\` -->`);
776
753
  parts.push("");
777
- // Cross-references
754
+ // Cross-references — keep terse; LLM can call `get_migration_guide("list")` or `get_framework_guide("list")` for more
778
755
  parts.push(`## Cross-References`);
779
756
  parts.push("");
780
- parts.push(`Essential MCP tools to call during migration:`);
757
+ parts.push(`- \`get_migration_guide("iterative-workflow")\` the full per-phase protocol`);
758
+ parts.push(`- \`get_migration_guide("custom-data-conversion")\` — enum-vs-component decisions`);
759
+ parts.push(`- \`get_migration_guide("prop-runtime-shapes")\` — runtime shapes & access patterns`);
760
+ parts.push(`- \`get_framework_guide("common-pitfalls")\` — gotchas & old→new property migrations`);
781
761
  parts.push("");
782
- parts.push(`- \`get_migration_guide("iterative-workflow")\` full protocol for resumable migrations`);
783
- parts.push(`- \`get_migration_guide("component-renderer-limitations")\` — critical constraints when using COMPONENT_LIST`);
784
- parts.push(`- \`get_migration_guide("prop-runtime-shapes")\` — \`.data\` vs \`.links\`, \`.variant\` vs \`.product\`, etc.`);
785
- parts.push(`- \`get_migration_guide("link-prop-decision-guide")\` — LINK vs LIST_OF_LINK vs COMPONENT_LIST`);
786
- parts.push(`- \`get_migration_guide("library-replacements")\` — swiper, headlessui, tailwind, etc.`);
787
- parts.push(`- \`get_migration_guide("react-to-preact")\` — observer rules, imports, IkasSlider removal`);
788
- parts.push(`- \`get_framework_guide("component-renderer-patterns")\` — full IkasComponentRenderer usage`);
789
- parts.push(`- \`get_framework_guide("common-pitfalls")\` — general gotchas`);
790
- parts.push(`- \`get_framework_guide("navigation-patterns")\` — Router.navigate, Router.navigateToPage`);
791
- parts.push(`- \`get_model_guide("<TypeName>")\` — IkasCart, IkasProduct, IkasCustomer shapes`);
762
+ parts.push(`Call \`get_migration_guide("list")\` or \`get_framework_guide("list")\` for the full topic catalog.`);
792
763
  parts.push("");
793
764
  return parts.join("\n");
794
765
  }
@@ -1170,14 +1141,7 @@ function generateSectionMigrationPlan(theme, sectionName, projectName, oldSource
1170
1141
  if (customDataPropsForCallouts.length > 0) {
1171
1142
  parts.push(`## Custom Data Decisions to Make`);
1172
1143
  parts.push("");
1173
- parts.push(`Each prop below references an old \`customData\` type. The conversion table above shows the MCP's **default** choice based on shape but you should verify it matches the data's actual semantics. **Heuristic:**`);
1174
- parts.push("");
1175
- parts.push(`- **Flat scalar set** (e.g. \`"left" | "right" | "center"\`) → new-system **enum prop** via \`config add-enum\`.`);
1176
- parts.push(`- **Structured record** (\`{image, link, title}\`, repeated in a list) → new-system **component** via \`config add-component\` + COMPONENT_LIST wiring.`);
1177
- parts.push("");
1178
- parts.push(`See \`get_migration_guide("custom-data-conversion")\` for worked examples (Position → enum; Slide → component; MenuItem → component).`);
1179
- parts.push("");
1180
- parts.push(`> **For each decision below, log it in MIGRATION.md under \`## Custom Data Decisions\`** with the format: \`- \\\`<CustomDataName>\\\` → enum/component \\\`<target name>\\\` (${new Date().toISOString().slice(0, 10)}) — reasoning\`.`);
1144
+ parts.push(`Each prop below references an old \`customData\` type. Verify the MCP's default against the actual data semantics, then run the CLI command. **Log every decision in MIGRATION.md \`## Custom Data Decisions\`** with reasoning. See \`get_migration_guide("custom-data-conversion")\` for the heuristic and worked examples.`);
1181
1145
  parts.push("");
1182
1146
  for (const p of customDataPropsForCallouts) {
1183
1147
  const cd = customDataMap.get(p.customDataId);
@@ -1206,56 +1170,83 @@ function generateSectionMigrationPlan(theme, sectionName, projectName, oldSource
1206
1170
  else {
1207
1171
  shape = cdType;
1208
1172
  }
1173
+ // Build the field source + names list once so we can use it for the lost-fields enumeration
1174
+ // AND for the component-path CLI template.
1175
+ const fieldSource = cd.type === "DYNAMIC_LIST" || cd.type === "STATIC_LIST"
1176
+ ? cd.nestedData?.[0]?.nestedData || []
1177
+ : cd.nestedData || [];
1178
+ const fieldDescriptions = fieldSource
1179
+ .filter((f) => f.key)
1180
+ .map((f) => `\`${f.key}\` (${f.type || "?"})`);
1209
1181
  parts.push(`### Prop \`${p.name || "?"}\` → customData \`${cdName}\``);
1210
1182
  parts.push("");
1211
1183
  parts.push(`**Shape:** \`${shape}\``);
1212
1184
  parts.push("");
1213
- let recommendation;
1214
1185
  if (shapeKind === "enum") {
1215
- recommendation = `**MCP default: enum prop.** This looks like a flat scalar set. Use \`config add-enum\` unless the data is actually used as a richer object (e.g. each "option" carries an image — in which case it's a component).`;
1186
+ parts.push(`**Default: enum prop.** Flat scalar set; use \`config add-enum\`.`);
1187
+ parts.push("");
1188
+ const enumName = cd.typescriptName || (cd.name ? cd.name.replace(/[^a-zA-Z0-9]/g, "") : "Enum");
1189
+ const enumOptions = (cd.enumOptions || []).reduce((acc, o) => {
1190
+ if (o.displayName && o.value)
1191
+ acc[o.displayName] = o.value;
1192
+ return acc;
1193
+ }, {});
1194
+ parts.push("```bash");
1195
+ parts.push(`npx ikas-component config add-enum --name "${enumName}" --options '${JSON.stringify(enumOptions)}'`);
1196
+ parts.push("```");
1197
+ parts.push("");
1198
+ parts.push(`If you believe this should be a component instead (e.g. each option secretly carries richer data not visible in the customData shape), see \`get_migration_guide("custom-data-conversion")\`.`);
1199
+ parts.push("");
1216
1200
  }
1217
1201
  else if (shapeKind === "list" || shapeKind === "record") {
1218
- recommendation = `**MCP default: component + COMPONENT_LIST.** This has multiple fields per item — a single enum value can't carry the structure. Use \`config add-component\` for a child component, then wire it via \`filteredComponentIds\` on the parent.`;
1202
+ const fieldCount = fieldDescriptions.length;
1203
+ const isMinimal = fieldCount > 0 && fieldCount <= 2;
1204
+ if (isMinimal) {
1205
+ parts.push(`⚠️ **This child would have only ${fieldCount} field${fieldCount === 1 ? "" : "s"}** (${fieldDescriptions.join(", ")}). \`COMPONENT_LIST\` is usually overkill at this size. **Prefer one of:**`);
1206
+ parts.push(`- repeated scalar props on the parent (\`title1\`/\`link1\`, \`title2\`/\`link2\`, …) for a small fixed count`);
1207
+ parts.push(`- a domain LIST prop type (\`LIST_OF_LINK\`, \`IMAGE_LIST\`, \`PRODUCT_LIST\`, …) when each item IS one domain object`);
1208
+ parts.push(`- \`COMPONENT_LIST\` (CLI command below) only if reordering in the editor is a real UX win`);
1209
+ parts.push("");
1210
+ parts.push(`See \`get_migration_guide("component-composition-decision-guide")\` for the full tree. Log your choice in MIGRATION.md → \`## Custom Data Decisions\`.`);
1211
+ parts.push("");
1212
+ }
1213
+ else {
1214
+ parts.push(`**Default: component + COMPONENT_LIST.** Multiple fields per item — a single enum value cannot carry this structure.`);
1215
+ parts.push("");
1216
+ if (fieldCount > 0) {
1217
+ parts.push(`⚠️ **Fields you would lose if you flatten this:** ${fieldDescriptions.join(", ")}. Flattening to a simpler prop type drops these from the editor UI permanently. **Do not "simplify for later"** — if the feature genuinely isn't wanted, log that explicitly in MIGRATION.md → \`## Notes\` with reasoning. Otherwise build the component.`);
1218
+ parts.push("");
1219
+ }
1220
+ parts.push(`> See \`get_migration_guide("component-composition-decision-guide")\` for when \`COMPONENT_LIST\` is overkill.`);
1221
+ parts.push("");
1222
+ }
1223
+ const compName = cd.typescriptName || (cd.name ? cd.name.replace(/[^a-zA-Z0-9]/g, "") : `${sectionPascal}Item`);
1224
+ const compPropsForCli = [];
1225
+ for (const f of fieldSource) {
1226
+ if (!f.key)
1227
+ continue;
1228
+ let fType = f.type;
1229
+ if (fType === "SLIDER")
1230
+ fType = "NUMBER";
1231
+ else if (fType === "PRODUCT_DETAIL")
1232
+ fType = "PRODUCT";
1233
+ compPropsForCli.push({ name: f.key, displayName: f.name || f.key, type: fType });
1234
+ }
1235
+ parts.push("```bash");
1236
+ if (isMinimal) {
1237
+ parts.push(`# Fallback: COMPONENT_LIST (use only if the simpler alternatives above don't fit)`);
1238
+ }
1239
+ parts.push(`npx ikas-component config add-component --name "${compName}" --type component --props '${JSON.stringify(compPropsForCli)}'`);
1240
+ parts.push(`# Then on the parent, set the prop's filteredComponentIds to the new component's id.`);
1241
+ parts.push("```");
1242
+ parts.push("");
1243
+ parts.push(`If you believe this should be an enum despite the structure, see \`get_migration_guide("custom-data-conversion")\`.`);
1244
+ parts.push("");
1219
1245
  }
1220
1246
  else {
1221
- recommendation = `**MCP default: unable to classify automatically — you decide.**`;
1247
+ parts.push(`**Unable to classify automatically — you decide.** See \`get_migration_guide("custom-data-conversion")\` for the enum-vs-component heuristic.`);
1248
+ parts.push("");
1222
1249
  }
1223
- parts.push(recommendation);
1224
- parts.push("");
1225
- parts.push(`**Both CLI templates** (pick the one that matches your decision):`);
1226
- parts.push("");
1227
- parts.push(`Enum path:`);
1228
- parts.push("```bash");
1229
- const enumName = cd.typescriptName || (cd.name ? cd.name.replace(/[^a-zA-Z0-9]/g, "") : "Enum");
1230
- const enumOptions = (cd.enumOptions || []).reduce((acc, o) => {
1231
- if (o.displayName && o.value)
1232
- acc[o.displayName] = o.value;
1233
- return acc;
1234
- }, {});
1235
- parts.push(`npx ikas-component config add-enum --name "${enumName}" --options '${JSON.stringify(enumOptions)}'`);
1236
- parts.push("```");
1237
- parts.push("");
1238
- parts.push(`Component path:`);
1239
- parts.push("```bash");
1240
- const compName = cd.typescriptName || (cd.name ? cd.name.replace(/[^a-zA-Z0-9]/g, "") : `${sectionPascal}Item`);
1241
- const compPropsForCli = [];
1242
- const fieldSource = cd.type === "DYNAMIC_LIST" || cd.type === "STATIC_LIST"
1243
- ? cd.nestedData?.[0]?.nestedData || []
1244
- : cd.nestedData || [];
1245
- for (const f of fieldSource) {
1246
- if (!f.key)
1247
- continue;
1248
- let fType = f.type;
1249
- if (fType === "SLIDER")
1250
- fType = "NUMBER";
1251
- else if (fType === "PRODUCT_DETAIL")
1252
- fType = "PRODUCT";
1253
- compPropsForCli.push({ name: f.key, displayName: f.name || f.key, type: fType });
1254
- }
1255
- parts.push(`npx ikas-component config add-component --name "${compName}" --type component --props '${JSON.stringify(compPropsForCli)}'`);
1256
- parts.push(`# Then on the parent, set the prop's filteredComponentIds to the new component's id.`);
1257
- parts.push("```");
1258
- parts.push("");
1259
1250
  }
1260
1251
  }
1261
1252
  // Enums to create first
@@ -1423,31 +1414,19 @@ function generateSectionMigrationPlan(theme, sectionName, projectName, oldSource
1423
1414
  parts.push("");
1424
1415
  }
1425
1416
  }
1426
- // Relevant guides
1427
- parts.push(`## ${nextStep + 1}. Relevant Guides (call these for details)`);
1417
+ // Relevant guides — keep terse; LLM can call get_migration_guide("list") for the full catalog
1418
+ parts.push(`## ${nextStep + 1}. Relevant Guides`);
1428
1419
  parts.push("");
1429
1420
  parts.push(`- \`get_migration_guide("react-to-preact")\` — code conversion patterns`);
1430
- parts.push(`- \`get_migration_guide("library-replacements")\` — library vanilla Preact patterns`);
1431
- parts.push(`- \`get_migration_guide("prop-runtime-shapes")\` exact runtime shapes (.data vs .links)`);
1432
- if (children.length > 0) {
1433
- parts.push(`- \`get_migration_guide("component-renderer-limitations")\` — critical COMPONENT_LIST constraints`);
1434
- parts.push(`- \`get_framework_guide("component-renderer-patterns")\` — full IkasComponentRenderer usage`);
1435
- parts.push(`- \`get_migration_example("custom-dynamic-list-to-component-list")\` — concrete example`);
1436
- }
1437
- if (target.isHeader || target.isFooter) {
1438
- parts.push(`- \`get_framework_guide("header-footer-patterns")\` — header/footer specifics`);
1421
+ parts.push(`- \`get_migration_guide("prop-runtime-shapes")\` — exact runtime shapes (\`.data\` vs \`.links\`, etc.)`);
1422
+ if (children.length > 0 || target.isHeader || target.isFooter) {
1423
+ parts.push(`- \`get_framework_guide("header-footer-patterns")\` COMPONENT_LIST + IkasComponentRenderer wiring`);
1439
1424
  }
1440
- parts.push(`- \`get_framework_guide("common-pitfalls")\` — observer rules, common mistakes`);
1441
1425
  parts.push("");
1442
1426
  // Completion
1443
1427
  parts.push(`## ${nextStep + 2}. Mark Complete`);
1444
1428
  parts.push("");
1445
- parts.push(`Once the section builds cleanly with \`npx ikas-component build\`:`);
1446
- parts.push(`1. Edit \`MIGRATION.md\` at the project root with your file-editing tool (no MCP tool needed)`);
1447
- parts.push(`2. Change the checkbox for \`${sectionId}\` from \`[ ]\` to \`[x]\``);
1448
- parts.push(`3. Also mark each child component as \`[x]\``);
1449
- parts.push(`4. If you made customData enum-vs-component decisions, log them under \`## Custom Data Decisions\` (one bullet per decision with reasoning)`);
1450
- parts.push(`5. Append an entry to the **Notes** section of \`MIGRATION.md\` noting: libraries replaced, any props added beyond the generated plan, the actual folder name the CLI created (in case it differs from the name you passed — e.g., \`FAQ\` → \`Faq/\`), and any other decisions a future agent should know.`);
1429
+ parts.push(`Once the section builds cleanly with \`npx ikas-component build\`: edit MIGRATION.md → tick \`[x]\` for \`${sectionId}\` and each child component, log any customData decisions under \`## Custom Data Decisions\`, and append a brief entry to \`## Notes\` with anything future sessions should know.`);
1451
1430
  parts.push("");
1452
1431
  return parts.join("\n");
1453
1432
  }