dsh-plugin-ekko-skin-manager 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ekko 皮肤管理器 · 旧版兼容入口
2
2
 
3
- **主题管理功能已整合到新版主题中。** 新用户请直接安装 [初音未来主题](https://github.com/cjjchina3088191870-sudo/dsh-plugin-miku-theme),主题内已包含管理界面、手机导航、外观设置和启动视频功能。
3
+ **主题管理功能已整合到新版主题中。** 新用户请直接安装 [玫瑰女王、初音未来与丝柯克主题套装](https://github.com/cjjchina3088191870-sudo/dsh-plugin-miku-theme),主题内已包含管理界面、手机导航、外观设置和启动视频功能。
4
4
 
5
5
  本仓库保留旧版兼容与迁移说明。新版主题可独立使用,安装其他兼容主题后,会自动纳入同一管理界面。
6
6
 
@@ -9,12 +9,12 @@
9
9
  适配 DSH 0.2.2-rc.1:
10
10
 
11
11
  ```sh
12
- dsh plugin --profile web add github:cjjchina3088191870-sudo/dsh-plugin-miku-theme#main
12
+ dsh plugin --profile web add dsh-plugin-miku-theme
13
13
  ```
14
14
 
15
15
  重启 DSH 并刷新网页,进入 **账号菜单 → 设置 → Ekko 皮肤** 即可使用。
16
16
 
17
- 电脑与手机可以分别上传启动视频,支持 MP4 / WebM、预览、声音控制与不同画面比例。完整介绍和主题预览请查看 [初音未来主题仓库](https://github.com/cjjchina3088191870-sudo/dsh-plugin-miku-theme#readme)。
17
+ 电脑与手机可以分别上传启动视频,支持 MP4 / WebM、预览、声音控制与不同画面比例。完整介绍和主题预览请查看 [玫瑰女王、初音未来与丝柯克主题套装仓库](https://github.com/cjjchina3088191870-sudo/dsh-plugin-miku-theme#readme)。
18
18
 
19
19
  ## 已安装独立管理器的用户
20
20
 
@@ -22,12 +22,14 @@ dsh plugin --profile web add github:cjjchina3088191870-sudo/dsh-plugin-miku-them
22
22
 
23
23
  ```sh
24
24
  dsh plugin --profile web remove dsh-plugin-ekko-skin-manager
25
- dsh plugin --profile web add github:cjjchina3088191870-sudo/dsh-plugin-miku-theme#main
25
+ dsh plugin --profile web add dsh-plugin-miku-theme
26
26
  ```
27
27
 
28
28
  完成后重启 DSH 并刷新网页。主题偏好和已保存的视频会保留;使用其他 profile 时,将 `web` 替换为对应名称。
29
29
 
30
- 独立管理器 0.2.x 与新版主题可以共用管理界面,但日常使用只安装主题即可。
30
+ 独立管理器 **0.3.1 及以上**与新版三主题套装可以共用管理界面,支持丝柯克、三个主题分别保存的外观设置与电脑/手机启动视频。日常使用只安装主题即可。
31
+
32
+ 保留独立管理器时,请一起升级到当前版本;0.3.0 及更早版本不支持丝柯克。
31
33
 
32
34
  ## 许可
33
35
 
package/design-qa.md CHANGED
@@ -52,3 +52,13 @@ H.264 1280×720 MP4 与 270×480 WebM 已在 Chromium 桌面及 393×760 手机
52
52
  ### 2026-11-07 · 启动片段的备用编码
53
53
 
54
54
  内置片段增加 VP8/Opus WebM,与原 MP4 保持同一内容;上传相同文件时通过内容哈希匹配备用编码。浏览器可以选择可用编码,媒体加载失败会尝试另一源,预览不再自动跳到 0.8 秒。核心 22 项通过;通过 HTTPS 网关访问已保存的视频,桌面和手机模拟视口均确认时间前进及可见动画,并验证屏蔽 WebM 后 MP4 回退仍正常。尚未在用户出现故障的实际设备上复现其原始错误。
55
+
56
+ ## 2026-11-13 — third-theme compatibility release 0.3.1
57
+
58
+ The legacy compatibility entry and the integrated bundle share the same root-scoped `client-v2` and `host-v2` leases. The first loaded entry owns the manager. Version0.3.0 only knew Rose/Miku and rejected a Skirk provider if it loaded before the new bundle.
59
+
60
+ The standalone core now mirrors the bundle's three-theme controller, UI, catalog/assets/preview routes, startup-video store/player and theme preferences. Its own package identity, migration command and shared lease entries remain. README now requires compatibility entry0.3.1+ for the three-theme suite; new users still install only the theme bundle.
61
+
62
+ Regression evidence: test/skirk-compat.test.mjs evaluates both independently built client bundles in one DOM, loads the standalone manager first, then registers all three theme providers. It verifies exactly one shared client, selected Skirk, continued service after the first lease is removed, and release after the last lease. An HTTP test verifies all three bundled themes, Skirk artwork/font/preview routes and independent Skirk mobile fit settings. These are contract/JSDOM/HTTP checks, not a full DSH browser install.
63
+
64
+ Full manager suite:22 passed,0 failed,2 existing native-runtime tests skipped because DSH_MODULES was not supplied. Log: work/rose-queen-release/manager-compat-tests.log.
package/lib/client.js CHANGED
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // src/client-entry.mjs
30
+ // work/rose-queen-release/manager-publish/src/client-entry.mjs
31
31
  var client_entry_exports = {};
32
32
  __export(client_entry_exports, {
33
33
  acquireClient: () => acquireClient,
@@ -36,13 +36,13 @@ __export(client_entry_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(client_entry_exports);
38
38
 
39
- // src/client.jsx
39
+ // work/rose-queen-release/manager-publish/src/client.jsx
40
40
  var import_react2 = __toESM(require("react"), 1);
41
41
 
42
- // src/video-settings.jsx
42
+ // work/rose-queen-release/manager-publish/src/video-settings.jsx
43
43
  var import_react = __toESM(require("react"), 1);
44
44
 
45
- // src/boot-player.mjs
45
+ // work/rose-queen-release/manager-publish/src/boot-player.mjs
46
46
  var BOOT_CSS = `
47
47
  .ekko-boot{position:fixed;inset:0;z-index:2147483000;display:grid;place-items:center;background:#10171e;color:#fff;opacity:1;isolation:isolate;font:14px/1.5 system-ui,sans-serif}
48
48
  .ekko-boot[data-skin="rose"]{background:#241a20;--boot-accent:#f3b3c6}.ekko-boot[data-skin="miku"]{--boot-accent:#81eff0}
@@ -255,7 +255,7 @@ function playBoot(skin, options, { preview = false } = {}) {
255
255
  return done;
256
256
  }
257
257
 
258
- // src/video-settings.jsx
258
+ // work/rose-queen-release/manager-publish/src/video-settings.jsx
259
259
  var API = "./api/ekko-skins/";
260
260
  var LIMIT = 96 * 1024 * 1024;
261
261
  var fields = (entry) => Object.fromEntries(["enabled", "sound", "volume", "fit", "maxSeconds"].map((k) => [k, entry[k]]));
@@ -379,7 +379,7 @@ function VideoSettings({ skin }) {
379
379
  };
380
380
  if (!data || !draft) return /* @__PURE__ */ import_react.default.createElement("section", { className: "ekko-skin-options ekko-video-settings", "data-testid": "ekko-video-settings" }, /* @__PURE__ */ import_react.default.createElement("h3", null, "\u542F\u52A8\u89C6\u9891"), /* @__PURE__ */ import_react.default.createElement("p", { role: "status" }, message || "\u6B63\u5728\u8BFB\u53D6\u89C6\u9891\u8BBE\u7F6E\u2026"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: load }, "\u91CD\u8BD5"));
381
381
  const update = (patch) => setDraft({ ...draft, ...patch }), fitKey = device === "mobile" ? "mobileFit" : "fit";
382
- return /* @__PURE__ */ import_react.default.createElement("section", { className: "ekko-skin-options ekko-video-settings", "data-testid": "ekko-video-settings", "data-device": device }, /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react.default.createElement("h3", null, skin === "miku" ? "\u521D\u97F3\u672A\u6765" : "\u6709\u83DC\u73AB\u7470", " \xB7 \u542F\u52A8\u89C6\u9891"), /* @__PURE__ */ import_react.default.createElement("span", { className: "ekko-skin-version" }, "\u6BCF\u6B3E\u4E3B\u9898\u5206\u522B\u4FDD\u5B58")), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-controls" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u542F\u7528\u542F\u52A8\u89C6\u9891", /* @__PURE__ */ import_react.default.createElement("small", null, "\u9875\u9762\u542F\u52A8\u65F6\u64AD\u653E\uFF0C\u53EF\u968F\u65F6\u8DF3\u8FC7")), /* @__PURE__ */ import_react.default.createElement("input", { type: "checkbox", checked: draft.enabled, disabled: busy, onChange: (e) => update({ enabled: e.target.checked }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64AD\u653E\u58F0\u97F3", /* @__PURE__ */ import_react.default.createElement("small", null, "\u6D4F\u89C8\u5668\u9650\u5236\u81EA\u52A8\u64AD\u653E\u65F6\u5148\u9759\u97F3\uFF0C\u70B9\u51FB\u53EF\u5F00\u542F\u58F0\u97F3")), /* @__PURE__ */ import_react.default.createElement("input", { type: "checkbox", checked: draft.sound, disabled: busy, onChange: (e) => update({ sound: e.target.checked }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u97F3\u91CF", /* @__PURE__ */ import_react.default.createElement("small", null, Math.round(draft.volume * 100), "%")), /* @__PURE__ */ import_react.default.createElement("input", { type: "range", min: "0", max: "100", value: Math.round(draft.volume * 100), disabled: busy, onChange: (e) => update({ volume: Number(e.target.value) / 100 }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u6700\u957F\u64AD\u653E\u65F6\u95F4", /* @__PURE__ */ import_react.default.createElement("small", null, "5\u201360 \u79D2\uFF0C\u5230\u65F6\u81EA\u52A8\u8FDB\u5165\u754C\u9762")), /* @__PURE__ */ import_react.default.createElement("input", { className: "ekko-video-seconds", type: "number", min: "5", max: "60", value: draft.maxSeconds, disabled: busy, onChange: (e) => update({ maxSeconds: Number(e.target.value) }) }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-device-tabs", role: "tablist", "aria-label": "\u542F\u52A8\u89C6\u9891\u5C4F\u5E55\u7C7B\u578B" }, ["desktop", "mobile"].map((value) => /* @__PURE__ */ import_react.default.createElement("button", { key: value, type: "button", role: "tab", id: "ekko-video-tab-" + skin + "-" + value, "aria-selected": device === value, "aria-controls": "ekko-video-panel-" + skin, disabled: busy, className: "ekko-skin-button", "data-active": device === value, onClick: () => {
382
+ return /* @__PURE__ */ import_react.default.createElement("section", { className: "ekko-skin-options ekko-video-settings", "data-testid": "ekko-video-settings", "data-device": device }, /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react.default.createElement("h3", null, skin === "skirk" ? "\u4E1D\u67EF\u514B \xB7 \u78F7\u661F\u73AF\u8F68" : skin === "miku" ? "\u521D\u97F3\u672A\u6765" : "\u73AB\u7470\u5973\u738B", " \xB7 \u542F\u52A8\u89C6\u9891"), /* @__PURE__ */ import_react.default.createElement("span", { className: "ekko-skin-version" }, "\u6BCF\u6B3E\u4E3B\u9898\u5206\u522B\u4FDD\u5B58")), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-controls" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u542F\u7528\u542F\u52A8\u89C6\u9891", /* @__PURE__ */ import_react.default.createElement("small", null, "\u9875\u9762\u542F\u52A8\u65F6\u64AD\u653E\uFF0C\u53EF\u968F\u65F6\u8DF3\u8FC7")), /* @__PURE__ */ import_react.default.createElement("input", { type: "checkbox", checked: draft.enabled, disabled: busy, onChange: (e) => update({ enabled: e.target.checked }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64AD\u653E\u58F0\u97F3", /* @__PURE__ */ import_react.default.createElement("small", null, "\u6D4F\u89C8\u5668\u9650\u5236\u81EA\u52A8\u64AD\u653E\u65F6\u5148\u9759\u97F3\uFF0C\u70B9\u51FB\u53EF\u5F00\u542F\u58F0\u97F3")), /* @__PURE__ */ import_react.default.createElement("input", { type: "checkbox", checked: draft.sound, disabled: busy, onChange: (e) => update({ sound: e.target.checked }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u97F3\u91CF", /* @__PURE__ */ import_react.default.createElement("small", null, Math.round(draft.volume * 100), "%")), /* @__PURE__ */ import_react.default.createElement("input", { type: "range", min: "0", max: "100", value: Math.round(draft.volume * 100), disabled: busy, onChange: (e) => update({ volume: Number(e.target.value) / 100 }) })), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u6700\u957F\u64AD\u653E\u65F6\u95F4", /* @__PURE__ */ import_react.default.createElement("small", null, "5\u201360 \u79D2\uFF0C\u5230\u65F6\u81EA\u52A8\u8FDB\u5165\u754C\u9762")), /* @__PURE__ */ import_react.default.createElement("input", { className: "ekko-video-seconds", type: "number", min: "5", max: "60", value: draft.maxSeconds, disabled: busy, onChange: (e) => update({ maxSeconds: Number(e.target.value) }) }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-device-tabs", role: "tablist", "aria-label": "\u542F\u52A8\u89C6\u9891\u5C4F\u5E55\u7C7B\u578B" }, ["desktop", "mobile"].map((value) => /* @__PURE__ */ import_react.default.createElement("button", { key: value, type: "button", role: "tab", id: "ekko-video-tab-" + skin + "-" + value, "aria-selected": device === value, "aria-controls": "ekko-video-panel-" + skin, disabled: busy, className: "ekko-skin-button", "data-active": device === value, onClick: () => {
383
383
  setDevice(value);
384
384
  setMessage("");
385
385
  } }, value === "mobile" ? "\u624B\u673A\u7AEF\u89C6\u9891" : "\u7535\u8111\u7AEF\u89C6\u9891"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-device-panel", role: "tabpanel", id: "ekko-video-panel-" + skin, "aria-labelledby": "ekko-video-tab-" + skin + "-" + device }, /* @__PURE__ */ import_react.default.createElement("p", { className: "ekko-skin-version" }, device === "mobile" ? "\u624B\u673A\u53CA\u7A84\u5C4F\u81EA\u52A8\u4F7F\u7528\u6B64\u89C6\u9891\uFF0C\u63A8\u8350 9:16 \u7AD6\u5C4F\uFF1B\u672A\u4E0A\u4F20\u65F6\u6CBF\u7528\u7535\u8111\u7AEF\u89C6\u9891\u3002" : "\u7535\u8111\u53CA\u5BBD\u5C4F\u4F7F\u7528\u6B64\u89C6\u9891\uFF0C\u63A8\u8350 16:9 \u6A2A\u5C4F\u3002", "\u652F\u6301\u5176\u4ED6\u5206\u8FA8\u7387\u4E0E\u6BD4\u4F8B\u3002"), /* @__PURE__ */ import_react.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react.default.createElement("span", null, device === "mobile" ? "\u624B\u673A\u7AEF" : "\u7535\u8111\u7AEF", "\u753B\u9762\u663E\u793A"), /* @__PURE__ */ import_react.default.createElement("select", { "aria-label": (device === "mobile" ? "\u624B\u673A\u7AEF" : "\u7535\u8111\u7AEF") + "\u753B\u9762\u663E\u793A", value: draft[fitKey], disabled: busy, onChange: (e) => update({ [fitKey]: e.target.value }) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "cover" }, "\u94FA\u6EE1\u5C4F\u5E55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "contain" }, "\u5B8C\u6574\u663E\u793A"))), /* @__PURE__ */ import_react.default.createElement("video", { key: device + source, ref: preview, className: "ekko-video-preview", "data-device": device, muted: !draft.sound, controls: true, playsInline: true, preload: "metadata", onLoadedMetadata: () => setMediaError(""), onError: (e) => {
@@ -390,9 +390,9 @@ function VideoSettings({ skin }) {
390
390
  }, src: source, "aria-label": (device === "mobile" ? "\u624B\u673A\u7AEF" : "\u7535\u8111\u7AEF") + "\u542F\u52A8\u89C6\u9891\u9884\u89C8" }), /* @__PURE__ */ import_react.default.createElement("p", { className: "ekko-video-name" }, entry.source === "upload" ? entry.name : entry.source === "fallback" ? "\u6CBF\u7528\u7535\u8111\u7AEF\u89C6\u9891" + (base.name ? " \xB7 " + base.name : "") : "\u9ED8\u8BA4\u542F\u52A8\u89C6\u9891"), mediaError && /* @__PURE__ */ import_react.default.createElement("p", { className: "ekko-video-message", role: "status" }, mediaError)), /* @__PURE__ */ import_react.default.createElement("p", { className: "ekko-skin-version" }, "\u652F\u6301 MP4 / WebM\uFF0C\u6BCF\u4E2A\u89C6\u9891\u6700\u5927 96 MiB\u3002\u7535\u8111\u7AEF\u4E0E\u624B\u673A\u7AEF\u5206\u522B\u4FDD\u5B58\uFF0C\u53EF\u5728\u5F53\u524D DSH \u7684\u5176\u4ED6\u8BBE\u5907\u4E0A\u4F7F\u7528\u3002"), /* @__PURE__ */ import_react.default.createElement("input", { ref: input, className: "ekko-video-file", tabIndex: "-1", type: "file", accept: "video/mp4,video/webm,.mp4,.webm", disabled: busy, "aria-label": "\u4E0A\u4F20" + (device === "mobile" ? "\u624B\u673A\u7AEF" : "\u7535\u8111\u7AEF") + "\u542F\u52A8\u89C6\u9891", onChange: (e) => void upload(e.target.files?.[0]) }), progress !== null && /* @__PURE__ */ import_react.default.createElement("div", { role: "status" }, /* @__PURE__ */ import_react.default.createElement("progress", { max: "100", value: progress }), /* @__PURE__ */ import_react.default.createElement("span", null, " \u4E0A\u4F20 ", progress, "%"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: () => operation.current?.abort() }, "\u53D6\u6D88\u4E0A\u4F20")), /* @__PURE__ */ import_react.default.createElement("div", { className: "ekko-video-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: busy, onClick: () => input.current?.click() }, "\u4E0A\u4F20", device === "mobile" ? "\u624B\u673A\u7AEF" : "\u7535\u8111\u7AEF", "\u89C6\u9891"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: busy, onClick: () => void playBoot(skin, { ...entry, ...fields(draft), fit: draft[fitKey] }, { preview: true }) }, "\u9884\u89C8\u542F\u52A8\u6548\u679C"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: busy || entry.source !== "upload", onClick: () => void save(true) }, device === "mobile" ? "\u6CBF\u7528\u7535\u8111\u7AEF\u89C6\u9891" : "\u6062\u590D\u9ED8\u8BA4\u89C6\u9891"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "ekko-skin-button", "data-active": "true", disabled: busy, onClick: () => void save() }, "\u4FDD\u5B58\u542F\u52A8\u8BBE\u7F6E")), /* @__PURE__ */ import_react.default.createElement("p", { role: "status", className: "ekko-video-message" }, message));
391
391
  }
392
392
 
393
- // src/controller.mjs
393
+ // work/rose-queen-release/manager-publish/src/controller.mjs
394
394
  var SELECTION_KEY = "dsh:ekko-skins:selection:v1";
395
- var SKIN_IDS = ["default", "rose", "miku"];
395
+ var SKIN_IDS = ["default", "rose", "miku", "skirk"];
396
396
  function readSelection(storage, fallback = "rose") {
397
397
  try {
398
398
  const value = JSON.parse(storage.getItem(SELECTION_KEY));
@@ -474,7 +474,7 @@ function createController({ storage, mount, prepare = async () => {
474
474
  return () => listeners.delete(fn);
475
475
  },
476
476
  register(provider) {
477
- if (!["rose", "miku"].includes(provider.id) || typeof provider.plugin?.apply !== "function") throw new TypeError("Unknown Ekko skin provider");
477
+ if (!["rose", "miku", "skirk"].includes(provider.id) || typeof provider.plugin?.apply !== "function") throw new TypeError("Unknown Ekko skin provider");
478
478
  providers.set(provider.id, provider);
479
479
  publish({});
480
480
  if (initialized && provider.id === wanted) void reconcile();
@@ -514,10 +514,10 @@ function createController({ storage, mount, prepare = async () => {
514
514
  };
515
515
  }
516
516
 
517
- // src/generated.mjs
518
- var STYLES = ".ekko-skins{display:grid;gap:18px;color:var(--dsw-alias-label-primary);font:14px/1.6 var(--ds-font-family,system-ui);}\n.ekko-skins h2,.ekko-skins h3,.ekko-skins p{margin:0;}.ekko-skins h2{font-size:20px;line-height:1.5;}.ekko-skins h3{font-size:15px;}\n.ekko-skins-intro{display:grid;gap:5px;}.ekko-skins-intro p,.ekko-skin-version,.ekko-skin-option small{color:var(--dsw-alias-label-secondary);font-size:12px;}\n.ekko-skin-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;}\n.ekko-skin-card{min-width:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:var(--dsw-alias-bg-layer-1);box-shadow:0 4px 12px #234c6510;}\n.ekko-skin-card[data-active='true']{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsw-alias-brand-primary) 18%,transparent);}\n.ekko-skin-cover{display:block;width:100%;aspect-ratio:1400/787;object-fit:cover;border-bottom:1px solid var(--dsw-alias-border-l3);}\n.ekko-skin-description{display:grid;gap:10px;padding:13px;}.ekko-skin-title{display:flex;align-items:center;justify-content:space-between;gap:8px;}.ekko-skin-state{color:var(--dsw-alias-brand-text);font-size:11px;white-space:nowrap;}\n.ekko-skin-button{border:1px solid var(--dsw-alias-border-l2);border-radius:9px;padding:7px 12px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;}\n.ekko-skin-button:disabled{opacity:.65;cursor:default;}.ekko-skin-button:focus-visible,.ekko-skins input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;}\n.ekko-skin-button[data-active='true']{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary-invert);}\n.ekko-skin-option select{min-height:40px;max-width:52%;padding:6px 9px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;}\n.ekko-skin-option select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;}\n.ekko-skin-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;}.ekko-skin-options{padding:15px;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;background:var(--dsw-alias-bg-layer-1);}\n.ekko-skin-option{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:40px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l3);}.ekko-skin-option:last-child{border:0;}.ekko-skin-option span{display:grid;gap:2px;}.ekko-skin-option input{accent-color:var(--dsw-alias-brand-primary);}.ekko-skin-option input[type='range']{width:130px;max-width:40%;}.ekko-skin-error{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;color:var(--dsw-alias-state-danger,#c43d3d);font-size:13px;}\n@media(max-width:640px){.ekko-skin-grid{grid-template-columns:1fr;}.ekko-skins h2{font-size:18px;}.ekko-skin-toolbar{align-items:flex-start;}.ekko-skin-description{padding:12px;}}\n/* Keep the native settings shell usable on phones: tabs above the content. */\n@media(max-width:640px){\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']){flex-direction:column;width:calc(100vw - 24px);max-width:calc(100vw - 24px);height:min(800px,calc(100dvh - 48px));}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_nav']{width:100%;padding:15px 12px 0;gap:12px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navTitle']{padding-inline:5px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navList']{flex-direction:row;gap:4px;overflow:auto;padding-bottom:5px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navCell']{flex:none;width:max-content;height:36px;padding:7px 10px;font-size:13px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']{min-height:0;width:100%;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']>[class*='_header']{position:absolute;top:10px;right:10px;height:auto;padding:0;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']>[class*='_header'] button{white-space:nowrap;flex-shrink:0;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_options']{padding:12px 12px 18px;min-width:0;}\n .ekko-skins{gap:13px;width:100%;min-width:0;}\n .ekko-skin-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;}\n .ekko-skin-description{padding:9px;gap:7px;min-width:0;}.ekko-skin-title{gap:4px;flex-wrap:wrap;}.ekko-skin-title h3{font-size:13px;}.ekko-skin-state{font-size:10px;}\n .ekko-skin-button{font-size:12px;padding:6px;min-height:36px;max-width:100%;overflow-wrap:anywhere;}\n .ekko-skin-toolbar{flex-wrap:wrap;min-width:0;}.ekko-skin-options{min-width:0;padding:11px;}.ekko-skin-options .ekko-skin-toolbar h3{font-size:13px;}\n}\n\n.ekko-video-settings{display:grid;gap:10px;min-width:0}.ekko-video-settings .ekko-skin-option{margin:0}.ekko-video-preview{display:block;width:100%;max-height:160px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:#101820;object-fit:contain}.ekko-video-name{font-weight:500;overflow-wrap:anywhere}.ekko-video-file{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden;pointer-events:none}.ekko-video-file::file-selector-button{font:inherit;padding:8px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);margin-right:8px}.ekko-video-actions{display:flex;gap:8px;flex-wrap:wrap}.ekko-video-seconds{width:72px;padding:7px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:inherit;font:inherit}.ekko-video-settings progress{max-width:100%;accent-color:var(--dsw-alias-brand-primary)}.ekko-video-message{font-size:12px;overflow-wrap:anywhere}\n\n.ekko-video-controls{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 18px;min-width:0}.ekko-video-controls .ekko-skin-option{min-width:0;gap:10px}.ekko-video-controls .ekko-skin-option:last-child{grid-column:1/-1}.ekko-video-controls .ekko-skin-option span{min-width:0}.ekko-video-controls input[type=range]{width:100px}.ekko-video-actions .ekko-skin-button{min-height:40px}.ekko-video-settings{scroll-margin-top:12px}\n@media(max-width:640px){.ekko-video-controls{grid-template-columns:1fr}.ekko-video-preview{max-height:140px}.ekko-video-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.ekko-video-actions .ekko-skin-button{width:100%;min-height:42px}.ekko-video-settings .ekko-skin-option small{font-size:11px}}\n\n.ekko-video-device-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;padding:5px;border:1px solid var(--dsw-alias-border-l3);border-radius:13px;background:var(--dsw-alias-bg-layer-2)}\n.ekko-video-device-tabs .ekko-skin-button{min-height:40px;box-shadow:none;background:transparent;border-color:transparent}\n.ekko-video-device-tabs .ekko-skin-button[data-active='true']{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}\n.ekko-video-device-panel{display:grid;gap:8px;min-width:0}\n.ekko-video-preview[data-device='mobile']{width:100%;height:210px;max-height:210px;object-fit:contain}\n.ekko-video-device-tabs .ekko-skin-button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n.ekko-video-controls .ekko-skin-option:last-child{grid-column:auto}\n@media(max-width:640px){.ekko-video-preview[data-device='mobile']{height:200px;max-height:200px}.ekko-video-device-tabs{gap:4px;padding:4px}.ekko-video-device-tabs .ekko-skin-button{min-height:40px}}\n\n/* Both phone modes use the active skin's existing artwork and jewellery tokens. */\n.ekko-mobile-navigation{display:none;}\n@media(max-width:700px) and (orientation:portrait){\n body[data-ekko-mobile-nav] .ekko-mobile-navigation{position:fixed;z-index:65;display:flex;box-sizing:border-box;align-items:center;color:var(--dsw-alias-brand-primary);}\n body[data-ekko-mobile-nav] .ekko-mobile-brand,\n body[data-ekko-mobile-nav] .ekko-mobile-action{position:relative;display:flex;flex:none;align-items:center;justify-content:center;box-sizing:border-box;width:44px;height:44px;min-height:44px;padding:8px;border:1px solid var(--ekko-rim-soft);border-radius:14px;background:var(--ekko-panel);box-shadow:inset 0 1px 0 var(--ekko-shine),0 3px 8px var(--ekko-shadow);color:inherit;cursor:pointer;}\n body[data-ekko-mobile-nav] .ekko-mobile-brand{padding:6px;border-color:var(--ekko-rim);}\n body[data-ekko-mobile-nav] .ekko-mobile-brand img{display:block;width:31px;height:31px;object-fit:contain;}\n body[data-ekko-mobile-nav] .ekko-mobile-action :is(svg,img){width:21px;height:21px;flex:none;}\n body[data-ekko-mobile-nav] .ekko-mobile-action[data-ekko-mobile-action='new']{margin-top:4px;border-color:var(--ekko-rim);box-shadow:inset 0 0 0 2px var(--ekko-shine),0 3px 8px var(--ekko-shadow);}\n body[data-ekko-mobile-nav] .ekko-mobile-action[aria-current]{background:var(--ekko-tint);border-color:var(--ekko-rim);}\n body[data-ekko-mobile-nav] .ekko-mobile-action:disabled{opacity:.45;cursor:default;}\n body[data-ekko-mobile-nav] .ekko-mobile-navigation button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;}\n body[data-ekko-mobile-nav] .ekko-mobile-navigation button:active{box-shadow:inset 1px 2px 5px var(--ekko-shadow);}\n body[data-ekko-mobile-nav='corner'] .ekko-mobile-navigation{top:calc(env(safe-area-inset-top,0px) + 7px);left:9px;}\n body[data-ekko-mobile-nav='corner'] :is(.ekko-mobile-actions,.ekko-mobile-footer){display:none;}\n /* Set clearance on the content column so native drawer/platform frame rules cannot override it. */\n body[data-ekko-mobile-nav='corner'] [data-ekko-mobile-frame] [data-ekko-mobile-center]{--dsh-frame-leading-clearance:62px;}\n body[data-ekko-mobile-nav='corner'] :is(.miku-welcome-brand,.rose-welcome-brand){padding-left:48px;}\n body[data-ekko-mobile-nav='corner'] :is(.miku-mark,.rose-mark){display:none;}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-navigation{inset:0 auto 0 0;width:60px;flex-direction:column;gap:10px;padding:calc(env(safe-area-inset-top,0px) + 13px) 7px max(10px,env(safe-area-inset-bottom,0px));background:var(--ekko-panel);border-right:1px solid var(--ekko-rim);box-shadow:inset -2px 0 0 var(--ekko-shine),inset -4px 0 0 var(--ekko-rim-soft);}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-actions{display:flex;flex:1;min-height:0;flex-direction:column;gap:10px;padding:0 0 4px;overflow:auto;scrollbar-width:none;}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-footer{display:flex;flex:none;padding-top:5px;border-top:1px solid var(--ekko-rim-soft);}\n body[data-ekko-mobile-nav='rail'] [data-ekko-mobile-frame] [data-ekko-mobile-center]{margin-inline-start:60px;--dsh-frame-leading-clearance:0px;}\n /* The native drawer stays inert while closed. Only our launchers remain visible. */\n body[data-ekko-mobile-nav] [data-ekko-mobile-frame] [data-shell-leading]{display:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-frame] [data-ekko-mobile-drawer]{z-index:80;background:var(--ekko-panel);box-shadow:12px 0 30px var(--ekko-shadow);}\n body[data-ekko-mobile-nav][data-ekko-mobile-drawer-open='true'] .ekko-mobile-navigation{visibility:hidden;pointer-events:none;}\n}\n\n/* Keep phone controls aligned when the icon rail reduces the editor width. */\n@media(max-width:700px) and (orientation:portrait){\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] :is([data-miku-editor-root],[data-rose-editor-root]){width:calc(100% + 8px);margin-inline-start:-4px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]{container:ekko-composer / inline-size;gap:6px;padding-top:14px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] :is([data-miku-editor-root],[data-rose-editor-root]) [data-composer-card]{min-height:140px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_scroll']{flex:1;min-height:56px;margin-right:0;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [contenteditable]{padding-inline:12px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button[class*='_primary']{align-self:center;transform:none;}\n}\n@container ekko-composer (max-width:350px){\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_row']{display:grid;grid-template-columns:auto minmax(0,1fr) 30px 34px;grid-template-areas:'extras extras extras extras' 'tools model activity send';gap:4px 6px;padding:4px 7px 6px;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_row']:not(:has([data-slot='conversation.input.right']:not(:empty))){grid-template-areas:'tools model activity send';}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [class*='_tools']{grid-area:tools;gap:5px;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] :is([class*='_trailing'],[class*='_standardControls'],[class*='_modes']){display:contents;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] :is([class*='_tools'],[class*='_standardControls'])[hidden]{display:none!important;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [class*='_trailing']>[class*='_activity']{display:contents;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']{grid-area:extras;display:flex!important;align-items:center;justify-content:flex-start;gap:8px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:thin;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']:empty{display:none!important;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']>*{flex:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model']{grid-area:model;display:flex!important;min-width:0;justify-content:flex-end;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model']>div{min-width:0;max-width:100%;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] button{min-width:0;max-width:100%;height:34px;padding-inline:4px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] :is([class*='_triggerLabel'],[class*='_triggerEffort']){display:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] button>svg:first-child{display:block;flex:none;width:18px;height:18px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.activity']{grid-area:activity;display:flex!important;align-items:center;justify-content:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button[class*='_primary']{grid-area:send;justify-self:end;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button:is([aria-label^='\u8BBF\u95EE\u6A21\u5F0F'],[aria-label^='Access mode']){padding-inline:6px;}\n}\n";
517
+ // work/rose-queen-release/manager-publish/src/generated.mjs
518
+ var STYLES = ".ekko-skins{display:grid;gap:18px;color:var(--dsw-alias-label-primary);font:14px/1.6 var(--ds-font-family,system-ui);}\n.ekko-skins h2,.ekko-skins h3,.ekko-skins p{margin:0;}.ekko-skins h2{font-size:20px;line-height:1.5;}.ekko-skins h3{font-size:15px;}\n.ekko-skins-intro{display:grid;gap:5px;}.ekko-skins-intro p,.ekko-skin-version,.ekko-skin-option small{color:var(--dsw-alias-label-secondary);font-size:12px;}\n.ekko-skin-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:14px;}\n.ekko-skin-card{min-width:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:var(--dsw-alias-bg-layer-1);box-shadow:0 4px 12px #234c6510;}\n.ekko-skin-card[data-active='true']{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsw-alias-brand-primary) 18%,transparent);}\n.ekko-skin-cover{display:block;width:100%;aspect-ratio:1400/787;object-fit:cover;border-bottom:1px solid var(--dsw-alias-border-l3);}\n.ekko-skin-description{display:grid;gap:10px;padding:13px;}.ekko-skin-title{display:flex;align-items:center;justify-content:space-between;gap:8px;}.ekko-skin-state{color:var(--dsw-alias-brand-text);font-size:11px;white-space:nowrap;}\n.ekko-skin-button{border:1px solid var(--dsw-alias-border-l2);border-radius:9px;padding:7px 12px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;}\n.ekko-skin-button:disabled{opacity:.65;cursor:default;}.ekko-skin-button:focus-visible,.ekko-skins input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;}\n.ekko-skin-button[data-active='true']{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary-invert);}\n.ekko-skin-option select{min-height:40px;max-width:52%;padding:6px 9px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;}\n.ekko-skin-option select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px;}\n.ekko-skin-toolbar{display:flex;align-items:center;justify-content:space-between;gap:12px;}.ekko-skin-options{padding:15px;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;background:var(--dsw-alias-bg-layer-1);}\n.ekko-skin-option{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:40px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l3);}.ekko-skin-option:last-child{border:0;}.ekko-skin-option span{display:grid;gap:2px;}.ekko-skin-option input{accent-color:var(--dsw-alias-brand-primary);}.ekko-skin-option input[type='range']{width:130px;max-width:40%;}.ekko-skin-error{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;color:var(--dsw-alias-state-danger,#c43d3d);font-size:13px;}\n@media(max-width:640px){.ekko-skin-grid{grid-template-columns:1fr;}.ekko-skins h2{font-size:18px;}.ekko-skin-toolbar{align-items:flex-start;}.ekko-skin-description{padding:12px;}}\n/* Keep the native settings shell usable on phones: tabs above the content. */\n@media(max-width:640px){\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']){flex-direction:column;width:calc(100vw - 24px);max-width:calc(100vw - 24px);height:min(800px,calc(100dvh - 48px));}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_nav']{width:100%;padding:15px 12px 0;gap:12px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navTitle']{padding-inline:5px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navList']{flex-direction:row;gap:4px;overflow:auto;padding-bottom:5px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_navCell']{flex:none;width:max-content;height:36px;padding:7px 10px;font-size:13px;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']{min-height:0;width:100%;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']>[class*='_header']{position:absolute;top:10px;right:10px;height:auto;padding:0;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList'])>[class*='_content']>[class*='_header'] button{white-space:nowrap;flex-shrink:0;}\n [role='dialog']:has(>[class*='_nav']>[class*='_navList']) [class*='_options']{padding:12px 12px 18px;min-width:0;}\n .ekko-skins{gap:13px;width:100%;min-width:0;}\n .ekko-skin-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:10px;}\n .ekko-skin-description{padding:9px;gap:7px;min-width:0;}.ekko-skin-title{gap:4px;flex-wrap:wrap;}.ekko-skin-title h3{font-size:13px;}.ekko-skin-state{font-size:10px;}\n .ekko-skin-button{font-size:12px;padding:6px;min-height:36px;max-width:100%;overflow-wrap:anywhere;}\n .ekko-skin-toolbar{flex-wrap:wrap;min-width:0;}.ekko-skin-options{min-width:0;padding:11px;}.ekko-skin-options .ekko-skin-toolbar h3{font-size:13px;}\n}\n\n.ekko-video-settings{display:grid;gap:10px;min-width:0}.ekko-video-settings .ekko-skin-option{margin:0}.ekko-video-preview{display:block;width:100%;max-height:160px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:#101820;object-fit:contain}.ekko-video-name{font-weight:500;overflow-wrap:anywhere}.ekko-video-file{position:absolute;width:1px;height:1px;opacity:0;overflow:hidden;pointer-events:none}.ekko-video-file::file-selector-button{font:inherit;padding:8px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);margin-right:8px}.ekko-video-actions{display:flex;gap:8px;flex-wrap:wrap}.ekko-video-seconds{width:72px;padding:7px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:inherit;font:inherit}.ekko-video-settings progress{max-width:100%;accent-color:var(--dsw-alias-brand-primary)}.ekko-video-message{font-size:12px;overflow-wrap:anywhere}\n\n.ekko-video-controls{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:0 18px;min-width:0}.ekko-video-controls .ekko-skin-option{min-width:0;gap:10px}.ekko-video-controls .ekko-skin-option:last-child{grid-column:1/-1}.ekko-video-controls .ekko-skin-option span{min-width:0}.ekko-video-controls input[type=range]{width:100px}.ekko-video-actions .ekko-skin-button{min-height:40px}.ekko-video-settings{scroll-margin-top:12px}\n@media(max-width:640px){.ekko-video-controls{grid-template-columns:1fr}.ekko-video-preview{max-height:140px}.ekko-video-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:8px}.ekko-video-actions .ekko-skin-button{width:100%;min-height:42px}.ekko-video-settings .ekko-skin-option small{font-size:11px}}\n\n.ekko-video-device-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:6px;padding:5px;border:1px solid var(--dsw-alias-border-l3);border-radius:13px;background:var(--dsw-alias-bg-layer-2)}\n.ekko-video-device-tabs .ekko-skin-button{min-height:40px;box-shadow:none;background:transparent;border-color:transparent}\n.ekko-video-device-tabs .ekko-skin-button[data-active='true']{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}\n.ekko-video-device-panel{display:grid;gap:8px;min-width:0}\n.ekko-video-preview[data-device='mobile']{width:100%;height:210px;max-height:210px;object-fit:contain}\n.ekko-video-device-tabs .ekko-skin-button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n.ekko-video-controls .ekko-skin-option:last-child{grid-column:auto}\n@media(max-width:640px){.ekko-video-preview[data-device='mobile']{height:200px;max-height:200px}.ekko-video-device-tabs{gap:4px;padding:4px}.ekko-video-device-tabs .ekko-skin-button{min-height:40px}}\n\n/* Both phone modes use the active skin's existing artwork and jewellery tokens. */\n.ekko-mobile-navigation{display:none;}\n@media(max-width:700px) and (orientation:portrait){\n body[data-ekko-mobile-nav] .ekko-mobile-navigation{position:fixed;z-index:65;display:flex;box-sizing:border-box;align-items:center;color:var(--dsw-alias-brand-primary);}\n body[data-ekko-mobile-nav] .ekko-mobile-brand,\n body[data-ekko-mobile-nav] .ekko-mobile-action{position:relative;display:flex;flex:none;align-items:center;justify-content:center;box-sizing:border-box;width:44px;height:44px;min-height:44px;padding:8px;border:1px solid var(--ekko-rim-soft);border-radius:14px;background:var(--ekko-panel);box-shadow:inset 0 1px 0 var(--ekko-shine),0 3px 8px var(--ekko-shadow);color:inherit;cursor:pointer;}\n body[data-ekko-mobile-nav] .ekko-mobile-brand{padding:6px;border-color:var(--ekko-rim);}\n body[data-ekko-mobile-nav] .ekko-mobile-brand img{display:block;width:31px;height:31px;object-fit:contain;}\n body[data-ekko-mobile-nav] .ekko-mobile-action :is(svg,img){width:21px;height:21px;flex:none;}\n body[data-ekko-mobile-nav] .ekko-mobile-action[data-ekko-mobile-action='new']{margin-top:4px;border-color:var(--ekko-rim);box-shadow:inset 0 0 0 2px var(--ekko-shine),0 3px 8px var(--ekko-shadow);}\n body[data-ekko-mobile-nav] .ekko-mobile-action[aria-current]{background:var(--ekko-tint);border-color:var(--ekko-rim);}\n body[data-ekko-mobile-nav] .ekko-mobile-action:disabled{opacity:.45;cursor:default;}\n body[data-ekko-mobile-nav] .ekko-mobile-navigation button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;}\n body[data-ekko-mobile-nav] .ekko-mobile-navigation button:active{box-shadow:inset 1px 2px 5px var(--ekko-shadow);}\n body[data-ekko-mobile-nav='corner'] .ekko-mobile-navigation{top:calc(env(safe-area-inset-top,0px) + 7px);left:9px;}\n body[data-ekko-mobile-nav='corner'] :is(.ekko-mobile-actions,.ekko-mobile-footer){display:none;}\n /* Set clearance on the content column so native drawer/platform frame rules cannot override it. */\n body[data-ekko-mobile-nav='corner'] [data-ekko-mobile-frame] [data-ekko-mobile-center]{--dsh-frame-leading-clearance:62px;}\n body[data-ekko-mobile-nav='corner'] :is(.miku-welcome-brand,.rose-welcome-brand){padding-left:48px;}\n body[data-ekko-mobile-nav='corner'] :is(.miku-mark,.rose-mark){display:none;}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-navigation{inset:0 auto 0 0;width:60px;flex-direction:column;gap:10px;padding:calc(env(safe-area-inset-top,0px) + 13px) 7px max(10px,env(safe-area-inset-bottom,0px));background:var(--ekko-panel);border-right:1px solid var(--ekko-rim);box-shadow:inset -2px 0 0 var(--ekko-shine),inset -4px 0 0 var(--ekko-rim-soft);}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-actions{display:flex;flex:1;min-height:0;flex-direction:column;gap:10px;padding:0 0 4px;overflow:auto;scrollbar-width:none;}\n body[data-ekko-mobile-nav='rail'] .ekko-mobile-footer{display:flex;flex:none;padding-top:5px;border-top:1px solid var(--ekko-rim-soft);}\n body[data-ekko-mobile-nav='rail'] [data-ekko-mobile-frame] [data-ekko-mobile-center]{margin-inline-start:60px;--dsh-frame-leading-clearance:0px;}\n /* The native drawer stays inert while closed. Only our launchers remain visible. */\n body[data-ekko-mobile-nav] [data-ekko-mobile-frame] [data-shell-leading]{display:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-frame] [data-ekko-mobile-drawer]{z-index:80;background:var(--ekko-panel);box-shadow:12px 0 30px var(--ekko-shadow);}\n body[data-ekko-mobile-nav][data-ekko-mobile-drawer-open='true'] .ekko-mobile-navigation{visibility:hidden;pointer-events:none;}\n}\n\n/* Keep phone controls aligned when the icon rail reduces the editor width. */\n@media(max-width:700px) and (orientation:portrait){\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] :is([data-miku-editor-root],[data-rose-editor-root]){width:calc(100% + 8px);margin-inline-start:-4px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]{container:ekko-composer / inline-size;gap:6px;padding-top:14px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] :is([data-miku-editor-root],[data-rose-editor-root]) [data-composer-card]{min-height:140px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_scroll']{flex:1;min-height:56px;margin-right:0;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [contenteditable]{padding-inline:12px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button[class*='_primary']{align-self:center;transform:none;}\n}\n@container ekko-composer (max-width:350px){\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_row']{display:grid;grid-template-columns:auto minmax(0,1fr) 30px 34px;grid-template-areas:'extras extras extras extras' 'tools model activity send';gap:4px 6px;padding:4px 7px 6px;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card]>[class*='_row']:not(:has([data-slot='conversation.input.right']:not(:empty))){grid-template-areas:'tools model activity send';}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [class*='_tools']{grid-area:tools;gap:5px;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] :is([class*='_trailing'],[class*='_standardControls'],[class*='_modes']){display:contents;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] :is([class*='_tools'],[class*='_standardControls'])[hidden]{display:none!important;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] [class*='_trailing']>[class*='_activity']{display:contents;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']{grid-area:extras;display:flex!important;align-items:center;justify-content:flex-start;gap:8px;min-width:0;max-width:100%;overflow-x:auto;scrollbar-width:thin;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']:empty{display:none!important;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.right']>*{flex:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model']{grid-area:model;display:flex!important;min-width:0;justify-content:flex-end;align-items:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model']>div{min-width:0;max-width:100%;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] button{min-width:0;max-width:100%;height:34px;padding-inline:4px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] :is([class*='_triggerLabel'],[class*='_triggerEffort']){display:none;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.model'] button>svg:first-child{display:block;flex:none;width:18px;height:18px;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-slot='conversation.input.activity']{grid-area:activity;display:flex!important;align-items:center;justify-content:center;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button[class*='_primary']{grid-area:send;justify-self:end;}\n body[data-ekko-mobile-nav] [data-ekko-mobile-center] [data-composer-card] button:is([aria-label^='\u8BBF\u95EE\u6A21\u5F0F'],[aria-label^='Access mode']){padding-inline:6px;}\n}\n";
519
519
 
520
- // src/mobile-navigation.mjs
520
+ // work/rose-queen-release/manager-publish/src/mobile-navigation.mjs
521
521
  function createMobileNavigation({ layout, document: doc = document }) {
522
522
  const view = doc.defaultView, body = doc.body;
523
523
  let current = null, nav, brand, actions, footer, frame, sidebar, center, raf = 0, disposed = false;
@@ -703,12 +703,12 @@ function createMobileNavigation({ layout, document: doc = document }) {
703
703
  };
704
704
  }
705
705
 
706
- // src/client.jsx
706
+ // work/rose-queen-release/manager-publish/src/client.jsx
707
707
  var inject = ["slots", "theme", "layout"];
708
- var NAMES = { rose: { zh: "\u6709\u83DC\u73AB\u7470", en: "Arina Rose" }, miku: { zh: "\u521D\u97F3\u672A\u6765", en: "Hatsune Miku" } };
708
+ var NAMES = { rose: { zh: "\u73AB\u7470\u5973\u738B", en: "Rose Queen" }, miku: { zh: "\u521D\u97F3\u672A\u6765", en: "Hatsune Miku" }, skirk: { zh: "\u4E1D\u67EF\u514B \xB7 \u78F7\u661F\u73AF\u8F68", en: "Skirk \xB7 Stellar Orbit" } };
709
709
  var COPY = {
710
- zh: { nav: "Ekko \u76AE\u80A4", title: "\u73AB\u7470\u4E0E\u521D\u97F3", intro: "\u9009\u62E9\u4F60\u7684\u521B\u4F5C\u7A7A\u95F4\uFF1B\u6BCF\u4E2A\u4E3B\u9898\u7684\u88C5\u9970\u504F\u597D\u5206\u522B\u4FDD\u7559\u3002", use: "\u4F7F\u7528", active: "\u5F53\u524D\u4F7F\u7528", switching: "\u6B63\u5728\u5207\u6362\u2026", native: "\u539F\u751F\u754C\u9762", options: "\u4E3B\u9898\u88C5\u9970", artwork: "\u6B22\u8FCE\u9875\u88C5\u9970", companion: "\u5BF9\u8BDD\u4EBA\u7269\u80CC\u666F", polaroid: "\u53F3\u4E0B\u89D2\u7167\u7247", opacity: "\u5BF9\u8BDD\u80CC\u666F\u6D53\u5EA6", reset: "\u6062\u590D\u6B64\u4E3B\u9898\u9ED8\u8BA4", loading: "\u6B63\u5728\u52A0\u8F7D\u4E3B\u9898\u2026", unavailable: "\u53EF\u9009\u4E3B\u9898\uFF0C\u5C1A\u672A\u5B89\u88C5", retry: "\u91CD\u8BD5", loadFailed: "\u76AE\u80A4\u7BA1\u7406\u5668\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u8BD5\u3002", materialFailed: "\u4E3B\u9898\u7D20\u6750\u672A\u80FD\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u8BD5\u3002" },
711
- en: { nav: "Ekko skins", title: "Rose & Miku", intro: "Choose your creative space. Each skin keeps its own appearance preferences.", use: "Use", active: "In use", switching: "Switching\u2026", native: "Native appearance", options: "Artwork preferences", artwork: "Welcome artwork", companion: "Chat character background", polaroid: "Corner photo", opacity: "Chat background opacity", reset: "Reset this skin", loading: "Loading skins\u2026", unavailable: "Optional skin, not installed", retry: "Retry", loadFailed: "Unable to load the skin manager. Please retry.", materialFailed: "Unable to load the skin artwork. Please retry." }
710
+ zh: { nav: "Ekko \u76AE\u80A4", title: "Ekko \u521B\u4F5C\u7A7A\u95F4", intro: "\u9009\u62E9\u4F60\u7684\u521B\u4F5C\u7A7A\u95F4\uFF1B\u6BCF\u4E2A\u4E3B\u9898\u7684\u88C5\u9970\u504F\u597D\u5206\u522B\u4FDD\u7559\u3002", use: "\u4F7F\u7528", active: "\u5F53\u524D\u4F7F\u7528", switching: "\u6B63\u5728\u5207\u6362\u2026", native: "\u539F\u751F\u754C\u9762", options: "\u4E3B\u9898\u88C5\u9970", artwork: "\u6B22\u8FCE\u9875\u88C5\u9970", companion: "\u5BF9\u8BDD\u4EBA\u7269\u80CC\u666F", polaroid: "\u53F3\u4E0B\u89D2\u7167\u7247", opacity: "\u5BF9\u8BDD\u80CC\u666F\u6D53\u5EA6", reset: "\u6062\u590D\u6B64\u4E3B\u9898\u9ED8\u8BA4", loading: "\u6B63\u5728\u52A0\u8F7D\u4E3B\u9898\u2026", unavailable: "\u53EF\u9009\u4E3B\u9898\uFF0C\u5C1A\u672A\u5B89\u88C5", retry: "\u91CD\u8BD5", loadFailed: "\u76AE\u80A4\u7BA1\u7406\u5668\u6682\u65F6\u65E0\u6CD5\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u8BD5\u3002", materialFailed: "\u4E3B\u9898\u7D20\u6750\u672A\u80FD\u52A0\u8F7D\uFF0C\u8BF7\u91CD\u8BD5\u3002" },
711
+ en: { nav: "Ekko skins", title: "Ekko creative spaces", intro: "Choose your creative space. Each skin keeps its own appearance preferences.", use: "Use", active: "In use", switching: "Switching\u2026", native: "Native appearance", options: "Artwork preferences", artwork: "Welcome artwork", companion: "Chat character background", polaroid: "Corner photo", opacity: "Chat background opacity", reset: "Reset this skin", loading: "Loading skins\u2026", unavailable: "Optional skin, not installed", retry: "Retry", loadFailed: "Unable to load the skin manager. Please retry.", materialFailed: "Unable to load the skin artwork. Please retry." }
712
712
  };
713
713
  var language = () => /^zh/i.test(document.documentElement.lang || navigator.language) ? "zh" : "en";
714
714
  function apply(ctx) {
@@ -808,10 +808,10 @@ function apply(ctx) {
808
808
  const choose = (target) => {
809
809
  void controller.choose(target);
810
810
  };
811
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "ekko-skins", "data-ekko-skin-manager": "", "aria-label": c.nav }, /* @__PURE__ */ import_react2.default.createElement("header", { className: "ekko-skins-intro" }, /* @__PURE__ */ import_react2.default.createElement("h2", null, c.title), /* @__PURE__ */ import_react2.default.createElement("p", null, c.intro)), state.error && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-error", role: "alert" }, state.error, " ", /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: load }, c.retry)), !state.catalog && !state.error && /* @__PURE__ */ import_react2.default.createElement("p", { role: "status" }, c.loading), /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-grid" }, ["rose", "miku"].map((skin) => {
811
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "ekko-skins", "data-ekko-skin-manager": "", "aria-label": c.nav }, /* @__PURE__ */ import_react2.default.createElement("header", { className: "ekko-skins-intro" }, /* @__PURE__ */ import_react2.default.createElement("h2", null, c.title), /* @__PURE__ */ import_react2.default.createElement("p", null, c.intro)), state.error && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-error", role: "alert" }, state.error, " ", /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: load }, c.retry)), !state.catalog && !state.error && /* @__PURE__ */ import_react2.default.createElement("p", { role: "status" }, c.loading), /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-grid" }, ["rose", "miku", "skirk"].map((skin) => {
812
812
  const entry = state.catalog?.skins.find((s) => s.id === skin), name = NAMES[skin][lang], active = id === skin, available = entry?.available && p.available.includes(skin);
813
813
  return /* @__PURE__ */ import_react2.default.createElement("article", { key: skin, className: "ekko-skin-card", "data-active": active }, entry?.preview && /* @__PURE__ */ import_react2.default.createElement("img", { className: "ekko-skin-cover", src: entry.preview[document.body.hasAttribute("data-ds-dark-theme") ? "dark" : "light"], alt: name, loading: "lazy" }), /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-description" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-title" }, /* @__PURE__ */ import_react2.default.createElement("h3", null, name), active && /* @__PURE__ */ import_react2.default.createElement("span", { className: "ekko-skin-state" }, c.active)), /* @__PURE__ */ import_react2.default.createElement("span", { className: "ekko-skin-version" }, entry?.version ? "v" + entry.version : c.unavailable), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", "data-active": active, disabled: !available || active || p.busy, onClick: () => choose(skin) }, p.busy && p.desired === skin ? c.switching : active ? c.active : c.use + " " + name)));
814
- })), /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react2.default.createElement("span", null, p.busy ? c.switching : id === "default" ? c.native : NAMES[id]?.[lang]), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: id === "default" || p.busy, onClick: () => choose("default") }, c.native)), p.error && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-error", role: "alert" }, p.error, /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: () => choose(p.desired) }, c.retry)), prefs && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-options" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react2.default.createElement("h3", null, NAMES[id][lang], " \xB7 ", c.options), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: p.busy, onClick: () => setPreference(id, { artwork: true, companion: true, polaroid: true, opacity: 0.12, mobileNav: "corner" }) }, c.reset)), /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react2.default.createElement("span", null, lang === "zh" ? "\u624B\u673A\u5BFC\u822A\u65B9\u5F0F" : "Phone navigation", /* @__PURE__ */ import_react2.default.createElement("small", null, lang === "zh" ? "\u7AD6\u5C4F\u624B\u673A\u751F\u6548\uFF0C\u4E24\u4E2A\u4E3B\u9898\u5206\u522B\u4FDD\u5B58" : "Portrait phones; saved separately for each skin")), /* @__PURE__ */ import_react2.default.createElement("select", { "aria-label": lang === "zh" ? "\u624B\u673A\u5BFC\u822A\u65B9\u5F0F" : "Phone navigation", value: prefs.mobileNav || "corner", disabled: p.busy, onChange: (e) => setPreference(id, { mobileNav: e.target.value }) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "corner" }, lang === "zh" ? "\u5DE6\u4E0A\u89D2\u6309\u94AE + \u62BD\u5C49" : "Corner button + drawer"), /* @__PURE__ */ import_react2.default.createElement("option", { value: "rail" }, lang === "zh" ? "\u5DE6\u4FA7\u7EB5\u5411\u56FE\u6807\u680F" : "Vertical icon rail"))), ["artwork", "companion", "polaroid"].map((key) => /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option", key }, /* @__PURE__ */ import_react2.default.createElement("span", null, c[key]), /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: prefs[key], disabled: p.busy, onChange: (e) => setPreference(id, { [key]: e.target.checked }) }))), /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react2.default.createElement("span", null, c.opacity, /* @__PURE__ */ import_react2.default.createElement("small", null, Math.round(prefs.opacity * 100), "%")), /* @__PURE__ */ import_react2.default.createElement("input", { type: "range", min: ".04", max: ".24", step: ".01", value: prefs.opacity, disabled: p.busy, onChange: (e) => setPreference(id, { opacity: Number(e.target.value) }) }))), prefs && /* @__PURE__ */ import_react2.default.createElement(VideoSettings, { key: id, skin: id }));
814
+ })), /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react2.default.createElement("span", null, p.busy ? c.switching : id === "default" ? c.native : NAMES[id]?.[lang]), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: id === "default" || p.busy, onClick: () => choose("default") }, c.native)), p.error && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-error", role: "alert" }, p.error, /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", onClick: () => choose(p.desired) }, c.retry)), prefs && /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-options" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "ekko-skin-toolbar" }, /* @__PURE__ */ import_react2.default.createElement("h3", null, NAMES[id][lang], " \xB7 ", c.options), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "ekko-skin-button", disabled: p.busy, onClick: () => setPreference(id, provider.defaults || { artwork: true, companion: true, polaroid: true, opacity: 0.12, mobileNav: "corner" }) }, c.reset)), /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react2.default.createElement("span", null, lang === "zh" ? "\u624B\u673A\u5BFC\u822A\u65B9\u5F0F" : "Phone navigation", /* @__PURE__ */ import_react2.default.createElement("small", null, lang === "zh" ? "\u7AD6\u5C4F\u624B\u673A\u751F\u6548\uFF0C\u5404\u4E3B\u9898\u5206\u522B\u4FDD\u5B58" : "Portrait phones; saved separately for each skin")), /* @__PURE__ */ import_react2.default.createElement("select", { "aria-label": lang === "zh" ? "\u624B\u673A\u5BFC\u822A\u65B9\u5F0F" : "Phone navigation", value: prefs.mobileNav || "corner", disabled: p.busy, onChange: (e) => setPreference(id, { mobileNav: e.target.value }) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "corner" }, lang === "zh" ? "\u5DE6\u4E0A\u89D2\u6309\u94AE + \u62BD\u5C49" : "Corner button + drawer"), /* @__PURE__ */ import_react2.default.createElement("option", { value: "rail" }, lang === "zh" ? "\u5DE6\u4FA7\u7EB5\u5411\u56FE\u6807\u680F" : "Vertical icon rail"))), ["artwork", "companion", ...id === "skirk" ? [] : ["polaroid"]].map((key) => /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option", key }, /* @__PURE__ */ import_react2.default.createElement("span", null, c[key]), /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: prefs[key], disabled: p.busy, onChange: (e) => setPreference(id, { [key]: e.target.checked }) }))), /* @__PURE__ */ import_react2.default.createElement("label", { className: "ekko-skin-option" }, /* @__PURE__ */ import_react2.default.createElement("span", null, c.opacity, /* @__PURE__ */ import_react2.default.createElement("small", null, Math.round(prefs.opacity * 100), "%")), /* @__PURE__ */ import_react2.default.createElement("input", { type: "range", min: ".04", max: ".24", step: ".01", value: prefs.opacity, disabled: p.busy, onChange: (e) => setPreference(id, { opacity: Number(e.target.value) }) }))), prefs && /* @__PURE__ */ import_react2.default.createElement(VideoSettings, { key: id, skin: id }));
815
815
  }
816
816
  function registerSection() {
817
817
  return ctx.slots.inject("settings.section", () => ctx.slots.register({ name: "settings.section", id: "ekko-skins", order: 115, label: () => COPY[language()].nav }, Panel));
@@ -860,7 +860,7 @@ function apply(ctx) {
860
860
  }, "ekko-skins: controller, section and presentation cleanup");
861
861
  }
862
862
 
863
- // src/shared-lease.mjs
863
+ // work/rose-queen-release/manager-publish/src/shared-lease.mjs
864
864
  function acquireShared(ctx, key, plugin, config = {}) {
865
865
  const symbol = /* @__PURE__ */ Symbol.for("dsh.ekko-skins.leases." + key);
866
866
  const leases = globalThis[symbol] ??= /* @__PURE__ */ new WeakMap(), root = ctx.root;
@@ -889,7 +889,7 @@ function acquireShared(ctx, key, plugin, config = {}) {
889
889
  return state.fiber;
890
890
  }
891
891
 
892
- // src/client-entry.mjs
892
+ // work/rose-queen-release/manager-publish/src/client-entry.mjs
893
893
  var manager = { name: "ekko-skins-shared-client-v2", inject, apply };
894
894
  function acquireClient(ctx) {
895
895
  return acquireShared(ctx, "client-v2", manager);
package/lib/index.js CHANGED
@@ -1,18 +1,19 @@
1
- // src/index.mjs
1
+ // work/rose-queen-release/manager-publish/src/index.mjs
2
+ import { existsSync as existsSync2 } from "node:fs";
2
3
  import { readFile as readFile2 } from "node:fs/promises";
3
4
  import { createRequire } from "node:module";
4
5
  import { createHash as createHash2 } from "node:crypto";
5
6
  import { dirname, join as join2 } from "node:path";
6
7
  import { pathToFileURL } from "node:url";
7
8
 
8
- // src/boot-media.mjs
9
+ // work/rose-queen-release/manager-publish/src/boot-media.mjs
9
10
  import { mkdir, readFile, writeFile, rename, unlink, readdir, stat, open } from "node:fs/promises";
10
11
  import { createReadStream, existsSync } from "node:fs";
11
12
  import { Readable } from "node:stream";
12
13
  import { join, basename } from "node:path";
13
14
  import { createHash, randomBytes } from "node:crypto";
14
15
 
15
- // src/vendor/video-route.mjs
16
+ // work/rose-queen-release/manager-publish/src/vendor/video-route.mjs
16
17
  function parseRange(header, size) {
17
18
  if (header === void 0 || header === null || header === "") return null;
18
19
  if (typeof header !== "string") return null;
@@ -41,10 +42,10 @@ function toInlineJson(value) {
41
42
  return JSON.stringify(value).replace(/</gu, "\\u003c").replace(/\u2028/gu, "\\u2028").replace(/\u2029/gu, "\\u2029");
42
43
  }
43
44
 
44
- // src/boot-media.mjs
45
+ // work/rose-queen-release/manager-publish/src/boot-media.mjs
45
46
  var MAX_VIDEO = 96 * 1024 * 1024;
46
47
  var CHUNK_SIZE = 512 * 1024;
47
- var IDS = ["rose", "miku"];
48
+ var IDS = ["rose", "miku", "skirk"];
48
49
  var DEVICES = ["desktop", "mobile"];
49
50
  var defaults = { enabled: true, sound: true, volume: 0.65, fit: "cover", maxSeconds: 30, file: null, name: null };
50
51
  var mediaName = /^[a-f0-9]{64}\.(mp4|webm)$/;
@@ -323,28 +324,36 @@ async function createMediaStore({ directory, resolvePackage }) {
323
324
  } };
324
325
  }
325
326
 
326
- // src/boot-generated.mjs
327
- var BOOT_SCRIPT = '(()=>{var D=`\n.ekko-boot{position:fixed;inset:0;z-index:2147483000;display:grid;place-items:center;background:#10171e;color:#fff;opacity:1;isolation:isolate;font:14px/1.5 system-ui,sans-serif}\n.ekko-boot[data-skin="rose"]{background:#241a20;--boot-accent:#f3b3c6}.ekko-boot[data-skin="miku"]{--boot-accent:#81eff0}\n.ekko-boot video{display:block;width:100%;height:100%;position:absolute;inset:0;object-fit:cover}\n.ekko-boot:after{content:"";position:absolute;inset:0;pointer-events:none;box-shadow:inset 0 0 0 2px var(--boot-accent),inset 0 -100px 100px -75px #000b}\n.ekko-boot button{position:relative;z-index:2;cursor:pointer;border:1px solid #fff8;background:#101820b8;color:white;border-radius:999px;min-height:44px;padding:9px 16px;font:inherit;backdrop-filter:blur(8px)}\n.ekko-boot button:focus-visible{outline:3px solid var(--boot-accent);outline-offset:3px}\n.ekko-boot-skip{position:absolute!important;right:max(18px,env(safe-area-inset-right));top:max(18px,env(safe-area-inset-top))}\n.ekko-boot-footer{position:absolute;bottom:max(20px,env(safe-area-inset-bottom));left:max(20px,env(safe-area-inset-left));right:max(20px,env(safe-area-inset-right));display:grid;gap:10px;z-index:2;text-shadow:0 1px 8px #000}\n.ekko-boot-toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.ekko-boot-toolbar span{margin-left:auto}.ekko-boot progress{width:100%;height:4px;accent-color:var(--boot-accent)}\n@media(prefers-reduced-motion:reduce){.ekko-boot{scroll-behavior:auto}}\n`,N=()=>/^zh/i.test(document.documentElement.lang||navigator.language)?{skip:"\\u8DF3\\u8FC7\\u89C6\\u9891",sound:"\\u5F00\\u542F\\u58F0\\u97F3",mute:"\\u9759\\u97F3",play:"\\u64AD\\u653E\\u89C6\\u9891",loading:"\\u6B63\\u5728\\u52A0\\u8F7D\\u542F\\u52A8\\u89C6\\u9891\\u2026",hint:"\\u70B9\\u51FB\\u753B\\u9762\\u6216\\u6309 Esc \\u8DF3\\u8FC7",title:"\\u4E3B\\u9898\\u542F\\u52A8\\u89C6\\u9891"}:{skip:"Skip video",sound:"Enable sound",mute:"Mute",play:"Play video",loading:"Loading startup video\\u2026",hint:"Click the picture or press Esc to skip",title:"Theme startup video"},R="(max-width: 768px), (hover: none) and (pointer: coarse) and (max-height: 768px)";function j(a,n=!1){return a&&(n&&a.mobile?{...a,...a.mobile,device:"mobile"}:{...a,device:n?"mobile":"desktop"})}function q(a,n){let i=a?.url,t=a?.fallbackUrl;return[...new Set((n?[t,i]:[i,t]).filter(Boolean))]}function U(a,n,{preview:i=!1}={}){if(!n?.url||n.available===!1||!i&&!n.enabled||!i&&window.matchMedia?.("(prefers-reduced-motion: reduce)").matches||document.querySelector(".ekko-boot"))return Promise.resolve();let t=N(),r=document.createElement("section"),e=document.createElement("video");r.className="ekko-boot",r.dataset.skin=a,r.dataset.device=n.device||"desktop",r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),r.setAttribute("aria-label",t.title);let h=document.createElement("style");h.dataset.ekkoBoot="",h.textContent=D,document.head.append(h),e.playsInline=!0,e.preload="auto",e.muted=!n.sound,e.volume=n.volume??.65,e.style.objectFit=n.fit||"cover";let w=q(n,!!e.canPlayType(\'video/webm; codecs="vp8, opus"\')),E=0;e.src=w[E];let T=(o,l)=>{let u=document.createElement("button");return u.type="button",u.textContent=o,u.className=l||"",u},f=T(t.skip,"ekko-boot-skip"),d=T(e.muted?t.sound:t.mute),s=T(t.play);s.hidden=!0;let _=document.createElement("div");_.className="ekko-boot-footer";let O=document.createElement("div");O.className="ekko-boot-toolbar";let g=document.createElement("span");g.textContent=t.loading;let m=document.createElement("progress");m.max=1,m.value=0,m.setAttribute("aria-label",t.title),O.append(d,s,g),_.append(O,m),r.append(e,f,_),document.body.append(r);let C=document.activeElement,k=document.getElementById("root"),K=k?.inert;k&&(k.inert=!0),f.focus();let A=new MutationObserver(()=>{t=N(),f.textContent=t.skip,d.textContent=e.muted?t.sound:t.mute,s.textContent=t.play,g.textContent=e.currentTime>0?t.hint:t.loading,r.setAttribute("aria-label",t.title),m.setAttribute("aria-label",t.title)});A.observe(document.documentElement,{attributes:!0,attributeFilter:["lang"]});let v=!1,p=!1,y=0,x,b,P,z=new Promise(o=>P=o);function B(){p||(p=!0,clearTimeout(b),clearTimeout(x),cancelAnimationFrame(y),A.disconnect(),document.removeEventListener("keydown",F,!0),e.pause(),e.removeAttribute("src"),e.load(),r.remove(),h.remove(),k&&(k.inert=K),C?.isConnected&&C!==document.body&&C.focus({preventScroll:!0}),P())}function c(o=800){if(v)return;v=!0,clearTimeout(b),clearTimeout(x),cancelAnimationFrame(y);let l=performance.now(),u=e.volume,L=()=>{if(p)return;let S=Math.min(1,(performance.now()-l)/o);r.style.opacity=String(1-S),e.volume=u*(1-S),S===1?B():y=requestAnimationFrame(L)};y=requestAnimationFrame(L),x=setTimeout(B,o+150)}function F(o){if(o.key==="Escape"&&(o.preventDefault(),o.stopPropagation(),c(250)),o.key==="Tab"){let l=[f,d,...s.hidden?[]:[s]],u=l.indexOf(document.activeElement);o.preventDefault(),l[(u+(o.shiftKey?-1:1)+l.length)%l.length].focus()}}document.addEventListener("keydown",F,!0),f.onclick=o=>{o.stopPropagation(),c(250)},r.onclick=o=>{o.target.closest("button")||c(250)},d.onclick=async o=>{o.stopPropagation(),e.muted=!e.muted;try{await e.play()}catch{s.hidden=!1}d.textContent=e.muted?t.sound:t.mute},s.onclick=async o=>{o.stopPropagation();try{await e.play(),s.hidden=!0}catch{e.muted=!0,d.textContent=t.sound;try{await e.play(),s.hidden=!0}catch{c(200)}}},e.addEventListener("ended",()=>c()),e.addEventListener("error",()=>{p||v||(E+1<w.length?(clearTimeout(b),b=setTimeout(()=>c(200),12e3),e.src=w[++E],e.load(),M()):c(200))}),e.addEventListener("playing",()=>{clearTimeout(b),s.hidden=!0,x||(x=setTimeout(()=>c(),Math.max(5,Math.min(60,n.maxSeconds||30))*1e3)),g.textContent=t.hint}),e.addEventListener("timeupdate",()=>{Number.isFinite(e.duration)&&e.duration>0&&(m.value=Math.min(1,e.currentTime/e.duration))}),b=setTimeout(()=>c(200),12e3);async function M(){try{await e.play()}catch{if(p||v)return;e.muted=!0,d.textContent=t.sound;try{await e.play()}catch{!p&&!v&&(s.hidden=!1)}}}return M(),z}function I({defaultSkin:a="miku"}={}){if(window.__EKKO_BOOT_STARTED__)return;window.__EKKO_BOOT_STARTED__=!0;let n=a;try{let i=JSON.parse(localStorage.getItem("dsh:ekko-skins:selection:v1"));i?.version===1&&["rose","miku","default"].includes(i.skin)&&(n=i.skin)}catch{}["rose","miku"].includes(n)&&(async()=>{try{let i=await fetch("./api/ekko-skins/boot",{credentials:"same-origin",signal:AbortSignal.timeout(3e3)});if(!i.ok)return;let t=await i.json();await U(n,j(t.skins?.[n],!!window.matchMedia?.(R).matches))}catch{}})()}try{I(globalThis.__EKKO_STARTUP_CONFIG__||{})}catch{}})();\n';
327
+ // work/rose-queen-release/manager-publish/src/boot-generated.mjs
328
+ var BOOT_SCRIPT = '(()=>{var D=`\n.ekko-boot{position:fixed;inset:0;z-index:2147483000;display:grid;place-items:center;background:#10171e;color:#fff;opacity:1;isolation:isolate;font:14px/1.5 system-ui,sans-serif}\n.ekko-boot[data-skin="rose"]{background:#241a20;--boot-accent:#f3b3c6}.ekko-boot[data-skin="miku"]{--boot-accent:#81eff0}\n.ekko-boot video{display:block;width:100%;height:100%;position:absolute;inset:0;object-fit:cover}\n.ekko-boot:after{content:"";position:absolute;inset:0;pointer-events:none;box-shadow:inset 0 0 0 2px var(--boot-accent),inset 0 -100px 100px -75px #000b}\n.ekko-boot button{position:relative;z-index:2;cursor:pointer;border:1px solid #fff8;background:#101820b8;color:white;border-radius:999px;min-height:44px;padding:9px 16px;font:inherit;backdrop-filter:blur(8px)}\n.ekko-boot button:focus-visible{outline:3px solid var(--boot-accent);outline-offset:3px}\n.ekko-boot-skip{position:absolute!important;right:max(18px,env(safe-area-inset-right));top:max(18px,env(safe-area-inset-top))}\n.ekko-boot-footer{position:absolute;bottom:max(20px,env(safe-area-inset-bottom));left:max(20px,env(safe-area-inset-left));right:max(20px,env(safe-area-inset-right));display:grid;gap:10px;z-index:2;text-shadow:0 1px 8px #000}\n.ekko-boot-toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.ekko-boot-toolbar span{margin-left:auto}.ekko-boot progress{width:100%;height:4px;accent-color:var(--boot-accent)}\n@media(prefers-reduced-motion:reduce){.ekko-boot{scroll-behavior:auto}}\n`,N=()=>/^zh/i.test(document.documentElement.lang||navigator.language)?{skip:"\\u8DF3\\u8FC7\\u89C6\\u9891",sound:"\\u5F00\\u542F\\u58F0\\u97F3",mute:"\\u9759\\u97F3",play:"\\u64AD\\u653E\\u89C6\\u9891",loading:"\\u6B63\\u5728\\u52A0\\u8F7D\\u542F\\u52A8\\u89C6\\u9891\\u2026",hint:"\\u70B9\\u51FB\\u753B\\u9762\\u6216\\u6309 Esc \\u8DF3\\u8FC7",title:"\\u4E3B\\u9898\\u542F\\u52A8\\u89C6\\u9891"}:{skip:"Skip video",sound:"Enable sound",mute:"Mute",play:"Play video",loading:"Loading startup video\\u2026",hint:"Click the picture or press Esc to skip",title:"Theme startup video"},R="(max-width: 768px), (hover: none) and (pointer: coarse) and (max-height: 768px)";function j(a,n=!1){return a&&(n&&a.mobile?{...a,...a.mobile,device:"mobile"}:{...a,device:n?"mobile":"desktop"})}function q(a,n){let i=a?.url,t=a?.fallbackUrl;return[...new Set((n?[t,i]:[i,t]).filter(Boolean))]}function U(a,n,{preview:i=!1}={}){if(!n?.url||n.available===!1||!i&&!n.enabled||!i&&window.matchMedia?.("(prefers-reduced-motion: reduce)").matches||document.querySelector(".ekko-boot"))return Promise.resolve();let t=N(),r=document.createElement("section"),e=document.createElement("video");r.className="ekko-boot",r.dataset.skin=a,r.dataset.device=n.device||"desktop",r.setAttribute("role","dialog"),r.setAttribute("aria-modal","true"),r.setAttribute("aria-label",t.title);let h=document.createElement("style");h.dataset.ekkoBoot="",h.textContent=D,document.head.append(h),e.playsInline=!0,e.preload="auto",e.muted=!n.sound,e.volume=n.volume??.65,e.style.objectFit=n.fit||"cover";let w=q(n,!!e.canPlayType(\'video/webm; codecs="vp8, opus"\')),E=0;e.src=w[E];let T=(o,l)=>{let u=document.createElement("button");return u.type="button",u.textContent=o,u.className=l||"",u},f=T(t.skip,"ekko-boot-skip"),d=T(e.muted?t.sound:t.mute),s=T(t.play);s.hidden=!0;let _=document.createElement("div");_.className="ekko-boot-footer";let O=document.createElement("div");O.className="ekko-boot-toolbar";let g=document.createElement("span");g.textContent=t.loading;let m=document.createElement("progress");m.max=1,m.value=0,m.setAttribute("aria-label",t.title),O.append(d,s,g),_.append(O,m),r.append(e,f,_),document.body.append(r);let C=document.activeElement,k=document.getElementById("root"),K=k?.inert;k&&(k.inert=!0),f.focus();let A=new MutationObserver(()=>{t=N(),f.textContent=t.skip,d.textContent=e.muted?t.sound:t.mute,s.textContent=t.play,g.textContent=e.currentTime>0?t.hint:t.loading,r.setAttribute("aria-label",t.title),m.setAttribute("aria-label",t.title)});A.observe(document.documentElement,{attributes:!0,attributeFilter:["lang"]});let v=!1,p=!1,y=0,x,b,P,z=new Promise(o=>P=o);function B(){p||(p=!0,clearTimeout(b),clearTimeout(x),cancelAnimationFrame(y),A.disconnect(),document.removeEventListener("keydown",F,!0),e.pause(),e.removeAttribute("src"),e.load(),r.remove(),h.remove(),k&&(k.inert=K),C?.isConnected&&C!==document.body&&C.focus({preventScroll:!0}),P())}function c(o=800){if(v)return;v=!0,clearTimeout(b),clearTimeout(x),cancelAnimationFrame(y);let l=performance.now(),u=e.volume,L=()=>{if(p)return;let S=Math.min(1,(performance.now()-l)/o);r.style.opacity=String(1-S),e.volume=u*(1-S),S===1?B():y=requestAnimationFrame(L)};y=requestAnimationFrame(L),x=setTimeout(B,o+150)}function F(o){if(o.key==="Escape"&&(o.preventDefault(),o.stopPropagation(),c(250)),o.key==="Tab"){let l=[f,d,...s.hidden?[]:[s]],u=l.indexOf(document.activeElement);o.preventDefault(),l[(u+(o.shiftKey?-1:1)+l.length)%l.length].focus()}}document.addEventListener("keydown",F,!0),f.onclick=o=>{o.stopPropagation(),c(250)},r.onclick=o=>{o.target.closest("button")||c(250)},d.onclick=async o=>{o.stopPropagation(),e.muted=!e.muted;try{await e.play()}catch{s.hidden=!1}d.textContent=e.muted?t.sound:t.mute},s.onclick=async o=>{o.stopPropagation();try{await e.play(),s.hidden=!0}catch{e.muted=!0,d.textContent=t.sound;try{await e.play(),s.hidden=!0}catch{c(200)}}},e.addEventListener("ended",()=>c()),e.addEventListener("error",()=>{p||v||(E+1<w.length?(clearTimeout(b),b=setTimeout(()=>c(200),12e3),e.src=w[++E],e.load(),M()):c(200))}),e.addEventListener("playing",()=>{clearTimeout(b),s.hidden=!0,x||(x=setTimeout(()=>c(),Math.max(5,Math.min(60,n.maxSeconds||30))*1e3)),g.textContent=t.hint}),e.addEventListener("timeupdate",()=>{Number.isFinite(e.duration)&&e.duration>0&&(m.value=Math.min(1,e.currentTime/e.duration))}),b=setTimeout(()=>c(200),12e3);async function M(){try{await e.play()}catch{if(p||v)return;e.muted=!0,d.textContent=t.sound;try{await e.play()}catch{!p&&!v&&(s.hidden=!1)}}}return M(),z}function I({defaultSkin:a="miku"}={}){if(window.__EKKO_BOOT_STARTED__)return;window.__EKKO_BOOT_STARTED__=!0;let n=a;try{let i=JSON.parse(localStorage.getItem("dsh:ekko-skins:selection:v1"));i?.version===1&&["rose","miku","skirk","default"].includes(i.skin)&&(n=i.skin)}catch{}["rose","miku","skirk"].includes(n)&&(async()=>{try{let i=await fetch("./api/ekko-skins/boot",{credentials:"same-origin",signal:AbortSignal.timeout(3e3)});if(!i.ok)return;let t=await i.json();await U(n,j(t.skins?.[n],!!window.matchMedia?.(R).matches))}catch{}})()}try{I(globalThis.__EKKO_STARTUP_CONFIG__||{})}catch{}})();\n';
328
329
 
329
- // src/index.mjs
330
+ // work/rose-queen-release/manager-publish/src/index.mjs
330
331
  var require2 = createRequire(import.meta.url);
331
332
  var PREFIX = "/ekko-skins";
332
- var PACKAGES = { rose: "dsh-plugin-rose-theme", miku: "dsh-plugin-miku-theme" };
333
+ var PACKAGES = { rose: "dsh-plugin-rose-theme", miku: "dsh-plugin-miku-theme", skirk: "dsh-plugin-miku-theme" };
334
+ function resolveSkinPackage(resolvePackage, id) {
335
+ if (id === "rose") try {
336
+ const bundled = join2(resolvePackage(PACKAGES.miku), "themes/rose");
337
+ if (existsSync2(join2(bundled, "package.json"))) return bundled;
338
+ } catch {
339
+ }
340
+ return resolvePackage(PACKAGES[id]);
341
+ }
333
342
  function createHandler({ resolvePackage = (name) => dirname(require2.resolve(name + "/package.json")), defaultSkin = "miku" } = {}) {
334
343
  async function catalog() {
335
344
  const skins = [];
336
345
  for (const [id, pkg] of Object.entries(PACKAGES)) {
337
346
  try {
338
- const root = resolvePackage(pkg), meta = JSON.parse(await readFile2(join2(root, "package.json"), "utf8"));
339
- skins.push({ id, version: meta.version, available: meta.dsh?.ekkoSkinProvider === 1, preview: { light: "./ekko-skins/preview/" + id + "/light.webp", dark: "./ekko-skins/preview/" + id + "/dark.webp" } });
347
+ const root = resolveSkinPackage(resolvePackage, id), meta = JSON.parse(await readFile2(join2(root, "package.json"), "utf8"));
348
+ skins.push({ id, version: meta.version, available: meta.dsh?.ekkoSkinProvider === 1 && (id !== "skirk" || Array.isArray(meta.dsh?.ekkoSkins) && meta.dsh.ekkoSkins.includes("skirk")), preview: { light: "./ekko-skins/preview/" + id + "/light.webp", dark: "./ekko-skins/preview/" + id + "/dark.webp" } });
340
349
  } catch {
341
350
  skins.push({ id, available: false });
342
351
  }
343
352
  }
344
353
  const installed = skins.filter((s) => s.available).map((s) => s.id);
345
- const preferred = ["rose", "miku", "default"].includes(defaultSkin) ? defaultSkin : "miku";
354
+ const preferred = ["rose", "miku", "skirk", "default"].includes(defaultSkin) ? defaultSkin : "miku";
346
355
  const selected = preferred === "default" || installed.includes(preferred) ? preferred : installed[0] || "default";
347
- return { version: "0.2.2", defaultSkin: selected, skins };
356
+ return { version: "0.3.1", defaultSkin: selected, skins };
348
357
  }
349
358
  return async (req, res) => {
350
359
  if (!["GET", "HEAD"].includes(req.method)) {
@@ -358,7 +367,7 @@ function createHandler({ resolvePackage = (name) => dirname(require2.resolve(nam
358
367
  res.end(req.method === "HEAD" ? void 0 : bytes2);
359
368
  return;
360
369
  }
361
- const match = /^\/ekko-skins\/(assets|preview)\/(rose|miku)\/([a-z0-9.-]+)$/.exec(pathname);
370
+ const match = /^\/ekko-skins\/(assets|preview)\/(rose|miku|skirk)\/([a-z0-9.-]+)$/.exec(pathname);
362
371
  if (!match) {
363
372
  res.writeHead(404).end();
364
373
  return;
@@ -366,24 +375,24 @@ function createHandler({ resolvePackage = (name) => dirname(require2.resolve(nam
366
375
  const [, kind, id, file] = match;
367
376
  let bytes;
368
377
  try {
369
- const root = resolvePackage(PACKAGES[id]);
378
+ const root = resolveSkinPackage(resolvePackage, id);
370
379
  if (kind === "assets") {
371
380
  if (!/^[a-f0-9]{64}\.(webp|png|svg|woff2)$/.test(file)) {
372
381
  res.writeHead(404).end();
373
382
  return;
374
383
  }
375
- const manifest = JSON.parse(await readFile2(join2(root, "assets/manifest.json"), "utf8"));
384
+ const manifest = JSON.parse(await readFile2(join2(root, id === "skirk" ? "assets/skirk/manifest.json" : "assets/manifest.json"), "utf8"));
376
385
  if (!Object.values(manifest).includes(file)) {
377
386
  res.writeHead(404).end();
378
387
  return;
379
388
  }
380
- bytes = await readFile2(join2(root, "assets/runtime", file));
389
+ bytes = await readFile2(join2(root, id === "skirk" ? "assets/skirk/runtime" : "assets/runtime", file));
381
390
  } else {
382
391
  if (!["light.webp", "dark.webp"].includes(file)) {
383
392
  res.writeHead(404).end();
384
393
  return;
385
394
  }
386
- bytes = await readFile2(join2(root, "preview", file));
395
+ bytes = await readFile2(join2(root, id === "skirk" ? "preview/skirk" : "preview", file));
387
396
  }
388
397
  } catch {
389
398
  res.writeHead(404).end();
@@ -405,7 +414,7 @@ function apply(ctx, config = {}) {
405
414
  ctx.inject(["webServer", "profileContext", "connection"], async (child) => {
406
415
  const profile = child.get("profileContext"), resolver = createRequire(pathToFileURL(join2(profile.dir, "package.json")));
407
416
  const resolvePackage = (name) => dirname(resolver.resolve(name + "/package.json"));
408
- const media = await createMediaStore({ directory: join2(profile.dir, "ekko-skins-media"), resolvePackage: (id) => resolvePackage(PACKAGES[id]) });
417
+ const media = await createMediaStore({ directory: join2(profile.dir, "ekko-skins-media"), resolvePackage: (id) => id === "skirk" ? join2(resolveSkinPackage(resolvePackage, id), "assets/skirk") : resolveSkinPackage(resolvePackage, id) });
409
418
  child.effect(() => () => media.close(), "ekko-skins: private media store");
410
419
  child.effect(() => child.get("webServer").register({ kind: "prefix", path: PREFIX, handler: createHandler({ defaultSkin: config.defaultSkin, resolvePackage }) }));
411
420
  for (const [path, methods, fetch, requestBody] of [
@@ -417,7 +426,7 @@ function apply(ctx, config = {}) {
417
426
  });
418
427
  }
419
428
 
420
- // src/shared-lease.mjs
429
+ // work/rose-queen-release/manager-publish/src/shared-lease.mjs
421
430
  function acquireShared(ctx, key, plugin, config = {}) {
422
431
  const symbol = /* @__PURE__ */ Symbol.for("dsh.ekko-skins.leases." + key);
423
432
  const leases = globalThis[symbol] ??= /* @__PURE__ */ new WeakMap(), root = ctx.root;
@@ -446,7 +455,7 @@ function acquireShared(ctx, key, plugin, config = {}) {
446
455
  return state.fiber;
447
456
  }
448
457
 
449
- // src/host-entry.mjs
458
+ // work/rose-queen-release/manager-publish/src/host-entry.mjs
450
459
  var host = { name: "ekko-skins-shared-host-v2", apply };
451
460
  function acquireHost(ctx, config = {}) {
452
461
  return acquireShared(ctx, "host-v2", host, config);