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

输入框增强 furkancak1r/dsh-composer-plus

DeepSeek Harnessv1.10.0
furkancak1r1 天前有提交已提供中文文档扫描:含敏感能力

DeepSeek Harness 输入辅助:历史记录、一键继续、拖拽调整队列顺序

32.9/100
综合分
4
GitHub 星标
2,707
npm 周下载
—/5
用户评分

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-composer-plus
npm 源 · dsh-composer-plus 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · ui
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功(非静态推断);本次验证针对插件 v1.12.0,当前版本为 v1.10.0
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

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

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

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/22 09:42:52

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

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 205 处,展示前 54 条)
  • 读取本地文件
    index.js:78
    const PACKAGE = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
  • 读取本地文件
    index.js:493
    const real = typeof cwd === 'string' ? await realpath(cwd).catch(() => cwd) : cwd;
  • 读取本地文件
    index.js:595
    const real = await realpath(dir).catch(() => dir);
  • 读取本地文件
    index.js:729
    read: async () => { try { const on = JSON.parse(await readFile(file, 'utf8'))?.on; return fallback ? on !== false : on === true; } catch { return fall
  • 写入本地文件
    index.js:731
    await mkdir(dirname(file), { recursive: true });
  • 写入本地文件
    index.js:733
    await writeFile(tmp, JSON.stringify({ on }), { mode: 0o600 });
  • 写入本地文件
    index.js:734
    await rename(tmp, file);
  • 读取本地文件
    index.js:747
    const ready = readFile(file, 'utf8').then((text) => {
  • 写入本地文件
    index.js:755
    await mkdir(dirname(file), { recursive: true });
  • 写入本地文件
    index.js:757
    await writeFile(tmp, data, { mode: 0o600 });
  • 写入本地文件
    index.js:758
    await rename(tmp, file);
  • 读取本地文件
    index.js:826
    const data = JSON.parse(await readFile(file, 'utf8'));
  • 删除本地文件
    index.js:1468
    if (tree.code !== 0) { await rm(join(store, 'index'), { force: true }); complete = await add(); tree = ok(await run(['write-tree']), 'git write-tree')
  • 删除本地文件
    index.js:1487
    await rm(join(store, 'ignored', `${old.split('/').at(-1)}.json`), { force: true });
  • 删除本地文件递归
    index.js:1532
    } finally { await rm(scratch, { recursive: true, force: true }); }
  • 删除本地文件
    index.js:1558
    await rm(join(store, 'rolled', `${old.split('/').at(-1)}.json`), { force: true });
  • 删除本地文件递归
    index.js:1676
    } finally { await rm(scratch, { recursive: true, force: true }); }
  • 删除本地文件递归
    index.js:1678
    forget: (id) => enqueue(id, () => rm(storeOf(id), { recursive: true, force: true })),
  • 写入本地文件
    tether/gateway/server.mjs:20
    const saveJson = (file, data) => { const tmp = file + '.' + process.pid + '.tmp'; writeFileSync(tmp, JSON.stringify(data), { mode: 0o600 }); renameSyn
  • 写入本地文件
    tether/gateway/server.mjs:20
    const saveJson = (file, data) => { const tmp = file + '.' + process.pid + '.tmp'; writeFileSync(tmp, JSON.stringify(data), { mode: 0o600 }); renameSyn
  • 读取本地文件
    tether/gateway/server.mjs:21
    const readJson = (file, fallback) => { try { return JSON.parse(readFileSync(file, 'utf8')) ?? fallback } catch { return fallback } }
  • 执行外部命令固定命令
    tether/gateway/server.mjs:24
    export function macName(read = () => execFileSync('scutil', ['--get', 'ComputerName'], { encoding: 'utf8', timeout: 2000 })) {
  • 执行外部命令来自配置/变量
    tether/gateway/server.mjs:104
    execFile(bins[i], ['status', '--json'], { timeout: 3000, maxBuffer: 8 << 20, env: { ...process.env, TAILSCALE_BE_CLI: '1' } }, (err, out) => {
  • 写入本地文件
    tether/gateway/server.mjs:273
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 读取本地文件
    tether/gateway/server.mjs:276
    let devices = existsSync(devFile) ? JSON.parse(readFileSync(devFile, 'utf8')) : []
  • 读取本地文件
    tether/gateway/server.mjs:276
    let devices = existsSync(devFile) ? JSON.parse(readFileSync(devFile, 'utf8')) : []
  • 读取本地文件
    tether/gateway/server.mjs:325
    if (!existsSync(k) || !existsSync(c)) {
  • 执行外部命令固定命令
    tether/gateway/server.mjs:326
    execFileSync('openssl', ['req', '-x509', '-newkey', 'rsa:2048', '-sha256', '-nodes', '-keyout', k, '-out', c, '-days', '825', '-subj', '/CN=DSH Mobile
  • 写入本地文件
    tether/gateway/server.mjs:327
    chmodSync(k, 0o600)
  • 读取本地文件
    tether/gateway/server.mjs:329
    key = readFileSync(k); cert = readFileSync(c)
  • 执行外部命令固定命令
    tether/gateway/server.mjs:362
    spawn('osascript', ['-e', 'display notification "' + safe + '" with title "Tether"'], { stdio: 'ignore' }).on('error', () => {})
  • 执行外部命令固定命令
    tether/gateway/server.mjs:380
    spawn('swift', [join(HERE, 'qr.swift'), c.payload, join(dir, 'qr.png')], { stdio: 'ignore', env })
  • 读取本地文件
    tether/gateway/server.mjs:665
    if (req.method === 'GET' && path === '/') { res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); return res.end(readFileSync(join(HERE,
  • 读取本地文件
    backup.mjs:67
    const exists = (p) => lstat(p).then(() => true, () => false);
  • 读取本地文件
    backup.mjs:68
    const isDir = (p) => lstat(p).then((s) => s.isDirectory(), () => false);
  • 读取本地文件
    backup.mjs:174
    try { names = (await readdir(rel === '' ? root : join(root, rel))).sort(); } catch { return; }
  • 读取本地文件
    backup.mjs:180
    try { st = await lstat(join(root, r)); } catch { continue; }
  • 读取本地文件
    backup.mjs:193
    const realHome = await realpath(home);
  • 写入本地文件
    backup.mjs:194
    await mkdir(dest, { recursive: true, mode: 0o700 });
  • 读取本地文件
    backup.mjs:195
    const realDest = await realpath(dest);
  • 写入本地文件
    backup.mjs:207
    await mkdir(join(realDest, VAULT), { recursive: true, mode: 0o700 });
  • 写入本地文件
    backup.mjs:209
    await mkdir(dirname(target), { recursive: true, mode: 0o700 });
  • 写入本地文件
    backup.mjs:210
    await writeFile(target, data, { flag: 'wx', mode: 0o600 });
  • 写入本地文件
    backup.mjs:291
    await pipeline(entries, zlib.createGzip({ level: 6 }), tap, createWriteStream(file, { flags: 'wx', mode: 0o600 }), { signal });
  • 写入本地文件
    backup.mjs:293
    await writeFile(`${file}.sha256`, `${sha} ${file}\n`, { mode: 0o600 });
  • 删除本地文件
    backup.mjs:310
    for (const suffix of ['', ...SIDECARS]) await rm(join(dest, `${name}${suffix}`), { force: true });
  • 删除本地文件递归
    backup.mjs:311
    await rm(join(dest, VAULT, name), { recursive: true, force: true });
  • 删除本地文件
    backup.mjs:654
    await rm(path, { force: true });
  • 删除本地文件递归
    backup.mjs:659
    await rm(staging, { recursive: true, force: true });
  • 删除本地文件递归
    backup.mjs:669
    await rm(staging, { recursive: true, force: true });
  • 删除本地文件
    backup.mjs:696
    return async () => { if ((await readJson(file))?.pid === process.pid) await rm(file, { force: true }); };
  • 执行外部命令来自配置/变量
    backup.mjs:1023
    const r2 = spawnSync(pnpm[0], [...pnpm.slice(1), 'install'], { cwd: join(done.home, 'profiles', p), stdio: 'inherit' });
  • 执行外部命令固定命令
    backup.mjs:1052
    if (spawnSync('pnpm', ['--version'], { stdio: 'ignore' }).status === 0) return ['pnpm'];
  • 执行外部命令来自配置/变量
    backup.mjs:1054
    return spawnSync(process.execPath, [own, '--version'], { stdio: 'ignore' }).status === 0 ? [process.execPath, own] : undefined;
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 输入历史记录
  • 一键继续
  • 拖拽调整队列顺序
v1.20.02026-11-03
· 新增 · 任务板:指向 Doing 里的卡片(或把键盘焦点移到卡片上)就能看到进度:运行了多久、待办列表走到哪一步、当前运行的工具和智能体最后一行输出。在「设置 → Composer Plus → 任务板」里,「悬停显示进度」可选「快速(不用 AI)」(默认,只读聊天记录)或「AI 摘要」(额外调用一次聊天所用模型,写一两句话)。Tether 会在每张运行中的卡片下方显示一行进度。 · 「新建任务」现在会在项目里打开 dsh 自带的新聊天,所以第一条消息就有 dsh 的输入框(文件、命令、模型菜单)。发送之后任务板重新打开。在此之前聊天停在 Todo,Todo 也只在这时显示。 · 变更 · 任务板不再有项目颜色:唯一的颜色是状态色(橙色等你处理,蓝色运行中,绿色已完成)。 · 项目里有聊天在等你处理时,任务板的项目列表会显示橙点。有聊天等你处理时,Tether 打开任务板会停在 Review。 · 只有项目列表滚动:标题、搜索项目、最近 2 小时活跃都固定不动。搜索项目的高度等于一行项目。 · 任务板变窄时,标题栏保持一行:「隐藏已完成」只显示图标。
v1.19.12026-11-03
· 新增 · 任务板的项目列表上方有搜索框和筛选器。在 Search projects 里输入项目名即可查找(不区分大小写和重音,按 Esc 清空输入框)。点 Active in the last 2 hours,只显示最近 2 小时内有会话处于等待、运行、完成未读或发生变更的项目。这个选择只保存在当前设备上。在 Tether 里点任务板标题,可打开同一个项目列表。 · 变更 · 窄窗口下的任务板卡片:标题只在词与词之间换行,不会把单词拆开。时间移到标签行末尾,标题因此占满卡片宽度。
v1.19.02026-11-03
· 新增 · 任务板像侧边栏一样显示你的 dsh 聊天及其实时状态。等待你批准、回答或审阅计划的聊天在 Review 里,带橙点。运行中的聊天在 Doing,已完成的在 Done(在你打开前是绿色)。新建任务只需一个提示词:按 Enter 就在项目里开一个新聊天。dsh 给聊天命名,再对聊天所用模型发一次短调用,写出最多 3 个标签。点卡片打开对应聊天。橙色卡片上点 Answer 就能在板上回答:Reject 或 Allow once,计划选 Approve 或 Request changes,问题选选项或自己输入。Hide finished 在本设备上隐藏 Done。Tether 在聊天标题菜单里有同样的板。 · What's new 窗口按 Application language 的语言显示发行说明。说明随包提供 13 种语言。没有对应语言的说明时显示英文说明。 · 变更 · 任务板不再维护自己的任务:notebook 卡片、Backlog 列、拖放和智能体板工具都已移除。旧的 board.json 仍留在磁盘上,不再读取。 · 聊天行上的 Git 分支只在 In one 列表视图里显示分支标签。在项目行下,聊天本就在其文件夹下,所以该行不显示 main 或分支名。Tether 也一样。 · 打开很多项目时,在 Open memory 里打字不再卡顿。Collapse all projects 按钮用了一条全页样式规则,导致每次按键浏览器都要重算整个页面。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-composer-plus — 适用于 DeepSeek Harness 的 Composer Plus English · 中文 · Türkçe · Español · Português (Brasil) · Français · Deutsch · Русский · 日本語 · 한국어 · Bahasa Indonesia · Tiếng Việt · हिन्दी 本文是译文,内容以英文版 README.md 为准。 为 DeepSeek Harness(dsh)桌面版和网页版界面带来 Codex 风格的实用功能:改动面板、滑动卡片式的功能创意、能搜索消息文字的侧边栏搜索、可同时恢复文件的回合回退、把对话删除到废纸篓、输入框下方的项目名称、侧边栏中的项目状态、输入历史、计划模式快捷键、一键继续、重启后继续运行中的对话、队列拖拽排序、会话深层链接、以 Markdown 格式导出对话、按对话授予的 Auto Review 许可、后台通知、通过 Tether 应用在 iPhone 上访问,以及自动更新。 一句话概括: 这是一个 DeepSeek Harness 插件(npm 包 dsh-composer-plus,在 设置 → 插件 中显示为 Composer Plus)。
展开完整文档(README 剩余 1 节)
dsh-composer-plus — 适用于 DeepSeek Harness 的 Composer Plus

English · 中文 · Türkçe · Español · Português (Brasil) · Français · Deutsch · Русский · 日本語 · 한국어 · Bahasa Indonesia · Tiếng Việt · हिन्दी

本文是译文,内容以英文版 README.md 为准。

为 DeepSeek Harness(dsh)桌面版和网页版界面带来 Codex 风格的实用功能:改动面板、滑动卡片式的功能创意、能搜索消息文字的侧边栏搜索、可同时恢复文件的回合回退、把对话删除到废纸篓、输入框下方的项目名称、侧边栏中的项目状态、输入历史、计划模式快捷键、一键继续、重启后继续运行中的对话、队列拖拽排序、会话深层链接、以 Markdown 格式导出对话、按对话授予的 Auto Review 许可、后台通知、通过 Tether 应用在 iPhone 上访问,以及自动更新。

一句话概括: 这是一个 DeepSeek Harness 插件(npm 包 dsh-composer-plus,在 设置 → 插件 中显示为 Composer Plus)。它添加了 git 改动面板、Tinder 式的功能创意卡片、也能查找消息中词语的侧边栏搜索、↶ 回合回退(仅对话,或对话和文件)、删除对话、输入框下方的项目名称、↑/↓ 输入历史、Shift+Tab /plan 切换、一键 ▶ 继续、重启后继续、拖拽调整队列顺序、复制会话链接、导出为 Markdown、Auto Review “本对话内允许”、后台通知、iPhone 访问(手机连接,Tether 应用)、11 种额外界面语言和自动更新。

这是非官方的社区插件。插件只在检查更新时访问网络(GitHub releases 和 npm registry);关闭 自动更新 后,启动时就不再发出这些请求。只有在你点击 推荐功能 时,功能创意 才会调用对话自己的模型。下一条消息预测(默认开启)每完成一个回合都会调用一次在设置中选择的模型(除非你另选,否则为 dsh 的默认模型),不需要点击;在 设置 → Composer Plus 中关闭它,即可停止这些调用。输入时补全(默认关闭)在你开启后,会在你每次输入停顿时调用为它选择的模型(默认使用预测的模型)。只有在你点击魔法棒时,优化提示词 才会调用模型。目标检查(默认开启)在智能体每次于自动轮次中把 /goal 标记为完成时调用一次模型。手机连接(默认关闭)只有在你开启后,才会接受来自本地网络或 tailnet 的 iPhone 连接。

安装

桌面应用: 设置 → 插件 → 添加插件 → 输入 dsh-composer-plus → 立即启用。
也可以粘贴 https://github.com/furkancak1r/dsh-composer-plus 来代替 npm 包名。

网页版 / CLI profile:

dsh plugin --profile web add dsh-composer-plus

然后重启 dsh。(CLI 无法安装到桌面版 profile 中;桌面版 profile 由应用自己管理。)

dsh 使用的 pnpm 会跳过发布不到 24 小时的版本。刚发布新版本时,请加上版本号:dsh-composer-plus@1.18.0。

功能

| 功能 | 使用方法 | 截图 |
| 改动面板 | 右侧边栏 → + → 改动。页面打开时显示 树:对话所在仓库的分支图。三张卡片统计分支数量:全部分支、已合并的分支和等待合并的分支。点击一张卡片只显示这些分支;再次点击则显示全部分支。每个分支是一个方框,显示它的最后一个提交:主分支已包含它的工作时为绿色,未包含时为橙色,主分支本身为蓝色。每个分支都有一个箭头,指向合并了它的分支(✅ 已合并),或指向它分出的那个分支(⏳ 等待中,虚线)。点击方框可查看该分支的提交,再点击某个提交可查看它的文件及差异。点击 已合并 可查看合并提交的文件,点击 等待中 可查看该分支将带入其目标分支的文件。只有在没有同名本地分支时,才会显示远程分支。在模式菜单中选择 未提交、未暂存、已暂存 或 分支,即可查看有改动的文件及其 +/- 行数;点击某个文件可查看它的差异。上一轮 会打开 dsh 自带的最近一轮改动审阅。本对话 只列出当前对话的文件工具(write、edit)在所有轮次中写入的文件,以及从第一条消息起的总差异。␣ 按钮可隐藏空白改动(git diff -w):仅缩进或换行符改变的行不显示。文件的 … 菜单 → 改动此文件的对话 会列出同一仓库中用写入或编辑工具改动过该文件的对话(最新的在前)以及对应的请求;点击即可打开该对话并定位到那条请求。 | |
| 功能创意 | 右侧边栏 → + → 功能创意 → 推荐功能。对话自己的模型会读取对话所属项目的简短概要(顶层文件、README 和清单文件的开头部分、README 其余部分的大纲、最近提交的标题),并推荐最多 8 个功能。这些功能以一叠卡片的形式显示,语言与 dsh 的界面语言一致。向右滑动卡片(或点击 ✓,或按 →;无论哪种方式,卡片都会飞向对应的一侧),即可在同一项目中新建对话:新对话以计划模式启动,并把该创意作为请求,因此在你批准计划之前不会有任何改动。要跳过计划,请点击 ▶ 直接实现(或按 ↑;卡片会向上飞出):新对话会立即启动,并把该创意作为普通请求,模型会做出改动并运行检查(审批照常适用)。向左滑动(或点击 ✕,或按 ←)可跳过;撤销(或按 Z)可找回跳过的卡片。点击 ↓(或按 ↓)可把好的创意留到以后:它会进入项目的 稍后 列表,同一项目文件夹中的每个对话都会显示这个列表(重启后也一样)。稍后(N) 会打开这个列表;规划 会为该创意启动同样的计划模式对话,直接实现 则启动不做规划的对话,两者都会把它从列表中移除;全部合并规划(N) 会为列表中的所有创意启动一个计划模式对话,因此共同的部分只需规划一次;从列表中移除 会删除它。复制为清单 会把整个列表以 Markdown 清单的形式复制到剪贴板(- [ ] Title — Summary,每个创意一行),可用于问题跟踪器或 TODO 文件;它不会发起任何网络请求。在某个创意上点击 创建 GitHub issue,会用你自己的 GitHub CLI(gh)登录,在项目的 GitHub 仓库中以该创意的标题和概要(以及理由)创建 issue;之后创意旁会显示 Issue #N 链接,点击即可打开该 issue。更多创意 会添加更多卡片。如果只想获得某一方面的创意,请在 推荐功能 旁边的输入框中输入一个简短的 关注主题(最多 80 个字符;按 Enter 也会开始推荐),或点击输入框下方的某个固定主题:性能、无障碍、测试、安全、易用性 或 文档(再次点击可清除)。之后,模型只会推荐与该主题相关的功能;输入框为空表示不限主题。同一项目中不会重复推荐同一个创意:每个推荐过的创意(跳过的、留到以后的或已开始的)都会进入项目的 历史,模型会被告知不要再推荐这些创意,标题重复的创意会被丢弃。历史 会列出这些创意,并标为 已开始 或 已建议;忘记(或 全部忘记)可让某个创意再次出现;仍在 稍后 列表中的创意不会被推荐,直到你从该列表中移除它。只有在你点击时才会调用模型。 | |
| 内容搜索 | dsh 自带的侧边栏搜索(工作区 旁边的放大镜;桌面应用中按 Cmd+K,浏览器中按 Cmd+Alt+K)不仅能按标题查找对话,还能按你的消息和回复中的词语查找对话,并在对话下方显示匹配的文字。dsh 本身已经带有这个搜索功能,但默认是关闭的;本功能会开启它,并在你的电脑上为它提供一个搜索索引文件。每次启动后的第一次搜索会创建索引(250 个对话约需 15 秒,见“限制”),之后的启动会继续使用这个索引。默认开启;更改在重启 dsh 后生效。 | |
| 回合回退 | 将鼠标悬停在你的某条消息上,点击 ↶(在“复制”旁边)。仅对话 会把这条消息及其后的所有内容(回复、工具调用)从对话和模型上下文中移除,并把这条消息放回输入框:修改后再次发送即可。对话和文件 会先列出这条消息之后发生变化的项目文件,然后把它们也恢复原样。这也包括命令(bash)所做的更改,而不只是 dsh 编辑工具所做的更改。正在运行的回合会先停止。对话日志永远不会被重写:一个隐藏标记会隐藏被撤回的部分,方式与 dsh 自带的 /compact 隐藏旧消息相同。如果安装了 dsh-rewind-plugin,则由它负责这项工作,Composer Plus 不会再显示第二个按钮。回退之后,输入框上方会出现 重新应用 栏:它会从回退之前开始一个新对话(消息和上下文相同),选择 对话和文件 时还会恢复文件;回退之后你更改过的文件会被列出并保留,除非你勾选覆盖它的选项。 | |
| 删除对话 | 侧边栏 → 对话的 … 菜单(或右键点击)→ 删除… → 删除。dsh 本身只能归档。对话会停止(包括它的回合、后台任务、子代理和定时任务,与 dsh 自带的归档相同),它保存的历史记录连同子代理对话会移到 macOS 废纸篓(在其他系统上为 $DSH_HOME/trash)。要找回它,请把文件夹放回原处并重启 dsh:它会显示在侧边栏的 仅显示已归档 视图中。 | |
| 输入框中的项目名称 | 输入框下方那一行(回合数、token、缓存命中、上下文)以对话的项目名称开头,让你随时知道对话在哪个项目中工作。这里显示的是 dsh 自己的项目标题;项目没有标题时,显示文件夹名称。将鼠标悬停在上面可查看完整的文件夹路径。点击它可在侧边栏中找到该对话(列表视图和项目视图均可):侧边栏和项目会展开(折叠的项目及其 展开其余 N 个会话 也会展开),列表会滚动到该对话,该对话会闪烁 5 秒。 | |
| 输入历史 | 在空输入框中按 ↑ / ↓,可以像在终端里一样浏览你发送过的消息。 | |
| Shift+Tab 计划模式 | Shift+Tab 会在草稿开头添加 /plan (再按一次可移除)。如果对话已处于计划模式,Shift+Tab 会退出计划模式。 | |
| 保持输入框焦点 | 发送 / 命令或技能后,光标仍留在输入框中,你可以立即继续输入。对于输入命令后按 Enter 的键盘宏,这同样有效。dsh 在解析命令时会把输入框设为只读,浏览器随后会移除焦点。本功能会把焦点放回输入框,除非菜单、对话框或其他输入框正持有焦点。 | |
| 问题卡片适应窗口 | 代理向你提问时,问题和答案在卡片中一起滚动,跳过和提交始终显示在底部。卡片使用窗口的高度(减去 200 px,留给对话标题和一部分对话),所以会随窗口变大变小。没有本功能时,dsh 把卡片限制在窗口的 60%(最多 520 px),并且只有答案可以滚动:较长的问题会把它自己的结尾、答案和按钮挤出卡片。 | |
| 对话标题栏适应窗口 | 窗口较窄时,dsh 对话标题栏中的按钮(模式、子代理、后台任务、打开方式、分支标签和授权标签)不再互相遮挡。对话标题至少保留 120 px;放不下的按钮换到右侧的第二行,每个按钮仍可点击。所有内容能放在一行时(宽窗口),标题栏与 dsh 原样一致。没有本功能时,dsh 只压缩标题:有子代理和后台任务时,在较窄的对话栏中按钮会互相覆盖。即使关闭本开关,分支标签(每个对话一个分支)和授权标签(本对话内允许)也会让标题栏适应窗口。 | |
| 一键继续 | 回合被停止、失败或中断后,空输入框会显示 ▶。点击一次即可在现有对话的基础上继续,不需要在输入框中输入内容,也不会添加可见的对话消息(模型会收到一条简短的隐藏提示“从停止的地方继续”,因为部分提供商,例如 Claude,会拒绝以助手回复结尾的请求)。队列中的消息会保留:▶ 只继续被停止的任务,之后再运行队列。已完成的回合仍显示普通的发送按钮。 | |
| 重启后继续 | 默认关闭:请在 设置 → Composer Plus 中开启。如果你在对话仍在运行时退出 dsh(或 dsh 被关闭),再次打开 dsh 后,该对话会自动继续,并使用与“一键继续”相同的隐藏提示。如果当时有目标轮次(/goal)正在运行,该目标会继续下一轮(dsh 每次启动时都会暂停目标,直到你恢复它们)。你停止的、已完成的或失败的对话不会继续。dsh 本身没有这项设置:它只会把这样的回合标记为已中断。 | |
| 队列拖拽排序 | 排队的消息会带一个把手(⠿)。拖动它即可调整顺序,或者让把手获得焦点后按 ↑ / ↓。按 Esc 取消。 | |
| 原地编辑排队消息 | 双击一条排队的消息,或点击它的编辑按钮(编辑排队消息),该行会打开一个编辑器:修改文字,用 ✕ 移除图片或文件,或用回形针按钮(添加图片或文件)或粘贴图片来添加新的。按 Enter 保存,按 Esc 取消,按 Shift+Enter 换行。消息在队列中的位置不变,你保留的图片和文件保持原样。编辑器打开时,队列不能重新排序。在 Tether 中:排队消息菜单 → Edit。 | |
| 停止后发送的消息优先 | 默认开启。在对话的队列中还有消息时停止对话,然后发送一条新消息:新消息会立即单独运行。排队的消息保持原有顺序,在它之后逐条运行,每轮一条。如果没有此功能,dsh 会把新消息加到队列末尾,转而先运行队列中的第一条消息,新消息最后才运行。对话运行时发送的消息仍会排在队列末尾。 | |
| 复制会话链接 | 在侧边栏中右键点击对话 → 复制会话链接。把 dsh-session:… 链接粘贴到另一个对话中,即可把那个对话作为只读上下文附加进来。dsh 0.2.1 自带 复制 Session ID,它只复制纯 ID;本菜单项紧跟在它后面。 | |
| 复制消息链接 | 将鼠标悬停在一条消息上,点击 🔗(在它的操作栏中;回答的按钮在时间旁边)。链接是会话链接加上消息编号:dsh-session:…#42。把它粘贴到消息中并发送:在 dsh 0.2.1 及更高版本中,链接显示为一个标签,点击它会打开那个对话、滚动到该消息并高亮显示 2 秒。和会话链接一样,它也会把那个对话作为只读上下文附加进来。 | |
| 将对话导出为 Markdown | 在侧边栏中右键点击对话(或打开它的 … 菜单)→ 导出为 Markdown…。对话框会显示该对话有多少条消息;复制到剪贴板 会把对话以 Markdown 格式复制,保存 .md 文件 会通过浏览器的下载功能把它保存为 <chat title>.md(dsh 桌面版:按你的系统设置,保存到“下载”文件夹或打开保存对话框)。文件包含对话标题、项目名称和日期,之后每条消息各有一个 ## 你 或 ## 助手 部分。代码块保持原样;如果某条消息中的代码块没有闭合,它会被闭合。 | |
| 复制项目路径 | 在侧边栏中右键点击项目 → 复制路径,即可复制它的文件夹的完整路径。 | |
| 新对话中的项目搜索 | 新对话 → 输入框上方的项目按钮。项目按 A–Z 顺序显示,顶部有 搜索项目 框。输入名称的一部分(不区分大小写和重音符号),按 Enter 即可选择第一个匹配项。没有匹配项时会显示 没有匹配的项目。侧边栏中 dsh 保存的项目顺序不会改变。 | |
| 新会话的默认工作区 | 设置 → Composer Plus → 新会话的默认工作区 → 新会话打开于:选择一个项目,或选择 通用文件夹(default-workspace)(默认值:dsh 自己的文件夹 Documents/deepseek-harness/default-workspace,首次使用时创建)。之后,侧边栏顶部的 新会话(及其快捷键)总是在那里打开新对话,即使另一个项目的对话正在打开也是如此。项目旁的 + 仍会打开该项目,新对话中输入框上方的项目按钮仍可更换项目。 | |
| 在对话中查找 | 在对话中按 Cmd+F(Mac)或 Ctrl+F(Windows 和 Linux),对话上方会打开查找框。输入词语后,屏幕上的消息和回复中所有匹配项都会高亮,当前匹配项颜色更深,查找框显示 n / 总数。Enter 或 ↓ 跳到下一个匹配项,Shift+Enter 或 ↑ 跳到上一个(也可用箭头按钮);对话会把匹配项滚动到中间。不区分大小写、重音和土耳其语无点 ı。Esc 关闭查找框,并把光标放回原处。回复流式输出时,查找结果会随之更新。 | |
| 每个对话一个分支 | 在新对话界面,项目按钮和模式按钮之间的分支按钮(分支图标)默认显示 新分支。输入第一条消息并发送。要留在当前分支,请在同一按钮中选择 “当前分支(main)”。第一条消息可以附带图片和文件。在计划模式下,新对话也以计划模式开始:以 /plan <消息> 发送消息(Shift+Tab),或先让新对话进入计划模式。AI 根据这条消息给分支命名(feat/…、fix/…),Composer Plus 在 <项目>/.worktrees/ 中为它创建 git worktree,复制 .worktreeinclude 列出的被忽略文件(例如 .env 和 node_modules/),并在那里打开一个带有你消息的新对话。打开的对话标题栏显示 ⑂ 分支 · N 处改动 · ↑ ↓(或 未推送);点击它打开 改动。同一菜单列出已打开的 worktree:选择一个即可在其中开始对话。要在侧边栏中把分支文件夹显示在其项目内,请选择 dsh 的 视图选项 → 按工作区树。 | |
| 工作区树中的分支 | 设置 → Composer Plus → 工作区树中的分支(默认关闭)。开启后,每个在 <project>/.worktrees/ 中有 worktree 文件夹的分支都会作为所属项目内的一个项目显示;在 dsh 中选择 视图选项 → 按工作区树 即可看到嵌套结构。文件夹被删除的分支会从列表中移除,dsh 会在 未分组 下显示它的对话。当项目文件夹中某个对话的智能体创建并切换到一个分支(git switch -c、git checkout -b),且该文件夹没有未提交的改动时,项目文件夹会切回原来的分支,该分支获得自己的文件夹,对话也会移进去:副本在分支项目中打开并继续执行任务,旧对话被归档。列表会在启动时、每 30 秒、每轮结束后以及你回到窗口时检查。 | |
| 下一条消息预测 | 默认开启;可在 设置 → Composer Plus 中关闭。智能体完成一个回合后(被停止或失败的回合除外),空输入框会以灰色文字显示对你下一条消息的猜测,并带有 按 Tab 接受 提示。Tab 会把文字放入输入框,但不会发送。Esc 会在本回合隐藏它。开始输入也会隐藏它,新的回合会替换它。开关下方的 模型 菜单列出 dsh 自己的模型(与 dsh 模型菜单的列表相同)。默认选中 dsh 默认,它跟随 dsh 的默认模型。每完成一个回合会进行一次简短的模型调用。在 Tether 中,猜测显示在空输入框上方:轻点它即可放入输入框。 | |
| 输入时补全 | 默认关闭;可在 设置 → Composer Plus 中开启。输入时,光标后紧跟的灰色文字会显示你的消息可能的后续内容。Tab 会把它添加到消息中,但不会发送。Esc 会隐藏它。它只建议你自己接下来要写的话:不会回答你,也不会编造错误信息或名称。消息看起来已完整,或模型不确定时,不显示任何内容。继续输入灰色文字中接下来的字符时,它会保留,不会再次调用模型。它的开关下方有自己的 模型 菜单。第一项 与“下一条消息预测”相同(默认)使用 下一条消息预测 的模型;选择其他模型,就可以为每个功能使用不同的模型,例如为补全选择更快的模型。你每次输入停顿时,它都会调用一次模型,因此消耗的 token 比预测多得多:请选择快速、低成本的模型。输入斜杠命令、消息中带有文件标签,或光标不在末尾时,它不会运行。在 Tether 中,输入时剩余部分会显示在输入框上方:轻点它即可添加。 | |
| 优化提示词 | 输入一个粗略的请求,然后点击模型菜单旁边的魔法棒(优化提示词)。一次模型调用会把它改写成更清晰的提示词:先写目标,有多个部分时列出简短的编号步骤,并写明要运行的检查。它会读取此对话(已回滚的消息除外)、项目的 README、AGENTS.md 和清单文件、已更改的文件以及文件名与你的用词匹配的文件,并保留你的语言。它从不编造文件名。新文本会替换你的草稿,但不会发送:阅读、修改后再按 Enter。Cmd/Ctrl+Z 一步即可恢复你的原文,该按钮(撤销优化)也可以。如果你在它处理时继续输入,你的新文本会保留。Esc 或再次点击可取消。它在设置中有自己的 模型 菜单(默认:与对话的模型相同)。对于 /goal <objective> 消息,它只改写目标,把它写成 目标检查 能够验证的完成条件:产出、必须通过的检查、要在对话中展示的证据、把无法完成的部分标记为未解决,以及同一障碍持续存在时停止。/goal 命令保持不变。不适用于其他斜杠命令、/goal 控制词(clear、pause、resume)或带文件标签的消息。在 Tether 中,魔法棒位于输入框旁边。 | |
| 目标检查 | 用 /goal 开始一个目标。当智能体在自动轮次中把目标标记为完成时,目标要通过两项检查才会关闭。首先,项目的测试命令会在对话的文件夹中、按对话的沙箱模式运行。命令是你自己设置的,或者从 package.json、Makefile、Cargo.toml、go.mod 或 pytest 中找到的。如果智能体自己最新的一步就是该测试的成功运行,则不再重复运行。然后,一次不带工具的独立模型调用会阅读目标、此对话、git status 和测试结果。模型会用一张证据表回答:目标的每一部分都标为已验证、不正确或未解决,并附上证据和修正办法;只有每一部分都已验证时,目标才会关闭。任一检查失败时,目标保持进行中,智能体会看到每个未完成的部分及其证据和修正办法,下一轮继续。目标栏下方的一行(目标检查)显示测试、上次结果以及已验证的部分数量(将鼠标悬停在上面可查看表格)。编辑 可设置你自己的测试命令以及时间或 token 上限;超过上限时目标会变为受阻。token 上限也会计入该对话的子智能体。立即运行 会运行检查但不关闭目标。它在设置中有自己的 模型 菜单(默认:与对话的模型相同)。你自己完成目标时,不做任何检查。 | |
| 在新对话中继续 | 在侧边栏中右键点击对话(或打开它的 … 菜单)→ 在新对话中继续…。调用一次该对话自己的模型,根据对话显示的内容写出交接说明:任务、产出、已完成、决定、未解决问题和下一步(工具调用及其结果是证据;你回滚的步骤不计入)。说明会在一个对话框中打开:阅读并修改它。重新生成 会写一份新说明。开始新对话(或 Cmd/Ctrl+Enter)会在同一项目中打开一个新对话,以该说明和旧对话的链接作为第一条消息;旧对话保持不变。当长对话已满或变慢,或者想第二天继续时,可以使用它。不会向项目写入任何内容。 | |
| 上下文明细 | 右侧边栏 → + → 上下文。该页面显示当前是什么在占用打开的对话的模型上下文,以及它占用了上下文窗口的多少:系统提示词、项目指令(AGENTS.md)、技能、你的消息、智能体回复和工具调用、工具结果(按工具)、MCP 结果(按服务器)、工具定义、压缩摘要和其他上下文说明,每项附令牌数和占比。点击某一部分可查看它的工具或服务器。它只读取对话日志(/compact 和回滚之后的状态),不调用模型;每个回合结束后以及点击 刷新 时会重新读取。可用它查看对话为何变慢或已满,例如一个很大的 MCP 工具结果或大量工具定义。 | |
| 计划步骤 | 默认关闭:请在 设置 → Composer Plus 中开启。智能体会获得工具 plan_next_steps:它可以在发出某条命令的同一条消息中,预先计划接下来的命令及其确切参数和条件,例如“构建通过后运行 npm test”。结果满足条件时,Composer Plus 会自行运行下一步,无需再次调用模型,因此长对话消耗的令牌更少。该步骤在对话中显示为一行简短说明“Composer Plus · Planned steps: ran test … without a model call”,随后是它的工具调用和结果。仅限 bash、read、grep 和 glob 步骤;审批、沙箱和受保护的文件照常作用于每一步。条件不满足、同时有两个步骤就绪、最后一步完成后以及你发送消息时,模型会重新作答。这个想法来自 HarnessMM(arXiv 2610.32813)。 | |
| 受保护的文件 | 默认开启。智能体自己的文件工具不能读取或更改与你的模式匹配的文件:对于 读取和写入 模式,对文件使用的 read、read_image 和 grep 会被拒绝;两种模式下 write、edit 和 str_replace_editor 都会被拒绝。智能体会看到原因,并被告知要问你。默认模式是 .env、.pem 和 .key。设置 → Composer Plus → 受保护的文件:添加一个模式(例如 published/ 或 config/.yml),点击它的类型可在 读取和写入 与 仅写入 之间切换,用 ✕ 移除它,或点击 使用默认值。不含 / 的模式会匹配任意文件夹中的文件名。这是护栏,不是沙箱:shell 命令(cat .env)、脚本或 MCP 工具仍能访问该文件(见“限制”)。 | |
| 禁止的命令 | 默认开启,列表为空。智能体的 shell 命令(bash、pwsh)不能运行与你的规则匹配的命令:阻止 规则会拒绝调用(智能体会看到原因,并被告知要问你),先询问 规则会显示 dsh 的审批卡片,只有你允许后命令才会运行。设置 → Composer Plus → 禁止的命令:输入一条规则(例如 npm publish、git push --force 或 ssh 192.168.2.19),点击类型可在 阻止 与 先询问 之间切换,然后点击 添加;点击规则的类型可以更改它,用 ✕ 移除它。一条规则是一个命令名和必须按此顺序出现在它后面的词; 匹配任意文本。它也能找到 &&、;、\| 之后,$(…)、bash -c "…" 或 eval 之中,以及 sudo 或 env 之后的命令。这是护栏,不是沙箱:变量($CMD)、脚本文件或其他程序仍能运行该命令(见“限制”)。 | |
| 任务看板 | 左侧边栏 → 任务看板。供你和智能体共用的 dsh 项目看板:待办、进行中、审核和已完成(以及积压,见下文)。在左侧选择一个项目或所有项目。新建任务(或按 n)会打开一张新卡片:输入标题后按 Enter。把卡片拖到另一列或两张卡片之间。点击卡片可查看并修改状态、标签、人工(智能体会跳过)、描述(Markdown)和评论。/ 搜索所有项目,h 只显示人工任务,导出按钮可把看板保存为 Markdown 或 JSON。智能体会获得看板工具:让对话“从看板领取下一个任务”,它会把待办最上面的卡片移到进行中,评论所做的工作并移到审核;由你移到已完成。在有未完成任务的项目中,每个对话都会自动获得这条规则。设置 → Composer Plus → 任务看板中有积压列的开关:智能体不会处理其中的卡片。 | |
| 项目记忆 | 默认关闭:请在 设置 → Composer Plus 中开启。每个项目文件夹都有自己的记忆,该项目之后的对话都会读取,就像 DS Bot 为每个 Bot 保存一份记忆。每个回合结束后,会用对话的模型调用一次,读取新消息(不含已回滚的消息),把你长期的偏好、决定和事实保存为简短笔记,并修改或删除旧笔记。智能体也可以自己保存、删除和搜索笔记(memory_remember、memory_forget、memory_recall)。笔记也可以是全局的:所有项目都会读取。新对话会在系统提示词中获得这些笔记;之后保存的笔记从下一个对话开始显示。文件是 dsh 主目录下的 Markdown(storages/dsh-composer-plus/memory/),绝不写入项目文件夹。 同一行的 打开记忆 会按项目(以及全局记忆)分组显示所有已保存的笔记,并可筛选。用你自己的话写下要修改的内容(例如“我从 yarn 换成了 pnpm”),然后点 预览修改:由 dsh 的默认模型提出修改,只有点 应用 才会保存。在 Tether 中:聊天标题菜单 → Project memory。 | |
| 本对话内允许 | 当 Auto Review 询问你时,审批卡片上会多出 本对话内允许:从此以后,同一对话中的同一工具都会被允许,参数不限,直到时限结束(默认 1 小时;可在 设置 → Composer Plus → 本对话内允许 中选择)。之后代理会再次询问。标题栏中的标签会列出这些授权及其结束时间,也可以撤销它们。授权在重启后仍然有效。 | |
| 项目状态 | 侧边栏中的项目行会显示与其对话相同的加载图标 / 等待 / 完成标记。因此,即使项目已折叠,你也能知道其中有对话正在运行或需要你处理。等待你处理的对话优先显示,其次是你尚未打开的已完成对话(绿色圆点,即使另一个对话仍在运行也会显示),最后是加载图标。将鼠标悬停在上面可查看详情。在按工作区树中,父文件夹的行也会显示其中每个项目(例如 .worktrees/ 中的每个分支文件夹)的对话状态,折叠时也一样。 | |
| 对话行显示 Git 分支 | 侧边栏中的每个对话行会显示一个小的灰色标签,内容是该对话最后一轮时项目文件夹所在的 git 分支(例如 main 或 feature/login;分离的 HEAD 没有分支,不显示标签)。同一项目中位于不同分支的两个对话不再看起来一样,你也能立即发现自己是否要在错误的分支上继续对话。将鼠标悬停在标签上可查看完整名称。Host 部分会在每轮开始和结束时读取分支(git branch --show-current,只读);安装后还没有新一轮的对话,或不是 git 仓库的文件夹,不会显示标签。当对话上方的项目行与分支同名时(例如“每个对话一个分支”的文件夹),该对话行不显示分支标签,但“列表视图”中仍会显示。 | |
| 全部标为已读 | 在侧边栏中,点击项目的 … 按钮 → 全部标为已读。该项目中所有对话的绿色未读圆点会立即消失;其他项目的圆点保持不变。项目中没有未读对话时,此项显示为灰色(没有未读对话)。 | |
| 活跃项目置顶 | 当某个对话开始运行或需要你处理时,它所在的项目会移到侧边栏顶部,并使用 dsh 自带的行动画(与把它拖到那里的效果相同)。已完成的项目保持原位;你可以像往常一样把它们拖到任意位置。移动会保存到 dsh 的项目顺序中,因此关闭此功能后会保留当前顺序。 | |
| 近期项目筛选 | 侧边栏 → 视图选项(滑块图标)→ 最近 2 小时内活跃。选中后,侧边栏只显示最近 2 小时内有活跃对话的项目。活跃对话包括:这段时间内更新过的对话、正在运行或等待中的对话、当前打开的对话,以及你尚未打开的已完成对话(dsh 的绿色“完成”圆点),超过 2 小时后也一样。没有这类对话的项目会被隐藏,新建的空项目也会被隐藏。在 按工作区树 中,只要父文件夹中的某个项目处于活跃状态,父文件夹就会保持显示,最近 2 小时内不活跃的对话也会被隐藏,因此只显示最近的对话。再次选择该项即可显示所有项目。这个选择保存在本设备上。 | |
| 折叠全部项目 | 侧边栏中有项目展开时,视图选项(滑块图标)旁边会出现一个按钮。点击它可以一次折叠所有展开的项目,例如 5 个项目中展开的 3 个。没有展开的项目时,这个按钮会再次隐藏。 | |
| 按状态排序 | 侧边栏 → 视图选项 → 排序方式 → 按状态(配合 单列表 使用)。已完成的对话排在最前(即带 dsh “完成”圆点的对话,以出错结束的回合也会显示这个圆点),然后是正在运行或等待中的对话,再然后是带有活跃自动化任务(Schedule)的对话,其余对话按 dsh 的顺序排列。打开已完成的对话后,它会往下移。只有视图会改变:选择 手动排序 或 最近更新 即可恢复。 | |
| 后台通知 | dsh 在后台时,如果回合完成(通知显示回复的第一行),或对话确实在等你处理,你都会收到通知。等你处理的情况包括:审批(显示工具名称)、回答(显示问题)或计划审阅。请求必须在 1.5 秒后仍未处理,才会发出通知,因此被自动处理的审批(Auto Review 授权、其他插件)不会发出通知;请求一旦得到处理,对应的通知也会立即撤回。程序坞/任务栏角标会显示等待中的对话数量。点击通知会打开对应的对话。 | |
| 空闲时打开等待中的对话 | 当某个对话提出问题,或等待审批或计划审阅(橙色圆点),或完成了你尚未查看的一轮(绿色圆点),而你 30 秒没有使用 dsh 时,dsh 会打开该对话。橙色对话先于绿色对话打开。同一组中,等待最久的先打开;下一个会在再次 30 秒没有使用后打开。按键、点击、移动鼠标、滚轮或触摸都会让 30 秒重新计时。有焦点的输入框中有文字、选中了文本,或打开了菜单或对话框时,也不会切换。等待中的对话正在屏幕上时,不会切换。如果你没有回答就离开了等待中的对话,再次 30 秒没有使用后,它会再次打开。绿色对话打开后,它的圆点会消失;下一个绿色对话要等你再次使用 dsh,之后又 30 秒没有使用时才会打开。dsh 在后台时也会生效,但 dsh 不会被带到前台。 | |
| 应用语言 | 设置 → Composer Plus → 应用语言 可以把整个 dsh 界面切换为 Türkçe、Español、Português (Brasil)、Français、Deutsch、Русский、日本語、한국어、Bahasa Indonesia、Tiếng Việt 或 हिन्दी(见下文)。 | |
| 手机连接(iPhone) | 通过 Tether 应用在 iPhone 上使用 dsh,可以在同一 Wi-Fi 下使用,也可以通过 Tailscale 使用。请在 设置 → Composer Plus 中开启它(默认关闭,因为它会在这台 Mac 上开放一个网络端口)。然后点击侧边栏左下角的 手机连接:用 iPhone 相机扫描二维码(轻点 Open in Tether),或用 Tether 中的 Scan code 扫描,轻点 Connect,然后点击 Approve。请先安装 Tether:没有它,相机无法打开这个二维码。手机可以显示你的对话、发送消息(可附照片:输入框的 + → Camera、Photos 或 Paste image)、回答审批和问题,以及切换模型和智能体。你可以配对任意多台 Mac:点击应用左上角的 Mac 名称即可在它们之间切换。手机连接 面板会列出已配对的 iPhone 及其上次连接时间:点击 Remove 可立即断开其中一部。“Tailscale only”会拒绝来自本地网络的连接(适用于共享 Wi-Fi),访问日志会显示谁尝试过连接。在 Tether 中,“Settings → Privacy”可以用 Face ID 锁定应用。 | |
| 自动更新 | dsh 启动时,插件会检查 最新的 GitHub release。如果它比当前版本新,并且已发布到 npm,插件会通过 dsh 自带的插件管理器(与 设置 → 插件 相同的途径)安装这个确切的版本,并通知你。重启 dsh 即可加载新版本。设置 → Composer Plus → Composer Plus 更新 会显示版本号,并提供 检查更新 / 立即更新。dsh 第一次以新版本启动时,会显示一次 Composer Plus N 的新功能 窗口,内容是该版本的发布说明(来自同一次更新检查,不会额外联网);点击 关闭 或按 Esc 关闭。 | |
| 备份 | 设置 → Composer Plus → 备份 → 立即备份:把整个 dsh 主目录(对话、设置、插件、MCP、技能)连同校验和写成 ~/Desktop/dsh-backups 中的一个归档。归档中的机密会被遮蔽:凭据文件、密钥文件(.pem、.key)以及 yml 设置中的 token、secret 和 password 值只保存在这台电脑上,位于该文件夹的 vault 中。cache/、dsh-runtimes/ 和 node_modules 不会归档(dsh 会重新生成它们)。列表中的每份备份都有 检查(完整读取)、用于另一台电脑(一个可复制到新电脑的文件夹,含救援控制台)和 删除。同一文件夹中 dsh-backup 的归档也会显示并可使用。要恢复,请退出 dsh 并使用救援控制台。 | |
| 自动备份 | 打开 自动备份(默认关闭:每份大约与不含缓存的 dsh 主目录一样大)。选择频率(每:6 小时到 7 天,默认 24 小时)和保留的份数(保留:3 到 14 份,默认 7 份)。下次备份时间显示在开关下方;失败的备份也会显示在那里,并在 30 分钟后重试。dsh 或 Composer Plus 以新版本启动时,会在启动后不久、新版本长时间使用你的数据之前拍一份快照(保留最新的两份,标记为 升级前)。 | |
| 会话日志检查 | 检查会话日志 会读取每个对话的日志,并列出 dsh 无法打开的日志(帧损坏、记录被截断、序号错误)。尾部撕裂的日志不会列出:dsh 会自行修复。从备份修复 会放回最新一份含有健康副本的备份中的副本,并把损坏的文件保留在旁边(.corrupt-<时间>)。该备份之后写入的消息不在副本中。在此 dsh 中打开的对话不会在这里修复:请退出 dsh,在救援控制台中修复。 | |
| 救援控制台 | 每次备份还会把救援控制台放进备份文件夹。当 dsh 已关闭或无法启动时,在该文件夹中打开 Composer Plus Rescue(macOS:Composer Plus Rescue.command):终端窗口中的菜单可以列出、检查和恢复备份,以及检查和修复会话日志。它不打开网络端口。恢复时需要输入 RESTORE,会把当前的 dsh 主目录保留为 .dsh.pre-restore-<时间>,从 vault 放回被遮蔽的机密,并把 cache/、dsh-runtimes/ 和 node_modules 移过来。它不需要 dsh:它使用 Node.js,或 DeepSeek Harness 应用本身。在新电脑上,复制 用于另一台电脑 生成的文件夹并在那里打开 Composer Plus Rescue。 | |

按钮、工具提示、提示信息和通知都会使用所选的 dsh 语言(见下文的“应用语言”)。

设置

每项功能都可以单独开启或关闭:dsh 设置 → Composer Plus。每一行都有一张小截图:将鼠标悬停在上面可查看放大的预览,点击可按原尺寸打开(按 Esc 关闭)。顶部的 搜索功能 框会按名称或描述筛选页面(支持任何语言,不区分大小写和重音符号);按 Esc 可清空。每一行都有一个开关和一段简短说明;更改会立即生效,不需要重启,并会保存在该设备上。行名后面的小 ? 会打开 README 中介绍该功能的部分,使用与 dsh 界面语言相同的 README。除 手机连接、重启后继续 和 输入时补全 外,所有功能默认开启。这三项以及 内容搜索、回合回退、下一条消息预测 和 目标检查 的开关由 dsh 的 Host 保存,因此它们对每个窗口都有效,并在重启后保留。下一条消息预测、输入时补全、优化提示词 和 目标检查 的 模型 选择也由 Host 保存(输入时补全 默认 与“下一条消息预测”相同,优化提示词 和 目标检查 默认 与对话的模型相同);本对话内允许 的 时限(默认 1 小时)也由 Host 保存。内容搜索 只有在重启 dsh 后才会改变(dsh 在启动时读取它);在此之前,它所在的行会显示 重启 dsh 后此更改生效。

应用语言

打开 设置 → Composer Plus → 应用语言,然后选择 系统语言 或 13 种语言之一:

English · 中文 · Türkçe · Español · Português (Brasil) · Français · Deutsch · Русский · 日本語 · 한국어 · Bahasa Indonesia · Tiếng Việt · हिन्दी

整个应用会立即切换语言。这个选择保存在 dsh 自己的 locale.preference 中(与 通用设置 → 语言 是同一个设置),因此重启后依然有效。系统语言 会清除这个选择:桌面应用跟随操作系统语言,网页版跟随浏览器语言,不支持的语言会回退为英语。安装插件绝不会覆盖你已经选择的语言。

每个语言包有 3,280 条文本:dsh 0.2.0-rc.2 和 0.2.1-rc.2 的全部界面文本(对话、侧边栏、设置、审批、自动化任务、文件预览、插件管理器、插件市场)、插件自己的控件,以及常用的 dsh-rewind 插件。以下内容不会翻译:你的消息、模型输出、代码、斜杠命令名称(/plan、/compact)、由提供商定义的标签(例如推理强度 High)、其他插件的文本,以及桌面应用的原生菜单和更新对话框(dsh 只提供这些内容的英文和中文版本)。较新版本的 dsh 新增的字符串,在语言包更新之前会以英文显示。如果其他插件已经提供了某种语言,该语言仍由那个插件提供。

键盘快捷键

| 按键 | 位置 | 操作 |
| ↑ / ↓ | 空输入框 | 上一条 / 下一条已发送的消息 |
| Shift+Tab | 输入框 | 添加/移除 /plan ,或退出计划模式 |
| ↑ / ↓ | 获得焦点的队列把手 | 移动排队的消息 |
| Esc | 拖动过程中 | 取消移动 |
| → / ← | 功能创意页面 | 实现 / 跳过最上面的卡片 |
| ↓ | 功能创意页面 | 把最上面的卡片保存到项目的“稍后”列表 |
| ↑ | 功能创意页面 | 不做规划,直接实现最上面的卡片 |
| Z | 功能创意页面 | 找回最后一张跳过的卡片 |
| Enter | 新对话的项目菜单,搜索框 | 选择第一个匹配项 |
| ↑ / ↓ | 新对话的项目菜单 | 在显示的项目之间移动 |
| Esc | 新对话的项目菜单,搜索框 | 清空搜索(再按一次关闭菜单) |
| Tab | 显示预测的空输入框 | 把预测放入输入框 |
| Tab | 光标后的灰色补全 | 把补全添加到消息中 |
| Esc | 显示预测的空输入框 | 隐藏预测 |
| Cmd/Ctrl+Z | 使用 优化提示词 后的输入框 | 恢复你输入的文本 |
| Esc | 优化提示词 运行时的输入框 | 取消优化 |
| Enter / Esc | 排队消息编辑器 | 保存 / 取消编辑 |
| Mac 上为 Cmd+F,Windows 和 Linux 上为 Ctrl+F | 打开的对话 | 打开 在对话中查找 |
| Enter / Shift+Enter、↓ / ↑ | 在对话中查找 框 | 下一个 / 上一个匹配项 |
| Esc | 在对话中查找 框 | 关闭查找框 |

打开的 / 或 @ 菜单会自己占用这些按键。

兼容性

已在 dsh 0.2.0-rc.2(桌面版和网页版)和 0.2.1-rc.2(网页版)上测试。每次推送时,CI 都会运行测试。

隐私与安全

- 继续: 经过身份验证的本地接口只会恢复最后一个被中断的回合,会拒绝过期或重复的请求,并保留现有的审批钩子。它不会发送新的用户消息。
- 重启后继续: 在你开启之前一直关闭。Host 端只在 $DSH_HOME/storages/dsh-composer-plus/resume.json(仅所有者可访问)中保存对话 ID 和开始时间,任何数据都不会离开你的电脑。只有当 dsh 自己的日志表明是 dsh(而不是你)停止了最后一个回合时,它才会继续该对话。审批和 Auto Review 照常适用于继续的回合。

- 改动面板: git 在你的电脑上、在对话自己的文件夹中以只读方式运行,并通过 dsh 经过身份验证的 /api 通道调用。它从不提交、暂存或拉取,只显示 git 自己列出的路径。树最多列出 1000 个本地和远程分支,每个分支最多显示最新的 300 个提交:只沿第一父提交,合并提交代表它带入的提交。它从不切换(checkout)分支。本对话 会读取对话自己的日志,找出它的文件工具写入的文件,并在一个会立即删除的临时文件夹中,把它们与该对话的回合回退快照进行比较;它不会向你的仓库或快照存储写入任何内容。
- 功能创意: 在你点击 推荐功能 之前,什么都不会运行。点击后,Host 端只读取对话自己的文件夹(浏览器从不发送路径):顶层条目的名称,README、AGENTS.md 和清单文件(package.json、pyproject.toml、Cargo.toml、go.mod 等)的前 6 kB,README 其余部分的大纲(标题、表格行、列表项,最多 6 kB),以及最近提交的标题(git log --format=%s,最多 6 kB),总计最多 28 kB。它会跳过 .env、密钥文件和 node_modules 等文件夹,并且只读取位于该文件夹内的普通文件:指向文件夹外部的符号链接、FIFO 或设备文件都会被跳过。这份概要会通过 dsh 自己的提供商设置,以一次请求的形式发送给对话所用的模型;它不会被添加到任何对话中。项目中的任何内容都不会被写入。向右滑动的创意会以计划模式新建对话,因此审批和计划审阅照常适用。直接实现 不使用计划模式启动对话:模型可以立即修改文件,对话平常的审批和 Auto Review 照常适用。留到以后的创意(标题、概要、理由、工作量)会与项目的文件夹路径一起,保存在 dsh home 下的 storages/dsh-composer-plus/later.json 中(仅所有者可访问的文件);不会向项目写入任何内容。推荐过的创意的历史(标题、概要、理由、工作量、日期、是否已启动)也以同样方式保存在 storages/dsh-composer-plus/idea-history.json 中,每个项目最多 200 条(最早的先被移除);该项目下次 推荐功能 时,这些标题会发送给模型。
- 内容搜索: 没有新的代码来搜索你的对话:插件只是开启 dsh 自带的消息索引(SQLite FTS5,dsh-session-query-sqlite),并为它提供一个文件 $DSH_HOME/cache/composer-plus/session-search.db(文件和文件夹仅所有者可访问)。这个文件包含你的用户消息和助手消息的文本,因此它的私密程度与 $DSH_HOME/sessions 中的对话日志相同。任何数据都不会离开你的电脑。它是 dsh 可以重新生成的副本:你可以在 dsh 关闭时删除它。开关保存在 $DSH_HOME/storages/dsh-composer-plus/content-search.json 中。
- 回合回退: 在你发送每条消息之前,Host 会在它自己的存储 $DSH_HOME/cache/composer-plus/rollback/<chat>.git(仅所有者可访问的文件夹)中,为对话的文件夹创建一个 git 快照。快照保存该文件夹中 git 能看到的文件(不包括被忽略的文件)的副本,因此它的私密程度与项目相同。它会读取你仓库中的对象(不会再复制一份 git 已有的内容),并且从不写入你仓库的索引、HEAD、分支、标签、stash 或配置;git 在你的仓库中做出的唯一更改,是更新它复用的对象文件的时间戳(这会推迟 git gc 对这些文件的清理)。带文件的回退只会写入对话文件夹内的普通文件;它会跳过符号链接、管道以及文件夹外的任何内容。任何数据都不会离开你的电脑。你可以在 dsh 关闭时删除这个存储(此后在发送新消息之前,回退只能用于对话本身)。删除对话 也会删除对话的存储。开关保存在 $DSH_HOME/storages/dsh-composer-plus/rollback.json 中。带文件的回退还会保留回退之前那一刻的文件(同一存储中的 refs/r/…),供 重新应用 使用;已重新应用的回退记录在 $DSH_HOME/storages/dsh-composer-plus/redone.json 中(仅所有者可访问)。
- 创建 GitHub issue(功能创意 → 稍后 列表):只在你点击时运行。Host 端会在对话的文件夹中运行你自己的 GitHub CLI(gh issue create),使用该创意保存的标题和概要(以及理由);gh 使用它自己的登录和该文件夹的 GitHub 远程仓库,因此 issue 会以你的账号创建在那个仓库中,能看到那个仓库的所有人都能看到它。dsh 会从它启动的命令中移除名称像令牌(token)的变量;如果你通过 GH_TOKEN 或 GITHUB_TOKEN 给 gh 提供了令牌,插件只把这两个变量传给 gh。issue 链接会与该创意一起保存在 later.json 中。
- 改动此文件的对话(改动面板,文件的“…”菜单):Host 端按 dsh 保存的样子,读取文件夹位于同一仓库中的对话的日志,并返回每个对话的标题、时间和请求的第一行;它从不打开该文件本身。
- 对话行显示 Git 分支: Host 端会在每轮开始和结束时,在对话的文件夹中运行 git branch --show-current(只读),并只把对话 id、分支名和时间保存在 $DSH_HOME/storages/dsh-composer-plus/session-branches.json 中(仅所有者可访问的文件,最多保留最新的 2000 个对话)。开关保存在它旁边的 branches.json 中。
- 在对话中查找 只在页面中运行:它读取页面显示的文本,不发送任何内容。
- 将对话导出为 Markdown: Host 端只读取对话自己的日志(即 dsh 显示的那些消息),并把它们交给页面;它不读取任何项目文件,也不通过网络发送任何内容。Markdown 只会进入你的剪贴板或你保存的文件。
- 删除对话: 把对话自己的日志文件夹($DSH_HOME/sessions/<project>/<chat>)移到废纸篓。它不会触碰项目文件夹。
- 本对话内允许: 授权连同授予时间一起保存在 $DSH_HOME/storages/dsh-composer-plus/chat-grants.json 中(仅所有者可访问)。一项授权只覆盖一个对话中的一个确切工具,直到时限结束(默认 1 小时)。如果该工具可以写入,授权也覆盖任何写入操作。可以在标题栏的标签中撤销授权。
- Auto Review 仍会检查每一次调用;审查失败的调用永远不会被自动允许。
- 手机连接: 在你开启之前一直关闭。开启后,Host 端会运行 Tether 网关:端口 19390 上的 HTTPS 服务只接受你的 Wi-Fi 子网和你的 tailnet(100.64.0.0/10);另有一个位于 127.0.0.1:19391 的配对页面(仅限这台 Mac)。手机需要二维码中的一次性代码(5 分钟内有效),还需要你在 Mac 上点击 Approve。手机会固定(pin)网关的证书。Mac 只保存每部手机令牌的哈希值(有效期 30 天,使用期间会续期);Remove 会立即关闭该手机的连接。手机只能调用允许列表中的 dsh 方法(对话、提示词、附件、斜杠命令、审批、问题、模型、智能体、目标),不能访问设置、凭据、文件浏览器或终端。“Tailscale only”会拒绝来自本地网络的所有连接,包括已经打开的连接。访问日志在 access.json 中保存最新的 200 次连接尝试(时间、IP 地址、设备名称、允许或拒绝,以及原因);其中从不包含令牌或配对代码。数据:$DSH_HOME/storages/dsh-composer-plus/mobile/(仅所有者可访问的文件)。详情:tether/README.md。
- 更新: Host 端会向 api.github.com 查询最新版本,并向 registry.npmjs.org 查询这个确切的版本;不会发送任何关于你或你的对话的信息。安装使用 dsh 的插件管理器(pnpm add dsh-composer-plus@<version>;如果 dsh 0.2.1 对已安装的插件拒绝这样做,则使用 pnpm add https://registry.npmjs.org/dsh-composer-plus/-/dsh-composer-plus-<version>.tgz,之后 profile 会把这个 URL 列为插件的来源),因此 dsh 自己的 registry、脚本和版本兼容性检查都会生效。预发布标签和旧版本永远不会被安装。
- 下一条消息预测: 默认开启;在 设置 → Composer Plus 中关闭它,即可停止这些模型调用。每完成一个回合,Host 端会把该对话中你自己的消息和智能体的文字回复(不含工具输出、隐藏上下文和推理内容),最多约 6,000 个字符(最新的部分),发送给所选的模型(除非你另选,否则为 dsh 的默认模型)。它通过 dsh 自己的提供商设置,以一次请求的形式发送。对话中不会保存任何内容:猜测不会被添加到对话历史中。开关和模型选择保存在 $DSH_HOME/storages/dsh-composer-plus/predict.json 中(仅所有者可访问的文件)。
- 输入时补全: 在你开启之前一直关闭。开启后,你每次输入停顿时,Host 端会把你目前已输入的文字,以及该对话中你自己的消息和智能体的文字回复(不含工具输出、隐藏上下文和推理内容;对话部分最多约 3,000 个字符),发送给在 输入时补全 下选择的模型(默认为 下一条消息预测 的模型)。新的停顿会停止较早的请求。对话中不会保存任何内容。开关保存在 $DSH_HOME/storages/dsh-composer-plus/complete.json 中(仅所有者可访问的文件)。
- 优化提示词: 在你点击魔法棒之前,什么都不会运行。点击后,Host 端会以一次请求的形式,把以下内容发送给在 优化提示词 下选择的模型(默认为对话自己的模型):你的草稿;该对话中你自己的消息和智能体的文字回复(不含工具输出、隐藏上下文、推理内容和已回退的消息;最多约 6,000 个字符,最新的部分);与 功能创意 相同的项目概要(文件规则也相同:不读取 .env 或密钥文件,跳过指向文件夹外部的符号链接和 FIFO);git status 列为已更改的路径;以及最多 30 个名称与你的草稿有相同词语的已跟踪或未跟踪(未被忽略)路径。除这份概要外,不会发送任何文件内容。对话和项目中都不会写入任何内容:回答只会替换输入框中的草稿,是否发送由你决定。模型选择保存在 $DSH_HOME/storages/dsh-composer-plus/improve.json 中(仅所有者可访问的文件)。
- 目标检查: 只有当智能体在自动轮次中把 /goal 标记为完成时(或者你点击 立即运行 时)才会运行。Host 端在对话的文件夹中、按对话的沙箱模式运行测试命令(与 dsh 自己的 bash 工具相同:同样的文件访问策略;沙箱无法启动时,测试不会运行,检查判为失败)。为了找到命令,它只读取 package.json、Makefile、Cargo.toml、go.mod、pyproject.toml 和 pytest.ini,并且只读取文件夹内的普通文件(不跟随指向文件夹外部的符号链接,不读取 FIFO)。然后,它以一次不带工具的请求,把以下内容发送给在 目标检查 下选择的模型(默认为对话自己的模型):目标;从目标开始以来的对话(你的消息、智能体的回复、截断到 1,000 个字符的工具调用以及每个工具结果的最后 2,000 个字符;不含推理内容和已回退的步骤;最多约 60,000 个字符,最新的部分);git status --short;以及测试输出的末尾。工具输出可能包含智能体读取过的内容,因此这次请求可能包含你文件的一部分,与对话本身相同。对话和项目中都不会写入任何内容。你的测试命令、上限、上次结果(含其输出的末尾)和模型选择保存在 $DSH_HOME/storages/dsh-composer-plus/goal-check.json 中(仅所有者可访问的文件,最新的 500 个对话)。
- 在新对话中继续: 在你点击之前,什么都不会运行。点击后,Host 端会把对话(与目标检查读取的方式相同:不含推理内容和已回退的步骤)发送给对话自己的模型,并显示交接说明;只有 开始新对话 才会创建新对话。项目中不会写入任何内容。
- 上下文明细: 只在 Host 上读取对话日志;不调用模型,不读取项目文件。
- 任务看板: 看板(任务的标题、描述、标签和评论,项目文件夹路径及其简短 ID)保存在 $DSH_HOME/storages/dsh-composer-plus/board.json 中(仅所有者可访问的文件);开关保存在旁边的 board-switch.json 中。数据不会离开你的电脑,也不会写入任何项目文件夹。看板工具会把你在看板上写的内容交给智能体,因此智能体读取任务时,任务文本会发送给对话所用的模型。损坏的看板文件会另存为 board.json.broken-<时间>,看板从空白开始。
- 受保护的文件: 列表和开关保存在 $DSH_HOME/storages/dsh-composer-plus/protected-files.json 中(仅所有者可访问的文件)。检查只读取每次文件工具调用的路径(及其真实路径),从不读取文件本身。
- 禁止的命令: 规则和开关保存在 $DSH_HOME/storages/dsh-composer-plus/blocked-commands.json 中(仅所有者可访问的文件)。检查只读取每次 bash 和 pwsh 调用的命令文本;它不运行任何内容,也不发送任何内容。
- 项目记忆: 在你开启之前一直关闭。开启后,每个顶层对话的回合结束时,Host 部分会把该对话自上次整理以来的新消息(你的消息和智能体的文字回复;不含工具输出、推理、隐藏上下文和已回滚的消息;分叉对话中复制自父对话的部分不算在内;最多约 16,000 个字符)和已保存的笔记,作为一次不带工具的请求发给对话自己的模型。笔记是 $DSH_HOME/storages/dsh-composer-plus/memory/ 下的 Markdown 文件(仅所有者可读写):每个项目文件夹对应 projects/<id>/(<id> 是文件夹真实路径的哈希;project.json 记录文件夹路径),另有 global/、journal.jsonl(每次改动及改动前后的那一行)和 reviewed.json(每个对话读到的位置)。项目文件夹中不会写入任何内容。看起来像密钥、令牌、密码或证件号码的笔记会被拒绝。项目的笔记会进入该文件夹中每个新对话的系统提示词,因此该对话的每次请求都会把它们发给模型。开关保存在同一位置的 memory.json 中。在你点 预览修改 之前,打开记忆 不会发送任何内容;点了之后,它会把显示的笔记和你的文字作为一次不带工具的请求发给 dsh 的默认模型。修改只在点 应用 时写入,日志中记为 editor。Tether 通过同一路由读取和修改笔记。
- 备份: 任何数据都不会离开你的电脑。归档保存在 ~/Desktop/dsh-backups 中(仅所有者可访问的文件)。机密不在归档中:凭据文件(.credentials.yaml、.env)、密钥文件(.pem、.key、.p12、.pfx)以及 yml 文件中 token、secret、password 和 API key 设置的值都会被遮蔽;它们的真实副本保存在同一文件夹的 composer-plus-vault/<archive>/ 中(仅所有者可访问),只在这台电脑上。用于另一台电脑 不会复制 vault:请在那台电脑上重新输入这些机密。你的对话日志、设置和 dsh 主目录的其余内容按原样保存在归档中:请像对待 $DSH_HOME 本身一样,不要公开该文件夹。备份使用 O_NOFOLLOW | O_NONBLOCK 读取文件;符号链接按链接保存(从不跟随),FIFO 和设备文件会被跳过。自动备份的开关和设置保存在 $DSH_HOME/storages/dsh-composer-plus/auto-backup.json 中,救援控制台的开关保存在 rescue-console.json 中;dsh 运行期间,running/host-<pid>.json 标明每个 dsh 进程(救援控制台读取它们,以便拒绝恢复)。
- 救援控制台: 一个终端菜单;它不打开网络端口。恢复只写入 dsh 主目录旁边的一个新文件夹(文件使用 O_EXCL | O_NOFOLLOW 写入,符号链接最后写入且从不跟随),并拒绝以下归档:含有不安全名称(..、绝对路径)、设备文件或 FIFO、多于一个顶层文件夹,或位于链接之下的条目。

故障排除

- macOS 上没有通知: 系统设置 → 通知 → DeepSeek Harness → 允许通知。选择“提醒”可以让通知一直留在屏幕上。
- dsh 更新后,▶、队列把手、项目状态、近期项目选项、折叠全部项目、复制路径、项目搜索框、下一条消息预测、输入时补全、本对话内允许或右键菜单不见了: 这些功能挂接在 dsh 当前的 HTML 上,因为 dsh 还没有为它们提供插槽。如果 dsh 修改了这部分标记,它们会自动隐藏;其他功能不受影响。请提交一个 issue。
- “更新失败”或“不是从 npm 安装的”: 从本地文件夹链接的副本或被重命名的副本无法自行更新;请在 设置 → 插件 中重新安装 dsh-composer-plus。在其他情况下,消息会显示 pnpm 错误的第一行;点击 检查更新 可重试。
- 手机连接提示网关未运行: “no IPv4 address on en0”表示这台 Mac 没有 Wi-Fi/以太网地址;“EADDRINUSE”表示另一个 dsh(或其他应用)正在使用端口 19390 或 19391。同一时间只能有一个 dsh 运行手机连接。
- 手机连接、重启后继续或内容搜索提示“重启 dsh”: 插件在 dsh 运行期间被更新了(对于内容搜索,也可能是你更改了开关);新状态会在重启后加载。
- 搜索只能找到标题: 内容搜索已关闭;或者你开启它或安装插件后还没有重启 dsh;或者这个词只出现在工具输出中(见“限制”)。
- 我的消息上没有 ↶ 按钮: 回合回退已关闭;或者该对话是子代理对话;或者已安装 dsh-rewind-plugin(请使用它的 ↶ 按钮)。更新后,请重启 dsh。
- “对话和文件”显示为灰色: 项目不是 git 仓库;或者没有这条消息之前的快照(这条消息比插件更早,或者它的快照已被最新的 50 个快照替换);或者没有文件发生变化。
- 删除时提示另一个 dsh 已打开此对话: 使用同一 dsh home 的另一个 dsh 持有该对话的锁。关闭那个窗口或那个 dsh,然后再次删除。在此期间,对话会保持归档状态。
- 开启“Tailscale only”后 iPhone 无法连接: Mac 和 iPhone 上都必须开启 Tailscale。Mac 上的 Tailscale 关闭时,手机连接面板会发出警告。访问日志会显示每次被拒绝的尝试及其原因。
- 重启后对话没有继续: dsh 退出时“重启后继续”处于关闭状态;或者你自己停止了那个回合;或者回合已经结束(完成或失败);或者对话已被归档;或者当时有超过 20 个对话正在运行(只有最新的 20 个会继续)。
- 重启后队列是空的: 清空队列的是 dsh 自己的退出流程。重启后继续只会在它继续的对话中放回队列;其他对话请重新发送消息。退出前刚删除的消息可能会回来:请再删除一次。
- 创建 GitHub issue 提示“gh could not open the issue”: 这条消息是 gh 自己输出的第一行。请在终端中运行 gh auth status,并用 gh auth login 登录;对话的文件夹必须有 GitHub 远程仓库(git remote -v)。“not installed or not on the PATH of dsh”表示 dsh 没有找到 gh:请安装它,或从一个能运行 gh 的终端启动 dsh。
- 对话行上没有分支标签: 安装此版本后,该对话还没有新的一轮;或者它的文件夹不是 git 仓库;或者 对话行显示 Git 分支 已关闭。更新后,请重启 dsh(分支由 Host 端记录)。
- 目标检查显示测试以代码 127 或 “not found” 退出: 从 Finder 或程序坞启动的 dsh 的 PATH 可能比终端里的短,因此找不到 npm、pnpm 或 cargo。请从终端启动 dsh,或者在 目标检查 → 编辑 中用完整路径设置你自己的测试命令。立即运行 会马上显示结果。
- 目标没有关闭,智能体一直在工作: 目标检查 发现了失败的测试或缺少的工作;目标下方的一行会显示原因(将鼠标悬停在结果上可查看详情)。请修正原因或测试命令,或者用 /goal 或目标栏自己完成目标(这不会被检查)。
- 刚发布新版本时安装失败: 请加上版本号(dsh-composer-plus@1.18.0),见上文的安装说明。
- 立即备份显示“另一个备份操作正在进行”: 另一个 dsh 窗口或救援控制台中正在运行一个操作(它们共用备份文件夹中的锁文件 .composer-plus.lock)。请等待它完成。如果没有操作在运行,下次点击时会接管已关闭进程留下的锁。
- 救援控制台显示“dsh is running”: 请先退出 dsh。如果 dsh 确实已关闭,消息中提到的文件是崩溃后留下的:删除它,然后重试。
- 恢复后 dsh 无法启动或缺少插件: 需要重新安装 profile 的插件包。恢复后,救援控制台会提供这一步;你也可以在它列出的 $DSH_HOME/profiles/ 下的每个文件夹中运行 pnpm install。不在 vault 中的机密(另一台电脑)必须重新输入:控制台会列出它们。

限制

- 不发送消息的“继续”依赖 dsh 的 agent/pre-step → agent/request 生命周期。升级 dsh 时,请重新检查兼容性。
- 功能创意 会在内存中为每个对话保留卡片,直到 dsh 或页面重新加载;之后,推荐功能 会再次询问模型。卡片使用你点击时 dsh 的界面语言;更改语言后,已在卡片堆中的卡片保持原来的语言,更多创意 则使用新语言。模型只能看到简短的项目概要,看不到代码,因此某个创意可能与项目已有的功能重复:跳过它即可。只有当 profile 中有 dsh 的 /plan 命令时,新对话才会以计划模式运行;否则,创意会作为普通的第一条消息发送。稍后 列表属于对话的文件夹路径:通过符号链接打开的同一个文件夹有它自己的列表。每个项目最多保留 50 个创意(移除一个后才能再添加),相同的标题只保留一次。拖动卡片只能决定向左或向右;要保存卡片,请使用 ↓;要直接实现,请使用 ▶。重复只按标题判断:模型仍可能以新名称推荐以前的创意,跳过它即可。如果模型只返回以前的创意,就不会显示新的创意:请再点击一次。关注主题越窄,越容易出现这种情况;请换一个更宽的主题,或清除主题。在 dsh 或页面重新加载之前,每个对话的关注主题都会保留在输入框中。
- 将对话导出为 Markdown 只包含你自己的消息和助手的文字回复:工具调用及其输出、推理内容、图片(用一行 [image] 标记)、隐藏上下文以及被回合回退或 dsh-rewind-plugin 移除的消息都不包含在内。同一回合的回复会合并为一个部分。一次导出最多包含约 400 万个字符;更长的对话只导出前面的部分,并附上一条说明。
- 重启后继续 是继续回合,而不是重放回合。退出时正在运行的工具调用会以 dsh 的“结果未知”结果结束,模型会被告知不要重复已完成的工作,但不能安全运行两次的命令仍可能再次运行。当时打开的子代理、审批和问题不会恢复:它们的父对话会继续,并再次询问。每次启动最多继续 20 个对话。
- 重启后继续 与队列:dsh 退出时会清空对话的队列。插件会根据对话日志放回你排队的消息,顺序、编辑内容、图片和文件都保持不变;这些消息会在继续的回合之后运行。只有会继续的对话才会恢复队列(开关已打开,且在回合运行时退出)。你自己删除队列中最后几条消息时,dsh 也会以同样的方式记录:如果你删除后、下一步开始前 dsh 退出,这些消息会回来。

- 内容搜索 是 dsh 自带的搜索,因此也有 dsh 的限制。它只搜索用户消息和助手消息:不搜索工具输出(命令、文件内容、结果),也不搜索推理内容,并且不能按用户、助手或工具消息筛选。它匹配完整的词,而不是词的一部分(deploy 找不到 deployment);不带重音的字母也能匹配带重音的字母(seker 能找到 şeker)。每个对话只显示一行,带有 dsh 的 240 字符摘录,最多显示 20 行。
- 内容搜索 的开销(在 247 个真实对话日志的副本上测得:159 MB,dsh 0.2.1-rc.2,Apple Silicon,32 GB):每次启动后的第一次搜索会构建索引,约需 15 秒。在此期间,dsh 的 Host 约有 7 秒不响应任何请求,因此其他对话会在这段时间内暂停流式输出(页面本身不会卡住)。Host 的内存在峰值时约增加 1.1 GB;一分钟后仍比启动时高约 0.5–0.6 GB,直到 dsh 退出。索引文件约 165 MB。之后的搜索约需 0.5 秒。重启后,第一次搜索约需 1 秒(只添加新的或有改动的对话),内存约增加 70 MB。如果你的电脑内存较少,请关闭此功能。
- 内容搜索 只有在重启 dsh 后才会生效,并且索引文件由所有使用同一 dsh home 的 dsh 共享:同一时间只运行一个这样的 dsh(dsh 规定每个索引文件只能有一个所有者)。
- 回合回退 只在 git 仓库中、并且只在对话的文件夹中恢复文件。每个对话保留最新的 50 个快照。被忽略的文件(.gitignore、info/exclude、你的全局忽略文件)、空文件夹、符号链接和子模块不会被恢复;创建快照时被忽略的文件永远不会被删除,即使该回合更改了忽略规则也一样。git 无法读取的文件不会进入快照。你每发送一条消息,就会对对话的文件夹执行一次 git add --all,写入私有存储:在包含大量未跟踪文件的超大文件夹中,这可能需要几秒钟,下一次工具调用会等待它完成(最多 10 秒;之后快照会在后台完成)。如果你仓库的 git gc 删除了旧快照需要的对象,该文件会被列为未恢复。只有消息的文字会回到输入框中:请重新添加它的图片或文件。子代理对话没有 ↶(子代理的文件更改算作启动它的对话的更改)。导出的对话(/export)中仍包含被撤回的消息。用一个隐藏标记撤回对话的一部分,这个思路来自 SiriLee 的 dsh-rewind-plugin(MIT);Composer Plus 没有使用其中的任何代码。
- 删除对话 需要 dsh 的归档功能(dsh 0.2.0 及更高版本)。如果对话(或它的某个子代理对话)在 15 秒内没有停止,或被另一个 dsh 持有,它会保持归档状态,不会移动任何内容。在 macOS 以外的系统上,废纸篓文件夹必须与对话历史位于同一磁盘。你删除的已打开对话会以归档和隐藏的状态留在 dsh 的内存中,直到 dsh 重启。请自行清倒废纸篓;dsh 不会替你清倒。
- dsh 的队列没有 move 操作,所以由插件的 Host 端在 dsh 的队列中直接移动排队的消息本身(一次改动,还是同一条消息)。带有图片或文件的消息也能移动。只有你自己的消息可以移动:队列中的目标轮次或对问题的回答会留在原处。如果在你拖动时有消息开始发送,则不会移动任何消息,并会显示一条提示说明这一点。
- 如果新版本不改动任何 dsh 设置,dsh 0.2.1 会立即加载更新;否则(以及在 dsh 0.2.0 上),请重启 dsh 来加载更新。插件从不替你重启 dsh。没有 dsh 插件管理器的网页版/CLI profile 只会提示有新版本。
- 本对话内允许 从授权的那一刻开始计算时限。新的时限会立即应用于仍在生效的授权,因此更短的时限可能会让它们立即结束。1.12 及更早版本的授权没有时间信息:更新后,代理会就这些工具再询问一次。
- 保持输入框焦点 只在发送 / 命令或技能后才会把焦点还给输入框。dsh 解析命令时,输入框会有几毫秒处于只读状态,因此这段时间内按下的键会丢失。如果 dsh 的 / 菜单仍然打开,Enter 会选择高亮的行,而不会发送。
- 问题卡片适应窗口 只改变 dsh 的问题卡片,不改变计划审阅卡片。它通过 dsh 的标记(data-question-key、data-question-scroll)找到卡片;如果 dsh 更新改变了这些标记,卡片会按 dsh 自己的样子显示。卡片高度跟随窗口,而不是对话:在较窄侧边面板中的对话里,较高的卡片仍可能超出对话上方。
- 对话标题栏适应窗口 通过 dsh 生成的类名(_titleRow、_titleCluster、_crumbs、_headerActions、_headerUtilities)找到对话标题栏,因为 dsh 没有为它提供布局接口。如果 dsh 更新改了这些类名,标题栏按 dsh 原样显示。在很窄的对话栏中,标题栏可能占两到三行,所以消息上方的空间会变小。
- 手机连接 只适用于 macOS(它使用 en0、openssl、swift 和 dns-sd)。它使用固定端口 19390 和 19391,因此每台 Mac 上同一时间只能有一个 dsh 运行它(每台 Mac 是手机 Mac 列表中的一项)。只有在 Tether 打开或刚转入后台时,手机才能收到通知(没有推送服务)。在 Tether 中打开“Settings → Notifications → Send notifications”之前,Tether 不会发送通知。此开关默认关闭,打开时 iOS 会请求通知权限。iOS 应用尚未上架 App Store:请用 Xcode 从 tether/ios 构建它。“Tailscale only”仍然需要 Mac 有 Wi-Fi 或以太网地址(只有在有这样的地址时,网关才会启动)。访问日志按 Mac 分别保存,只保留最新的 200 次尝试;一分钟内重复的尝试不会新增一行,而是把同一行的次数加一。Tether 的应用锁不会隐藏 iPhone 锁定屏幕上的通知预览:请在 iOS 设置中关闭它们。Tether 的绿点跟随 Mac:在 dsh 中打开的对话,手机上的绿点也会消失。在 Tether 中打开的对话,只在手机上消失;Mac 上 dsh 自己的绿点会一直保留,直到你在 Mac 上打开该对话。
- 会话链接在对话中有效;点击它不会打开对应的对话。用 复制消息链接 复制的链接,只在 dsh 0.2.1 及更高版本中、并且只从对话中的消息里才能打开对应的消息(dsh 0.2.0 没有用户文本规则,所以链接仍会被复制,但只显示为普通文本)。被回退移除的消息,或被压缩从 dsh 加载的历史中移除的消息,无法显示:此时链接会给出提示。🔗 按钮依附在 dsh 的消息行上;如果 dsh 更新改变了这部分标记,按钮就不会显示。
- 全部标为已读 通过 dsh 中一个不是公开 API 的部分(dsh 会话状态中的 completionUnread 列表)来更改 dsh 自己的未读圆点。如果 dsh 更新重命名了它,该菜单项就不会显示。该菜单项放在 dsh 项目的“…”菜单中,而这个菜单没有给插件的插槽;如果 dsh 修改了这个菜单,该菜单项也不会显示。
- 原地编辑排队消息 不会修改在此期间已经开始发送的消息,也不会覆盖在此期间已被修改的消息(例如在 iPhone 上的 Tether 中修改的),并会显示提示说明这一点。新图片需要支持图片的模型(dsh 自身的图片限制同样适用),新文件必须上传完成后才能保存。只能编辑你自己的排队消息,不能编辑队列中的目标轮次或对问题的回答。插件更新后,只有纯文字的编辑能立即生效:保存带图片或文件的消息之前,请重启 dsh(Host 端在启动时加载)。
- 重新应用 从不更改被回退的对话:它会从回退之前开始一个新对话(dsh 自带的分叉,模型上下文相同),因此新对话有新的 id 和标题。只有对话中最新的一次回退可以重新应用,只能一次,并且只在它之后没有新内容时可用(发送新消息后该选项消失)。回退之后你更改过的文件会被保留,除非你勾选覆盖它的选项。重新应用需要回退时保留的快照(同样是最新 50 个快照的范围);在此版本之前做的回退,或用 仅对话 做的回退,只会恢复消息。
- 树 分支图对每个箭头的指向是推测出来的,因为 git 不保存一个分支被合并进了哪个分支。已合并的分支指向最先用合并提交接收它的分支。等待中的分支指向它分出的最近的分支(优先主分支);如果两个分支从同一个提交分出,分支图可能会选错。通过快进(fast-forward)前移的分支没有合并提交,因此它的 已合并 标签不会打开任何内容。主分支是 origin 的默认分支,否则是 main 或 master,再否则是当前打开的分支。分支图读取最新的 20,000 个提交,最多显示 60 个分支;历史更长时,它会提示有些箭头可能不对。用 squash 或 rebase 合并的分支(例如在 GitHub 上)会显示为 等待中:git 不保留它与其提交之间的关联。
- 本对话 只统计 dsh 的文件工具(write、edit、str_replace_editor)写入的文件。命令(bash)更改的文件不在这个视图中;它们显示在 未提交 下。如果没有该对话的回合回退快照(回合回退已关闭、安装了 dsh-rewind-plugin,或对话比插件更早),视图会与最后一次提交比较,并给出提示。回合回退为每个对话保留最新的 50 个快照:在更长的对话中,视图与保留的最早快照比较,说明从哪条消息开始,并且不计入更早的改动。隐藏空白改动 就是 git diff -w:只在行内空格上有变化的行也会被隐藏。
- 创建 GitHub issue 需要 dsh 的 PATH 中有 GitHub CLI(gh),并且对话的文件夹中有 GitHub 远程仓库。它最多运行 60 秒;如果 gh 用时更长,issue 可能已经在 GitHub 上创建,但列表中没有它的链接(再次点击之前,请先到 GitHub 上查看:列表只从已完成的运行中读取链接,所以再次点击可能会创建第二个 issue)。有多个 GitHub 远程仓库的文件夹使用 gh 自己的默认仓库(gh repo set-default)。
- 改动此文件的对话 与 本对话 一样,只识别 dsh 的文件工具(write、edit、str_replace_editor):命令(bash)做出的改动不会列出。它读取该仓库最新的 300 个对话(按创建时间),对话更多时会给出提示;它最多显示 100 行。重命名的文件按工具写入时的名称列出。文件夹在仓库之外的对话(包括通过另一条路径指向相同文件的情况)不计入。dsh 启动后第一次打开时,会读取该仓库的所有对话日志(275 个对话约需 4 秒);之后再打开时,只读取此后有变化的对话。
- 对话行显示 Git 分支 显示的是对话最后一轮开始或结束时其文件夹所在的分支,而不是当前的分支:在回合之外切换分支,要到下一轮之后才会显示。此版本之前的对话,在下一轮之前不显示标签。标签放在 dsh 的对话行标记中(dsh 在那里没有插槽);如果 dsh 更新改变了这部分标记,就不会显示标签。当对话上方的项目行与分支同名时(例如“每个对话一个分支”的文件夹),该对话行不显示分支标签,但“列表视图”中仍会显示。
- 每个对话一个分支 在计划模式下:dsh 把 /plan <消息> 作为命令而不是消息发送,因此 Composer Plus 会在 dsh 的输入框中接管该命令的提交(不是公开 API)。如果 dsh 更新改变了这一点,选择 新分支 时的 /plan <消息> 会在已打开的新对话中作为 dsh 自己的命令运行。当 Host 无法在新对话中开启计划模式时,分支文件夹会保留,消息不会发送,因此新对话不会在默认模式下修改文件。
- 每个对话一个分支:当对话的分支文件夹(<project>/.worktrees/<name>)被删除时(例如对话自己的智能体移除了 worktree 并删除了分支),对话的下一步会把对话移出该文件夹。它的分支文件夹项目会从侧边栏消失,对话显示在“未分组”下并保持打开。在 dsh 0.2.1 及更高版本中,对话在主项目文件夹中继续,模型会收到一条关于新文件夹的说明。在 dsh 0.2.0 上,对话保留已删除的文件夹:在那里运行的命令会失败,直到你开始一个新对话。没有对话使用的已删除分支的项目也会从侧边栏消失:Composer Plus 在启动时和每 30 秒检查一次分支文件夹,不需要任何侧边栏筛选。对话移动期间,同一仓库中的新分支会回答“请重试”。关闭开关后,dsh 自己的错误会再次出现(“working-directory: directory does not exist”)。
- 工作区树中的分支 会在无需点击的情况下写入 git:移动对话时,它把项目文件夹切回原来的分支(git switch),并添加一个 worktree(git worktree add)。它从不删除分支、worktree 或文件。dsh 不能更改对话的文件夹,所以被移动的对话是一个副本(dsh 自己的分叉,带有新的 id),旧对话会被归档。副本会继续已停止的任务;分支出现时正在运行的工具调用会以拒绝结束,智能体会在新文件夹中再次运行它。旧对话的目标不会随之移动。只有文件夹是仓库主文件夹的对话会移动,而且只针对它在该轮中创建并切换到的分支(git switch -c、git checkout -b):只用 git branch 创建的分支、有未提交改动的文件夹、链接的 worktree 或子文件夹都不会移动。只有直接位于 <project>/.worktrees/ 中且有分支的 worktree 会显示在树中;分离的 worktree 或位于其他位置的 worktree 不会显示。只有当原对话是正在打开的对话时,副本才会自动打开(插件通过 dsh 的侧边栏行判断);否则它在分支项目中。
- 在对话中查找 只搜索页面显示的内容:已加载的消息和回复(向上滚动或点击 加载更早 可查看更早的内容),不搜索已收起的工具步骤,也不搜索工具输出中被折叠的文本。它最多统计 2,000 个匹配项(之后显示“2000+”)。它使用浏览器的高亮 API(Chromium 105 及更高版本;桌面应用支持):在较旧的浏览器中,计数和跳转仍然可用,只是没有颜色。Cmd+F(Mac)或 Ctrl+F(Windows 和 Linux)只在屏幕上有对话时打开它;在其他地方,浏览器自带的查找照常工作。在 Mac 上,Ctrl+F 在文本框中仍保持 macOS 的用法(光标向前移动一个字符)。
- 空闲时打开等待中的对话 只知道 dsh 自己的窗口看到的操作:在其他应用中的操作不算,因此 dsh 在后台时,它会在 30 秒后打开等待中的对话。它不会把 dsh 带到前台。只阅读而不按键、不点击、不移动鼠标,也算空闲。它只看带有 dsh 橙色圆点(问题、审批或计划审阅)或绿色圆点(你尚未打开的已完成一轮)的对话;子代理的请求显示在其父对话中。橙色对话先打开。打开绿色对话会去掉它的圆点,所以下一个绿色对话要等你下一次按键、点击、移动鼠标、滚动滚轮或触摸后才开始计 30 秒:你回来时,其他绿色圆点仍在。等待中的对话在屏幕上时,不会打开其他对话;你没有回答就离开的对话,在再次 30 秒没有使用后可能会再次打开。30 秒不能更改。
- 重启前发出的通知,点击后只会把 dsh 带到前台。
- 活跃项目通过 dsh 保存的项目顺序来移动,因此新顺序在重启后依然保留。不属于任何项目的对话(“未分组”)无法移动;dsh 总是把它们列在最后。
- dsh 在侧边栏的视图选项菜单中没有扩展点,所以近期项目选项被添加到 dsh 自己的菜单中。如果 dsh 更新修改了这个菜单,该选项将不会显示,所有项目都保持可见。筛选作用于项目行,因此 单列表 不会被筛选。在 按工作区树 中,只要父文件夹中的某个项目处于活跃状态,父文件夹就会保持显示,最近 2 小时内不活跃的对话行也会被隐藏;在 按工作区 中只筛选项目行。筛选会从 dsh 保存的视图设置(不是公开 API)读取 dsh 当前的视图;如果 dsh 更新改了它的名称,按工作区树 会按 按工作区 的方式筛选。项目状态也读取同一设置:在 按工作区树 中,父文件夹的行也会统计其中各项目的对话;如果 dsh 改了该设置的名称,每行只显示自己的对话。按状态 也有同类限制:dsh 没有排序插槽,因此该菜单项和行顺序依赖 dsh 的菜单和列表标记。
- dsh 也没有项目行菜单或“工作区”标题栏插槽。复制路径 通过 dsh 的行标记找到项目行;折叠全部项目 放在 dsh 的标题栏中,并用与点击项目行相同的方式折叠每个展开的项目。如果 dsh 更新修改了这些标记,右键点击会显示浏览器自己的菜单,按钮也不会显示。
- dsh 在新对话的项目菜单中也没有扩展点,所以 搜索项目 框和 A–Z 顺序依赖 dsh 的菜单标记。如果 dsh 更新修改了这些标记,菜单会按 dsh 自己的样子显示:使用保存的顺序,没有搜索框。A–Z 顺序只是一种视图,不会改变 dsh 保存的项目顺序。
- dsh 也没有决定 新会话 在何处打开的扩展点。新会话的默认工作区 包装了 dsh 的一个非公开 API 方法(dsh 工作区服务的 startSession)。如果 dsh 更新改了它的名字,新会话 会在 dsh 自己选择的位置打开(当前或最近的项目)。所有不指定项目的调用都使用默认值:侧边栏按钮、它的快捷键、徽标,以及 自动化任务 页面上的 新建。dsh 启动时仍会打开上一个对话。通用文件夹在首次使用时创建并加入你的项目;在 Windows 或 Linux 上,如果 Documents 文件夹被移动过,它可能与 dsh 自己的文件夹不同。
- dsh 也没有输入框提示的扩展点,所以 下一条消息预测 的文字覆盖在 dsh 自己的占位文字([data-composer-placeholder])上。如果 dsh 更新修改了这部分标记,就不会显示预测。开启期间,每完成一个回合都会进行一次简短的模型调用。
- 输入时补全 通过 dsh 自己的输入框提示显示文字(即 dsh 用于斜杠命令参数提示的 --dsh-composer-hint 样式)。输入斜杠命令、消息中带有文件或符号标签,或光标不在消息末尾时,它不会运行。如果 dsh 更新修改了这个样式,就不会显示补全。你每次输入停顿都会进行一次模型调用。
- 优化提示词 只能看到简短的项目概要、已更改的路径以及名称与你的用词匹配的路径,看不到代码本身。因此它可能漏掉正确的文件,并且只会提到提供给它的路径。发送前请先阅读新文本。输入除 /goal <目标> 以外的斜杠命令、/goal 控制词(clear、pause、resume),或消息中带有文件或符号标签时,它不会运行(新文本是纯文本,标签会丢失);一条消息最多 8,000 个字符。对于 /goal 目标,它只根据草稿和上下文写出条件;过于严格的条件可能会多花目标轮次,因此发送前请先阅读。图片仍保留在附件中:只有文字会改变。每次点击都会进行一次模型调用;较强的模型可能需要一分钟(按 Esc 取消)。
- 目标检查 只检查智能体在自动目标轮次中做出的完成:你在对话中要求的完成、/goal 和目标栏都不会被检查。智能体可以自己修改测试或测试命令用到的文件;审核模型会阅读对话,可以看到这一点,但它在两个方向上都可能出错(错误的“尚未完成”会多花一轮;错误的“已完成”会关闭目标)。审核模型看到的是对话和 git status,而不是代码本身。只有当智能体最新的一步能更改文件的操作就是它自己在同一文件夹中成功运行完全相同命令的 bash 时,才会复用这次测试;带管道(| tail)或 && 的命令不会被复用。预算在回合结束时计算,因此一个回合可能会超出预算。token 预算也会计算该对话的子智能体对话的调用(在每个回合结束时从它们保存的日志中读取,因此子智能体很多的对话检查起来会稍慢一些)。证据表来自审核模型自己对对话的阅读:它标为已验证的部分,在重要时仍需要你自己查看。检查运行期间 update_goal 会等待(测试最多 15 分钟,审核最多 3 分钟)。分支对话会得到新的对话 id,因此它开始时没有父对话自己的测试命令和上限。每次进入审核的完成都会花费一次模型调用。
- 受保护的文件 是护栏,不是沙箱。它覆盖 dsh 自己的文件工具(read、read_image、对文件使用 grep、write、edit、str_replace_editor)。shell 命令(cat .env)、智能体编写的脚本、子智能体的 shell、MCP 工具、glob 列表以及对整个文件夹使用的 grep 仍能访问受保护的文件。如需真正的限制,请使用 dsh 的沙箱模式,或者不要把机密放在项目文件夹中。模式支持 、* 和 ?,不支持 {a,b} 或 [ab],并且不区分大小写。
- 禁止的命令 是护栏,不是沙箱。它只读取 dsh 的 bash 和 pwsh 工具的命令文本。指代该命令的变量或别名(CMD=npm; $CMD publish)、shell 函数、智能体编写的脚本文件、其他程序(python -c、node -e、make)、MCP 工具以及你自己的终端仍能运行它。规则匹配的范围可能比你想要的更大:命令中的任何词都可以被当作命令名(echo npm publish 会匹配 npm publish),规则的词之间也可以夹着其他词(git push --force 也会匹配 git push origin main --force)。规则匹配过多时,请把它写得更长。先询问 需要一个能够询问的对话:在审批策略为 never 的对话中(例如委派的子智能体),dsh 无法显示卡片,因此调用会被拒绝并附上原因。审批卡片以英文显示原因。本对话内允许 不会回答 先询问 卡片。
- 在新对话中继续 会把对话(消息、工具调用以及每个工具结果的末尾,最多约 60,000 个字符,最新的部分)发送给对话自己的模型。交接说明可能漏掉某个决定或文件:开始前请先阅读。新对话只知道这份交接说明和链接的对话(dsh 会把旧对话作为只读上下文附加进来);它的模型上下文从很小开始,旧对话保持不变。每个对话同一时间只能进行一次写说明或开始操作。
- 上下文明细 按 dsh 自己的规则显示估算值(每个 token 约 4 个字符),与 dsh 的上下文环使用相同的规则;模型自己的计数可能不同。工具定义取自最新的一次请求。它按对话日志中的样子显示上下文;正在运行的回合会在它的下一步之后出现。
- 计划步骤 只有在模型确实做了计划时才会节省令牌:开启后,每个请求都会带上 plan_next_steps 工具和一段简短说明(约 500 个令牌),即使在模型从不做计划的对话中也是如此。条件只证明它所写的内容(例如:构建的退出码为 0),并不证明工作正确。ok 读取 dsh 自己的结果标记([exit code: N]、超时、沙箱拒绝);一个失败但退出码不为非零的命令会被视为通过。步骤一次只运行一个;同时就绪的两个步骤会交回给模型。该步骤的消息会作为对话模型的助手消息保存(dsh 没有标记插件所写消息的方式),因此它的文字会说明是 Composer Plus 运行的。Tether 中没有此功能。
- 任务看板 只认识 dsh 的项目:不在项目中的对话显示所有项目,“每个对话一个分支”的文件夹(<项目>/.worktrees/<名称>)算作它所属的项目。项目 ID(acme#12)来自文件夹名,在 dsh 中重命名项目后保持不变。“保持看板最新”的规则只会加入其项目有未完成任务的对话;已获得该规则的对话会一直保留它。智能体被告知把已完成、积压和人工任务留给你,但工具不会拒绝:智能体仍可能移动这些卡片。功能开启时,看板工具会出现在每个对话的工具列表中(每次请求约 1,000 个令牌);如果不用看板,请关闭它。页面显示时每 2 秒读取一次看板;智能体的修改会在这段时间内显示。你编辑的文本如果被智能体同时修改,则不会保存:面板会显示新文本和原因。不支持图片、不支持在多台电脑之间通过 git 同步、也不支持网络共享(Kanzo 有这些功能)。创意和外观来自 emanuele-em 的 Kanzo(AGPL-3.0);Composer Plus 没有使用它的任何代码。
- 停止后发送的消息优先 只在你停止对话后生效(或在某一轮失败后,或打开仍有队列的对话时):对话运行时发送的消息仍会排在队列末尾。它只会越过你自己的排队消息:如果队列中有目标轮次或问题回复,仍保持 dsh 自己的顺序。它会读取 dsh 中一个非公开 API 的部分(被停止的那一轮是否仍在结束中);如果 dsh 更新后改了它的名称,消息要等那一轮结束后才会被移到前面。子代理对话保持 dsh 自己的顺序。
- 项目记忆 属于对话的第一个文件夹(dsh 的项目文件夹):用 cd 更换文件夹的对话仍使用第一个项目的记忆;通过另一条路径打开的同一文件夹共用同一份记忆。对话开始时会冻结其记忆部分,所以之后保存的笔记从下一个对话开始显示(memory_recall 能立即找到)。整理只保留模型决定保留的内容:它可能漏掉某个事实,也可能保留错误的内容;请在 打开记忆 中检查并在那里修改,或在 dsh 关闭时手动编辑文件。打开记忆 会把所选项目的笔记和全局笔记(选择“全部笔记”时为所有项目;最多约 60,000 个字符,其余只计数,在该次请求中无法修改)以及你的文字发送给 dsh 的默认模型,而不是对话的模型。预览在 Mac 上保留 30 分钟,直到 dsh 重启;如果在此期间整理或智能体修改了笔记,应用 会拒绝,你需要重新预览。应用 要么保存预览中的全部修改,要么一项也不保存:只要有一项修改无法保存(例如 MEMORY.md 已满),笔记就保持原样,并显示原因。每个包含你的消息的回合结束后都会调用一次模型;调用失败时,下一个回合后会再次读取同样的消息。子智能体对话不做整理。这个思路和文件格式来自 DS Bot(Apache-2.0);Composer Plus 没有使用它的代码,也从不读取或写入 DS Bot 自己的记忆。
- 备份 只使用一个固定文件夹 ~/Desktop/dsh-backups(dsh-backup 的默认文件夹,因此它的归档仍然可用);没有设置可以改用其他文件夹。归档大小约等于不含 cache/ 和 dsh-runtimes/ 的 dsh 主目录(实测:在 Apple Silicon 上,1.6 GB 的文件约用 30 秒生成 830 MB 的归档;期间 dsh 保持响应)。读取期间发生变化的文件,会按备份打开它时的状态保存,因此打开中的对话的日志末尾可能是一条被截断的记录,dsh 会在下次写入时修复它。遮蔽按单行中的键名查找 yml 文件中的机密(token:、apiKey:、…);流式映射({token: x})中、此类键下的列表中、JSON 文件中(例如 .json 文件中某个 MCP 服务器的 apiKey)或使用其他名称的机密会留在归档中。dsh-backup 按类型生成的归档(dsh-t-…)不会列出。用于另一台电脑 会复制归档(在 APFS 上是克隆:不占用额外空间);vault 不会随之复制。立即备份 不会删除任何备份。自动备份会保留 Composer Plus 生成的最新备份(自动备份 的 保留 设置),并删除它生成的更早备份;升级前的快照单独计数(保留最新的 2 份)。dsh-backup 的归档永远不会被删除:请用 删除 移除它们。只要 dsh-backup 仍已安装,它就会把 Composer Plus 的归档计入自己的保留份数,并可能删除它们。
- 恢复 只在 dsh 关闭时于救援控制台中运行:它会替换整个 dsh 主目录。旧目录会以 .dsh.pre-restore- 保留在旁边,直到你删除它,因此磁盘需要能容纳两者。对话保留其项目路径:在另一台电脑上,位于其他路径的项目会显示为缺失,直到你重新添加它。指向 dsh 主目录之外的符号链接(例如从其他文件夹链接的技能)会作为链接恢复;它们的目标必须存在于那台电脑上。
- 会话日志检查 按照 dsh 自己判断能否打开的规则读取每个对话的最新日志:不是 JSON 或顺序错乱的行,只有在其后还有回合结束时才算损坏(否则 dsh 会打开该对话,只是不含从该行起的各行,因此不会列出它)。它不会按照 dsh 自己的事件规则检查日志中的事件,因此被判为健康的日志在 dsh 升级后仍可能无法打开。修复会从一份备份中取回副本:该备份之后的消息会从该对话中丢失(损坏的文件保留在旁边)。在此 dsh 中打开的对话不会在设置中修复:dsh 正持有它。
- 自动备份 只在 dsh 运行时运行:dsh 关闭期间到期的备份,会在下次启动后约 45 秒运行。新版本的快照在那次启动之后拍摄,而不是在更新之前。
- 已向上游请求内置支持:队列 move 见 #773,“继续”状态见 #9269。

常见问题

如何为 DeepSeek Harness 添加改动 / git diff 面板? 安装 dsh-composer-plus,然后打开右侧边栏 → + → 改动。

dsh 能像滑 Tinder 卡片一样为我的项目推荐功能吗? 可以:右侧边栏 → + → 功能创意 → 推荐功能。向右滑动会新建一个对话来规划该功能,点击 ▶ 直接实现 会新建一个不做规划、立即实现该功能的对话,向左滑动则跳过。

dsh 侧边栏搜索能按消息中的词语查找对话,而不只是按标题吗? 可以,使用 内容搜索(默认开启):安装插件后重启一次 dsh,然后使用 工作区 旁边的放大镜。匹配的对话会显示该词周围的文字。

能像在 OpenCode 或 Claude Code 中那样撤销一个回合并编辑我的提示词吗? 可以,使用 回合回退:点击消息上的 ↶,选择 对话和文件,编辑回到输入框中的文字,然后发送。

可以删除对话,而不是归档它吗? 可以,使用 删除对话:… → 删除…。历史记录会移到废纸篓,因此误删后可以恢复。

如何查看对话属于哪个项目? 看输入框下方那一行:开启 输入框中的项目名称(默认开启)后,这一行会以项目名称开头。将鼠标悬停在上面可查看文件夹路径。

如何在 dsh 输入框中使用 ↑/↓ 消息历史? 安装本插件;在空输入框中按 ↑ / ↓ 即可浏览你发送过的消息。

如何不输入“继续”就让被停止或失败的 dsh 回合继续? 使用本插件后,回合被停止、失败或中断时,发送按钮会变成 ▶;点击一次即可继续。

我退出并重新打开 dsh 后,正在运行的对话会继续吗? dsh 本身不会:dsh 会把这样的回合标记为已中断并等待(目标也会等待 /goal resume)。开启 设置 → Composer Plus → 重启后继续 后,dsh 退出时正在运行的对话会在下次启动时自动继续。

预测由哪个模型生成? 由你在 设置 → Composer Plus → 下一条消息预测 → 模型 中选择的模型生成。这个列表就是 dsh 自己的模型列表。dsh 默认 跟随 dsh 的默认模型。如果 dsh 不再列出所选的模型,预测会改用默认模型。输入时补全 有自己的 模型 菜单:与“下一条消息预测”相同(默认)跟随预测的模型;选择其他模型时,该模型只用于补全。如果 dsh 不再列出这个模型,补全会改用预测的模型。

dsh 能在发送前优化我的提示词吗,就像 Roo Code 或 Augment 中的 Enhance prompt 按钮那样? 可以,使用 优化提示词(默认开启):输入一个粗略的请求,然后点击模型菜单旁边的魔法棒。它会以此对话和项目为上下文,用你的语言改写文字,但不会发送。Cmd/Ctrl+Z 或 撤销优化 可恢复你的原文。在 设置 → Composer Plus → 优化提示词 → 模型 中选择它的模型。

能否让智能体不再自己宣布工作已完成,就像 loop engineering 中的审核循环那样? 可以,使用 目标检查(默认开启):用 /goal 开始一个目标。当智能体说目标已完成时,会运行项目的测试,并由一次独立的模型调用对照对话检查目标;任一项失败时,目标保持进行中,智能体会看到原因。在目标下方的 目标检查 行中用 编辑 设置你自己的测试命令、时间上限或 token 上限。

智能体能像 DS Bot 的记忆那样,在不同对话之间记住我的偏好吗? 可以,使用 项目记忆(默认关闭):在 设置 → Composer Plus 中开启。每个回合结束后,你长期的偏好和决定会作为简短笔记保存到该对话的项目中,该项目的每个新对话都会读取。让智能体记住某件事,它会立即保存。要查看或修改笔记,请点同一行的 打开记忆,写下要修改的内容。

我和智能体能像 Kanzo 那样共用一个任务看板吗? 可以,使用任务看板(默认开启):在左侧边栏打开它,用新建任务添加任务。在对话中让智能体“从看板领取下一个任务”:它会把卡片移到进行中,评论所做的工作,然后移到审核。把任务标记为人工即可留给自己。

dsh 能像 dsh-backup 那样备份我的对话和设置吗? 可以:设置 → Composer Plus → 备份 → 立即备份。它把相同格式的归档写入同一个文件夹(~/Desktop/dsh-backups),因此 dsh-backup 的归档也会显示并可以恢复,你可以卸载 dsh-backup。打开 自动备份 即可按计划备份。

dsh 无法再启动了。如何恢复备份? 打开备份文件夹(~/Desktop/dsh-backups),双击 Composer Plus Rescue.command(Linux:composer-plus-rescue.sh,Windows:Composer Plus Rescue.cmd)。选择 3) Restore a backup,选中一份备份并输入 RESTORE。它不需要 dsh 也能运行。

如何把 dsh 迁移到新电脑? 在旧电脑上:备份 → 某份备份旁边的 用于另一台电脑。把该文件夹复制到新电脑,在新电脑上安装 dsh 并退出它,然后打开复制过来的文件夹中的 Composer Plus Rescue 并恢复。请重新输入你的 API 密钥(它们留在旧电脑上)。

崩溃后某个对话打不开了。能修复吗? 设置 → Composer Plus → 会话日志检查 → 检查会话日志。用 从备份修复 可以从最新的备份中取回损坏的对话(该备份之后的消息会丢失)。

如何在 dsh 中调整排队消息的顺序? 拖动排队消息上的 ⠿ 把手,或者让它获得焦点后按 ↑ / ↓。

如何修改排队消息中的错字? 在队列中双击这条消息,修改文字后按 Enter(按 Esc 取消)。它在队列中的位置不变。你也可以在那里移除它的图片和文件,或添加新的。

如何一次清除一个项目的所有未读圆点? 侧边栏 → 项目的 … 按钮 → 全部标为已读。

可以链接到长对话中的某一条消息吗? 可以:将鼠标悬停在这条消息上,点击 🔗。在对话中发送这个链接:在 dsh 0.2.1 及更高版本中,点击它会打开那个对话并定位到这条消息。

我误回退了一个回合。可以找回来吗? 可以:回退之后,立即使用输入框上方的 重新应用。它会从回退之前开始一个新对话,消息相同;如果回退时选择了 对话和文件,它还会把文件恢复回来。

哪个对话改动了这个文件? 右侧边栏 → 改动 → 文件的 … → 改动此文件的对话。点击某一行,即可打开该对话并定位到做出改动的那条请求。

可以在一个很长的对话中搜索吗? 可以:在对话中按 Cmd+F(Mac)或 Ctrl+F(Windows 和 Linux)。在对话中查找 会高亮每个匹配项,并用 Enter 和 Shift+Enter 在它们之间跳转。

如何只查看一个对话更改过的文件? 右侧边栏 → 改动 → 本对话。点击 ␣ 可隐藏只有空白的改动。

如何阻止智能体运行 npm publish 或 git push --force? 设置 → Composer Plus → 禁止的命令:输入 npm publish,选择 阻止 或 先询问,然后点击 添加。阻止 会拒绝该命令,智能体会问你;先询问 每次都会显示审批卡片。受保护的文件覆盖智能体的文件工具;禁止的命令覆盖它的 shell 命令。

如何让 Auto Review 在同一个对话中不再反复询问同一个工具? 点击审批卡片上的 本对话内允许。它只覆盖该对话中的这个确切工具,默认有效 1 小时;可以在标题栏的标签中撤销它。在 设置 → Composer Plus → 本对话内允许 中更改时间。

我的 iPhone 丢了。如何阻止它访问我的 Mac? 点击侧边栏左下角的 手机连接,然后点击该 iPhone 旁边的 Remove。它的密钥会立即失效;只有通过你在 Mac 上批准的新配对,它才能重新连接。

可以用 Face ID 锁定 Tether 吗? 可以:在 Tether 中打开“Settings → Privacy → Lock with Face ID”。之后,Tether 在打开时以及你回到它时,都会要求 Face ID(或密码)。

如何在 dsh 侧边栏中只显示我今天用过的项目? 侧边栏 → 视图选项(滑块图标)→ 最近 2 小时内活跃。再次选择该项即可显示所有项目。

如何在 dsh 中复制项目的文件夹路径? 在侧边栏中右键点击项目 → 复制路径。

如何一次折叠 dsh 侧边栏中的所有项目? 点击视图选项(滑块图标)旁边的折叠按钮。至少有一个项目展开时,这个按钮才会显示。

dsh 任务完成或需要审批时,如何收到 macOS / Windows 通知? 保持 后台通知 开启(默认开启),并在操作系统设置中允许 DeepSeek Harness 发送通知。

dsh 能自己打开向我提问的对话吗? 可以,使用 空闲时打开等待中的对话(默认开启):当某个对话在等待回答、审批或计划审阅,而你 30 秒没有使用 dsh 时,dsh 会打开它。完成了你尚未查看的一轮的对话(绿色圆点)也会这样打开,在橙色对话之后。你在输入、滚动或移动鼠标时,它会等待。

如何把 DeepSeek Harness 界面切换为土耳其语、西班牙语、日语……? 设置 → Composer Plus → 应用语言。

如何在 iPhone 上使用 dsh? 用 Xcode 从 tether/ios 构建 Tether 应用,开启 设置 → Composer Plus → 手机连接(iPhone),点击左下角的 手机连接,扫描二维码(用 iPhone 相机或 Tether 中的 Scan code),轻点 Connect,然后点击 Approve。不在家时,请在两台设备上都使用 Tailscale。

如何让新会话总在同一个项目中打开? 设置 → Composer Plus → 新会话的默认工作区 → 新会话打开于 → 选择项目。其他项目旁的 + 仍会打开那个项目。

如何在同一个项目中同时开发多个功能,并让每个功能在自己的分支上? 使用 每个对话一个分支:在新对话界面,分支按钮默认显示 新分支:直接发送第一条消息。每个对话都有自己的分支和 worktree 文件夹;如果 .worktreeinclude 列出了你的 .env 和 node_modules,它们也会一起复制过去。对话标题栏会显示你当前所在的分支。

侧边栏能显示项目的每个分支,并在智能体创建分支时移动我的对话吗? 可以,使用 工作区树中的分支(默认关闭):在 设置 → Composer Plus 中开启它,然后在 dsh 中选择 视图选项 → 按工作区树。每个在 <project>/.worktrees/ 中有 worktree 的分支都会显示在其项目内。当你让项目文件夹中的智能体创建一个分支并在其中工作,且文件夹没有未提交的改动时,对话会自动移到该分支。删除分支的文件夹后,它会从列表中移除;它的对话会移到 未分组。

可以从 iPhone 发送照片吗? 可以。在 Tether 的对话中,轻点消息输入框旁边的 + → Camera、Photos(最多 4 张)或 Paste image。照片会作为你消息的附件发送到 Mac 上的对话,因此模型能看到它们。

dsh 能否不再询问模型就运行下一条命令? 可以,使用 计划步骤(默认关闭):在 设置 → Composer Plus 中开启。之后模型可以带条件地计划接下来的命令,例如“构建通过后运行测试”,结果满足条件时,Composer Plus 会在不重新调用模型的情况下运行该步骤。审批和沙箱保持不变。

它支持桌面应用吗? 支持:设置 → 插件 → 添加插件 → dsh-composer-plus。已在 dsh 0.2.0-rc.2(桌面版和网页版)和 0.2.1-rc.2(网页版)上测试。

开发

截图从一个临时 dsh 重新生成,这个 dsh 使用假模型和虚构的演示项目(acme-web、weather-cli、docs-site),因此截图中没有任何真实数据。功能缩略图放在 assets/features/ 中(随包发布,在设置中显示);只用于 README 的图片放在 docs/images/ 中(不在 npm 包中):

PLAYWRIGHT=/path/to/playwright node scripts/capture-screenshots.mjs /path/to/dsh/lib/bin.js
sidebar project features (recent filter, Copy path, Collapse all): real-app test + their thumbnails
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-sidebar-projects.mjs /path/to/dsh/lib/bin.js
recent filter + a finished chat older than 2 hours (fake model): the project stays until you open the chat
PLAYWRIGHT=/path/to/playwright node test/browser-recent-finished.mjs /path/to/dsh/lib/bin.js
PLAYWRIGHT=/path/to/playwright node test/browser-recent-tree.mjs /path/to/dsh/lib/bin.js
Order by status (fake model + Schedule): real-app test + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-status-order.mjs /path/to/dsh/lib/bin.js
every Settings feature row shows a loading screenshot and a ? link to its README row
PLAYWRIGHT=/path/to/playwright node test/browser-settings-shots.mjs /path/to/dsh/lib/bin.js
What's new after an update: the release notes show once, Esc and Close close them
PLAYWRIGHT=/path/to/playwright node test/browser-whats-new.mjs /path/to/dsh/lib/bin.js
README feature anchors (the ? links) on github.com, headless: each #feature-… shows the start of its row
PLAYWRIGHT=/path/to/playwright node test/browser-readme-anchors.mjs
Keep composer focus (fake model + demo skill): typing goes on after a / command + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-keep-focus.mjs /path/to/dsh/lib/bin.js
Fit question card to window (fake model asks a long question at 1280 × 820): question, answers, Skip and Submit readable, height follows the window + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-question-fit.mjs /path/to/dsh/lib/bin.js
Fit chat header to window (fake model, subagent + background jobs, branch pill, grants chip): no overlap from 1280 to 320 px, wide header unchanged + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-header-fit.mjs /path/to/dsh/lib/bin.js
Mobile connect: switch on, QR popover, a fake iPhone pairs and calls dsh through the gateway, switch off + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-mobile-connect.mjs /path/to/dsh/lib/bin.js
Resume after restart (fake slow model, real quit and start): a running chat and a goal continue, a stopped chat does not
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-resume-restart.mjs /path/to/dsh/lib/bin.js
Resume after restart with a queue (fake model, real quit and start): text, image, file, a drag and an edit come back in order
PLAYWRIGHT=/path/to/playwright node test/browser-resume-queue.mjs /path/to/dsh/lib/bin.js
Feature ideas (fake model, made-up project): suggest, drag left, Undo, ✓ starts a new chat in plan mode, ▶ Build now one without, Plan all one for the Later list, a focus topic chip, Copy as checklist + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-feature-ideas.mjs /path/to/dsh/lib/bin.js
Export chat as Markdown (fake model, made-up project): right-click → Export as Markdown…, copy and save keep the code blocks, switch off + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-export-markdown.mjs /path/to/dsh/lib/bin.js
Content search (fake model, made-up chats): a message-only word finds its chat with the snippet, switch off + restart = titles only + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-content-search.mjs /path/to/dsh/lib/bin.js
Turn rollback + Delete chat (fake model, made-up git project): bash edit → ↶ Chat and files → files back, .git unchanged; Delete… → Trash + its thumbnails
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-turn-rollback.mjs /path/to/dsh/lib/bin.js
Improve prompt (fake model, made-up git project): the wand sends the draft with the chat and the project, the answer replaces the draft, Cmd+Z and Undo bring it back + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-prompt-improve.mjs /path/to/dsh/lib/bin.js
Goal check (fake model, made-up project): a failing test and a verifier "not done" keep the goal open, the agent's own test run is reused, a pass closes it, a token budget blocks it + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-goal-check.mjs /path/to/dsh/lib/bin.js
Mark all as read, Copy message link, Edit queued message in place, Redo, Changes → This chat and Hide whitespace (fake model, made-up git projects) + their thumbnails
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-six-features.mjs /path/to/dsh/lib/bin.js
Changes Tree (fake model, made-up git history): the branch map (counts, colors, arrows), a branch's commits, commit files and diffs, Merged and Waiting files, back marks the box + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-changes-tree.mjs /path/to/dsh/lib/bin.js
Branches in the workspace tree (fake model, made-up git project): a worktree becomes a project, the agent's new branch moves the chat, a deleted folder leaves the tree + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-branch-tree.mjs /path/to/dsh/lib/bin.js
Allow for this chat with a time limit (fake model that is also the Auto Review reviewer): the grant ends after 1 hour
PLAYWRIGHT=/path/to/playwright node test/browser-grant-ttl.mjs /path/to/dsh/lib/bin.js
Next message prediction and Complete while typing (fake models): calls, Tab, Esc, model choice + their thumbnails
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-predict.mjs /path/to/dsh/lib/bin.js
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-complete.mjs /path/to/dsh/lib/bin.js
Project search in a new chat: A–Z order, filter, Enter + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-project-picker.mjs /path/to/dsh/lib/bin.js
Queue drag-and-drop and Continue with a queued message (slow fake model)
PLAYWRIGHT=/path/to/playwright node test/browser-queue-drag.mjs /path/to/dsh/lib/bin.js
PLAYWRIGHT=/path/to/playwright node test/browser-continue-queue.mjs /path/to/dsh/lib/bin.js
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-stop-send.mjs /path/to/dsh/lib/bin.js
Edit queued message in place with images and files (slow fake model) + its thumbnail
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-queue-edit.mjs /path/to/dsh/lib/bin.js
Task board: the page, the agent tools (fake model), drag and drop, search, the switch
SHOT=1 PLAYWRIGHT=/path/to/playwright node test/browser-task-board.mjs /path/to/dsh/lib/bin.js

npm run build:locales # after editing locales/<id>.json
npm run build:readme # after editing docs/features.json
npm test

新功能规则: 设置 → Composer Plus 中的每个功能行都会显示一张截图。把功能 id 添加到 client.js 的 SHOT_OF 和 index.js 的 SHOTS 中,并发布 assets/features/<id>.webp(从临时演示 dsh 中截取,使用英文界面,大小约 60 kB 或更小)。把该功能(使用同一张图片)添加到 docs/features.json,然后运行 npm run build:readme:它会写入 README.md 和每个翻译版 README.<id>.md 的功能表格,以及 llms.txt 中的列表。功能没有截图时,test/shots.test.mjs 会失败;test/browser-settings-shots.mjs 会检查真实的设置页面。每次更改的完整检查清单见 AGENTS.md。

测试会在假的 React/DOM 上运行真实的 client.js,并在临时 git 仓库上运行真实的 index.js(Host 端)。Tether 网关测试(test/tether-gateway.test.mjs)使用模拟的 dsh host 和真实的 TLS 网关。iPhone 应用位于 tether/ios 中(见 tether/README.md 和 tether/AGENTS.md)。每个 Host 路由、它的请求以及 Tether 能否调用它,都列在 docs/ROUTES.md 中。node test/browser-history.mjs '<dsh web URL with ?token=…>' 会在真实浏览器中,针对一个使用独立 DSH_HOME 的临时 dsh web 检查输入历史。

语言包是 locales/<id>.json 中的纯数据 JSON,由 npm run build:locales 嵌入到唯一的客户端入口中(不使用翻译服务,也不在运行时下载)。npm test 会检查每个语言包是否覆盖全部键、占位符和换行是否一致,以及跟随系统语言和手动覆盖时的行为。如需在本地安装的 Playwright 中进行隔离的真实应用检查:

PLAYWRIGHT=/path/to/playwright node test/browser-language.mjs /path/to/dsh/lib/bin.js

License

MIT
预览分享卡片长什么样 ↓furkancak1r/dsh-composer-plus
分享 · DeepSeek Harness Hub
furkancak1r/dsh-composer-plus

DeepSeek Harness 输入辅助:历史记录、一键继续、拖拽调整队列顺序

这是你的仓库?认领条目

回到顶部