@motion-proto/live-tokens 0.74.0 → 0.76.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.
Files changed (171) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
  2. package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
  3. package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
  4. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
  5. package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
  6. package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
  7. package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
  8. package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
  9. package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
  10. package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
  11. package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
  12. package/.claude/skills/live-tokens-create-theme/SKILL.md +52 -48
  13. package/.claude/skills/live-tokens-create-theme/references/design-directions.md +1 -1
  14. package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
  15. package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
  16. package/.claude/skills/live-tokens-set-colors/SKILL.md +47 -38
  17. package/.claude/skills/live-tokens-set-geometry/SKILL.md +58 -35
  18. package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +5 -3
  19. package/.claude/skills/live-tokens-set-type/SKILL.md +30 -30
  20. package/CHANGELOG.md +138 -0
  21. package/README.md +17 -7
  22. package/bin/check-component.mjs +91 -19
  23. package/bin/check-page.mjs +102 -21
  24. package/bin/cli.mjs +87 -113
  25. package/bin/contractRunner.mjs +945 -0
  26. package/bin/create.mjs +1 -1
  27. package/bin/lib/catalogue.mjs +37 -30
  28. package/bin/lib/findings.mjs +46 -15
  29. package/bin/lib/report.mjs +3 -3
  30. package/bin/lib/tokenVocabulary.mjs +4 -4
  31. package/bin/migrate-routes.mjs +5 -5
  32. package/bin/migrate.mjs +4 -4
  33. package/bin/save-theme.mjs +8 -9
  34. package/bin/set-colors.mjs +9 -11
  35. package/bin/set-geometry.mjs +7 -7
  36. package/bin/set-type.mjs +5 -7
  37. package/bin/setup-claude.mjs +110 -0
  38. package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
  39. package/dist-plugin/{chunk-7VRTBGJT.js → chunk-PDNL4NC5.js} +9 -2
  40. package/dist-plugin/{chunk-V3YF6CGT.js → chunk-SWXRVZKT.js} +43 -1
  41. package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.cts} +1 -0
  42. package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.ts} +1 -0
  43. package/dist-plugin/index.cjs +310 -147
  44. package/dist-plugin/index.d.cts +1 -1
  45. package/dist-plugin/index.d.ts +1 -1
  46. package/dist-plugin/index.js +218 -122
  47. package/dist-plugin/migrateData/index.cjs +66 -2
  48. package/dist-plugin/migrateData/index.d.cts +1 -1
  49. package/dist-plugin/migrateData/index.d.ts +1 -1
  50. package/dist-plugin/migrateData/index.js +3 -3
  51. package/dist-plugin/setColors/index.cjs +61 -4
  52. package/dist-plugin/setColors/index.d.cts +1 -1
  53. package/dist-plugin/setColors/index.d.ts +1 -1
  54. package/dist-plugin/setColors/index.js +5 -5
  55. package/dist-plugin/setGeometry/index.cjs +107 -44
  56. package/dist-plugin/setGeometry/index.d.cts +5 -5
  57. package/dist-plugin/setGeometry/index.d.ts +5 -5
  58. package/dist-plugin/setGeometry/index.js +51 -45
  59. package/dist-plugin/setType/index.cjs +15 -0
  60. package/dist-plugin/setType/index.d.cts +1 -1
  61. package/dist-plugin/setType/index.d.ts +1 -1
  62. package/dist-plugin/setType/index.js +1 -1
  63. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  64. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  65. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  66. package/package.json +35 -8
  67. package/src/app/site.css +19 -9
  68. package/src/editor/bootstrap.ts +2 -0
  69. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
  70. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  71. package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
  72. package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
  73. package/src/editor/component-editor/TabBarEditor.svelte +1 -1
  74. package/src/editor/component-editor/TableEditor.svelte +2 -2
  75. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
  76. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
  77. package/src/editor/core/components/adjustAliases.ts +59 -45
  78. package/src/editor/core/components/aliasKinds.ts +9 -5
  79. package/src/editor/core/preview/themePreview.ts +9 -2
  80. package/src/editor/core/sketch/sketchLayer.ts +22 -0
  81. package/src/editor/core/store/editorStore.ts +10 -1
  82. package/src/editor/core/themes/buildColors.ts +3 -3
  83. package/src/editor/core/themes/liveStateStream.ts +26 -0
  84. package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
  85. package/src/editor/core/themes/migrations/index.ts +2 -0
  86. package/src/editor/core/themes/themeDocumentSync.ts +22 -11
  87. package/src/editor/core/themes/themeService.ts +9 -2
  88. package/src/editor/pages/ComponentEditorPage.svelte +17 -1
  89. package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
  90. package/src/editor/skill-atlas/SkillAtlas.svelte +75 -573
  91. package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
  92. package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
  93. package/src/editor/skill-atlas/edges.ts +31 -0
  94. package/src/editor/skill-atlas/skillSources.generated.ts +20 -19
  95. package/src/editor/skill-atlas/skillTrees.ts +19 -3840
  96. package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
  97. package/src/editor/skill-atlas/trees/create-component.ts +275 -0
  98. package/src/editor/skill-atlas/trees/create-page.ts +320 -0
  99. package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
  100. package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
  101. package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
  102. package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
  103. package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
  104. package/src/editor/skill-atlas/trees/set-type.ts +142 -0
  105. package/src/editor/skill-atlas/types.ts +3 -4
  106. package/src/editor/skill-atlas/wireLayout.ts +287 -0
  107. package/src/live-tokens/data/themes/autumn.json +15 -15
  108. package/src/live-tokens/data/themes/halloween.json +15 -15
  109. package/src/live-tokens/data/themes/midnight-study.json +15 -15
  110. package/src/live-tokens/data/themes/ocean.json +15 -15
  111. package/src/live-tokens/data/themes/royal-velvet.json +15 -15
  112. package/src/live-tokens/data/themes/sketchy.json +15 -15
  113. package/src/live-tokens/data/themes/spring-meadow.json +15 -15
  114. package/src/live-tokens/data/themes/sunset.json +15 -15
  115. package/src/system/components/Badge.svelte +7 -0
  116. package/src/system/components/Button.svelte +7 -0
  117. package/src/system/components/Callout.svelte +10 -6
  118. package/src/system/components/Card.svelte +23 -4
  119. package/src/system/components/CodeSnippet.svelte +4 -3
  120. package/src/system/components/CollapsibleSection.svelte +23 -8
  121. package/src/system/components/CornerBadge.svelte +6 -0
  122. package/src/system/components/Dialog.svelte +13 -6
  123. package/src/system/components/IconButton.svelte +9 -0
  124. package/src/system/components/Image.svelte +8 -0
  125. package/src/system/components/ImageLightbox.svelte +6 -0
  126. package/src/system/components/InlineEditActions.svelte +7 -0
  127. package/src/system/components/Input.svelte +7 -0
  128. package/src/system/components/MenuSelect.svelte +7 -0
  129. package/src/system/components/Notification.svelte +7 -0
  130. package/src/system/components/Panel.svelte +6 -0
  131. package/src/system/components/ProgressBar.svelte +5 -0
  132. package/src/system/components/RadioButton.svelte +11 -5
  133. package/src/system/components/SectionDivider.svelte +8 -0
  134. package/src/system/components/SegmentedControl.svelte +6 -0
  135. package/src/system/components/SideNavigation.svelte +6 -0
  136. package/src/system/components/Slider.svelte +7 -4
  137. package/src/system/components/TabBar.svelte +15 -9
  138. package/src/system/components/Table.svelte +8 -3
  139. package/src/system/components/Toggle.svelte +4 -4
  140. package/src/system/components/Tooltip.svelte +6 -0
  141. package/src/testing-js/chunk-AO7EZHYV.js +776 -0
  142. package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
  143. package/src/testing-js/chunk-FAFOAWYL.js +39 -0
  144. package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
  145. package/src/testing-js/chunk-L73N4NSO.js +23 -0
  146. package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
  147. package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
  148. package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
  149. package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
  150. package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
  151. package/src/testing-js/component-alias.contract.js +81 -0
  152. package/src/testing-js/component-alias.contract.js.map +1 -0
  153. package/src/testing-js/component-editor.contract.js +62 -0
  154. package/src/testing-js/component-editor.contract.js.map +1 -0
  155. package/src/testing-js/component-render.contract.js +568 -0
  156. package/src/testing-js/component-render.contract.js.map +1 -0
  157. package/src/testing-js/index.d.ts +293 -0
  158. package/src/testing-js/index.js +222 -0
  159. package/src/testing-js/index.js.map +1 -0
  160. package/src/testing-js/registry.contract.js +39 -0
  161. package/src/testing-js/registry.contract.js.map +1 -0
  162. package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
  163. package/src/testing-js/vitest.d.ts +3 -0
  164. package/src/testing-js/vitest.js +13 -0
  165. package/src/testing-js/vitest.js.map +1 -0
  166. package/template/README.md +13 -0
  167. package/template/_gitignore +6 -0
  168. package/template/package.json +3 -1
  169. package/template/src/pages/Home.svelte +4 -18
  170. package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
  171. package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
@@ -38,8 +38,8 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // vite-plugin/themeFileApi.ts
41
- var import_fs4 = __toESM(require("fs"), 1);
42
- var import_path4 = __toESM(require("path"), 1);
41
+ var import_fs5 = __toESM(require("fs"), 1);
42
+ var import_path5 = __toESM(require("path"), 1);
43
43
 
44
44
  // src/editor/core/themes/parsers/globalRootBlock.ts
45
45
  function extractGlobalRootBody(source) {
@@ -1664,6 +1664,47 @@ var colorsAndTypeMigration_2026_09_03_dropLegacyComponentKeys = {
1664
1664
  }
1665
1665
  };
1666
1666
 
1667
+ // src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts
1668
+ var RENAMES2 = {
1669
+ tabbar: Object.fromEntries(
1670
+ ["default", "hover", "active", "disabled"].map((s) => [
1671
+ `--tabbar-${s}-indicator-border-width`,
1672
+ `--tabbar-${s}-indicator-width`
1673
+ ])
1674
+ ),
1675
+ collapsiblesection: Object.fromEntries(
1676
+ ["default", "hover"].flatMap((s) => [
1677
+ [`--collapsiblesection-divider-${s}-border`, `--collapsiblesection-divider-${s}-hairline-color`],
1678
+ [`--collapsiblesection-divider-${s}-border-width`, `--collapsiblesection-divider-${s}-hairline-thickness`]
1679
+ ])
1680
+ ),
1681
+ dialog: Object.fromEntries(
1682
+ ["header", "footer"].flatMap((part) => [
1683
+ [`--dialog-${part}-border`, `--dialog-${part}-divider`],
1684
+ [`--dialog-${part}-border-width`, `--dialog-${part}-divider-width`]
1685
+ ])
1686
+ ),
1687
+ table: {
1688
+ "--table-default-header-border": "--table-default-header-divider",
1689
+ "--table-default-header-border-width": "--table-default-header-divider-width"
1690
+ }
1691
+ };
1692
+ var componentMigration_2026_09_07_strokeRoleRenames = {
1693
+ id: "2026-09-07-stroke-role-renames",
1694
+ fromVersion: 26,
1695
+ toVersion: 27,
1696
+ appliesTo: "component-config",
1697
+ apply(rawVars, meta) {
1698
+ const renames = meta.component ? RENAMES2[meta.component] : void 0;
1699
+ if (!renames) return { ...rawVars };
1700
+ const out = {};
1701
+ for (const [key, value] of Object.entries(rawVars)) {
1702
+ out[renames[key] ?? key] = value;
1703
+ }
1704
+ return out;
1705
+ }
1706
+ };
1707
+
1667
1708
  // src/editor/core/themes/migrations/index.ts
1668
1709
  var MIGRATIONS = [
1669
1710
  colorsAndTypeMigration_2026_04_24_legacyKeysAndBgToCanvas,
@@ -1699,7 +1740,8 @@ var MIGRATIONS = [
1699
1740
  componentMigration_2026_09_01_tabbarActiveTint,
1700
1741
  componentMigration_2026_09_01_gateSuffixEnabled,
1701
1742
  componentMigration_2026_09_02_sectiondividerDropTitleOutline,
1702
- colorsAndTypeMigration_2026_09_03_dropLegacyComponentKeys
1743
+ colorsAndTypeMigration_2026_09_03_dropLegacyComponentKeys,
1744
+ componentMigration_2026_09_07_strokeRoleRenames
1703
1745
  ];
1704
1746
  function countFor(kind) {
1705
1747
  return MIGRATIONS.filter((m) => m.appliesTo === kind).length;
@@ -1815,9 +1857,11 @@ function versionedFileResourceServer(opts) {
1815
1857
  function ensureMeta() {
1816
1858
  if (!import_fs.default.existsSync(activePath)) {
1817
1859
  import_fs.default.writeFileSync(activePath, JSON.stringify({ activeFile: defaultName }));
1860
+ opts.onWrite?.(activePath);
1818
1861
  }
1819
1862
  if (!import_fs.default.existsSync(productionPath)) {
1820
1863
  import_fs.default.writeFileSync(productionPath, JSON.stringify({ productionFile: defaultName }));
1864
+ opts.onWrite?.(productionPath);
1821
1865
  }
1822
1866
  }
1823
1867
  function filePath(name) {
@@ -1882,9 +1926,11 @@ function versionedFileResourceServer(opts) {
1882
1926
  }
1883
1927
  function setActiveName(name) {
1884
1928
  import_fs.default.writeFileSync(activePath, JSON.stringify({ activeFile: name }));
1929
+ opts.onWrite?.(activePath);
1885
1930
  }
1886
1931
  function setProductionName(name) {
1887
1932
  import_fs.default.writeFileSync(productionPath, JSON.stringify({ productionFile: name }));
1933
+ opts.onWrite?.(productionPath);
1888
1934
  }
1889
1935
  function hasWorking() {
1890
1936
  return import_fs.default.existsSync(workingPath);
@@ -1900,9 +1946,12 @@ function versionedFileResourceServer(opts) {
1900
1946
  function writeWorking(data) {
1901
1947
  ensureDir();
1902
1948
  import_fs.default.writeFileSync(workingPath, JSON.stringify(data, null, 2));
1949
+ opts.onWrite?.(workingPath);
1903
1950
  }
1904
1951
  function clearWorking() {
1905
- if (import_fs.default.existsSync(workingPath)) import_fs.default.unlinkSync(workingPath);
1952
+ if (!import_fs.default.existsSync(workingPath)) return;
1953
+ import_fs.default.unlinkSync(workingPath);
1954
+ opts.onWrite?.(workingPath);
1906
1955
  }
1907
1956
  return {
1908
1957
  dir,
@@ -1955,6 +2004,67 @@ async function dispatch(req, res, routes) {
1955
2004
  return false;
1956
2005
  }
1957
2006
 
2007
+ // vite-plugin/files/dataTreeWatch.ts
2008
+ var import_fs2 = __toESM(require("fs"), 1);
2009
+ var import_path2 = __toESM(require("path"), 1);
2010
+ function fingerprint(file) {
2011
+ try {
2012
+ return import_fs2.default.readFileSync(file, "utf-8");
2013
+ } catch {
2014
+ return null;
2015
+ }
2016
+ }
2017
+ function dataTreeWatch(opts) {
2018
+ const debounceMs = opts.debounceMs ?? 100;
2019
+ const ownWrites = /* @__PURE__ */ new Map();
2020
+ const listeners = /* @__PURE__ */ new Set();
2021
+ let watchers = [];
2022
+ let timer = null;
2023
+ function noteOwnWrite(file) {
2024
+ const resolved = import_path2.default.resolve(file);
2025
+ ownWrites.set(resolved, fingerprint(resolved));
2026
+ }
2027
+ function onEvent(dir, filename) {
2028
+ if (!filename) return;
2029
+ const file = import_path2.default.resolve(dir, filename.toString());
2030
+ if (!opts.isLive(file)) return;
2031
+ if (ownWrites.has(file) && ownWrites.get(file) === fingerprint(file)) return;
2032
+ ownWrites.delete(file);
2033
+ if (timer) clearTimeout(timer);
2034
+ timer = setTimeout(() => {
2035
+ timer = null;
2036
+ for (const listener of listeners) listener();
2037
+ }, debounceMs);
2038
+ }
2039
+ function start() {
2040
+ for (const dir of opts.dirs) {
2041
+ if (!import_fs2.default.existsSync(dir)) continue;
2042
+ const watcher = import_fs2.default.watch(
2043
+ dir,
2044
+ { recursive: true, persistent: false },
2045
+ (_event, filename) => onEvent(dir, filename)
2046
+ );
2047
+ watcher.on("error", () => watcher.close());
2048
+ watchers.push(watcher);
2049
+ }
2050
+ }
2051
+ function stop() {
2052
+ for (const watcher of watchers) watcher.close();
2053
+ watchers = [];
2054
+ if (timer) clearTimeout(timer);
2055
+ timer = null;
2056
+ }
2057
+ function subscribe(listener) {
2058
+ if (listeners.size === 0) start();
2059
+ listeners.add(listener);
2060
+ return () => {
2061
+ listeners.delete(listener);
2062
+ if (listeners.size === 0) stop();
2063
+ };
2064
+ }
2065
+ return { noteOwnWrite, subscribe };
2066
+ }
2067
+
1958
2068
  // src/editor/core/themes/migrateComponentConfig.ts
1959
2069
  function migrateComponentConfig(component, aliasesIn, rawConfig, fileVersion) {
1960
2070
  const stringPart = {};
@@ -2671,9 +2781,19 @@ function nextAvailableName(exists, baseName, maxAttempts = 1e3) {
2671
2781
  }
2672
2782
 
2673
2783
  // vite-plugin/files/dataPaths.ts
2674
- var import_fs2 = __toESM(require("fs"), 1);
2675
- var import_path2 = __toESM(require("path"), 1);
2784
+ var import_fs3 = __toESM(require("fs"), 1);
2785
+ var import_path3 = __toESM(require("path"), 1);
2676
2786
  var DEFAULT_DATA_DIR = "src/live-tokens/data";
2787
+ var TEST_DATA_DIR_ENV = "LIVE_TOKENS_TEST_DATA_DIR";
2788
+ function testDataDir() {
2789
+ const raw = process.env[TEST_DATA_DIR_ENV];
2790
+ return raw && raw.trim() !== "" ? import_path3.default.resolve(raw.trim()) : void 0;
2791
+ }
2792
+ var TEST_PACKAGE_DATA_DIR_ENV = "LIVE_TOKENS_TEST_PACKAGE_DATA_DIR";
2793
+ function testPackageDataDir() {
2794
+ const raw = process.env[TEST_PACKAGE_DATA_DIR_ENV];
2795
+ return raw && raw.trim() !== "" ? import_path3.default.resolve(raw.trim()) : void 0;
2796
+ }
2677
2797
  var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
2678
2798
  "dataDir",
2679
2799
  "colorsAndTypeDir",
@@ -2688,9 +2808,9 @@ var cached = null;
2688
2808
  function readLiveTokensConfig() {
2689
2809
  if (cached) return cached;
2690
2810
  try {
2691
- const configPath = import_path2.default.resolve("live-tokens.config.json");
2692
- if (!import_fs2.default.existsSync(configPath)) return cached = {};
2693
- const parsed = JSON.parse(import_fs2.default.readFileSync(configPath, "utf-8"));
2811
+ const configPath = import_path3.default.resolve("live-tokens.config.json");
2812
+ if (!import_fs3.default.existsSync(configPath)) return cached = {};
2813
+ const parsed = JSON.parse(import_fs3.default.readFileSync(configPath, "utf-8"));
2694
2814
  if (!parsed || typeof parsed !== "object") return cached = {};
2695
2815
  const unknown = Object.keys(parsed).filter(
2696
2816
  (k) => k !== "$schema" && !KNOWN_CONFIG_KEYS.has(k)
@@ -2707,71 +2827,81 @@ function readLiveTokensConfig() {
2707
2827
  }
2708
2828
  }
2709
2829
  function resolveDataDirs(opts = {}) {
2830
+ const isolated = testDataDir();
2831
+ if (isolated) {
2832
+ return {
2833
+ dataDir: isolated,
2834
+ colorsAndTypeDir: import_path3.default.join(isolated, "colors-and-type"),
2835
+ componentConfigsDir: import_path3.default.join(isolated, "component-configs"),
2836
+ themesDir: import_path3.default.join(isolated, "themes"),
2837
+ sketchStylesDir: import_path3.default.join(isolated, "sketch-styles")
2838
+ };
2839
+ }
2710
2840
  const fileConfig = readLiveTokensConfig();
2711
2841
  const dataDirRaw = opts.dataDir ?? fileConfig.dataDir ?? DEFAULT_DATA_DIR;
2712
- const dataDir = import_path2.default.resolve(dataDirRaw);
2713
- const sub = (name) => import_path2.default.resolve(dataDir, name);
2842
+ const dataDir = import_path3.default.resolve(dataDirRaw);
2843
+ const sub = (name) => import_path3.default.resolve(dataDir, name);
2714
2844
  return {
2715
2845
  dataDir,
2716
- colorsAndTypeDir: opts.colorsAndTypeDir ? import_path2.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path2.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
2717
- componentConfigsDir: opts.componentConfigsDir ? import_path2.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path2.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
2718
- themesDir: opts.themesDir ? import_path2.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path2.default.resolve(fileConfig.themesDir) : sub("themes"),
2846
+ colorsAndTypeDir: opts.colorsAndTypeDir ? import_path3.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path3.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
2847
+ componentConfigsDir: opts.componentConfigsDir ? import_path3.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path3.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
2848
+ themesDir: opts.themesDir ? import_path3.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path3.default.resolve(fileConfig.themesDir) : sub("themes"),
2719
2849
  sketchStylesDir: sub("sketch-styles"),
2720
- legacyManifestsDir: fileConfig.manifestsDir ? import_path2.default.resolve(fileConfig.manifestsDir) : void 0
2850
+ legacyManifestsDir: fileConfig.manifestsDir ? import_path3.default.resolve(fileConfig.manifestsDir) : void 0
2721
2851
  };
2722
2852
  }
2723
2853
 
2724
2854
  // vite-plugin/files/legacyLayout.ts
2725
- var import_fs3 = __toESM(require("fs"), 1);
2726
- var import_path3 = __toESM(require("path"), 1);
2855
+ var import_fs4 = __toESM(require("fs"), 1);
2856
+ var import_path4 = __toESM(require("path"), 1);
2727
2857
  function jsonFiles(dir) {
2728
- if (!import_fs3.default.existsSync(dir)) return [];
2858
+ if (!import_fs4.default.existsSync(dir)) return [];
2729
2859
  try {
2730
- return import_fs3.default.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => import_path3.default.join(dir, f));
2860
+ return import_fs4.default.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => import_path4.default.join(dir, f));
2731
2861
  } catch {
2732
2862
  return [];
2733
2863
  }
2734
2864
  }
2735
2865
  function isDirectory(dir) {
2736
2866
  try {
2737
- return import_fs3.default.statSync(dir).isDirectory();
2867
+ return import_fs4.default.statSync(dir).isDirectory();
2738
2868
  } catch {
2739
2869
  return false;
2740
2870
  }
2741
2871
  }
2742
2872
  function parseJsonFile(file) {
2743
2873
  try {
2744
- return JSON.parse(import_fs3.default.readFileSync(file, "utf-8"));
2874
+ return JSON.parse(import_fs4.default.readFileSync(file, "utf-8"));
2745
2875
  } catch {
2746
2876
  return null;
2747
2877
  }
2748
2878
  }
2749
2879
  function holdsATheme(themesDir) {
2750
2880
  return jsonFiles(themesDir).some((file) => {
2751
- if (import_path3.default.basename(file).startsWith("_")) return false;
2881
+ if (import_path4.default.basename(file).startsWith("_")) return false;
2752
2882
  const raw = parseJsonFile(file);
2753
2883
  if (!raw || typeof raw !== "object") return false;
2754
2884
  return "colorsAndType" in raw || "theme" in raw;
2755
2885
  });
2756
2886
  }
2757
2887
  function detectLegacyLayout(input) {
2758
- const manifestsDir = input.configuredManifestsDir ?? import_path3.default.join(input.dataDir, "manifests");
2888
+ const manifestsDir = input.configuredManifestsDir ?? import_path4.default.join(input.dataDir, "manifests");
2759
2889
  const themesHoldAThemeFile = holdsATheme(input.themesDir);
2760
2890
  if (isDirectory(manifestsDir) && !themesHoldAThemeFile) {
2761
2891
  return { manifestsDir, evidence: `${manifestsDir} is the pre-0.48 whole-theme directory` };
2762
2892
  }
2763
2893
  if (jsonFiles(input.colorsAndTypeDir).length > 0) return null;
2764
2894
  for (const file of jsonFiles(input.themesDir)) {
2765
- if (import_path3.default.basename(file).startsWith("_")) continue;
2895
+ if (import_path4.default.basename(file).startsWith("_")) continue;
2766
2896
  if (isColorsAndTypeShaped(parseJsonFile(file))) {
2767
2897
  return { manifestsDir, evidence: `${file} is a colors-and-type file, not a theme` };
2768
2898
  }
2769
2899
  }
2770
- const pointer = ["_active.json", "_production.json"].map((name) => import_path3.default.join(input.themesDir, name)).find((p) => import_fs3.default.existsSync(p));
2771
- if (pointer && !themesHoldAThemeFile && !import_fs3.default.existsSync(input.colorsAndTypeDir)) {
2900
+ const pointer = ["_active.json", "_production.json"].map((name) => import_path4.default.join(input.themesDir, name)).find((p) => import_fs4.default.existsSync(p));
2901
+ if (pointer && !themesHoldAThemeFile && !import_fs4.default.existsSync(input.colorsAndTypeDir)) {
2772
2902
  return {
2773
2903
  manifestsDir,
2774
- evidence: `${pointer} points at colors and type, and there is no ${import_path3.default.basename(input.colorsAndTypeDir)} directory`
2904
+ evidence: `${pointer} points at colors and type, and there is no ${import_path4.default.basename(input.colorsAndTypeDir)} directory`
2775
2905
  };
2776
2906
  }
2777
2907
  return null;
@@ -3027,7 +3157,7 @@ var tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions = {
3027
3157
  };
3028
3158
 
3029
3159
  // vite-plugin/tokensCssMigrations/migrations/2026-07-20-line-height-rename.ts
3030
- var RENAMES2 = [
3160
+ var RENAMES3 = [
3031
3161
  ["--line-height-xs", "--line-height-none"],
3032
3162
  ["--line-height-sm", "--line-height-tighter"],
3033
3163
  ["--line-height-md", "--line-height-normal"],
@@ -3047,7 +3177,7 @@ var tokensCssMigration_2026_07_20_lineHeightRename = {
3047
3177
  description: "Reshape --line-height-{xs..xl} to leading vocabulary (none/tightest/tighter/tight/normal/relaxed); retire the 2.0 slot",
3048
3178
  apply(css) {
3049
3179
  let out = css;
3050
- for (const [oldName, newName] of RENAMES2) out = renameToken2(out, oldName, newName);
3180
+ for (const [oldName, newName] of RENAMES3) out = renameToken2(out, oldName, newName);
3051
3181
  out = removeToken(out, "--line-height-xl");
3052
3182
  out = ensureScale(out, {
3053
3183
  anchorPrefixes: ["--line-height-", "--font-size-", "--font-weight-", "--font-"],
@@ -3280,7 +3410,7 @@ var tokensCssMigration_2026_08_27_editorialLargeSteps = {
3280
3410
  };
3281
3411
 
3282
3412
  // vite-plugin/tokensCssMigrations/migrations/2026-09-01-scrim-rename.ts
3283
- var RENAMES3 = [
3413
+ var RENAMES4 = [
3284
3414
  ["--overlay-low", "--scrim-low"],
3285
3415
  ["--overlay-high", "--scrim-high"],
3286
3416
  ["--overlay", "--scrim"]
@@ -3291,7 +3421,7 @@ var tokensCssMigration_2026_09_01_scrimRename = {
3291
3421
  description: "Rename --overlay-{low,base,high} to --scrim-*; a scrim dims what is behind it",
3292
3422
  apply(css) {
3293
3423
  let out = css;
3294
- for (const [oldName, newName] of RENAMES3) out = renameToken2(out, oldName, newName);
3424
+ for (const [oldName, newName] of RENAMES4) out = renameToken2(out, oldName, newName);
3295
3425
  return out;
3296
3426
  }
3297
3427
  };
@@ -3382,14 +3512,14 @@ var import_node_url = require("url");
3382
3512
  var import_meta = {};
3383
3513
  var PKG_VERSION = (() => {
3384
3514
  try {
3385
- let dir = import_path4.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
3515
+ let dir = import_path5.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
3386
3516
  for (let i = 0; i < 4; i++) {
3387
- const p = import_path4.default.join(dir, "package.json");
3388
- if (import_fs4.default.existsSync(p)) {
3389
- const json = JSON.parse(import_fs4.default.readFileSync(p, "utf-8"));
3517
+ const p = import_path5.default.join(dir, "package.json");
3518
+ if (import_fs5.default.existsSync(p)) {
3519
+ const json = JSON.parse(import_fs5.default.readFileSync(p, "utf-8"));
3390
3520
  if (json?.name === "@motion-proto/live-tokens") return json.version ?? "";
3391
3521
  }
3392
- const up = import_path4.default.dirname(dir);
3522
+ const up = import_path5.default.dirname(dir);
3393
3523
  if (up === dir) break;
3394
3524
  dir = up;
3395
3525
  }
@@ -3433,56 +3563,64 @@ function themeFileApi(opts) {
3433
3563
  const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
3434
3564
  const THEMES_DIR = dataDirs.themesDir;
3435
3565
  const SKETCH_STYLES_DIR = dataDirs.sketchStylesDir;
3436
- const CSS_PATH = import_path4.default.resolve(opts.tokensCssPath);
3437
- const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? import_path4.default.resolve(opts.tokensGeneratedCssPath) : import_path4.default.join(dataDirs.dataDir, "tokens.generated.css");
3438
- const FONTS_CSS_PATH = opts.fontsCssPath ? import_path4.default.resolve(opts.fontsCssPath) : import_path4.default.join(import_path4.default.dirname(CSS_PATH), "fonts.css");
3566
+ const CSS_PATH = import_path5.default.resolve(opts.tokensCssPath);
3567
+ const ISOLATED_DATA_DIR = testDataDir();
3568
+ const GENERATED_CSS_PATH = ISOLATED_DATA_DIR ? import_path5.default.join(ISOLATED_DATA_DIR, "tokens.generated.css") : opts.tokensGeneratedCssPath ? import_path5.default.resolve(opts.tokensGeneratedCssPath) : import_path5.default.join(dataDirs.dataDir, "tokens.generated.css");
3569
+ const FONTS_CSS_PATH = ISOLATED_DATA_DIR ? import_path5.default.join(ISOLATED_DATA_DIR, "fonts.css") : opts.fontsCssPath ? import_path5.default.resolve(opts.fontsCssPath) : import_path5.default.join(import_path5.default.dirname(CSS_PATH), "fonts.css");
3439
3570
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
3440
- const consumerComponentDirs = opts.componentsSrcDir ? [import_path4.default.resolve(opts.componentsSrcDir)] : [import_path4.default.resolve("src/components"), import_path4.default.resolve("src/system/components")];
3441
- const packageComponentsDir = import_path4.default.resolve(
3442
- import_path4.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
3571
+ const consumerComponentDirs = opts.componentsSrcDir ? [import_path5.default.resolve(opts.componentsSrcDir)] : [import_path5.default.resolve("src/components"), import_path5.default.resolve("src/system/components")];
3572
+ const packageComponentsDir = import_path5.default.resolve(
3573
+ import_path5.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
3443
3574
  "..",
3444
3575
  "src",
3445
3576
  "system",
3446
3577
  "components"
3447
3578
  );
3448
- const packageDataDir = import_path4.default.resolve(
3449
- import_path4.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
3579
+ const packageDataDir = testPackageDataDir() ?? import_path5.default.resolve(
3580
+ import_path5.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
3450
3581
  "..",
3451
3582
  "src",
3452
3583
  "live-tokens",
3453
3584
  "data"
3454
3585
  );
3455
- const packageColorsAndTypeDir = import_path4.default.join(packageDataDir, "colors-and-type");
3456
- const packageThemesDir = import_path4.default.join(packageDataDir, "themes");
3457
- const packageComponentConfigsDir = import_path4.default.join(packageDataDir, "component-configs");
3458
- const packageSketchStylesDir = import_path4.default.join(packageDataDir, "sketch-styles");
3586
+ const packageColorsAndTypeDir = import_path5.default.join(packageDataDir, "colors-and-type");
3587
+ const packageThemesDir = import_path5.default.join(packageDataDir, "themes");
3588
+ const packageComponentConfigsDir = import_path5.default.join(packageDataDir, "component-configs");
3589
+ const packageSketchStylesDir = import_path5.default.join(packageDataDir, "sketch-styles");
3459
3590
  function shippedNames(dataDir, subdir) {
3460
3591
  try {
3461
- const pkgRoot = import_path4.default.resolve(dataDir, "..", "..", "..");
3462
- const pkg = JSON.parse(import_fs4.default.readFileSync(import_path4.default.join(pkgRoot, "package.json"), "utf-8"));
3592
+ const pkgRoot = import_path5.default.resolve(dataDir, "..", "..", "..");
3593
+ const pkg = JSON.parse(import_fs5.default.readFileSync(import_path5.default.join(pkgRoot, "package.json"), "utf-8"));
3463
3594
  const files = Array.isArray(pkg.files) ? pkg.files : [];
3464
3595
  const owned = new RegExp(`^src/live-tokens/data/${subdir}/[^/]+\\.json$`);
3465
- return files.filter((f) => owned.test(f)).map((f) => import_path4.default.basename(f, ".json"));
3596
+ return files.filter((f) => owned.test(f)).map((f) => import_path5.default.basename(f, ".json"));
3466
3597
  } catch {
3467
3598
  return [];
3468
3599
  }
3469
3600
  }
3470
3601
  const COMPONENTS_SCAN_DIRS = [...consumerComponentDirs];
3471
- if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && import_fs4.default.existsSync(packageComponentsDir)) {
3602
+ if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && import_fs5.default.existsSync(packageComponentsDir)) {
3472
3603
  COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
3473
3604
  }
3605
+ const isLiveStateFile = (file) => file === import_path5.default.join(THEMES_DIR, "_active.json") || import_path5.default.basename(file) === "_working.json" && (file.startsWith(COLORS_AND_TYPE_DIR + import_path5.default.sep) || file.startsWith(COMPONENT_CONFIGS_DIR + import_path5.default.sep));
3606
+ const liveWatch = dataTreeWatch({
3607
+ dirs: [COLORS_AND_TYPE_DIR, COMPONENT_CONFIGS_DIR, THEMES_DIR],
3608
+ isLive: isLiveStateFile
3609
+ });
3474
3610
  const colorsAndTypeResource = versionedFileResourceServer({
3475
3611
  dir: COLORS_AND_TYPE_DIR,
3476
3612
  packageDir: packageColorsAndTypeDir,
3477
- packageOwnedNames: shippedNames(packageDataDir, "colors-and-type")
3613
+ packageOwnedNames: shippedNames(packageDataDir, "colors-and-type"),
3614
+ onWrite: liveWatch.noteOwnWrite
3478
3615
  });
3479
3616
  const componentResourceCache = /* @__PURE__ */ new Map();
3480
3617
  function componentResource(comp) {
3481
3618
  let r = componentResourceCache.get(comp);
3482
3619
  if (!r) {
3483
3620
  r = versionedFileResourceServer({
3484
- dir: import_path4.default.join(COMPONENT_CONFIGS_DIR, comp),
3485
- packageDir: import_path4.default.join(packageComponentConfigsDir, comp)
3621
+ dir: import_path5.default.join(COMPONENT_CONFIGS_DIR, comp),
3622
+ packageDir: import_path5.default.join(packageComponentConfigsDir, comp),
3623
+ onWrite: liveWatch.noteOwnWrite
3486
3624
  });
3487
3625
  componentResourceCache.set(comp, r);
3488
3626
  }
@@ -3490,7 +3628,8 @@ function themeFileApi(opts) {
3490
3628
  }
3491
3629
  const themesResource = versionedFileResourceServer({
3492
3630
  dir: THEMES_DIR,
3493
- packageDir: packageThemesDir
3631
+ packageDir: packageThemesDir,
3632
+ onWrite: liveWatch.noteOwnWrite
3494
3633
  });
3495
3634
  const sketchStylesResource = versionedFileResourceServer({
3496
3635
  dir: SKETCH_STYLES_DIR,
@@ -3571,7 +3710,7 @@ function themeFileApi(opts) {
3571
3710
  const productionThemeName = themesResource.getProductionName();
3572
3711
  const productionTheme = readTheme(productionThemeName)?.theme ?? null;
3573
3712
  if (themesResource.existingPath(productionThemeName) !== null && !productionTheme?.colorsAndType) {
3574
- const tail = `${import_path4.default.basename(GENERATED_CSS_PATH)} was left as it was.`;
3713
+ const tail = `${import_path5.default.basename(GENERATED_CSS_PATH)} was left as it was.`;
3575
3714
  throw new Error(
3576
3715
  unreadableThemeReason(productionThemeName) === "colors-and-type" ? `[live-tokens] ${notAThemeError(productionThemeName)} ${tail}` : `[live-tokens] Production theme "${productionThemeName}" is unreadable, so ${tail} Repair the theme file or adopt another theme.`
3577
3716
  );
@@ -3609,7 +3748,7 @@ function themeFileApi(opts) {
3609
3748
  }
3610
3749
  }
3611
3750
  let componentOverrideCount = 0;
3612
- if (import_fs4.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3751
+ if (import_fs5.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3613
3752
  const blocks = [];
3614
3753
  for (const comp of listComponentNames()) {
3615
3754
  const prodCfg = productionTheme?.componentConfigs[comp];
@@ -3642,12 +3781,12 @@ function themeFileApi(opts) {
3642
3781
  lines.push("");
3643
3782
  }
3644
3783
  }
3645
- if (!import_fs4.default.existsSync(import_path4.default.dirname(GENERATED_CSS_PATH))) {
3646
- import_fs4.default.mkdirSync(import_path4.default.dirname(GENERATED_CSS_PATH), { recursive: true });
3784
+ if (!import_fs5.default.existsSync(import_path5.default.dirname(GENERATED_CSS_PATH))) {
3785
+ import_fs5.default.mkdirSync(import_path5.default.dirname(GENERATED_CSS_PATH), { recursive: true });
3647
3786
  }
3648
- import_fs4.default.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
3787
+ import_fs5.default.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
3649
3788
  console.log(
3650
- `[regenerateTokensCss] Wrote ${import_path4.default.basename(GENERATED_CSS_PATH)} (${colorsAndTypeVarCount} theme vars, ${componentOverrideCount} component overrides)`
3789
+ `[regenerateTokensCss] Wrote ${import_path5.default.basename(GENERATED_CSS_PATH)} (${colorsAndTypeVarCount} theme vars, ${componentOverrideCount} component overrides)`
3651
3790
  );
3652
3791
  }
3653
3792
  function syncFontsToCss(colorsAndTypeData) {
@@ -3675,18 +3814,18 @@ function themeFileApi(opts) {
3675
3814
  lines.push("");
3676
3815
  }
3677
3816
  const content = lines.join("\n");
3678
- if (!import_fs4.default.existsSync(import_path4.default.dirname(FONTS_CSS_PATH))) {
3679
- import_fs4.default.mkdirSync(import_path4.default.dirname(FONTS_CSS_PATH), { recursive: true });
3817
+ if (!import_fs5.default.existsSync(import_path5.default.dirname(FONTS_CSS_PATH))) {
3818
+ import_fs5.default.mkdirSync(import_path5.default.dirname(FONTS_CSS_PATH), { recursive: true });
3680
3819
  }
3681
- import_fs4.default.writeFileSync(FONTS_CSS_PATH, content);
3682
- console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${import_path4.default.basename(FONTS_CSS_PATH)}`);
3820
+ import_fs5.default.writeFileSync(FONTS_CSS_PATH, content);
3821
+ console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${import_path5.default.basename(FONTS_CSS_PATH)}`);
3683
3822
  }
3684
3823
  function componentNameFromFile(filePath) {
3685
- return import_path4.default.basename(filePath, ".svelte").toLowerCase();
3824
+ return import_path5.default.basename(filePath, ".svelte").toLowerCase();
3686
3825
  }
3687
3826
  function isThemeAwareComponent(filePath) {
3688
3827
  try {
3689
- const source = import_fs4.default.readFileSync(filePath, "utf-8");
3828
+ const source = import_fs5.default.readFileSync(filePath, "utf-8");
3690
3829
  return /:global\(:root\)\s*\{/.test(source);
3691
3830
  } catch {
3692
3831
  return false;
@@ -3695,10 +3834,10 @@ function themeFileApi(opts) {
3695
3834
  function listComponentSourcePaths() {
3696
3835
  const byName = /* @__PURE__ */ new Map();
3697
3836
  for (const dir of COMPONENTS_SCAN_DIRS) {
3698
- if (!import_fs4.default.existsSync(dir)) continue;
3699
- for (const f of import_fs4.default.readdirSync(dir)) {
3837
+ if (!import_fs5.default.existsSync(dir)) continue;
3838
+ for (const f of import_fs5.default.readdirSync(dir)) {
3700
3839
  if (!f.endsWith(".svelte")) continue;
3701
- const full = import_path4.default.join(dir, f);
3840
+ const full = import_path5.default.join(dir, f);
3702
3841
  if (!isThemeAwareComponent(full)) continue;
3703
3842
  const name = componentNameFromFile(f);
3704
3843
  if (!byName.has(name)) byName.set(name, full);
@@ -3712,18 +3851,18 @@ function themeFileApi(opts) {
3712
3851
  function warnOnTokenDrift(log) {
3713
3852
  let tokensCss = "";
3714
3853
  try {
3715
- tokensCss = import_fs4.default.readFileSync(CSS_PATH, "utf-8");
3854
+ tokensCss = import_fs5.default.readFileSync(CSS_PATH, "utf-8");
3716
3855
  } catch {
3717
3856
  return;
3718
3857
  }
3719
3858
  let generatedCss = "";
3720
3859
  try {
3721
- generatedCss = import_fs4.default.readFileSync(GENERATED_CSS_PATH, "utf-8");
3860
+ generatedCss = import_fs5.default.readFileSync(GENERATED_CSS_PATH, "utf-8");
3722
3861
  } catch {
3723
3862
  }
3724
3863
  const componentSources = listComponentSourcePaths().map((p) => ({
3725
3864
  name: componentNameFromFile(p),
3726
- source: import_fs4.default.readFileSync(p, "utf-8")
3865
+ source: import_fs5.default.readFileSync(p, "utf-8")
3727
3866
  }));
3728
3867
  const missing = validateTokensCss({ tokensCss, generatedCss, componentSources });
3729
3868
  if (missing.length === 0) return;
@@ -3731,7 +3870,7 @@ function themeFileApi(opts) {
3731
3870
  (m) => ` ${m.token} (referenced by ${m.referencedBy.join(", ")})`
3732
3871
  );
3733
3872
  log(
3734
- `[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${import_path4.default.relative(process.cwd(), CSS_PATH)}:
3873
+ `[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${import_path5.default.relative(process.cwd(), CSS_PATH)}:
3735
3874
  ${lines.join("\n")}
3736
3875
  These render as blank/empty editor slots. Run \`npx live-tokens migrate\` to reconcile.`
3737
3876
  );
@@ -3739,30 +3878,30 @@ ${lines.join("\n")}
3739
3878
  function autoMigrateAdditive(log) {
3740
3879
  let before = "";
3741
3880
  try {
3742
- before = import_fs4.default.readFileSync(CSS_PATH, "utf-8");
3881
+ before = import_fs5.default.readFileSync(CSS_PATH, "utf-8");
3743
3882
  } catch {
3744
3883
  return;
3745
3884
  }
3746
3885
  const { css, applied, changed } = runAdditiveTokensCssMigrations(before);
3747
3886
  if (!changed) return;
3748
- import_fs4.default.writeFileSync(CSS_PATH, css);
3887
+ import_fs5.default.writeFileSync(CSS_PATH, css);
3749
3888
  log(
3750
- `[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${import_path4.default.relative(process.cwd(), CSS_PATH)}: ${applied.join(", ")}. Review the diff in git.`
3889
+ `[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${import_path5.default.relative(process.cwd(), CSS_PATH)}: ${applied.join(", ")}. Review the diff in git.`
3751
3890
  );
3752
3891
  }
3753
3892
  function generateDefaultConfig(comp, sourcePath) {
3754
- if (!import_fs4.default.existsSync(sourcePath)) return;
3893
+ if (!import_fs5.default.existsSync(sourcePath)) return;
3755
3894
  const r = componentResource(comp);
3756
3895
  r.ensureDir();
3757
3896
  const defaultPath = r.filePath("default");
3758
- const sourceStat = import_fs4.default.statSync(sourcePath);
3897
+ const sourceStat = import_fs5.default.statSync(sourcePath);
3759
3898
  let createdAt = (/* @__PURE__ */ new Date()).toISOString();
3760
3899
  let existingUpdatedAt;
3761
3900
  let existingAliases;
3762
3901
  let existingSchemaVersion;
3763
- if (import_fs4.default.existsSync(defaultPath)) {
3902
+ if (import_fs5.default.existsSync(defaultPath)) {
3764
3903
  try {
3765
- const existing = JSON.parse(import_fs4.default.readFileSync(defaultPath, "utf-8"));
3904
+ const existing = JSON.parse(import_fs5.default.readFileSync(defaultPath, "utf-8"));
3766
3905
  if (existing.createdAt) createdAt = existing.createdAt;
3767
3906
  if (typeof existing.updatedAt === "string") existingUpdatedAt = existing.updatedAt;
3768
3907
  if (existing.aliases && typeof existing.aliases === "object") {
@@ -3771,13 +3910,13 @@ ${lines.join("\n")}
3771
3910
  if (typeof existing.schemaVersion === "number") existingSchemaVersion = existing.schemaVersion;
3772
3911
  } catch {
3773
3912
  }
3774
- const defaultStat = import_fs4.default.statSync(defaultPath);
3913
+ const defaultStat = import_fs5.default.statSync(defaultPath);
3775
3914
  if (defaultStat.mtimeMs >= sourceStat.mtimeMs && existingSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION) {
3776
3915
  return;
3777
3916
  }
3778
3917
  }
3779
3918
  const now = (/* @__PURE__ */ new Date()).toISOString();
3780
- const source = import_fs4.default.readFileSync(sourcePath, "utf-8");
3919
+ const source = import_fs5.default.readFileSync(sourcePath, "utf-8");
3781
3920
  const body = extractGlobalRootBody(source);
3782
3921
  const aliases = extractAliasDeclarations(body);
3783
3922
  const aliasesUnchanged = existingAliases !== void 0 && JSON.stringify(existingAliases) === JSON.stringify(aliases);
@@ -3792,14 +3931,14 @@ ${lines.join("\n")}
3792
3931
  };
3793
3932
  if (aliasesUnchanged && schemaStampCurrent && existingUpdatedAt) {
3794
3933
  const t = /* @__PURE__ */ new Date();
3795
- import_fs4.default.utimesSync(defaultPath, t, t);
3934
+ import_fs5.default.utimesSync(defaultPath, t, t);
3796
3935
  return;
3797
3936
  }
3798
- import_fs4.default.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
3937
+ import_fs5.default.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
3799
3938
  }
3800
3939
  function ensureComponentConfigsDir() {
3801
- if (!import_fs4.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3802
- import_fs4.default.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
3940
+ if (!import_fs5.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3941
+ import_fs5.default.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
3803
3942
  }
3804
3943
  for (const sourcePath of listComponentSourcePaths()) {
3805
3944
  const comp = componentNameFromFile(sourcePath);
@@ -3812,14 +3951,14 @@ ${lines.join("\n")}
3812
3951
  const legacy = [];
3813
3952
  const check = (dir) => {
3814
3953
  for (const name of ["_active.json", "_production.json"]) {
3815
- const p = import_path4.default.join(dir, name);
3816
- if (import_fs4.default.existsSync(p)) legacy.push(import_path4.default.relative(process.cwd(), p));
3954
+ const p = import_path5.default.join(dir, name);
3955
+ if (import_fs5.default.existsSync(p)) legacy.push(import_path5.default.relative(process.cwd(), p));
3817
3956
  }
3818
3957
  };
3819
3958
  check(COLORS_AND_TYPE_DIR);
3820
- if (import_fs4.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3821
- for (const entry of import_fs4.default.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
3822
- if (entry.isDirectory()) check(import_path4.default.join(COMPONENT_CONFIGS_DIR, entry.name));
3959
+ if (import_fs5.default.existsSync(COMPONENT_CONFIGS_DIR)) {
3960
+ for (const entry of import_fs5.default.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
3961
+ if (entry.isDirectory()) check(import_path5.default.join(COMPONENT_CONFIGS_DIR, entry.name));
3823
3962
  }
3824
3963
  }
3825
3964
  return legacy;
@@ -3827,19 +3966,19 @@ ${lines.join("\n")}
3827
3966
  function warnOnLegacyPointers(legacy, bakeHeld, warn) {
3828
3967
  if (legacy.length === 0) return;
3829
3968
  warn(
3830
- `[live-tokens] ${legacy.length} legacy pointer file(s) left from the pre-working-set data model, starting with ${legacy[0]}. They are no longer read. Run \`npx live-tokens migrate\` to heal the tree.` + (bakeHeld ? ` Until then this tree has named no production theme, so ${import_path4.default.basename(GENERATED_CSS_PATH)} is left exactly as it is rather than rebuilt from the default.` : "")
3969
+ `[live-tokens] ${legacy.length} legacy pointer file(s) left from the pre-working-set data model, starting with ${legacy[0]}. They are no longer read. Run \`npx live-tokens migrate\` to heal the tree.` + (bakeHeld ? ` Until then this tree has named no production theme, so ${import_path5.default.basename(GENERATED_CSS_PATH)} is left exactly as it is rather than rebuilt from the default.` : "")
3831
3970
  );
3832
3971
  }
3833
3972
  function warnOnLegacyLayout(evidence, warn) {
3834
3973
  warn(
3835
- `[live-tokens] This project still uses the data layout from 0.47 and earlier: ${evidence}. Since 0.48 the whole-theme theme files live in \`themes/\` and the colors and type live in \`colors-and-type/\`. Nothing in the data directory was written, the editor cannot save, and ${import_path4.default.basename(GENERATED_CSS_PATH)} is left exactly as it is. Run \`npx live-tokens migrate\` to move the directories and heal the tree, then restart the dev server.`
3974
+ `[live-tokens] This project still uses the data layout from 0.47 and earlier: ${evidence}. Since 0.48 the whole-theme theme files live in \`themes/\` and the colors and type live in \`colors-and-type/\`. Nothing in the data directory was written, the editor cannot save, and ${import_path5.default.basename(GENERATED_CSS_PATH)} is left exactly as it is. Run \`npx live-tokens migrate\` to move the directories and heal the tree, then restart the dev server.`
3836
3975
  );
3837
3976
  }
3838
3977
  function warnOnUnmigratedSketchStyles(warn) {
3839
- const legacyDir = import_path4.default.join(dataDirs.dataDir, "sketch-presets");
3840
- if (!import_fs4.default.existsSync(legacyDir)) return;
3978
+ const legacyDir = import_path5.default.join(dataDirs.dataDir, "sketch-presets");
3979
+ if (!import_fs5.default.existsSync(legacyDir)) return;
3841
3980
  warn(
3842
- `[live-tokens] Saved sketchstyles still live under the retired ${import_path4.default.basename(legacyDir)}/ directory name. Run \`npx live-tokens migrate\` to rename it to ${import_path4.default.basename(SKETCH_STYLES_DIR)}/; until then they will not show up in the Sketchstyle view.`
3981
+ `[live-tokens] Saved sketchstyles still live under the retired ${import_path5.default.basename(legacyDir)}/ directory name. Run \`npx live-tokens migrate\` to rename it to ${import_path5.default.basename(SKETCH_STYLES_DIR)}/; until then they will not show up in the Sketchstyle view.`
3843
3982
  );
3844
3983
  }
3845
3984
  const diskThemeResolvers = {
@@ -3863,7 +4002,7 @@ ${lines.join("\n")}
3863
4002
  const resolved = themesResource.existingPath(fileName);
3864
4003
  if (resolved === null) return "missing";
3865
4004
  try {
3866
- if (isColorsAndTypeShaped(JSON.parse(import_fs4.default.readFileSync(resolved, "utf-8")))) {
4005
+ if (isColorsAndTypeShaped(JSON.parse(import_fs5.default.readFileSync(resolved, "utf-8")))) {
3867
4006
  return "colors-and-type";
3868
4007
  }
3869
4008
  } catch {
@@ -3871,7 +4010,7 @@ ${lines.join("\n")}
3871
4010
  return "corrupt";
3872
4011
  }
3873
4012
  function notAThemeError(fileName) {
3874
- return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${import_path4.default.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme skill "create-theme".`;
4013
+ return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${import_path5.default.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme skill "create-theme".`;
3875
4014
  }
3876
4015
  function respondUnreadableTheme(res, fileName, missingError) {
3877
4016
  switch (unreadableThemeReason(fileName)) {
@@ -3890,18 +4029,18 @@ ${lines.join("\n")}
3890
4029
  }
3891
4030
  function writeTheme(fileName, theme) {
3892
4031
  themesResource.ensureDir();
3893
- import_fs4.default.writeFileSync(themesResource.filePath(fileName), JSON.stringify(theme, null, 2));
4032
+ import_fs5.default.writeFileSync(themesResource.filePath(fileName), JSON.stringify(theme, null, 2));
3894
4033
  }
3895
4034
  function migrateLocalThemes(warn) {
3896
- if (import_path4.default.resolve(THEMES_DIR) === import_path4.default.resolve(packageThemesDir)) return;
3897
- if (!import_fs4.default.existsSync(THEMES_DIR)) return;
3898
- for (const file of import_fs4.default.readdirSync(THEMES_DIR)) {
4035
+ if (import_path5.default.resolve(THEMES_DIR) === import_path5.default.resolve(packageThemesDir)) return;
4036
+ if (!import_fs5.default.existsSync(THEMES_DIR)) return;
4037
+ for (const file of import_fs5.default.readdirSync(THEMES_DIR)) {
3899
4038
  if (!file.endsWith(".json") || file.startsWith("_")) continue;
3900
4039
  const fileName = file.slice(0, -".json".length);
3901
4040
  if (fileName === "default") continue;
3902
4041
  let raw;
3903
4042
  try {
3904
- raw = JSON.parse(import_fs4.default.readFileSync(import_path4.default.join(THEMES_DIR, file), "utf-8"));
4043
+ raw = JSON.parse(import_fs5.default.readFileSync(import_path5.default.join(THEMES_DIR, file), "utf-8"));
3905
4044
  } catch {
3906
4045
  continue;
3907
4046
  }
@@ -3922,7 +4061,7 @@ ${lines.join("\n")}
3922
4061
  function ensureDefaultTheme(warn) {
3923
4062
  let existing = null;
3924
4063
  try {
3925
- existing = JSON.parse(import_fs4.default.readFileSync(themesResource.filePath("default"), "utf-8"));
4064
+ existing = JSON.parse(import_fs5.default.readFileSync(themesResource.filePath("default"), "utf-8"));
3926
4065
  } catch {
3927
4066
  }
3928
4067
  if (isColorsAndTypeShaped(existing)) {
@@ -3959,9 +4098,9 @@ ${lines.join("\n")}
3959
4098
  themesResource.ensureDir();
3960
4099
  ensureDefaultTheme(warn);
3961
4100
  migrateLocalThemes(warn);
3962
- const productionPointerHeld = !import_fs4.default.existsSync(themesResource.productionPath) && listLegacyPointers().length > 0;
4101
+ const productionPointerHeld = !import_fs5.default.existsSync(themesResource.productionPath) && listLegacyPointers().length > 0;
3963
4102
  if (productionPointerHeld) {
3964
- if (!import_fs4.default.existsSync(themesResource.activePath)) themesResource.setActiveName("default");
4103
+ if (!import_fs5.default.existsSync(themesResource.activePath)) themesResource.setActiveName("default");
3965
4104
  } else {
3966
4105
  themesResource.ensureMeta();
3967
4106
  }
@@ -4040,8 +4179,8 @@ ${lines.join("\n")}
4040
4179
  }
4041
4180
  function clearAllWorking() {
4042
4181
  colorsAndTypeResource.clearWorking();
4043
- if (!import_fs4.default.existsSync(COMPONENT_CONFIGS_DIR)) return;
4044
- for (const entry of import_fs4.default.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
4182
+ if (!import_fs5.default.existsSync(COMPONENT_CONFIGS_DIR)) return;
4183
+ for (const entry of import_fs5.default.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
4045
4184
  if (entry.isDirectory()) componentResource(entry.name).clearWorking();
4046
4185
  }
4047
4186
  }
@@ -4084,6 +4223,7 @@ ${lines.join("\n")}
4084
4223
  const SKETCH_STYLES_ROUTE = `${API_BASE}/sketch-styles`;
4085
4224
  const SKETCH_STYLE_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-styles/([a-z0-9\\-_]+)$`);
4086
4225
  const PRODUCTION_ROUTE = `${API_BASE}/production`;
4226
+ const EVENTS_ROUTE = `${API_BASE}/events`;
4087
4227
  async function handleListColorsAndType(_ctx) {
4088
4228
  const files = colorsAndTypeResource.listNames().map((fileName) => {
4089
4229
  const data = colorsAndTypeResource.readJson(fileName);
@@ -4168,15 +4308,15 @@ ${lines.join("\n")}
4168
4308
  }
4169
4309
  const body = JSON.parse(await readBody(req));
4170
4310
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4171
- if (import_fs4.default.existsSync(filePath)) {
4311
+ if (import_fs5.default.existsSync(filePath)) {
4172
4312
  try {
4173
- const existing = JSON.parse(import_fs4.default.readFileSync(filePath, "utf-8"));
4313
+ const existing = JSON.parse(import_fs5.default.readFileSync(filePath, "utf-8"));
4174
4314
  if (existing.createdAt) body.createdAt = existing.createdAt;
4175
4315
  } catch {
4176
4316
  }
4177
4317
  }
4178
4318
  if (!body.createdAt) body.createdAt = body.updatedAt;
4179
- import_fs4.default.writeFileSync(filePath, JSON.stringify(body, null, 2));
4319
+ import_fs5.default.writeFileSync(filePath, JSON.stringify(body, null, 2));
4180
4320
  jsonResponse(res, 200, { ok: true, fileName });
4181
4321
  return;
4182
4322
  }
@@ -4185,8 +4325,8 @@ ${lines.join("\n")}
4185
4325
  jsonResponse(res, 403, { error: "Cannot delete the default colors and type" });
4186
4326
  return;
4187
4327
  }
4188
- if (import_fs4.default.existsSync(filePath)) {
4189
- import_fs4.default.unlinkSync(filePath);
4328
+ if (import_fs5.default.existsSync(filePath)) {
4329
+ import_fs5.default.unlinkSync(filePath);
4190
4330
  } else if (colorsAndTypeResource.existingPath(fileName)) {
4191
4331
  jsonResponse(res, 403, {
4192
4332
  error: "Cannot delete colors and type shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
@@ -4273,16 +4413,16 @@ ${lines.join("\n")}
4273
4413
  body.component = comp;
4274
4414
  body.name = body.name || name;
4275
4415
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4276
- if (import_fs4.default.existsSync(configPath)) {
4416
+ if (import_fs5.default.existsSync(configPath)) {
4277
4417
  try {
4278
- const existing = JSON.parse(import_fs4.default.readFileSync(configPath, "utf-8"));
4418
+ const existing = JSON.parse(import_fs5.default.readFileSync(configPath, "utf-8"));
4279
4419
  if (existing.createdAt) body.createdAt = existing.createdAt;
4280
4420
  } catch {
4281
4421
  }
4282
4422
  }
4283
4423
  if (!body.createdAt) body.createdAt = body.updatedAt;
4284
4424
  r.ensureDir();
4285
- import_fs4.default.writeFileSync(configPath, JSON.stringify(body, null, 2));
4425
+ import_fs5.default.writeFileSync(configPath, JSON.stringify(body, null, 2));
4286
4426
  jsonResponse(res, 200, { ok: true, fileName: name });
4287
4427
  return;
4288
4428
  }
@@ -4291,7 +4431,7 @@ ${lines.join("\n")}
4291
4431
  jsonResponse(res, 403, { error: "Cannot delete default config" });
4292
4432
  return;
4293
4433
  }
4294
- if (import_fs4.default.existsSync(configPath)) import_fs4.default.unlinkSync(configPath);
4434
+ if (import_fs5.default.existsSync(configPath)) import_fs5.default.unlinkSync(configPath);
4295
4435
  jsonResponse(res, 200, { ok: true });
4296
4436
  return;
4297
4437
  }
@@ -4299,7 +4439,7 @@ ${lines.join("\n")}
4299
4439
  async function handleListComponentConfigs({ params, res }) {
4300
4440
  const [comp] = params;
4301
4441
  const r = componentResource(comp);
4302
- if (!import_fs4.default.existsSync(r.dir)) {
4442
+ if (!import_fs5.default.existsSync(r.dir)) {
4303
4443
  jsonResponse(res, 404, { error: "Component not found" });
4304
4444
  return;
4305
4445
  }
@@ -4387,9 +4527,9 @@ ${lines.join("\n")}
4387
4527
  const body = JSON.parse(await readBody(req));
4388
4528
  const { theme } = normalizeTheme(body, diskThemeResolvers);
4389
4529
  theme.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4390
- if (import_fs4.default.existsSync(filePath)) {
4530
+ if (import_fs5.default.existsSync(filePath)) {
4391
4531
  try {
4392
- const existing = JSON.parse(import_fs4.default.readFileSync(filePath, "utf-8"));
4532
+ const existing = JSON.parse(import_fs5.default.readFileSync(filePath, "utf-8"));
4393
4533
  if (existing.createdAt) theme.createdAt = existing.createdAt;
4394
4534
  } catch {
4395
4535
  }
@@ -4411,7 +4551,7 @@ ${lines.join("\n")}
4411
4551
  });
4412
4552
  return;
4413
4553
  }
4414
- if (import_fs4.default.existsSync(filePath)) {
4554
+ if (import_fs5.default.existsSync(filePath)) {
4415
4555
  const deletingActive = themesResource.getActiveName() === fileName;
4416
4556
  const liveColors = deletingActive ? resolveLiveColorsAndType(activeTheme()) : null;
4417
4557
  const liveComponents = {};
@@ -4421,7 +4561,7 @@ ${lines.join("\n")}
4421
4561
  if (resolved) liveComponents[comp] = resolved.data;
4422
4562
  }
4423
4563
  }
4424
- import_fs4.default.unlinkSync(filePath);
4564
+ import_fs5.default.unlinkSync(filePath);
4425
4565
  if (themesResource.existingPath(fileName) === null && deletingActive) {
4426
4566
  themesResource.setActiveName("default");
4427
4567
  }
@@ -4468,30 +4608,50 @@ ${lines.join("\n")}
4468
4608
  return;
4469
4609
  }
4470
4610
  clearAllWorking();
4471
- const knownComponents = listComponentNames();
4472
4611
  themesResource.setActiveName(fileName);
4473
- const resolvedConfigs = {};
4474
- for (const comp of knownComponents) {
4475
- const resolved = resolveLiveComponentConfig(comp, theme);
4476
- if (resolved) resolvedConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
4477
- }
4478
- const resolvedColorsAndType = resolveLiveColorsAndType(theme);
4612
+ const knownComponents = listComponentNames();
4479
4613
  const skippedComponents = Object.keys(theme.componentConfigs).filter(
4480
4614
  (comp) => !knownComponents.includes(comp)
4481
4615
  );
4482
4616
  jsonResponse(res, 200, {
4483
4617
  ok: true,
4484
- theme: { ...theme, _fileName: fileName },
4485
- colorsAndType: resolvedColorsAndType && {
4486
- ...resolvedColorsAndType.data,
4487
- _fileName: fileName,
4488
- _source: resolvedColorsAndType.source
4489
- },
4490
- componentConfigs: resolvedConfigs,
4618
+ ...resolveLiveState(theme, fileName),
4491
4619
  skippedComponents,
4492
4620
  filled
4493
4621
  });
4494
4622
  }
4623
+ function resolveLiveState(theme, fileName) {
4624
+ const componentConfigs = {};
4625
+ for (const comp of listComponentNames()) {
4626
+ const resolved = resolveLiveComponentConfig(comp, theme);
4627
+ if (resolved) componentConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
4628
+ }
4629
+ const colorsAndType = resolveLiveColorsAndType(theme);
4630
+ return {
4631
+ fileName,
4632
+ theme: { ...theme, _fileName: fileName },
4633
+ colorsAndType: colorsAndType && { ...colorsAndType.data, _fileName: fileName, _source: colorsAndType.source },
4634
+ componentConfigs
4635
+ };
4636
+ }
4637
+ async function handleEvents({ req, res }) {
4638
+ res.statusCode = 200;
4639
+ res.setHeader("Content-Type", "text/event-stream");
4640
+ res.setHeader("Cache-Control", "no-cache");
4641
+ res.setHeader("Connection", "keep-alive");
4642
+ res.write(": connected\n\n");
4643
+ const unsubscribe = liveWatch.subscribe(() => {
4644
+ const activeFile = themesResource.getActiveName();
4645
+ const read = readTheme(activeFile);
4646
+ if (!read) return;
4647
+ const state = resolveLiveState(read.theme, activeFile);
4648
+ res.write(`event: live-state
4649
+ data: ${JSON.stringify(state)}
4650
+
4651
+ `);
4652
+ });
4653
+ req.on("close", unsubscribe);
4654
+ }
4495
4655
  async function handleExportTheme({ params, res }) {
4496
4656
  const [fileName] = params;
4497
4657
  if (rejectReservedName(res, fileName)) return;
@@ -4652,22 +4812,22 @@ ${lines.join("\n")}
4652
4812
  }
4653
4813
  body.name = String(body.name || fileName);
4654
4814
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4655
- if (import_fs4.default.existsSync(filePath)) {
4815
+ if (import_fs5.default.existsSync(filePath)) {
4656
4816
  try {
4657
- const existing = JSON.parse(import_fs4.default.readFileSync(filePath, "utf-8"));
4817
+ const existing = JSON.parse(import_fs5.default.readFileSync(filePath, "utf-8"));
4658
4818
  if (existing.createdAt) body.createdAt = existing.createdAt;
4659
4819
  } catch {
4660
4820
  }
4661
4821
  }
4662
4822
  if (!body.createdAt) body.createdAt = body.updatedAt;
4663
4823
  sketchStylesResource.ensureDir();
4664
- import_fs4.default.writeFileSync(filePath, JSON.stringify(body, null, 2));
4824
+ import_fs5.default.writeFileSync(filePath, JSON.stringify(body, null, 2));
4665
4825
  jsonResponse(res, 200, { ok: true, fileName });
4666
4826
  return;
4667
4827
  }
4668
4828
  if (req.method === "DELETE") {
4669
- if (import_fs4.default.existsSync(filePath)) {
4670
- import_fs4.default.unlinkSync(filePath);
4829
+ if (import_fs5.default.existsSync(filePath)) {
4830
+ import_fs5.default.unlinkSync(filePath);
4671
4831
  } else if (sketchStylesResource.existingPath(fileName)) {
4672
4832
  jsonResponse(res, 403, {
4673
4833
  error: "Cannot delete a sketchstyle shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
@@ -4763,12 +4923,13 @@ ${lines.join("\n")}
4763
4923
  { method: "PUT", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
4764
4924
  { method: "DELETE", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
4765
4925
  { method: "POST", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: methodNotAllowed },
4926
+ { method: "GET", pattern: EVENTS_ROUTE, handler: handleEvents },
4766
4927
  { method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptTheme },
4767
4928
  { method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
4768
4929
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
4769
4930
  { method: "DELETE", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed }
4770
4931
  ];
4771
- const isEditorOwnedJson = (file) => file.endsWith(".json") && import_path4.default.resolve(file).startsWith(dataDirs.dataDir + import_path4.default.sep);
4932
+ const isEditorOwnedJson = (file) => file.endsWith(".json") && import_path5.default.resolve(file).startsWith(dataDirs.dataDir + import_path5.default.sep);
4772
4933
  return {
4773
4934
  name: "theme-file-api",
4774
4935
  config() {
@@ -4796,8 +4957,10 @@ ${lines.join("\n")}
4796
4957
  const { productionPointerHeld } = ensureThemesDir((msg) => server.config.logger.warn(msg));
4797
4958
  const openTheme = activeTheme();
4798
4959
  if (openTheme) pruneMatchingWorking(openTheme);
4799
- if (!productionPointerHeld || !import_fs4.default.existsSync(GENERATED_CSS_PATH)) regenerateTokensCss();
4800
- if (opts.autoMigrate) autoMigrateAdditive((msg) => server.config.logger.info(msg));
4960
+ if (!productionPointerHeld || !import_fs5.default.existsSync(GENERATED_CSS_PATH)) regenerateTokensCss();
4961
+ if (opts.autoMigrate && !ISOLATED_DATA_DIR) {
4962
+ autoMigrateAdditive((msg) => server.config.logger.info(msg));
4963
+ }
4801
4964
  warnOnTokenDrift((msg) => server.config.logger.warn(msg));
4802
4965
  warnOnLegacyPointers(
4803
4966
  listLegacyPointers(),
@@ -4820,7 +4983,7 @@ ${lines.join("\n")}
4820
4983
  },
4821
4984
  handleHotUpdate(ctx) {
4822
4985
  if (legacyLayout) return;
4823
- const normalized = import_path4.default.resolve(ctx.file);
4986
+ const normalized = import_path5.default.resolve(ctx.file);
4824
4987
  if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
4825
4988
  if (!normalized.endsWith(".svelte")) return;
4826
4989
  if (!isThemeAwareComponent(normalized)) return;