dsh-tower 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +159 -2
- package/README.zh.md +160 -0
- package/cordis.patch.yml +23 -0
- package/icon.svg +7 -0
- package/index.js +296 -0
- package/lib/git.js +144 -0
- package/lib/modeStore.js +68 -0
- package/lib/store.js +123 -0
- package/lib/tools.js +801 -0
- package/lib/tower.js +1507 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +53 -4
- package/worker.js +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.0 — 2026-10-18
|
|
4
|
+
|
|
5
|
+
- **包名改为 `dsh-tower` 并发布到 npm**:安装命令为 `dsh plugin --profile web add dsh-tower`,
|
|
6
|
+
可出现在 DSH 插件中心;同时保留 `github:louifinn/dsh-tower` 与本地 checkout 的安装方式。
|
|
7
|
+
- Host 插件名、`tower-worker` preset 插件名、`cordis.patch.yml`、可选 UI 包(`dsh-tower-ui`)与
|
|
8
|
+
中英文 README 全部同步改名;移除 `package.json` 的 `private` 字段。
|
|
9
|
+
- 已安装 `@local/dsh-tower` 的用户需要 `remove_bundle` 后重新安装 `dsh-tower`;配置项 `id: tower`
|
|
10
|
+
与 config 内容不变,运行行为无变化。
|
|
11
|
+
|
|
12
|
+
## 1.0.5 — 2026-10-18
|
|
13
|
+
|
|
14
|
+
- README 增加源码安装命令 `dsh plugin --profile web add github:louifinn/dsh-tower`,满足
|
|
15
|
+
dsh-plugin.org 的收录要求(公开仓库 + `dsh-plugin` topic + README 安装命令 + 根 package.json)。
|
|
16
|
+
- 无运行时行为变化。
|
|
17
|
+
|
|
18
|
+
## 1.0.4 — 2026-10-18
|
|
19
|
+
|
|
20
|
+
- 版权署名统一为 **Loui Finn**:`LICENSE`、`README.md`、`README.zh.md` 与 `package.json` 的 author。
|
|
21
|
+
- 无运行时行为变化。
|
|
22
|
+
|
|
23
|
+
## 1.0.3 — 2026-10-18
|
|
24
|
+
|
|
25
|
+
- 开源前整理:README 改为英文主文档(中文版保留在 `README.zh.md`),补充特性、安装、安全约束、
|
|
26
|
+
工作原理、排障与贡献说明;添加 CI/许可证徽章与 “powered by dsh” 徽章。
|
|
27
|
+
- `tests/README.md`、`ui-bundle/README.md` 改为英文并去掉与特定会话绑定的表述。
|
|
28
|
+
- 新增 `CONTRIBUTING.md`、`SECURITY.md`;`.gitignore` 增加 `.env`/密钥/覆盖率等防泄漏规则。
|
|
29
|
+
- `package.json` 补充 repository/homepage/bugs/keywords 元数据。
|
|
30
|
+
- 清理提交作者邮箱:历史提交改用 GitHub noreply 地址重新发布。
|
|
31
|
+
- 无运行时行为变化。
|
|
32
|
+
|
|
33
|
+
## 1.0.2 — 2026-10-18
|
|
34
|
+
|
|
35
|
+
- **仓库布局改为符合 DSH 插件规范**:仓库根目录即 bundle 包根目录,`package.json`(含
|
|
36
|
+
`dsh.bundle.patch`)与 `cordis.patch.yml` 都在根目录;原先的 `bundle/` 子目录已移除。
|
|
37
|
+
- `package.json` 合并了插件包声明(name/version/exports/files/dsh)与开发脚本(`npm test`)。
|
|
38
|
+
- 测试与文档中的相对路径同步更新(`../bundle/...` → `../...`),README 更新为插件包说明。
|
|
39
|
+
- 无运行时行为变化。
|
|
40
|
+
|
|
41
|
+
## 1.0.1 — 2026-10-18
|
|
42
|
+
|
|
43
|
+
- **修复:`/tower <指令>` 会把一条没有 `role` 的消息写入会话,导致后续模型请求 422
|
|
44
|
+
`messages[N]: missing field role`(会话表现为“损坏”)。** `agent.steer` 需要完整的
|
|
45
|
+
`UserMessage`(`id` + `role` + `content` + `source`),不是 `{content, source}` 初始化对象;
|
|
46
|
+
转发时改为本地构造完整消息(`randomUUID()` 作为 id),与 `createUserMessage()` 的形状一致。
|
|
47
|
+
- 新增回归测试:mock 上下文断言转发消息带 `role:"user"` 与唯一 `id`;
|
|
48
|
+
隔离 Web 运行时用 `/tower 这是一条测试消息` 实测模型正常回复,会话日志中 spliced/user/message
|
|
49
|
+
均带 `role`/`id`。
|
|
50
|
+
- 提供 `tests/live/repair-session.cjs`:可修复已被旧版本写坏的会话日志(补 `role`/`id`,
|
|
51
|
+
原子写 + 备份 + 生成验证副本)。
|
|
52
|
+
|
|
53
|
+
## 1.0.0 — 2026-10-18
|
|
54
|
+
|
|
55
|
+
- `/tower` 命令支持裸调用、`on`/`off`、以及携带用户指令(`/tower on 继续`、`/tower off 继续`、`/tower 继续`);指令与附件通过 `agent.steer` 转发。
|
|
56
|
+
- 新增 `allowAgentControl` 配置:开启后模型可通过 `tower_control` 自行进出模式,必须给出理由。
|
|
57
|
+
- 进入模式时通过 `ctx.goals.pause` 暂停活跃 goal,并在结果中提示用户自行恢复。
|
|
58
|
+
- 模式持久化到 `$DSH_HOME/tower-mode/modes.json`(原子写、保留 200 条)。
|
|
59
|
+
- 移除 P6 验收用的临时 `tower_mode_dev` 钩子。
|
|
60
|
+
- 新增 README、单元测试、协议 e2e 测试与 opt-in UI bundle。
|
|
61
|
+
- 版本从 0.1.0 提升到 1.0.0。
|
|
62
|
+
|
|
63
|
+
## 0.1.0 — 2026-10-17
|
|
64
|
+
|
|
65
|
+
- 首个可用版本:P1–P6(mission/worktree/spawn/inbox/review/merge/rebase/teardown/mode)。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Loui Finn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,160 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-tower
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/louifinn/dsh-tower/actions/workflows/test.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-tower)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[中文说明](README.zh.md)
|
|
7
|
+
|
|
8
|
+
**Tower** is a multi-agent orchestration plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). It turns one agent session into a small engineering team: the session acts as the *control tower*, worker agents do the implementation inside isolated Git worktrees, and nothing reaches your base branch without an independent review and a hard merge gate.
|
|
9
|
+
|
|
10
|
+
The repository root **is** the DSH bundle: `package.json` declares `dsh.bundle.patch` and `cordis.patch.yml` lives at the root, as the DSH plugin specification expects.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Human-owned Tower mode.** `/tower` toggles a session-level stance that narrows the tool surface and injects the Tower protocol. `/tower on|off <instruction>` also forwards your instruction to the model in the same step.
|
|
15
|
+
- **Missions with real isolation.** Every mission gets its own branch and Git worktree; workers never touch your checkout.
|
|
16
|
+
- **Review-gated merges.** A reviewer bound to the current branch tip must submit a `clean` / `merge` verdict; the merge gate re-checks scope, staleness, task completion, review history, and worktree ownership before a `--no-ff` merge.
|
|
17
|
+
- **Durable coordination.** Roster, inbox, findings, reviews, and mission state are persisted under `.git/dsh-tower/`, so a restart does not lose the plan.
|
|
18
|
+
- **Safe by default.** While Tower mode is active, `create_goal`, `update_goal(resume)`, `todo_write`, the Team task board, and `spawn_teammate` are refused; a paused goal is never resumed automatically.
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- DeepSeek Harness `0.2.1-rc.2` (or a compatible newer build)
|
|
23
|
+
- Node.js 22 or newer
|
|
24
|
+
- Git (worktrees are created locally; no network access is required)
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Install the published package into a DSH profile:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web add dsh-tower
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or install it inside DSH with the plugin manager:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
plugin_manager({ action: "install_bundle", target: "dsh-tower" })
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For development, a local checkout can be linked instead:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
dsh plugin --profile web add github:louifinn/dsh-tower
|
|
44
|
+
# or link an existing checkout
|
|
45
|
+
dsh plugin --profile <profile> add <absolute path to this repository>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The Host plugin is loaded when the DSH process starts, so **restart DSH after installing or updating**. Remove it with `remove_bundle` and the package name `dsh-tower`.
|
|
49
|
+
|
|
50
|
+
## Quick start
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
/tower on
|
|
54
|
+
|
|
55
|
+
tower_init <repoRoot>
|
|
56
|
+
tower_plan <repoRoot> missions=[...]
|
|
57
|
+
tower_spawn <repoRoot> missionId=M1 role=worker
|
|
58
|
+
# worker implements and reports completion
|
|
59
|
+
tower_preflight <repoRoot> missionId=M1 # must be green before merging
|
|
60
|
+
tower_spawn <repoRoot> missionId=M1 role=reviewer
|
|
61
|
+
tower_review ... # reviewer submits verdict
|
|
62
|
+
tower_preflight <repoRoot> missionId=M1
|
|
63
|
+
tower_merge <repoRoot> missionId=M1
|
|
64
|
+
tower_teardown <repoRoot>
|
|
65
|
+
|
|
66
|
+
/tower off
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
A typical run takes one worker mission and one reviewer round for a small change.
|
|
70
|
+
|
|
71
|
+
## Commands
|
|
72
|
+
|
|
73
|
+
| Input | Behavior |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `/tower` | Enter Tower mode (stays on if already on) |
|
|
76
|
+
| `/tower on` | Enter or stay |
|
|
77
|
+
| `/tower on <instruction>` | Enter/stay **and** forward `<instruction>` as the next user message |
|
|
78
|
+
| `/tower off` | Leave Tower mode |
|
|
79
|
+
| `/tower off <instruction>` | Leave **and** forward `<instruction>` |
|
|
80
|
+
| `/tower <instruction>` | Ensure on, then forward `<instruction>` |
|
|
81
|
+
|
|
82
|
+
Image and file attachments are forwarded together with the instruction as one complete `UserMessage`.
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
- id: tower
|
|
88
|
+
name: 'dsh-tower'
|
|
89
|
+
config:
|
|
90
|
+
section: 'Optional replacement for the Tower-mode system prompt text'
|
|
91
|
+
allowAgentControl: true # true registers tower_control; false makes the mode human-only
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- `allowAgentControl` defaults to `false` in code. The bundled `cordis.patch.yml` enables it (`true`) so the model may enter/leave Tower mode when the user intent or task state clearly warrants it, always stating a reason.
|
|
95
|
+
- When disabled, only the human can change the mode.
|
|
96
|
+
|
|
97
|
+
## Tools (17)
|
|
98
|
+
|
|
99
|
+
`tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_finding` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode`
|
|
100
|
+
|
|
101
|
+
`tower_control` exists only when `allowAgentControl: true`.
|
|
102
|
+
|
|
103
|
+
## Safety and guardrails
|
|
104
|
+
|
|
105
|
+
- **No merge without a green gate.** `tower_preflight` is read-only and reports stable blocker codes; `tower_merge` refuses when any blocker remains.
|
|
106
|
+
- **Review is bound to a commit.** If the branch tip moves after a review, the gate reports `tip-moved`; re-review is required (a clean rebase waiver is the only exception).
|
|
107
|
+
- **Scope enforcement.** A mission may only change files matched by its declared scope globs; `out-of-scope` blocks the merge.
|
|
108
|
+
- **Worktree ownership.** Dirty worktrees, a running worker, or a branch owned by a closed mission block teardown/merge.
|
|
109
|
+
- **Goal isolation.** Entering Tower mode pauses the active goal and records it; leaving does not resume it. Use `/tower off` and resume the goal yourself.
|
|
110
|
+
|
|
111
|
+
The 13 stable blocker codes are: `branch-missing`, `deps-unmerged`, `read-only-survey`, `stale-base`, `no-review`, `review-hold`, `not-clean`, `review-not-approved`, `tip-moved`, `review-mission-mismatch`, `out-of-scope`, `base-dirty`, `branch-owned-by-closed-missions` (plus mission/worker guards).
|
|
112
|
+
|
|
113
|
+
## How it works
|
|
114
|
+
|
|
115
|
+
A mission moves through `planned → active → completed → merged` (or `blocked` / `paused` / `abandoned`). State lives in `<git-common-dir>/dsh-tower/`:
|
|
116
|
+
|
|
117
|
+
| Path | Contents |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `.git/dsh-tower/state.json` | missions, roster, reviews, findings, inbox |
|
|
120
|
+
| `.git/dsh-tower/activity.jsonl` | append-only activity log |
|
|
121
|
+
| `<checkout parent>/.dsh-tower-worktrees/<hash>/<missionId>` | per-mission worktree |
|
|
122
|
+
| `$DSH_HOME/tower-mode/modes.json` | Tower mode state per agent/session |
|
|
123
|
+
|
|
124
|
+
Workers and reviewers are ordinary DSH subagents started with the bundled `tower-worker` preset; their tools are restricted to the mission surface (filesystem, shell, and Tower protocol tools), never merge/spawn.
|
|
125
|
+
|
|
126
|
+
## Project layout
|
|
127
|
+
|
|
128
|
+
| Path | Contents |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `package.json`, `cordis.patch.yml` | bundle manifest and loader patch (inserts the Host plugin and the `tower-worker` preset) |
|
|
131
|
+
| `index.js`, `lib/`, `worker.js` | Host entry, protocol implementation, worker preset policy |
|
|
132
|
+
| `locale/`, `icon.svg` | localization and icon |
|
|
133
|
+
| `tests/` | pure-function, protocol end-to-end, and plugin-level tests; optional isolated Web-runtime scripts |
|
|
134
|
+
| `ui-bundle/` | optional Client widget (static `/tower` hint), not installed by default |
|
|
135
|
+
| `.github/workflows/test.yml` | CI running the offline suite on Node 22/24 |
|
|
136
|
+
|
|
137
|
+
## Development and testing
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm test # node --test tests/*.test.mjs
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The offline suite needs no DSH process and creates throwaway Git repositories in the OS temp directory. `tests/README.md` documents the isolated Web-runtime checks, model-driven acceptance, and the session-diagnostic scripts used while hardening the plugin.
|
|
144
|
+
|
|
145
|
+
## Troubleshooting
|
|
146
|
+
|
|
147
|
+
- **The plugin does not appear after install/update.** Host plugins load at DSH startup; restart DSH. Confirm the entry point targets this repository root (the folder with `package.json` and `cordis.patch.yml`), not a subdirectory.
|
|
148
|
+
- **`tower_control` is missing.** The config `allowAgentControl` is `false`; set it to `true` and restart.
|
|
149
|
+
- **Merge is blocked.** Run `tower_preflight` and read the blocker codes above; `stale-base` means run `tower_rebase` first.
|
|
150
|
+
- **A mission branch is stale after base moved.** `tower_rebase` rebases inside the worktree; a clean conflict-free rebase waives re-review for the previous verdict.
|
|
151
|
+
|
|
152
|
+
## Contributing
|
|
153
|
+
|
|
154
|
+
Issues and pull requests are welcome. Please run `npm test` before opening a PR; see [CONTRIBUTING.md](CONTRIBUTING.md) for details. Security reports: please avoid opening a public issue with exploit details; open a minimal issue asking for a private channel.
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT © Loui Finn
|
|
159
|
+
|
|
160
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# dsh-tower
|
|
2
|
+
|
|
3
|
+
[](https://github.com/louifinn/dsh-tower/actions/workflows/test.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-tower)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[English](README.md)
|
|
7
|
+
|
|
8
|
+
**Tower** 是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)的多代理编排插件。它把一个 agent 会话变成一个小型工程团队:会话本身是*控制塔*,worker agent 在隔离的 Git worktree 里实现任务,任何改动都必须经过独立审查和硬门禁才能合入基线分支。
|
|
9
|
+
|
|
10
|
+
仓库根目录**就是** DSH bundle 包根:`package.json` 声明 `dsh.bundle.patch`,`cordis.patch.yml` 位于根目录,符合 DSH 插件规范。
|
|
11
|
+
|
|
12
|
+
## 特性
|
|
13
|
+
|
|
14
|
+
- **由人类掌握的 Tower 模式。** `/tower` 切换会话级模式:收窄工具面并注入 Tower 协议;`/tower on|off <指令>` 还能把指令作为下一步用户消息转发给模型。
|
|
15
|
+
- **任务级隔离。** 每个 mission 使用独立分支和 Git worktree,worker 不会碰到你的主检出。
|
|
16
|
+
- **审查门禁合并。** 审查者必须针对当前分支 tip 给出 `clean` / `merge` 结论;合并门禁重新校验 scope、分支新鲜度、任务完成度、审查记录与 worktree 归属,通过后才执行 `--no-ff` 合并。
|
|
17
|
+
- **可恢复的协作状态。** roster、inbox、findings、reviews 与 mission 状态持久化在 `.git/dsh-tower/` 下,重启不会丢计划。
|
|
18
|
+
- **默认安全。** Tower 模式开启期间拒绝 `create_goal`、`update_goal(resume)`、`todo_write`、Team 任务板与 `spawn_teammate`;被暂停的 goal 不会被自动恢复。
|
|
19
|
+
|
|
20
|
+
## 环境要求
|
|
21
|
+
|
|
22
|
+
- DeepSeek Harness `0.2.1-rc.2`(或兼容的新版本)
|
|
23
|
+
- Node.js 22+
|
|
24
|
+
- Git(worktree 在本地创建,不需要联网)
|
|
25
|
+
|
|
26
|
+
## 安装
|
|
27
|
+
|
|
28
|
+
把已发布的包安装到 DSH profile:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web add dsh-tower
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
或在 DSH 中用插件管理器安装:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
plugin_manager({ action: "install_bundle", target: "dsh-tower" })
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
开发时也可以链接本地检出或从 GitHub 安装:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
dsh plugin --profile web add github:louifinn/dsh-tower
|
|
44
|
+
# 或链接本地 checkout
|
|
45
|
+
dsh plugin --profile <profile> add <本仓库的绝对路径>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Host 插件在 DSH 进程启动时加载,**安装或更新后需重启 DSH**。卸载使用 `remove_bundle`,包名 `dsh-tower`。
|
|
49
|
+
|
|
50
|
+
## 快速开始
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
/tower on
|
|
54
|
+
|
|
55
|
+
tower_init <repoRoot>
|
|
56
|
+
tower_plan <repoRoot> missions=[...]
|
|
57
|
+
tower_spawn <repoRoot> missionId=M1 role=worker
|
|
58
|
+
# worker 实现并汇报完成
|
|
59
|
+
tower_preflight <repoRoot> missionId=M1 # 必须全绿才能合并
|
|
60
|
+
tower_spawn <repoRoot> missionId=M1 role=reviewer
|
|
61
|
+
tower_review ... # 审查者提交结论
|
|
62
|
+
tower_preflight <repoRoot> missionId=M1
|
|
63
|
+
tower_merge <repoRoot> missionId=M1
|
|
64
|
+
tower_teardown <repoRoot>
|
|
65
|
+
|
|
66
|
+
/tower off
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
小改动通常一轮 worker + 一轮 reviewer 即可完成。
|
|
70
|
+
|
|
71
|
+
## 命令
|
|
72
|
+
|
|
73
|
+
| 输入 | 行为 |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `/tower` | 开启 Tower 模式(已开启则保持) |
|
|
76
|
+
| `/tower on` | 开启或保持 |
|
|
77
|
+
| `/tower on <指令>` | 开启/保持,并把 `<指令>` 作为下一条用户消息转发 |
|
|
78
|
+
| `/tower off` | 退出 Tower 模式 |
|
|
79
|
+
| `/tower off <指令>` | 退出并转发 `<指令>` |
|
|
80
|
+
| `/tower <指令>` | 确保开启,然后转发 `<指令>` |
|
|
81
|
+
|
|
82
|
+
图片与文件附件会随指令一起作为一条完整的 `UserMessage` 转发。
|
|
83
|
+
|
|
84
|
+
## 配置
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
- id: tower
|
|
88
|
+
name: 'dsh-tower'
|
|
89
|
+
config:
|
|
90
|
+
section: '(可选)覆盖 Tower 模式系统提示文案'
|
|
91
|
+
allowAgentControl: true # true 时注册 tower_control;false 时只有人类能切换
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- 代码中 `allowAgentControl` 默认 `false`;仓库自带的 `cordis.patch.yml` 把它设为 `true`:当用户意图或任务状态明确时,模型可以自行进出 Tower 模式,但必须给出理由。
|
|
95
|
+
- 设为 `false` 时只有人类能切换模式。
|
|
96
|
+
|
|
97
|
+
## 工具(17 个)
|
|
98
|
+
|
|
99
|
+
`tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_finding` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode`
|
|
100
|
+
|
|
101
|
+
`tower_control` 仅在 `allowAgentControl: true` 时存在。
|
|
102
|
+
|
|
103
|
+
## 安全与约束
|
|
104
|
+
|
|
105
|
+
- **门禁不全绿不合并。** `tower_preflight` 是只读检查,返回稳定的 blocker code;存在 blocker 时 `tower_merge` 拒绝合并。
|
|
106
|
+
- **审查绑定提交。** 审查后分支 tip 变化会报 `tip-moved`,必须重新审查;唯一的例外是干净 rebase 的免审豁免。
|
|
107
|
+
- **scope 强制。** mission 只能修改其 scope glob 匹配的文件,越界会以 `out-of-scope` 阻止合并。
|
|
108
|
+
- **worktree 归属。** 脏工作树、运行中的 worker、已关闭 mission 的分支都会阻止合并或 teardown。
|
|
109
|
+
- **goal 隔离。** 进入 Tower 模式会暂停活跃 goal 并记录;退出不会自动恢复,需要你自行恢复。
|
|
110
|
+
|
|
111
|
+
13 个稳定 blocker code:`branch-missing`、`deps-unmerged`、`read-only-survey`、`stale-base`、`no-review`、`review-hold`、`not-clean`、`review-not-approved`、`tip-moved`、`review-mission-mismatch`、`out-of-scope`、`base-dirty`、`branch-owned-by-closed-missions`(另有 mission/worker 守卫)。
|
|
112
|
+
|
|
113
|
+
## 工作原理
|
|
114
|
+
|
|
115
|
+
mission 生命周期:`planned → active → completed → merged`(或 `blocked` / `paused` / `abandoned`)。状态位置:
|
|
116
|
+
|
|
117
|
+
| 路径 | 内容 |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `.git/dsh-tower/state.json` | missions、roster、reviews、findings、inbox |
|
|
120
|
+
| `.git/dsh-tower/activity.jsonl` | 只追加的活动日志 |
|
|
121
|
+
| `<主检出父目录>/.dsh-tower-worktrees/<hash>/<missionId>` | 每个 mission 的 worktree |
|
|
122
|
+
| `$DSH_HOME/tower-mode/modes.json` | 每个 agent/session 的 Tower 模式状态 |
|
|
123
|
+
|
|
124
|
+
worker 与 reviewer 是使用内置 `tower-worker` preset 的普通 DSH 子代理;它们的工具被限制在 mission 允许面(文件系统、shell、Tower 协议工具),不包含 merge/spawn。
|
|
125
|
+
|
|
126
|
+
## 项目结构
|
|
127
|
+
|
|
128
|
+
| 路径 | 内容 |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `package.json`、`cordis.patch.yml` | bundle 清单与 loader patch(插入 Host 插件和 `tower-worker` preset) |
|
|
131
|
+
| `index.js`、`lib/`、`worker.js` | Host 入口、协议实现、worker preset 策略 |
|
|
132
|
+
| `locale/`、`icon.svg` | 本地化与图标 |
|
|
133
|
+
| `tests/` | 纯函数、协议 e2e、插件级测试;可选的真实 Web 运行时脚本 |
|
|
134
|
+
| `ui-bundle/` | 可选 Client 小挂件(静态 `/tower` 提示),默认不安装 |
|
|
135
|
+
| `.github/workflows/test.yml` | CI:Node 22/24 上跑离线套件 |
|
|
136
|
+
|
|
137
|
+
## 开发与测试
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm test # node --test tests/*.test.mjs
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
离线套件不需要 DSH 进程,只在系统临时目录创建一次性 Git 仓库。隔离 Web 运行时检查、模型驱动验收和会话诊断脚本见 `tests/README.md`。
|
|
144
|
+
|
|
145
|
+
## 常见问题
|
|
146
|
+
|
|
147
|
+
- **安装/更新后插件不出现。** Host 插件在 DSH 启动时加载,请重启 DSH;并确认安装目标指向本仓库根目录(含 `package.json` 与 `cordis.patch.yml` 的那一层),而不是子目录。
|
|
148
|
+
- **没有 `tower_control`。** 配置 `allowAgentControl` 为 `false`;改为 `true` 并重启。
|
|
149
|
+
- **合并被阻止。** 运行 `tower_preflight` 查看 blocker code;`stale-base` 表示先执行 `tower_rebase`。
|
|
150
|
+
- **基线前进后分支过期。** `tower_rebase` 在 worktree 内完成 rebase;干净且无冲突的 rebase 可免去上一轮审查的重审。
|
|
151
|
+
|
|
152
|
+
## 贡献
|
|
153
|
+
|
|
154
|
+
欢迎 issue 与 pull request。提交 PR 前请先运行 `npm test`,细节见 [CONTRIBUTING.md](CONTRIBUTING.md)。安全相关问题请不要在公开 issue 里贴利用细节,先开一个最小化 issue 申请私下渠道。
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT © Loui Finn
|
|
159
|
+
|
|
160
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
- insert:
|
|
2
|
+
- id: tower
|
|
3
|
+
name: 'dsh-tower'
|
|
4
|
+
config:
|
|
5
|
+
allowAgentControl: true
|
|
6
|
+
- id: preset-tower-worker
|
|
7
|
+
name: '@deepseek-ai/dsh-agent-preset'
|
|
8
|
+
config:
|
|
9
|
+
id: tower-worker
|
|
10
|
+
name: Tower Worker
|
|
11
|
+
description: Executes one Tower mission inside its assigned git worktree.
|
|
12
|
+
order: 60
|
|
13
|
+
plugins:
|
|
14
|
+
- id: tower-worker-policy
|
|
15
|
+
name: 'dsh-tower/worker'
|
|
16
|
+
- id: tower-worker-fs
|
|
17
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
18
|
+
- id: tower-worker-fs-search
|
|
19
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
20
|
+
config:
|
|
21
|
+
sampleOverCapGlobResults: false
|
|
22
|
+
- id: tower-worker-pwsh
|
|
23
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
package/icon.svg
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
|
2
|
+
<rect x="4" y="4" width="56" height="56" rx="12" fill="#141a24"/>
|
|
3
|
+
<rect x="16" y="13" width="32" height="9" rx="2" fill="#f9b98c"/>
|
|
4
|
+
<rect x="20" y="26" width="24" height="8" rx="2" fill="#d98a5f"/>
|
|
5
|
+
<rect x="24" y="38" width="16" height="7" rx="2" fill="#b56f4c"/>
|
|
6
|
+
<path d="M14 52h36" stroke="#8a5238" stroke-width="3" stroke-linecap="round"/>
|
|
7
|
+
</svg>
|