elcrm 1.1.2 → 1.1.3

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 (41) hide show
  1. package/dist/index.js +548 -33
  2. package/dist/vite/concat-css.js +13 -1
  3. package/dist/vite/postbuild.js +13 -1
  4. package/package.json +4 -3
  5. package/templates/elcrm-cursor/AGENTS.md +3 -1
  6. package/templates/elcrm-cursor/rules/elcrm-jsdoc.mdc +89 -0
  7. package/templates/elcrm-cursor/rules/elcrm-lib.mdc +1 -0
  8. package/templates/elcrm-cursor/rules/elcrm-packages.mdc +2 -2
  9. package/templates/elcrm-cursor/rules/elcrm-theme.mdc +1 -0
  10. package/templates/elcrm-cursor/rules/elcrm-tokens.mdc +40 -0
  11. package/templates/elcrm-cursor/rules/elcrm-ui.mdc +1 -0
  12. package/templates/elcrm-cursor/rules/elcrm.mdc +1 -1
  13. package/templates/elcrm-docs/CLI.elCRM.md +4 -3
  14. package/templates/elcrm-docs/COMPONENTS.elCRM.md +51 -46
  15. package/templates/panel/web/src/App.tsx +15 -1
  16. package/templates/panel/web/src/component/Header.tsx +19 -6
  17. package/templates/panel/web/src/lazyRoute.ts +6 -0
  18. package/templates/panel/web/src/lib/routeKey.ts +8 -1
  19. package/templates/panel/web/src/lib/theme.ts +20 -3
  20. package/templates/panel/web/src/modules/Account/index.tsx +12 -8
  21. package/templates/panel/web/src/modules/Account/router.sections.ts +5 -3
  22. package/templates/panel/web/src/modules/Account/sections/Profile.tsx +9 -4
  23. package/templates/panel/web/src/modules/Account/sections/Sessions.tsx +1 -1
  24. package/templates/panel/web/src/modules/Home/index.tsx +11 -4
  25. package/templates/panel/web/src/modules/Home/modal/Demo.tsx +10 -0
  26. package/templates/panel/web/src/modules/List/index.tsx +12 -11
  27. package/templates/panel/web/src/modules/List/router.sections.ts +6 -4
  28. package/templates/panel/web/src/modules/List/sections/Basic.tsx +3 -3
  29. package/templates/panel/web/src/modules/List/sections/Horizontal.tsx +1 -1
  30. package/templates/panel/web/src/modules/List/sections/Rows.tsx +6 -3
  31. package/templates/panel/web/src/modules/Settings/index.tsx +14 -8
  32. package/templates/panel/web/src/modules/Settings/router.sections.ts +7 -4
  33. package/templates/panel/web/src/modules/Settings/sections/Appearance.tsx +8 -4
  34. package/templates/panel/web/src/modules/Settings/sections/General.tsx +5 -1
  35. package/templates/panel/web/src/modules/Settings/sections/Profile.tsx +5 -1
  36. package/templates/panel/web/src/pages/Auth.tsx +10 -0
  37. package/templates/panel/web/src/pages/Main.tsx +7 -1
  38. package/templates/panel/web/src/state.ts +9 -0
  39. package/templates/panel/web/src/style/theme-dark.css +18 -87
  40. package/templates/panel/web/src/style/theme-light.css +18 -87
  41. package/templates/panel/web/src/style/theme.css +29 -78
package/dist/index.js CHANGED
@@ -688,6 +688,391 @@ var init_form_tokens = __esm(() => {
688
688
  DEPRECATED_DECL_RE = new RegExp(`(?:${FORM_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})\\s*:`);
689
689
  });
690
690
 
691
+ // src/lib/migrate/components.ts
692
+ import { readFileSync as readFileSync10 } from "fs";
693
+ function removeDecl2(css, name) {
694
+ const re = new RegExp(`\\n?[ \\t]*${name.replace(/-/g, "\\-")}\\s*:[^;\\n}]+;?[ \\t]*`, "g");
695
+ let n = 0;
696
+ const next = css.replace(re, () => {
697
+ n++;
698
+ return "";
699
+ });
700
+ return { next: next.replace(/\n{3,}/g, `
701
+
702
+ `), n };
703
+ }
704
+ function rewriteComponentsCss(source) {
705
+ let next = source;
706
+ let hits = 0;
707
+ for (const [re, to] of VAR_REPLACEMENTS2) {
708
+ next = next.replace(re, () => {
709
+ hits++;
710
+ return to;
711
+ });
712
+ }
713
+ for (const name of COMPONENTS_TOKEN_DEPRECATED) {
714
+ const stillUsed = new RegExp(`var\\(\\s*${name.replace(/-/g, "\\-")}\\s*`, "i").test(next);
715
+ if (stillUsed)
716
+ continue;
717
+ const rem = removeDecl2(next, name);
718
+ next = rem.next;
719
+ hits += rem.n;
720
+ }
721
+ return { next, hits };
722
+ }
723
+ function rewriteImports2(source) {
724
+ let hits = 0;
725
+ let next = source;
726
+ const replaceImportList = (list) => {
727
+ let s = list;
728
+ const before = s;
729
+ s = s.replace(/\bBlock\b/g, "Stack");
730
+ s = s.replace(/\bRow\b/g, "Stack");
731
+ s = s.replace(/\bColumn\b/g, "Stack");
732
+ const parts = s.split(",").map((p) => p.trim()).filter(Boolean);
733
+ const seen = new Set;
734
+ const uniq = [];
735
+ for (const p of parts) {
736
+ const bare = p.replace(/\s+as\s+\w+$/, "").trim();
737
+ if (seen.has(bare)) {
738
+ hits++;
739
+ continue;
740
+ }
741
+ seen.add(bare);
742
+ uniq.push(p);
743
+ }
744
+ if (s !== before || uniq.join(", ") !== list.trim())
745
+ hits++;
746
+ return uniq.join(", ");
747
+ };
748
+ next = next.replace(/import\s*\{([^}]+)\}\s*from\s*["']@elcrm\/components["']/g, (full, list) => {
749
+ if (!/\b(Block|Row|Column)\b/.test(list))
750
+ return full;
751
+ hits++;
752
+ return `import { ${replaceImportList(list)} } from "@elcrm/components"`;
753
+ });
754
+ next = next.replace(/import\s*\{\s*Block\s*\}\s*from\s*["']@elcrm\/components\/Block["']/g, () => {
755
+ hits++;
756
+ return `import { Stack } from "@elcrm/components/Stack"`;
757
+ });
758
+ next = next.replace(/import\s*\{\s*Row\s*\}\s*from\s*["']@elcrm\/components\/Row["']/g, () => {
759
+ hits++;
760
+ return `import { Stack } from "@elcrm/components/Stack"`;
761
+ });
762
+ next = next.replace(/import\s*\{\s*Column\s*\}\s*from\s*["']@elcrm\/components\/Column["']/g, () => {
763
+ hits++;
764
+ return `import { Stack } from "@elcrm/components/Stack"`;
765
+ });
766
+ return { next, hits };
767
+ }
768
+ function rewriteJsx(source) {
769
+ let hits = 0;
770
+ let next = source;
771
+ next = next.replace(/<Block([^>]*?)\srow(\s|\/|>)/g, (_m, attrs, end) => {
772
+ hits++;
773
+ return `<Stack${attrs} direction="row"${end}`;
774
+ });
775
+ next = next.replace(/<\/Block>/g, () => {
776
+ hits++;
777
+ return "</Stack>";
778
+ });
779
+ next = next.replace(/<Block(\s|\/|>)/g, (_m, end) => {
780
+ hits++;
781
+ return `<Stack${end}`;
782
+ });
783
+ next = next.replace(/<Row(\s[^/>]*(?:\/>|>))/g, (_m, rest) => {
784
+ hits++;
785
+ return `<Stack direction="row"${rest}`;
786
+ });
787
+ next = next.replace(/<\/Row>/g, () => {
788
+ hits++;
789
+ return "</Stack>";
790
+ });
791
+ next = next.replace(/<\/Column>/g, () => {
792
+ hits++;
793
+ return "</Stack>";
794
+ });
795
+ next = next.replace(/<Column(\s|\/|>)/g, (_m, end) => {
796
+ hits++;
797
+ return `<Stack${end}`;
798
+ });
799
+ next = next.replace(/\bactiveKey=/g, () => {
800
+ hits++;
801
+ return "value=";
802
+ });
803
+ next = next.replace(/\bdefaultActiveKey=/g, () => {
804
+ hits++;
805
+ return "defaultValue=";
806
+ });
807
+ return { next, hits };
808
+ }
809
+ function rewriteSectionOnChange(source) {
810
+ if (!/\b(NavSections|TabSections)\b/.test(source)) {
811
+ return { next: source, hits: 0 };
812
+ }
813
+ let hits = 0;
814
+ const next = source.replace(/\bonChange=/g, () => {
815
+ hits++;
816
+ return "onValueChange=";
817
+ });
818
+ return { next, hits };
819
+ }
820
+ function rewriteItemKeys(source) {
821
+ if (!/\b(Menu|NavSections|TabSections|MenuItem|NavSectionsItem|TabSectionsItem)\b/.test(source)) {
822
+ return { next: source, hits: 0 };
823
+ }
824
+ let hits = 0;
825
+ const next = source.replace(/(\{\s*)key(\s*:\s*["'`])/g, (_m, a, b) => {
826
+ hits++;
827
+ return `${a}value${b}`;
828
+ });
829
+ const next2 = next.replace(/(\.\s*)key(\s*(?:[,)\]]|;|\s*[=!]==))/g, (full, a, b) => {
830
+ if (/\bt\.key|\bi\.key|item\.key/.test(full) || /t\.key|i\.key/.test(a + "key")) {
831
+ hits++;
832
+ return `${a}value${b}`;
833
+ }
834
+ return full;
835
+ });
836
+ const next3 = next2.replace(/\b(t|i|item)\.key\b/g, (_m, obj) => {
837
+ hits++;
838
+ return `${obj}.value`;
839
+ });
840
+ return { next: next3, hits };
841
+ }
842
+ function rewriteComponentsTsx(source) {
843
+ let hits = 0;
844
+ let next = source;
845
+ const imp = rewriteImports2(next);
846
+ next = imp.next;
847
+ hits += imp.hits;
848
+ const jsx = rewriteJsx(next);
849
+ next = jsx.next;
850
+ hits += jsx.hits;
851
+ const oc = rewriteSectionOnChange(next);
852
+ next = oc.next;
853
+ hits += oc.hits;
854
+ const keys = rewriteItemKeys(next);
855
+ next = keys.next;
856
+ hits += keys.hits;
857
+ return { next, hits };
858
+ }
859
+ function fixStackDirectionSpacing(source) {
860
+ return source.replace(/<Stack direction="row"(\S)/g, `<Stack direction="row" $1`);
861
+ }
862
+ async function migrateComponents(cwd, dry) {
863
+ const pkg = readPackageJson(cwd);
864
+ if (pkg?.name === "@elcrm/components")
865
+ return [];
866
+ const changes = [];
867
+ const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r));
868
+ for (const file of files) {
869
+ const raw = readFileSync10(file, "utf8");
870
+ let next = raw;
871
+ let hits = 0;
872
+ if (file.endsWith(".css")) {
873
+ const r = rewriteComponentsCss(raw);
874
+ next = r.next;
875
+ hits = r.hits;
876
+ } else if (/\.(tsx?|jsx?|mdx?)$/.test(file)) {
877
+ const r = rewriteComponentsTsx(raw);
878
+ next = fixStackDirectionSpacing(r.next);
879
+ hits = r.hits;
880
+ } else {
881
+ continue;
882
+ }
883
+ if (hits === 0 || next === raw)
884
+ continue;
885
+ if (writeIfChanged(file, next, dry) || dry) {
886
+ changes.push({
887
+ file: rel(cwd, file),
888
+ detail: `${hits}\xD7 components (Stack / value / shell-tokens)`
889
+ });
890
+ }
891
+ }
892
+ return changes;
893
+ }
894
+ function lineHasDeprecatedComponentsToken(line) {
895
+ const t = line.trim();
896
+ if (!t || t.startsWith("/*") || t.startsWith("*"))
897
+ return false;
898
+ if (DEPRECATED_VAR_RE2.test(t))
899
+ return true;
900
+ if (!DEPRECATED_DECL_RE2.test(t))
901
+ return false;
902
+ if (/:\s*var\(\s*--shell-/.test(t))
903
+ return false;
904
+ return true;
905
+ }
906
+ var VAR_REPLACEMENTS2, COMPONENTS_TOKEN_DEPRECATED, DEPRECATED_VAR_RE2, DEPRECATED_DECL_RE2;
907
+ var init_components = __esm(() => {
908
+ init_pkg();
909
+ init_walk();
910
+ VAR_REPLACEMENTS2 = [
911
+ [/var\(\s*--layout-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background-muted)"],
912
+ [/var\(\s*--header-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background)"],
913
+ [/var\(\s*--header-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
914
+ [/var\(\s*--header-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
915
+ [/var\(\s*--footer-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
916
+ [/var\(\s*--footer-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
917
+ [/var\(\s*--item-background-hover\s*(?:,[^)]+)?\)/gi, "var(--shell-background-hover)"],
918
+ [/var\(\s*--item-background-active\s*(?:,[^)]+)?\)/gi, "var(--shell-background-selected)"],
919
+ [/var\(\s*--item-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
920
+ [/var\(\s*--card-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background)"],
921
+ [/var\(\s*--card-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
922
+ [/var\(\s*--card-shadow\s*(?:,[^)]+)?\)/gi, "var(--shell-shadow)"],
923
+ [/var\(\s*--menu-item-background-hover\s*(?:,[^)]+)?\)/gi, "var(--shell-background-hover)"],
924
+ [/var\(\s*--menu-item-background-active\s*(?:,[^)]+)?\)/gi, "var(--shell-background-selected)"],
925
+ [/var\(\s*--menu-item-color-active\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
926
+ [/var\(\s*--menu-item-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
927
+ [/var\(\s*--loading-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
928
+ [/var\(\s*--section-title-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
929
+ [/var\(\s*--section-description-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
930
+ [/var\(\s*--section-auth-card-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background)"],
931
+ [/var\(\s*--section-auth-card-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
932
+ [/var\(\s*--section-auth-card-shadow\s*(?:,[^)]+)?\)/gi, "var(--shell-shadow)"],
933
+ [/var\(\s*--section-block-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
934
+ [/var\(\s*--nav-sections-label-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
935
+ [/var\(\s*--nav-sections-item-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
936
+ [/var\(\s*--nav-sections-item-background-hover\s*(?:,[^)]+)?\)/gi, "var(--shell-background-hover)"],
937
+ [/var\(\s*--nav-sections-item-background-active\s*(?:,[^)]+)?\)/gi, "var(--shell-background-selected)"],
938
+ [/var\(\s*--nav-sections-accent\s*(?:,[^)]+)?\)/gi, "var(--shell-color-accent)"],
939
+ [/var\(\s*--nav-sections-icon-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
940
+ [/var\(\s*--nav-sections-group-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
941
+ [/var\(\s*--nav-sections-footer-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
942
+ [/var\(\s*--tab-sections-border\s*(?:,[^)]+)?\)/gi, "var(--shell-border)"],
943
+ [/var\(\s*--tab-sections-color-active\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
944
+ [/var\(\s*--tab-sections-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-muted)"],
945
+ [/var\(\s*--tab-sections-accent\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
946
+ [/var\(\s*--tab-sections-badge-background\s*(?:,[^)]+)?\)/gi, "var(--shell-color-danger)"],
947
+ [/var\(\s*--brand-color-hover\s*(?:,[^)]+)?\)/gi, "var(--shell-color-accent)"],
948
+ [/var\(\s*--brand-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
949
+ [/var\(\s*--badge-neutral-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color)"],
950
+ [/var\(\s*--badge-accent-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-accent)"],
951
+ [/var\(\s*--badge-success-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-success)"],
952
+ [/var\(\s*--badge-danger-color\s*(?:,[^)]+)?\)/gi, "var(--shell-color-danger)"],
953
+ [/var\(\s*--list-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap-sm)"],
954
+ [/var\(\s*--item-padding\s*(?:,[^)]+)?\)/gi, "var(--shell-padding)"],
955
+ [/var\(\s*--item-radius\s*(?:,[^)]+)?\)/gi, "var(--shell-radius)"],
956
+ [/var\(\s*--block-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
957
+ [/var\(\s*--row-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
958
+ [/var\(\s*--column-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"]
959
+ ];
960
+ COMPONENTS_TOKEN_DEPRECATED = [
961
+ "--layout-background",
962
+ "--layout-min-height",
963
+ "--layout-gap",
964
+ "--header-background",
965
+ "--header-color",
966
+ "--header-border",
967
+ "--header-padding",
968
+ "--header-gap",
969
+ "--footer-background",
970
+ "--footer-color",
971
+ "--footer-border",
972
+ "--footer-padding",
973
+ "--footer-font-size",
974
+ "--list-gap",
975
+ "--list-padding",
976
+ "--item-background",
977
+ "--item-background-hover",
978
+ "--item-background-active",
979
+ "--item-color",
980
+ "--item-color-muted",
981
+ "--item-border",
982
+ "--item-radius",
983
+ "--item-padding",
984
+ "--item-gap",
985
+ "--card-background",
986
+ "--card-border",
987
+ "--card-shadow",
988
+ "--card-radius",
989
+ "--card-padding",
990
+ "--block-gap",
991
+ "--block-padding",
992
+ "--row-gap",
993
+ "--column-gap",
994
+ "--menu-gap",
995
+ "--menu-item-radius",
996
+ "--menu-item-padding",
997
+ "--menu-item-background",
998
+ "--menu-item-background-hover",
999
+ "--menu-item-background-active",
1000
+ "--menu-item-color",
1001
+ "--menu-item-color-active",
1002
+ "--loading-padding",
1003
+ "--loading-color",
1004
+ "--section-gap",
1005
+ "--section-description-size",
1006
+ "--section-icon-gap",
1007
+ "--section-body-gap",
1008
+ "--section-actions-gap",
1009
+ "--section-auth-padding",
1010
+ "--section-auth-card-padding",
1011
+ "--section-auth-card-radius",
1012
+ "--section-block-padding-bottom",
1013
+ "--section-block-margin-bottom",
1014
+ "--section-title-color",
1015
+ "--section-description-color",
1016
+ "--section-auth-card-background",
1017
+ "--section-auth-card-border",
1018
+ "--section-auth-card-shadow",
1019
+ "--section-block-border",
1020
+ "--nav-sections-gap",
1021
+ "--nav-sections-item-radius",
1022
+ "--nav-sections-item-padding",
1023
+ "--nav-sections-label-color",
1024
+ "--nav-sections-item-color",
1025
+ "--nav-sections-item-background-hover",
1026
+ "--nav-sections-item-background-active",
1027
+ "--nav-sections-accent",
1028
+ "--nav-sections-icon-color",
1029
+ "--nav-sections-group-border",
1030
+ "--nav-sections-footer-border",
1031
+ "--tab-sections-gap",
1032
+ "--tab-sections-tab-padding",
1033
+ "--tab-sections-tab-gap",
1034
+ "--tab-sections-badge-size",
1035
+ "--tab-sections-border",
1036
+ "--tab-sections-color",
1037
+ "--tab-sections-color-active",
1038
+ "--tab-sections-accent",
1039
+ "--tab-sections-badge-background",
1040
+ "--tab-sections-badge-color",
1041
+ "--badge-padding",
1042
+ "--badge-radius",
1043
+ "--badge-font-size",
1044
+ "--badge-font-weight",
1045
+ "--badge-border",
1046
+ "--badge-neutral-background",
1047
+ "--badge-neutral-color",
1048
+ "--badge-accent-background",
1049
+ "--badge-accent-color",
1050
+ "--badge-success-background",
1051
+ "--badge-success-color",
1052
+ "--badge-warning-background",
1053
+ "--badge-warning-color",
1054
+ "--badge-danger-background",
1055
+ "--badge-danger-color",
1056
+ "--brand-font-weight",
1057
+ "--brand-letter-spacing",
1058
+ "--brand-color",
1059
+ "--brand-color-hover",
1060
+ "--empty-state-gap",
1061
+ "--empty-state-padding",
1062
+ "--empty-state-icon-gap",
1063
+ "--empty-state-title-size",
1064
+ "--empty-state-description-size",
1065
+ "--empty-state-max-width",
1066
+ "--empty-state-actions-gap",
1067
+ "--empty-state-actions-margin-top",
1068
+ "--radio-group-gap",
1069
+ "--page-pad",
1070
+ "--page-gap"
1071
+ ];
1072
+ DEPRECATED_VAR_RE2 = new RegExp(`var\\(\\s*(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})\\s*`, "i");
1073
+ DEPRECATED_DECL_RE2 = new RegExp(`(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})\\s*:`);
1074
+ });
1075
+
691
1076
  // src/lib/migrate/front.ts
692
1077
  var exports_front = {};
693
1078
  __export(exports_front, {
@@ -714,18 +1099,21 @@ var init_front = __esm(() => {
714
1099
  init_legacy_hacks();
715
1100
  init_form_aliases();
716
1101
  init_form_tokens();
1102
+ init_components();
717
1103
  FRONT_MIGRATIONS = {
718
1104
  "size-sml": migrateSizeSml,
719
1105
  "field-border": migrateFieldBorder,
720
1106
  "modal-create": migrateModalCreate,
721
1107
  "form-aliases": migrateFormAliases,
722
1108
  "form-tokens": migrateFormTokens,
1109
+ components: migrateComponents,
723
1110
  "legacy-hacks": migrateLegacyReactHack,
724
1111
  "socket-server": migrateSocketServer
725
1112
  };
726
1113
  FRONT_MIGRATE_ORDER = [
727
1114
  "form-aliases",
728
1115
  "form-tokens",
1116
+ "components",
729
1117
  "size-sml",
730
1118
  "field-border",
731
1119
  "modal-create",
@@ -734,7 +1122,7 @@ var init_front = __esm(() => {
734
1122
  });
735
1123
 
736
1124
  // src/index.ts
737
- import { readFileSync as readFileSync19 } from "fs";
1125
+ import { readFileSync as readFileSync20 } from "fs";
738
1126
  import { dirname as dirname4, join as join18 } from "path";
739
1127
  import { fileURLToPath as fileURLToPath2 } from "url";
740
1128
 
@@ -880,15 +1268,20 @@ init_front();
880
1268
 
881
1269
  // src/lib/cssSync.ts
882
1270
  init_form_tokens();
1271
+ init_components();
883
1272
  import {
884
1273
  existsSync as existsSync6,
885
1274
  readdirSync as readdirSync3,
886
- readFileSync as readFileSync10,
1275
+ readFileSync as readFileSync11,
887
1276
  statSync as statSync3,
888
1277
  writeFileSync as writeFileSync4
889
1278
  } from "fs";
890
1279
  import { createRequire } from "module";
891
1280
  import { dirname, join as join6 } from "path";
1281
+ var TOKEN_DEPRECATED = new Set([
1282
+ ...FORM_TOKEN_DEPRECATED,
1283
+ ...COMPONENTS_TOKEN_DEPRECATED
1284
+ ]);
892
1285
  var COLOR_VALUE = /#|rgba?\(|hsla?\(|oklch|oklab|color-mix|lab\(|lch\(|hwb\(/i;
893
1286
  var COLOR_NAME = /(?:^|-)(bg|fg|color|fill|track|thumb|overlay|shadow|border|ring|background|placeholder)(?:-|$)/i;
894
1287
  var GEOM_VALUE = /(?:^|\s)(\d*\.?\d+)(px|em|rem|%|vh|vw|dvh|ch|ex|s|ms|deg|fr|pt)\b|^[0-9.]+$|ease|linear|none/i;
@@ -1008,7 +1401,7 @@ function resolvePkgRoot(pkgName, cwd) {
1008
1401
  }
1009
1402
  function readPkgJson(dir) {
1010
1403
  try {
1011
- return JSON.parse(readFileSync10(join6(dir, "package.json"), "utf8"));
1404
+ return JSON.parse(readFileSync11(join6(dir, "package.json"), "utf8"));
1012
1405
  } catch {
1013
1406
  return null;
1014
1407
  }
@@ -1064,7 +1457,7 @@ function collectPkgTokens(pkgName, cwd) {
1064
1457
  const acc = [];
1065
1458
  const seen = new Set;
1066
1459
  for (const file of files) {
1067
- const css = readFileSync10(file, "utf8");
1460
+ const css = readFileSync11(file, "utf8");
1068
1461
  const kind = fileKind(file);
1069
1462
  if (kind !== "mixed") {
1070
1463
  for (const [name, value] of parseCustomProps(css)) {
@@ -1232,9 +1625,9 @@ function syncElcrmCss(options) {
1232
1625
  const file = fileFor(bucket);
1233
1626
  if (!existsSync6(file))
1234
1627
  continue;
1235
- let css = readFileSync10(file, "utf8");
1628
+ let css = readFileSync11(file, "utf8");
1236
1629
  const have = existingTokenNames(css);
1237
- const missing = allDefs.filter((d) => d.bucket === bucket && !have.has(d.name) && !FORM_TOKEN_DEPRECATED.includes(d.name));
1630
+ const missing = allDefs.filter((d) => d.bucket === bucket && !have.has(d.name) && !TOKEN_DEPRECATED.has(d.name));
1238
1631
  const uniq = [];
1239
1632
  const seen = new Set;
1240
1633
  for (const d of missing) {
@@ -1257,7 +1650,7 @@ function syncElcrmCss(options) {
1257
1650
  writeFileSync4(file, next, "utf8");
1258
1651
  }
1259
1652
  if (existsSync6(paths.elcrm)) {
1260
- let css = readFileSync10(paths.elcrm, "utf8");
1653
+ let css = readFileSync11(paths.elcrm, "utf8");
1261
1654
  for (const exp of cssExports) {
1262
1655
  const specs = [];
1263
1656
  if (exp.light)
@@ -1284,7 +1677,7 @@ function syncElcrmCss(options) {
1284
1677
  import { resolve } from "path";
1285
1678
 
1286
1679
  // src/lib/test/detect.ts
1287
- import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
1680
+ import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
1288
1681
  import { join as join7 } from "path";
1289
1682
  function hasElcrmServer(pkg) {
1290
1683
  for (const section of [
@@ -1339,17 +1732,42 @@ function readPkgAt(dir) {
1339
1732
  if (!existsSync7(path))
1340
1733
  return null;
1341
1734
  try {
1342
- return JSON.parse(readFileSync11(path, "utf8"));
1735
+ return JSON.parse(readFileSync12(path, "utf8"));
1343
1736
  } catch {
1344
1737
  return null;
1345
1738
  }
1346
1739
  }
1347
1740
 
1348
1741
  // src/lib/test/front.ts
1349
- import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync12, statSync as statSync5 } from "fs";
1742
+ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
1350
1743
  import { join as join8, relative as relative2 } from "path";
1351
1744
  init_form_tokens();
1745
+ init_components();
1352
1746
  var SKIP = new Set(["node_modules", "dist", ".git", "coverage", ".bun"]);
1747
+ function isThemeTokenFile(rel2) {
1748
+ const n = rel2.replace(/\\/g, "/");
1749
+ return /(?:^|\/)(?:theme(?:-light|-dark)?|elcrm)\.css$/.test(n);
1750
+ }
1751
+ function isGeneratedIcons(rel2) {
1752
+ return /icons\.generated\.(tsx?|jsx?)$/.test(rel2.replace(/\\/g, "/"));
1753
+ }
1754
+ var HARD_HEX_RE = /#[0-9a-fA-F]{3,8}\b/;
1755
+ var HARD_RGB_RE = /\b(?:rgb|rgba|hsl|hsla)\s*\(/i;
1756
+ var HARD_NAMED_RE = /(?:^|[;{]\s*|(?:color|background(?:-color)?|border-color|fill|stroke|outline-color)\s*:\s*)(?:white|black|red|blue|navy|gray|grey|silver|whitesmoke)\b/i;
1757
+ var JSX_COLOR_PROP_RE = /\b(?:color|background(?:Color)?|borderColor|fill)\s*=\s*\{?\s*["'](?:#|rgb|hsl|white|black)/i;
1758
+ function lineForColorScan(line) {
1759
+ return line.replace(/var\([^)]*\)/g, "").replace(/url\s*\([^)]*\)/gi, "");
1760
+ }
1761
+ function hardcodedColorReason(line) {
1762
+ const s = lineForColorScan(line);
1763
+ if (HARD_HEX_RE.test(s) || HARD_RGB_RE.test(s) || JSX_COLOR_PROP_RE.test(line)) {
1764
+ return "\u043B\u0438\u0442\u0435\u0440\u0430\u043B \u0446\u0432\u0435\u0442\u0430 \u2014 var(--button-*|--field-*|--item-*|--layout-*) \u0438\u0437 theme";
1765
+ }
1766
+ if (HARD_NAMED_RE.test(s) && !/\btransparent\b|\bcurrentColor\b|\binherit\b/.test(s)) {
1767
+ return "\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0446\u0432\u0435\u0442 \u2014 \u0442\u043E\u043A\u0435\u043D @elcrm/* / theme";
1768
+ }
1769
+ return null;
1770
+ }
1353
1771
  var DEPRECATED_SOCKET_IMPORT_RE = /(?:from\s+|require\s*\(\s*)["']@elcrm\/(?:socket\/server|socket-server)["']/;
1354
1772
  var THEMES_CSS_IMPORT_RE = /(?:from\s+|import\s+)["']@elcrm\/[^"']+\/themes\.css["']|import\s+["']@elcrm\/[^"']+\/themes\.css["']/;
1355
1773
  var LEGACY_PASSKEY_IMPORT_RE = /(?:from\s+|require\s*\(\s*)["']@elcrm\/passkey["']/;
@@ -1469,8 +1887,9 @@ function collectFrontIssues(cwd, pkg) {
1469
1887
  files.push(inSrc);
1470
1888
  }
1471
1889
  for (const file of files) {
1472
- const text = readFileSync12(file, "utf8");
1890
+ const text = readFileSync13(file, "utf8");
1473
1891
  const rel2 = relative2(cwd, file);
1892
+ const skipHardColor = isLib || isThemeTokenFile(rel2) || isGeneratedIcons(rel2);
1474
1893
  if (DEPRECATED_SOCKET_IMPORT_RE.test(text)) {
1475
1894
  issues.push({
1476
1895
  level: "error",
@@ -1576,12 +1995,56 @@ function collectFrontIssues(cwd, pkg) {
1576
1995
  fixable: true
1577
1996
  });
1578
1997
  }
1998
+ if (lineHasDeprecatedComponentsToken(line)) {
1999
+ issues.push({
2000
+ level: "warn",
2001
+ code: "components-token-legacy",
2002
+ message: "legacy \u0442\u043E\u043A\u0435\u043D @elcrm/components \u2192 --shell-* (elcrm migrate components)",
2003
+ file: rel2,
2004
+ line: i + 1,
2005
+ fixable: true
2006
+ });
2007
+ }
2008
+ if (/\b(Block|Row|Column)\b/.test(line) && /@elcrm\/components/.test(text) && /from\s+["']@elcrm\/components/.test(text)) {
2009
+ if (/import\s*\{[^}]*\b(Block|Row|Column)\b/.test(line) || /<\/?(?:Block|Row|Column)\b/.test(line)) {
2010
+ issues.push({
2011
+ level: "warn",
2012
+ code: "components-stack",
2013
+ message: "Block/Row/Column \u0443\u0441\u0442\u0430\u0440\u0435\u043B\u0438 \u2014 Stack (elcrm migrate components)",
2014
+ file: rel2,
2015
+ line: i + 1,
2016
+ fixable: true
2017
+ });
2018
+ }
2019
+ }
2020
+ if (/\b(activeKey|defaultActiveKey)\s*=/.test(line) && /@elcrm\/components/.test(text)) {
2021
+ issues.push({
2022
+ level: "warn",
2023
+ code: "components-value",
2024
+ message: "activeKey/defaultActiveKey \u2192 value/defaultValue (elcrm migrate components)",
2025
+ file: rel2,
2026
+ line: i + 1,
2027
+ fixable: true
2028
+ });
2029
+ }
2030
+ if (!skipHardColor) {
2031
+ const why = hardcodedColorReason(line);
2032
+ if (why) {
2033
+ issues.push({
2034
+ level: "warn",
2035
+ code: "hardcoded-color",
2036
+ message: why,
2037
+ file: rel2,
2038
+ line: i + 1
2039
+ });
2040
+ }
2041
+ }
1579
2042
  });
1580
2043
  }
1581
2044
  return issues;
1582
2045
  }
1583
2046
  async function runPkgScript(cwd, script) {
1584
- const pkg = JSON.parse(readFileSync12(join8(cwd, "package.json"), "utf8"));
2047
+ const pkg = JSON.parse(readFileSync13(join8(cwd, "package.json"), "utf8"));
1585
2048
  if (!pkg.scripts?.[script])
1586
2049
  return { ran: false, ok: true };
1587
2050
  console.log(`\u2192 bun run ${script}`);
@@ -1624,7 +2087,7 @@ function printIssues(issues, title) {
1624
2087
  }
1625
2088
 
1626
2089
  // src/lib/test/serverScan.ts
1627
- import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync13, statSync as statSync6 } from "fs";
2090
+ import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync14, statSync as statSync6 } from "fs";
1628
2091
  import { join as join9, relative as relative3 } from "path";
1629
2092
 
1630
2093
  // src/lib/test/serverRules.ts
@@ -2026,7 +2489,7 @@ function scanServerProject(root) {
2026
2489
  walkFiles2(root, root, files);
2027
2490
  const findings = [];
2028
2491
  for (const file of files) {
2029
- const text = readFileSync13(file, "utf8");
2492
+ const text = readFileSync14(file, "utf8");
2030
2493
  if (file.endsWith("package.json")) {
2031
2494
  findings.push(...scanPackageJson(root, file, text));
2032
2495
  } else {
@@ -2295,7 +2758,7 @@ import {
2295
2758
  existsSync as existsSync11,
2296
2759
  mkdirSync,
2297
2760
  readdirSync as readdirSync7,
2298
- readFileSync as readFileSync14,
2761
+ readFileSync as readFileSync15,
2299
2762
  statSync as statSync7,
2300
2763
  writeFileSync as writeFileSync5
2301
2764
  } from "fs";
@@ -2339,7 +2802,7 @@ function isEmptyDir(dir) {
2339
2802
  function writePkgName(pkgPath, name) {
2340
2803
  if (!existsSync11(pkgPath))
2341
2804
  return;
2342
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf8"));
2805
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf8"));
2343
2806
  pkg.name = name;
2344
2807
  pkg.version = pkg.version ?? "0.0.0";
2345
2808
  writeFileSync5(pkgPath, JSON.stringify(pkg, null, 2) + `
@@ -2506,7 +2969,7 @@ async function cmdMigrate(parsed) {
2506
2969
  console.log(dry ? `
2507
2970
  --dry: ${changes.length} \u043F\u043E\u0442\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0445 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439.` : `
2508
2971
  \u041F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E: ${changes.length}.`);
2509
- if (name === "front" || name === "ui" || name === "size-sml" || name === "form-tokens") {
2972
+ if (name === "front" || name === "ui" || name === "size-sml" || name === "form-tokens" || name === "components") {
2510
2973
  console.log("\u0414\u0430\u043B\u044C\u0448\u0435: elcrm css && elcrm audit");
2511
2974
  }
2512
2975
  }
@@ -2701,7 +3164,7 @@ import { resolve as resolve3 } from "path";
2701
3164
  import {
2702
3165
  existsSync as existsSync13,
2703
3166
  readdirSync as readdirSync9,
2704
- readFileSync as readFileSync16,
3167
+ readFileSync as readFileSync17,
2705
3168
  rmSync,
2706
3169
  statSync as statSync8,
2707
3170
  writeFileSync as writeFileSync7
@@ -2709,12 +3172,24 @@ import {
2709
3172
  import { join as join13 } from "path";
2710
3173
 
2711
3174
  // src/vite/concat-css.ts
2712
- import { readdirSync as readdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync6 } from "fs";
3175
+ import { readdirSync as readdirSync8, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "fs";
2713
3176
  import { join as join12 } from "path";
3177
+ var SKIP_CSS = new Set([
3178
+ "index.css",
3179
+ "tokens.css",
3180
+ "light.css",
3181
+ "dark.css",
3182
+ "themes.css"
3183
+ ]);
2714
3184
  function concatDistCss(options) {
2715
3185
  const outFile = options.outFile ?? "index.css";
2716
- const files = readdirSync8(options.distDir).filter((f) => f.endsWith(".css") && f !== outFile).sort();
2717
- const css = files.map((f) => readFileSync15(join12(options.distDir, f), "utf8")).join(`
3186
+ const skip = new Set([
3187
+ ...SKIP_CSS,
3188
+ outFile,
3189
+ ...options.skip ?? []
3190
+ ]);
3191
+ const files = readdirSync8(options.distDir).filter((f) => f.endsWith(".css") && !skip.has(f)).sort();
3192
+ const css = files.map((f) => readFileSync16(join12(options.distDir, f), "utf8")).join(`
2718
3193
  `);
2719
3194
  const outPath = join12(options.distDir, outFile);
2720
3195
  writeFileSync6(outPath, css);
@@ -2745,7 +3220,7 @@ function postbuildLib(options) {
2745
3220
  const flat = join13(dist, `${name}.d.ts`);
2746
3221
  const src = existsSync13(impl) ? impl : existsSync13(nestedIndex) ? nestedIndex : null;
2747
3222
  if (src) {
2748
- const text = readFileSync16(src, "utf8").replace(/from ['"]\.\.\/([^'"]+)['"]/g, `from './$1'`);
3223
+ const text = readFileSync17(src, "utf8").replace(/from ['"]\.\.\/([^'"]+)['"]/g, `from './$1'`);
2749
3224
  writeFileSync7(flat, text);
2750
3225
  console.log(`[postbuild] types \u2192 ${name}.d.ts`);
2751
3226
  }
@@ -2812,12 +3287,13 @@ async function cmdCss(parsed) {
2812
3287
  }
2813
3288
 
2814
3289
  // src/commands/audit.ts
2815
- import { existsSync as existsSync14, readFileSync as readFileSync17 } from "fs";
3290
+ import { existsSync as existsSync14, readFileSync as readFileSync18 } from "fs";
2816
3291
  import { join as join14, relative as relative4 } from "path";
2817
3292
  init_pkg();
2818
3293
  init_walk();
2819
3294
  init_front();
2820
3295
  init_form_tokens();
3296
+ init_components();
2821
3297
  function scan(cwd) {
2822
3298
  const out = [];
2823
3299
  const pkg = readPackageJson(cwd);
@@ -2848,7 +3324,7 @@ function scan(cwd) {
2848
3324
  }
2849
3325
  const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r));
2850
3326
  for (const file of files) {
2851
- const text = readFileSync17(file, "utf8");
3327
+ const text = readFileSync18(file, "utf8");
2852
3328
  const rel2 = relative4(cwd, file);
2853
3329
  const lines = text.split(/\r?\n/);
2854
3330
  lines.forEach((line, i) => {
@@ -2930,7 +3406,7 @@ function scan(cwd) {
2930
3406
  return false;
2931
3407
  if (/theme(-light|-dark)?\.css$/.test(f))
2932
3408
  return false;
2933
- const t = readFileSync17(f, "utf8");
3409
+ const t = readFileSync18(f, "utf8");
2934
3410
  return t.includes("--search-border:") && t.includes("--button-secondary-bg:") && t.includes("transparent");
2935
3411
  });
2936
3412
  if (toolbarMarkers.length > 1) {
@@ -2957,7 +3433,7 @@ function scan(cwd) {
2957
3433
  "theme-dark.css",
2958
3434
  "theme.css"
2959
3435
  ].map((f) => join14(styleDir, f));
2960
- const themeText = themeFiles.filter(existsSync14).map((f) => readFileSync17(f, "utf8")).join(`
3436
+ const themeText = themeFiles.filter(existsSync14).map((f) => readFileSync18(f, "utf8")).join(`
2961
3437
  `);
2962
3438
  if (themeText && !/--popup-shadow\s*:/.test(themeText) && /--date-popup-shadow\s*:|--select-background\s*:/.test(themeText)) {
2963
3439
  out.push({
@@ -2979,7 +3455,7 @@ function scan(cwd) {
2979
3455
  for (const file of files) {
2980
3456
  if (!file.endsWith(".css"))
2981
3457
  continue;
2982
- const text = readFileSync17(file, "utf8");
3458
+ const text = readFileSync18(file, "utf8");
2983
3459
  const relPath = relative4(cwd, file);
2984
3460
  const lines = text.split(/\r?\n/);
2985
3461
  lines.forEach((line, i) => {
@@ -2995,6 +3471,16 @@ function scan(cwd) {
2995
3471
  fix: "elcrm migrate form-tokens"
2996
3472
  });
2997
3473
  }
3474
+ if (lineHasDeprecatedComponentsToken(line)) {
3475
+ out.push({
3476
+ level: "warn",
3477
+ code: "components-token-legacy",
3478
+ message: "legacy components-\u0442\u043E\u043A\u0435\u043D \u2192 --shell-*",
3479
+ file: relPath,
3480
+ line: i + 1,
3481
+ fix: "elcrm migrate components"
3482
+ });
3483
+ }
2998
3484
  });
2999
3485
  }
3000
3486
  return out;
@@ -3108,7 +3594,7 @@ import {
3108
3594
  existsSync as existsSync15,
3109
3595
  mkdirSync as mkdirSync2,
3110
3596
  readdirSync as readdirSync10,
3111
- readFileSync as readFileSync18,
3597
+ readFileSync as readFileSync19,
3112
3598
  writeFileSync as writeFileSync8
3113
3599
  } from "fs";
3114
3600
  import { dirname as dirname3, join as join15 } from "path";
@@ -3126,7 +3612,7 @@ function readBundled(relPath) {
3126
3612
  if (!existsSync15(full)) {
3127
3613
  throw new Error(`\u0428\u0430\u0431\u043B\u043E\u043D \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: ${relPath}`);
3128
3614
  }
3129
- return readFileSync18(full, "utf8");
3615
+ return readFileSync19(full, "utf8");
3130
3616
  }
3131
3617
 
3132
3618
  // src/commands/docs.ts
@@ -3153,8 +3639,13 @@ async function cmdDocs(parsed) {
3153
3639
 
3154
3640
  // src/commands/cursor.ts
3155
3641
  import { join as join17, resolve as resolve5 } from "path";
3156
- var ALWAYS = ["elcrm.mdc", "elcrm-packages.mdc"];
3157
- var UI = ["elcrm-ui.mdc", "elcrm-module.mdc", "elcrm-theme.mdc"];
3642
+ var ALWAYS = ["elcrm.mdc", "elcrm-packages.mdc", "elcrm-jsdoc.mdc"];
3643
+ var UI = [
3644
+ "elcrm-ui.mdc",
3645
+ "elcrm-module.mdc",
3646
+ "elcrm-theme.mdc",
3647
+ "elcrm-tokens.mdc"
3648
+ ];
3158
3649
  var SERVER = ["elcrm-server.mdc", "elcrm-rpc.mdc"];
3159
3650
  var LIB = ["elcrm-lib.mdc"];
3160
3651
  function writeOne(dest, body, dry, force, label) {
@@ -3191,6 +3682,23 @@ async function cmdCursor(parsed) {
3191
3682
  console.log(c.gray("\u0410\u0433\u0435\u043D\u0442: AGENTS.md + rules (\u0443\u0437\u043A\u0438\u0435 glob) + .cursor/docs. \u0421\u0434\u0430\u0447\u0430: elcrm test."));
3192
3683
  }
3193
3684
 
3685
+ // src/commands/upd.ts
3686
+ import { spawnSync as spawnSync2 } from "child_process";
3687
+ async function cmdUpd() {
3688
+ const bun = spawnSync2("bun", ["--version"], { encoding: "utf8" });
3689
+ const cmd = bun.status === 0 ? "bun" : "npm";
3690
+ const args = ["i", "-g", "elcrm@latest"];
3691
+ console.log(`${c.cyan("\u2192")} ${cmd} ${args.join(" ")}`);
3692
+ const r = spawnSync2(cmd, args, {
3693
+ stdio: "inherit",
3694
+ env: process.env
3695
+ });
3696
+ if (r.status !== 0) {
3697
+ process.exit(r.status ?? 1);
3698
+ }
3699
+ console.log(c.green("CLI \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D. \u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430: elcrm -v"));
3700
+ }
3701
+
3194
3702
  // src/index.ts
3195
3703
  function cliVersion() {
3196
3704
  const here = dirname4(fileURLToPath2(import.meta.url));
@@ -3199,7 +3707,7 @@ function cliVersion() {
3199
3707
  join18(here, "package.json")
3200
3708
  ]) {
3201
3709
  try {
3202
- const v = JSON.parse(readFileSync19(p, "utf8")).version;
3710
+ const v = JSON.parse(readFileSync20(p, "utf8")).version;
3203
3711
  if (typeof v === "string" && v)
3204
3712
  return v;
3205
3713
  } catch {}
@@ -3216,6 +3724,9 @@ function showHelp() {
3216
3724
  elcrm <\u043A\u043E\u043C\u0430\u043D\u0434\u0430> [\u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B] [\u0444\u043B\u0430\u0433\u0438]
3217
3725
 
3218
3726
  \u041A\u043E\u043C\u0430\u043D\u0434\u044B:
3727
+ upd
3728
+ \u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0430\u043C CLI: bun i -g elcrm@latest (\u0431\u0435\u0437 bun \u2014 npm)
3729
+
3219
3730
  update [--dry] [--core] [--no-install] [--fix] [--test]
3220
3731
  \u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435 @elcrm/* \u0434\u043E latest; --fix = migrate front; --test = elcrm test
3221
3732
  \u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F: elcrm update --fix --test
@@ -3229,7 +3740,7 @@ function showHelp() {
3229
3740
 
3230
3741
  migrate <name> [--dry]
3231
3742
  migrate --list
3232
- \u041C\u0438\u0433\u0440\u0430\u0446\u0438\u0438: front|ui, form-aliases, form-tokens, size-sml, field-border, modal-create, legacy-hacks, socket-server
3743
+ \u041C\u0438\u0433\u0440\u0430\u0446\u0438\u0438: front|ui, form-aliases, form-tokens, components, size-sml, field-border, modal-create, legacy-hacks, socket-server
3233
3744
 
3234
3745
  audit [--fix] [--dry] [--dir=\u2026]
3235
3746
  \u0423\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0439 API + CSS-\u0442\u043E\u043A\u0435\u043D\u044B form (padding-\u0430\u043B\u0438\u0430\u0441\u044B, popup-shadow, border shorthand)
@@ -3273,6 +3784,7 @@ function showHelp() {
3273
3784
 
3274
3785
  \u041F\u0440\u0438\u043C\u0435\u0440\u044B:
3275
3786
  elcrm -v
3787
+ elcrm upd
3276
3788
  elcrm update
3277
3789
  elcrm update --dry
3278
3790
  elcrm update --fix --test
@@ -3311,6 +3823,9 @@ async function main() {
3311
3823
  console.log("parseArgs:", JSON.stringify(parsed, null, 2));
3312
3824
  }
3313
3825
  switch (parsed.command) {
3826
+ case "upd":
3827
+ await cmdUpd();
3828
+ break;
3314
3829
  case "update":
3315
3830
  await cmdUpdate(parsed);
3316
3831
  break;