@cmssy/cli 12.11.0 → 12.13.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.
@@ -0,0 +1,3 @@
1
+ import cmssy from "@cmssy/eslint-plugin";
2
+
3
+ export default [...cmssy.configs.standalone];
package/dist/index.js CHANGED
@@ -603,14 +603,281 @@ function runAddBlock(options, deps) {
603
603
 
604
604
  // src/init.ts
605
605
  import {
606
- copyFileSync,
607
- existsSync as existsSync3,
606
+ copyFileSync as copyFileSync2,
607
+ existsSync as existsSync4,
608
608
  mkdirSync as mkdirSync2,
609
- readFileSync as readFileSync3,
610
- writeFileSync as writeFileSync2
609
+ readFileSync as readFileSync4,
610
+ writeFileSync as writeFileSync3
611
611
  } from "fs";
612
- import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
612
+ import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
613
613
  import { fileURLToPath } from "url";
614
+
615
+ // src/eslint-config.ts
616
+ import { copyFileSync, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
617
+ import { join as join3 } from "path";
618
+ var ESLINT_PLUGIN = "@cmssy/eslint-plugin";
619
+ var ESLINT_CONFIG_FILE = "eslint.config.mjs";
620
+ var ESLINT_PURPOSE = "the two wiring mistakes no build catches: server config pulled into a client bundle, and a provider the /cmssy-edit route never gets";
621
+ var FLAT_CONFIGS = [
622
+ "eslint.config.js",
623
+ "eslint.config.mjs",
624
+ "eslint.config.cjs",
625
+ "eslint.config.ts",
626
+ "eslint.config.mts",
627
+ "eslint.config.cts"
628
+ ];
629
+ var LEGACY_CONFIGS = [
630
+ ".eslintrc.js",
631
+ ".eslintrc.cjs",
632
+ ".eslintrc.mjs",
633
+ ".eslintrc.json",
634
+ ".eslintrc.yml",
635
+ ".eslintrc.yaml",
636
+ ".eslintrc"
637
+ ];
638
+ var SPREAD = "...cmssy.configs.recommended";
639
+ var IMPORT_LINE = `import cmssy from "${ESLINT_PLUGIN}";`;
640
+ var STANDALONE_SNIPPET = `${IMPORT_LINE}
641
+ export default [...cmssy.configs.standalone];`;
642
+ var APPEND_SNIPPET = `${IMPORT_LINE}
643
+ export default [...yourConfig, ${SPREAD}];`;
644
+ var REQUIRE_SNIPPET = `const cmssy = require("${ESLINT_PLUGIN}");
645
+ module.exports = [...yourConfig, ${SPREAD}];`;
646
+ var INLINE_STANDALONE = `an ${ESLINT_CONFIG_FILE} of \`${IMPORT_LINE} export default [...cmssy.configs.standalone];\``;
647
+ var BUILDERS = /* @__PURE__ */ new Set([
648
+ "config",
649
+ "defineConfig",
650
+ "defineFlatConfig",
651
+ "tseslint.config"
652
+ ]);
653
+ var WIRED = /(?:import|require)[\s\S]{0,200}?["']@cmssy\/eslint-plugin["']/;
654
+ var RULES = "cmssy/edit-route-provider-parity and cmssy/no-server-config-in-client";
655
+ function describeExpression(expression) {
656
+ const stack = [];
657
+ const pairs = { ")": "(", "]": "[", "}": "{" };
658
+ let closed = -1;
659
+ for (let i = 0; i < expression.length; i += 1) {
660
+ const char = expression[i];
661
+ if (char === '"' || char === "'" || char === "`") {
662
+ i += 1;
663
+ while (i < expression.length && expression[i] !== char) {
664
+ if (expression[i] === "\\") i += 1;
665
+ i += 1;
666
+ }
667
+ if (i >= expression.length) return { balanced: false, single: false };
668
+ continue;
669
+ }
670
+ if (char === "/" && expression[i + 1] === "/") {
671
+ while (i < expression.length && expression[i] !== "\n") i += 1;
672
+ continue;
673
+ }
674
+ if (char === "/" && expression[i + 1] === "*") {
675
+ i += 2;
676
+ while (i < expression.length && !(expression[i] === "*" && expression[i + 1] === "/")) {
677
+ i += 1;
678
+ }
679
+ if (i >= expression.length) return { balanced: false, single: false };
680
+ i += 1;
681
+ continue;
682
+ }
683
+ if (char === "(" || char === "[" || char === "{") {
684
+ stack.push(char);
685
+ continue;
686
+ }
687
+ if (char === ")" || char === "]" || char === "}") {
688
+ if (stack.pop() !== pairs[char])
689
+ return { balanced: false, single: false };
690
+ if (stack.length === 0) closed = i;
691
+ continue;
692
+ }
693
+ if (char === ";" && stack.length === 0) {
694
+ return { balanced: false, single: false };
695
+ }
696
+ }
697
+ return {
698
+ balanced: stack.length === 0,
699
+ single: closed === expression.length - 1
700
+ };
701
+ }
702
+ function indentOf(inner) {
703
+ return /\n([ \t]+)\S/.exec(inner)?.[1] ?? " ";
704
+ }
705
+ function appendItem(inner) {
706
+ if (inner.trim() === "") return `
707
+ ${SPREAD},
708
+ `;
709
+ if (!inner.includes("\n")) {
710
+ return `${inner.replace(/,\s*$/, "")}, ${SPREAD}`;
711
+ }
712
+ const body = inner.replace(/\s+$/, "");
713
+ const close = /\n([ \t]*)$/.exec(inner);
714
+ const item = `${body}${body.endsWith(",") ? "" : ","}
715
+ ${indentOf(inner)}${SPREAD}`;
716
+ return close ? `${item},
717
+ ${close[1]}` : item;
718
+ }
719
+ function patchExpression(expression) {
720
+ const shape = describeExpression(expression);
721
+ if (!shape.balanced) return null;
722
+ if (expression.startsWith("[") && expression.endsWith("]") && shape.single) {
723
+ return `[${appendItem(expression.slice(1, -1))}]`;
724
+ }
725
+ const call = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\(([\s\S]*)\)$/.exec(
726
+ expression
727
+ );
728
+ if (call && shape.single && BUILDERS.has(call[1])) {
729
+ const args = call[2];
730
+ const only = args.trim();
731
+ if (only.startsWith("[") && only.endsWith("]")) {
732
+ const inner = patchExpression(only);
733
+ if (inner) return `${call[1]}(${inner})`;
734
+ }
735
+ return `${call[1]}(${appendItem(args)})`;
736
+ }
737
+ return `[...${expression}, ${SPREAD}]`;
738
+ }
739
+ function insertImport(source) {
740
+ const lines = source.split("\n");
741
+ let at = 0;
742
+ let block = false;
743
+ for (; at < lines.length; at += 1) {
744
+ const line = lines[at].trim();
745
+ if (block) {
746
+ if (line.includes("*/")) block = false;
747
+ continue;
748
+ }
749
+ if (line === "" || line.startsWith("//") || line.startsWith("#!")) continue;
750
+ if (line.startsWith("/*")) {
751
+ block = !line.includes("*/");
752
+ continue;
753
+ }
754
+ break;
755
+ }
756
+ const next = lines[at] ?? "";
757
+ const spacer = next.trim() === "" || next.startsWith("import ") ? [] : [""];
758
+ lines.splice(at, 0, IMPORT_LINE, ...spacer);
759
+ return lines.join("\n");
760
+ }
761
+ function patchFlatConfig(source) {
762
+ const exports = [...source.matchAll(/^export default\b/gm)];
763
+ const last = exports.at(-1);
764
+ if (last?.index === void 0) return null;
765
+ const head = source.slice(0, last.index);
766
+ const expression = source.slice(last.index + "export default".length).trim().replace(/;$/, "").trimEnd();
767
+ if (expression === "") return null;
768
+ const patched = patchExpression(expression);
769
+ if (!patched) return null;
770
+ const result = insertImport(`${head}export default ${patched};
771
+ `);
772
+ if (!result.includes(SPREAD)) return null;
773
+ return result;
774
+ }
775
+ function withoutComments(source) {
776
+ let out = "";
777
+ for (let i = 0; i < source.length; i += 1) {
778
+ const char = source[i];
779
+ if (char === '"' || char === "'" || char === "`") {
780
+ out += char;
781
+ i += 1;
782
+ while (i < source.length && source[i] !== char) {
783
+ if (source[i] === "\\") {
784
+ out += source[i];
785
+ i += 1;
786
+ }
787
+ out += source[i] ?? "";
788
+ i += 1;
789
+ }
790
+ out += source[i] ?? "";
791
+ continue;
792
+ }
793
+ if (char === "/" && source[i + 1] === "/") {
794
+ while (i < source.length && source[i] !== "\n") i += 1;
795
+ out += "\n";
796
+ continue;
797
+ }
798
+ if (char === "/" && source[i + 1] === "*") {
799
+ i += 2;
800
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) {
801
+ i += 1;
802
+ }
803
+ i += 1;
804
+ continue;
805
+ }
806
+ out += char;
807
+ }
808
+ return out;
809
+ }
810
+ function findFile(root, names) {
811
+ return names.find((name) => existsSync3(join3(root, name)));
812
+ }
813
+ function wireEslintConfig(root, pkg, asset) {
814
+ const flat = findFile(root, FLAT_CONFIGS);
815
+ const legacy = findFile(root, LEGACY_CONFIGS);
816
+ const installed = pkg.dependencies?.eslint !== void 0 || pkg.devDependencies?.eslint !== void 0;
817
+ if (!flat && legacy) {
818
+ return {
819
+ dependency: true,
820
+ notes: [
821
+ {
822
+ status: "fail",
823
+ message: `${legacy} is the legacy eslintrc format, so ${RULES} were not wired`,
824
+ fix: `migrate to flat config (an eslint.config.mjs) and add:
825
+ ${STANDALONE_SNIPPET}`
826
+ }
827
+ ]
828
+ };
829
+ }
830
+ if (!flat && !installed) {
831
+ return {
832
+ dependency: false,
833
+ notes: [
834
+ {
835
+ status: "unknown",
836
+ message: `this app has no eslint, so ${RULES} were not wired - they are the only check for a provider the editor route never gets; install eslint and rerun, or write ${INLINE_STANDALONE} yourself`
837
+ }
838
+ ]
839
+ };
840
+ }
841
+ if (!flat) {
842
+ copyFileSync(asset, join3(root, ESLINT_CONFIG_FILE));
843
+ return { written: ESLINT_CONFIG_FILE, dependency: true, notes: [] };
844
+ }
845
+ const source = readFileSync3(join3(root, flat), "utf8");
846
+ if (WIRED.test(withoutComments(source))) {
847
+ return { dependency: true, notes: [] };
848
+ }
849
+ if (flat.endsWith(".cjs") || /\bmodule\.exports\b/.test(source)) {
850
+ return {
851
+ dependency: true,
852
+ notes: [
853
+ {
854
+ status: "fail",
855
+ message: `${flat} is CommonJS, so ${RULES} were not wired - it was left untouched`,
856
+ fix: `add them yourself:
857
+ ${REQUIRE_SNIPPET}`
858
+ }
859
+ ]
860
+ };
861
+ }
862
+ const patched = patchFlatConfig(source);
863
+ if (!patched) {
864
+ return {
865
+ dependency: true,
866
+ notes: [
867
+ {
868
+ status: "fail",
869
+ message: `${flat} has no default export this can extend, so ${RULES} were not wired - it was left untouched`,
870
+ fix: `add them yourself:
871
+ ${APPEND_SNIPPET}`
872
+ }
873
+ ]
874
+ };
875
+ }
876
+ writeFileSync2(join3(root, flat), patched);
877
+ return { patched: flat, dependency: true, notes: [] };
878
+ }
879
+
880
+ // src/init.ts
614
881
  var ASSETS_DIR = fileURLToPath(new URL("../assets/init", import.meta.url));
615
882
  var CLI_PACKAGE_JSON = fileURLToPath(
616
883
  new URL("../package.json", import.meta.url)
@@ -635,40 +902,53 @@ function frameworkFiles(framework, root) {
635
902
  return files;
636
903
  }
637
904
  function cliVersion() {
638
- const pkg = JSON.parse(readFileSync3(CLI_PACKAGE_JSON, "utf8"));
905
+ const pkg = JSON.parse(readFileSync4(CLI_PACKAGE_JSON, "utf8"));
639
906
  return pkg.version;
640
907
  }
641
- function addDependencies(root, pkg, framework) {
642
- const present = { ...pkg.dependencies, ...pkg.devDependencies };
643
- const missing = framework.dependencies.filter(
644
- (name) => present[name] === void 0
908
+ function sortedEntries(entries) {
909
+ return Object.fromEntries(
910
+ Object.entries(entries).sort(([a], [b]) => a.localeCompare(b))
645
911
  );
646
- if (missing.length === 0) return [];
912
+ }
913
+ function addDependencies(root, pkg, framework, development) {
914
+ const present = { ...pkg.dependencies, ...pkg.devDependencies };
915
+ const absent = (name) => present[name] === void 0;
916
+ const missing = framework.dependencies.filter(absent);
917
+ const missingDev = development.filter(absent);
918
+ if (missing.length === 0 && missingDev.length === 0) return [];
647
919
  const range = `^${cliVersion()}`;
648
- const dependencies = { ...pkg.dependencies };
649
- for (const name of missing) dependencies[name] = range;
650
- pkg.dependencies = Object.fromEntries(
651
- Object.entries(dependencies).sort(([a], [b]) => a.localeCompare(b))
652
- );
653
- writeFileSync2(
654
- join3(root, "package.json"),
920
+ const pinned = (names) => Object.fromEntries(names.map((name) => [name, range]));
921
+ if (missing.length > 0) {
922
+ pkg.dependencies = sortedEntries({
923
+ ...pkg.dependencies,
924
+ ...pinned(missing)
925
+ });
926
+ }
927
+ if (missingDev.length > 0) {
928
+ pkg.devDependencies = sortedEntries({
929
+ ...pkg.devDependencies,
930
+ ...pinned(missingDev)
931
+ });
932
+ }
933
+ writeFileSync3(
934
+ join4(root, "package.json"),
655
935
  `${JSON.stringify(pkg, null, 2)}
656
936
  `
657
937
  );
658
- return missing.map((name) => `${name}@${range}`);
938
+ return [...missing, ...missingDev].map((name) => `${name}@${range}`);
659
939
  }
660
940
  function detectInstallCommand(root) {
661
- if (existsSync3(join3(root, "pnpm-lock.yaml")) || existsSync3(join3(root, "pnpm-workspace.yaml"))) {
941
+ if (existsSync4(join4(root, "pnpm-lock.yaml")) || existsSync4(join4(root, "pnpm-workspace.yaml"))) {
662
942
  return "pnpm install";
663
943
  }
664
- if (existsSync3(join3(root, "yarn.lock"))) return "yarn";
665
- if (existsSync3(join3(root, "bun.lock")) || existsSync3(join3(root, "bun.lockb"))) {
944
+ if (existsSync4(join4(root, "yarn.lock"))) return "yarn";
945
+ if (existsSync4(join4(root, "bun.lock")) || existsSync4(join4(root, "bun.lockb"))) {
666
946
  return "bun install";
667
947
  }
668
948
  return "npm install";
669
949
  }
670
950
  function existingFile(root, base) {
671
- return ["tsx", "ts", "jsx", "js"].map((extension) => `${base}.${extension}`).find((candidate) => existsSync3(join3(root, candidate)));
951
+ return ["tsx", "ts", "jsx", "js"].map((extension) => `${base}.${extension}`).find((candidate) => existsSync4(join4(root, candidate)));
672
952
  }
673
953
  function frameworkNotes(framework, root, skipped) {
674
954
  const notes = [];
@@ -703,7 +983,7 @@ function frameworkNotes(framework, root, skipped) {
703
983
  status: "unknown",
704
984
  message: "the cmssy wiring needs the React integration and a server adapter - run: npx astro add react node"
705
985
  });
706
- if (existsSync3(join3(root, "src/pages/index.astro"))) {
986
+ if (existsSync4(join4(root, "src/pages/index.astro"))) {
707
987
  notes.push({
708
988
  status: "unknown",
709
989
  message: "src/pages/index.astro shadows the cmssy catch-all for / - delete it and the cmssy page serves /"
@@ -728,7 +1008,7 @@ function runInit(options, deps) {
728
1008
  const { log } = deps;
729
1009
  try {
730
1010
  const root = resolve2(deps.cwd, options.dir ?? ".");
731
- if (!existsSync3(root)) {
1011
+ if (!existsSync4(root)) {
732
1012
  throw new CliError(
733
1013
  `${root} does not exist`,
734
1014
  "pass --dir with the app's directory, or run cmssy init inside it"
@@ -745,8 +1025,8 @@ function runInit(options, deps) {
745
1025
  const written = [];
746
1026
  const skipped = [];
747
1027
  for (const file of frameworkFiles(framework, root)) {
748
- const target = join3(root, file.target);
749
- if (existsSync3(target) && !options.force) {
1028
+ const target = join4(root, file.target);
1029
+ if (existsSync4(target) && !options.force) {
750
1030
  skipped.push(file.target);
751
1031
  log(
752
1032
  formatResult({
@@ -757,12 +1037,36 @@ function runInit(options, deps) {
757
1037
  continue;
758
1038
  }
759
1039
  mkdirSync2(dirname2(target), { recursive: true });
760
- copyFileSync(join3(ASSETS_DIR, framework.name, file.asset), target);
1040
+ copyFileSync2(join4(ASSETS_DIR, framework.name, file.asset), target);
761
1041
  written.push(file.target);
762
1042
  log(formatResult({ status: "ok", message: `wrote ${file.target}` }));
763
1043
  log(` ${file.purpose}`);
764
1044
  }
765
- const added = addDependencies(root, pkg, framework);
1045
+ const eslint = wireEslintConfig(
1046
+ root,
1047
+ pkg,
1048
+ join4(ASSETS_DIR, ESLINT_CONFIG_FILE)
1049
+ );
1050
+ if (eslint.written) {
1051
+ written.push(eslint.written);
1052
+ log(formatResult({ status: "ok", message: `wrote ${eslint.written}` }));
1053
+ log(` ${ESLINT_PURPOSE}`);
1054
+ }
1055
+ if (eslint.patched) {
1056
+ log(
1057
+ formatResult({
1058
+ status: "ok",
1059
+ message: `wired ${ESLINT_PLUGIN} into ${eslint.patched}`
1060
+ })
1061
+ );
1062
+ log(` ${ESLINT_PURPOSE}`);
1063
+ }
1064
+ const added = addDependencies(
1065
+ root,
1066
+ pkg,
1067
+ framework,
1068
+ eslint.dependency ? [ESLINT_PLUGIN] : []
1069
+ );
766
1070
  if (added.length > 0) {
767
1071
  log(
768
1072
  formatResult({
@@ -771,7 +1075,10 @@ function runInit(options, deps) {
771
1075
  })
772
1076
  );
773
1077
  }
774
- for (const note of frameworkNotes(framework, root, skipped)) {
1078
+ for (const note of [
1079
+ ...frameworkNotes(framework, root, skipped),
1080
+ ...eslint.notes
1081
+ ]) {
775
1082
  log(formatResult(note));
776
1083
  }
777
1084
  log("");
@@ -814,8 +1121,8 @@ function runInit(options, deps) {
814
1121
  }
815
1122
 
816
1123
  // src/link.ts
817
- import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
818
- import { join as join5 } from "path";
1124
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
1125
+ import { join as join6 } from "path";
819
1126
  import {
820
1127
  buildEditorUrl,
821
1128
  checkDraftSecret,
@@ -823,8 +1130,8 @@ import {
823
1130
  } from "@cmssy/core/preflight";
824
1131
 
825
1132
  // src/env-load.ts
826
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
827
- import { join as join4 } from "path";
1133
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1134
+ import { join as join5 } from "path";
828
1135
 
829
1136
  // src/env-file.ts
830
1137
  function parseEnvFile(content) {
@@ -863,9 +1170,9 @@ function applyEnv(vars, env) {
863
1170
  var ENV_FILES = [".env.local", ".env"];
864
1171
  function loadEnvFiles(cwd, env) {
865
1172
  for (const file of ENV_FILES) {
866
- const path = join4(cwd, file);
867
- if (!existsSync4(path)) continue;
868
- applyEnv(parseEnvFile(readFileSync4(path, "utf8")), env);
1173
+ const path = join5(cwd, file);
1174
+ if (!existsSync5(path)) continue;
1175
+ applyEnv(parseEnvFile(readFileSync5(path, "utf8")), env);
869
1176
  }
870
1177
  }
871
1178
 
@@ -1042,9 +1349,9 @@ function resolvePreviewUrl(options) {
1042
1349
  return origin;
1043
1350
  }
1044
1351
  function writeEnvLocal(cwd, updates) {
1045
- const path = join5(cwd, ".env.local");
1046
- const existing = existsSync5(path) ? readFileSync5(path, "utf8") : null;
1047
- writeFileSync3(path, mergeEnvContent(existing, updates));
1352
+ const path = join6(cwd, ".env.local");
1353
+ const existing = existsSync6(path) ? readFileSync6(path, "utf8") : null;
1354
+ writeFileSync4(path, mergeEnvContent(existing, updates));
1048
1355
  }
1049
1356
  async function runLink(options, deps) {
1050
1357
  const { cwd, env, log } = deps;
@@ -1158,7 +1465,7 @@ async function runLink(options, deps) {
1158
1465
  }
1159
1466
 
1160
1467
  // src/types-command.ts
1161
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync, writeFileSync as writeFileSync4 } from "fs";
1468
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync5 } from "fs";
1162
1469
  import { dirname as dirname3, relative, resolve as resolvePath } from "path";
1163
1470
  import { DEFAULT_CMSSY_API_URL } from "@cmssy/core";
1164
1471
 
@@ -1502,7 +1809,7 @@ function existingOperationNames(cwd, skipPath) {
1502
1809
  if (full === skipPath) continue;
1503
1810
  let source;
1504
1811
  try {
1505
- source = readFileSync6(full, "utf8");
1812
+ source = readFileSync7(full, "utf8");
1506
1813
  } catch {
1507
1814
  continue;
1508
1815
  }
@@ -1522,7 +1829,7 @@ function syncOperations(options, deps) {
1522
1829
  const source = generateOperationsFile();
1523
1830
  let previous = null;
1524
1831
  try {
1525
- previous = readFileSync6(outPath, "utf8");
1832
+ previous = readFileSync7(outPath, "utf8");
1526
1833
  } catch {
1527
1834
  previous = null;
1528
1835
  }
@@ -1550,7 +1857,7 @@ function syncOperations(options, deps) {
1550
1857
  }
1551
1858
  try {
1552
1859
  mkdirSync3(dirname3(outPath), { recursive: true });
1553
- writeFileSync4(outPath, source);
1860
+ writeFileSync5(outPath, source);
1554
1861
  } catch (error) {
1555
1862
  throw new CliError(
1556
1863
  `could not write ${shown}: ${error.message}`,
@@ -1597,7 +1904,7 @@ async function runTypes(options, deps) {
1597
1904
  const source = generateModelTypes(models, { workspace });
1598
1905
  let previous = null;
1599
1906
  try {
1600
- previous = readFileSync6(outPath, "utf8");
1907
+ previous = readFileSync7(outPath, "utf8");
1601
1908
  } catch {
1602
1909
  previous = null;
1603
1910
  }
@@ -1616,7 +1923,7 @@ async function runTypes(options, deps) {
1616
1923
  return 1;
1617
1924
  }
1618
1925
  mkdirSync3(dirname3(outPath), { recursive: true });
1619
- writeFileSync4(outPath, source);
1926
+ writeFileSync5(outPath, source);
1620
1927
  const fieldCount = models.reduce(
1621
1928
  (total, model) => total + model.fields.length,
1622
1929
  0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmssy/cli",
3
- "version": "12.11.0",
3
+ "version": "12.13.0",
4
4
  "description": "The cmssy CLI: `cmssy init` wires cmssy into an existing Next.js, Astro or React Router app; `cmssy link` connects it to a workspace and verifies the editor wiring.",
5
5
  "keywords": [
6
6
  "cmssy",
@@ -27,7 +27,7 @@
27
27
  "assets"
28
28
  ],
29
29
  "dependencies": {
30
- "@cmssy/core": "12.11.0"
30
+ "@cmssy/core": "12.13.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^20.0.0",