---
url: /wave-agent/specs/desktop/desktop-deep-link.md
description: >-
  从网页通过 `wave://` 唤起 CodeWave IDE：协议注册与三端接收、克隆仓库到所选目录、自动新建会话并发送链接携带的提示词、clone
  出的仓库经 credential helper 复用本机登录态（链接不携带任何凭据）
---

# 功能规格说明：桌面端深链唤起

**创建日期**：2026-10-12

> 本规格定义与兄弟产品 **codewave sdd**（web coding agent）的接力面：sdd 在 web 上生成 spec 文档并推入 git，然后给出一个 `wave://` 链接，把用户接续到桌面端继续开发。**链接只携带仓库地址、分支与提示词，不携带任何凭据**：clone 与后续 git 操作一律使用本机已有的 Wave 登录态（SSO token），本机未登录时先引导登录；该凭据在 git 服务侧如何校验由 sdd 后端负责。相关规格：[desktop-shell.md](./desktop-shell.md)（SSO 登录、单实例、外链白名单）、[desktop-sessions.md](./desktop-sessions.md)（工作目录与会话新建）、[../enterprise/sso-auth.md](../enterprise/sso-auth.md)（凭据存储与刷新）。

## 用户场景与测试

### 用户故事：从网页唤起桌面端并克隆仓库开始开发（优先级：P1）

作为 codewave sdd 的用户，我在 web 上让 agent 生成好 spec 并推入 git 之后，希望点一下页面上的链接就唤起 CodeWave IDE、选个目录，然后仓库被克隆好、自动开一个新对话并把链接里的提示词（例如「实现 spec」）发进去，以便不用手动 clone、不用手动建会话就能接着开发。

**为什么是这个优先级**：这是本能力的全部价值——唤起、clone、自动开对话并发送提示词，缺任何一环用户都要回到手工流程，sdd 到桌面端的接力就断了。

**独立测试**：构造一条带仓库地址、分支与提示词的 `wave://` 链接，分别在「桌面端未运行」与「桌面端已运行」两种状态下点击，验证确认框弹出、选定目录后仓库被克隆到该目录下的同名子目录、新会话以该子目录为工作目录建立、首条消息为链接里的提示词；再验证取消、目标目录已存在、仓库地址缺失、链接超长四类拒绝路径不产生任何 clone 或会话。

**验收场景**：

1. **假设**桌面端未运行（Windows / Linux），**当**用户从网页点击 `wave://` 链接，**则**应用冷启动、从命令行参数中识别出该链接，窗口就绪后弹出克隆确认框。
2. **假设**桌面端未运行（macOS），**当**用户点击链接，**则**链接在窗口就绪之前即被接收并暂存，待窗口就绪后再弹出确认框，不得丢失。
3. **假设**桌面端已运行，**当**用户点击链接，**则**不启动第二个实例，由已运行的实例接收该链接、把窗口带到前台并弹出确认框；macOS 由系统派发给运行中的实例，Windows / Linux 由二次启动转交，三端行为一致。
4. **假设**多条链接连续到达（含冷启动期间到达的），**则**按到达顺序逐条处理，不丢失、不互相覆盖。
5. **假设**确认框已弹出，**则**在用户确认之前即展示将要克隆的仓库地址、将使用的分支、以及将要发送给 agent 的提示词全文——用户在确认前能看到这一步将要发生什么。
6. **假设**用户选定目录并确认，**则**在该目录下创建以仓库名命名的子目录并把仓库克隆进去；用户选定的是「放在哪儿」，仓库名由仓库地址推导，链接不能指定绝对路径。
7. **假设**目标子目录已存在（无论是否为空），**则**不覆盖、不自动改名，提示用户另选目录。
8. **假设** clone 成功，**则**自动新建一个以该子目录为工作目录的会话（不复用任何既有会话，也不复用唤起前正在显示的那个），并把链接里的提示词作为首条消息自动发出。
9. **假设**链接未携带提示词，**则**只新建会话、不自动发送任何消息。
10. **假设** clone 失败（网络不可达、认证被拒、无权限、磁盘空间不足、本机未安装 git 等），**则**在应用内给出可读错误，不新建会话，且不残留半成品目录。
11. **假设**用户在确认框取消，**则**不 clone、不新建会话；若应用是因本次唤起才冷启动的，停留在正常启动后的初始状态。
12. **假设**链接缺少仓库地址、分支形态非法、或仓库地址不是受支持的形态（仅接受 http(s) 与 ssh 形态的仓库地址，不接受本地路径与 `file://`），**则**拒绝该链接并给出可读错误，不发起任何 clone。
13. **假设**链接整体长度超过安全上限，**则**拒绝并给出可读提示，不得进入 clone 流程后才在系统层静默失败。
14. **假设**同一条链接被重复触发（用户手滑双击、或同一任务重复点击），**则**不产生重复的 clone 或重复的会话。

***

### 用户故事：克隆出的仓库长期自动认证（优先级：P1）

作为刚被链接接过手的用户，我希望 agent 之后在这个仓库里 push / pull / fetch 时自动带上认证，不用我再配任何凭据。

**为什么是这个优先级**：sdd 的意图是让桌面端接手「实现 spec」并把改动推回 git；认证断在 push 上，等于整个接力只做了一半。

**独立测试**：完成一次由链接发起的 clone，检查新仓库的 git 配置里存在指向本机 Wave 取凭据的 credential helper 且不含凭据本身；在该仓库内触发一次 git 网络操作，验证认证自动完成且每次认证前重新取凭据；在本机无可用凭据时验证取凭据快速失败并给出可读原因、不挂起等待输入。

**验收场景**：

1. **假设**用户确认 clone，**则** clone 即以本机已有的 Wave 登录态完成认证，用户不需要额外输入任何东西。
2. **假设** clone 完成，**则**该仓库的 git 配置里写入 credential helper，其值为「向本机 Wave 取当前登录凭据」的命令；**凭据本身不得写入仓库配置**。
3. **假设**之后在该仓库内执行 git 网络操作，**则**每次认证前都重新取一次当前有效凭据——凭据轮换或刷新后自动跟上，不得依赖 clone 当时的那一份。
4. **假设**本机全局/系统层已存在其他 credential helper，**则**注入时先清空继承来的 helper，避免本机已有的凭据缓存把动态凭据钉死。
5. **假设**本机没有可用凭据，**则**取凭据的过程快速失败并给出可读原因，不得挂在等待输入上（agent 自动执行 git 时没有终端可以输入）。
6. **假设**任意时刻，**则**应用日志、错误提示与仓库配置中均不得出现凭据明文。

***

### 用户故事：认证只来自本机登录态（链接不携带凭据）（优先级：P1）

作为桌面端用户，我希望链接里不带任何凭据、认证只用我本机已有的 Wave 登录态，本机未登录时先明确告诉我需要登录；任何网页都能构造这样的链接，凭据绝不能被一条链接安装进我的机器。

**为什么是这个优先级**：凭据的来源决定了这条链路是「接续开发」还是「点一下陌生链接就换一个身份」——后者是不可接受的安全面。来源钉死为本机登录态后，未登录时的引导就成了这条链路上唯一还缺的一环，缺它则 clone 直接失败且用户不知道原因。

**独立测试**：在未登录状态下用链接唤起，验证 clone 确认框之前先出现登录引导、用户取消即结束、登录完成后继续走确认框；在已登录状态下用链接唤起，验证不再出现登录引导；用一条带凭据字段（如 `token=`）的链接唤起，验证该字段不被读取、本机登录态不被改写；用一个当前身份无权的仓库验证错误提示指明可能是身份问题。

**验收场景**：

1. **假设**本机已登录，**当**用户确认 clone，**则** clone 与之后该仓库的 git 操作都使用本机登录态，链接内容不参与认证。
2. **假设**本机未登录，**则**在弹出 clone 确认框之前先提示需要登录（认证只可能来自本机登录态，没有第二条路径），用户取消则整个流程结束：不 clone、不新建会话。
3. **假设**本机未登录、用户在登录引导中完成登录，**则**登录成功后继续走 clone 确认流程。
4. **假设**链接中出现任何凭据字段（如 `token=`），**则**该字段一律不被读取，本机登录态不被改写。
5. **假设** clone 因身份与仓库授权不符被拒，**则**错误提示说明「当前登录身份可能无权访问该仓库」，而不是只透出底层 git 报错。

***

### 边界情况

* **协议注册在三端落点不同**：macOS 靠打包配置（`Info.plist` 的 URL scheme）；Windows 的安装器**不写注册表**，必须由应用在运行时自行注册，因此**首次运行前点链接不会唤起应用**——这是安装后的正常时序，不是缺陷。卸载后注册表残留会导致「点链接仍弹确认框但打不开」，需在卸载路径上一并清理。
* **开发（未打包）模式下 macOS 注册不上**：macOS 的协议注册必须有已打包的应用包，因此本条链路只能在打包产物上验收，dev 运行时不具备该能力。
* **浏览器侧必然有一次确认**：首次点击会弹「是否打开 CodeWave IDE」，用户可勾选「始终允许」。浏览器**不提供**「唤起成功 / 失败」的回调，因此发起方（sdd）需要自备降级，本规格不承担（见非目标）。
* **链接长度的平台差异（必须由应用侧先拦）**：Windows 上超长链接是**静默失败**（浏览器确认框照弹、点确定后什么都不发生），因此上限校验必须在应用侧完成并给出可读拒绝，不能寄望于系统报错。中文提示词经 URL 编码后单字约占 9 个字符，上限判定要按**编码后**长度。macOS 未发现同类硬上限，但上限判定按最严的平台统一执行。
* **链接文本必须按 URL 规范编码**：提示词为自由文本（可含中文、空格、`&`、`#` 等），编码与解码两侧都要正确处理；解析入口需容忍残缺的百分号转义而不抛异常中断整个唤起。
* **确认框是唯一的人类确认点**：任意网页都能构造本链接，且 Windows 上任何应用都能注册同名 scheme（后注册者胜出）。因此确认框必须如实展示仓库地址、分支与提示词全文，不能让用户在不知情的情况下触发 clone；自动发送提示词**不等于**自动批准工具调用，仍按当前权限模式逐次确认。
* **目标目录与 clone 的失败面**：目录不可写、磁盘空间不足、路径含符号链接、clone 中途网络中断等，一律按验收场景 10 处理（可读错误 + 清理半成品 + 不建会话）。
* **远端主机不在本条链路内**：唤起与 clone 都只作用于本机，不因链接把会话切到 SSH 远端主机。
* **与被唤起前的界面状态无关**：无论唤起时用户正在看哪个会话或是否停在欢迎态，clone 成功后一律新建会话，不覆盖、不复用既有会话（与 [desktop-sessions.md](./desktop-sessions.md)「选定目录一律新建对话」一致）。

## 非目标（明确排除）

* **不定义发起方（sdd）侧的降级引导**：浏览器拿不到唤起成败，「没反应？去下载桌面端」这类兜底由发起方自己实现。
* **不支持在 SSH 远端主机上 clone**：本条链路的 clone 固定落在本机。
* **不定义除「clone 并开会话」以外的深链动作**：打开指定会话、打开指定文件、打开工作目录等动作不在本规格内。
* **不改动权限模式**：链接触发的会话沿用用户当前权限模式，不自动批准任何工具调用。
* **不提供防 scheme 劫持**：Windows 上同名 scheme 可被其他应用抢注。主要缓解是**链接里没有凭据可劫**（凭据只来自本机登录态），劫持者最多拿到仓库地址、分支与提示词——这也是确认框必须如实展示这三项的原因；凭据本身在任何情况下都不写入仓库配置、日志或错误提示。
