@ikas/component-cli 2.5.1 → 2.6.1

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 (44) hide show
  1. package/dist/commands/add.d.ts.map +1 -1
  2. package/dist/commands/add.js +10 -1
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/config.d.ts.map +1 -1
  5. package/dist/commands/config.js +224 -46
  6. package/dist/commands/config.js.map +1 -1
  7. package/dist/commands/create-design-tokens.d.ts +17 -0
  8. package/dist/commands/create-design-tokens.d.ts.map +1 -1
  9. package/dist/commands/create-design-tokens.js +194 -24
  10. package/dist/commands/create-design-tokens.js.map +1 -1
  11. package/dist/commands/delete-theme-globals.d.ts.map +1 -1
  12. package/dist/commands/delete-theme-globals.js +3 -3
  13. package/dist/commands/delete-theme-globals.js.map +1 -1
  14. package/dist/commands/dev.d.ts.map +1 -1
  15. package/dist/commands/dev.js +70 -9
  16. package/dist/commands/dev.js.map +1 -1
  17. package/dist/commands/publish.d.ts.map +1 -1
  18. package/dist/commands/publish.js +23 -2
  19. package/dist/commands/publish.js.map +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +27 -6
  22. package/dist/index.js.map +1 -1
  23. package/dist/types.d.ts +10 -0
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/utils/compile.d.ts.map +1 -1
  26. package/dist/utils/compile.js +21 -4
  27. package/dist/utils/compile.js.map +1 -1
  28. package/dist/utils/component-helpers.d.ts +56 -2
  29. package/dist/utils/component-helpers.d.ts.map +1 -1
  30. package/dist/utils/component-helpers.js +141 -4
  31. package/dist/utils/component-helpers.js.map +1 -1
  32. package/dist/utils/editor-action-client.d.ts +1 -1
  33. package/dist/utils/editor-action-client.d.ts.map +1 -1
  34. package/dist/utils/editor-action-client.js.map +1 -1
  35. package/dist/utils/forbid-external-packages.d.ts +16 -0
  36. package/dist/utils/forbid-external-packages.d.ts.map +1 -0
  37. package/dist/utils/forbid-external-packages.js +89 -0
  38. package/dist/utils/forbid-external-packages.js.map +1 -0
  39. package/dist/utils/websocket-server.d.ts +4 -2
  40. package/dist/utils/websocket-server.d.ts.map +1 -1
  41. package/dist/utils/websocket-server.js +1 -1
  42. package/dist/utils/websocket-server.js.map +1 -1
  43. package/package.json +1 -1
  44. package/templates/add/section.css +11 -0
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwMpC,wBAAgB,gBAAgB,IAAI,OAAO,CAI1C"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuNpC,wBAAgB,gBAAgB,IAAI,OAAO,CAI1C"}
@@ -4,7 +4,7 @@ import ora from "ora";
4
4
  import inquirer from "inquirer";
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
- import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, generateComponentId, } from "../utils/component-helpers.js";
7
+ import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, isValidProjectId, generateComponentId, } from "../utils/component-helpers.js";
8
8
  async function addComponent() {
9
9
  const configPath = path.resolve(process.cwd(), "ikas.config.json");
10
10
  // Check if we're in an ikas component project
@@ -100,6 +100,15 @@ async function addComponent() {
100
100
  });
101
101
  console.log(chalk.green(` Added prop "${propName}" (${propDetails.type})\n`));
102
102
  }
103
+ // A malformed projectId (hand-edited config) breaks the editor's republish
104
+ // stability: published/local id prefixes stop matching and every publish
105
+ // INSERTs duplicate design elements. Fail fast, before any filesystem writes.
106
+ if (config.projectId && !isValidProjectId(config.projectId)) {
107
+ console.error(chalk.red(`Error: invalid projectId "${config.projectId}" in ikas.config.json`));
108
+ console.error(chalk.gray("projectId must be at least 6 alphanumeric characters (no '-' or '_'). " +
109
+ "Restore the original generated value — do not hand-edit it."));
110
+ process.exit(1);
111
+ }
103
112
  // Create component
104
113
  const spinner = ora("Creating component...").start();
105
114
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,+BAA+B,CAAC;AAEvC,KAAK,UAAU,YAAY;IACzB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAEnE,8CAA8C;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC,CAAC;QACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,uBAAuB;IACvB,MAAM,MAAM,GAAwB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAErF,4BAA4B;IAC5B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC9C;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,6BAA6B;YACtC,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;gBAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAAE,OAAO,4BAA4B,CAAC;gBACvD,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1C,OAAO,8EAA8E,CAAC;gBACxF,CAAC;gBACD,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACvC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;oBACzD,OAAO,cAAc,UAAU,kBAAkB,CAAC;gBACpD,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;SAC/C;KACF,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC9C;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,mCAAmC;YAC5C,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,8CAA8C,EAAE,KAAK,EAAE,WAAW,EAAE;gBAC5E,EAAE,IAAI,EAAE,0DAA0D,EAAE,KAAK,EAAE,SAAS,EAAE;aACvF;SACF;KACF,CAAC,CAAC;IAEH,mBAAmB;IACnB,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,IAAI,YAAY,GAAG,IAAI,CAAC;IAExB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC,CAAC;IAEjF,OAAO,YAAY,EAAE,CAAC;QACpB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACzC;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,oCAAoC;gBAC7C,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE;aACxC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,YAAY,GAAG,KAAK,CAAC;YACrB,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACxC;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,eAAe;gBACxB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;aAC9D;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,YAAY;gBACrB,OAAO,EAAE,UAAU;aACpB;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,wBAAwB;gBACjC,OAAO,EAAE,KAAK;aACf;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,yBAAyB;aACnC;SACF,CAAC,CAAC;QAEH,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,WAAW,CAAC,WAAW;YACpC,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,SAAS;SAClD,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,QAAQ,MAAM,WAAW,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,8EAA8E;IAC9E,IAAI,MAAM,CAAC,SAAS,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,MAAM,CAAC,SAAS,uBAAuB,CAAC,CAAC,CAAC;QAC/F,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,IAAI,CACR,wEAAwE;YACtE,6DAA6D,CAChE,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,mBAAmB;IACnB,MAAM,OAAO,GAAG,GAAG,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,CAAC;IAErD,IAAI,CAAC;QACH,8CAA8C;QAC9C,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,SAAS,GAAG,iBAAiB,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAkB,aAAa,EAAE,CAAC,CAAC;QAEpF,mBAAmB;QACnB,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEhD,eAAe;QACf,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,EACnC,iBAAiB,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,WAAW,CAAC,CACjF,CAAC;QAEF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,EACpC,qBAAqB,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,CAC3D,CAAC;QAEF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACrC,kBAAkB,CAAC,aAAa,EAAE,aAAa,CAAC,CACjD,CAAC;QAEF,gBAAgB;QAChB,MAAM,YAAY,GAAwB;YACxC,EAAE,EAAE,WAAW;YACf,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,oBAAoB,aAAa,YAAY;YACpD,MAAM,EAAE,oBAAoB,aAAa,aAAa;YACtD,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,KAAK;SACN,CAAC;QAEF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrC,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE9D,0BAA0B;QAC1B,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC3E,EAAE,CAAC,aAAa,CACd,eAAe,EACf,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,WAAW,EAAE,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CACzF,CAAC;QAEF,0BAA0B;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACzE,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,YAAY,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;QACD,YAAY,IAAI,YAAY,aAAa,cAAc,aAAa,YAAY,CAAC;QACjF,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAE1C,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,aAAa,yBAAyB,CAAC,CAAC,CAAC;QAEnF,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,aAAa,YAAY,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,aAAa,aAAa,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,aAAa,WAAW,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC,CAAC;IAEhF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC;SACtB,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,YAAY,CAAC,CAAC;AAC1B,CAAC"}
@@ -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;AA0lDpC,wBAAgB,mBAAmB,IAAI,OAAO,CA2M7C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAu5DpC,wBAAgB,mBAAmB,IAAI,OAAO,CAuU7C"}
@@ -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, validateFilteredComponentIds, } from "../utils/component-helpers.js";
4
+ import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, isValidProjectId, 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)) {
@@ -31,7 +31,10 @@ function resolveComponent(config, ref) {
31
31
  success: false,
32
32
  error: "Component reference required: pass --id (preferred) or --name (exact PascalCase). " +
33
33
  "Run `ikas-component config list-components` to see canonical ids.",
34
- validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
34
+ validComponents: config.components.map((c) => ({
35
+ id: c.id,
36
+ name: c.name,
37
+ })),
35
38
  }));
36
39
  process.exit(1);
37
40
  }
@@ -52,7 +55,10 @@ function resolveComponent(config, ref) {
52
55
  ? `Component not found: id="${id}".`
53
56
  : `Component not found: name="${name}". Names are matched exactly (PascalCase, no normalization).`,
54
57
  lookup: id ? { id } : { name },
55
- validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
58
+ validComponents: config.components.map((c) => ({
59
+ id: c.id,
60
+ name: c.name,
61
+ })),
56
62
  hint: "Use --id (preferred) or exact PascalCase --name. " +
57
63
  "Run `ikas-component config list-components` to see canonical ids.",
58
64
  }));
@@ -235,13 +241,23 @@ async function parsePropsFlag(propsJson, config, configPath) {
235
241
  process.exit(1);
236
242
  }
237
243
  // Validate LINK / LIST_OF_LINK defaultValue shape (reject JSON strings and legacy { href })
238
- if ((propType === "LINK" || propType === "LIST_OF_LINK") && r.defaultValue !== undefined) {
244
+ if ((propType === "LINK" || propType === "LIST_OF_LINK") &&
245
+ r.defaultValue !== undefined) {
239
246
  const linkError = validateLinkDefaultValue(propType, r.defaultValue, r.name);
240
247
  if (linkError) {
241
248
  console.log(JSON.stringify({ success: false, error: linkError }));
242
249
  process.exit(1);
243
250
  }
244
251
  }
252
+ // Validate SVG / SVG_LIST defaultValue (reject malformed/oversized/unsafe SVG)
253
+ if ((propType === "SVG" || propType === "SVG_LIST") &&
254
+ r.defaultValue !== undefined) {
255
+ const svgError = validateSvgDefaultValue(propType, r.defaultValue, r.name);
256
+ if (svgError) {
257
+ console.log(JSON.stringify({ success: false, error: svgError }));
258
+ process.exit(1);
259
+ }
260
+ }
245
261
  // Auto-generate displayName if omitted
246
262
  const displayName = typeof r.displayName === "string" && r.displayName
247
263
  ? r.displayName
@@ -266,7 +282,10 @@ async function parsePropsFlag(propsJson, config, configPath) {
266
282
  process.exit(1);
267
283
  }
268
284
  // Validate enum type exists (checks config then live dev server)
269
- if (config && configPath && typeof r.enumTypeId === "string" && !r.enumTypeId.startsWith("@ikas/")) {
285
+ if (config &&
286
+ configPath &&
287
+ typeof r.enumTypeId === "string" &&
288
+ !r.enumTypeId.startsWith("@ikas/")) {
270
289
  const resolved = await resolveEnumType(r.enumTypeId, config, configPath);
271
290
  if (!resolved) {
272
291
  console.log(JSON.stringify({
@@ -285,9 +304,7 @@ async function parsePropsFlag(propsJson, config, configPath) {
285
304
  ...(typeof r.description === "string" && r.description
286
305
  ? { description: r.description }
287
306
  : {}),
288
- ...(r.defaultValue !== undefined
289
- ? { defaultValue: r.defaultValue }
290
- : {}),
307
+ ...(r.defaultValue !== undefined ? { defaultValue: r.defaultValue } : {}),
291
308
  ...(typeof r.groupId === "string" && r.groupId
292
309
  ? { groupId: r.groupId }
293
310
  : {}),
@@ -297,11 +314,19 @@ async function parsePropsFlag(propsJson, config, configPath) {
297
314
  ...(propType === "ENUM" && typeof r.enumTypeId === "string"
298
315
  ? { enumTypeId: r.enumTypeId }
299
316
  : {}),
300
- ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.filteredComponentIds && Array.isArray(r.filteredComponentIds)
301
- ? { filteredComponentIds: assertKnownComponentIds(r.filteredComponentIds, config) }
317
+ ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") &&
318
+ r.filteredComponentIds &&
319
+ Array.isArray(r.filteredComponentIds)
320
+ ? {
321
+ filteredComponentIds: assertKnownComponentIds(r.filteredComponentIds, config),
322
+ }
302
323
  : {}),
303
- ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.privateVarMap && typeof r.privateVarMap === "object"
304
- ? { privateVarMap: r.privateVarMap }
324
+ ...((propType === "COMPONENT" || propType === "COMPONENT_LIST") &&
325
+ r.privateVarMap &&
326
+ typeof r.privateVarMap === "object"
327
+ ? {
328
+ privateVarMap: r.privateVarMap,
329
+ }
305
330
  : {}),
306
331
  };
307
332
  props.push(prop);
@@ -333,6 +358,18 @@ async function addComponent(name, options) {
333
358
  if (!config.projectId) {
334
359
  config.projectId = generateProjectId();
335
360
  }
361
+ else if (!isValidProjectId(config.projectId)) {
362
+ // A malformed projectId (hand-edited config) breaks the editor's republish
363
+ // stability: published/local id prefixes stop matching and every publish
364
+ // INSERTs duplicate design elements. Fail fast instead of corrupting data.
365
+ console.log(JSON.stringify({
366
+ success: false,
367
+ error: `Invalid projectId "${config.projectId}" in ikas.config.json. ` +
368
+ "projectId must be at least 6 alphanumeric characters (no '-' or '_'). " +
369
+ "Restore the original generated value — do not hand-edit it.",
370
+ }));
371
+ process.exit(1);
372
+ }
336
373
  // Parse --props (and validate filteredComponentIds) BEFORE any filesystem side-effects
337
374
  // so a bad payload doesn't leave an empty component directory behind.
338
375
  const props = options.props
@@ -438,7 +475,9 @@ async function addProp(ref, options) {
438
475
  }
439
476
  // Validate that enumTypeId references an existing enum type
440
477
  // (checks config.customTypes first, then falls back to the live dev server)
441
- if (propType === "ENUM" && options.enumTypeId && !options.enumTypeId.startsWith("@ikas/")) {
478
+ if (propType === "ENUM" &&
479
+ options.enumTypeId &&
480
+ !options.enumTypeId.startsWith("@ikas/")) {
442
481
  const resolved = await resolveEnumType(options.enumTypeId, config, configPath);
443
482
  if (!resolved) {
444
483
  console.log(JSON.stringify({
@@ -468,43 +507,69 @@ async function addProp(ref, options) {
468
507
  }
469
508
  // Parse filteredComponentIds JSON for COMPONENT/COMPONENT_LIST
470
509
  let parsedFilteredIds;
471
- if (options.filteredComponentIds && (propType === "COMPONENT" || propType === "COMPONENT_LIST")) {
510
+ if (options.filteredComponentIds &&
511
+ (propType === "COMPONENT" || propType === "COMPONENT_LIST")) {
472
512
  try {
473
513
  parsedFilteredIds = JSON.parse(options.filteredComponentIds);
474
514
  if (!Array.isArray(parsedFilteredIds)) {
475
- console.log(JSON.stringify({ success: false, error: "--filteredComponentIds must be a JSON array of strings." }));
515
+ console.log(JSON.stringify({
516
+ success: false,
517
+ error: "--filteredComponentIds must be a JSON array of strings.",
518
+ }));
476
519
  process.exit(1);
477
520
  }
478
521
  }
479
522
  catch {
480
- console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
523
+ console.log(JSON.stringify({
524
+ success: false,
525
+ error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}`,
526
+ }));
481
527
  process.exit(1);
482
528
  }
483
529
  assertKnownComponentIds(parsedFilteredIds, config);
484
530
  }
485
531
  // Parse privateVarMap JSON for COMPONENT/COMPONENT_LIST
486
532
  let parsedPrivateVarMap;
487
- if (options.privateVarMap && (propType === "COMPONENT" || propType === "COMPONENT_LIST")) {
533
+ if (options.privateVarMap &&
534
+ (propType === "COMPONENT" || propType === "COMPONENT_LIST")) {
488
535
  try {
489
536
  parsedPrivateVarMap = JSON.parse(options.privateVarMap);
490
- if (typeof parsedPrivateVarMap !== "object" || Array.isArray(parsedPrivateVarMap)) {
491
- console.log(JSON.stringify({ success: false, error: "--privateVarMap must be a JSON object mapping keys to {id, typeId}." }));
537
+ if (typeof parsedPrivateVarMap !== "object" ||
538
+ Array.isArray(parsedPrivateVarMap)) {
539
+ console.log(JSON.stringify({
540
+ success: false,
541
+ error: "--privateVarMap must be a JSON object mapping keys to {id, typeId}.",
542
+ }));
492
543
  process.exit(1);
493
544
  }
494
545
  }
495
546
  catch {
496
- console.log(JSON.stringify({ success: false, error: `Invalid --privateVarMap JSON: ${options.privateVarMap}` }));
547
+ console.log(JSON.stringify({
548
+ success: false,
549
+ error: `Invalid --privateVarMap JSON: ${options.privateVarMap}`,
550
+ }));
497
551
  process.exit(1);
498
552
  }
499
553
  }
500
- const parsedDefaultValue = options.defaultValue !== undefined ? parseDefaultValue(options.defaultValue, propType) : undefined;
501
- if ((propType === "LINK" || propType === "LIST_OF_LINK") && parsedDefaultValue !== undefined) {
554
+ const parsedDefaultValue = options.defaultValue !== undefined
555
+ ? parseDefaultValue(options.defaultValue, propType)
556
+ : undefined;
557
+ if ((propType === "LINK" || propType === "LIST_OF_LINK") &&
558
+ parsedDefaultValue !== undefined) {
502
559
  const linkError = validateLinkDefaultValue(propType, parsedDefaultValue, options.name);
503
560
  if (linkError) {
504
561
  console.log(JSON.stringify({ success: false, error: linkError }));
505
562
  process.exit(1);
506
563
  }
507
564
  }
565
+ if ((propType === "SVG" || propType === "SVG_LIST") &&
566
+ parsedDefaultValue !== undefined) {
567
+ const svgError = validateSvgDefaultValue(propType, parsedDefaultValue, options.name);
568
+ if (svgError) {
569
+ console.log(JSON.stringify({ success: false, error: svgError }));
570
+ process.exit(1);
571
+ }
572
+ }
508
573
  const newProp = {
509
574
  name: options.name,
510
575
  displayName: options.displayName,
@@ -535,8 +600,12 @@ async function addProp(ref, options) {
535
600
  required: newProp.required,
536
601
  ...(newProp.groupId ? { groupId: newProp.groupId } : {}),
537
602
  ...(newProp.enumTypeId ? { enumTypeId: newProp.enumTypeId } : {}),
538
- ...(newProp.filteredComponentIds ? { filteredComponentIds: newProp.filteredComponentIds } : {}),
539
- ...(newProp.privateVarMap ? { privateVarMap: newProp.privateVarMap } : {}),
603
+ ...(newProp.filteredComponentIds
604
+ ? { filteredComponentIds: newProp.filteredComponentIds }
605
+ : {}),
606
+ ...(newProp.privateVarMap
607
+ ? { privateVarMap: newProp.privateVarMap }
608
+ : {}),
540
609
  },
541
610
  }));
542
611
  }
@@ -557,6 +626,16 @@ function parseDefaultValue(value, propType) {
557
626
  catch {
558
627
  return value;
559
628
  }
629
+ case "SVG_LIST":
630
+ // Same reasoning as LINK_LIST: SVG_LIST must be stored as an array of SVG strings.
631
+ // Parse it here; if it is not valid JSON, return the raw string so
632
+ // validateSvgDefaultValue can report a precise "must be an array" error.
633
+ try {
634
+ return JSON.parse(value);
635
+ }
636
+ catch {
637
+ return value;
638
+ }
560
639
  default:
561
640
  return value;
562
641
  }
@@ -579,7 +658,8 @@ const validateSingleLink = (link, propName, path) => {
579
658
  if ("href" in l && !("linkType" in l)) {
580
659
  return `${where} uses a legacy { href } shape without "linkType". Use "linkType" + "externalLink"/"pageType" instead. ${LINK_SHAPE_HELP}`;
581
660
  }
582
- if (typeof l.linkType !== "string" || !VALID_LINK_TYPES.includes(l.linkType)) {
661
+ if (typeof l.linkType !== "string" ||
662
+ !VALID_LINK_TYPES.includes(l.linkType)) {
583
663
  return `${where} must have a valid "linkType" (one of ${VALID_LINK_TYPES.join(", ")}). ${LINK_SHAPE_HELP}`;
584
664
  }
585
665
  if (l.subLinks !== undefined && !Array.isArray(l.subLinks)) {
@@ -604,12 +684,78 @@ function validateLinkDefaultValue(propType, value, propName) {
604
684
  if (typeof value === "string") {
605
685
  return `defaultValue for prop "${propName}" is a JSON string but must be an object { "links": [...] }. ${LINK_SHAPE_HELP}`;
606
686
  }
607
- if (!value || typeof value !== "object" || Array.isArray(value) || !Array.isArray(value.links)) {
687
+ if (!value ||
688
+ typeof value !== "object" ||
689
+ Array.isArray(value) ||
690
+ !Array.isArray(value.links)) {
608
691
  return `defaultValue for prop "${propName}" must be an object with a "links" array: { "links": [ <link>, ... ] }. ${LINK_SHAPE_HELP}`;
609
692
  }
610
693
  const links = value.links;
611
694
  return firstError(links, (link, i) => validateSingleLink(link, propName, `.links[${i}]`));
612
695
  }
696
+ const SVG_DEFAULT_HELP = "An SVG default must be a single well-formed <svg>…</svg> string ≤ 64 KB with no embedded base64 raster images. " +
697
+ "Tip: the editor uses each svg's `class` attribute as its display name — set class=\"my-icon\" to name it; " +
698
+ "SVG_LIST items with no class show as svg-1, svg-2, ….";
699
+ // Keep the cap and base64 pattern in sync with @ikas/editor-models validate-svg.ts (the
700
+ // authoritative validator). Duplicated here on purpose — see validateSvgShape below.
701
+ const SVG_MAX_SIZE_KB = 64;
702
+ const SVG_BASE64_RASTER_RE = /data:image\/[a-z0-9.+-]+;base64/i;
703
+ const SVG_SHAPE_RE = /^\s*(?:<\?xml[^>]*\?>\s*)?(?:<!DOCTYPE[^>]*>\s*)?<svg[\s>][\s\S]*<\/svg>\s*$/i;
704
+ // Count TOP-LEVEL <svg> roots without a DOM: scan svg open/close tags in order and track
705
+ // nesting depth. A root is any <svg> opened at depth 0. This matches the editor's DOM-based
706
+ // single-root check — it rejects siblings (`<svg/><svg/>`) while allowing a nested <svg>.
707
+ // Self-closing <svg .../> counts as a root but opens no nesting level.
708
+ function svgRootCount(input) {
709
+ const tags = input.match(/<svg\b[^>]*>|<\/svg\s*>/gi) || [];
710
+ return tags.reduce((acc, tag) => {
711
+ if (tag.startsWith("</"))
712
+ return { depth: Math.max(0, acc.depth - 1), roots: acc.roots };
713
+ const roots = acc.depth === 0 ? acc.roots + 1 : acc.roots;
714
+ const depth = /\/>\s*$/.test(tag) ? acc.depth : acc.depth + 1;
715
+ return { depth, roots };
716
+ }, { depth: 0, roots: 0 }).roots;
717
+ }
718
+ // Lightweight, dependency-free SVG structure check. This standalone CLI is publishable and
719
+ // must not depend on the private @ikas/editor-models package (nor pull a DOM/DOMPurify into a
720
+ // CLI), so it mirrors the RULES of the editor's validateSvg (size, base64, single <svg> root)
721
+ // for fast authoring feedback. The authoritative sanitize runs in the editor/upload path.
722
+ // Returns a rejection reason, or null if the shape is acceptable.
723
+ function validateSvgShape(input) {
724
+ if (typeof input !== "string" || input.trim() === "")
725
+ return "empty or not a string";
726
+ if (Buffer.byteLength(input, "utf8") > SVG_MAX_SIZE_KB * 1024)
727
+ return `exceeds ${SVG_MAX_SIZE_KB} KB`;
728
+ if (SVG_BASE64_RASTER_RE.test(input))
729
+ return "embedded base64 raster image not allowed";
730
+ if (!SVG_SHAPE_RE.test(input))
731
+ return "not a single-root <svg> document";
732
+ if (svgRootCount(input) !== 1)
733
+ return "must be exactly one <svg> root";
734
+ return null;
735
+ }
736
+ // Validates an SVG / SVG_LIST defaultValue. Returns an error message, or null if valid.
737
+ // Authoring an SVG default is a common mistake source for agents; rejecting here (with an
738
+ // instructive message) keeps malformed/oversized SVGs out of published components.
739
+ function validateSvgDefaultValue(propType, value, propName) {
740
+ if (value === undefined || value === null)
741
+ return null;
742
+ if (propType === "SVG") {
743
+ const reason = validateSvgShape(value);
744
+ return reason
745
+ ? `defaultValue for prop "${propName}" is not a valid SVG: ${reason}. ${SVG_DEFAULT_HELP}`
746
+ : null;
747
+ }
748
+ // SVG_LIST
749
+ if (!Array.isArray(value)) {
750
+ return `defaultValue for prop "${propName}" must be an array of SVG strings: [ "<svg>…</svg>", ... ]. ${SVG_DEFAULT_HELP}`;
751
+ }
752
+ return firstError(value, (svg, i) => {
753
+ const reason = validateSvgShape(svg);
754
+ return reason
755
+ ? `defaultValue[${i}] for prop "${propName}" is not a valid SVG: ${reason}. ${SVG_DEFAULT_HELP}`
756
+ : null;
757
+ });
758
+ }
613
759
  function updateProp(ref, options) {
614
760
  const { config, configPath } = loadConfig();
615
761
  const component = resolveComponent(config, ref);
@@ -693,14 +839,18 @@ function updateProp(ref, options) {
693
839
  }
694
840
  }
695
841
  if (options.filteredComponentIds !== undefined) {
696
- if (options.filteredComponentIds === "" || options.filteredComponentIds === "none") {
842
+ if (options.filteredComponentIds === "" ||
843
+ options.filteredComponentIds === "none") {
697
844
  delete prop.filteredComponentIds;
698
845
  }
699
846
  else {
700
847
  try {
701
848
  const parsed = JSON.parse(options.filteredComponentIds);
702
849
  if (!Array.isArray(parsed)) {
703
- console.log(JSON.stringify({ success: false, error: "--filteredComponentIds must be a JSON array of strings." }));
850
+ console.log(JSON.stringify({
851
+ success: false,
852
+ error: "--filteredComponentIds must be a JSON array of strings.",
853
+ }));
704
854
  process.exit(1);
705
855
  }
706
856
  assertKnownComponentIds(parsed, config);
@@ -708,7 +858,10 @@ function updateProp(ref, options) {
708
858
  }
709
859
  catch (err) {
710
860
  if (err instanceof SyntaxError) {
711
- console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
861
+ console.log(JSON.stringify({
862
+ success: false,
863
+ error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}`,
864
+ }));
712
865
  process.exit(1);
713
866
  }
714
867
  throw err;
@@ -723,13 +876,19 @@ function updateProp(ref, options) {
723
876
  try {
724
877
  const parsed = JSON.parse(options.privateVarMap);
725
878
  if (typeof parsed !== "object" || Array.isArray(parsed)) {
726
- console.log(JSON.stringify({ success: false, error: "--privateVarMap must be a JSON object mapping keys to {id, typeId}." }));
879
+ console.log(JSON.stringify({
880
+ success: false,
881
+ error: "--privateVarMap must be a JSON object mapping keys to {id, typeId}.",
882
+ }));
727
883
  process.exit(1);
728
884
  }
729
885
  prop.privateVarMap = parsed;
730
886
  }
731
887
  catch {
732
- console.log(JSON.stringify({ success: false, error: `Invalid --privateVarMap JSON: ${options.privateVarMap}` }));
888
+ console.log(JSON.stringify({
889
+ success: false,
890
+ error: `Invalid --privateVarMap JSON: ${options.privateVarMap}`,
891
+ }));
733
892
  process.exit(1);
734
893
  }
735
894
  }
@@ -749,7 +908,9 @@ function updateProp(ref, options) {
749
908
  ...(prop.groupId ? { groupId: prop.groupId } : {}),
750
909
  ...(prop.typeId ? { typeId: prop.typeId } : {}),
751
910
  ...(prop.enumTypeId ? { enumTypeId: prop.enumTypeId } : {}),
752
- ...(prop.filteredComponentIds ? { filteredComponentIds: prop.filteredComponentIds } : {}),
911
+ ...(prop.filteredComponentIds
912
+ ? { filteredComponentIds: prop.filteredComponentIds }
913
+ : {}),
753
914
  ...(prop.privateVarMap ? { privateVarMap: prop.privateVarMap } : {}),
754
915
  },
755
916
  }));
@@ -813,7 +974,10 @@ function removeComponent(ref) {
813
974
  removedComponentId: component.id,
814
975
  removedComponentName: component.name,
815
976
  removedDirectory: path.relative(process.cwd(), componentDir),
816
- remainingComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
977
+ remainingComponents: config.components.map((c) => ({
978
+ id: c.id,
979
+ name: c.name,
980
+ })),
817
981
  }));
818
982
  }
819
983
  function addPropGroup(ref, options) {
@@ -920,10 +1084,10 @@ function removePropGroup(ref, options) {
920
1084
  process.exit(1);
921
1085
  }
922
1086
  if (found.parent) {
923
- found.parent.children = found.parent.children.filter(c => c.id !== options.id);
1087
+ found.parent.children = found.parent.children.filter((c) => c.id !== options.id);
924
1088
  }
925
1089
  else {
926
- component.propGroups = component.propGroups.filter(g => g.id !== options.id);
1090
+ component.propGroups = component.propGroups.filter((g) => g.id !== options.id);
927
1091
  }
928
1092
  // Clear groupId from props referencing the deleted group
929
1093
  for (const prop of component.props) {
@@ -936,7 +1100,7 @@ function removePropGroup(ref, options) {
936
1100
  success: true,
937
1101
  componentName: component.name,
938
1102
  removedPropGroup: options.id,
939
- remainingPropGroups: component.propGroups.map(g => g.id),
1103
+ remainingPropGroups: component.propGroups.map((g) => g.id),
940
1104
  }));
941
1105
  }
942
1106
  function movePropGroup(ref, options) {
@@ -953,7 +1117,10 @@ function movePropGroup(ref, options) {
953
1117
  component.propGroups = movePropGroupInTree(component.propGroups, options.id, options.parent || null, options.index);
954
1118
  }
955
1119
  catch (e) {
956
- console.log(JSON.stringify({ success: false, error: e.message || "Failed to move prop group" }));
1120
+ console.log(JSON.stringify({
1121
+ success: false,
1122
+ error: e.message || "Failed to move prop group",
1123
+ }));
957
1124
  process.exit(1);
958
1125
  }
959
1126
  saveConfig(configPath, config);
@@ -1009,7 +1176,9 @@ function listComponents() {
1009
1176
  required: p.required,
1010
1177
  ...(p.groupId ? { groupId: p.groupId } : {}),
1011
1178
  })),
1012
- ...(c.propGroups && c.propGroups.length > 0 ? { propGroups: c.propGroups } : {}),
1179
+ ...(c.propGroups && c.propGroups.length > 0
1180
+ ? { propGroups: c.propGroups }
1181
+ : {}),
1013
1182
  }));
1014
1183
  console.log(JSON.stringify({
1015
1184
  success: true,
@@ -1023,7 +1192,9 @@ function listComponents() {
1023
1192
  async function addEnum(options) {
1024
1193
  const { config, configPath } = loadConfig();
1025
1194
  // Validate name
1026
- if (!options.name || typeof options.name !== "string" || !options.name.trim()) {
1195
+ if (!options.name ||
1196
+ typeof options.name !== "string" ||
1197
+ !options.name.trim()) {
1027
1198
  console.log(JSON.stringify({ success: false, error: "Enum name is required." }));
1028
1199
  process.exit(1);
1029
1200
  }
@@ -1137,7 +1308,7 @@ function updateEnum(options) {
1137
1308
  Object.keys(enumOptions).length === 0) {
1138
1309
  console.log(JSON.stringify({
1139
1310
  success: false,
1140
- error: 'Options must be a non-empty JSON object.',
1311
+ error: "Options must be a non-empty JSON object.",
1141
1312
  }));
1142
1313
  process.exit(1);
1143
1314
  }
@@ -1210,8 +1381,7 @@ function listEnums() {
1210
1381
  }
1211
1382
  // --- Command registration ---
1212
1383
  export function createConfigCommand() {
1213
- const config = new Command("config")
1214
- .description("Non-interactive commands for managing ikas.config.json (designed for AI agents and scripting)");
1384
+ const config = new Command("config").description("Non-interactive commands for managing ikas.config.json (designed for AI agents and scripting)");
1215
1385
  config
1216
1386
  .command("add-component")
1217
1387
  .description("Add a new component to the project")
@@ -1220,7 +1390,7 @@ export function createConfigCommand() {
1220
1390
  .option("--isHeader", "Mark this section as the store header (only for type: section)")
1221
1391
  .option("--isFooter", "Mark this section as the store footer (only for type: section)")
1222
1392
  .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. " +
1223
- "Example: '[{\"name\":\"title\",\"type\":\"TEXT\",\"required\":true,\"defaultValue\":\"Hello\",\"groupId\":\"basic\"}]'")
1393
+ 'Example: \'[{"name":"title","type":"TEXT","required":true,"defaultValue":"Hello","groupId":"basic"}]\'')
1224
1394
  .action((options) => {
1225
1395
  addComponent(options.name, options);
1226
1396
  });
@@ -1239,7 +1409,7 @@ export function createConfigCommand() {
1239
1409
  .option("--typeId <typeId>", "Type ID for TYPE props (required when type is TYPE)")
1240
1410
  .option("--enumTypeId <enumTypeId>", "Enum type ID for ENUM props (required when type is ENUM)")
1241
1411
  .option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
1242
- .option("--privateVarMap <json>", 'JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)')
1412
+ .option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)")
1243
1413
  .action((options) => {
1244
1414
  addProp({ id: options.componentId, name: options.component }, options);
1245
1415
  });
@@ -1330,7 +1500,7 @@ export function createConfigCommand() {
1330
1500
  .option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
1331
1501
  .requiredOption("--id <id>", "Group ID to move")
1332
1502
  .option("--parent <parentId>", "Target parent group ID (omit to move to root)")
1333
- .option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", v => parseInt(v, 10))
1503
+ .option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", (v) => parseInt(v, 10))
1334
1504
  .action((options) => {
1335
1505
  movePropGroup({ id: options.componentId, name: options.component }, options);
1336
1506
  });
@@ -1426,7 +1596,15 @@ async function fetchLiveEditorEnumById(enumId) {
1426
1596
  clearTimeout(timeout);
1427
1597
  const types = message.payload?.types || [];
1428
1598
  const match = types.find((t) => t.category === "enum" && t.id === enumId);
1429
- finish(match ? { id: match.id, name: match.name, ...(match.enumOptions ? { enumOptions: match.enumOptions } : {}) } : null);
1599
+ finish(match
1600
+ ? {
1601
+ id: match.id,
1602
+ name: match.name,
1603
+ ...(match.enumOptions
1604
+ ? { enumOptions: match.enumOptions }
1605
+ : {}),
1606
+ }
1607
+ : null);
1430
1608
  }
1431
1609
  }
1432
1610
  catch {