Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
443 changes: 204 additions & 239 deletions .github/workflows/release.yml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ docs/mobile-connection-latency.zh.md

# Local pnpm content store
/.pnpm-store/
/.build/
/packages/ppt-runtime/templates/
/packages/ppt-bundles/
4 changes: 4 additions & 0 deletions build/dsh-desktop-safe.patch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
- id: ui-brand-official
disabled: true

# Match the normal Desktop settings/model setup during recovery.
- id: ui-settings-account
disabled: true

- insert:
- id: dsh-desktop-client-ui
name: dsh-desktop-client-ui
Expand Down
8 changes: 6 additions & 2 deletions build/dsh-desktop.patch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

# Keep the stock directory-picker (auto) row active: the native backend
# serves ctx.directoryPicker, so host-side consumers (host.pickDirectory,
# plugins reading the seam) work unmodified. The client surface keeps its
# Electron-dialog bridge via the client-ui patch in patches/.
# plugins reading the seam) work unmodified. The client surface reads the
# upstream __DSH_DIRECTORY_PICKER__ bridge exposed by preload.

# Disable the stock single-slot occupant before mounting Desktop's equivalent;
# two occupants cannot share either brand seat. The Desktop plugin preserves
Expand All @@ -18,6 +18,10 @@
- id: ui-brand-official
disabled: true

# Keep the v0.9.2 settings launcher and model setup without upstream account UI.
- id: ui-settings-account
disabled: true

- insert:
- id: dsh-desktop-client-ui
name: dsh-desktop-client-ui
Expand Down
6 changes: 4 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ For reused or deferred legacy trees, startup reads bundle manifests and YAML lay

A baseline market that cannot be installed — an offline or restricted network reports this as a pnpm fetch, 404 or EPERM failure — only blocks startup when the market already in the profile is absent, unreadable or still owned by a generation. Otherwise the boot continues on the installed market and the pending marker retries the repair on the next launch.

Safe Mode uses the installation anchor for both host plugin imports and client bundle discovery, without requiring `profiles/node_modules`. The paired `dsh-app-boot` / `dsh-client-modules` patches target Harness `0.1.5-rc.2`: `mountRootInclude` publishes the explicit host anchor on the loader using `Symbol.for("dsh.desktop.host-module-base-url")`, and client discovery consumes it for bare package names only. Configuration-relative paths and ordinary profiles keep their existing resolution. This small loader handoff is needed because the published client registry otherwise re-resolves from the Profile tree; remove both hunks when upstream propagates an equivalent resolution anchor. Regression coverage includes the actual recovery subprocess's authenticated HTML and executable bootstrap, plus path-resolution behavior tests.
Safe Mode uses the installation anchor for both host plugin imports and client bundle discovery, without requiring `profiles/node_modules`. The paired `dsh-app-boot` / `dsh-client-modules` patches target Harness `0.1.7-rc.1`: `mountRootInclude` publishes the explicit host anchor on the loader using `Symbol.for("dsh.desktop.host-module-base-url")`, and client discovery consumes it for bare package names only. Configuration-relative paths and ordinary profiles keep their existing resolution. This loader handoff is needed because client discovery otherwise re-resolves from the Profile tree; remove both hunks when upstream propagates an equivalent resolution anchor. Regression coverage includes the actual recovery subprocess's authenticated HTML and executable bootstrap, plus path-resolution behavior tests.

Normal-profile Desktop patch insertions resolve from the actual bundled Harness entry, then use the same absolute source URLs for backend loading and client discovery. The patch file's directory is not a package anchor: installed patches live directly in `resources`, while runtime packages live in `resources/app.asar.unpacked/node_modules`. Missing host sources retain the package name, anchor and original resolution cause, and leave the previous generated patch intact.

## Mobile access boundary

Expand All @@ -106,4 +108,4 @@ Update metadata and artifacts are produced by the native release workflow. macOS

Most of the product UI remains upstream Harness. DSH Desktop adds native host surfaces through Electron Main and preload code, uses Harness extension slots where available, and tracks unavoidable upstream package changes as reproducible `patch-package` files. This keeps the desktop layer reviewable while making upstream upgrades an explicit compatibility exercise.

Safe Mode preset discovery and mounting also consume the explicit host anchor through the `dsh-agent-presets@0.1.5-rc.2` patch. Its own filesystem health check and `PresetTree` importer bypass the root loader import hook, so both must use the same installation base; without the Desktop anchor they retain upstream context-relative behavior. Remove this patch when upstream supports a host resolution anchor for both paths. The recovery subprocess regression creates a default-preset session through the real authenticated RPC with `profiles/node_modules` absent, catching the 24-unresolvable-plugins failure beyond frontend readiness.
Harness 0.1.7 replaces directory based `dsh-agent-presets` with Profile composition entries. Before launching the normal web Profile, Desktop converts valid user directories into those entries, backs up the original tree and Profile patch, and leaves the original directories untouched. Safe Mode continues to resolve its bundled preset and client packages from the installation anchor; the recovery subprocess regression creates a default-preset session through the authenticated RPC with `profiles/node_modules` absent.
66 changes: 66 additions & 0 deletions docs/baseline-runtime-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 0.1.7 baseline 兼容修复

## 模型配置

目标:`@deepseek-ai/dsh-client-ui-settings-models@0.1.7-rc.1`。

保留已有模型搜索、行内视觉开关、服务商选择和推理等级配置补丁。修正补丁中 5 个已移除的图标导出;DeepSeek 高级选项通过当前 `capacityInput` 契约渲染容量字段,避免调用不存在的旧 `capacityField`。

验证:图标导出检查、编辑器展开及容量编辑行为测试、真实 Dev 模型页和高级选项展开。未保存用户模型配置。升级时重新核对上游组件和字段契约,不机械重放旧渲染代码。

## generation 宿主依赖校验

Harness 0.1.7 可以通过运行时 resolver 将宿主依赖解析到当前安装,而旧 `profiles/node_modules` 链接仍指向另一安装。Desktop 的两条 generation 安装入口现在传入当前 DSH 入口。校验只对约定的宿主单例核对该入口提供的精确解析结果,不将整个安装目录作为普通第三方依赖的允许范围。

回归覆盖:旧共享链接与当前宿主不同、当前宿主可用、普通第三方依赖逃逸仍被拒绝。实际 Dev 的 `dsh-antigravity@0.0.7` 已安装并显示模型。Windows 安装包尚未验收。

## Undici 8 与旧 Fetch 的 HTTP/2 响应头

目标:`undici@8.11.0`,补丁 `patches/undici+8.11.0.patch`。

`Dispatcher1Wrapper` 将 `controller.rawHeaders` 原样传给旧 handler;HTTP/2 的该值是对象,旧 Fetch 要求扁平数组,因而丢失 Content-Type / Content-Encoding,gzip 数据随后被当成 JSON。修复将对象转换为原有 `toRawHeaders` 格式;HTTP/1.1 已有数组不变。同样处理 upgrade 头与 trailers。

这是共享网络层兼容修复,影响使用旧 Dispatcher API 的调用者,不仅是 AntiGravity。不改变代理选路、认证、请求内容或压缩协商。上游 wrapper 正式兼容对象响应头后应删除补丁,并重跑同一回归。

验证:内置 Fetch 的 gzip JSON、对象/数组响应头、重复 Set-Cookie、分块 SSE、HTTP/1.1 数组保持原样、trailers;在 Electron Node 24.17.0 中通过 Harness 代理向 Google OAuth token 端点发送无凭据诊断请求,修复前得到 gzip 字节且无响应头,修复后能解析预期的 HTTP 400 JSON。该检查不代表真实账号认证或模型推理验收。

### Windows header clearance after rc.2

`ConversationHeader` now owns the `<header>` outside `conversation.session.header`.
The old preload selector (`[data-slot="conversation.session.header"] > header`)
therefore no longer reserves space for native caption controls. The conversation
patch adds only `data-dsh-conversation-header` to the resident header; preload
uses that marker to reserve the native caption height and keeps all header slots
in normal flow below it. This covers sessionless and active views without cloning
contributions or relying on generated class names. This is window chrome, so the
layout stays in preload rather than a business plugin. Remove the marker patch
when upstream exposes an equivalent stable header/Windows clearance contract.

Regression: `test/windows-titlebar-header.test.mjs` executes the installed rc.2
header in both session states and verifies slot ownership/count. Local Chromium
geometry checks cover narrow/wide, light/dark and blank/active layouts; they do
not replace final Windows installer checks (DPI, zoom, maximize and clicks).

## 插件 Harness 版本声明采用告警策略

目标:`dsh-app-boot` 和 `dsh-plugin-manager` 的 `0.1.7-rc.2` 补丁。
适用于所有插件的 Harness peer 版本范围声明,不设包名白名单,也不限于 rc.1 → rc.2。
版本范围不包含当前 Harness 时,安装检查、Profile 组合预检、运行时行预检及 manager 启用检查输出告警并继续尝试。
告警表示兼容性未经确认,不能当作实际加载成功;不修改第三方 manifest 或自动写入版本豁免。

Profile 组合仍从当前 Profile 和安装 anchor 解析;普通 Profile 与 Safe Mode 的依赖解析范围不变。
缺包、损坏的 manifest/YAML、非字符串 peer 字段及实际 import/apply/activation 错误仍保留原始诊断和恢复入口。
仅放宽版本声明门禁,不放宽 generation 依赖闭包与宿主单例校验。
安装告警进入安装输出和日志,启动告警按同一声明及运行时版本在每个进程中去重。

回归:`profile-boot-preflight.test.ts`、`plugin-startup-failure.test.ts`、`plugin-version-policy.test.mjs`。
覆盖旧声明正常运行、实际 API 失败、损坏输入、manager 安装不回滚及 manifest 不变。
当上游支持宿主选择同等告警策略时,改用公开配置并移除此策略补丁。

## CLI-only peer 校验

`@deepseek-ai/dsh@0.1.7-rc.2` 只提供 `bin.dsh = lib/bin.js`,没有可导入根入口。
generation 校验不能把 `require.resolve()` 失败直接当作缺包:对于没有 main/exports 的 CLI 包,检查包内实际存在的 bin 文件,再沿用宿主目录和单例校验。
不执行 CLI,不用 bin 掩盖损坏的 main/exports,不接受目录、缺失文件或越出包目录的 bin。
这只影响安装后依赖校验阶段,不改变 Profile 解析基准和插件加载协议;实际 import/激活仍由 Harness 验证。
回归位于 `test/generation-installer.test.ts`。旧 CI 安装包需重新构建后才能获得此修复。
22 changes: 22 additions & 0 deletions docs/macos-window-chrome.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# macOS 窗口按钮与 Harness rc.2 布局

对照官方 `dsh-v0.1.7-rc.2` 的 `apps/desktop/src/preload-platform.ts`、`apps/desktop/src/main.ts`、`packages/client/ui-layout/src/client/AppFrame.module.css`:

- preload 在客户端挂载前声明 `html[data-platform=darwin]`。
- 使用官方 16/18 原生按钮坐标;不再混用原来的 9px 高度和旧侧栏顶部 padding。
- 收起后由 Harness 隐藏整个侧栏并挂载 `shell.leading`;官方变量为主内容保留顶部和左侧空间。
- main 在加载、进入/退出全屏时通知 preload,映射为 `data-fullscreen`,让官方 CSS 在全屏时回收按钮留白。

平台标记同时影响 shortcuts 环境检测。DSH Desktop 没有官方 `keyboard`/快捷键设置原生桥,因此显式声明 `data-dsh-desktop-web-shortcuts=true`,通过 `dsh-client-shortcuts` 最小补丁继续使用已有 Web 键盘与存储适配器。没有该标记的官方宿主仍要求自己的原生桥;这不是通用的错误吞掉或自动降级。若未来接入完整原生快捷键桥,应同时删除标记与补丁。

不额外复制官方侧栏/顶栏布局,不改变 Windows 的标题栏行为。行为回归覆盖 preload 首次标记、无 document root 时的全屏状态、退出全屏、监听清理和官方/自有宿主快捷键环境区分。

验证:全量 152 个测试文件 / 1261 项通过;typecheck 通过;两项补丁在独立临时依赖目录中 npm ci 后重放成功;真实 macOS Dev 启动、侧栏收起及展开正常,收起后顶部控件与标题留白已确认。屏幕共享指示器覆盖了原生按钮区域,按钮本体及全屏过渡尚未完成视觉验收;未验证最终安装包。

`npm run build` 与 `git diff --check` 通过。

## 完整采用官方窗口材质

macOS 窗口采用 `hiddenInset`、`trafficLightPosition: { x: 16, y: 18 }`、`vibrancy: sidebar`、`visualEffectState: active` 和透明窗口背景。显示时保持原生材质;隐藏/最小化时改用官方深浅底色,恢复时重新挂接 sidebar 材质,避免透明闪烁。主题同步不再把可见 macOS 窗口覆盖成不透明底色。移除旧固定拖拽覆盖条,由官方 `data-window-drag` 标记的行负责拖拽。

新增 backdrop 状态转换测试;完整回归 153 个文件 / 1263 项、typecheck 通过。
4 changes: 2 additions & 2 deletions docs/mobile-pairing-pin-design.zh.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 手机配对:按模式拆分(扫码即连 / 隧道 PIN)

> 状态:已实现(2026-09-14)。
> 范围:把桌面「允许 / 拒绝」改成按连接模式授权;Cloudflare 保活;免费 Pinggy 过期体验做诚实。配对中转见文末附录,**不在本次实现**。
> 状态:已实现(2026-09-14)。
> 范围:把桌面「允许 / 拒绝」改成按连接模式授权;Cloudflare 保活;免费 Pinggy 过期体验做诚实。配对中转见文末附录,**不在本次实现**。
> 相关代码:[`src/main/mobile/lan-mobile-bridge.ts`](../src/main/mobile/lan-mobile-bridge.ts)、[`src/main/mobile/lan-mobile-pages.ts`](../src/main/mobile/lan-mobile-pages.ts)、[`src/main/index.ts`](../src/main/index.ts)。

## 1. 结论摘要
Expand Down
60 changes: 60 additions & 0 deletions docs/patch-compatibility-review-0.1.7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 0.1.7-rc.1 补丁兼容性复核

范围:当前 baseline 的 25 个 patch-package 补丁,以及消费这些接缝的 Desktop 客户端插件。检查对象为实际安装的发布代码,不以补丁能应用作为运行正确的证明。

## 本轮发现并修复

1. **通用模型编辑器的未定义图标**:`ModelListEditor` 引用了已不存在的局部 `IconChevron` / `IconTrash`,会在有自定义模型行时抛错。改用当前 primitives 的 Regular 图标。新增通用编辑器展开、容量修改回归;保留搜索、视觉开关及推理配置。
2. **遗留模型向导的未定义状态**:`DeepSeekOnboardingDialog` 修改了一半,删掉 `onboardingReadiness(state)` 却仍读取 `readiness`。恢复原有状态推导并覆盖加载、缺密钥、已就绪及错误分支。当前 Desktop 已取消该向导的 slot 注册、使用自己的向导,因此这是潜伏代码问题,不能据此认定当前 Desktop 首次启动必然白屏。
3. **pi-ai 流式回放格式混用**:补全缺失 terminal content 时曾保存 Harness 的 `reasoning` / `tool-call`,而 `toPiReplayState` 要求原生 `thinking` / `toolCall`。改为保存原生 partial / toolCall,并保留签名;对外流式 block 仍为 Harness 格式。回归覆盖三个内容类型及回放签名。上游保证 terminal content 完整后,可删除这段补全逻辑。

前序已修复:模型选择器和模型配置页的旧图标导出、DeepSeek 容量编辑 helper;内置生图从旧 `settings.plugin.item` 迁到 `settings.plugins.tab`(后者属于自有插件,不是 patches 文件)。

## 全部补丁检查表

“未发现新增问题”仅表示本轮静态检查和相关源码回归范围内未发现,不表示全部平台、插件组合已验收。

| 包(省略 @deepseek-ai/;除特别说明外均为 0.1.7-rc.1) | 检查重点 | 结论 |
| --- | --- | --- |
| cordis-plugin-loader 1.0.5 | 超时、错误链、启动失败归属 | 未发现新增问题 |
| dsh | CLI 失败出口、宿主包依赖清单 | 未发现新增问题 |
| dsh-api-remotes | session.delete 编解码与服务映射 | 未发现新增问题 |
| dsh-api-session-controller | 文件访问、删除、预设迁移、远程事件 | 未发现新增问题 |
| dsh-app-boot | bundle 归属、禁用状态、启动审计 | 未发现新增问题 |
| dsh-client-file-upload | staged file 的 Agent 作用域 | 未发现新增问题 |
| dsh-client-modules | 客户端发现、combo 缓存、source map | 未发现新增问题 |
| dsh-client-ui-agent-preset | 导入导出、搜索、Modal 引用 | 未发现新增问题 |
| dsh-client-ui-attachment | 文件卡片回调、组件导出 | 未发现新增问题 |
| dsh-client-ui-chat | 上传文件打开链、错误提示 | 未发现新增问题 |
| dsh-client-ui-conversation | 输入区及 PPT slot 声明、props、图标 | 未发现新增接口缺失;布局改动仍由 PPT 组合测试覆盖 |
| dsh-client-ui-deliverables | 本地路径识别与文件打开 | 未发现新增问题 |
| dsh-client-ui-model-selection | 图标、搜索、推理等级 | 前序修复后未发现新增问题 |
| dsh-client-ui-settings-general | 设置入口、onboarding 条件 | 未发现新增问题 |
| dsh-client-ui-settings-models | 两类编辑器、向导状态、组件引用 | 本轮修复两项 |
| dsh-client-ui-sidebar | 品牌及平台间距接缝 | 未发现新增接口问题;不等于跨平台视觉验收 |
| dsh-client-ui-trajectory | provider 错误码展示 | 未发现新增问题 |
| dsh-client-ui-workspace | 导航接缝、未读、删除生命周期 | 未发现新增问题 |
| dsh-llm-deepseek | AUTH / QUOTA / FORBIDDEN 分类 | 未发现新增问题 |
| dsh-llm-pi-ai | 流式事件、回放、请求头 | 本轮修复内容格式混用 |
| dsh-plugin-manager | generation backend、commit/rollback 接口 | 未发现新增接口缺失;本轮不代表完成插件事务架构重写 |
| dsh-session-persistence | 可选删除接口 | 未发现新增问题 |
| dsh-session-persistence-jsonl | 删除租约及坏日志跳过 | 未发现新增问题 |
| dsh-workspace | 持久会话删除后的索引清理 | 未发现新增问题 |
| undici 8.11.0 | 新旧 Dispatcher 响应头及 trailers | 前序修复后未发现新增问题 |

## 防止同类遗漏

- `patch-runtime-compatibility.test.mjs` 从 patches 动态收集已修改 JS,检查未解析的局部标识符,覆盖未执行的条件分支;仅豁免宿主提供的 `global` / `setImmediate`。
- 同一测试核对所有被补丁修改的客户端对 primitives 的成员引用,不再只查两个包的图标。
- 同一测试核对四个维护中的 Desktop 客户端所注入的 slot 在当前安装 Harness 中确有声明。该检查不验证贡献项可见性、容器布局及生命周期。
- `model-settings-render.test.mjs` 执行两种模型编辑器及向导状态分支;`pi-ai-terminal-replay.test.mjs` 执行实际流转换及回放投影。

## 验收边界

干净补丁重放在独立临时项目中进行,安装 25 个补丁对应版本并通过 `npm ci --ignore-scripts` 后运行 `patch-package --error-on-fail`。该步骤验证补丁目标及重放,不等同于本仓库完整 postinstall(品牌资源、Electron 安装等)或安装包验收。

本轮未操作用户凭据、未保存模型设置、未发送付费模型请求。新增的通用编辑器修复仍需真实页面交互验收;pi-ai 修复仍需真实服务商的多轮推理/工具调用验收。Windows/macOS 最终安装包不在本轮已验证范围内。

本轮已执行:25 个补丁全部重放成功;51 个补丁目标文件与当前工作目录逐字节一致;完整回归 149 个文件 / 1251 项通过;`npm run typecheck`、`git diff --check` 通过。测试及重放均未修改真实 Profile。

`npm run build` 通过。该命令包含 PPT 资源构建及 Electron 编译,不包含签名或最终安装包验收。
Loading