dsh-tower 2.1.0 → 2.4.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 +137 -0
- package/COMPATIBILITY.md +6 -1
- package/CONTRIBUTING.md +78 -5
- package/PRINCIPLES.md +163 -0
- package/README.en.md +35 -19
- package/README.md +28 -18
- package/SECURITY.md +6 -0
- package/{lib → adapters}/archive.js +1 -1
- package/{lib → adapters}/caseSensitivity.js +1 -1
- package/adapters/default.js +51 -10
- package/{lib → adapters}/git.js +1 -1
- package/{lib → adapters}/leases.js +1 -1
- package/{lib → adapters}/legacy.js +1 -1
- package/adapters/persistence.js +543 -0
- package/adapters/store-fs.js +28 -1
- package/adapters/store.js +204 -0
- package/{lib → adapters}/tests.js +9 -5
- package/adapters/vcs-git.js +15 -1
- package/{lib → adapters}/workspaceLock.js +1 -1
- package/{lib → adapters}/worktreeOwnership.js +1 -1
- package/app/archive.js +4 -6
- package/app/batch.js +9 -10
- package/app/board.js +2 -4
- package/app/checkCompletion.js +9 -10
- package/app/enrichedMissions.js +2 -4
- package/app/findings.js +6 -7
- package/app/gate.js +1 -2
- package/app/init.js +24 -29
- package/app/merge.js +58 -51
- package/app/messages.js +7 -8
- package/app/mission.js +5 -5
- package/app/plan.js +8 -5
- package/app/provision.js +12 -14
- package/app/read.js +6 -3
- package/app/rebase.js +14 -16
- package/app/recording.js +7 -8
- package/app/review.js +15 -8
- package/app/roster.js +14 -15
- package/{lib → app}/spawn-prechecks.js +4 -3
- package/app/spawn.js +12 -13
- package/app/teardown.js +8 -9
- package/app/tower.js +89 -35
- package/cordis.patch.yml +56 -28
- package/docs/README.md +7 -2
- package/docs/adr/0001-ports-adapters-as-data.md +49 -0
- package/docs/adr/0002-single-state-json.md +50 -0
- package/docs/adr/0003-allow-agent-control-default-true.md +48 -0
- package/docs/adr/0004-surface-budget.md +70 -0
- package/docs/adr/0005-component-surface.md +130 -0
- package/docs/adr/README.md +52 -0
- package/docs/agents/workflow.md +51 -0
- package/docs/architecture/overview.md +192 -43
- package/docs/guide/hot-reload.md +5 -5
- package/docs/guide/install-upgrade-migration.md +13 -0
- package/docs/guide/release.md +1 -1
- package/docs/operations/incident.md +82 -0
- package/docs/operations/runbook.md +12 -3
- package/docs/operations/security.md +1 -1
- package/docs/reference/blockers.md +2 -2
- package/docs/reference/component-surface.md +135 -0
- package/docs/reference/config.generated.md +2 -9
- package/docs/reference/config.md +11 -9
- package/docs/reference/doctor.md +53 -2
- package/docs/reference/errors.generated.md +41 -37
- package/docs/reference/errors.md +53 -41
- package/docs/reference/events.md +38 -6
- package/docs/reference/surface-budget.md +157 -0
- package/docs/reference/tools.generated.md +8 -5
- package/docs/reference/tools.md +10 -7
- package/docs/zh/README.md +1 -1
- package/docs/zh/guide/hot-reload.md +4 -4
- package/docs/zh/guide/install-upgrade-migration.md +10 -0
- package/docs/zh/operations/security.md +1 -1
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/config.md +9 -9
- package/docs/zh/reference/doctor.md +29 -1
- package/docs/zh/reference/tools.md +10 -8
- package/domain/batch.js +2 -2
- package/domain/components.js +641 -0
- package/domain/config/schema.js +62 -28
- package/domain/contracts/outputs.js +16 -2
- package/domain/contracts/tool-inputs/ops.js +1 -0
- package/domain/errors.js +308 -43
- package/domain/events.js +207 -0
- package/domain/integration/gate.js +17 -2
- package/domain/integration/merge.js +35 -0
- package/domain/lockBudget.js +30 -0
- package/domain/mission.js +12 -1
- package/domain/missions/completion.js +14 -0
- package/domain/missions/lifecycle.js +9 -3
- package/domain/missions/plan.js +14 -0
- package/domain/missions/review.js +90 -7
- package/domain/read/views.js +3 -0
- package/domain/state/archive.js +1 -1
- package/domain/state.js +1 -1
- package/domain/surface.js +347 -0
- package/host/capability-batch.js +15 -0
- package/host/capability-hmr.js +30 -0
- package/host/capability-import.js +11 -0
- package/host/capability-leases.js +11 -0
- package/host/capability-registry.js +149 -0
- package/host/capability-tests.js +16 -0
- package/{lib → host}/doctor.js +157 -18
- package/{lib → host}/hmr.js +2 -4
- package/{lib → host}/modeStore.js +1 -1
- package/host/presets.js +77 -0
- package/{lib → host}/tool-registry.js +235 -44
- package/host/tower.js +32 -0
- package/index.js +40 -25
- package/locale/en.json +31 -11
- package/locale/zh.json +30 -10
- package/package.json +24 -4
- package/ports/archive.js +18 -0
- package/ports/caseSensitivity.js +15 -0
- package/ports/clock.js +10 -2
- package/ports/config.js +19 -0
- package/ports/contract.js +38 -0
- package/ports/events.js +24 -0
- package/ports/ids.js +10 -2
- package/ports/index.js +54 -2
- package/ports/ownership.js +17 -0
- package/ports/state.js +16 -0
- package/ports/store.js +52 -3
- package/ports/vcs.js +25 -4
- package/scripts/architecture-waivers.json +19 -0
- package/scripts/architecture.mjs +634 -23
- package/scripts/check-components.mjs +235 -0
- package/scripts/check-docs.mjs +8 -35
- package/scripts/check-pack.mjs +68 -39
- package/scripts/check-philosophy.mjs +266 -0
- package/scripts/component-surface.json +395 -0
- package/scripts/domain-metrics.mjs +13 -4
- package/scripts/generate-component-surface.mjs +59 -0
- package/scripts/generate-config-reference.mjs +14 -1
- package/scripts/generate-error-reference.mjs +68 -14
- package/scripts/generate-events-reference.mjs +83 -0
- package/scripts/generate-tools-reference.mjs +18 -25
- package/scripts/generate-types.mjs +127 -0
- package/scripts/issue-audit.mjs +2 -2
- package/scripts/lib/surface.mjs +87 -0
- package/scripts/lib/tool-surface.mjs +85 -0
- package/scripts/mount-smoke/fixtures.mjs +3 -3
- package/scripts/mount-smoke/surface.mjs +96 -27
- package/scripts/mount-smoke.mjs +3 -1
- package/scripts/pack-manifest.txt +75 -22
- package/scripts/regression-audit.mjs +164 -0
- package/scripts/release-check.mjs +1 -1
- package/scripts/surface-baseline.json +52 -0
- package/scripts/surface-baseline.mjs +118 -0
- package/scripts/types-coverage.mjs +184 -0
- package/scripts/types-strict-manifest.txt +10 -0
- package/scripts/types-strict.mjs +141 -0
- package/skills.js +8 -1
- package/tools/adopt.js +2 -3
- package/tools/batch.js +2 -3
- package/tools/complete.js +2 -3
- package/tools/diff.js +3 -3
- package/tools/doctor.js +7 -10
- package/tools/finding.js +2 -3
- package/tools/findings.js +3 -3
- package/tools/import-legacy.js +3 -5
- package/tools/inbox.js +3 -3
- package/tools/index.js +9 -8
- package/tools/init.js +3 -6
- package/tools/interrupt.js +2 -3
- package/tools/legacy-map.js +3 -5
- package/tools/merge.js +3 -3
- package/tools/mission.js +2 -3
- package/tools/plan.js +6 -5
- package/tools/preflight.js +2 -3
- package/tools/rebase.js +3 -3
- package/tools/recover.js +38 -13
- package/tools/reload.js +36 -40
- package/tools/resource.js +3 -5
- package/tools/review.js +3 -4
- package/tools/roster.js +2 -3
- package/tools/send.js +2 -2
- package/tools/spawn.js +8 -5
- package/tools/status.js +11 -4
- package/tools/teardown.js +2 -3
- package/tools/test.js +2 -2
- package/types/index.d.ts +29 -13
- package/ui-bundle/README.md +37 -3
- package/ui-bundle/client.cards.js +356 -0
- package/ui-bundle/client.denied.js +142 -0
- package/ui-bundle/client.dock.js +333 -0
- package/ui-bundle/client.helpers.js +271 -0
- package/ui-bundle/client.js +79 -1747
- package/ui-bundle/client.locales.js +247 -0
- package/ui-bundle/client.mode.js +206 -0
- package/ui-bundle/client.overlay.js +64 -0
- package/ui-bundle/client.styles.js +151 -0
- package/ui-bundle/client.toolview.js +82 -0
- package/ui-bundle/package.json +1 -0
- package/lib/persistence.js +0 -356
- package/lib/presets.js +0 -35
- package/lib/store.js +0 -133
- /package/{lib → adapters}/stateFile.js +0 -0
- /package/{lib → app}/briefing.js +0 -0
- /package/{lib → app}/spawn-support.js +0 -0
- /package/{lib → host}/compatibility.js +0 -0
- /package/{lib → host}/config.js +0 -0
- /package/{lib → host}/modeState.js +0 -0
package/README.md
CHANGED
|
@@ -127,19 +127,26 @@ tower_teardown repoRoot=D:\work\repo
|
|
|
127
127
|
|
|
128
128
|
## 组件模型
|
|
129
129
|
|
|
130
|
-
本 bundle 采用
|
|
131
|
-
`
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
review
|
|
130
|
+
本 bundle 采用 **强制 host 锚点 + 可单独启停的可选行**(#121):`cordis.patch.yml` 插入顶层
|
|
131
|
+
`tower` group(挂载 Host 插件与强制的 `preset-tower-worker`),随后是可选组件 `tower-skills`、
|
|
132
|
+
`tower-batch`、`tower-import`、`tower-leases`、`tower-tests`、`tower-hmr`(随包关闭)与
|
|
133
|
+
`preset-tower-reviewer`。在插件页关闭某一行,只会移除该能力;模式、规划工具、`tower_status`
|
|
134
|
+
与其余工具继续工作。
|
|
135
|
+
|
|
136
|
+
进入 Tower 模式与 `tower_plan` 前会校验必需的 preset。worker preset 是强制依赖;reviewer
|
|
137
|
+
preset 只在 `review.requireReview` 为 true 时必需,因此审查可选时允许关闭 reviewer 行,强制审查
|
|
138
|
+
开启时会以带解释的 `preset-missing` 锁定。`tower-tests` 关闭且 `gates.requireTests:true` 时同样
|
|
139
|
+
拒绝。`tower_doctor` 与 `tower_recover` 不是组件、也没有配置键:任何配置都会注册它们(#122)。
|
|
140
|
+
|
|
141
|
+
原则 11([PRINCIPLES.md](PRINCIPLES.md))与
|
|
142
|
+
[ADR 0005](docs/adr/0005-component-surface.md) 要求:只有关闭后仍不破坏其余能力的 capability
|
|
143
|
+
才能成为组件;host、健康检查、恢复通道、审查契约与合并门禁永远不是开关。逐键答案见生成的
|
|
144
|
+
[组件表面](docs/reference/component-surface.md),由 `npm run docs:check:components` 强制。
|
|
138
145
|
|
|
139
146
|
## 配置
|
|
140
147
|
|
|
141
148
|
```yaml
|
|
142
|
-
- id: tower
|
|
149
|
+
- id: tower-host
|
|
143
150
|
name: 'dsh-tower'
|
|
144
151
|
config:
|
|
145
152
|
section: '(可选,兼容别名)覆盖 Tower 模式系统提示文案'
|
|
@@ -164,18 +171,18 @@ review/merge 阶段死锁。
|
|
|
164
171
|
- 代码中 `mode.allowAgentControl` 默认 `true`;随包 `cordis.patch.yml` 也显式设为 `true`:模型可在用户意图/任务状态明确时自行进出,但必须给出理由;设为 `false` 时只有人类能切换。随包 patch 还默认开启 `mode.workspaceLock`(单活塔)、`send.interruptDefault`、`init.autoGitInit`,并把 `spawn.staleMs` 设为 15s。
|
|
165
172
|
- `/tower base <branch>` 可设置会话级 init base 偏好;`/tower on` 会清除活跃 plan mode(`mode.planModePolicy:"refuse"` 则拒绝进入),保证 plan/tower 互斥。
|
|
166
173
|
- 仓库级配置:在 `<git-common-dir>/dsh-tower/config.json`(通常是 `.git/dsh-tower/config.json`)放入同样的 JSON 结构,可覆盖 `review`/`merge`/`worktrees`/`spawn`;优先级为代码默认 < profile < 仓库配置 < 工具参数。`mode.*` 属于会话级,只在 profile 生效。
|
|
167
|
-
- 所有键与默认值见 [docs/reference/config.md](docs/reference/config.md)
|
|
174
|
+
- 所有键与默认值见 [docs/reference/config.md](docs/reference/config.md);未知键(顶层与分组内)都会被拒绝,防止拼写错误静默失效。工具错误码见 [docs/reference/errors.md](docs/reference/errors.md)。
|
|
168
175
|
|
|
169
|
-
## 工具(
|
|
176
|
+
## 工具(29 个:22 个核心 + 7 个可选)
|
|
170
177
|
|
|
171
178
|
`tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_diff` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_interrupt` · `tower_finding` · `tower_findings` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode` · `tower_doctor` · `tower_recover` · `tower_test` · `tower_batch` · `tower_resource` · `tower_import_legacy` · `tower_legacy_map`
|
|
172
179
|
|
|
173
|
-
|
|
180
|
+
上面列出的是 22 个核心工具加 5 个由组件行拥有的可选工具。`tower_control` 是第 6 个可选工具,默认注册(`allowAgentControl:true`);设为 `false` 可禁用。`tower_reload` 是第 7 个,仅在 `tower-hmr` 组件行开启时注册(随包关闭),无 HMR 服务调用会返回 `reload-unavailable`(因此最多 29 个工具:22 个核心 + 7 个可选)。`tower_doctor` 与 `tower_recover` 属于核心:任何配置都会注册它们(#122)。mission 级工具同时接受 `id` 作为 `missionId` 的别名;`task_done`/`taskDone` 等 snake/camel 写法均可。
|
|
174
181
|
|
|
175
182
|
## 安全与约束
|
|
176
183
|
|
|
177
184
|
- **门禁不全绿不合并。** `tower_preflight` 是只读检查,返回稳定的 blocker code;存在 blocker 时 `tower_merge` 拒绝合并。
|
|
178
|
-
- **审查绑定提交。** 开启 `review.requireReview` 时,审查后分支 tip 变化会报 `tip-moved`,必须重新审查;reviewer 使用只读 preset
|
|
185
|
+
- **审查绑定提交。** 开启 `review.requireReview` 时,审查后分支 tip 变化会报 `tip-moved`,必须重新审查;reviewer 使用只读 preset,若在审查期间改动分支,提交审查会被拒绝。非 clean 的一轮审查会让 mission 回到 active,此后其他 route 仍可为同一 reviewed tip 提交结论并追加到同一轮;依赖为 `completed` 的 survey 视为已满足(build 依赖仍需 merged)。
|
|
179
186
|
- **scope 强制。** mission 只能修改其 scope glob 匹配的文件,越界会以 `out-of-scope` 阻止合并。
|
|
180
187
|
- **worktree 归属。** 脏工作树、运行中的 worker、已关闭 mission 的分支都会阻止合并或 teardown。
|
|
181
188
|
- **goal 隔离。** 进入 Tower 模式会暂停活跃 goal 并记录;退出不会自动恢复,需要你自行恢复。
|
|
@@ -199,8 +206,8 @@ worker 与 reviewer 是使用内置 `tower-worker` preset 的普通 DSH 子代
|
|
|
199
206
|
|
|
200
207
|
| 路径 | 内容 |
|
|
201
208
|
|---|---|
|
|
202
|
-
| `package.json`、`cordis.patch.yml` | bundle 清单与 loader patch
|
|
203
|
-
| `index.js`、`
|
|
209
|
+
| `package.json`、`cordis.patch.yml` | bundle 清单与 loader patch(强制 `tower` host group + 可选能力行) |
|
|
210
|
+
| `index.js`、`host/`、`adapters/`、`app/`、`domain/`、`ports/`、`tools/`、`worker.js` | Host 入口;`domain/` 纯核心;`ports/` 契约;`adapters/` 唯一 I/O;`app/` 用例;`host/` 组合根与会话胶水;`tools/` 每工具一个 handler;worker preset 策略 |
|
|
204
211
|
| `locale/`、`icon.svg` | 本地化与图标 |
|
|
205
212
|
| `tests/` | 纯函数、协议 e2e、插件级测试;可选的真实 Web 运行时脚本 |
|
|
206
213
|
| `ui-bundle/` | 可选 Client 小挂件(Tower 工具卡片、Tower·on 状态 chip、模式感知的 disabled 行、dock 摘要、临时 overlay 状态条),默认不安装 |
|
|
@@ -212,7 +219,7 @@ worker 与 reviewer 是使用内置 `tower-worker` preset 的普通 DSH 子代
|
|
|
212
219
|
npm test # node --test tests/*.test.mjs
|
|
213
220
|
```
|
|
214
221
|
|
|
215
|
-
热重载开发:`npm run dev:hmr` 把本仓库加入当前 profile 的 HMR watch root(需重启 DSH 一次),之后编辑 `
|
|
222
|
+
热重载开发:`npm run dev:hmr` 把本仓库加入当前 profile 的 HMR watch root(需重启 DSH 一次),之后编辑 `host/`、`adapters/`、`app/`、`domain/` 代码可用 `/tower reload` 或自动 watch 生效;详见 [docs/guide/hot-reload.md](docs/guide/hot-reload.md)。
|
|
216
223
|
|
|
217
224
|
离线套件不需要 DSH 进程,只在系统临时目录创建一次性 Git 仓库。隔离 Web 运行时检查、模型驱动验收和会话诊断脚本见 `tests/README.md`。
|
|
218
225
|
|
|
@@ -222,18 +229,21 @@ npm test # node --test tests/*.test.mjs
|
|
|
222
229
|
|
|
223
230
|
| Job | 声明 | 证据 |
|
|
224
231
|
|---|---|---|
|
|
225
|
-
| `test (22)`、`test (24)`(Ubuntu) | 离线套件、文档一致性、生成文档、发布文件清单、架构、类型与 domain 纯度全部成立 | `npm test`、`npm run docs:check
|
|
232
|
+
| `test (22)`、`test (24)`(Ubuntu) | 离线套件、文档一致性、生成文档、发布文件清单、架构、类型与 domain 纯度全部成立 | `npm test`、`npm run docs:check`、五个 `docs:check:generated*`(含生成的类型词汇表)、`pack:check`、`architecture:check`、`types:coverage`、`types:strict:check`、`types:check`、`domain:check` |
|
|
226
233
|
| `test (22, windows)`(`windows-latest`,非必需检查) | 同一套离线套件与离线 gates 在真实 Windows 文件系统上成立;路径大小写、`pwsh` shell、rename/unlink 重试都不是只在 Linux 上被假设 | `npm test` + 与 Ubuntu 相同的离线 gates(不跑 release/coverage) |
|
|
227
234
|
| `test` 的 `Coverage (Node 22)` 步骤 | 覆盖率在 CI 中真实测量(只报告,不设阈值、不加徽章) | `npm run test:coverage` |
|
|
228
235
|
| `test` 的 `Release check`(Node 22)步骤 | tag 是一种声明:版本已越过上一个版本 tag、推送的 tag 是 `v<version>`、CHANGELOG 带有发布内容 | `npm run release:check` |
|
|
229
236
|
| `mount`(Node 22) | 打出的 tarball 经 plugin CLI 装进一次性 profile 后,真实 loader 挂载并注册了 bundle 声称的表面 | `npm run smoke:mount` |
|
|
230
237
|
| `mount-fixtures`(Node 22,非必需检查) | mount smoke 仍会因正确的种子失败而变红(改名一个工具 id、删除 skills 段),三次运行共用一次缓存的 host 安装 | `npm run smoke:fixtures -- --host-dir <缓存的 host>` |
|
|
238
|
+
| `live (<固定 host 版本>)`(nightly/手动,非必需检查) | 浏览器 live suite 在固定 host 版本矩阵上仍能驱动真实 Web 运行时;push/PR 只做无浏览器的环境与解析检查 | nightly 跑 `npm run test:live -- --script nightly`;push 跑 `npm run test:live -- --check` |
|
|
231
239
|
|
|
232
240
|
`test` 的三条 leg 在 job 内用 `matrix.name` 固定各自的 context 字符串:`test (22)`、`test (24)` 与新增的 `test (22, windows)`。前两条是 `main` 的必需检查,名字逐字节不变;把 `os` 直接塞进 matrix 会把它们改名成 `test (22, ubuntu-latest)`,保护规则将永远等不到该 context,所以矩阵用显式 `include` + `name`。Windows leg 只跑 Node 22 和离线套件/离线 gates(无浏览器、无 live suite、无 release/coverage),与现有 job 并行,不延长关键路径。它目前不是必需 context:让它变绿是本 issue 的验收,把它加入保护设置是 #94 的人工步骤。
|
|
233
241
|
|
|
242
|
+
live suite 需要下载浏览器并真实启动 host,因此移出 push/PR,改为 nightly `schedule`(另支持 `workflow_dispatch`),在固定 host 版本矩阵上运行;它的输出第一行打印解析后的 `DSH_HOME` 与 host 版本。push 上只保留 `--check`(环境 + Playwright 解析,无浏览器)。Playwright 由 `tests/live/package-lock.json` 固定,root 的 `npm ci` 不下载浏览器。
|
|
243
|
+
|
|
234
244
|
`tests/platform.test.mjs` 用注入的 `platform`/`rename`/`unlink` 在任意 OS 上同时断言 win32 与 POSIX 两条分支;唯一需要真实 Windows 的“rename 覆盖被打开的目标文件”用例在 Linux 上以 `# SKIP` 计入 TAP(`tests 11`、`skipped 1`),而不是静默消失。macOS 不单设 runner:它与 Linux 走同一条 POSIX 分支,这是 #86 的非目标。
|
|
235
245
|
|
|
236
|
-
`mount` 断言一次性 profile 的**已加载表面**,而不是 `cordis.patch.yml`
|
|
246
|
+
`mount` 断言一次性 profile 的**已加载表面**,而不是 `cordis.patch.yml` 的文本:随包 profile 加载 28 个 `tower_*` 工具(27 个 `tools/*.js` 模块 + `tower_mode` / `tower_control`,减去因 `tower-hmr` 随包关闭而不注册的 `tower_reload`;所有可选能力行全开时为 29 个)、3 个内置 skill、`tower-worker` / `tower-reviewer` 两个 preset、`/tower` 命令、一个顶层 `tower` host group 以及可选的顶层能力行(`tower-hmr` 随包关闭)。它不调用模型、不打开浏览器。在维护者的 Windows 机器上实测:host 冷装(含安装)约 100 秒,host 已缓存约 85 秒;CI 中该步骤上限为 3 分钟(`timeout-minutes: 3`),`mount` job 上限 5 分钟。红叉会打印解析后的 profile 路径、host build、已加载计数与每一条未满足的声明。
|
|
237
247
|
|
|
238
248
|
host build 只固定在一个地方:`scripts/mount-smoke/host.json`,`COMPATIBILITY.md` 最新一行由单元测试强制与它一致,发布时不再各写一遍。`npm run smoke:fixtures` 用两种种子失败(改名一个工具 id、删除 skills 段)证明 smoke 会以正确原因变红;CI 中它作为非必需的 `mount-fixtures` job 运行,control 与两个种子通过 `--host-dir` 共用一次缓存的 host 安装(本机热跑约 2 分钟)。
|
|
239
249
|
|
package/SECURITY.md
CHANGED
|
@@ -42,6 +42,12 @@ gh api repos/louifinn/dsh-tower/branches/main/protection \
|
|
|
42
42
|
|
|
43
43
|
Please do **not** publish exploit details in a public issue. Open a minimal issue titled `security: request private contact` describing only the impact category (for example “merge gate bypass”), and a maintainer will arrange a private channel. Include the affected version and, if possible, a minimal reproduction in the private follow-up.
|
|
44
44
|
|
|
45
|
+
A security fix that shipped and then stopped working is a regression, not an
|
|
46
|
+
ordinary bug. Use the six-field record in
|
|
47
|
+
[docs/operations/incident.md](docs/operations/incident.md) (including the
|
|
48
|
+
`Regression test:` path) once the private report is resolved; the public closure
|
|
49
|
+
still carries no exploit detail.
|
|
50
|
+
|
|
45
51
|
## Supported versions
|
|
46
52
|
|
|
47
53
|
Security fixes target the latest released `2.x` line (currently `2.0.4`). Older pre-release snapshots
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// mission id, so a crash between the two files is recoverable on the next
|
|
13
13
|
// mutation instead of losing a mission.
|
|
14
14
|
import path from 'node:path'
|
|
15
|
-
import { fsp } from '
|
|
15
|
+
import { fsp } from './store-fs.js'
|
|
16
16
|
import {
|
|
17
17
|
ARCHIVE_VERSION,
|
|
18
18
|
archiveDocumentError,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// stat failure). "Unknown" is deliberately not "case-sensitive": init
|
|
14
14
|
// keeps working and `tower_doctor` reports the safe default.
|
|
15
15
|
import path from 'node:path'
|
|
16
|
-
import { fsp } from '
|
|
16
|
+
import { fsp } from './store-fs.js'
|
|
17
17
|
|
|
18
18
|
/** Prefix is public so tests and support code can recognise a leaked probe. */
|
|
19
19
|
export const CASE_PROBE_PREFIX = '.tower-case-probe-'
|
package/adapters/default.js
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
|
-
// Default composition root for Tower
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// Default composition root for the Tower ports (#50, #69).
|
|
2
|
+
//
|
|
3
|
+
// This module is the one place where the concrete adapters (node:fs,
|
|
4
|
+
// node:child_process) are turned into the plain deps object the app layer
|
|
5
|
+
// takes. `createDefaultDeps()` is called once by the host entry (index.js); the
|
|
6
|
+
// app never imports an adapter. Tests and embedders use the memoised
|
|
7
|
+
// `defaultDeps` (or host/tower.js) so the process has exactly one adapter set.
|
|
8
|
+
import crypto from 'node:crypto'
|
|
9
|
+
import * as archive from './archive.js'
|
|
10
|
+
import * as caseSensitivity from './caseSensitivity.js'
|
|
11
|
+
import * as config from '../host/config.js'
|
|
12
|
+
import { loadStateFile } from './stateFile.js'
|
|
13
|
+
import * as ownership from './worktreeOwnership.js'
|
|
14
|
+
import { createStorePort } from './store-fs.js'
|
|
15
|
+
import { createVcsPort } from './vcs-git.js'
|
|
16
|
+
import { NOOP_EVENT_PORT } from '../ports/events.js'
|
|
5
17
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Assemble a dependency object implementing every port in ports/.
|
|
20
|
+
* @param {Partial<Record<'store'|'vcs'|'config'|'state'|'archive'|'ownership'|'caseSensitivity'|'clock'|'ids'|'events', any>>} [overrides]
|
|
21
|
+
* @returns {Record<string, any>}
|
|
22
|
+
*/
|
|
23
|
+
export function createDefaultDeps(overrides = {}) {
|
|
24
|
+
const store = createStorePort()
|
|
25
|
+
return {
|
|
26
|
+
store,
|
|
27
|
+
vcs: createVcsPort(),
|
|
28
|
+
config: {
|
|
29
|
+
runtimeConfig: config.runtimeConfig,
|
|
30
|
+
resolveRepoConfig: config.resolveRepoConfig,
|
|
31
|
+
},
|
|
32
|
+
state: { loadStateFile },
|
|
33
|
+
archive: {
|
|
34
|
+
readIndex: archive.readArchiveIndex,
|
|
35
|
+
readEntry: archive.readArchivedEntry,
|
|
36
|
+
writeEntries: archive.writeArchiveEntries,
|
|
37
|
+
},
|
|
38
|
+
ownership: {
|
|
39
|
+
assertOwnership: ownership.assertOwnership,
|
|
40
|
+
canonicalPath: ownership.canonicalPath,
|
|
41
|
+
},
|
|
42
|
+
caseSensitivity: { detect: caseSensitivity.detectCaseSensitivity },
|
|
43
|
+
clock: { now: () => Date.now() },
|
|
44
|
+
ids: { uuid: () => crypto.randomUUID(), shortHash: store.shortHash },
|
|
45
|
+
// The host entry replaces this with the Cordis emitter; default deps (and
|
|
46
|
+
// tests/embedders) keep the no-op channel so events never fail a tool.
|
|
47
|
+
events: NOOP_EVENT_PORT,
|
|
48
|
+
...overrides,
|
|
49
|
+
}
|
|
12
50
|
}
|
|
51
|
+
|
|
52
|
+
/** The single process-wide default adapter set. */
|
|
53
|
+
export const defaultDeps = createDefaultDeps()
|
package/{lib → adapters}/git.js
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TowerToolError } from '../domain/errors.js'
|
|
2
2
|
// Minimal git port: array arguments only, bounded output, no shell.
|
|
3
|
-
import { execFile } from '
|
|
3
|
+
import { execFile } from './vcs-git.js'
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
|
|
6
6
|
const GIT_TIMEOUT_MS = 15000
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// Fail-closed protocol: a held, expired, or token-mismatched lease is reported,
|
|
12
12
|
// never silently taken over. Only the token holder may release a lease, and
|
|
13
13
|
// releasing an expired lease requires an explicit `force: true`.
|
|
14
|
-
import { fsp } from '
|
|
14
|
+
import { fsp } from './store-fs.js'
|
|
15
15
|
import path from 'node:path'
|
|
16
16
|
import crypto from 'node:crypto'
|
|
17
17
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
//
|
|
10
10
|
// `validateLegacyMap` is the audit-only mapping check: a map is a record that
|
|
11
11
|
// legacy id X corresponds to DSH mission Y. It never adopts or restores work.
|
|
12
|
-
import { fsp } from '
|
|
12
|
+
import { fsp } from './store-fs.js'
|
|
13
13
|
import path from 'node:path'
|
|
14
14
|
import crypto from 'node:crypto'
|
|
15
15
|
|