🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

主题工坊 IRdotAI/dsh-studio

DeepSeek Harnessv0.0.1
IRdotAI27 天前有提交已提供中文文档扫描:含敏感能力

换主题、调外观、管提示词,一站搞定界面个性化

30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/8 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add IRdotAI/dsh-studio
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
数据截至 2026/10/31·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/03·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 27 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-studio @ 0.0.1
✓Node 引擎要求 >=22.5 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/15 20:11:17

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 67 处,展示前 56 条)
  • 读取本地文件
    lib/index.js:51
    return existsSync(file) ? file : null;
  • 读取本地文件
    lib/index.js:73
    return readdirSync(abs)
  • 读取本地文件
    lib/index.js:96
    return readdirSync(abs)
  • 读取本地文件
    lib/index.js:119
    const days = readdirSync(this.dir).filter((f) => /^\d{4}-\d{2}-\d{2}\.jpg$/.test(f)).sort();
  • 读取本地文件
    lib/index.js:123
    try { meta = JSON.parse(readFileSync(join(this.dir, `${day}.json`), "utf8")); } catch { }
  • 请求外部主机www.bing.com
    lib/index.js:147
    const res = await fetch(`https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=${encodeURIComponent(market)}`, { headers: { "user-agent": "
  • 发起网络请求
    lib/index.js:147
    const res = await fetch(`https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=${encodeURIComponent(market)}`, { headers: { "user-agent": "
  • 请求外部主机www.bing.com_1920x1080.jpg
    lib/index.js:151
    const pic = await fetch(`https://www.bing.com${image.urlbase}_1920x1080.jpg`, { headers: { "user-agent": "dsh-studio" }, signal: AbortSignal.timeout(3
  • 发起网络请求
    lib/index.js:151
    const pic = await fetch(`https://www.bing.com${image.urlbase}_1920x1080.jpg`, { headers: { "user-agent": "dsh-studio" }, signal: AbortSignal.timeout(3
  • 写入本地文件
    lib/index.js:155
    mkdirSync(this.dir, { recursive: true });
  • 写入本地文件
    lib/index.js:157
    writeFileSync(join(this.dir, `${day}.jpg`), bytes);
  • 写入本地文件
    lib/index.js:158
    writeFileSync(join(this.dir, `${day}.json`), JSON.stringify({ title: String(image.title ?? ""), copyright: String(image.copyright ?? "") }));
  • 读取本地文件
    lib/index.js:160
    const old = readdirSync(this.dir).filter((f) => /^\d{4}-\d{2}-\d{2}\.(jpg|json)$/.test(f)).sort().slice(0, -6);
  • 删除本地文件
    lib/index.js:161
    for (const f of old) { try { unlinkSync(join(this.dir, f)); } catch { } }
  • 写入本地文件
    lib/index.js:220
    mkdirSync(dirname(this.file), { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/index.js:222
    writeFileSync(tmp, JSON.stringify(this.state, null, "\t"), "utf8");
  • 写入本地文件
    lib/index.js:223
    renameSync(tmp, this.file);
  • 请求外部主机raw.githubusercontent.com
    lib/index.js:397
    const res = await fetch(`https://raw.githubusercontent.com/${repo}/main/gallery/index.json`, { headers: { "user-agent": "dsh-studio" }, signal: AbortS
  • 发起网络请求
    lib/index.js:397
    const res = await fetch(`https://raw.githubusercontent.com/${repo}/main/gallery/index.json`, { headers: { "user-agent": "dsh-studio" }, signal: AbortS
  • 请求外部主机api.deepseek.com
    lib/index.js:419
    const res = await fetch("https://api.deepseek.com/user/balance", { headers: { authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(15_000) })
  • 发起网络请求
    lib/index.js:419
    const res = await fetch("https://api.deepseek.com/user/balance", { headers: { authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(15_000) })
  • 发起网络请求
    lib/client.js:2668
    const res = await fetch("/api/studio/" + path, { cache: "no-store" });
  • 发起网络请求
    lib/client.js:2678
    const res = await fetch("/api/studio/" + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body ?? {}) });
  • 写入剪贴板
    lib/client.js:3460
    void navigator.clipboard?.writeText(text);
  • 读取剪贴板
    lib/client.js:3487
    async function readClipboard() {
  • 读取剪贴板
    lib/client.js:3489
    return (await navigator.clipboard.readText()) ?? "";
  • 读取剪贴板
    lib/client.js:3503
    const clipboard = needs.clipboard ? await readClipboard() : "";
  • 读取剪贴板
    lib/client.js:3511
    const clipboard = promptPlaceholders(fill.prompt.text).clipboard ? await readClipboard() : "";
  • 写入剪贴板
    lib/client.js:4933
    void navigator.clipboard?.writeText(json).then(() => toast(t("prompts.packCopied")), () => toast(t("export.copyFailed")));
  • 读取本地文件
    lib/updater.js:26
    return JSON.parse(readFileSync(file, "utf8"));
  • 写入本地文件
    lib/updater.js:115
    mkdirSync(this.dataDir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/updater.js:117
    writeFileSync(tmp, JSON.stringify({ releases: this.releases, lastCheck: this.lastCheck, pending }, null, "\t"));
  • 写入本地文件
    lib/updater.js:118
    renameSync(tmp, this.file);
  • 请求外部主机api.github.com
    lib/updater.js:174
    const res = await fetch(`https://api.github.com/repos/${this.repo}/releases?per_page=50`, {
  • 发起网络请求
    lib/updater.js:174
    const res = await fetch(`https://api.github.com/repos/${this.repo}/releases?per_page=50`, {
  • 读取本地文件
    lib/updater.js:221
    if (!existsSync(this.settingsFile)) return null;
  • 写入本地文件
    lib/updater.js:224
    copyFileSync(this.settingsFile, target);
  • 读取本地文件
    lib/updater.js:225
    const backups = readdirSync(this.dataDir).filter((f) => /^studio\.backup-.*\.json$/.test(f)).sort();
  • 删除本地文件
    lib/updater.js:227
    try { unlinkSync(join(this.dataDir, old)); } catch { }
  • 写入本地文件
    lib/restart.js:83
    try { appendFileSync(logFile, `${new Date().toISOString()} ${text}\n`); } catch { }
  • 读取本地文件
    lib/usage.js:21
    if (existsSync(file)) {
  • 读取本地文件
    lib/usage.js:22
    const parsed = JSON.parse(readFileSync(file, "utf8"));
  • 写入本地文件
    lib/usage.js:43
    mkdirSync(dirname(this.file), { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/usage.js:45
    writeFileSync(tmp, JSON.stringify({ version: 1, records: this.records }));
  • 写入本地文件
    lib/usage.js:46
    renameSync(tmp, this.file);
  • 执行外部命令固定命令
    lib/windows.js:25
    this.value = parse(execFileSync("reg", ["query", KEY, "/v", "AccentColor"], { encoding: "utf8", timeout: 3000, windowsHide: true, stdio: ["ignore", "p
  • 执行外部命令固定命令
    lib/windows.js:35
    execFile("reg", ["query", KEY, "/v", "AccentColor"], { timeout: 3000, windowsHide: true }, (error, stdout) => {
  • 读取本地文件
    lib/sync.js:46
    if (existsSync(this.tokenFile)) {
  • 读取本地文件
    lib/sync.js:47
    const saved = readFileSync(this.tokenFile, "utf8").trim();
  • 读取密钥环境变量
    lib/sync.js:55
    if (process.env.GITHUB_TOKEN) return { value: process.env.GITHUB_TOKEN, source: "env" };
  • 发起网络请求
    lib/sync.js:78
    const res = await fetch(API + path, {
  • 发起网络请求
    lib/sync.js:98
    const res = await fetch(`${API}/user`, { headers: { accept: "application/vnd.github+json", authorization: `Bearer ${value}`, "user-agent": "dsh-studio
  • 写入本地文件
    lib/sync.js:101
    mkdirSync(this.dataDir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/sync.js:102
    writeFileSync(this.tokenFile, value, { encoding: "utf8", mode: 0o600 });
  • 删除本地文件
    lib/sync.js:110
    try { unlinkSync(this.tokenFile); } catch { }
  • 发起网络请求
    lib/sync.js:161
    if (file.truncated && file.raw_url) content = await (await fetch(file.raw_url, { signal: AbortSignal.timeout(20_000) })).text();
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:www.bing.com、www.bing.com_1920x1080.jpg、raw.githubusercontent.com、api.deepseek.com、api.github.com

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 切换17款主题
  • 编辑自定义主题
  • 管理已存提示词

DeepSeek Harness 的主题与个性化:17 款主题、主题编辑器、液态玻璃面板、壁纸、自定义 logo 与问候语、已存提示词,还有 Ctrl+K 快速切换器

README

由 DeepSeek 最新模型翻译生成
Studio for DeepSeek Harness 为 DeepSeek Harness(DSH)打造的主题与个性化插件:18 款主题;主题编辑器,能根据一种心情、一种颜色、任意词语或任意图片生成主题;每个工作区一套主题;社区主题与提示词包画廊;液态玻璃面板;壁纸(Bing 每日图、幻灯片和视频);字体;按计划保存的外观,可跟随日出日落切换;Windows 强调色;布局控制与专注模式;AI 模式;任务完成提醒;用量与费用看板,带消费提醒;聊天导出为 Markdown 和 PDF;无障碍选项;更智能的已保存提示词;设置同步;Ctrl+K 快速切换器;19 种语言。 零 npm 依赖。除非你开启同步,否则设置只留在你的机器上。
展开完整文档(README 剩余 1 节)
Studio for DeepSeek Harness

为 DeepSeek Harness(DSH)打造的主题与个性化插件:18 款主题;主题编辑器,能根据一种心情、一种颜色、任意词语或任意图片生成主题;每个工作区一套主题;社区主题与提示词包画廊;液态玻璃面板;壁纸(Bing 每日图、幻灯片和视频);字体;按计划保存的外观,可跟随日出日落切换;Windows 强调色;布局控制与专注模式;AI 模式;任务完成提醒;用量与费用看板,带消费提醒;聊天导出为 Markdown 和 PDF;无障碍选项;更智能的已保存提示词;设置同步;Ctrl+K 快速切换器;19 种语言。

零 npm 依赖。除非你开启同步,否则设置只留在你的机器上。

Studio 使用 Liquid Glass 主题与磨砂玻璃面板

| 液态玻璃 + 个性化问候 | 快速切换器(实时预览) | 主题编辑器 |
| 壁纸上的磨砂玻璃输入框,问候语「Good night, RdotA」 | Ctrl+K 快速切换器预览 Tokyo Night | 主题编辑器:心情、单色、任意词语,Cyber 心情在整个应用中预览 |

| 社区画廊 | 用量与费用(示例数据) | 外观与计划,日语界面 |
| 画廊标签页,展示社区主题及其作者 | 用量标签页:总计、30 天图表和各模型价格 | 已保存外观与按时间段的计划,界面为日语 |

| 会先提问的提示词 | 已保存提示词 | 浅色模式(Synthwave) |
| 已保存提示词在插入前询问 Topic 和 Audience | 输入框旁的已保存提示词菜单 | 浅色模式下的 Studio 主题页面 |

安装

在应用内: 打开 DSH → 侧边栏 Plugins → Add plugin → 输入

github:IRdotAI/dsh-studio

在终端:

npx @deepseek-ai/dsh plugin --profile web add github:IRdotAI/dsh-studio

然后重启 dsh web。侧边栏会出现 Studio 入口。需要 DSH 0.2(已在 0.2.0-rc.2 上测试)、web 配置档和 Node 22.5+。安装插件时 pnpm 必须在你的 PATH 上(npm install -g pnpm)。

已经在 1.3 或更高版本?Studio 会自己提示更新(Studio → Updates)。

要卸载,在 Plugins 页面找到它的条目,点 Uninstall。

使用

- 侧边栏里的 Studio 包含全部功能,按标签页分类。在右上角选择语言(Automatic 跟随浏览器,如果 DSH 本身设为中文则跟随 DSH)。
- Ctrl+K(macOS 上是 Cmd+K)在任何地方都能打开快速切换器:主题(用方向键切换可实时预览,按 Esc 恢复你原来的主题)、你的外观、AI 模式、浅色/深色、文字大小、聊天宽度、专注模式、氛围、已保存的提示词、提醒、聊天导出、备份、更新,以及每个 Studio 页面。
- 在输入框里输入 /theme、/ai、/transcript、/prompts、/focus 或 /studio,或者点击输入框旁边的 ✦ 按钮,打开已保存的提示词。

功能

| 模块 | 你能得到什么 |
| 18 款主题 | Liquid Glass、Midnight、Dracula、Nord、Tokyo Night、Catppuccin、Rosé Pine、Gruvbox、Solarized、Forest、Ocean、Synthwave、Sakura、Arc Reactor、Espresso、Paper、AMOLED 和 High Contrast,外加默认外观。每款都有浅色和深色两个版本,所以 DSH 的浅色 / 深色 / 跟随系统切换照常可用。 |
| 按工作区设置主题 | 给任意工作区单独指定主题或外观,一眼就能区分不同项目。切换工作区时主题跟着变,回到其他地方则恢复你常用的主题。 |
| 主题编辑器 | 按模式分别挑选背景色、文字色和强调色,还能再加一个可选的第二强调色用于渐变。Studio 用 OKLCH 从这些颜色推导出每个表面、边框、按钮和文字色阶,并设置对比度下限,保证次要文字始终可读。实时对比度徽标配一键 Fix、屏幕取色器 💧、任意 CSS 颜色(rgb(…)、hsl(…)、tomato)、撤销/重做(Ctrl+Z / Ctrl+Y)、Make Light from Dark(以及反向操作)、色盲预览、编辑时全应用预览、可分享的 dshs1: 代码和 .json 主题文件。 |
| 生成主题 | 十二种情绪(Calm、Cozy、Cyber、Sunset……,每次点击都有新变化)、一种颜色配一条色彩和谐规则(单色、类似色、互补色、分裂互补、三角色)、任意词语(同一个词总是生成同一款主题),或者 🎲 给我惊喜。用 锁定 🔒 留住你喜欢的颜色,生成器会保留它们。微调滑块能整体移动主题(色相、鲜艳度、暖度、背景),变体提供八种现成的变化。文字始终可读。 |
| 从图片生成主题 | 用你的桌面壁纸、Studio 壁纸或任意图片生成主题:Studio 对图片颜色做聚类,挑出背景色调和强调色,并调整它们以适配两种模式的对比度。 |
| 社区画廊 | Studio → Gallery 列出其他用户分享的主题和提示词包;点一下就能添加一款主题或一整套提示词。在主题编辑器里点 Submit to the gallery,或者在提示词文件夹上点,会打开 GitHub 并带上你准备好的文件。见 gallery/。 |
| 外观与定时切换 | 把主题、样式和壁纸一起保存成命名外观,然后一键切换整套配置,或者按计划切换:在指定时间,或者你所在地的日出和日落时(比如日出用浅色主题,日落用 Liquid Glass)。你自己手动改的设置会一直保留,直到下一次切换。 |
| Windows 颜色 | 使用我的 Windows 强调色 会把当前主题的高亮色换成你的 Windows 强调色,之后你改强调色它也跟着变;跟随 Windows 浅色/深色 则随系统切换。 |
| 液态玻璃 | 样式 → 材质会把侧边栏、输入框、卡片、对话框、消息气泡和菜单变成磨砂透明的面板:背景模糊、淡淡的霜感、顶部高光边缘和一道斜向光泽。DSH 自己的界面元素在运行时定位,所以 DSH 更新后依然可用。匹配我的桌面 一键套用整套外观。 |
| 布局 | 聊天宽度(从窄到全宽)、界面大小(75–140 %),以及 专注模式,会把侧边栏和侧面板收起来。 |
| 壁纸 | 上传图片或使用 URL;(在 Windows 上)使用你的桌面壁纸,会跟随壁纸变化;Bing 每日,每天换一张图;幻灯片,从图片文件夹轮播,间隔从几分钟到一天一次;或者一段静音循环的 视频,窗口隐藏时暂停。可见度和模糊可调。 |
| 样式 | 界面字体和代码字体(预设、任意已安装字体,或一个装满 .otf/.ttf/.woff2 文件的文件夹)、圆角样式、强调色染色的聊天气泡、强调色文本选中、表面色调。 |
| 氛围 | 极光辉光、暗角、胶片颗粒或 CRT 扫描线,带强度滑块。绝不挡住点击;遵循减少动态效果设置。 |
| 身份 | 在侧边栏重命名应用,更换 logo(emoji、字母组合或你自己的图片,一键移除),并把新聊天标题换成问候语,比如 Good {timeOfDay}, {name},用你的语言。 |
| AI 偏好 | 可选的自定义指令:你的名字、关于你、回复风格(简洁、详尽、友好、导师、管家、激情)、回复语言和自由格式指令。默认关闭;该标签页会原样显示模型将收到什么。 |
| AI 模式 | 保存好的样式、语言和指令组合:起步有编程、写作、简单解释和头脑风暴,另外还有你自己保存的任意组合。在输入框用 /ai 切换,或按 Ctrl+K,或在 AI 标签页切换。 |
| 已保存提示词 | 六个起步模板;可以添加、编辑、排序,并把自己的提示词归入文件夹。插入时占位符会自动填充:{clipboard}、{date}、{time}、{day},以及 {ask:Topic},它会先问你。把所有提示词分享成一个 dshp1: 包代码,用代码或文件添加包,或把文件夹发送到画廊。 |
| 聊天导出 | /transcript(或 Ctrl+K → 导出此聊天)把打开的聊天保存为 Markdown 文件、PDF(用你主题的颜色,或白底黑字的朴素样式),或复制为 Markdown。 |
| 任务提醒 | 任务完成时发桌面通知并播放声音(四个内置音效,合成生成,音量可调),你也可以选择在智能体需要你批准或回答时提醒。只在你看向别处时提醒,而且如果你愿意,只提醒超过一定时长的任务。 |
| 用量与费用 | 每次模型调用的精确 token 数(输入、输出、缓存读取),今天、最近 7 天、最近 30 天和全部时间的总计,30 天图表,按模型分列的表,以及最近的调用记录。输入每百万 token 的价格,即可用八种货币查看花费。检查余额会向 DeepSeek 查询你的账户余额。 |
| 花费提醒 | 设置每日和/或每月预算。Studio 会显示已用掉多少,并在接近预算和达到预算时各提醒你一次(弹窗、声音和桌面通知)。 |
| 无障碍 | 高对比度主题、减少透明度(纯色面板,不显示壁纸;跟随 Windows 自身设置)、醒目的键盘焦点轮廓,以及字距更宽松的易读字体。 |
| 同步 | 把 Studio 设置备份到私有 GitHub Gist,在另一台电脑上恢复,可以手动,也可以在每次改动一分钟后自动进行。上传的图片留在本地,除非你选择一并包含。 |
| 19 种语言 | English、简体中文、繁體中文、日本語、한국어、Español、Français、Deutsch、Português (Brasil)、Italiano、Русский、Українська、Polski、Nederlands、Türkçe、Tiếng Việt、Bahasa Indonesia、हिन्दी 和 العربية(从右到左)。 |
| 高级 | 自定义 CSS(最后应用;使用 --dsw- 设计 token)、以 JSON 导出/导入设置、重置。 |
| 更新 | 有新版本时显示更新横幅和侧边栏圆点,可选自动更新,列出每个版本供更新、重装或降级,更新后自动重启 harness,让新版本自行接管。 |
| 致谢 | Studio 由谁打造、基于什么构建,以及每个改编主题配色的来源。 |

更新

Studio 从本仓库的 releases 自行更新:

- 有新版本时,Studio 顶部的横幅(以及侧边栏图标上的圆点)会提供 立即更新、开启自动更新 和 更新内容。
- Studio → 更新 列出每个版本。可以 更新 到更新的版本、重装 当前版本,或者在新版本带来麻烦时 降级 到旧版本。
- 开启 自动更新 后,Studio 每 6 小时检查一次 GitHub,并自行安装新版本。
- 安装走 DeepSeek Harness 自己的插件管理器(与 插件 → 添加插件 相同)。新版本只在全新的 harness 中运行,所以 Studio 随后会自行重启 DeepSeek Harness:你主动发起的更新立即重启,自动更新则在没有任务运行时重启。已打开的窗口会自行采用新版本。重启会复用启动 harness 时的原命令,在同一个终端或日志中,因此 Ctrl+C(或启动它的应用)仍能将其停止。可在 Studio → 更新 → 更新后自行重启 DeepSeek Harness 下关闭。用 dsh 命令以外的方式启动的 harness 需要手动重启,更新页面会说明这一点。
- 每次安装前都会备份你的设置(~/.dsh/studio/studio.backup-.json,保留最新五份)。
- 降级会自动关掉自动更新,这样 Studio 不会立刻又跳回去。
- 1.3.0 之前的版本没有 Updates 页面;要从这类版本回来,走 Plugins → Add plugin → github:IRdotAI/dsh-studio 再装一次。

一键更新要求 Studio 是从 GitHub 安装的。如果是从本地文件夹链接过来的副本(开发者安装),Updates 页面会说明这一点,并从那个文件夹更新。

隐私

- 设置存放在 ~/.dsh/studio/studio.json(或 $DSH_HOME/studio/studio.json),上传的图片也在里面。使用记录放在旁边的 usage.json,从不离开你的机器。
- Sync 在你添加 GitHub token 之前是关闭的。token 保存在 ~/.dsh/studio/github-token(只有你能读),从不发给浏览器,只用来和 GitHub 通信。备份会存到你账号下的私有 gist。
- Check balance 会把你已有的 DeepSeek API key 发给 DeepSeek 自己的余额接口,而且只在你按下按钮时才发。
- Gallery 标签页从 GitHub 上的这个仓库下载主题和提示词包列表。
- AI 偏好(以及模式)只在你开启它们时,才会加进模型的系统提示词。
- 用 URL 设置的壁纸由你的浏览器从那个 URL 拉取。上传的图片、幻灯片文件夹、视频文件和桌面壁纸从不离开你的机器。
- Bing daily 每天从 bing.com 下载当日图片一次,最近三张保存在 ~/.dsh/studio/bing/。
- Sunrise and sunset 使用你输入或授权一次的位置;位置会取整到约 10 km,只存在你的设置里。时间在你的机器上算出。
- Chat export 在浏览器里完成;不上传任何东西。

工作原理

DSH 插件有宿主端(Node)和浏览器端(React)两半。Studio 的宿主端负责存储设置,通过带鉴权的 /api/studio/ 路由提供这些设置,在每次页面加载时注入样式表(所以你的主题从第一帧就在),提供桌面壁纸和字体文件,读取 Windows 强调色,从 llm/stream 瀑布流记录 token 用量,执行 gist 同步,并贡献可选的系统提示词段落。浏览器端渲染 UI,并实时更新样式表。

主题化的做法是重新推导 DSH 的三套静态色阶(--dsw-static-neutral-bluish-、--dsw-static-neutral-、--dsw-static-deepseek-)。所有别名 token 都指向它们,所以整个界面会跟着变,同时保留原来的对比度阶梯。

| 文件 | 作用 |
| lib/shared.js | 纯核心:颜色计算、预设、调色板提取、样式表构建、设置校验、日程与日出日落时间、提示词占位符、用量总计与预算、人设文本与模式、聊天导出。两半共用。 |
| lib/index.js | 宿主端:设置文件、API 路由、首屏样式表、壁纸(桌面、Bing、幻灯片、视频)与字体服务、图库与余额查询、聊天导出、系统提示词区块。 |
| lib/updater.js | 在 GitHub 上查找发行版,并通过 harness 插件管理器安装更新或降级。 |
| lib/restart.js | 安装完成后重启 harness:先优雅关闭,再在同一进程树中重新执行同一条 dsh web 命令。 |
| lib/usage.js | 用量记录器:包装 llm/stream,保存每次调用的 token 数量。 |
| lib/windows.js | 读取 Windows 主题色。 |
| lib/sync.js | 私有 gist 备份与恢复。 |
| src/client/.js | 浏览器端源码,每个区域一个文件(store、styles、各个标签页、快速切换器、composer 按钮、斜杠命令、入口)。 |
| locales/.json | 界面文案,每种语言一个文件。英文已内置进 bundle,其他语言按需加载。 |
| lib/client.js | 生成产物,浏览器 bundle。修改 src/client/、locales/en.json 或 lib/shared.js 后,运行 node scripts/build.mjs。 |
| gallery/ | 社区主题与提示词包,以及生成的 index.json,供 Gallery 标签页读取。 |

API

所有路由都在 DSH 自带的浏览器认证之后。

- GET /api/studio/state:设置,以及这台机器能提供什么(桌面壁纸、已服务的字体、Windows 主题色)
- POST /api/studio/patch:局部更新(对象合并,数组替换)
- POST /api/studio/replace:整份设置导入
- POST /api/studio/reset,带 {"confirm":"reset-studio"}
- GET /api/studio/desktop-wallpaper:当前 Windows 壁纸
- GET /api/studio/bing-wallpaper:今天的 Bing 图片(每天下载一次)
- GET /api/studio/wallpaper-file?i=<n>:幻灯片文件夹中的一张图片
- GET /api/studio/video-wallpaper:视频壁纸文件(支持 Range)
- GET /api/studio/export?session=<id>:某个会话的消息,用于导出
- GET /api/studio/font?f=<file>:配置的字体文件夹中的一个文件(只服务该文件夹内的文件)
- GET /api/studio/updates:版本、发行版与更新状态;POST 时传 {"action":"check"}、{"action":"install","version":"x.y.z"} 或 {"action":"restart"}
- GET /api/studio/usage:用量总计与最近调用;POST 时传 {"action":"clear"} 或 {"action":"balance"}
- GET /api/studio/sync:同步状态;POST 时传 {"action":"set-token","token":"…"}、clear-token、push 或 pull
- GET /api/studio/gallery:社区图库(缓存一小时);POST 可刷新
- GET /api/studio/locale?lang=:某种语言的界面文案

开发

git clone https://github.com/IRdotAI/dsh-studio
cd dsh-studio
node scripts/build.mjs # rebuild lib/client.js
node test/selftest.mjs # 41 checks
node scripts/check-locales.mjs # every language has every string
node scripts/build-gallery.mjs # validate gallery themes and prompt packs, rebuild gallery/index.json
npx @deepseek-ai/dsh plugin --profile web add "$PWD" # install your local copy

改动 lib/ 下任何内容后都要重启 dsh web(宿主模块有缓存)。

添加语言: 在 lib/shared.js 的 LANGUAGES 里加上它,把 locales/en.json 复制成 locales/.json,翻译其中的值(保留每个 {placeholder}),然后运行 node scripts/check-locales.mjs。

DSH 插件里值得知道的坑:

- connection.fetch.register 的路径必须是以 /api/ 开头的完整路径,否则会抛 "invalid exact Fetch route"。
- 精确路由只按路径做键,所以同一个路径上的 GET 和 POST 必须写成一条路由,用 methods: ["GET", "POST"]。
- requestBody: "streaming" 的路由不能处理 GET(桥接层总会附带 body)。读取类请求保持 buffered。
- 宿主注入的 如果用 html:root body 选择器,优先级会高过 DSH 的 token 表,而且还能覆盖首屏绘制。
- DSH 会把菜单传送到 <body>,再按屏幕上的矩形定位,所以缩放应用要用 #root 上的 zoom,绝不要用 。
- 插件斜杠命令如果和宿主命令同名(/export、/plan、/goal……),整个 / 菜单都会失效。宿主行还排在前面,所以名字只要是宿主命令的开头(/mode 对 /model),就永远没法用 Enter 选中。Studio 在提供自己的每条命令之前,都会先检查宿主的命令。

致谢

由 RdotA 制作。主题配色改编自 Dracula、Nord、Catppuccin、Gruvbox、Solarized、Tokyo Night 和 Rosé Pine。完整致谢与链接见 CREDITS.md,应用内也在 Studio → Credits 里。

许可

MIT
预览分享卡片长什么样 ↓IRdotAI/dsh-studio
分享 · DeepSeek Harness Hub
IRdotAI/dsh-studio

换主题、调外观、管提示词,一站搞定界面个性化

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部