From 974eb85ff72ecf545ce15a071443bcdafcd23e1d Mon Sep 17 00:00:00 2001 From: starsstreaming <2946843254lw@gmail.com> Date: Tue, 18 Aug 2026 12:51:03 +0800 Subject: [PATCH] feat: add an in-page DSH background console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install the plugin and run dsh web: a compact 背景 entry appears above 设置. Pick image/video from a folder, restore the last background on launch, and follow DSH light/dark instead of overwriting it. Tray stays optional for DSH. --- README.md | 13 +- docs/deepseek-harness.md | 13 +- integrations/deepseek-harness/README.zh-CN.md | 10 +- integrations/deepseek-harness/client.js | 27 +- integrations/deepseek-harness/console.js | 290 ++++++++++++++++++ integrations/deepseek-harness/host-apply.mjs | 11 +- integrations/deepseek-harness/index.mjs | 63 +++- integrations/deepseek-harness/package.json | 4 +- .../deepseek-harness/test/plugin.test.mjs | 41 +-- .../deepseek-harness/test/ui-host.test.mjs | 220 +++++++++++++ integrations/deepseek-harness/ui-host.mjs | 266 ++++++++++++++++ packages/adapter-dsh/src/session.ts | 2 +- 12 files changed, 896 insertions(+), 64 deletions(-) create mode 100644 integrations/deepseek-harness/console.js create mode 100644 integrations/deepseek-harness/test/ui-host.test.mjs create mode 100644 integrations/deepseek-harness/ui-host.mjs diff --git a/README.md b/README.md index a20371d..e33fa29 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ beautiCode 是一个本地背景工具,**主要面向 DeepSeek Harness和Codex**。 -它不包含、不安装、也不启动 DSH。请先自行安装 DeepSeek Harness 并运行 `dsh web`,再启动 beautiCode,选中 DeepSeek Harness 或 Codex,就可以把电脑里的: +它不包含、不安装、也不启动 DSH。请先自行安装 DeepSeek Harness 并运行 `dsh web`。插件装好后,DSH 侧栏「设置」上方会出现「背景」,不必再开托盘。Codex Desktop 仍走 beautiCode 托盘。可以把电脑里的: * 图片 * 动态壁纸 @@ -120,7 +120,7 @@ Ctrl + Shift + Space 深夜电台 ``` -保存后,可以直接从托盘菜单切换。 +保存后,可以从 DSH 侧栏「背景」或托盘菜单切换。 对于视频主题,beautiCode 还会记录播放进度。 @@ -152,7 +152,7 @@ Ctrl + Shift + Space 想直接使用 beautiCode,可以下载 [Windows 安装包](https://github.com/starsstreaming/beautiCode/releases/latest)。 安装包自带 Node.js,不需要另外安装 Node.js、npm 或 pnpm。 Codex Desktop 路径与原来一样:启动后选 **Codex Desktop**,托盘会按需拉起 Codex。 -DeepSeek Harness 由你自己运行:把插件装进 DSH profile,再启动 `dsh web`,然后在选择框里选 **DeepSeek Harness**。beautiCode 绝不替你启动 DSH。页面打开后可以用 `/bg`、`/bg-theme`、`/bg-clear`,或直接跟 AI 说把本机图片/视频设成背景。 +DeepSeek Harness 由你自己运行:把插件装进 DSH profile,再启动 `dsh web`。beautiCode 绝不替你启动 DSH。页面打开后,用侧栏「背景」从文件夹选图片或 MP4;也可以用 `/bg`、`/bg-theme`、`/bg-clear`,或直接跟 AI 说把本机图片/视频设成背景。下次打开 DSH 会恢复上次的背景。
@@ -182,7 +182,9 @@ dsh web
npx @deepseek-ai/dsh web
```
-再启动 beautiCode:选 **Codex Desktop** 仍由托盘拉起 Codex;选 **DeepSeek Harness** 则连接你已经启动的 DSH 网页。
+打开 DSH 网页后,侧栏「设置」上方有「背景」:可从文件夹选图片或 MP4、清除、开关声音、切换已保存主题。网页控制台没有摸鱼。外观浅色/深色仍用 DSH 自己的设置。下次启动会恢复上次背景。
+
+Codex Desktop 仍要开 beautiCode 托盘。选 **DeepSeek Harness** 时托盘只连接你已经启动的 DSH 网页,不会替你启动 DSH。
若自动写入失败,才需要手动安装插件。把路径换成实际安装目录(默认是 `%LOCALAPPDATA%\Programs\beautiCode`):
@@ -216,7 +218,8 @@ npm install
# 若要手动安装(dsh plugin add 需要 pnpm):
# npx @deepseek-ai/dsh plugin --profile web add file:%CD%/integrations/deepseek-harness
npx @deepseek-ai/dsh web
-npm run tray
+# DSH 侧栏「背景」即可换图换视频。托盘只在要用 Codex 或摸鱼热键时再开:
+# npm run tray
```
或打开宿主选择器:
diff --git a/docs/deepseek-harness.md b/docs/deepseek-harness.md
index 3ad758e..322b9df 100644
--- a/docs/deepseek-harness.md
+++ b/docs/deepseek-harness.md
@@ -5,13 +5,14 @@ beautiCode 通过 DeepSeek Harness 的 Cordis 插件接口接入(`@beauticode/
## 已实现能力
- 图片背景、MP4 视频背景与清除。首页(`data-phase="hero"`)壁纸保持原亮度;进入会话(`active` / `settling`)后才压暗。
+- 网页控制台:插件装好后,DSH 侧栏「设置」上方出现「背景」。可从系统文件夹选择图片或 MP4、清除、开关声音、切换已保存主题。不需要托盘。网页控制台没有摸鱼。
- 对话工具与斜杠命令:在 DSH 里说「把某个本机 MP4 设成背景」,或输入 `/bg`、`/bg-theme`、`/bg-clear`。插件自己完成导入,不需要托盘。若托盘已经在跑,则复用托盘,避免两套写入打架。
- 视频默认静音;可请求开启声音。若浏览器自动播放策略阻止开启声音,会继续静音播放并返回 `blocked: true`。
- 视频播放位置随已保存主题记录;切换主题、重新应用与页面恢复时从最近位置继续。
-- 摸鱼模式:隐藏 DSH 的 `#root`,背景舞台继续显示和播放;`Ctrl+Shift+Space` 可退出。
-- 深色、浅色、跟随系统三种背景色调。
+- 摸鱼模式:隐藏 DSH 的 `#root`,背景舞台继续显示和播放;`Ctrl+Shift+Space` 可退出(托盘全局热键)。网页控制台不提供摸鱼。
+- 外观浅色 / 深色跟随 DSH 自己的设置,插件不再改写 DSH 主题 DOM。
- 图片/视频主题的保存、切换和删除。
-- 页面刷新或稍后打开时,会恢复当前背景与模式。找不到 `#root` 时应用失败并回滚,不会静默画坏页。
+- 页面刷新或稍后打开时,会恢复当前背景。找不到 `#root` 时应用失败并回滚,不会静默画坏页。
同一个 beautiCode 数据目录一次只能运行一个宿主会话,避免 Codex 与 DSH 同时写入造成状态损坏。
@@ -48,9 +49,13 @@ npx @deepseek-ai/dsh plugin --profile web add file:%LOCALAPPDATA%\Programs\beaut
也可以参考 [`integrations/deepseek-harness/cordis.patch.example.yml`](../integrations/deepseek-harness/cordis.patch.example.yml)。
+## 网页控制台
+
+插件注入 `console.js`,把「背景」插在侧栏「设置」同一格里(`display: contents`,不另铺底色)。点开后的面板挂在 `document.body` 上,用实色,避免吃半透明壁纸 token。同源 `POST /__beauticode/ui/*` 转到已有的 `createBeauticodeActions()`。页面连上 SSE 后会 `reapply` 上次背景。DSH 会话列表底部的 fade 在有壁纸时关掉,避免叠出一条暗影。
+
## 控制端
-启动 beautiCode,在选择框里选 DeepSeek Harness(或直接 `start-tray.ps1 -TargetHost dsh`)。托盘只连接你正在运行的 DSH 网页:
+托盘可选。启动 beautiCode,在选择框里选 DeepSeek Harness(或直接 `start-tray.ps1 -TargetHost dsh`)。托盘只连接你正在运行的 DSH 网页:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File apps\tray\start-tray.ps1 -TargetHost dsh -DshUrl http://127.0.0.1:3080
diff --git a/integrations/deepseek-harness/README.zh-CN.md b/integrations/deepseek-harness/README.zh-CN.md
index de14508..49ed217 100644
--- a/integrations/deepseek-harness/README.zh-CN.md
+++ b/integrations/deepseek-harness/README.zh-CN.md
@@ -1,10 +1,12 @@
# DeepSeek Harness 桥接插件
-该 Cordis 插件向 DSH Web 注入 beautiCode 浏览器客户端,并提供本机鉴权接口。支持图片、MP4、播放位置、静音、摸鱼模式、深浅色调以及清除背景。
+该 Cordis 插件向 DSH Web 注入 beautiCode 浏览器客户端,并提供本机鉴权接口。支持图片、MP4、播放位置、静音、摸鱼模式以及清除背景。
-插件会注册对话工具(`beauticode_*`)和斜杠命令(`/bg`、`/bg-theme`、`/bg-clear`),把本机文件导入为背景。不需要托盘;托盘若已在跑则复用它。
+装好插件并运行 `dsh web` 后,侧栏「设置」上方会出现「背景」:可从文件夹选图片或 MP4、清除、开关声音、切换已保存主题。网页控制台没有摸鱼;浅色/深色跟 DSH 自己的外观走。下次打开会恢复上次背景。
-beautiCode **不启动** DeepSeek Harness。请先自己运行 `dsh web`,再打开 beautiCode 选择 DeepSeek Harness。
+插件也会注册对话工具(`beauticode_*`)和斜杠命令(`/bg`、`/bg-theme`、`/bg-clear`)。不需要托盘;托盘若已在跑则复用它。
+
+beautiCode **不启动** DeepSeek Harness。请先自己运行 `dsh web`。
安装包和托盘会把插件写入你的 DSH profile,不需要 pnpm。源码环境也可以手动(`dsh plugin add` 需要 pnpm):
@@ -20,6 +22,6 @@ npx @deepseek-ai/dsh web
1. 修改 `cordis.patch.example.yml` 中的 `file:///.../index.mjs`。
2. 确保 DSH 和 beautiCode 使用相同的 `BEAUTICODE_DATA_ROOT`。
3. 自己运行 `dsh web`(或带 `--patch`)。
-4. 打开页面后输入 `/bg <本机绝对路径>`,或直接跟 AI 说把某个视频/图片设为背景。
+4. 打开页面后用侧栏「背景」,或输入 `/bg <本机绝对路径>`,或直接跟 AI 说把某个视频/图片设为背景。
安全边界:DSH Web 必须绑定本机回环地址;控制端点需要随机令牌;媒体 URL 仅允许带令牌的回环 HTTP 地址;浏览器回执只接受同源请求。
diff --git a/integrations/deepseek-harness/client.js b/integrations/deepseek-harness/client.js
index 7e3ce68..7c6f34a 100644
--- a/integrations/deepseek-harness/client.js
+++ b/integrations/deepseek-harness/client.js
@@ -7,7 +7,7 @@
const clientId =
globalThis.crypto?.randomUUID?.() ||
`bc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
- const desiredModes = { fish: false, muted: true, tone: "dark" };
+ const desiredModes = { fish: false, muted: true, tone: "auto" };
let activePayload = null;
let playbackBlocked = false;
const systemDarkMedia = globalThis.matchMedia?.("(prefers-color-scheme: dark)") ?? null;
@@ -59,31 +59,30 @@ html[data-bc-fish="true"] #beauticode-bg-stage::after{background:transparent!imp
#beauticode-bg-stage img{z-index:0}
#beauticode-bg-stage video{z-index:1}
html[data-bc-active="true"] #root{position:relative;z-index:1;background:transparent!important}
+html[data-bc-active="true"] [class*="_fade"]{display:none!important}
html[data-bc-fish="true"] #root{opacity:0!important;visibility:hidden!important;pointer-events:none!important}
`;
document.head.append(style);
- function resolvedTone() {
- if (desiredModes.tone !== "auto") return desiredModes.tone;
+ function dshAppearance() {
+ const body = document.body;
+ if (body?.hasAttribute("data-ds-dark-theme")) return "dark";
+ const scheme = document.documentElement.style.colorScheme;
+ if (scheme === "dark" || scheme === "light") return scheme;
return systemDarkMedia?.matches ? "dark" : "light";
}
+ function resolvedTone() {
+ return dshAppearance();
+ }
+
function isDshThemeSynced(tone = resolvedTone()) {
- const body = document.body;
- if (!body) return false;
- return (
- body.hasAttribute("data-ds-dark-theme") === (tone === "dark") &&
- document.documentElement.style.colorScheme === tone
- );
+ return document.documentElement.dataset.bcResolvedTone === tone;
}
function syncDshTheme() {
const tone = resolvedTone();
- const root = document.documentElement;
- const body = document.body;
- root.dataset.bcResolvedTone = tone;
- if (root.style.colorScheme !== tone) root.style.colorScheme = tone;
- if (body) body.toggleAttribute("data-ds-dark-theme", tone === "dark");
+ document.documentElement.dataset.bcResolvedTone = tone;
return isDshThemeSynced(tone);
}
diff --git a/integrations/deepseek-harness/console.js b/integrations/deepseek-harness/console.js
new file mode 100644
index 0000000..4a52384
--- /dev/null
+++ b/integrations/deepseek-harness/console.js
@@ -0,0 +1,290 @@
+(() => {
+ "use strict";
+ if (window.__beauticodeConsoleLoaded) return;
+ window.__beauticodeConsoleLoaded = true;
+
+ const IMAGE_ACCEPT = ".jpg,.jpeg,.png,.webp,.avif,image/jpeg,image/png,image/webp,image/avif";
+ const VIDEO_ACCEPT = ".mp4,video/mp4";
+
+ const style = document.createElement("style");
+ style.dataset.beauticodeConsole = "true";
+ style.textContent = `
+#beauticode-console{display:contents}
+#beauticode-console .bc-trigger{cursor:pointer;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:none;border-radius:12px;background:transparent;color:inherit;font:inherit;font-size:14px;line-height:22px;align-items:center;gap:8px;display:flex;overflow:hidden}
+#beauticode-console .bc-trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}
+#beauticode-console.rail .bc-trigger{width:36px;height:36px;margin:8px 0 10px;padding:0;border-radius:50%;justify-content:center;gap:0}
+#beauticode-console.rail .bc-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
+#beauticode-console .bc-icon{flex:none;display:block}
+#beauticode-console .bc-label{white-space:nowrap;overflow:hidden}
+#beauticode-console-pop{position:fixed;z-index:2000;box-sizing:border-box;width:220px;padding:10px;border:1px solid rgba(255,255,255,.08);border-radius:16px;background:#2c323c;color:#e8eaed;box-shadow:var(--dsw-shadow-lv2,0 8px 24px rgba(0,0,0,.28));font:inherit;font-size:13px}
+#beauticode-console-pop *{box-sizing:border-box;font-family:inherit}
+body:not([data-ds-dark-theme]) #beauticode-console-pop{background:#fff;color:#1b1f24;border-color:rgba(0,0,0,.08)}
+#beauticode-console-pop .bc-status{color:var(--dsw-alias-label-secondary,#9aa3ad);font-size:12px;line-height:18px;margin:0 0 8px}
+#beauticode-console-pop .bc-row{display:flex;gap:6px;margin:0 0 6px}
+#beauticode-console-pop .bc-btn,#beauticode-console-pop .bc-theme-toggle{cursor:pointer;flex:1;min-width:0;height:32px;padding:0 8px;border:1px solid rgba(255,255,255,.1);border-radius:12px;background:rgba(255,255,255,.06);color:inherit;font-size:13px;line-height:20px}
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-btn,
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-theme-toggle{border-color:rgba(0,0,0,.08);background:#f4f6f8}
+#beauticode-console-pop .bc-btn:hover,#beauticode-console-pop .bc-theme-toggle:hover{background:rgba(255,255,255,.12)}
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-btn:hover,
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-theme-toggle:hover{background:#eceff3}
+#beauticode-console-pop .bc-btn:disabled,#beauticode-console-pop .bc-theme-toggle:disabled,#beauticode-console-pop .bc-theme-item:disabled{opacity:.45;cursor:default}
+#beauticode-console-pop .bc-btn.on{background:rgba(255,255,255,.16)}
+#beauticode-console-pop .bc-theme-toggle{width:100%;text-align:left}
+#beauticode-console-pop .bc-theme-list{margin:6px 0 0;max-height:160px;overflow:auto;border:1px solid rgba(255,255,255,.08);border-radius:12px;background:#232830;padding:4px}
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-theme-list{border-color:rgba(0,0,0,.08);background:#f4f6f8}
+#beauticode-console-pop .bc-theme-item{cursor:pointer;display:block;width:100%;height:32px;padding:0 8px;border:none;border-radius:8px;background:transparent;color:inherit;font-size:13px;line-height:32px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
+#beauticode-console-pop .bc-theme-item:hover{background:rgba(255,255,255,.08)}
+body:not([data-ds-dark-theme]) #beauticode-console-pop .bc-theme-item:hover{background:rgba(0,0,0,.06)}
+#beauticode-console-pop .bc-msg{color:var(--dsw-alias-label-secondary,#9aa3ad);font-size:12px;line-height:16px;margin:6px 0 0;max-height:3.2em;overflow:hidden}
+#beauticode-console-file{display:none !important}
+`;
+ document.head.append(style);
+
+ const host = document.createElement("div");
+ host.id = "beauticode-console";
+ host.innerHTML =
+ '';
+
+ const pop = document.createElement("div");
+ pop.id = "beauticode-console-pop";
+ pop.hidden = true;
+ pop.innerHTML =
+ '
未就绪
' + + '