@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
@@ -5,7 +5,7 @@ import {
5
5
  nextAvailableName,
6
6
  normalizeTheme,
7
7
  versionedFileResourceServer
8
- } from "./chunk-7VRTBGJT.js";
8
+ } from "./chunk-PDNL4NC5.js";
9
9
  import {
10
10
  formatGradientValue,
11
11
  palettesToVars,
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-O6GQ6GBH.js";
17
17
  import {
18
18
  CURRENT_COMPONENT_SCHEMA_VERSION
19
- } from "./chunk-V3YF6CGT.js";
19
+ } from "./chunk-SWXRVZKT.js";
20
20
  import {
21
21
  TOKENS_CSS_MIGRATIONS,
22
22
  extractGlobalRootBody,
@@ -30,12 +30,14 @@ import {
30
30
  parseOklchCss
31
31
  } from "./chunk-7TQQTHI6.js";
32
32
  import {
33
- resolveDataDirs
34
- } from "./chunk-W6Y4BWFB.js";
33
+ resolveDataDirs,
34
+ testDataDir,
35
+ testPackageDataDir
36
+ } from "./chunk-6WGFOJXO.js";
35
37
 
36
38
  // vite-plugin/themeFileApi.ts
37
- import fs from "fs";
38
- import path from "path";
39
+ import fs2 from "fs";
40
+ import path2 from "path";
39
41
 
40
42
  // src/editor/core/themes/migrations/2026-07-21-palette-oklch-basis.ts
41
43
  var round = (v, dp) => {
@@ -166,18 +168,79 @@ async function dispatch(req, res, routes) {
166
168
  return false;
167
169
  }
168
170
 
171
+ // vite-plugin/files/dataTreeWatch.ts
172
+ import fs from "fs";
173
+ import path from "path";
174
+ function fingerprint(file) {
175
+ try {
176
+ return fs.readFileSync(file, "utf-8");
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+ function dataTreeWatch(opts) {
182
+ const debounceMs = opts.debounceMs ?? 100;
183
+ const ownWrites = /* @__PURE__ */ new Map();
184
+ const listeners = /* @__PURE__ */ new Set();
185
+ let watchers = [];
186
+ let timer = null;
187
+ function noteOwnWrite(file) {
188
+ const resolved = path.resolve(file);
189
+ ownWrites.set(resolved, fingerprint(resolved));
190
+ }
191
+ function onEvent(dir, filename) {
192
+ if (!filename) return;
193
+ const file = path.resolve(dir, filename.toString());
194
+ if (!opts.isLive(file)) return;
195
+ if (ownWrites.has(file) && ownWrites.get(file) === fingerprint(file)) return;
196
+ ownWrites.delete(file);
197
+ if (timer) clearTimeout(timer);
198
+ timer = setTimeout(() => {
199
+ timer = null;
200
+ for (const listener of listeners) listener();
201
+ }, debounceMs);
202
+ }
203
+ function start() {
204
+ for (const dir of opts.dirs) {
205
+ if (!fs.existsSync(dir)) continue;
206
+ const watcher = fs.watch(
207
+ dir,
208
+ { recursive: true, persistent: false },
209
+ (_event, filename) => onEvent(dir, filename)
210
+ );
211
+ watcher.on("error", () => watcher.close());
212
+ watchers.push(watcher);
213
+ }
214
+ }
215
+ function stop() {
216
+ for (const watcher of watchers) watcher.close();
217
+ watchers = [];
218
+ if (timer) clearTimeout(timer);
219
+ timer = null;
220
+ }
221
+ function subscribe(listener) {
222
+ if (listeners.size === 0) start();
223
+ listeners.add(listener);
224
+ return () => {
225
+ listeners.delete(listener);
226
+ if (listeners.size === 0) stop();
227
+ };
228
+ }
229
+ return { noteOwnWrite, subscribe };
230
+ }
231
+
169
232
  // vite-plugin/themeFileApi.ts
170
233
  import { fileURLToPath } from "url";
171
234
  var PKG_VERSION = (() => {
172
235
  try {
173
- let dir = path.dirname(fileURLToPath(import.meta.url));
236
+ let dir = path2.dirname(fileURLToPath(import.meta.url));
174
237
  for (let i = 0; i < 4; i++) {
175
- const p = path.join(dir, "package.json");
176
- if (fs.existsSync(p)) {
177
- const json = JSON.parse(fs.readFileSync(p, "utf-8"));
238
+ const p = path2.join(dir, "package.json");
239
+ if (fs2.existsSync(p)) {
240
+ const json = JSON.parse(fs2.readFileSync(p, "utf-8"));
178
241
  if (json?.name === "@motion-proto/live-tokens") return json.version ?? "";
179
242
  }
180
- const up = path.dirname(dir);
243
+ const up = path2.dirname(dir);
181
244
  if (up === dir) break;
182
245
  dir = up;
183
246
  }
@@ -221,56 +284,64 @@ function themeFileApi(opts) {
221
284
  const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
222
285
  const THEMES_DIR = dataDirs.themesDir;
223
286
  const SKETCH_STYLES_DIR = dataDirs.sketchStylesDir;
224
- const CSS_PATH = path.resolve(opts.tokensCssPath);
225
- const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? path.resolve(opts.tokensGeneratedCssPath) : path.join(dataDirs.dataDir, "tokens.generated.css");
226
- const FONTS_CSS_PATH = opts.fontsCssPath ? path.resolve(opts.fontsCssPath) : path.join(path.dirname(CSS_PATH), "fonts.css");
287
+ const CSS_PATH = path2.resolve(opts.tokensCssPath);
288
+ const ISOLATED_DATA_DIR = testDataDir();
289
+ const GENERATED_CSS_PATH = ISOLATED_DATA_DIR ? path2.join(ISOLATED_DATA_DIR, "tokens.generated.css") : opts.tokensGeneratedCssPath ? path2.resolve(opts.tokensGeneratedCssPath) : path2.join(dataDirs.dataDir, "tokens.generated.css");
290
+ const FONTS_CSS_PATH = ISOLATED_DATA_DIR ? path2.join(ISOLATED_DATA_DIR, "fonts.css") : opts.fontsCssPath ? path2.resolve(opts.fontsCssPath) : path2.join(path2.dirname(CSS_PATH), "fonts.css");
227
291
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
228
- const consumerComponentDirs = opts.componentsSrcDir ? [path.resolve(opts.componentsSrcDir)] : [path.resolve("src/components"), path.resolve("src/system/components")];
229
- const packageComponentsDir = path.resolve(
230
- path.dirname(fileURLToPath(import.meta.url)),
292
+ const consumerComponentDirs = opts.componentsSrcDir ? [path2.resolve(opts.componentsSrcDir)] : [path2.resolve("src/components"), path2.resolve("src/system/components")];
293
+ const packageComponentsDir = path2.resolve(
294
+ path2.dirname(fileURLToPath(import.meta.url)),
231
295
  "..",
232
296
  "src",
233
297
  "system",
234
298
  "components"
235
299
  );
236
- const packageDataDir = path.resolve(
237
- path.dirname(fileURLToPath(import.meta.url)),
300
+ const packageDataDir = testPackageDataDir() ?? path2.resolve(
301
+ path2.dirname(fileURLToPath(import.meta.url)),
238
302
  "..",
239
303
  "src",
240
304
  "live-tokens",
241
305
  "data"
242
306
  );
243
- const packageColorsAndTypeDir = path.join(packageDataDir, "colors-and-type");
244
- const packageThemesDir = path.join(packageDataDir, "themes");
245
- const packageComponentConfigsDir = path.join(packageDataDir, "component-configs");
246
- const packageSketchStylesDir = path.join(packageDataDir, "sketch-styles");
307
+ const packageColorsAndTypeDir = path2.join(packageDataDir, "colors-and-type");
308
+ const packageThemesDir = path2.join(packageDataDir, "themes");
309
+ const packageComponentConfigsDir = path2.join(packageDataDir, "component-configs");
310
+ const packageSketchStylesDir = path2.join(packageDataDir, "sketch-styles");
247
311
  function shippedNames(dataDir, subdir) {
248
312
  try {
249
- const pkgRoot = path.resolve(dataDir, "..", "..", "..");
250
- const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf-8"));
313
+ const pkgRoot = path2.resolve(dataDir, "..", "..", "..");
314
+ const pkg = JSON.parse(fs2.readFileSync(path2.join(pkgRoot, "package.json"), "utf-8"));
251
315
  const files = Array.isArray(pkg.files) ? pkg.files : [];
252
316
  const owned = new RegExp(`^src/live-tokens/data/${subdir}/[^/]+\\.json$`);
253
- return files.filter((f) => owned.test(f)).map((f) => path.basename(f, ".json"));
317
+ return files.filter((f) => owned.test(f)).map((f) => path2.basename(f, ".json"));
254
318
  } catch {
255
319
  return [];
256
320
  }
257
321
  }
258
322
  const COMPONENTS_SCAN_DIRS = [...consumerComponentDirs];
259
- if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && fs.existsSync(packageComponentsDir)) {
323
+ if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && fs2.existsSync(packageComponentsDir)) {
260
324
  COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
261
325
  }
326
+ const isLiveStateFile = (file) => file === path2.join(THEMES_DIR, "_active.json") || path2.basename(file) === "_working.json" && (file.startsWith(COLORS_AND_TYPE_DIR + path2.sep) || file.startsWith(COMPONENT_CONFIGS_DIR + path2.sep));
327
+ const liveWatch = dataTreeWatch({
328
+ dirs: [COLORS_AND_TYPE_DIR, COMPONENT_CONFIGS_DIR, THEMES_DIR],
329
+ isLive: isLiveStateFile
330
+ });
262
331
  const colorsAndTypeResource = versionedFileResourceServer({
263
332
  dir: COLORS_AND_TYPE_DIR,
264
333
  packageDir: packageColorsAndTypeDir,
265
- packageOwnedNames: shippedNames(packageDataDir, "colors-and-type")
334
+ packageOwnedNames: shippedNames(packageDataDir, "colors-and-type"),
335
+ onWrite: liveWatch.noteOwnWrite
266
336
  });
267
337
  const componentResourceCache = /* @__PURE__ */ new Map();
268
338
  function componentResource(comp) {
269
339
  let r = componentResourceCache.get(comp);
270
340
  if (!r) {
271
341
  r = versionedFileResourceServer({
272
- dir: path.join(COMPONENT_CONFIGS_DIR, comp),
273
- packageDir: path.join(packageComponentConfigsDir, comp)
342
+ dir: path2.join(COMPONENT_CONFIGS_DIR, comp),
343
+ packageDir: path2.join(packageComponentConfigsDir, comp),
344
+ onWrite: liveWatch.noteOwnWrite
274
345
  });
275
346
  componentResourceCache.set(comp, r);
276
347
  }
@@ -278,7 +349,8 @@ function themeFileApi(opts) {
278
349
  }
279
350
  const themesResource = versionedFileResourceServer({
280
351
  dir: THEMES_DIR,
281
- packageDir: packageThemesDir
352
+ packageDir: packageThemesDir,
353
+ onWrite: liveWatch.noteOwnWrite
282
354
  });
283
355
  const sketchStylesResource = versionedFileResourceServer({
284
356
  dir: SKETCH_STYLES_DIR,
@@ -359,7 +431,7 @@ function themeFileApi(opts) {
359
431
  const productionThemeName = themesResource.getProductionName();
360
432
  const productionTheme = readTheme(productionThemeName)?.theme ?? null;
361
433
  if (themesResource.existingPath(productionThemeName) !== null && !productionTheme?.colorsAndType) {
362
- const tail = `${path.basename(GENERATED_CSS_PATH)} was left as it was.`;
434
+ const tail = `${path2.basename(GENERATED_CSS_PATH)} was left as it was.`;
363
435
  throw new Error(
364
436
  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.`
365
437
  );
@@ -397,7 +469,7 @@ function themeFileApi(opts) {
397
469
  }
398
470
  }
399
471
  let componentOverrideCount = 0;
400
- if (fs.existsSync(COMPONENT_CONFIGS_DIR)) {
472
+ if (fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
401
473
  const blocks = [];
402
474
  for (const comp of listComponentNames()) {
403
475
  const prodCfg = productionTheme?.componentConfigs[comp];
@@ -430,12 +502,12 @@ function themeFileApi(opts) {
430
502
  lines.push("");
431
503
  }
432
504
  }
433
- if (!fs.existsSync(path.dirname(GENERATED_CSS_PATH))) {
434
- fs.mkdirSync(path.dirname(GENERATED_CSS_PATH), { recursive: true });
505
+ if (!fs2.existsSync(path2.dirname(GENERATED_CSS_PATH))) {
506
+ fs2.mkdirSync(path2.dirname(GENERATED_CSS_PATH), { recursive: true });
435
507
  }
436
- fs.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
508
+ fs2.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
437
509
  console.log(
438
- `[regenerateTokensCss] Wrote ${path.basename(GENERATED_CSS_PATH)} (${colorsAndTypeVarCount} theme vars, ${componentOverrideCount} component overrides)`
510
+ `[regenerateTokensCss] Wrote ${path2.basename(GENERATED_CSS_PATH)} (${colorsAndTypeVarCount} theme vars, ${componentOverrideCount} component overrides)`
439
511
  );
440
512
  }
441
513
  function syncFontsToCss(colorsAndTypeData) {
@@ -463,18 +535,18 @@ function themeFileApi(opts) {
463
535
  lines.push("");
464
536
  }
465
537
  const content = lines.join("\n");
466
- if (!fs.existsSync(path.dirname(FONTS_CSS_PATH))) {
467
- fs.mkdirSync(path.dirname(FONTS_CSS_PATH), { recursive: true });
538
+ if (!fs2.existsSync(path2.dirname(FONTS_CSS_PATH))) {
539
+ fs2.mkdirSync(path2.dirname(FONTS_CSS_PATH), { recursive: true });
468
540
  }
469
- fs.writeFileSync(FONTS_CSS_PATH, content);
470
- console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${path.basename(FONTS_CSS_PATH)}`);
541
+ fs2.writeFileSync(FONTS_CSS_PATH, content);
542
+ console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${path2.basename(FONTS_CSS_PATH)}`);
471
543
  }
472
544
  function componentNameFromFile(filePath) {
473
- return path.basename(filePath, ".svelte").toLowerCase();
545
+ return path2.basename(filePath, ".svelte").toLowerCase();
474
546
  }
475
547
  function isThemeAwareComponent(filePath) {
476
548
  try {
477
- const source = fs.readFileSync(filePath, "utf-8");
549
+ const source = fs2.readFileSync(filePath, "utf-8");
478
550
  return /:global\(:root\)\s*\{/.test(source);
479
551
  } catch {
480
552
  return false;
@@ -483,10 +555,10 @@ function themeFileApi(opts) {
483
555
  function listComponentSourcePaths() {
484
556
  const byName = /* @__PURE__ */ new Map();
485
557
  for (const dir of COMPONENTS_SCAN_DIRS) {
486
- if (!fs.existsSync(dir)) continue;
487
- for (const f of fs.readdirSync(dir)) {
558
+ if (!fs2.existsSync(dir)) continue;
559
+ for (const f of fs2.readdirSync(dir)) {
488
560
  if (!f.endsWith(".svelte")) continue;
489
- const full = path.join(dir, f);
561
+ const full = path2.join(dir, f);
490
562
  if (!isThemeAwareComponent(full)) continue;
491
563
  const name = componentNameFromFile(f);
492
564
  if (!byName.has(name)) byName.set(name, full);
@@ -500,18 +572,18 @@ function themeFileApi(opts) {
500
572
  function warnOnTokenDrift(log) {
501
573
  let tokensCss = "";
502
574
  try {
503
- tokensCss = fs.readFileSync(CSS_PATH, "utf-8");
575
+ tokensCss = fs2.readFileSync(CSS_PATH, "utf-8");
504
576
  } catch {
505
577
  return;
506
578
  }
507
579
  let generatedCss = "";
508
580
  try {
509
- generatedCss = fs.readFileSync(GENERATED_CSS_PATH, "utf-8");
581
+ generatedCss = fs2.readFileSync(GENERATED_CSS_PATH, "utf-8");
510
582
  } catch {
511
583
  }
512
584
  const componentSources = listComponentSourcePaths().map((p) => ({
513
585
  name: componentNameFromFile(p),
514
- source: fs.readFileSync(p, "utf-8")
586
+ source: fs2.readFileSync(p, "utf-8")
515
587
  }));
516
588
  const missing = validateTokensCss({ tokensCss, generatedCss, componentSources });
517
589
  if (missing.length === 0) return;
@@ -519,7 +591,7 @@ function themeFileApi(opts) {
519
591
  (m) => ` ${m.token} (referenced by ${m.referencedBy.join(", ")})`
520
592
  );
521
593
  log(
522
- `[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${path.relative(process.cwd(), CSS_PATH)}:
594
+ `[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${path2.relative(process.cwd(), CSS_PATH)}:
523
595
  ${lines.join("\n")}
524
596
  These render as blank/empty editor slots. Run \`npx live-tokens migrate\` to reconcile.`
525
597
  );
@@ -527,30 +599,30 @@ ${lines.join("\n")}
527
599
  function autoMigrateAdditive(log) {
528
600
  let before = "";
529
601
  try {
530
- before = fs.readFileSync(CSS_PATH, "utf-8");
602
+ before = fs2.readFileSync(CSS_PATH, "utf-8");
531
603
  } catch {
532
604
  return;
533
605
  }
534
606
  const { css, applied, changed } = runAdditiveTokensCssMigrations(before);
535
607
  if (!changed) return;
536
- fs.writeFileSync(CSS_PATH, css);
608
+ fs2.writeFileSync(CSS_PATH, css);
537
609
  log(
538
- `[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${path.relative(process.cwd(), CSS_PATH)}: ${applied.join(", ")}. Review the diff in git.`
610
+ `[live-tokens] autoMigrate applied ${applied.length} additive migration(s) to ${path2.relative(process.cwd(), CSS_PATH)}: ${applied.join(", ")}. Review the diff in git.`
539
611
  );
540
612
  }
541
613
  function generateDefaultConfig(comp, sourcePath) {
542
- if (!fs.existsSync(sourcePath)) return;
614
+ if (!fs2.existsSync(sourcePath)) return;
543
615
  const r = componentResource(comp);
544
616
  r.ensureDir();
545
617
  const defaultPath = r.filePath("default");
546
- const sourceStat = fs.statSync(sourcePath);
618
+ const sourceStat = fs2.statSync(sourcePath);
547
619
  let createdAt = (/* @__PURE__ */ new Date()).toISOString();
548
620
  let existingUpdatedAt;
549
621
  let existingAliases;
550
622
  let existingSchemaVersion;
551
- if (fs.existsSync(defaultPath)) {
623
+ if (fs2.existsSync(defaultPath)) {
552
624
  try {
553
- const existing = JSON.parse(fs.readFileSync(defaultPath, "utf-8"));
625
+ const existing = JSON.parse(fs2.readFileSync(defaultPath, "utf-8"));
554
626
  if (existing.createdAt) createdAt = existing.createdAt;
555
627
  if (typeof existing.updatedAt === "string") existingUpdatedAt = existing.updatedAt;
556
628
  if (existing.aliases && typeof existing.aliases === "object") {
@@ -559,13 +631,13 @@ ${lines.join("\n")}
559
631
  if (typeof existing.schemaVersion === "number") existingSchemaVersion = existing.schemaVersion;
560
632
  } catch {
561
633
  }
562
- const defaultStat = fs.statSync(defaultPath);
634
+ const defaultStat = fs2.statSync(defaultPath);
563
635
  if (defaultStat.mtimeMs >= sourceStat.mtimeMs && existingSchemaVersion === CURRENT_COMPONENT_SCHEMA_VERSION) {
564
636
  return;
565
637
  }
566
638
  }
567
639
  const now = (/* @__PURE__ */ new Date()).toISOString();
568
- const source = fs.readFileSync(sourcePath, "utf-8");
640
+ const source = fs2.readFileSync(sourcePath, "utf-8");
569
641
  const body = extractGlobalRootBody(source);
570
642
  const aliases = extractAliasDeclarations(body);
571
643
  const aliasesUnchanged = existingAliases !== void 0 && JSON.stringify(existingAliases) === JSON.stringify(aliases);
@@ -580,14 +652,14 @@ ${lines.join("\n")}
580
652
  };
581
653
  if (aliasesUnchanged && schemaStampCurrent && existingUpdatedAt) {
582
654
  const t = /* @__PURE__ */ new Date();
583
- fs.utimesSync(defaultPath, t, t);
655
+ fs2.utimesSync(defaultPath, t, t);
584
656
  return;
585
657
  }
586
- fs.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
658
+ fs2.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
587
659
  }
588
660
  function ensureComponentConfigsDir() {
589
- if (!fs.existsSync(COMPONENT_CONFIGS_DIR)) {
590
- fs.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
661
+ if (!fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
662
+ fs2.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
591
663
  }
592
664
  for (const sourcePath of listComponentSourcePaths()) {
593
665
  const comp = componentNameFromFile(sourcePath);
@@ -600,14 +672,14 @@ ${lines.join("\n")}
600
672
  const legacy = [];
601
673
  const check = (dir) => {
602
674
  for (const name of ["_active.json", "_production.json"]) {
603
- const p = path.join(dir, name);
604
- if (fs.existsSync(p)) legacy.push(path.relative(process.cwd(), p));
675
+ const p = path2.join(dir, name);
676
+ if (fs2.existsSync(p)) legacy.push(path2.relative(process.cwd(), p));
605
677
  }
606
678
  };
607
679
  check(COLORS_AND_TYPE_DIR);
608
- if (fs.existsSync(COMPONENT_CONFIGS_DIR)) {
609
- for (const entry of fs.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
610
- if (entry.isDirectory()) check(path.join(COMPONENT_CONFIGS_DIR, entry.name));
680
+ if (fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
681
+ for (const entry of fs2.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
682
+ if (entry.isDirectory()) check(path2.join(COMPONENT_CONFIGS_DIR, entry.name));
611
683
  }
612
684
  }
613
685
  return legacy;
@@ -615,19 +687,19 @@ ${lines.join("\n")}
615
687
  function warnOnLegacyPointers(legacy, bakeHeld, warn) {
616
688
  if (legacy.length === 0) return;
617
689
  warn(
618
- `[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 ${path.basename(GENERATED_CSS_PATH)} is left exactly as it is rather than rebuilt from the default.` : "")
690
+ `[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 ${path2.basename(GENERATED_CSS_PATH)} is left exactly as it is rather than rebuilt from the default.` : "")
619
691
  );
620
692
  }
621
693
  function warnOnLegacyLayout(evidence, warn) {
622
694
  warn(
623
- `[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 ${path.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.`
695
+ `[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 ${path2.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.`
624
696
  );
625
697
  }
626
698
  function warnOnUnmigratedSketchStyles(warn) {
627
- const legacyDir = path.join(dataDirs.dataDir, "sketch-presets");
628
- if (!fs.existsSync(legacyDir)) return;
699
+ const legacyDir = path2.join(dataDirs.dataDir, "sketch-presets");
700
+ if (!fs2.existsSync(legacyDir)) return;
629
701
  warn(
630
- `[live-tokens] Saved sketchstyles still live under the retired ${path.basename(legacyDir)}/ directory name. Run \`npx live-tokens migrate\` to rename it to ${path.basename(SKETCH_STYLES_DIR)}/; until then they will not show up in the Sketchstyle view.`
702
+ `[live-tokens] Saved sketchstyles still live under the retired ${path2.basename(legacyDir)}/ directory name. Run \`npx live-tokens migrate\` to rename it to ${path2.basename(SKETCH_STYLES_DIR)}/; until then they will not show up in the Sketchstyle view.`
631
703
  );
632
704
  }
633
705
  const diskThemeResolvers = {
@@ -651,7 +723,7 @@ ${lines.join("\n")}
651
723
  const resolved = themesResource.existingPath(fileName);
652
724
  if (resolved === null) return "missing";
653
725
  try {
654
- if (isColorsAndTypeShaped(JSON.parse(fs.readFileSync(resolved, "utf-8")))) {
726
+ if (isColorsAndTypeShaped(JSON.parse(fs2.readFileSync(resolved, "utf-8")))) {
655
727
  return "colors-and-type";
656
728
  }
657
729
  } catch {
@@ -659,7 +731,7 @@ ${lines.join("\n")}
659
731
  return "corrupt";
660
732
  }
661
733
  function notAThemeError(fileName) {
662
- return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${path.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme skill "create-theme".`;
734
+ return `"${fileName}" is a colors-and-type file, not a theme. Before 0.48 those lived in themes/; move it to ${path2.basename(COLORS_AND_TYPE_DIR)}/ or delete it. To build a theme, use the theme skill "create-theme".`;
663
735
  }
664
736
  function respondUnreadableTheme(res, fileName, missingError) {
665
737
  switch (unreadableThemeReason(fileName)) {
@@ -678,18 +750,18 @@ ${lines.join("\n")}
678
750
  }
679
751
  function writeTheme(fileName, theme) {
680
752
  themesResource.ensureDir();
681
- fs.writeFileSync(themesResource.filePath(fileName), JSON.stringify(theme, null, 2));
753
+ fs2.writeFileSync(themesResource.filePath(fileName), JSON.stringify(theme, null, 2));
682
754
  }
683
755
  function migrateLocalThemes(warn) {
684
- if (path.resolve(THEMES_DIR) === path.resolve(packageThemesDir)) return;
685
- if (!fs.existsSync(THEMES_DIR)) return;
686
- for (const file of fs.readdirSync(THEMES_DIR)) {
756
+ if (path2.resolve(THEMES_DIR) === path2.resolve(packageThemesDir)) return;
757
+ if (!fs2.existsSync(THEMES_DIR)) return;
758
+ for (const file of fs2.readdirSync(THEMES_DIR)) {
687
759
  if (!file.endsWith(".json") || file.startsWith("_")) continue;
688
760
  const fileName = file.slice(0, -".json".length);
689
761
  if (fileName === "default") continue;
690
762
  let raw;
691
763
  try {
692
- raw = JSON.parse(fs.readFileSync(path.join(THEMES_DIR, file), "utf-8"));
764
+ raw = JSON.parse(fs2.readFileSync(path2.join(THEMES_DIR, file), "utf-8"));
693
765
  } catch {
694
766
  continue;
695
767
  }
@@ -710,7 +782,7 @@ ${lines.join("\n")}
710
782
  function ensureDefaultTheme(warn) {
711
783
  let existing = null;
712
784
  try {
713
- existing = JSON.parse(fs.readFileSync(themesResource.filePath("default"), "utf-8"));
785
+ existing = JSON.parse(fs2.readFileSync(themesResource.filePath("default"), "utf-8"));
714
786
  } catch {
715
787
  }
716
788
  if (isColorsAndTypeShaped(existing)) {
@@ -747,9 +819,9 @@ ${lines.join("\n")}
747
819
  themesResource.ensureDir();
748
820
  ensureDefaultTheme(warn);
749
821
  migrateLocalThemes(warn);
750
- const productionPointerHeld = !fs.existsSync(themesResource.productionPath) && listLegacyPointers().length > 0;
822
+ const productionPointerHeld = !fs2.existsSync(themesResource.productionPath) && listLegacyPointers().length > 0;
751
823
  if (productionPointerHeld) {
752
- if (!fs.existsSync(themesResource.activePath)) themesResource.setActiveName("default");
824
+ if (!fs2.existsSync(themesResource.activePath)) themesResource.setActiveName("default");
753
825
  } else {
754
826
  themesResource.ensureMeta();
755
827
  }
@@ -828,8 +900,8 @@ ${lines.join("\n")}
828
900
  }
829
901
  function clearAllWorking() {
830
902
  colorsAndTypeResource.clearWorking();
831
- if (!fs.existsSync(COMPONENT_CONFIGS_DIR)) return;
832
- for (const entry of fs.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
903
+ if (!fs2.existsSync(COMPONENT_CONFIGS_DIR)) return;
904
+ for (const entry of fs2.readdirSync(COMPONENT_CONFIGS_DIR, { withFileTypes: true })) {
833
905
  if (entry.isDirectory()) componentResource(entry.name).clearWorking();
834
906
  }
835
907
  }
@@ -872,6 +944,7 @@ ${lines.join("\n")}
872
944
  const SKETCH_STYLES_ROUTE = `${API_BASE}/sketch-styles`;
873
945
  const SKETCH_STYLE_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-styles/([a-z0-9\\-_]+)$`);
874
946
  const PRODUCTION_ROUTE = `${API_BASE}/production`;
947
+ const EVENTS_ROUTE = `${API_BASE}/events`;
875
948
  async function handleListColorsAndType(_ctx) {
876
949
  const files = colorsAndTypeResource.listNames().map((fileName) => {
877
950
  const data = colorsAndTypeResource.readJson(fileName);
@@ -956,15 +1029,15 @@ ${lines.join("\n")}
956
1029
  }
957
1030
  const body = JSON.parse(await readBody(req));
958
1031
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
959
- if (fs.existsSync(filePath)) {
1032
+ if (fs2.existsSync(filePath)) {
960
1033
  try {
961
- const existing = JSON.parse(fs.readFileSync(filePath, "utf-8"));
1034
+ const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
962
1035
  if (existing.createdAt) body.createdAt = existing.createdAt;
963
1036
  } catch {
964
1037
  }
965
1038
  }
966
1039
  if (!body.createdAt) body.createdAt = body.updatedAt;
967
- fs.writeFileSync(filePath, JSON.stringify(body, null, 2));
1040
+ fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
968
1041
  jsonResponse(res, 200, { ok: true, fileName });
969
1042
  return;
970
1043
  }
@@ -973,8 +1046,8 @@ ${lines.join("\n")}
973
1046
  jsonResponse(res, 403, { error: "Cannot delete the default colors and type" });
974
1047
  return;
975
1048
  }
976
- if (fs.existsSync(filePath)) {
977
- fs.unlinkSync(filePath);
1049
+ if (fs2.existsSync(filePath)) {
1050
+ fs2.unlinkSync(filePath);
978
1051
  } else if (colorsAndTypeResource.existingPath(fileName)) {
979
1052
  jsonResponse(res, 403, {
980
1053
  error: "Cannot delete colors and type shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
@@ -1061,16 +1134,16 @@ ${lines.join("\n")}
1061
1134
  body.component = comp;
1062
1135
  body.name = body.name || name;
1063
1136
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1064
- if (fs.existsSync(configPath)) {
1137
+ if (fs2.existsSync(configPath)) {
1065
1138
  try {
1066
- const existing = JSON.parse(fs.readFileSync(configPath, "utf-8"));
1139
+ const existing = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
1067
1140
  if (existing.createdAt) body.createdAt = existing.createdAt;
1068
1141
  } catch {
1069
1142
  }
1070
1143
  }
1071
1144
  if (!body.createdAt) body.createdAt = body.updatedAt;
1072
1145
  r.ensureDir();
1073
- fs.writeFileSync(configPath, JSON.stringify(body, null, 2));
1146
+ fs2.writeFileSync(configPath, JSON.stringify(body, null, 2));
1074
1147
  jsonResponse(res, 200, { ok: true, fileName: name });
1075
1148
  return;
1076
1149
  }
@@ -1079,7 +1152,7 @@ ${lines.join("\n")}
1079
1152
  jsonResponse(res, 403, { error: "Cannot delete default config" });
1080
1153
  return;
1081
1154
  }
1082
- if (fs.existsSync(configPath)) fs.unlinkSync(configPath);
1155
+ if (fs2.existsSync(configPath)) fs2.unlinkSync(configPath);
1083
1156
  jsonResponse(res, 200, { ok: true });
1084
1157
  return;
1085
1158
  }
@@ -1087,7 +1160,7 @@ ${lines.join("\n")}
1087
1160
  async function handleListComponentConfigs({ params, res }) {
1088
1161
  const [comp] = params;
1089
1162
  const r = componentResource(comp);
1090
- if (!fs.existsSync(r.dir)) {
1163
+ if (!fs2.existsSync(r.dir)) {
1091
1164
  jsonResponse(res, 404, { error: "Component not found" });
1092
1165
  return;
1093
1166
  }
@@ -1175,9 +1248,9 @@ ${lines.join("\n")}
1175
1248
  const body = JSON.parse(await readBody(req));
1176
1249
  const { theme } = normalizeTheme(body, diskThemeResolvers);
1177
1250
  theme.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1178
- if (fs.existsSync(filePath)) {
1251
+ if (fs2.existsSync(filePath)) {
1179
1252
  try {
1180
- const existing = JSON.parse(fs.readFileSync(filePath, "utf-8"));
1253
+ const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1181
1254
  if (existing.createdAt) theme.createdAt = existing.createdAt;
1182
1255
  } catch {
1183
1256
  }
@@ -1199,7 +1272,7 @@ ${lines.join("\n")}
1199
1272
  });
1200
1273
  return;
1201
1274
  }
1202
- if (fs.existsSync(filePath)) {
1275
+ if (fs2.existsSync(filePath)) {
1203
1276
  const deletingActive = themesResource.getActiveName() === fileName;
1204
1277
  const liveColors = deletingActive ? resolveLiveColorsAndType(activeTheme()) : null;
1205
1278
  const liveComponents = {};
@@ -1209,7 +1282,7 @@ ${lines.join("\n")}
1209
1282
  if (resolved) liveComponents[comp] = resolved.data;
1210
1283
  }
1211
1284
  }
1212
- fs.unlinkSync(filePath);
1285
+ fs2.unlinkSync(filePath);
1213
1286
  if (themesResource.existingPath(fileName) === null && deletingActive) {
1214
1287
  themesResource.setActiveName("default");
1215
1288
  }
@@ -1256,30 +1329,50 @@ ${lines.join("\n")}
1256
1329
  return;
1257
1330
  }
1258
1331
  clearAllWorking();
1259
- const knownComponents = listComponentNames();
1260
1332
  themesResource.setActiveName(fileName);
1261
- const resolvedConfigs = {};
1262
- for (const comp of knownComponents) {
1263
- const resolved = resolveLiveComponentConfig(comp, theme);
1264
- if (resolved) resolvedConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
1265
- }
1266
- const resolvedColorsAndType = resolveLiveColorsAndType(theme);
1333
+ const knownComponents = listComponentNames();
1267
1334
  const skippedComponents = Object.keys(theme.componentConfigs).filter(
1268
1335
  (comp) => !knownComponents.includes(comp)
1269
1336
  );
1270
1337
  jsonResponse(res, 200, {
1271
1338
  ok: true,
1272
- theme: { ...theme, _fileName: fileName },
1273
- colorsAndType: resolvedColorsAndType && {
1274
- ...resolvedColorsAndType.data,
1275
- _fileName: fileName,
1276
- _source: resolvedColorsAndType.source
1277
- },
1278
- componentConfigs: resolvedConfigs,
1339
+ ...resolveLiveState(theme, fileName),
1279
1340
  skippedComponents,
1280
1341
  filled
1281
1342
  });
1282
1343
  }
1344
+ function resolveLiveState(theme, fileName) {
1345
+ const componentConfigs = {};
1346
+ for (const comp of listComponentNames()) {
1347
+ const resolved = resolveLiveComponentConfig(comp, theme);
1348
+ if (resolved) componentConfigs[comp] = { ...resolved.data, _fileName: fileName, _source: resolved.source };
1349
+ }
1350
+ const colorsAndType = resolveLiveColorsAndType(theme);
1351
+ return {
1352
+ fileName,
1353
+ theme: { ...theme, _fileName: fileName },
1354
+ colorsAndType: colorsAndType && { ...colorsAndType.data, _fileName: fileName, _source: colorsAndType.source },
1355
+ componentConfigs
1356
+ };
1357
+ }
1358
+ async function handleEvents({ req, res }) {
1359
+ res.statusCode = 200;
1360
+ res.setHeader("Content-Type", "text/event-stream");
1361
+ res.setHeader("Cache-Control", "no-cache");
1362
+ res.setHeader("Connection", "keep-alive");
1363
+ res.write(": connected\n\n");
1364
+ const unsubscribe = liveWatch.subscribe(() => {
1365
+ const activeFile = themesResource.getActiveName();
1366
+ const read = readTheme(activeFile);
1367
+ if (!read) return;
1368
+ const state = resolveLiveState(read.theme, activeFile);
1369
+ res.write(`event: live-state
1370
+ data: ${JSON.stringify(state)}
1371
+
1372
+ `);
1373
+ });
1374
+ req.on("close", unsubscribe);
1375
+ }
1283
1376
  async function handleExportTheme({ params, res }) {
1284
1377
  const [fileName] = params;
1285
1378
  if (rejectReservedName(res, fileName)) return;
@@ -1440,22 +1533,22 @@ ${lines.join("\n")}
1440
1533
  }
1441
1534
  body.name = String(body.name || fileName);
1442
1535
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1443
- if (fs.existsSync(filePath)) {
1536
+ if (fs2.existsSync(filePath)) {
1444
1537
  try {
1445
- const existing = JSON.parse(fs.readFileSync(filePath, "utf-8"));
1538
+ const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1446
1539
  if (existing.createdAt) body.createdAt = existing.createdAt;
1447
1540
  } catch {
1448
1541
  }
1449
1542
  }
1450
1543
  if (!body.createdAt) body.createdAt = body.updatedAt;
1451
1544
  sketchStylesResource.ensureDir();
1452
- fs.writeFileSync(filePath, JSON.stringify(body, null, 2));
1545
+ fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
1453
1546
  jsonResponse(res, 200, { ok: true, fileName });
1454
1547
  return;
1455
1548
  }
1456
1549
  if (req.method === "DELETE") {
1457
- if (fs.existsSync(filePath)) {
1458
- fs.unlinkSync(filePath);
1550
+ if (fs2.existsSync(filePath)) {
1551
+ fs2.unlinkSync(filePath);
1459
1552
  } else if (sketchStylesResource.existingPath(fileName)) {
1460
1553
  jsonResponse(res, 403, {
1461
1554
  error: "Cannot delete a sketchstyle shipped with the package. Saving it creates a local copy; deleting that copy restores the shipped version.",
@@ -1551,12 +1644,13 @@ ${lines.join("\n")}
1551
1644
  { method: "PUT", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
1552
1645
  { method: "DELETE", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
1553
1646
  { method: "POST", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: methodNotAllowed },
1647
+ { method: "GET", pattern: EVENTS_ROUTE, handler: handleEvents },
1554
1648
  { method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptTheme },
1555
1649
  { method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
1556
1650
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
1557
1651
  { method: "DELETE", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed }
1558
1652
  ];
1559
- const isEditorOwnedJson = (file) => file.endsWith(".json") && path.resolve(file).startsWith(dataDirs.dataDir + path.sep);
1653
+ const isEditorOwnedJson = (file) => file.endsWith(".json") && path2.resolve(file).startsWith(dataDirs.dataDir + path2.sep);
1560
1654
  return {
1561
1655
  name: "theme-file-api",
1562
1656
  config() {
@@ -1584,8 +1678,10 @@ ${lines.join("\n")}
1584
1678
  const { productionPointerHeld } = ensureThemesDir((msg) => server.config.logger.warn(msg));
1585
1679
  const openTheme = activeTheme();
1586
1680
  if (openTheme) pruneMatchingWorking(openTheme);
1587
- if (!productionPointerHeld || !fs.existsSync(GENERATED_CSS_PATH)) regenerateTokensCss();
1588
- if (opts.autoMigrate) autoMigrateAdditive((msg) => server.config.logger.info(msg));
1681
+ if (!productionPointerHeld || !fs2.existsSync(GENERATED_CSS_PATH)) regenerateTokensCss();
1682
+ if (opts.autoMigrate && !ISOLATED_DATA_DIR) {
1683
+ autoMigrateAdditive((msg) => server.config.logger.info(msg));
1684
+ }
1589
1685
  warnOnTokenDrift((msg) => server.config.logger.warn(msg));
1590
1686
  warnOnLegacyPointers(
1591
1687
  listLegacyPointers(),
@@ -1608,7 +1704,7 @@ ${lines.join("\n")}
1608
1704
  },
1609
1705
  handleHotUpdate(ctx) {
1610
1706
  if (legacyLayout) return;
1611
- const normalized = path.resolve(ctx.file);
1707
+ const normalized = path2.resolve(ctx.file);
1612
1708
  if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
1613
1709
  if (!normalized.endsWith(".svelte")) return;
1614
1710
  if (!isThemeAwareComponent(normalized)) return;