@ikas/component-cli 1.4.0-beta.4 → 1.4.0-beta.41

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.
Files changed (123) hide show
  1. package/dist/commands/add-sections-to-page.d.ts +3 -0
  2. package/dist/commands/add-sections-to-page.d.ts.map +1 -0
  3. package/dist/commands/add-sections-to-page.js +39 -0
  4. package/dist/commands/add-sections-to-page.js.map +1 -0
  5. package/dist/commands/add-to-page.d.ts +3 -0
  6. package/dist/commands/add-to-page.d.ts.map +1 -0
  7. package/dist/commands/add-to-page.js +41 -0
  8. package/dist/commands/add-to-page.js.map +1 -0
  9. package/dist/commands/build.d.ts.map +1 -1
  10. package/dist/commands/build.js +5 -165
  11. package/dist/commands/build.js.map +1 -1
  12. package/dist/commands/config.d.ts.map +1 -1
  13. package/dist/commands/config.js +143 -111
  14. package/dist/commands/config.js.map +1 -1
  15. package/dist/commands/create-design-tokens.d.ts +7 -0
  16. package/dist/commands/create-design-tokens.d.ts.map +1 -0
  17. package/dist/commands/create-design-tokens.js +127 -0
  18. package/dist/commands/create-design-tokens.js.map +1 -0
  19. package/dist/commands/create-global-variable.d.ts +3 -0
  20. package/dist/commands/create-global-variable.d.ts.map +1 -0
  21. package/dist/commands/create-global-variable.js +53 -0
  22. package/dist/commands/create-global-variable.js.map +1 -0
  23. package/dist/commands/create-page.d.ts +3 -0
  24. package/dist/commands/create-page.d.ts.map +1 -0
  25. package/dist/commands/create-page.js +31 -0
  26. package/dist/commands/create-page.js.map +1 -0
  27. package/dist/commands/delete-theme-globals.d.ts +4 -0
  28. package/dist/commands/delete-theme-globals.d.ts.map +1 -0
  29. package/dist/commands/delete-theme-globals.js +48 -0
  30. package/dist/commands/delete-theme-globals.js.map +1 -0
  31. package/dist/commands/dev.d.ts.map +1 -1
  32. package/dist/commands/dev.js +213 -23
  33. package/dist/commands/dev.js.map +1 -1
  34. package/dist/commands/get-component-props.d.ts +3 -0
  35. package/dist/commands/get-component-props.d.ts.map +1 -0
  36. package/dist/commands/get-component-props.js +32 -0
  37. package/dist/commands/get-component-props.js.map +1 -0
  38. package/dist/commands/get-page-by-type.d.ts +3 -0
  39. package/dist/commands/get-page-by-type.d.ts.map +1 -0
  40. package/dist/commands/get-page-by-type.js +25 -0
  41. package/dist/commands/get-page-by-type.js.map +1 -0
  42. package/dist/commands/get-section-values.d.ts +3 -0
  43. package/dist/commands/get-section-values.d.ts.map +1 -0
  44. package/dist/commands/get-section-values.js +39 -0
  45. package/dist/commands/get-section-values.js.map +1 -0
  46. package/dist/commands/import.d.ts +3 -0
  47. package/dist/commands/import.d.ts.map +1 -0
  48. package/dist/commands/import.js +25 -0
  49. package/dist/commands/import.js.map +1 -0
  50. package/dist/commands/list-entities.d.ts +3 -0
  51. package/dist/commands/list-entities.d.ts.map +1 -0
  52. package/dist/commands/list-entities.js +32 -0
  53. package/dist/commands/list-entities.js.map +1 -0
  54. package/dist/commands/list-imported.d.ts +3 -0
  55. package/dist/commands/list-imported.d.ts.map +1 -0
  56. package/dist/commands/list-imported.js +25 -0
  57. package/dist/commands/list-imported.js.map +1 -0
  58. package/dist/commands/list-page-sections.d.ts +3 -0
  59. package/dist/commands/list-page-sections.d.ts.map +1 -0
  60. package/dist/commands/list-page-sections.js +25 -0
  61. package/dist/commands/list-page-sections.js.map +1 -0
  62. package/dist/commands/list-pages.d.ts +3 -0
  63. package/dist/commands/list-pages.d.ts.map +1 -0
  64. package/dist/commands/list-pages.js +21 -0
  65. package/dist/commands/list-pages.js.map +1 -0
  66. package/dist/commands/list-theme-globals.d.ts +3 -0
  67. package/dist/commands/list-theme-globals.d.ts.map +1 -0
  68. package/dist/commands/list-theme-globals.js +22 -0
  69. package/dist/commands/list-theme-globals.js.map +1 -0
  70. package/dist/commands/publish-theme.d.ts +3 -0
  71. package/dist/commands/publish-theme.d.ts.map +1 -0
  72. package/dist/commands/publish-theme.js +29 -0
  73. package/dist/commands/publish-theme.js.map +1 -0
  74. package/dist/commands/search-products.d.ts +3 -0
  75. package/dist/commands/search-products.d.ts.map +1 -0
  76. package/dist/commands/search-products.js +40 -0
  77. package/dist/commands/search-products.js.map +1 -0
  78. package/dist/commands/update-global-variable.d.ts +3 -0
  79. package/dist/commands/update-global-variable.d.ts.map +1 -0
  80. package/dist/commands/update-global-variable.js +47 -0
  81. package/dist/commands/update-global-variable.js.map +1 -0
  82. package/dist/commands/update-page-sections.d.ts +3 -0
  83. package/dist/commands/update-page-sections.d.ts.map +1 -0
  84. package/dist/commands/update-page-sections.js +39 -0
  85. package/dist/commands/update-page-sections.js.map +1 -0
  86. package/dist/commands/update-section-prop.d.ts +3 -0
  87. package/dist/commands/update-section-prop.d.ts.map +1 -0
  88. package/dist/commands/update-section-prop.js +59 -0
  89. package/dist/commands/update-section-prop.js.map +1 -0
  90. package/dist/commands/upload-image.d.ts +3 -0
  91. package/dist/commands/upload-image.d.ts.map +1 -0
  92. package/dist/commands/upload-image.js +38 -0
  93. package/dist/commands/upload-image.js.map +1 -0
  94. package/dist/commands/upload-images.d.ts +3 -0
  95. package/dist/commands/upload-images.d.ts.map +1 -0
  96. package/dist/commands/upload-images.js +48 -0
  97. package/dist/commands/upload-images.js.map +1 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +49 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/types.d.ts +1 -1
  102. package/dist/types.d.ts.map +1 -1
  103. package/dist/utils/compile.d.ts +4 -1
  104. package/dist/utils/compile.d.ts.map +1 -1
  105. package/dist/utils/compile.js +517 -48
  106. package/dist/utils/compile.js.map +1 -1
  107. package/dist/utils/component-helpers.d.ts +1 -1
  108. package/dist/utils/component-helpers.d.ts.map +1 -1
  109. package/dist/utils/component-helpers.js +4 -0
  110. package/dist/utils/component-helpers.js.map +1 -1
  111. package/dist/utils/editor-action-client.d.ts +28 -0
  112. package/dist/utils/editor-action-client.d.ts.map +1 -0
  113. package/dist/utils/editor-action-client.js +116 -0
  114. package/dist/utils/editor-action-client.js.map +1 -0
  115. package/dist/utils/load-image.d.ts +16 -0
  116. package/dist/utils/load-image.d.ts.map +1 -0
  117. package/dist/utils/load-image.js +50 -0
  118. package/dist/utils/load-image.js.map +1 -0
  119. package/dist/utils/websocket-server.d.ts +48 -0
  120. package/dist/utils/websocket-server.d.ts.map +1 -1
  121. package/dist/utils/websocket-server.js +58 -0
  122. package/dist/utils/websocket-server.js.map +1 -1
  123. package/package.json +1 -1
@@ -17,9 +17,48 @@ function loadConfig() {
17
17
  function saveConfig(configPath, config) {
18
18
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
19
19
  }
20
- function findComponent(config, name) {
21
- const pascalName = toPascalCase(name);
22
- return config.components.find((c) => c.name === pascalName);
20
+ /**
21
+ * Resolve a component by canonical id (preferred) or exact PascalCase name.
22
+ * No silent normalization: pass --id from `config list-components`, or pass --name
23
+ * exactly as stored in ikas.config.json. Exits with a structured JSON error
24
+ * (listing valid {id, name} pairs) if zero/both/missing.
25
+ */
26
+ function resolveComponent(config, ref) {
27
+ const id = ref.id?.trim() || undefined;
28
+ const name = ref.name?.trim() || undefined;
29
+ if (!id && !name) {
30
+ console.log(JSON.stringify({
31
+ success: false,
32
+ error: "Component reference required: pass --id (preferred) or --name (exact PascalCase). " +
33
+ "Run `ikas-component config list-components` to see canonical ids.",
34
+ validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
35
+ }));
36
+ process.exit(1);
37
+ }
38
+ if (id && name) {
39
+ console.log(JSON.stringify({
40
+ success: false,
41
+ error: "Specify only one of --id or --name, not both.",
42
+ }));
43
+ process.exit(1);
44
+ }
45
+ const found = id
46
+ ? config.components.find((c) => c.id === id)
47
+ : config.components.find((c) => c.name === name);
48
+ if (!found) {
49
+ console.log(JSON.stringify({
50
+ success: false,
51
+ error: id
52
+ ? `Component not found: id="${id}".`
53
+ : `Component not found: name="${name}". Names are matched exactly (PascalCase, no normalization).`,
54
+ lookup: id ? { id } : { name },
55
+ validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
56
+ hint: "Use --id (preferred) or exact PascalCase --name. " +
57
+ "Run `ikas-component config list-components` to see canonical ids.",
58
+ }));
59
+ process.exit(1);
60
+ }
61
+ return found;
23
62
  }
24
63
  function getComponentNames(config) {
25
64
  return config.components.map((c) => c.name);
@@ -105,6 +144,19 @@ function camelCaseToDisplayName(name) {
105
144
  .replace(/([a-z])([A-Z])/g, "$1 $2")
106
145
  .replace(/^./, (c) => c.toUpperCase());
107
146
  }
147
+ const ALLOWED_PROP_FIELDS = new Set([
148
+ "name",
149
+ "displayName",
150
+ "type",
151
+ "required",
152
+ "description",
153
+ "defaultValue",
154
+ "groupId",
155
+ "typeId",
156
+ "enumTypeId",
157
+ "filteredComponentIds",
158
+ "privateVarMap",
159
+ ]);
108
160
  /**
109
161
  * Parse and validate the --props JSON flag for add-component.
110
162
  * Returns validated ComponentProp[] or exits with error.
@@ -132,6 +184,16 @@ async function parsePropsFlag(propsJson, config, configPath) {
132
184
  const props = [];
133
185
  for (const raw of rawProps) {
134
186
  const r = raw;
187
+ const unknownFields = Object.keys(r).filter((k) => !ALLOWED_PROP_FIELDS.has(k));
188
+ if (unknownFields.length > 0) {
189
+ console.log(JSON.stringify({
190
+ success: false,
191
+ error: `Unknown field(s) in --props entry: ${unknownFields.join(", ")}. ` +
192
+ `Allowed: ${[...ALLOWED_PROP_FIELDS].join(", ")}. ` +
193
+ `Note: use "groupId" (not "group") and "defaultValue" (not "default") in --props JSON.`,
194
+ }));
195
+ process.exit(1);
196
+ }
135
197
  if (!r.name || typeof r.name !== "string") {
136
198
  console.log(JSON.stringify({
137
199
  success: false,
@@ -322,16 +384,9 @@ async function addComponent(name, options) {
322
384
  ],
323
385
  }));
324
386
  }
325
- async function addProp(componentName, options) {
387
+ async function addProp(ref, options) {
326
388
  const { config, configPath } = loadConfig();
327
- const component = findComponent(config, componentName);
328
- if (!component) {
329
- console.log(JSON.stringify({
330
- success: false,
331
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
332
- }));
333
- process.exit(1);
334
- }
389
+ const component = resolveComponent(config, ref);
335
390
  // Validate prop type
336
391
  const propType = options.type.toUpperCase();
337
392
  if (!PROP_TYPES.includes(propType)) {
@@ -479,16 +534,9 @@ function parseDefaultValue(value, propType) {
479
534
  return value;
480
535
  }
481
536
  }
482
- function updateProp(componentName, options) {
537
+ function updateProp(ref, options) {
483
538
  const { config, configPath } = loadConfig();
484
- const component = findComponent(config, componentName);
485
- if (!component) {
486
- console.log(JSON.stringify({
487
- success: false,
488
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
489
- }));
490
- process.exit(1);
491
- }
539
+ const component = resolveComponent(config, ref);
492
540
  const propIndex = component.props.findIndex((p) => p.name === options.prop);
493
541
  if (propIndex === -1) {
494
542
  console.log(JSON.stringify({
@@ -622,16 +670,9 @@ function updateProp(componentName, options) {
622
670
  },
623
671
  }));
624
672
  }
625
- function removeProp(componentName, options) {
673
+ function removeProp(ref, options) {
626
674
  const { config, configPath } = loadConfig();
627
- const component = findComponent(config, componentName);
628
- if (!component) {
629
- console.log(JSON.stringify({
630
- success: false,
631
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
632
- }));
633
- process.exit(1);
634
- }
675
+ const component = resolveComponent(config, ref);
635
676
  const propIndex = component.props.findIndex((p) => p.name === options.prop);
636
677
  if (propIndex === -1) {
637
678
  console.log(JSON.stringify({
@@ -652,21 +693,30 @@ function removeProp(componentName, options) {
652
693
  remainingProps: component.props.map((p) => p.name),
653
694
  }));
654
695
  }
655
- function removeComponent(options) {
656
- const { config, configPath } = loadConfig();
657
- const pascalName = toPascalCase(options.name);
658
- const componentIndex = config.components.findIndex((c) => c.name === pascalName);
659
- if (componentIndex === -1) {
660
- console.log(JSON.stringify({
661
- success: false,
662
- error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
663
- }));
664
- process.exit(1);
696
+ /**
697
+ * Strip a deleted component's ID from every other component's COMPONENT/COMPONENT_LIST
698
+ * `filteredComponentIds` allowlist. Empty arrays are deleted to keep the field optional
699
+ * (mirrors the editor-side convention).
700
+ */
701
+ function pruneFilteredComponentIdRefs(config, removedId) {
702
+ for (const component of config.components) {
703
+ for (const prop of component.props || []) {
704
+ if (!prop.filteredComponentIds)
705
+ continue;
706
+ prop.filteredComponentIds = prop.filteredComponentIds.filter((id) => id !== removedId);
707
+ if (prop.filteredComponentIds.length === 0)
708
+ delete prop.filteredComponentIds;
709
+ }
665
710
  }
666
- const component = config.components[componentIndex];
711
+ }
712
+ function removeComponent(ref) {
713
+ const { config, configPath } = loadConfig();
714
+ const component = resolveComponent(config, ref);
715
+ const componentIndex = config.components.indexOf(component);
667
716
  const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
668
- // Remove component from config
717
+ // Remove component from config and strip orphaned references from remaining components
669
718
  config.components.splice(componentIndex, 1);
719
+ pruneFilteredComponentIdRefs(config, component.id);
670
720
  saveConfig(configPath, config);
671
721
  // Remove component directory
672
722
  if (fs.existsSync(componentDir)) {
@@ -676,21 +726,15 @@ function removeComponent(options) {
676
726
  updateBarrelExport(process.cwd(), getComponentNames(config));
677
727
  console.log(JSON.stringify({
678
728
  success: true,
679
- removedComponent: pascalName,
729
+ removedComponentId: component.id,
730
+ removedComponentName: component.name,
680
731
  removedDirectory: path.relative(process.cwd(), componentDir),
681
- remainingComponents: getComponentNames(config),
732
+ remainingComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
682
733
  }));
683
734
  }
684
- function addPropGroup(componentName, options) {
735
+ function addPropGroup(ref, options) {
685
736
  const { config, configPath } = loadConfig();
686
- const component = findComponent(config, componentName);
687
- if (!component) {
688
- console.log(JSON.stringify({
689
- success: false,
690
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
691
- }));
692
- process.exit(1);
693
- }
737
+ const component = resolveComponent(config, ref);
694
738
  if (!component.propGroups)
695
739
  component.propGroups = [];
696
740
  // Check uniqueness
@@ -741,16 +785,9 @@ function addPropGroup(componentName, options) {
741
785
  },
742
786
  }));
743
787
  }
744
- function updatePropGroup(componentName, options) {
788
+ function updatePropGroup(ref, options) {
745
789
  const { config, configPath } = loadConfig();
746
- const component = findComponent(config, componentName);
747
- if (!component) {
748
- console.log(JSON.stringify({
749
- success: false,
750
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
751
- }));
752
- process.exit(1);
753
- }
790
+ const component = resolveComponent(config, ref);
754
791
  if (!component.propGroups || component.propGroups.length === 0) {
755
792
  console.log(JSON.stringify({
756
793
  success: false,
@@ -780,16 +817,9 @@ function updatePropGroup(componentName, options) {
780
817
  },
781
818
  }));
782
819
  }
783
- function removePropGroup(componentName, options) {
820
+ function removePropGroup(ref, options) {
784
821
  const { config, configPath } = loadConfig();
785
- const component = findComponent(config, componentName);
786
- if (!component) {
787
- console.log(JSON.stringify({
788
- success: false,
789
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
790
- }));
791
- process.exit(1);
792
- }
822
+ const component = resolveComponent(config, ref);
793
823
  if (!component.propGroups || component.propGroups.length === 0) {
794
824
  console.log(JSON.stringify({
795
825
  success: false,
@@ -825,16 +855,9 @@ function removePropGroup(componentName, options) {
825
855
  remainingPropGroups: component.propGroups.map(g => g.id),
826
856
  }));
827
857
  }
828
- function movePropGroup(componentName, options) {
858
+ function movePropGroup(ref, options) {
829
859
  const { config, configPath } = loadConfig();
830
- const component = findComponent(config, componentName);
831
- if (!component) {
832
- console.log(JSON.stringify({
833
- success: false,
834
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
835
- }));
836
- process.exit(1);
837
- }
860
+ const component = resolveComponent(config, ref);
838
861
  if (!component.propGroups || component.propGroups.length === 0) {
839
862
  console.log(JSON.stringify({
840
863
  success: false,
@@ -857,16 +880,9 @@ function movePropGroup(componentName, options) {
857
880
  parentGroupId: options.parent || null,
858
881
  }));
859
882
  }
860
- function updateComponent(options) {
883
+ function updateComponent(ref, options) {
861
884
  const { config, configPath } = loadConfig();
862
- const component = findComponent(config, options.name);
863
- if (!component) {
864
- console.log(JSON.stringify({
865
- success: false,
866
- error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
867
- }));
868
- process.exit(1);
869
- }
885
+ const component = resolveComponent(config, ref);
870
886
  if (options.isHeader !== undefined) {
871
887
  if (options.isHeader) {
872
888
  component.isHeader = true;
@@ -1119,14 +1135,16 @@ export function createConfigCommand() {
1119
1135
  .option("--type <type>", "Component type: section or component", "component")
1120
1136
  .option("--isHeader", "Mark this section as the store header (only for type: section)")
1121
1137
  .option("--isFooter", "Mark this section as the store footer (only for type: section)")
1122
- .option("--props <json>", "JSON array of props, e.g. '[{\"name\":\"title\",\"type\":\"TEXT\",\"required\":true}]'. Each prop needs name+type; displayName is auto-generated from name if omitted.")
1138
+ .option("--props <json>", "JSON array of props. Required per entry: name, type. Optional: displayName (auto from name), required, description, defaultValue, groupId, typeId (TYPE props), enumTypeId (ENUM props), filteredComponentIds, privateVarMap. " +
1139
+ "Example: '[{\"name\":\"title\",\"type\":\"TEXT\",\"required\":true,\"defaultValue\":\"Hello\",\"groupId\":\"basic\"}]'")
1123
1140
  .action((options) => {
1124
1141
  addComponent(options.name, options);
1125
1142
  });
1126
1143
  config
1127
1144
  .command("add-prop")
1128
1145
  .description("Add a prop to a component")
1129
- .requiredOption("--component <name>", "Component name")
1146
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1147
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1130
1148
  .requiredOption("--name <name>", "Prop name (camelCase)")
1131
1149
  .requiredOption("--displayName <displayName>", "Display name in editor")
1132
1150
  .requiredOption("--type <type>", `Prop type: ${PROP_TYPES.join(", ")}`)
@@ -1139,12 +1157,13 @@ export function createConfigCommand() {
1139
1157
  .option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
1140
1158
  .option("--privateVarMap <json>", 'JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)')
1141
1159
  .action((options) => {
1142
- addProp(options.component, options);
1160
+ addProp({ id: options.componentId, name: options.component }, options);
1143
1161
  });
1144
1162
  config
1145
1163
  .command("update-prop")
1146
1164
  .description("Update a prop on a component")
1147
- .requiredOption("--component <name>", "Component name")
1165
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1166
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1148
1167
  .requiredOption("--prop <propName>", "Prop name to update")
1149
1168
  .option("--displayName <displayName>", "New display name")
1150
1169
  .option("--type <type>", "New prop type")
@@ -1157,76 +1176,89 @@ export function createConfigCommand() {
1157
1176
  .option("--filteredComponentIds <json>", "JSON array of component IDs (use 'none' to clear)")
1158
1177
  .option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (use 'none' to clear)")
1159
1178
  .action((options) => {
1160
- updateProp(options.component, options);
1179
+ updateProp({ id: options.componentId, name: options.component }, options);
1161
1180
  });
1162
1181
  config
1163
1182
  .command("remove-prop")
1164
1183
  .description("Remove a prop from a component")
1165
- .requiredOption("--component <name>", "Component name")
1184
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1185
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1166
1186
  .requiredOption("--prop <propName>", "Prop name to remove")
1167
1187
  .action((options) => {
1168
- removeProp(options.component, options);
1188
+ removeProp({ id: options.componentId, name: options.component }, options);
1169
1189
  });
1170
1190
  config
1171
1191
  .command("update-component")
1172
- .description("Update a component's metadata (isHeader, isFooter)")
1173
- .requiredOption("--name <name>", "Component name")
1192
+ .description("Update a component's metadata (isHeader, isFooter). Identify by --id (preferred) or exact --name.")
1193
+ .option("--id <id>", "Component id (preferred; from `config list-components`)")
1194
+ .option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1174
1195
  .option("--isHeader", "Mark as store header")
1175
1196
  .option("--no-isHeader", "Unmark as store header")
1176
1197
  .option("--isFooter", "Mark as store footer")
1177
1198
  .option("--no-isFooter", "Unmark as store footer")
1178
1199
  .action((options) => {
1179
- updateComponent(options);
1200
+ updateComponent({ id: options.id, name: options.name }, options);
1180
1201
  });
1181
1202
  config
1182
1203
  .command("remove-component")
1183
- .description("Remove a component from the project (deletes files)")
1184
- .requiredOption("--name <name>", "Component name to remove")
1204
+ .description("Remove a component from the project (deletes files). Identify by --id (preferred) or exact --name.")
1205
+ .option("--id <id>", "Component id (preferred; from `config list-components`)")
1206
+ .option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1185
1207
  .action((options) => {
1186
- removeComponent(options);
1208
+ removeComponent({ id: options.id, name: options.name });
1187
1209
  });
1188
1210
  config
1189
1211
  .command("add-prop-group")
1190
1212
  .description("Add a prop group to a component")
1191
- .requiredOption("--component <name>", "Component name")
1213
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1214
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1192
1215
  .requiredOption("--id <id>", "Group ID (unique within component, kebab-case)")
1193
1216
  .requiredOption("--name <name>", "Display name in editor")
1194
1217
  .option("--description <description>", "Group description")
1195
1218
  .option("--parent <parentId>", "Parent group ID (for nesting, max 1 level)")
1196
1219
  .action((options) => {
1197
- addPropGroup(options.component, options);
1220
+ addPropGroup({ id: options.componentId, name: options.component }, options);
1198
1221
  });
1199
1222
  config
1200
1223
  .command("update-prop-group")
1201
1224
  .description("Update a prop group on a component")
1202
- .requiredOption("--component <name>", "Component name")
1225
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1226
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1203
1227
  .requiredOption("--id <id>", "Group ID to update")
1204
1228
  .option("--name <name>", "New display name")
1205
1229
  .option("--description <description>", "New description")
1206
1230
  .action((options) => {
1207
- updatePropGroup(options.component, options);
1231
+ updatePropGroup({ id: options.componentId, name: options.component }, options);
1208
1232
  });
1209
1233
  config
1210
1234
  .command("remove-prop-group")
1211
1235
  .description("Remove a prop group from a component (props become ungrouped)")
1212
- .requiredOption("--component <name>", "Component name")
1236
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1237
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1213
1238
  .requiredOption("--id <id>", "Group ID to remove")
1214
1239
  .action((options) => {
1215
- removePropGroup(options.component, options);
1240
+ removePropGroup({ id: options.componentId, name: options.component }, options);
1216
1241
  });
1217
1242
  config
1218
1243
  .command("move-prop-group")
1219
1244
  .description("Move a prop group to a different parent or position (for drag-and-drop reordering)")
1220
- .requiredOption("--component <name>", "Component name")
1245
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1246
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1221
1247
  .requiredOption("--id <id>", "Group ID to move")
1222
1248
  .option("--parent <parentId>", "Target parent group ID (omit to move to root)")
1223
1249
  .option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", v => parseInt(v, 10))
1224
1250
  .action((options) => {
1225
- movePropGroup(options.component, options);
1251
+ movePropGroup({ id: options.componentId, name: options.component }, options);
1252
+ });
1253
+ config
1254
+ .command("list-components")
1255
+ .description("List all components and their props (with canonical ids for use with --id flags)")
1256
+ .action(() => {
1257
+ listComponents();
1226
1258
  });
1227
1259
  config
1228
1260
  .command("list")
1229
- .description("List all components and their props")
1261
+ .description("Alias for `list-components` (kept for backwards compatibility)")
1230
1262
  .action(() => {
1231
1263
  listComponents();
1232
1264
  });