@ikas/component-cli 2.1.0 → 2.2.0

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 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA28CpC,wBAAgB,mBAAmB,IAAI,OAAO,CAuL7C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA49CpC,wBAAgB,mBAAmB,IAAI,OAAO,CAuM7C"}
@@ -1,7 +1,7 @@
1
1
  import { Command } from "commander";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
- import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, generateComponentId, generateUniqueId, updateBarrelExport, findPropGroup, collectPropGroupIds, movePropGroupInTree, } from "../utils/component-helpers.js";
4
+ import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, generateComponentId, generateUniqueId, updateBarrelExport, findPropGroup, collectPropGroupIds, movePropGroupInTree, validateFilteredComponentIds, } from "../utils/component-helpers.js";
5
5
  function loadConfig() {
6
6
  const configPath = path.resolve(process.cwd(), "ikas.config.json");
7
7
  if (!fs.existsSync(configPath)) {
@@ -17,13 +17,79 @@ 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);
26
65
  }
66
+ /**
67
+ * Emit a structured JSON error for unknown filteredComponentIds entries and exit non-zero.
68
+ * Lists valid `{ id, name }` pairs so the LLM/caller can recover.
69
+ */
70
+ function emitFilteredComponentIdsError(unknown, components) {
71
+ console.log(JSON.stringify({
72
+ success: false,
73
+ error: `Unknown filteredComponentIds: ${unknown.join(", ")}. ` +
74
+ `Component ids are opaque and cannot be derived from names — they must come from the ` +
75
+ `componentId returned by 'config add-component' or from 'config list'.`,
76
+ validComponents: components.map((c) => ({ id: c.id, name: c.name })),
77
+ }));
78
+ process.exit(1);
79
+ }
80
+ /**
81
+ * Validate `input` ids against `config.components` and return the same array on success.
82
+ * Exits with a JSON error if any id is unknown. Use at every write site that accepts
83
+ * filteredComponentIds from user/LLM input.
84
+ */
85
+ function assertKnownComponentIds(input, config) {
86
+ const components = config?.components ?? [];
87
+ const { unknown } = validateFilteredComponentIds(input, components);
88
+ if (unknown.length > 0) {
89
+ emitFilteredComponentIdsError(unknown, components);
90
+ }
91
+ return input;
92
+ }
27
93
  function regenerateTypes(component, componentType, config) {
28
94
  const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
29
95
  const typesPath = path.join(componentDir, "types.ts");
@@ -201,7 +267,7 @@ async function parsePropsFlag(propsJson, config, configPath) {
201
267
  ? { enumTypeId: r.enumTypeId }
202
268
  : {}),
203
269
  ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.filteredComponentIds && Array.isArray(r.filteredComponentIds)
204
- ? { filteredComponentIds: r.filteredComponentIds }
270
+ ? { filteredComponentIds: assertKnownComponentIds(r.filteredComponentIds, config) }
205
271
  : {}),
206
272
  ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.privateVarMap && typeof r.privateVarMap === "object"
207
273
  ? { privateVarMap: r.privateVarMap }
@@ -236,14 +302,15 @@ async function addComponent(name, options) {
236
302
  if (!config.projectId) {
237
303
  config.projectId = generateProjectId();
238
304
  }
305
+ // Parse --props (and validate filteredComponentIds) BEFORE any filesystem side-effects
306
+ // so a bad payload doesn't leave an empty component directory behind.
307
+ const props = options.props
308
+ ? await parsePropsFlag(options.props, config, configPath)
309
+ : [];
239
310
  const componentId = generateComponentId(config.projectId);
240
311
  const componentDir = path.resolve(process.cwd(), `src/components/${pascalName}`);
241
312
  // Create directory
242
313
  fs.mkdirSync(componentDir, { recursive: true });
243
- // Parse --props if provided, otherwise empty
244
- const props = options.props
245
- ? await parsePropsFlag(options.props, config, configPath)
246
- : [];
247
314
  // Auto-create prop groups from groupId references in props
248
315
  const referencedGroupIds = new Set();
249
316
  for (const prop of props) {
@@ -294,16 +361,9 @@ async function addComponent(name, options) {
294
361
  ],
295
362
  }));
296
363
  }
297
- async function addProp(componentName, options) {
364
+ async function addProp(ref, options) {
298
365
  const { config, configPath } = loadConfig();
299
- const component = findComponent(config, componentName);
300
- if (!component) {
301
- console.log(JSON.stringify({
302
- success: false,
303
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
304
- }));
305
- process.exit(1);
306
- }
366
+ const component = resolveComponent(config, ref);
307
367
  // Validate prop type
308
368
  const propType = options.type.toUpperCase();
309
369
  if (!PROP_TYPES.includes(propType)) {
@@ -389,6 +449,7 @@ async function addProp(componentName, options) {
389
449
  console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
390
450
  process.exit(1);
391
451
  }
452
+ assertKnownComponentIds(parsedFilteredIds, config);
392
453
  }
393
454
  // Parse privateVarMap JSON for COMPONENT/COMPONENT_LIST
394
455
  let parsedPrivateVarMap;
@@ -450,16 +511,9 @@ function parseDefaultValue(value, propType) {
450
511
  return value;
451
512
  }
452
513
  }
453
- function updateProp(componentName, options) {
514
+ function updateProp(ref, options) {
454
515
  const { config, configPath } = loadConfig();
455
- const component = findComponent(config, componentName);
456
- if (!component) {
457
- console.log(JSON.stringify({
458
- success: false,
459
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
460
- }));
461
- process.exit(1);
462
- }
516
+ const component = resolveComponent(config, ref);
463
517
  const propIndex = component.props.findIndex((p) => p.name === options.prop);
464
518
  if (propIndex === -1) {
465
519
  console.log(JSON.stringify({
@@ -542,11 +596,15 @@ function updateProp(componentName, options) {
542
596
  console.log(JSON.stringify({ success: false, error: "--filteredComponentIds must be a JSON array of strings." }));
543
597
  process.exit(1);
544
598
  }
599
+ assertKnownComponentIds(parsed, config);
545
600
  prop.filteredComponentIds = parsed;
546
601
  }
547
- catch {
548
- console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
549
- process.exit(1);
602
+ catch (err) {
603
+ if (err instanceof SyntaxError) {
604
+ console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
605
+ process.exit(1);
606
+ }
607
+ throw err;
550
608
  }
551
609
  }
552
610
  }
@@ -589,16 +647,9 @@ function updateProp(componentName, options) {
589
647
  },
590
648
  }));
591
649
  }
592
- function removeProp(componentName, options) {
650
+ function removeProp(ref, options) {
593
651
  const { config, configPath } = loadConfig();
594
- const component = findComponent(config, componentName);
595
- if (!component) {
596
- console.log(JSON.stringify({
597
- success: false,
598
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
599
- }));
600
- process.exit(1);
601
- }
652
+ const component = resolveComponent(config, ref);
602
653
  const propIndex = component.props.findIndex((p) => p.name === options.prop);
603
654
  if (propIndex === -1) {
604
655
  console.log(JSON.stringify({
@@ -619,21 +670,30 @@ function removeProp(componentName, options) {
619
670
  remainingProps: component.props.map((p) => p.name),
620
671
  }));
621
672
  }
622
- function removeComponent(options) {
623
- const { config, configPath } = loadConfig();
624
- const pascalName = toPascalCase(options.name);
625
- const componentIndex = config.components.findIndex((c) => c.name === pascalName);
626
- if (componentIndex === -1) {
627
- console.log(JSON.stringify({
628
- success: false,
629
- error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
630
- }));
631
- process.exit(1);
673
+ /**
674
+ * Strip a deleted component's ID from every other component's COMPONENT/COMPONENT_LIST
675
+ * `filteredComponentIds` allowlist. Empty arrays are deleted to keep the field optional
676
+ * (mirrors the editor-side convention).
677
+ */
678
+ function pruneFilteredComponentIdRefs(config, removedId) {
679
+ for (const component of config.components) {
680
+ for (const prop of component.props || []) {
681
+ if (!prop.filteredComponentIds)
682
+ continue;
683
+ prop.filteredComponentIds = prop.filteredComponentIds.filter((id) => id !== removedId);
684
+ if (prop.filteredComponentIds.length === 0)
685
+ delete prop.filteredComponentIds;
686
+ }
632
687
  }
633
- const component = config.components[componentIndex];
688
+ }
689
+ function removeComponent(ref) {
690
+ const { config, configPath } = loadConfig();
691
+ const component = resolveComponent(config, ref);
692
+ const componentIndex = config.components.indexOf(component);
634
693
  const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
635
- // Remove component from config
694
+ // Remove component from config and strip orphaned references from remaining components
636
695
  config.components.splice(componentIndex, 1);
696
+ pruneFilteredComponentIdRefs(config, component.id);
637
697
  saveConfig(configPath, config);
638
698
  // Remove component directory
639
699
  if (fs.existsSync(componentDir)) {
@@ -643,21 +703,15 @@ function removeComponent(options) {
643
703
  updateBarrelExport(process.cwd(), getComponentNames(config));
644
704
  console.log(JSON.stringify({
645
705
  success: true,
646
- removedComponent: pascalName,
706
+ removedComponentId: component.id,
707
+ removedComponentName: component.name,
647
708
  removedDirectory: path.relative(process.cwd(), componentDir),
648
- remainingComponents: getComponentNames(config),
709
+ remainingComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
649
710
  }));
650
711
  }
651
- function addPropGroup(componentName, options) {
712
+ function addPropGroup(ref, options) {
652
713
  const { config, configPath } = loadConfig();
653
- const component = findComponent(config, componentName);
654
- if (!component) {
655
- console.log(JSON.stringify({
656
- success: false,
657
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
658
- }));
659
- process.exit(1);
660
- }
714
+ const component = resolveComponent(config, ref);
661
715
  if (!component.propGroups)
662
716
  component.propGroups = [];
663
717
  // Check uniqueness
@@ -708,16 +762,9 @@ function addPropGroup(componentName, options) {
708
762
  },
709
763
  }));
710
764
  }
711
- function updatePropGroup(componentName, options) {
765
+ function updatePropGroup(ref, options) {
712
766
  const { config, configPath } = loadConfig();
713
- const component = findComponent(config, componentName);
714
- if (!component) {
715
- console.log(JSON.stringify({
716
- success: false,
717
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
718
- }));
719
- process.exit(1);
720
- }
767
+ const component = resolveComponent(config, ref);
721
768
  if (!component.propGroups || component.propGroups.length === 0) {
722
769
  console.log(JSON.stringify({
723
770
  success: false,
@@ -747,16 +794,9 @@ function updatePropGroup(componentName, options) {
747
794
  },
748
795
  }));
749
796
  }
750
- function removePropGroup(componentName, options) {
797
+ function removePropGroup(ref, options) {
751
798
  const { config, configPath } = loadConfig();
752
- const component = findComponent(config, componentName);
753
- if (!component) {
754
- console.log(JSON.stringify({
755
- success: false,
756
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
757
- }));
758
- process.exit(1);
759
- }
799
+ const component = resolveComponent(config, ref);
760
800
  if (!component.propGroups || component.propGroups.length === 0) {
761
801
  console.log(JSON.stringify({
762
802
  success: false,
@@ -792,16 +832,9 @@ function removePropGroup(componentName, options) {
792
832
  remainingPropGroups: component.propGroups.map(g => g.id),
793
833
  }));
794
834
  }
795
- function movePropGroup(componentName, options) {
835
+ function movePropGroup(ref, options) {
796
836
  const { config, configPath } = loadConfig();
797
- const component = findComponent(config, componentName);
798
- if (!component) {
799
- console.log(JSON.stringify({
800
- success: false,
801
- error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
802
- }));
803
- process.exit(1);
804
- }
837
+ const component = resolveComponent(config, ref);
805
838
  if (!component.propGroups || component.propGroups.length === 0) {
806
839
  console.log(JSON.stringify({
807
840
  success: false,
@@ -824,16 +857,9 @@ function movePropGroup(componentName, options) {
824
857
  parentGroupId: options.parent || null,
825
858
  }));
826
859
  }
827
- function updateComponent(options) {
860
+ function updateComponent(ref, options) {
828
861
  const { config, configPath } = loadConfig();
829
- const component = findComponent(config, options.name);
830
- if (!component) {
831
- console.log(JSON.stringify({
832
- success: false,
833
- error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
834
- }));
835
- process.exit(1);
836
- }
862
+ const component = resolveComponent(config, ref);
837
863
  if (options.isHeader !== undefined) {
838
864
  if (options.isHeader) {
839
865
  component.isHeader = true;
@@ -1093,7 +1119,8 @@ export function createConfigCommand() {
1093
1119
  config
1094
1120
  .command("add-prop")
1095
1121
  .description("Add a prop to a component")
1096
- .requiredOption("--component <name>", "Component name")
1122
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1123
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1097
1124
  .requiredOption("--name <name>", "Prop name (camelCase)")
1098
1125
  .requiredOption("--displayName <displayName>", "Display name in editor")
1099
1126
  .requiredOption("--type <type>", `Prop type: ${PROP_TYPES.join(", ")}`)
@@ -1106,12 +1133,13 @@ export function createConfigCommand() {
1106
1133
  .option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
1107
1134
  .option("--privateVarMap <json>", 'JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)')
1108
1135
  .action((options) => {
1109
- addProp(options.component, options);
1136
+ addProp({ id: options.componentId, name: options.component }, options);
1110
1137
  });
1111
1138
  config
1112
1139
  .command("update-prop")
1113
1140
  .description("Update a prop on a component")
1114
- .requiredOption("--component <name>", "Component name")
1141
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1142
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1115
1143
  .requiredOption("--prop <propName>", "Prop name to update")
1116
1144
  .option("--displayName <displayName>", "New display name")
1117
1145
  .option("--type <type>", "New prop type")
@@ -1124,76 +1152,89 @@ export function createConfigCommand() {
1124
1152
  .option("--filteredComponentIds <json>", "JSON array of component IDs (use 'none' to clear)")
1125
1153
  .option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (use 'none' to clear)")
1126
1154
  .action((options) => {
1127
- updateProp(options.component, options);
1155
+ updateProp({ id: options.componentId, name: options.component }, options);
1128
1156
  });
1129
1157
  config
1130
1158
  .command("remove-prop")
1131
1159
  .description("Remove a prop from a component")
1132
- .requiredOption("--component <name>", "Component name")
1160
+ .option("--component-id <id>", "Component id (preferred; from `config list-components`)")
1161
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1133
1162
  .requiredOption("--prop <propName>", "Prop name to remove")
1134
1163
  .action((options) => {
1135
- removeProp(options.component, options);
1164
+ removeProp({ id: options.componentId, name: options.component }, options);
1136
1165
  });
1137
1166
  config
1138
1167
  .command("update-component")
1139
- .description("Update a component's metadata (isHeader, isFooter)")
1140
- .requiredOption("--name <name>", "Component name")
1168
+ .description("Update a component's metadata (isHeader, isFooter). Identify by --id (preferred) or exact --name.")
1169
+ .option("--id <id>", "Component id (preferred; from `config list-components`)")
1170
+ .option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1141
1171
  .option("--isHeader", "Mark as store header")
1142
1172
  .option("--no-isHeader", "Unmark as store header")
1143
1173
  .option("--isFooter", "Mark as store footer")
1144
1174
  .option("--no-isFooter", "Unmark as store footer")
1145
1175
  .action((options) => {
1146
- updateComponent(options);
1176
+ updateComponent({ id: options.id, name: options.name }, options);
1147
1177
  });
1148
1178
  config
1149
1179
  .command("remove-component")
1150
- .description("Remove a component from the project (deletes files)")
1151
- .requiredOption("--name <name>", "Component name to remove")
1180
+ .description("Remove a component from the project (deletes files). Identify by --id (preferred) or exact --name.")
1181
+ .option("--id <id>", "Component id (preferred; from `config list-components`)")
1182
+ .option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1152
1183
  .action((options) => {
1153
- removeComponent(options);
1184
+ removeComponent({ id: options.id, name: options.name });
1154
1185
  });
1155
1186
  config
1156
1187
  .command("add-prop-group")
1157
1188
  .description("Add a prop group to a component")
1158
- .requiredOption("--component <name>", "Component name")
1189
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1190
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1159
1191
  .requiredOption("--id <id>", "Group ID (unique within component, kebab-case)")
1160
1192
  .requiredOption("--name <name>", "Display name in editor")
1161
1193
  .option("--description <description>", "Group description")
1162
1194
  .option("--parent <parentId>", "Parent group ID (for nesting, max 1 level)")
1163
1195
  .action((options) => {
1164
- addPropGroup(options.component, options);
1196
+ addPropGroup({ id: options.componentId, name: options.component }, options);
1165
1197
  });
1166
1198
  config
1167
1199
  .command("update-prop-group")
1168
1200
  .description("Update a prop group on a component")
1169
- .requiredOption("--component <name>", "Component name")
1201
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1202
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1170
1203
  .requiredOption("--id <id>", "Group ID to update")
1171
1204
  .option("--name <name>", "New display name")
1172
1205
  .option("--description <description>", "New description")
1173
1206
  .action((options) => {
1174
- updatePropGroup(options.component, options);
1207
+ updatePropGroup({ id: options.componentId, name: options.component }, options);
1175
1208
  });
1176
1209
  config
1177
1210
  .command("remove-prop-group")
1178
1211
  .description("Remove a prop group from a component (props become ungrouped)")
1179
- .requiredOption("--component <name>", "Component name")
1212
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1213
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1180
1214
  .requiredOption("--id <id>", "Group ID to remove")
1181
1215
  .action((options) => {
1182
- removePropGroup(options.component, options);
1216
+ removePropGroup({ id: options.componentId, name: options.component }, options);
1183
1217
  });
1184
1218
  config
1185
1219
  .command("move-prop-group")
1186
1220
  .description("Move a prop group to a different parent or position (for drag-and-drop reordering)")
1187
- .requiredOption("--component <name>", "Component name")
1221
+ .option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
1222
+ .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1188
1223
  .requiredOption("--id <id>", "Group ID to move")
1189
1224
  .option("--parent <parentId>", "Target parent group ID (omit to move to root)")
1190
1225
  .option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", v => parseInt(v, 10))
1191
1226
  .action((options) => {
1192
- movePropGroup(options.component, options);
1227
+ movePropGroup({ id: options.componentId, name: options.component }, options);
1228
+ });
1229
+ config
1230
+ .command("list-components")
1231
+ .description("List all components and their props (with canonical ids for use with --id flags)")
1232
+ .action(() => {
1233
+ listComponents();
1193
1234
  });
1194
1235
  config
1195
1236
  .command("list")
1196
- .description("List all components and their props")
1237
+ .description("Alias for `list-components` (kept for backwards compatibility)")
1197
1238
  .action(() => {
1198
1239
  listComponents();
1199
1240
  });