sillyspec 3.15.2 → 3.16.1
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/.husky/pre-push +13 -0
- package/README.md +1 -1
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -0
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -0
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -0
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -0
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +193 -0
- package/docs/sillyspec/file-lifecycle.md +106 -1167
- package/docs/worktree-isolation.md +57 -2
- package/package.json +5 -1
- package/src/db.js +17 -0
- package/src/hooks/worktree-guard.js +166 -47
- package/src/index.js +44 -3
- package/src/progress.js +79 -0
- package/src/run.js +447 -55
- package/src/stage-contract.js +347 -0
- package/src/stages/archive.js +6 -10
- package/src/stages/brainstorm.js +4 -1
- package/src/stages/doctor.js +43 -2
- package/src/stages/execute.js +32 -5
- package/src/stages/propose.js +4 -1
- package/src/stages/quick.js +3 -3
- package/src/stages/scan.js +18 -18
- package/src/workflow.js +6 -2
- package/src/worktree-apply.js +14 -0
- package/src/worktree.js +201 -11
- package/test/check-syntax.mjs +26 -0
- package/test/run-tests.mjs +20 -0
- package/test/scan-paths.test.mjs +68 -0
- package/test/stage-contract.test.mjs +128 -0
- package/test/stage-definitions.test.mjs +43 -0
- package/test/worktree-guard.test.mjs +78 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
author: qinyi
|
|
3
|
+
created_at: 2026-06-04 16:25:42
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Worktree 与 Hook 门禁
|
|
7
|
+
|
|
8
|
+
## 命令入口
|
|
9
|
+
|
|
10
|
+
`src/index.js` 暴露:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
sillyspec worktree create <change-name> [--base <branch>]
|
|
14
|
+
sillyspec worktree apply <change-name> [--check-only]
|
|
15
|
+
sillyspec worktree list
|
|
16
|
+
sillyspec worktree cleanup <change-name>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
实现分别调用:
|
|
20
|
+
|
|
21
|
+
- `WorktreeManager.create()`
|
|
22
|
+
- `applyWorktree()`
|
|
23
|
+
- `WorktreeManager.list()`
|
|
24
|
+
- `WorktreeManager.cleanup()`
|
|
25
|
+
|
|
26
|
+
## `create`
|
|
27
|
+
|
|
28
|
+
默认路径:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
.sillyspec/.runtime/worktrees/<change-name>/
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
默认分支:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
sillyspec/<change-name>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
关键校验与分支:
|
|
41
|
+
|
|
42
|
+
1. `changeName` 不能为空,不能包含 `..`、`/`、`\`。
|
|
43
|
+
2. 如果当前目录是 git submodule,直接报错。
|
|
44
|
+
3. 如果当前目录已经是 linked worktree,创建 `native-worktree` meta,复用当前目录。
|
|
45
|
+
4. 普通主工作区必须先确认 `.sillyspec/.runtime/worktrees` 被 `.gitignore` 忽略,否则报错。
|
|
46
|
+
5. 如果 worktree 目录存在但没有 `meta.json`,视为幽灵目录并自动删除。
|
|
47
|
+
6. 如果目标 branch 已存在,报错。
|
|
48
|
+
7. 默认 base 是当前 `HEAD`;传 `--base` 时使用指定 ref。
|
|
49
|
+
8. `git worktree add` 失败时:
|
|
50
|
+
- 如果 git 版本低于 2.15 或不可用,报错。
|
|
51
|
+
- 其他失败降级为 `in-place-fallback`,在主工作区记录 meta。
|
|
52
|
+
9. 创建普通 worktree 后,会 best-effort `fetch origin` 并尝试 fast-forward 到默认远端分支。
|
|
53
|
+
10. 主工作区已有 staged/unstaged/untracked 变更时,会 overlay 到 worktree,并创建 baseline checkpoint commit。
|
|
54
|
+
|
|
55
|
+
## `meta.json`
|
|
56
|
+
|
|
57
|
+
普通 worktree 的 `meta.json` 位于 worktree 目录内:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
.sillyspec/.runtime/worktrees/<change>/meta.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`native-worktree` 和 `in-place-fallback` 下,meta 仍写到 `.sillyspec/.runtime/worktrees/<change>/meta.json`,其中 `worktreePath` 可能指向当前工作目录。
|
|
64
|
+
|
|
65
|
+
主要字段:
|
|
66
|
+
|
|
67
|
+
| 字段 | 说明 |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `changeName` | 变更名 |
|
|
70
|
+
| `branch` | worktree 分支 |
|
|
71
|
+
| `baseBranch` | 基准分支或 ref |
|
|
72
|
+
| `baseHash` | 创建时基准 commit |
|
|
73
|
+
| `actualBaseHash` | worktree 当前 HEAD |
|
|
74
|
+
| `createdAt` | 创建时间 |
|
|
75
|
+
| `worktreePath` | 实际执行目录 |
|
|
76
|
+
| `mode` | `worktree` / `native-worktree` / `in-place-fallback` |
|
|
77
|
+
| `baselineFiles` | 从主工作区 overlay 的未提交文件 |
|
|
78
|
+
| `baselineCommit` | baseline checkpoint commit |
|
|
79
|
+
| `baselineHash` | execute 前主工作区 dirty baseline hash |
|
|
80
|
+
|
|
81
|
+
## `apply`
|
|
82
|
+
|
|
83
|
+
`applyWorktree(changeName, { checkOnly })` 的真实流程:
|
|
84
|
+
|
|
85
|
+
1. 读取 `meta.json`。
|
|
86
|
+
2. diff base 使用 `baselineCommit || baseHash`。
|
|
87
|
+
3. 收集 tracked diff 和 untracked 新文件。
|
|
88
|
+
4. 从 `.sillyspec/changes/<change>/design.md` 解析“文件变更清单”作为 allow list。
|
|
89
|
+
5. 如果 allow list 非空,要求 changed files 都在清单内。
|
|
90
|
+
6. 如果 meta 有 `baselineHash`,重新计算主工作区 dirty hash;不同则拒绝 apply。
|
|
91
|
+
7. 检查主工作区和 apply 文件有无未提交冲突。
|
|
92
|
+
8. 比较主工作区 `HEAD` 与 worktree `baseHash` 的目标文件 blob。
|
|
93
|
+
9. `--check-only` 到这里返回。
|
|
94
|
+
10. 生成临时 patch。
|
|
95
|
+
11. 在主工作区执行 `git apply --check`。
|
|
96
|
+
12. 执行 `git apply --3way`。
|
|
97
|
+
13. 成功后自动调用 `WorktreeManager.cleanup()`。
|
|
98
|
+
|
|
99
|
+
无变更时,如果不是 check-only,也会 cleanup。
|
|
100
|
+
|
|
101
|
+
## `cleanup`
|
|
102
|
+
|
|
103
|
+
`cleanup(changeName, { force })`:
|
|
104
|
+
|
|
105
|
+
| mode | 非 force 行为 |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `worktree` | 尝试 `git worktree remove --force`,删除目录,删除分支,删除 meta 目录 |
|
|
108
|
+
| `native-worktree` | 抛错,避免删除用户自己的 worktree |
|
|
109
|
+
| `in-place-fallback` | 返回 `skipped` |
|
|
110
|
+
| 无 meta 且目录不存在 | 返回 `skipped` |
|
|
111
|
+
|
|
112
|
+
如果 `git worktree remove` 失败但目录可删,结果是 `force-cleaned`。
|
|
113
|
+
|
|
114
|
+
## execute 阶段
|
|
115
|
+
|
|
116
|
+
`execute.js` 的固定前缀第 3 步是“创建 worktree”,prompt 要求运行:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
sillyspec worktree create <change-name>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
后续 Wave prompt 要求把子代理 cwd 设置为 worktree 路径。完成确认 step 根据 mode 分别处理:
|
|
123
|
+
|
|
124
|
+
- `worktree`:check-only,用户确认后 apply,再 cleanup。
|
|
125
|
+
- `native-worktree`:可以 apply,但不要 cleanup。
|
|
126
|
+
- `in-place-fallback`:跳过 apply/cleanup。
|
|
127
|
+
- 无 worktree:只展示 diff 摘要。
|
|
128
|
+
|
|
129
|
+
注意:`buildExecuteSteps()` 有 `noWorktree` 参数,但当前 `runCommand()` 没有解析 `--no-worktree` flag,CLI help 也没有列出该 flag。文档不要把 `--no-worktree` 写成已接通的公开流程。
|
|
130
|
+
|
|
131
|
+
## quick 阶段
|
|
132
|
+
|
|
133
|
+
quick 当前不创建 worktree。
|
|
134
|
+
|
|
135
|
+
`quick.js` 第 2 步明确写的是“直接在主工作区实现任务”。`worktree-guard.js` 在 stage 为 `quick` 时,对 Write/Edit/MultiEdit 直接放行;Bash 仅拦截危险命令。quick 作为辅助阶段完成后,`run.js` 会重置 quick 步骤并清空 `currentStage`,从而删除 gate 状态。
|
|
136
|
+
|
|
137
|
+
因此旧文档中“quick 创建 worktree/meta.json”的描述不符合当前代码。
|
|
138
|
+
|
|
139
|
+
## Hook 门禁
|
|
140
|
+
|
|
141
|
+
入口:`src/hooks/claude-pre-tool-use.cjs`
|
|
142
|
+
|
|
143
|
+
输入:Claude Code PreToolUse hook 的 JSON。它只映射这些工具:
|
|
144
|
+
|
|
145
|
+
- `Write`
|
|
146
|
+
- `Edit`
|
|
147
|
+
- `MultiEdit`
|
|
148
|
+
- `Bash`
|
|
149
|
+
|
|
150
|
+
实际判断:`src/hooks/worktree-guard.js`
|
|
151
|
+
|
|
152
|
+
### 文件白名单
|
|
153
|
+
|
|
154
|
+
以下写入直接放行:
|
|
155
|
+
|
|
156
|
+
- 路径中包含 `.sillyspec`,但 `.sillyspec/.runtime/worktrees/` 例外
|
|
157
|
+
- 路径中包含 `.git`
|
|
158
|
+
- 扩展名为 `.md`
|
|
159
|
+
- 文件名为 `package.json`、`tsconfig.json`、`local.yaml`、`local.yml`
|
|
160
|
+
|
|
161
|
+
`.sillyspec/.runtime/worktrees/` 下的写入不会仅因路径包含 `.sillyspec` 而放行;它必须命中当前 gate 中 active change 对应的 `meta.json.worktreePath`。
|
|
162
|
+
|
|
163
|
+
### 阶段门禁
|
|
164
|
+
|
|
165
|
+
阶段读取顺序:
|
|
166
|
+
|
|
167
|
+
1. `.sillyspec/.runtime/gate-status.json`
|
|
168
|
+
2. `sqlite3` CLI 查询 `.sillyspec/.runtime/sillyspec.db`
|
|
169
|
+
|
|
170
|
+
只有 `execute` 和 `quick` 被视为允许源码写入的阶段。
|
|
171
|
+
|
|
172
|
+
### execute 写入
|
|
173
|
+
|
|
174
|
+
execute 阶段的源码写入必须位于已登记 worktree 内:
|
|
175
|
+
|
|
176
|
+
1. hook 读取 `.sillyspec/.runtime/gate-status.json` 或 SQLite,得到当前 active changes。
|
|
177
|
+
2. 对每个 active change 读取 `.sillyspec/.runtime/worktrees/<change>/meta.json`。
|
|
178
|
+
3. 只有目标路径位于 `meta.json.worktreePath` 内时才允许写入。
|
|
179
|
+
|
|
180
|
+
这意味着随便构造一个包含 `.sillyspec/.runtime/worktrees/` 字符串的路径不会被放行。主工作区写源码仍会被拦截。
|
|
181
|
+
|
|
182
|
+
### quick 写入
|
|
183
|
+
|
|
184
|
+
quick 阶段写文件直接放行,不要求 worktree。
|
|
185
|
+
|
|
186
|
+
### Bash 命令
|
|
187
|
+
|
|
188
|
+
- 已登记 worktree 内 cwd:全部 Bash 放行。
|
|
189
|
+
- 非 execute/quick:只读白名单放行。
|
|
190
|
+
- quick:危险黑名单拦截,其余放行。
|
|
191
|
+
- execute 主工作区:危险黑名单拦截;只读白名单放行;其他不确定命令当前放行。
|
|
192
|
+
|
|
193
|
+
`worktree-guard.js` 的本地扩展白名单优先读取 `.sillyspec/local.yaml` / `.sillyspec/local.yml`,并兼容项目根 `local.yaml` / `local.yml`。
|