sillyspec 3.20.2 → 3.20.4
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/.claude/skills/sillyspec-archive/SKILL.md +21 -21
- package/.claude/skills/sillyspec-auto/SKILL.md +83 -83
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +44 -44
- package/.claude/skills/sillyspec-commit/SKILL.md +106 -106
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -45
- package/.claude/skills/sillyspec-doctor/SKILL.md +31 -31
- package/.claude/skills/sillyspec-execute/SKILL.md +30 -30
- package/.claude/skills/sillyspec-explore/SKILL.md +109 -109
- package/.claude/skills/sillyspec-knowledge/SKILL.md +269 -269
- package/.claude/skills/sillyspec-plan/SKILL.md +21 -21
- package/.claude/skills/sillyspec-propose/SKILL.md +21 -21
- package/.claude/skills/sillyspec-quick/SKILL.md +21 -21
- package/.claude/skills/sillyspec-resume/SKILL.md +68 -68
- package/.claude/skills/sillyspec-scan/SKILL.md +21 -21
- package/.claude/skills/sillyspec-state/SKILL.md +54 -54
- package/.claude/skills/sillyspec-status/SKILL.md +21 -21
- package/.claude/skills/sillyspec-verify/SKILL.md +21 -21
- package/.claude/skills/sillyspec-workspace/SKILL.md +157 -157
- package/.husky/pre-push +13 -13
- package/CLAUDE.md +18 -18
- package/README.md +198 -188
- package/SKILL.md +90 -91
- package/bin/sillyspec.js +2 -2
- package/docs/brainstorm-plan-contract.md +64 -64
- package/docs/plan-execute-contract.md +123 -123
- package/docs/platform-scan-protocol.md +298 -298
- package/docs/revision-mode.md +115 -115
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -99
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -218
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -167
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -148
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +211 -193
- package/docs/sillyspec/file-lifecycle.md +125 -125
- package/docs/workflow-contract-regression.md +106 -106
- package/docs/worktree-isolation.md +252 -252
- package/package.json +40 -40
- package/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -7446
- package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -1
- package/packages/dashboard/dist/index.html +16 -16
- package/packages/dashboard/index.html +15 -15
- package/packages/dashboard/package-lock.json +2384 -2384
- package/packages/dashboard/package.json +25 -25
- package/packages/dashboard/server/executor.js +86 -86
- package/packages/dashboard/server/index.js +588 -588
- package/packages/dashboard/server/parser.js +526 -526
- package/packages/dashboard/server/watcher.js +344 -344
- package/packages/dashboard/src/App.vue +558 -558
- package/packages/dashboard/src/components/ActionBar.vue +93 -93
- package/packages/dashboard/src/components/CommandPalette.vue +96 -96
- package/packages/dashboard/src/components/DetailPanel.vue +137 -137
- package/packages/dashboard/src/components/LogStream.vue +65 -65
- package/packages/dashboard/src/components/PipelineStage.vue +95 -95
- package/packages/dashboard/src/components/PipelineView.vue +156 -156
- package/packages/dashboard/src/components/ProjectList.vue +210 -210
- package/packages/dashboard/src/components/StageBadge.vue +67 -67
- package/packages/dashboard/src/components/StepCard.vue +94 -94
- package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +61 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +43 -43
- package/packages/dashboard/src/composables/useDashboard.js +170 -170
- package/packages/dashboard/src/composables/useKeyboard.js +119 -119
- package/packages/dashboard/src/composables/useWebSocket.js +129 -129
- package/packages/dashboard/src/main.js +8 -8
- package/packages/dashboard/src/style.css +132 -132
- package/packages/dashboard/vite.config.js +18 -18
- package/src/brainstorm-postcheck.js +158 -158
- package/src/change-list.js +52 -52
- package/src/change-risk-profile.js +352 -352
- package/src/classify-change.js +73 -73
- package/src/constants.js +70 -70
- package/src/contract-matrix.js +278 -278
- package/src/db.js +201 -201
- package/src/endpoint-extractor.js +315 -315
- package/src/hooks/claude-pre-tool-use.cjs +125 -125
- package/src/hooks/worktree-guard.js +653 -653
- package/src/index.js +922 -900
- package/src/init.js +431 -431
- package/src/knowledge-match.js +130 -130
- package/src/migrate.js +117 -117
- package/src/modules.js +482 -482
- package/src/progress.js +1734 -1734
- package/src/run.js +3465 -3358
- package/src/scan-postcheck.js +387 -383
- package/src/setup.js +398 -398
- package/src/stage-contract.js +700 -700
- package/src/stages/archive.js +160 -160
- package/src/stages/brainstorm-auto.js +229 -229
- package/src/stages/brainstorm.js +645 -645
- package/src/stages/doctor.js +365 -365
- package/src/stages/execute.js +625 -625
- package/src/stages/explore.js +34 -34
- package/src/stages/index.js +29 -29
- package/src/stages/knowledge.js +498 -498
- package/src/stages/plan-postcheck.js +511 -513
- package/src/stages/plan.js +582 -582
- package/src/stages/propose.js +174 -174
- package/src/stages/quick.js +82 -82
- package/src/stages/scan.js +558 -558
- package/src/stages/status.js +65 -65
- package/src/stages/verify.js +322 -322
- package/src/sync.js +497 -497
- package/src/task-review.js +346 -346
- package/src/workflow.js +785 -785
- package/src/worktree-apply.js +549 -549
- package/src/worktree-deps.js +185 -0
- package/src/worktree.js +982 -932
- package/templates/workflows/archive-impact.yaml +79 -79
- package/templates/workflows/scan-docs.yaml +132 -132
- package/test/brainstorm-plan-contract.test.mjs +273 -273
- package/test/check-syntax.mjs +26 -26
- package/test/contract-artifacts.test.mjs +323 -323
- package/test/decision-supersede.test.mjs +277 -277
- package/test/knowledge-match.test.mjs +231 -231
- package/test/plan-execute-contract.test.mjs +330 -330
- package/test/plan-optimization.test.mjs +572 -572
- package/test/platform-artifacts.test.mjs +166 -166
- package/test/platform-failure-samples.test.mjs +199 -199
- package/test/platform-recovery-chain.test.mjs +167 -167
- package/test/platform-recovery.test.mjs +136 -136
- package/test/platform-scan-p0.test.mjs +168 -168
- package/test/revision-v1.test.mjs +1145 -1145
- package/test/run-scan-project-parse.test.mjs +200 -200
- package/test/run-tests.mjs +48 -48
- package/test/scan-knowledge.test.mjs +175 -175
- package/test/scan-paths.test.mjs +68 -68
- package/test/scan-postcheck.test.mjs +197 -197
- package/test/spec-dir.test.mjs +206 -206
- package/test/stage-contract.test.mjs +299 -299
- package/test/stage-definitions.test.mjs +39 -39
- package/test/wait-gates.test.mjs +496 -496
- package/test/worktree-deps-provision.test.mjs +148 -0
- package/test/worktree-guard.test.mjs +71 -71
- package/test/worktree-native-overlay.test.mjs +188 -188
|
@@ -1,252 +1,252 @@
|
|
|
1
|
-
# Worktree 隔离
|
|
2
|
-
|
|
3
|
-
SillySpec 在 `execute` 和 `quick` 阶段使用 **git worktree** 隔离 AI 子代理的代码修改,确保主工作区始终干净。
|
|
4
|
-
|
|
5
|
-
## 概述
|
|
6
|
-
|
|
7
|
-
AI 子代理在执行任务时会在 worktree 中修改源码,而非直接在主工作区操作。任务完成后通过 `worktree apply` 将变更合入主工作区。这带来几个好处:
|
|
8
|
-
|
|
9
|
-
- **安全性** — 主工作区不受意外修改影响
|
|
10
|
-
- **可审计** — 变更集中在一个 diff 中,便于 review
|
|
11
|
-
- **可回退** — 不满意直接 cleanup,主工作区零影响
|
|
12
|
-
- **多 Agent 并行** — 多个子代理可以同时工作在不同的 worktree 中
|
|
13
|
-
|
|
14
|
-
### 架构示意
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
主工作区 worktree 隔离区
|
|
18
|
-
┌──────────────────────┐ ┌──────────────────────────┐
|
|
19
|
-
│ src/ │ │ .sillyspec/.runtime/ │
|
|
20
|
-
│ (hook 禁止写入) │ │ worktrees/ │
|
|
21
|
-
│ .sillyspec/ │ │ <change-name>/ │
|
|
22
|
-
│ changes/ │ │ src/ (完整副本) │
|
|
23
|
-
│ <change-name>/ │ │ node_modules/ │
|
|
24
|
-
│ design.md │ │ ... │
|
|
25
|
-
│ tasks.md │ │ │
|
|
26
|
-
│ .sillyspec/.runtime/ │ │ 分支: sillyspec/<name> │
|
|
27
|
-
│ gate-status.json │ └──────────────────────────┘
|
|
28
|
-
│ worktrees/ │ │
|
|
29
|
-
│ <change-name>/ │ │ sillyspec worktree apply
|
|
30
|
-
│ meta.json │────────────────────┘
|
|
31
|
-
└──────────────────────┘
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## 命令参考
|
|
35
|
-
|
|
36
|
-
### `sillyspec worktree create <change-name> [--base <branch>]`
|
|
37
|
-
|
|
38
|
-
创建一个隔离的 worktree。
|
|
39
|
-
|
|
40
|
-
- 基于 `--base` 分支(默认当前 HEAD)创建新分支 `sillyspec/<change-name>`
|
|
41
|
-
- worktree 目录位于 `.sillyspec/.runtime/worktrees/<change-name>/`
|
|
42
|
-
- 在目录内生成 `meta.json` 记录元数据(分支名、base hash、创建时间等)
|
|
43
|
-
- 如果 worktree 已存在则报错,提示先执行 cleanup
|
|
44
|
-
|
|
45
|
-
### `sillyspec worktree apply <change-name> [--check-only]`
|
|
46
|
-
|
|
47
|
-
将 worktree 中的变更合入主工作区。
|
|
48
|
-
|
|
49
|
-
- 读取 `meta.json` 中的 base hash,与主工作区比对
|
|
50
|
-
- 从 `design.md` 解析文件变更清单,校验变更范围
|
|
51
|
-
- `--check-only` 只输出检查结果,不实际 apply
|
|
52
|
-
- 校验通过后生成 patch 并 3-way apply 到主工作区
|
|
53
|
-
- apply 成功后自动清理 worktree
|
|
54
|
-
|
|
55
|
-
**文件变更清单解析:** 从 `.sillyspec/changes/<change-name>/design.md` 中的 `## 文件变更清单` 表格提取。
|
|
56
|
-
|
|
57
|
-
### `sillyspec worktree list`
|
|
58
|
-
|
|
59
|
-
列出所有活跃的 worktree。
|
|
60
|
-
|
|
61
|
-
输出表格包含变更名、分支名和创建时间。
|
|
62
|
-
|
|
63
|
-
### `sillyspec worktree cleanup <change-name>`
|
|
64
|
-
|
|
65
|
-
清理指定的 worktree。
|
|
66
|
-
|
|
67
|
-
- 强制移除 worktree 目录
|
|
68
|
-
- 删除 `sillyspec/<change-name>` 分支
|
|
69
|
-
- 删除 `meta.json`
|
|
70
|
-
|
|
71
|
-
> ⚠️ cleanup 会丢弃所有未 apply 的变更,请确认后再执行。
|
|
72
|
-
|
|
73
|
-
## Hook 拦截机制
|
|
74
|
-
|
|
75
|
-
SillySpec 通过 hook 在 AI 工具调用(Write/Edit/MultiEdit/Bash)前拦截非法写入。判断逻辑采用 **三重门禁**:
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
allowWrite = stageGate && locationGate && fileGate
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### 阶段门禁(stageGate)
|
|
82
|
-
|
|
83
|
-
- 读取 `.sillyspec/.runtime/gate-status.json`(由 CLI 维护)
|
|
84
|
-
- 只有 `execute` 和 `quick` 阶段允许源码写入
|
|
85
|
-
- 其他阶段(brainstorm/plan/verify/archive/explore)→ 禁止
|
|
86
|
-
- 无 `gate-status.json` → 禁止(默认安全)
|
|
87
|
-
|
|
88
|
-
### 位置门禁(locationGate)
|
|
89
|
-
|
|
90
|
-
- 目标路径必须在 `.sillyspec/.runtime/worktrees/` 下才允许源码写入
|
|
91
|
-
- 主工作区的源码目录一律禁止
|
|
92
|
-
|
|
93
|
-
### 文件门禁(fileGate)
|
|
94
|
-
|
|
95
|
-
文档类、配置类文件在所有阶段放行,不受阶段和位置限制:
|
|
96
|
-
|
|
97
|
-
- `.sillyspec/` 开头的路径
|
|
98
|
-
- `.md` 文件
|
|
99
|
-
- `package.json`、`tsconfig.json`、`local.yaml` 等配置文件
|
|
100
|
-
- `.git/` 下的文件
|
|
101
|
-
|
|
102
|
-
### Bash 命令拦截
|
|
103
|
-
|
|
104
|
-
| 类型 | 示例 |
|
|
105
|
-
|------|------|
|
|
106
|
-
| **只读放行** | `grep`、`cat`、`git diff`、`git status`、`ls`、`find`、`sillyspec worktree apply/create/list/cleanup` |
|
|
107
|
-
| **禁止** | `git add`、`git commit`、`git push`、`git checkout`、`rm -rf`、`sudo` 等 |
|
|
108
|
-
| **不确定** | 启发式判断,放行但警告 |
|
|
109
|
-
|
|
110
|
-
> 在 worktree 目录下执行 Bash 命令时全部放行,不做拦截。
|
|
111
|
-
|
|
112
|
-
## 降级方案和逃生开关
|
|
113
|
-
|
|
114
|
-
| 场景 | 处理方式 |
|
|
115
|
-
|------|---------|
|
|
116
|
-
| **git < 2.15** | 不支持 worktree,报错停止 |
|
|
117
|
-
| **`--no-worktree` 标志** | 跳过隔离创建,但 hook 仍然拦截源码写入 |
|
|
118
|
-
| **`SILLYSPEC_DISABLE_HOOKS=1`** | 紧急禁用所有 hook,全部放行 |
|
|
119
|
-
| **无 gate-status.json** | stageGate=false,默认禁止源码写入 |
|
|
120
|
-
| **worktree 创建失败** | 自动降级为 in-place + baseline protection(mode: in-place-fallback) |
|
|
121
|
-
| **已在 linked worktree** | 复用当前目录(mode: native-worktree) |
|
|
122
|
-
| **worktree 目录未 ignore** | 阻断创建,提示修复 |
|
|
123
|
-
|
|
124
|
-
> ⚠️ in-place 降级模式仍会记录 baseline(baselineFiles + baselineHash + baselineCommit),hook 拦截继续生效,不会无保护地直接写源码。
|
|
125
|
-
|
|
126
|
-
## 多 Agent 并行使用
|
|
127
|
-
|
|
128
|
-
不同的 AI 子代理可以同时创建各自的 worktree:
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
# Agent A 处理 task-01
|
|
132
|
-
sillyspec worktree create feature-auth
|
|
133
|
-
# worktree: .sillyspec/.runtime/worktrees/feature-auth/
|
|
134
|
-
|
|
135
|
-
# Agent B 处理 task-02
|
|
136
|
-
sillyspec worktree create feature-ui
|
|
137
|
-
# worktree: .sillyspec/.runtime/worktrees/feature-ui/
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
两个 Agent 在各自的 worktree 中独立工作,互不干扰。各自完成后分别 apply 合入主工作区。
|
|
141
|
-
|
|
142
|
-
> 💡 如果两个 Agent 修改了相同的文件,后 apply 的一方可能遇到冲突。建议在 `plan` 阶段通过 Wave 分组避免同一文件被多个 Agent 修改。
|
|
143
|
-
|
|
144
|
-
## 环境变量
|
|
145
|
-
|
|
146
|
-
| 变量 | 说明 |
|
|
147
|
-
|------|------|
|
|
148
|
-
| `SILLYSPEC_DISABLE_HOOKS` | 设为 `1` 时禁用所有 hook(紧急逃生) |
|
|
149
|
-
| `SILLYSPEC_WORKTREE_DIR` | 自定义 worktree 存储目录(默认 `.sillyspec/.runtime/worktrees/`) |
|
|
150
|
-
|
|
151
|
-
## 环境隔离检测
|
|
152
|
-
|
|
153
|
-
SillySpec 在创建 worktree 前会自动检测当前环境的隔离状态:
|
|
154
|
-
|
|
155
|
-
### submodule 防护
|
|
156
|
-
|
|
157
|
-
使用 `git rev-parse --git-dir` 和 `--git-common-dir` 判断是否在 linked worktree 中。
|
|
158
|
-
同时用 `--show-superproject-working-tree` 排除 git submodule 的误判:
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
if GIT_DIR != GIT_COMMON && 无 superproject:
|
|
162
|
-
→ 已在 linked worktree,复用当前隔离环境
|
|
163
|
-
if 无 superproject 为空:
|
|
164
|
-
→ 在 git submodule 内,阻断创建并提示
|
|
165
|
-
else:
|
|
166
|
-
→ 在主仓库中,正常创建 worktree
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### .gitignore 强制校验
|
|
170
|
-
|
|
171
|
-
worktree 存储目录 `.sillyspec/.runtime/worktrees/` 必须被 `.gitignore` 忽略:
|
|
172
|
-
|
|
173
|
-
- **init / doctor 阶段:** 预检查并提示修复
|
|
174
|
-
- **execute 阶段:** 未 ignore 则直接阻断 worktree 创建,抛出明确错误
|
|
175
|
-
- **不会自动修改 .gitignore:** 避免污染 baseline
|
|
176
|
-
|
|
177
|
-
修复方式:在项目 `.gitignore` 中添加:
|
|
178
|
-
```
|
|
179
|
-
.sillyspec/.runtime/worktrees/
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### isolation 状态
|
|
183
|
-
|
|
184
|
-
worktree create 后,isolation 状态写入 `sillyspec.db` 的 `changes` 表(权威状态源):
|
|
185
|
-
|
|
186
|
-
| 字段 | 说明 |
|
|
187
|
-
|------|------|
|
|
188
|
-
| `isolation_status` | pending / verified / degraded / blocked |
|
|
189
|
-
| `isolation_mode` | worktree / native-worktree / in-place-fallback / null |
|
|
190
|
-
| `isolation_reason` | blocked 或 degraded 时的原因说明 |
|
|
191
|
-
|
|
192
|
-
状态映射:
|
|
193
|
-
|
|
194
|
-
| status | mode | 触发条件 |
|
|
195
|
-
|--------|------|----------|
|
|
196
|
-
| verified | worktree | `git worktree add` 成功 |
|
|
197
|
-
| verified | native-worktree | 已在 linked worktree,复用 |
|
|
198
|
-
| degraded | in-place-fallback | `git worktree add` 失败,降级 in-place |
|
|
199
|
-
| blocked | null | submodule 内 / gitignore 未配置 |
|
|
200
|
-
| null | null | 尚未执行隔离检查 |
|
|
201
|
-
|
|
202
|
-
> ⚠️ isolation 的权威来源是 sillyspec.db。meta.json 中的 mode 仅作为 worktree 目录的运行时元信息。gate-status.json 不存储 isolation。
|
|
203
|
-
|
|
204
|
-
## 常见问题和故障排除
|
|
205
|
-
|
|
206
|
-
### worktree 残留无法清理
|
|
207
|
-
|
|
208
|
-
```bash
|
|
209
|
-
# 查看所有活跃 worktree
|
|
210
|
-
sillyspec worktree list
|
|
211
|
-
|
|
212
|
-
# 强制清理指定 worktree
|
|
213
|
-
sillyspec worktree cleanup <change-name>
|
|
214
|
-
|
|
215
|
-
# 如果 worktree 目录被手动删除但分支残留
|
|
216
|
-
git worktree prune
|
|
217
|
-
git branch -D sillyspec/<change-name>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### apply 失败:base hash 不一致
|
|
221
|
-
|
|
222
|
-
说明主工作区在 worktree 创建后又被修改过。处理方式:
|
|
223
|
-
|
|
224
|
-
1. 检查主工作区的变更:`git diff`
|
|
225
|
-
2. 如果主工作区变更不重要 → `git stash` 后重试 apply
|
|
226
|
-
3. 如果重要 → 手动解决冲突
|
|
227
|
-
|
|
228
|
-
### apply 失败:文件清单校验不通过
|
|
229
|
-
|
|
230
|
-
说明 worktree 中修改了 `design.md` 清单之外的文件。处理方式:
|
|
231
|
-
|
|
232
|
-
1. 查看清单外文件:apply 的输出会列出
|
|
233
|
-
2. 确认是否是合理的新增(如测试文件)
|
|
234
|
-
3. 更新 `design.md` 中的文件变更清单后重试
|
|
235
|
-
4. 或用 `--check-only` 排查后再 apply
|
|
236
|
-
|
|
237
|
-
### Hook 误拦截了合法操作
|
|
238
|
-
|
|
239
|
-
- 临时方案:设置 `SILLYSPEC_DISABLE_HOOKS=1` 环境变量
|
|
240
|
-
- 检查目标文件是否应加入文件白名单(fileGate)
|
|
241
|
-
- 检查当前阶段是否正确(gate-status.json)
|
|
242
|
-
|
|
243
|
-
### worktree 内 node_modules 问题
|
|
244
|
-
|
|
245
|
-
worktree 创建后需要安装依赖:
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
cd .sillyspec/.runtime/worktrees/<change-name>/
|
|
249
|
-
npm install
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
如果项目使用 pnpm 且有 monorepo,可能需要额外配置。
|
|
1
|
+
# Worktree 隔离
|
|
2
|
+
|
|
3
|
+
SillySpec 在 `execute` 和 `quick` 阶段使用 **git worktree** 隔离 AI 子代理的代码修改,确保主工作区始终干净。
|
|
4
|
+
|
|
5
|
+
## 概述
|
|
6
|
+
|
|
7
|
+
AI 子代理在执行任务时会在 worktree 中修改源码,而非直接在主工作区操作。任务完成后通过 `worktree apply` 将变更合入主工作区。这带来几个好处:
|
|
8
|
+
|
|
9
|
+
- **安全性** — 主工作区不受意外修改影响
|
|
10
|
+
- **可审计** — 变更集中在一个 diff 中,便于 review
|
|
11
|
+
- **可回退** — 不满意直接 cleanup,主工作区零影响
|
|
12
|
+
- **多 Agent 并行** — 多个子代理可以同时工作在不同的 worktree 中
|
|
13
|
+
|
|
14
|
+
### 架构示意
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
主工作区 worktree 隔离区
|
|
18
|
+
┌──────────────────────┐ ┌──────────────────────────┐
|
|
19
|
+
│ src/ │ │ .sillyspec/.runtime/ │
|
|
20
|
+
│ (hook 禁止写入) │ │ worktrees/ │
|
|
21
|
+
│ .sillyspec/ │ │ <change-name>/ │
|
|
22
|
+
│ changes/ │ │ src/ (完整副本) │
|
|
23
|
+
│ <change-name>/ │ │ node_modules/ │
|
|
24
|
+
│ design.md │ │ ... │
|
|
25
|
+
│ tasks.md │ │ │
|
|
26
|
+
│ .sillyspec/.runtime/ │ │ 分支: sillyspec/<name> │
|
|
27
|
+
│ gate-status.json │ └──────────────────────────┘
|
|
28
|
+
│ worktrees/ │ │
|
|
29
|
+
│ <change-name>/ │ │ sillyspec worktree apply
|
|
30
|
+
│ meta.json │────────────────────┘
|
|
31
|
+
└──────────────────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 命令参考
|
|
35
|
+
|
|
36
|
+
### `sillyspec worktree create <change-name> [--base <branch>]`
|
|
37
|
+
|
|
38
|
+
创建一个隔离的 worktree。
|
|
39
|
+
|
|
40
|
+
- 基于 `--base` 分支(默认当前 HEAD)创建新分支 `sillyspec/<change-name>`
|
|
41
|
+
- worktree 目录位于 `.sillyspec/.runtime/worktrees/<change-name>/`
|
|
42
|
+
- 在目录内生成 `meta.json` 记录元数据(分支名、base hash、创建时间等)
|
|
43
|
+
- 如果 worktree 已存在则报错,提示先执行 cleanup
|
|
44
|
+
|
|
45
|
+
### `sillyspec worktree apply <change-name> [--check-only]`
|
|
46
|
+
|
|
47
|
+
将 worktree 中的变更合入主工作区。
|
|
48
|
+
|
|
49
|
+
- 读取 `meta.json` 中的 base hash,与主工作区比对
|
|
50
|
+
- 从 `design.md` 解析文件变更清单,校验变更范围
|
|
51
|
+
- `--check-only` 只输出检查结果,不实际 apply
|
|
52
|
+
- 校验通过后生成 patch 并 3-way apply 到主工作区
|
|
53
|
+
- apply 成功后自动清理 worktree
|
|
54
|
+
|
|
55
|
+
**文件变更清单解析:** 从 `.sillyspec/changes/<change-name>/design.md` 中的 `## 文件变更清单` 表格提取。
|
|
56
|
+
|
|
57
|
+
### `sillyspec worktree list`
|
|
58
|
+
|
|
59
|
+
列出所有活跃的 worktree。
|
|
60
|
+
|
|
61
|
+
输出表格包含变更名、分支名和创建时间。
|
|
62
|
+
|
|
63
|
+
### `sillyspec worktree cleanup <change-name>`
|
|
64
|
+
|
|
65
|
+
清理指定的 worktree。
|
|
66
|
+
|
|
67
|
+
- 强制移除 worktree 目录
|
|
68
|
+
- 删除 `sillyspec/<change-name>` 分支
|
|
69
|
+
- 删除 `meta.json`
|
|
70
|
+
|
|
71
|
+
> ⚠️ cleanup 会丢弃所有未 apply 的变更,请确认后再执行。
|
|
72
|
+
|
|
73
|
+
## Hook 拦截机制
|
|
74
|
+
|
|
75
|
+
SillySpec 通过 hook 在 AI 工具调用(Write/Edit/MultiEdit/Bash)前拦截非法写入。判断逻辑采用 **三重门禁**:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
allowWrite = stageGate && locationGate && fileGate
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 阶段门禁(stageGate)
|
|
82
|
+
|
|
83
|
+
- 读取 `.sillyspec/.runtime/gate-status.json`(由 CLI 维护)
|
|
84
|
+
- 只有 `execute` 和 `quick` 阶段允许源码写入
|
|
85
|
+
- 其他阶段(brainstorm/plan/verify/archive/explore)→ 禁止
|
|
86
|
+
- 无 `gate-status.json` → 禁止(默认安全)
|
|
87
|
+
|
|
88
|
+
### 位置门禁(locationGate)
|
|
89
|
+
|
|
90
|
+
- 目标路径必须在 `.sillyspec/.runtime/worktrees/` 下才允许源码写入
|
|
91
|
+
- 主工作区的源码目录一律禁止
|
|
92
|
+
|
|
93
|
+
### 文件门禁(fileGate)
|
|
94
|
+
|
|
95
|
+
文档类、配置类文件在所有阶段放行,不受阶段和位置限制:
|
|
96
|
+
|
|
97
|
+
- `.sillyspec/` 开头的路径
|
|
98
|
+
- `.md` 文件
|
|
99
|
+
- `package.json`、`tsconfig.json`、`local.yaml` 等配置文件
|
|
100
|
+
- `.git/` 下的文件
|
|
101
|
+
|
|
102
|
+
### Bash 命令拦截
|
|
103
|
+
|
|
104
|
+
| 类型 | 示例 |
|
|
105
|
+
|------|------|
|
|
106
|
+
| **只读放行** | `grep`、`cat`、`git diff`、`git status`、`ls`、`find`、`sillyspec worktree apply/create/list/cleanup` |
|
|
107
|
+
| **禁止** | `git add`、`git commit`、`git push`、`git checkout`、`rm -rf`、`sudo` 等 |
|
|
108
|
+
| **不确定** | 启发式判断,放行但警告 |
|
|
109
|
+
|
|
110
|
+
> 在 worktree 目录下执行 Bash 命令时全部放行,不做拦截。
|
|
111
|
+
|
|
112
|
+
## 降级方案和逃生开关
|
|
113
|
+
|
|
114
|
+
| 场景 | 处理方式 |
|
|
115
|
+
|------|---------|
|
|
116
|
+
| **git < 2.15** | 不支持 worktree,报错停止 |
|
|
117
|
+
| **`--no-worktree` 标志** | 跳过隔离创建,但 hook 仍然拦截源码写入 |
|
|
118
|
+
| **`SILLYSPEC_DISABLE_HOOKS=1`** | 紧急禁用所有 hook,全部放行 |
|
|
119
|
+
| **无 gate-status.json** | stageGate=false,默认禁止源码写入 |
|
|
120
|
+
| **worktree 创建失败** | 自动降级为 in-place + baseline protection(mode: in-place-fallback) |
|
|
121
|
+
| **已在 linked worktree** | 复用当前目录(mode: native-worktree) |
|
|
122
|
+
| **worktree 目录未 ignore** | 阻断创建,提示修复 |
|
|
123
|
+
|
|
124
|
+
> ⚠️ in-place 降级模式仍会记录 baseline(baselineFiles + baselineHash + baselineCommit),hook 拦截继续生效,不会无保护地直接写源码。
|
|
125
|
+
|
|
126
|
+
## 多 Agent 并行使用
|
|
127
|
+
|
|
128
|
+
不同的 AI 子代理可以同时创建各自的 worktree:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Agent A 处理 task-01
|
|
132
|
+
sillyspec worktree create feature-auth
|
|
133
|
+
# worktree: .sillyspec/.runtime/worktrees/feature-auth/
|
|
134
|
+
|
|
135
|
+
# Agent B 处理 task-02
|
|
136
|
+
sillyspec worktree create feature-ui
|
|
137
|
+
# worktree: .sillyspec/.runtime/worktrees/feature-ui/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
两个 Agent 在各自的 worktree 中独立工作,互不干扰。各自完成后分别 apply 合入主工作区。
|
|
141
|
+
|
|
142
|
+
> 💡 如果两个 Agent 修改了相同的文件,后 apply 的一方可能遇到冲突。建议在 `plan` 阶段通过 Wave 分组避免同一文件被多个 Agent 修改。
|
|
143
|
+
|
|
144
|
+
## 环境变量
|
|
145
|
+
|
|
146
|
+
| 变量 | 说明 |
|
|
147
|
+
|------|------|
|
|
148
|
+
| `SILLYSPEC_DISABLE_HOOKS` | 设为 `1` 时禁用所有 hook(紧急逃生) |
|
|
149
|
+
| `SILLYSPEC_WORKTREE_DIR` | 自定义 worktree 存储目录(默认 `.sillyspec/.runtime/worktrees/`) |
|
|
150
|
+
|
|
151
|
+
## 环境隔离检测
|
|
152
|
+
|
|
153
|
+
SillySpec 在创建 worktree 前会自动检测当前环境的隔离状态:
|
|
154
|
+
|
|
155
|
+
### submodule 防护
|
|
156
|
+
|
|
157
|
+
使用 `git rev-parse --git-dir` 和 `--git-common-dir` 判断是否在 linked worktree 中。
|
|
158
|
+
同时用 `--show-superproject-working-tree` 排除 git submodule 的误判:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
if GIT_DIR != GIT_COMMON && 无 superproject:
|
|
162
|
+
→ 已在 linked worktree,复用当前隔离环境
|
|
163
|
+
if 无 superproject 为空:
|
|
164
|
+
→ 在 git submodule 内,阻断创建并提示
|
|
165
|
+
else:
|
|
166
|
+
→ 在主仓库中,正常创建 worktree
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### .gitignore 强制校验
|
|
170
|
+
|
|
171
|
+
worktree 存储目录 `.sillyspec/.runtime/worktrees/` 必须被 `.gitignore` 忽略:
|
|
172
|
+
|
|
173
|
+
- **init / doctor 阶段:** 预检查并提示修复
|
|
174
|
+
- **execute 阶段:** 未 ignore 则直接阻断 worktree 创建,抛出明确错误
|
|
175
|
+
- **不会自动修改 .gitignore:** 避免污染 baseline
|
|
176
|
+
|
|
177
|
+
修复方式:在项目 `.gitignore` 中添加:
|
|
178
|
+
```
|
|
179
|
+
.sillyspec/.runtime/worktrees/
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### isolation 状态
|
|
183
|
+
|
|
184
|
+
worktree create 后,isolation 状态写入 `sillyspec.db` 的 `changes` 表(权威状态源):
|
|
185
|
+
|
|
186
|
+
| 字段 | 说明 |
|
|
187
|
+
|------|------|
|
|
188
|
+
| `isolation_status` | pending / verified / degraded / blocked |
|
|
189
|
+
| `isolation_mode` | worktree / native-worktree / in-place-fallback / null |
|
|
190
|
+
| `isolation_reason` | blocked 或 degraded 时的原因说明 |
|
|
191
|
+
|
|
192
|
+
状态映射:
|
|
193
|
+
|
|
194
|
+
| status | mode | 触发条件 |
|
|
195
|
+
|--------|------|----------|
|
|
196
|
+
| verified | worktree | `git worktree add` 成功 |
|
|
197
|
+
| verified | native-worktree | 已在 linked worktree,复用 |
|
|
198
|
+
| degraded | in-place-fallback | `git worktree add` 失败,降级 in-place |
|
|
199
|
+
| blocked | null | submodule 内 / gitignore 未配置 |
|
|
200
|
+
| null | null | 尚未执行隔离检查 |
|
|
201
|
+
|
|
202
|
+
> ⚠️ isolation 的权威来源是 sillyspec.db。meta.json 中的 mode 仅作为 worktree 目录的运行时元信息。gate-status.json 不存储 isolation。
|
|
203
|
+
|
|
204
|
+
## 常见问题和故障排除
|
|
205
|
+
|
|
206
|
+
### worktree 残留无法清理
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# 查看所有活跃 worktree
|
|
210
|
+
sillyspec worktree list
|
|
211
|
+
|
|
212
|
+
# 强制清理指定 worktree
|
|
213
|
+
sillyspec worktree cleanup <change-name>
|
|
214
|
+
|
|
215
|
+
# 如果 worktree 目录被手动删除但分支残留
|
|
216
|
+
git worktree prune
|
|
217
|
+
git branch -D sillyspec/<change-name>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### apply 失败:base hash 不一致
|
|
221
|
+
|
|
222
|
+
说明主工作区在 worktree 创建后又被修改过。处理方式:
|
|
223
|
+
|
|
224
|
+
1. 检查主工作区的变更:`git diff`
|
|
225
|
+
2. 如果主工作区变更不重要 → `git stash` 后重试 apply
|
|
226
|
+
3. 如果重要 → 手动解决冲突
|
|
227
|
+
|
|
228
|
+
### apply 失败:文件清单校验不通过
|
|
229
|
+
|
|
230
|
+
说明 worktree 中修改了 `design.md` 清单之外的文件。处理方式:
|
|
231
|
+
|
|
232
|
+
1. 查看清单外文件:apply 的输出会列出
|
|
233
|
+
2. 确认是否是合理的新增(如测试文件)
|
|
234
|
+
3. 更新 `design.md` 中的文件变更清单后重试
|
|
235
|
+
4. 或用 `--check-only` 排查后再 apply
|
|
236
|
+
|
|
237
|
+
### Hook 误拦截了合法操作
|
|
238
|
+
|
|
239
|
+
- 临时方案:设置 `SILLYSPEC_DISABLE_HOOKS=1` 环境变量
|
|
240
|
+
- 检查目标文件是否应加入文件白名单(fileGate)
|
|
241
|
+
- 检查当前阶段是否正确(gate-status.json)
|
|
242
|
+
|
|
243
|
+
### worktree 内 node_modules 问题
|
|
244
|
+
|
|
245
|
+
worktree 创建后需要安装依赖:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
cd .sillyspec/.runtime/worktrees/<change-name>/
|
|
249
|
+
npm install
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
如果项目使用 pnpm 且有 monorepo,可能需要额外配置。
|
package/package.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sillyspec",
|
|
3
|
-
"version": "3.20.
|
|
4
|
-
"description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
|
|
5
|
-
"icon": "logo.jpg",
|
|
6
|
-
"homepage": "https://sillyspec.ppdmq.top/",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "https://github.com/q512426816/sillyspec.git"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"bin": {
|
|
13
|
-
"sillyspec": "./bin/sillyspec.js"
|
|
14
|
-
},
|
|
15
|
-
"engines": {
|
|
16
|
-
"node": ">=18"
|
|
17
|
-
},
|
|
18
|
-
"keywords": [
|
|
19
|
-
"sillyspec",
|
|
20
|
-
"ai",
|
|
21
|
-
"claude",
|
|
22
|
-
"cursor",
|
|
23
|
-
"spec-driven"
|
|
24
|
-
],
|
|
25
|
-
"license": "MIT",
|
|
26
|
-
"scripts": {
|
|
27
|
-
"test": "node test/run-tests.mjs",
|
|
28
|
-
"lint": "node test/check-syntax.mjs"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"@inquirer/prompts": "^7.10.1",
|
|
32
|
-
"chalk": "^5.6.2",
|
|
33
|
-
"chokidar": "^4.0",
|
|
34
|
-
"js-yaml": "^4.2.0",
|
|
35
|
-
"open": "^10.1",
|
|
36
|
-
"ora": "^9.3.0",
|
|
37
|
-
"sql.js": "^1.14.1",
|
|
38
|
-
"ws": "^8.18"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "sillyspec",
|
|
3
|
+
"version": "3.20.4",
|
|
4
|
+
"description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
|
|
5
|
+
"icon": "logo.jpg",
|
|
6
|
+
"homepage": "https://sillyspec.ppdmq.top/",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/q512426816/sillyspec.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"sillyspec": "./bin/sillyspec.js"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"sillyspec",
|
|
20
|
+
"ai",
|
|
21
|
+
"claude",
|
|
22
|
+
"cursor",
|
|
23
|
+
"spec-driven"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test": "node test/run-tests.mjs",
|
|
28
|
+
"lint": "node test/check-syntax.mjs"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@inquirer/prompts": "^7.10.1",
|
|
32
|
+
"chalk": "^5.6.2",
|
|
33
|
+
"chokidar": "^4.0",
|
|
34
|
+
"js-yaml": "^4.2.0",
|
|
35
|
+
"open": "^10.1",
|
|
36
|
+
"ora": "^9.3.0",
|
|
37
|
+
"sql.js": "^1.14.1",
|
|
38
|
+
"ws": "^8.18"
|
|
39
|
+
}
|
|
40
|
+
}
|