Skip to content
dsh.fish
Bundle

dsh-macos-desktop

Retro macOS (System 7 / Mac OS 9) desktop UI for DSH web: chat, files, terminal, browser, docs and knowledge base inside one pixel desktop

Source
Taylor-Cat
stars
5 stars
License
MIT
Updated
Updated 3 days ago

Readme

# dsh-macos-desktop

把 DeepSeek Harness (DSH) 的 Web 界面改造成一个 **复古情怀 + 现代 macOS(Big Sur / Sonoma)质感** 的桌面系统。它**不替换**官方界面,而是通过 DSH 官方 `shell.overlay` 槽位,在官方对话之上叠加一整块桌面:

- **左侧** = macOS 桌面(壁纸 / 图标 / 多窗口系统);
- **右侧** = DSH 原生对话界面(CSS 主题化成 macOS 浅色/深色风,功能全保留);
- **顶部**菜单栏横跨全屏(时钟 / 天气 / 迷你日历 / Spotlight),**底部** Dock 悬浮(分组 + 运行指示点 + 角标),中间可拖动分隔条。

一句话:**把 DSH 装进一台「Mac」**——文件、终端、文档、浏览器、知识库、便签、番茄钟、截图、AI 生图、AI 看图,都在同一个窗口系统里完成,同时官方对话能力一个不丢。

### 为什么做它

- 想让 DSH 用起来像一台「电脑」而不是一个聊天框:桌面图标、窗口、Dock、菜单栏、回收站这些熟悉的心智模型,让文件/终端/文档/对话能**同屏协作**。
- **官方 UI 功能一个不丢**:右侧就是原生对话(实时 mux 流、工具轨迹、token 用量、权限、模型切换),只是被主题化;菜单栏「DSH ▸ 显示原始界面」一键切回,卸载插件后界面原样恢复。
- 纯前端 + 纯 JS 实现,无原生模块、无构建步骤;Windows / macOS / Linux 全兼容。

### 核心特性速览

| 类别 | 能力 |
|---|---|
| **桌面** | 左右分栏 + 毛玻璃、多窗口、Aero Snap 边缘吸附、Spotlight 搜索(⌘K)、迷你日历、天气、深色模式、开机蓝鲸动画 |
| **文件** | 隔离的 `desktop/` 目录、回收站、便签(位置持久化)、拖拽上传、右键菜单(复制路径 / 设为壁纸 / 用 AI) |
| **应用** | 终端(Win powershell/cmd + POSIX PTY)、多标签浏览器、文档办公(docx/pdf/pptx + 富文本)、知识库、计算器、番茄钟 |
| **AI** | 原生对话、用 AI 看图(modlens)、截图→自动看图→发给 AI、@知识库引用、AI 生图(DashScope 通义万相)、进度条 + Token 组件 |

### 快速开始

```sh
# 安装(发布到 GitHub 后)
dsh plugin --profile web add github:你的用户名/dsh-macos-desktop
# 或本地开发(改代码重启即生效)
dsh plugin --profile web add link:../dsh-macos-desktop

dsh web   # 重启后打开 http://127.0.0.1:3080,Ctrl/Cmd+Shift+R 硬刷新
```

> 详细安装方式、环境变量、验证步骤、安全边界见下文各节。

---

## 0. 这是什么 / 不是什么

**是**:一个符合 DSH 插件规范的 npm 包(`dsh.bundle` + `dsh.client`),宿主半侧跑在 DSH Node 进程里提供文件/终端/文档的 HTTP 面,浏览器半侧画出一整块复古桌面。

**不是**:不修改 DSH 框架源码;不引入 playwright/puppeteer/原生模块/构建步骤;不另起炉灶重写对话(对话复用官方 session 流)。

---

## 1. 前置环境

| 依赖 | 版本 | 说明 |
|---|---|---|
| Node.js | ≥ 22.19.0(本仓库在 v24.19.0 上验证过语法) | DSH 0.1.x 要求 Node 22+ |
| npm | ≥ 9 | 随 Node 附带 |
| pnpm | 任意较新版本 | `dsh plugin` 实际是转发给 pnpm |

安装 DSH 并启动 Web(首次会自动初始化 `web` profile):

```sh
# 全局安装 DSH 启动器(如已安装可跳过)
npm install -g @deepseek-ai/dsh

# 启动 Web 界面(默认 http://127.0.0.1:3080)
dsh web

# 换端口启动
dsh web --port 8080
```

> 说明:`dsh web` 是 `dsh --profile web` 的别名。启动器自己的 flag 要写在最前面;`--port` 属于 web 应用,写在 `web` 之后。

---

## 2. 插件安装(以本机实际核实的 `dsh plugin` 子命令为准)

`dsh plugin --profile <name> <pnpm 参数>` 会在 profile 目录里把后面的参数原样转发给 pnpm,因此子命令就是 pnpm 的子命令。下面用绝对路径 `<插件目录>` 代指本仓库目录,例如 `C:\Users\you\dsh-macos-desktop`。

### 2.1 本地目录(file: 安装,复制)

```sh
dsh plugin --profile web add "C:\Users\you\dsh-macos-desktop"
```

等价于在 profile 里执行 `pnpm add <绝对路径>`。**file: 安装是复制不是链接**,之后改代码不会生效,需要 `remove` 再 `add`,或干脆重启 DSH。

### 2.2 tgz 包

```sh
# 先在本仓库目录打包(可选,直接 add 目录也行)
npm pack
# 安装 tgz(相对路径会被锚定到你执行命令的目录)
dsh plugin --profile web add ./dsh-macos-desktop-0.1.0.tgz
```

### 2.3 GitHub / git 仓库

```sh
dsh plugin --profile web add github:你的用户名/dsh-macos-desktop
# 或
dsh plugin --profile web add "git+https://github.com/你的用户名/dsh-macos-desktop.git"
```

> git 托管的插件如果带 `prepare` 构建脚本,pnpm 默认会拦截,按 pnpm 打印的提示在 profile 目录的 `pnpm-workspace.yaml` 里加入 `allowBuilds` 再重跑。**本插件无构建步骤**,直接可用。

### 2.4 link: 链接安装(开发时改代码即生效)

```sh
dsh plugin --profile web add link:../dsh-macos-desktop
```

`link:` 是软链接,改代码后重启 DSH 即生效(适合调试)。但注意 link 安装不经过 `files` 字段裁剪。

### 2.5 更新 / 查看 / 卸载

```sh
# 更新
dsh plugin --profile web update dsh-macos-desktop
# 查看已装依赖
dsh plugin --profile web list
# 卸载
dsh plugin --profile web remove dsh-macos-desktop
```

卸载后再重启 + 硬刷新,官方界面原样恢复。

---

## 3. 配置文件逐行解释

### 3.1 `package.json` 关键字段

```jsonc
{
  "name": "dsh-macos-desktop",          // 包名 = 插件 ID = 客户端 bundle id,三处必须一致
  "type": "module",                     // 宿主半侧是 ESM(lib/index.js 用 named export)
  "main": "lib/index.js",               // 宿主半侧入口
  "exports": {
    ".": { "default": "./lib/index.js" },
    "./client": { "default": "./lib/client.js" },  // 浏览器半侧入口(client-modules 从这里读)
    "./cordis.patch.yml": "./cordis.patch.yml",    // bundle patch 导出
    "./package.json": "./package.json"
  },
  "dsh": {
    "bundle": { "patch": "./cordis.patch.yml" },   // 声明这是 bundle,patch 参与宿主组合层
    "client": { "platform": "web" }                // 声明这是 web 客户端插件,进 __DSH_BOOT__
  }
}
```

> 关于字段的一点校正:DSH 0.1.x 的 `dsh.client` **没有 `id` 字段**——插件 ID 就是包名,客户端 bundle 的 `id` 也等于包名。字段只有 `platform`(必填,`"web"`)和可选的 `inject`(跨包模块依赖边)、`immediately`。不要写 `"client": { "id": "..." }`,那样既无效还容易和真实包名不一致。

### 3.2 `cordis.patch.yml`

```yaml
# 把本包作为一个宿主平面 row 插入组合:
- insert:
    - id: dsh-macos-desktop   # row id,与包名一致
      name: 'dsh-macos-desktop'  # 解析到本包(宿主半侧 lib/index.js)
```

- 这个 patch 在 `dsh-base`、`dsh-web-app` 之后、profile 自己的 `cordis.patch.yml` 之前叠加。
- `client-modules` 的节点半侧会扫描带 `dsh.client` 声明的 row,把 `/plugins/dsh-macos-desktop/client.js` 注入 `window.__DSH_BOOT__`。
- row id 与包名一致是硬要求:客户端 bundle 的 `id` 就是包名,模块表按这个 id 解析 `/plugins/<id>/client.js`。

### 3.3 宿主半侧 `lib/index.js` 的注入

```js
export const name = 'dsh-macos-desktop'
export const inject = ['webServer', 'fs', 'subprocess', 'workspaceRegistry']  // 硬依赖(宿主平面服务)
export function apply(ctx) { /* 注册 HTTP 路由 + 终端 + 文档 + 统计 */ }
```

`webServer` / `fs` / `subprocess` 都是 `dsh-base` + `dsh-web-app` 提供的宿主平面服务;`sandboxPolicy` / `tokenMeter` / `sessions` / `sessionQuery` 用 `ctx.get()` 可选读取,缺了也能启动(对应功能降级)。`shell`(bash executor)不再依赖:mkdir/rename/delete 改用跨平台的 `node:fs`,因为 Windows 上没有 `bash`,POSIX 的 `mkdir -p`/`mv`/`rm -rf` 走不通。

---

## 4. 环境变量

### 4.1 本插件自身

本插件**没有密钥**。它复用 DSH 自己的模型与凭据体系(对话走 DSH 官方 `session.prompt`),所以不需要也不接受任何私钥环境变量。文档、终端、文件都只在授权 workspace 内操作(见 §9 安全边界)。

### 4.2 DSH 官方环境变量(按需)

| 变量 | 作用 | 取值/默认 |
|---|---|---|
| `DSH_HOME` | DSH 数据根目录 | 默认 `~/.dsh` |
| `DSH_PERMISSION_MODE` | 权限预设(文件/终端操作权限) | `workspace-write`(默认)/ `danger-full-access` |
| `DSH_TOOLS_MODE` | 工具呈现模式 | `native` / `code` / `both`,默认 native |
| `DEEPSEEK_API_KEY` | DeepSeek 模型 API 密钥 | 通过凭据 seam 解析,也可写入 `$DSH_HOME/.credentials.yaml` 或受信环境层 |
| `DSH_WEB_SEARCH_PROVIDER` | Web 搜索提供方 | 如 `deepseek` |
| `DSH_WEB_FETCH_PROVIDER` | Web 抓取提供方 | 按部署 |
| `DSH_WEB_URL` | 本会话 Web GUI 地址 | 由 DSH 自动注入 |
| `DASHSCOPE_API_KEY` | 「AI 生图」用,阿里云百炼(DashScope)密钥(可选,优先读环境变量) | 用户自备;设置后重启 `dsh web` |

> **DashScope Key 安全存放(不暴露给 AI)**:Key 存**工作区之外**的密钥文件 `$DSH_HOME\secrets\dashscope.key`(默认 `C:\Users\<你>\.dsh\secrets\dashscope.key`),宿主进程启动/调用时读取,AI 会话受沙箱限制读不到、也不会被打印或回显。配置步骤(任选其一):① 环境变量 `set DASHSCOPE_API_KEY=sk-xxx` 后重启;② 密钥文件:`mkdir "$env:USERPROFILE\.dsh\secrets"; Set-Content "$env:USERPROFILE\.dsh\secrets\dashscope.key" "sk-xxx"` 后重启。生图时自动读取,界面只显示「未配置」提示、不显示 Key。

> 关于默认模型:DSH 0.1.x **没有 `DSH_MODEL` 环境变量**。默认模型在设置里(`agent-default-model`),会话模型在 Web 界面右上角模型选择器里选。密钥用 `DEEPSEEK_API_KEY`(或其它 provider 对应变量),不要写死在代码或 patch 里。

> 「用 AI 看图」依赖 `modlens` CLI:`npm i -g @liustack/modlens`(未装时该功能会给出安装提示,不影响其它功能)。Windows 下已修复「未安装」误报:调用改用 `node <modlens>/dist/main.js -i <图片>`(不依赖 `modlens.cmd`/PATH),找不到时才报安装提示;引擎未配置(Gemini key / Antigravity)会引导跑 `npx @liustack/modlens doctor`。

---

## 5. 验证

```sh
# 1) 确认已安装
dsh plugin --profile web list

# 2) 确认组合进了配置树(应能看到 dsh-macos-desktop 这一 row)
dsh --profile web --dump-config

# 3) 重启 + 硬刷新
dsh web
# 浏览器打开 http://127.0.0.1:3080 后按 Ctrl/Cmd + Shift + R 硬刷新
```

预期:硬刷新后先看到深色开机画面(蓝鲸 + 进度条)→ 弹"开机统计"框 → 进入桌面(顶部菜单栏、底部 Dock、桌面文件图标)。Dock 点「AI 助手」开对话,点「文件」开文件管理器,「终端」「浏览器」「文档」「知识库」同理。菜单栏 "DSH ▸ 显示原始界面" 切回官方 UI,左上角会出现 "DSH 桌面" 按钮切回来。

### 5.1 开发期自检脚本(可选,本仓库自带)

```sh
# 结构自检(package.json + cordis.patch.yml + 入口文件)
node verify-structure.cjs .

# 宿主半侧冒烟(import + apply() 注册 33 条路由不抛错)
node smoke-host.cjs
```

---

## 6. 常见坑

| 现象 | 原因 | 解法 |
|---|---|---|
| `file:` 安装改代码不生效 | file: 是复制不是链接 | `remove` 再 `add`,或改用 `link:`,或重启 |
| `Cannot find package dsh-macos-desktop` | 相对路径装到了 profile 目录里 | 用**绝对路径**,或让相对路径以 `./`/`../` 开头(会被锚定到当前目录) |
| patch 没生效 | patch 路径写了相对路径 | `dsh.bundle.patch` 用 `./cordis.patch.yml` 这种包内相对路径;profile 内引用用绝对路径 |
| `service "xxx" is not declared` | 宿主/客户端用了 `ctx.xxx` 却没在 `inject` 声明 | 声明 `inject`,或用 `ctx.get('xxx')` 可选读取 |
| 客户端 bundle 加载但页面报错 | 客户端用了 JSX/TS/import | 客户端用 `React.createElement` + 纯 JS,只从平台模块表 `require('react')` |
| 插件 ID 不一致 | 包名 / bundle id / `window.__ModuleLoader__.load({id})` 三处不一致 | 三处都写 `dsh-macos-desktop` |
| git 插件装不上 | pnpm 拦截了 `prepare` 构建 | 按提示在 profile 的 `pnpm-workspace.yaml` 加 `allowBuilds` |
| 文档功能报"依赖未安装" | doc 库懒加载失败 | 确认 `dsh plugin --profile web list` 里有 docx/mammoth/pdf-lib/pdf-parse |

---

## 7. 系统级依赖

**无。** 本插件文档处理全用纯 JS 库,不需要 LibreOffice、不需要系统字体、不需要原生模块。

- Windows / macOS / Linux:安装命令都是空的,装完 Node + pnpm + DSH 即可。

---

## 8. 文档处理依赖清单与选型理由

| 库 | 版本 | 用途 | 理由 |
|---|---|---|---|
| `docx` | ^8.0.0 | 新建/生成 `.docx` | 纯 JS 生成 Word(OOXML),无原生依赖 |
| `mammoth` | ^1.6.0 | 读取 `.docx` → 文本/HTML | 稳定、纯 JS,专注提取内容 |
| `pdf-lib` | ^1.17.1 | 新建 `.pdf` | 零依赖纯 JS,`save()` 出字节流 |
| `pdf-parse` | ^1.1.1 | 提取 `.pdf` 文本 | 轻量;代码里直接 `import 'pdf-parse/lib/pdf-parse.js'` 跳过其 CLI 守卫 |
| `pptxgenjs` | ^3.12.0 | 新建/生成 `.pptx` | 纯 JS 生成 PowerPoint(OOXML),无原生依赖 |

预览策略(省依赖):

- `.pdf` 预览走**浏览器原生渲染**:宿主把文件以 `application/pdf` 原样返回,桌面用 `<iframe>` 展示(不需要任何 PDF 渲染库)。
- `.docx` 预览走 `mammoth` 提取文本后展示。
- `.pptx` 生成走 `pptxgenjs`(标题页 + 每段一页),预览暂无内建渲染器(走「用外部程序打开」)。
- 图片(png/jpg/gif/webp/svg)预览走 `<img>`。
- 这些依赖都是懒加载(`await import(...)`),某个库没装上也不会拖垮插件启动。

---

## 9. 安全边界(重要)

- **只操作授权 workspace**:宿主半侧对每个路径做 `withinRoot(workspaceRoot, path)` 校验。`workspaceRoot` 优先取 `workspaceRegistry.list()[0].path`(`dsh-workspace` 的持久化权威工作区,迁移改名后也正确),取不到才回退到 `sandboxPolicy.workspaceRoot`(它默认是 `process.cwd()`,即 DSH 启动目录,可能指向主目录而非真正工作区)。越界路径直接 `400 拒绝访问`(Windows 下比较时不区分大小写)。
- **文本读写走沙箱 `fs` 服务**(`fs.readText` / `fs.writeText` / `fs.listDir` / `fs.readBytes`)。
- **mkdir / rename / delete 用 `node:fs`**(`mkdir({recursive})` / `rename` / `rm({recursive,force})`),在 `withinRoot` 校验通过之后才执行——这样 Windows 上也无需 bash 即可完成文件管理。**delete 现在改为「移到回收站」**(`workspace/.trash/`,带 `.meta.json` 记录原路径),可还原/清空;仅「清空回收站」才真正 `rm`。
- **二进制写(docx/pdf 生成)用 `node:fs`**,同样在 `withinRoot` 校验通过之后才落盘,因为 `fs` 服务只有文本写、没有字节写。
- **桌面图标区**:只通过专用路由 `/api/desktop` 列出 workspace 内 `desktop/` 文件夹的内容(该目录不存在时自动创建),**绝不**列出 workspace 根目录或任何真实系统目录(主目录 / AppData / NTUSER.DAT 等)。「此电脑」入口也只以 workspace 根目录为边界(`withinRoot` + 前端根目录钳制双重限制)。
- **终端**:只允许 `cwd` 在 workspace 内;POSIX 走 `subprocess.spawnTerminal`(`/bin/bash --noprofile --norc -i`),Windows 走 `subprocess.spawn` 起的持久 `powershell.exe`/`cmd.exe`(受限模式下均经 `sandbox.confine` 包装)。
- **知识库 / 壁纸 / 便签**:一律走 `withinRoot` 校验的 workspace 内路径;知识库「任意本地目录」实际受沙箱限制为 **workspace 内任意目录**(workspace 外会被拒绝,这是安全边界,不是 bug)。

一句话:**绝不触碰 workspace 之外的路径**。

---

## 10. 内嵌浏览器(iframe)说明

「浏览器」应用是纯 iframe,不做服务端抓取(不引入 playwright/puppeteer)。

- 很多站点通过 `X-Frame-Options: DENY/SAMEORIGIN` 或 `CSP frame-ancestors` 禁止被嵌入,iframe 会白屏或报错。本应用检测到加载失败会给出友好提示页:「该站点禁止被嵌入,可尝试在外部打开」,并提供"在外部打开"按钮。
- 常见**可**嵌入(或提供 embed 版)的站点:`https://example.com`、维基百科、MDN、GitHub 的 embed 页、各大站点公开的 embed 页面等;常见**禁止**嵌入:google.com、facebook、银行等。
- 宿主端说明:iframe 的 `sandbox` 设为 `allow-scripts allow-same-origin allow-forms allow-popups`,没有放开 `allow-top-navigation` 等危险项;`frame-src` 无需额外配置(同源 iframe 不受 DSH 自身 CSP 限制,因为内容是用户输入的第三方 URL)。
- 混合内容说明:若 DSH 跑在 `http://127.0.0.1`,嵌入 `https://` 站点没问题;反过来在 `https://` 页面嵌 `http://` 会被浏览器拦截(本插件不涉及)。

---

## 11. 对话界面怎么做的(复用官方能力)

「AI 助手」窗口**完全复用 DSH 官方会话能力**,不另造轮子:

- 通过客户端 `ctx.sessions`(官方 `SessionRuntime`,它内部已持有官方 mux 事件流)拿到**实时推送**:`session.getSnapshot()` + `session.subscribe()` 直接读组装好的对话快照,回复/工具调用**逐块实时流出,不再轮询**。
- 发送/停止/重命名走 `session.prompt` / `session.cancel` / `session.rename`;会话列表走 `sessions.list`;新建走 `sessions.create`;搜索走 `sessions.search`。
- 工具调用轨迹来自快照里的 `tool-result` 节点(默认收起,可展开看参数/结果),token 用量来自 `assistant` 节点的 `usage` 累加。
- 模型切换(deepseek-v4-pro/flash)与思考强度(Off/High/Max)通过 `connection.api.sessions.selectModel` 写入当前会话。
- 权限设置、模式/工作区切换、更完整的轨迹/上下文占用等,走菜单栏 "DSH ▸ 显示原始界面" 切回官方 UI 操作——**官方能力一个没丢,只是不重复实现**。

### @知识库 引用(B4)

在输入框里用 `@知识库名 问题` 发送,插件会:把知识库目录做关键词检索(文件名 + 文本内容 grep,不搞向量检索),取前 6 条片段拼接成 `【知识库相关内容】+【用户问题】` 一起 `session.prompt` 注入上下文。这是**检索-注入**(RAG 的朴素版),不是向量召回;`@知识库名` 来自「知识库」应用里自建的库。

---

## 12. 已实现 / 已知限制 / 后续建议

### 12.1 已实现

- **左右分栏布局(核心)**:左侧 = macOS 桌面(壁纸/桌面图标/窗口系统),右侧 = DSH **官方对话界面**(CSS 覆盖成 macOS 风格,功能全保留),常驻右侧不再藏进「显示原始界面」。**顶部菜单栏横跨全屏,Dock 悬浮于底部之上**(不占空间,左右纵向都占满);中间可拖动分隔条调整两侧比例(20%–80%)。
- **底部 Dock(悬浮 + 精致图标)**:像素图标(此电脑/文件/文档/终端/浏览器/知识库/AI 生图/计算器/回收站/设置),**已移除「AI 助手」重复入口**(原生对话常驻右侧,是唯一对话入口);图标**可添加/删除**(右键移除,+号菜单加回,持久化到 localStorage)。图标用「圆角矩形 squircle + 上下渐变 + 居中像素 glyph + 顶部高光」重绘,参考 macOS 图标质感。
- **现代 macOS 风格(Big Sur / Sonoma 质感)**:更大圆角(窗口 16px/卡片/按钮 8–12px)、更高毛玻璃(blur 24–34px + saturate 170–185%)、蓝色 accent `#0a84ff`、柔和渐变壁纸(内置 + 用户照片)、细腻双层阴影、系统字体(SF Pro/Segoe UI)、窗口红黄绿「交通灯」按钮、Dock squircle 图标带高光。
- **官方对话界面风格化(稳健版)**:用 `body{--dsw-alias-*:...!important}` 覆盖 DSH 主题 token(背景/文字/边框/品牌/状态色全套),`color-scheme:light`,右侧真正变浅色 macOS 风,功能(对话/工具轨迹/token/权限/模式切换)全保留。**分栏选择器改用结构选择器 `*:has(> [data-shell-overlay])`**(降级保留 `.pI_x6G_frame`),不再依赖会随 DSH 构建变化的哈希类名。
- 桌面文件 = **`desktop/` 文件夹**内容(隔离目录,绝不显示真实系统目录);**3 秒轮询 + 右上角「↻」手动刷新按钮**,系统里放进/删除/重命名文件即时反映;**每个文件浏览窗口独立维护 cwd + 乱序响应丢弃守卫**,点不同文件夹/此电脑不会串目录;右键菜单(新建/排列/刷新 + 文件:打开/用 AI/重命名/删除/**设为壁纸**,文件窗口与桌面图标均可用)。
- **回收站(废纸篓)**:删除改为「移到回收站」(`workspace/.trash/`),可还原/清空;宿主持久化映射元数据。
- **复古计算器**:加减乘除,Dock 一键打开。
- **菜单栏像素数字时钟**:HH:MM:SS 实时刷新。
- **顶栏 Big Sur 菜单 + 天气**:菜单重构为「🍎 + DSH 桌面 + 文件/显示/窗口/帮助」分组(把新建/刷新/最近打开/排列方式/设置/关于本机/折叠桌面等合理归类,去掉重复标签);右侧显示**郑州实时天气**(Open-Meteo 免费 API,温度 + 天气图标,失败/离线优雅降级为「—」)。
- **浏览器外部打开**:工具栏常驻「外部打开」按钮(当前 URL 一键唤起系统浏览器,弹确认防误触);被拒嵌入页的「在外部浏览器打开」同样确认后打开。
- **对话 @ 知识库弹窗**:输入框输入 `@` 弹出知识库选择列表,点选插入 `@库名 `;保留手动输入 `@库名` 方式兼容。
- **知识库管理修复**:创建/删除/重命名/切换/搜索逻辑重构(`cur` 派生自 id 消除竞态),并修复「留空目录会错误建到 workspace 根」的宿主 bug(现在自动建到桌面子目录)。
- **PDF/Word 预览增强**:PDF 走 iframe + 顶部「在新窗口打开」;Word 用 `mammoth.convertToHtml` 渲染**可读 HTML**(标题/列表/表格保留),不再是纯文本。
- **文档办公富文本**:新建文档带格式工具栏(字号 12/14/16/18/20pt、加粗、斜体、自由换行),格式真实落盘——`.docx` 用 run 的 `bold/italics/size`、`.pdf` 用 Helvetica Bold/Oblique + `fontSize` 内联排版、`.pptx` 用 pptxgenjs 生成(标题页 + 每段一页),`.txt` 纯文本丢格式(正常)。格式选择器新增「PPT (.pptx)」。
- **趣味彩蛋**:开机加载随机复古梗(「正在转动 1.44MB 软盘…」「正在给鲸鱼喂鱼…」)、回收站俏皮文案、Dock hover 带梗提示、终端错误语气轻松化、**开机鲸鱼连续点击冒泡吐梗**。
- **用 AI 看图(3.1 已接入)**:右键图片 →「用 AI 看图」→ 宿主跑 `modlens` 输出结构化 JSON(OCR/版面/语义)→ 弹窗展示 + 「发给 AI 助手」。需 `npm i -g @liustack/modlens`。**调用方式已修复**:不再依赖 PATH 里的 `modlens.cmd`(Windows 下找不到导致误报「未安装」),改为 `createRequire` 精确解析 `@liustack/modlens/dist/main.js` 后用 `node <main.js> -i <图片> --timeout 180000` 调用,并正确解包 `JSON.result`;失败提示会引导你跑 `npx @liustack/modlens doctor` 检查视觉引擎(Gemini key / Antigravity `agy`)是否配好。
- **AI 生图(3.2 已接入)**:Dock「AI 生图」app——提示词 + 比例(1:1/16:9/4:3)+ 风格(插画/像素/复古/写实)+ 可选参考图(经 modlens 视觉描述增强 prompt),走 DashScope 通义万相 `wanx-v1` 文生图(异步任务轮询),需 `DASHSCOPE_API_KEY`。
- 对话窗口(自定义 ChatApp)保留:官方 mux 事件流实时推送、Markdown、代码复制、工具折叠、会话重命名/搜索、模型切换、@知识库 注入、用 AI 处理。
- **任务进度条 + Token 组件数据源**:直接从 DSH 官方 `sessions` 服务的 mux 快照取数(订阅当前会话 `snapshot`,累加 assistant 节点 `usage` 得 token、统计 `runningCalls`/`tool-result` 得进度),**不再依赖自定义 ChatApp 窗口**——原生对话常驻右侧后这两个小组件依然实时更新;进度条窗口只在「开机完成后且任务进行中」出现,不再在加载界面弹出。
- **桌面 3 秒轮询改为「变更检测」**:`loadDesktop` 每次拿到目录列表后先算签名(`type:path` 拼接),内容未变就不 `setState`——避免每 3 秒整棵桌面子树重渲染,加载更顺、CPU 更低;文件增删/改名仍即时反映(签名变了才刷新)。
- **whale-girl 宠物层级修复**:桌面 overlay 与 whale-girl 宠物同处 `z-index:2147483000`,DOM 顺序可能把宠物埋到桌面下;本插件加 `[data-whale-girl]{z-index:2147483600!important}` 让宠物**永远浮在最上层**,无论拖到哪都可见、可点。
- **Spotlight 搜索(⌘K / Ctrl+K 或菜单栏🔍)**:居中出现搜索框,搜 App + 搜文件(复用 `/api/search`),回车/点击直接打开,Esc 关闭。
- **深色模式**:设置里新增「深色模式」主题,桌面与右侧官方对话一起变暗(`body.dsm-dark` 覆盖 `--dsw-alias-*` + `color-scheme:dark`)。
- **Dock 分组分隔线 + 回收站角标**:此电脑与回收站/设置之间加竖分隔线;回收站非空时 Dock 图标右上角亮红点角标(10 秒轻轮询 + 删除/还原/清空即时刷新)。
- **迷你日历**:点菜单栏时钟弹出当月日历(今天高亮、跨月灰显)。
- **窗口最小化动效**:最小化时窗口缩放淡出「缩进 Dock」,点 Dock 图标弹回(`transition` + `dsm-minimized`,关闭仍即时隐藏)。
- **拖拽上传到桌面/文件窗口**:本地文件拖进桌面或文件窗口即上传(宿主新增 `/api/upload`,raw body 二进制 + `dir`/`name` 查询参数,仍走 `withinRoot` 校验)。
- **多窗口**:文件/浏览器/终端/编辑器/预览/文档等支持**开多个窗口**(双击不同文件夹/文件各自开新窗,标题带文件名、级联错位);设置/计算器/回收站/知识库/文档办公/生图/对话仍是单实例。
- **桌面图标拖动 + 网格吸附记忆**:桌面右键「排列方式」关掉「自动排列」后,图标可拖动,松手吸附 96px 网格并记住位置(localStorage);重开「自动排列」恢复自动排序。
- **窗口边缘吸附(Aero Snap)**:拖动窗口到桌面区顶部=最大化、拖到左/右边缘=半屏。
- **便签增强**:便签位置持久化(拖动后记住,刷新不丢);Dock 新增「便签」图标一键新建(原右键「新建便签」仍可用)。
- **番茄钟**:Dock 新增「番茄钟」——25 分钟专注 / 5 分钟休息,开始/暂停/重置/切换,到点 Toast 提醒。
- **截图工具**:Dock 新增「截图」——一键把桌面面板截成 PNG(存到 `desktop/screenshots/`),并**自动「用 AI 看图」**(modlens 描述 + 「发给 AI 助手」)。纯前端 DOM→canvas 实现,无新依赖。
- **UI 更贴近现代 macOS**:窗口圆角 16→18px、阴影更柔和、交通灯按钮加内描边/高光、毛玻璃 blur/saturate 微调。
- 其余原功能全保留:终端(Windows powershell/cmd 适配)、多标签浏览器、知识库、3 弹窗、Token 组件、设置、便利贴、关于本机、最近文件、8bit 鲸鱼、进度条、窗口拖动/缩放/最大化、开机流程。

### 12.2 已知限制

- 终端是 SSE + POST,不是 WebSocket;输出为纯文本(TERM=dumb),不做 xterm.js 的完整 ANSI 渲染。
- Windows 终端的平台限制(如实说明):① 官方 `dsh-subprocess-local` 的 `spawnTerminal` 在 win32 上直接抛 `terminal inspection is unsupported on platform win32`,因此本插件在 Windows 改用 `subprocess.spawn` 的**管道终端**(无真 PTY),不做 ANSI 渲染、无真前景进程组;② 管道模式下 **Ctrl+C 无法中断正在运行的命令**(`0x03` 会被忽略,这是 Windows 管道终端的固有限制);③ Windows PowerShell 5.1(`powershell.exe`)非 ASCII 输出默认走 OEM 代码页,可能乱码,`pwsh` 7 默认 UTF-8 无此问题。要完整终端体验仍建议在 Linux/macOS 上使用。
- 右侧官方界面的配色覆盖走 `body{--dsw-alias-*:…!important}`(DSH 主题 token 写在 body 内联,author-important 才能压过);分栏选择器已改为结构选择器 `*:has(> [data-shell-overlay])` + `.pI_x6G_frame` 双保险,升级 DSH 后哈希变化也能命中——功能不受影响,只影响样式。
- **壁纸/毛玻璃新方案**:壁纸设为**整个页面背景**(`body`,左右共享同一张),左桌面 overlay 透明、右官方界面的**内部容器**(侧边栏/聊天区列)的 `::before` 伪元素加 `backdrop-filter: blur` 半透明磨砂——不给 frame/列本身加 backdrop-filter(会建立 containing block 破坏左侧 overlay 的 fixed 定位、并困住设置弹窗),改在列的 `::before` 上做真模糊。**官方设置弹窗保持全屏居中、z-index 高于桌面 overlay**,不被 Dock/菜单栏/窗口遮挡、可正常点击。
- 进度条没有"总步骤数"权威来源,用"当前工具名 + 工具调用数"估计,跑到 90% 封顶直到结束。
- 余额/费用:token 单价是**内置估算值**(¥/百万 token,见 `lib/client.js` 的 `PRICES`),不是实时计价;`/user/balance` 接口需要 `DEEPSEEK_API_KEY` 且主机能访问 api.deepseek.com,否则自动降级为手动初始余额。
- 模型切换的思考强度值(high/max)是 best-effort:真实取值是适配器自己的 `reasoningEffort` id,不同 provider 可能不同。
- 知识库「任意本地目录」受沙箱限制为 **workspace 内**目录。
- iframe 被拒站点只能外部打开,链接跳转拦截依赖 iframe `onError`(跨域子页内的导航不会触发父页事件,属浏览器安全限制)。

### 12.3 后续迭代建议(本轮不做)

鲸鱼动画;更多弹窗;ima 联动;拖拽上传;目录实时刷新;xterm.js 完整终端渲染;壁纸轮播;斜杠快捷指令;现代 macOS 弹跳 Dock 动画;pptx 预览渲染器(当前生成后可「外部打开」,内嵌预览后续补)。

---

## 13. 1 分钟验证路径

```sh
# 30 秒装好
dsh plugin --profile web add "C:\你的路径\dsh-macos-desktop"
dsh plugin --profile web list          # 应看到 dsh-macos-desktop

# 30 秒看效果
dsh web                                # 重启
# 打开 http://127.0.0.1:3080 → Ctrl/Cmd+Shift+R 硬刷新
# → 开机鲸鱼 + 进度条 → 进入复古桌面:
#    左侧 = 桌面,右侧 = DSH 原生对话界面(macOS 风),底部 Dock + 顶部菜单栏横跨全屏
```

验证清单:

1. **分栏**:拖动中间分隔条,左右比例联动;菜单栏「DSH ▸ 折叠桌面」→ 右侧全屏,「展开桌面」恢复。
2. **Dock**:右键 Dock 图标「移除」,点 Dock 末尾「+」加回;配置在重启后保留。
3. **毛玻璃**:Dock/菜单栏/窗口标题栏/弹窗/Token 组件应呈半透明模糊。
4. **PDF/Word**:双击 `.pdf` 出 iframe 预览 + 「在新窗口打开」;双击 `.docx` 出可读 HTML(标题/表格),不再是纯文本。
5. **回收站**:删除一个文件 → Dock 点「回收站」→ 还原 / 清空。
6. **计算器 / 时钟 / 设为壁纸**:Dock 开计算器;菜单栏右上角像素时钟;右键图片 →「设为壁纸」。

## 13.1 壁纸替换

把 SVG/PNG/JPG/WebP 图片放进 workspace 的 **`desktop/wallpapers/`** 文件夹(插件首次启动会自动创建该目录,文件名随意)。然后任选其一:

1. 硬刷新(Ctrl/Cmd+Shift+R)后打开「设置」→「壁纸」下拉选择;
2. 或在桌面/文件里**右键图片 →「设为壁纸」**(选「默认」回到内置纯色壁纸)。

壁纸读取走插件自带的 `/dsh-macos-desktop/file` 文件服务,不需要额外配置。

## 14. 目录结构

```
dsh-macos-desktop/
├── package.json          # dsh.bundle + dsh.client 声明、文档依赖
├── cordis.patch.yml      # 宿主组合 patch(插入本包 row)
├── lib/
│   ├── index.js          # 宿主半侧:文件/终端/文档/统计/搜索/回收站/富文本文档
│   └── client.js         # 浏览器半侧:整个复古桌面(React + 内联 CSS)
├── verify-structure.cjs  # 结构自检脚本(可选)
├── smoke-host.cjs        # 宿主半侧冒烟脚本(可选)
└── README.md
```

## 15. 生态调研结论(3.1 / 3.2 已确认并接入)

### 15.1 视觉/看图插件(已接入 modlens)

- [modlens](https://github.com/liustack/modlens):CLI 工具,把图片转成结构化 JSON(OCR/版面/语义),给「纯文本模型」补视觉。**已接入**:宿主 `/api/vision` 用 `subprocess` 跑 `modlens <图片>`,前端右键图片 →「用 AI 看图」。需 `npm i -g @liustack/modlens`。
- [dsh-vision-complete](https://github.com/Yts1919/dsh-vision-complete):面向 DSH 的视觉 skill,可作后续补充(本轮未用)。

### 15.2 AI 生图插件(已接入 DashScope 文生图)

- [Deepseek-omnimodal](https://github.com/good-boy4069/Deepseek-omnimodal) 证实 DashScope/Qwen 是现成生图路线。**已接入**:宿主 `/api/gen-image` 直连 DashScope `wanx-v1` 文生图(异步任务 + 轮询),前端「AI 生图」app(提示词/比例/风格/参考图)。需 `DASHSCOPE_API_KEY`(阿里云百炼)。
- **注意**:`wanx-v1` 是「文生图」,参考图以「modlens 视觉描述增强 prompt」的方式生效(非真图生图);要真·图生图需另接 DashScope 图生图模型,可后续迭代。

### 15.3 UI 魔改调研(供 2.2 参考,已落地)

- [deepseek-harness-themes](https://github.com/orxz/deepseek-harness-themes)、[dsh-skin](https://github.com/KinGao294/dsh-skin)、[dsh-bg-image](https://github.com/lyh9712/dsh-bg-image)、[DSH-Transparent-UI-Plugin](https://github.com/WYH66666666/DSH-Transparent-UI-Plugin) 均采用 **`--dsw-alias-*` token 覆盖**实现主题/半透明磨砂,证实了本插件「body token !important 覆盖」是社区通用做法;其中 dsh-bg-image 做了「侧边栏/聊天区半透明磨砂」。分栏布局的 `position:fixed` overlay 是本插件的特有复杂度,社区无直接同款,故用「结构选择器 + 列级 ::before 磨砂」的稳健方案。

### 15.4 Office 文档处理(dsh-office → 实为 dsh-cowork)

- GitHub 上**未找到**名字恰好为 `dsh-office` 的独立仓库。功能最接近的是 [dsh-cowork](https://github.com/Jesse-njx/dsh-cowork):提供 `doc_read` / `doc_write` 系列工具,覆盖 **xlsx / pdf / docx / pptx / ipynb** 的读写。
- **与本插件的冲突点**:本插件「文档办公」app 已自建 docx/pdf 读写 + 富文本(`docx`/`mammoth`/`pdf-lib`/`pdf-parse`),dsh-cowork 若作为独立工具注册,会在对话里与自建文档能力**重复**(两套 docx/pdf 处理入口)。
- **整合方式(本插件方案)**:**不把 dsh-cowork 的 docx/pdf 工具纳入桌面**,只取其「pptx 能力」补位——本插件已在「文档办公」app 里直接加 `pptxgenjs` 生成 `.pptx`(格式选择器新增「PPT (.pptx)」),**桌面只保留一个文档入口**,不出现两套重复入口。若你更想要 dsh-cowork 在对话里的 xlsx/ipynb 工具(本插件没有),可另装它作为对话工具(与本插件文件管理器不冲突,因为它走对话工具面、不是 UI 面)。
- **Windows 兼容**:pptxgenjs 是纯 JS 库(零原生依赖),Windows/macOS/Linux 均可直接生成 `.pptx`。

### 15.5 对话图表/表格渲染(dsh-genui)

- [dsh-genui](https://github.com/omdsh-dev/dsh-genui):在 DSH 对话回复里渲染**图表 / 表格 / 组件**(AI 输出 Mermaid/表格/ECharts 等结构化标记时转成可视化组件),与本插件右侧「官方对话界面」是**同一块区域**。
- **冲突点与整合方式**:dsh-genui 挂载在官方对话/消息渲染层,本插件右侧是「官方对话界面 CSS 化」而非自绘聊天(除进度条/Token 小组件外不接管消息渲染),因此**两者在同一对话流里协同、互不替换**。视觉一致性靠本插件已有的 `body{--dsw-alias-*:…!important}` 主题覆盖 + 列级 `::before` 磨砂,dsh-genui 渲染出来的组件会自动继承 DSH 主题 token,跟随本插件的浅色 macOS 风。**无需在本插件里重写 dsh-genui 的组件**,只保证主题 token 覆盖兼容即可。
- **Windows 兼容**:dsh-genui 是纯前端渲染插件,无宿主原生依赖,Windows 下照常工作。



## 16. 社区插件安装(§四)

**本环境(沙箱)无权限执行 `dsh plugin add`(PowerShell 执行策略 + 沙箱拦截外部写/网络),以下命令请在你本机手动执行。**

> **本轮新增 `pptxgenjs` 依赖(link: 安装不自动拉新依赖)**:请先在本仓库目录跑一次 `npm install`(装进插件自己的 `node_modules`),或 `dsh plugin --profile web update dsh-macos-desktop`,再重启 `dsh web`。否则「文档办公 → 新建 PPT」会因缺 `pptxgenjs` 报「依赖未安装」。

- **dsh-vision-toolkit**(视觉工具,可选,与本插件「用 AI 看图」互补):
  ```powershell
  dsh plugin --profile web add github:Anionex/dsh-vision-toolkit
  # 或
  dsh plugin --profile web add "@dsh-external/dsh-vision-toolkit"
  ```
  仓库:https://github.com/Anionex/dsh-vision-toolkit —— 装完重启 `dsh web`,它作为独立工具注册(图片问答/长截图 OCR),与本插件无冲突(不同功能面)。

- **dsh-genui**(对话里渲染图表/表格/组件):
  ```powershell
  dsh plugin --profile web add github:omdsh-dev/dsh-genui
  ```
  仓库:https://github.com/omdsh-dev/dsh-genui —— 装完重启 `dsh web` 即生效(纯前端渲染插件)。它挂在右侧官方对话流里渲染图表/表格,与本插件右侧「官方界面 CSS 化」协同、互不替换,视觉继承本插件的 macOS 主题 token。若 pnpm 提示拦截 `prepare` 构建,按提示在 profile 的 `pnpm-workspace.yaml` 加入 `allowBuilds` 再重跑(见 §2.3)。

- **dsh-cowork**(Office 文档读写工具,xlsx/pdf/docx/pptx/ipynb,可选):
  ```powershell
  dsh plugin --profile web add github:Jesse-njx/dsh-cowork
  ```
  仓库:https://github.com/Jesse-njx/dsh-cowork —— 装完重启 `dsh web`,以「对话工具」形式注册(不是 UI 入口),与本插件「文档办公」app 的 docx/pdf 能力有**部分重叠**。**默认不必装**:本插件已用 `pptxgenjs` 补齐 pptx 生成,docx/pdf 读写 + 富文本也已自带;只有当你还需要**对话里的 xlsx/ipynb 工具**时才装它,桌面不会因此多出一套文档入口(它走工具面,本插件走 UI 面,互不打架)。

- **dsh-plugin-add**:GitHub 上**未找到**名为 `dsh-plugin-add` 的独立仓库;它大概率指「插件市场/一键安装」类工具。可选用以下之一替代:
  ```powershell
  # WhaleHub 插件市场(发现/搜索/一键安装)
  dsh plugin --profile web add github:vvlife/whalehub-dsh
  # 或 插件管理面板
  dsh plugin --profile web add github:Noob-stupid/dsh-plugin-hub
  ```
  若你手头有确切的 `dsh-plugin-add` 仓库地址,把命令里的 `github:作者/仓库` 换成该地址即可。

Install

dsh plugin --profile web add github:Taylor-Cat/dsh-macos-desktop

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source