gsd-lite 0.3.1 → 0.3.5
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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/commands/prd.md +3 -142
- package/commands/resume.md +1 -1
- package/commands/start.md +3 -155
- package/hooks/gsd-context-monitor.cjs +23 -17
- package/hooks/gsd-session-init.cjs +1 -1
- package/hooks/gsd-statusline.cjs +17 -15
- package/package.json +1 -1
- package/references/evidence-spec.md +167 -0
- package/references/execution-loop.md +162 -0
- package/references/review-classification.md +84 -0
- package/references/state-diagram.md +218 -0
- package/src/schema.js +146 -26
- package/src/server.js +7 -0
- package/src/tools/orchestrator.js +76 -47
- package/src/tools/state.js +104 -60
- package/src/tools/verify.js +6 -3
- package/src/utils.js +39 -18
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "gsd",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "AI orchestration tool — GSD management shell + Superpowers quality core. 5 commands, 4 agents, 5 workflows, MCP server, context monitoring.",
|
|
16
|
-
"version": "0.3.
|
|
16
|
+
"version": "0.3.4",
|
|
17
17
|
"keywords": ["orchestration", "mcp", "tdd", "task-management"],
|
|
18
18
|
"category": "Development workflows"
|
|
19
19
|
}
|
package/commands/prd.md
CHANGED
|
@@ -126,149 +126,10 @@ argument-hint: File path to requirements doc, or inline description text
|
|
|
126
126
|
进入执行主循环。phase = 管理边界,task = 执行边界。
|
|
127
127
|
|
|
128
128
|
<execution_loop>
|
|
129
|
+
参考 `references/execution-loop.md` 获取完整 9 步执行循环规范 (11.1-11.9) 及依赖门槛语义。
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
for each pending phase:
|
|
134
|
-
加载 phase 计划 + todo DAG
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 11.2 — 选择 runnable task
|
|
138
|
-
|
|
139
|
-
选择条件:
|
|
140
|
-
- `lifecycle` 属于 `{pending, needs_revalidation}`
|
|
141
|
-
- `requires` 中每个依赖都满足对应 gate
|
|
142
|
-
- 不被 unresolved blocker 阻塞
|
|
143
|
-
- 未超过 retry 上限
|
|
144
|
-
|
|
145
|
-
如果 0 个 runnable task 且 phase 未完成:
|
|
146
|
-
```
|
|
147
|
-
├── 全部 blocked → workflow_mode = awaiting_user,展示所有 blocker
|
|
148
|
-
└── 全部等待 review → 触发 batch review (L1) 或等待 L2 review 完成
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### 11.3 — 构建 executor 上下文 + 串行派发
|
|
152
|
-
|
|
153
|
-
executor 上下文传递协议 (orchestrator → executor):
|
|
154
|
-
```
|
|
155
|
-
├── task_spec: 从 phases/*.md 提取当前 task 的规格段落
|
|
156
|
-
├── research_decisions: 从 research_basis 引用的 decision 摘要
|
|
157
|
-
├── predecessor_outputs: 前置依赖 task 的 files_changed + checkpoint_commit
|
|
158
|
-
├── project_conventions: CLAUDE.md 路径 (executor 自行读取)
|
|
159
|
-
├── workflows: 需加载的工作流文件路径 (如 tdd-cycle.md)
|
|
160
|
-
└── constraints: retry_count / level / review_required
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
派发 `executor` 子代理执行单个 task。
|
|
164
|
-
|
|
165
|
-
### 11.4 — 处理 executor 结果
|
|
166
|
-
|
|
167
|
-
严格按 agent result contract 处理:
|
|
168
|
-
```
|
|
169
|
-
├── checkpointed → 写入 checkpoint commit + evidence refs → 进入审查 (11.5)
|
|
170
|
-
├── blocked → 写入 blocked_reason / unblock_condition
|
|
171
|
-
│ → 编排器检查 decisions 数组,能自动回答则重新派发
|
|
172
|
-
│ → 不能回答 → workflow_mode = awaiting_user,向用户转达
|
|
173
|
-
├── failed → retry_count + 1
|
|
174
|
-
│ → 未超限 → 重新派发 executor
|
|
175
|
-
│ → 超限 (3次) 或返回 [FAILED] 且错误指纹重复
|
|
176
|
-
│ 或修复尝试未收敛 → 触发 debugger (见下方)
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
**Debugger 触发流程:**
|
|
180
|
-
1. 编排器派发 `debugger` 子代理,传入: 错误信息 + executor 修复尝试记录 + 相关代码路径
|
|
181
|
-
2. debugger 返回: 根因分析 + 修复方向建议
|
|
182
|
-
3. 编排器决定:
|
|
183
|
-
- 带修复方向重新派发 executor
|
|
184
|
-
- 标记 task failed
|
|
185
|
-
- 标记 phase failed
|
|
186
|
-
|
|
187
|
-
**Decisions 累积:**
|
|
188
|
-
- executor 返回 `[DECISION]` → 编排器追加到 `state.json` 的 `decisions` 数组
|
|
189
|
-
- 每条 decision 记录: `id` / `task` / `summary` / `phase`
|
|
190
|
-
- decisions 跨 task、跨 phase、跨 `/clear` + `/gsd:resume` 持久保留
|
|
191
|
-
- 编排器收到 `[BLOCKED]` 时,先查 `decisions` 数组尝试自动回答
|
|
192
|
-
|
|
193
|
-
### 11.5 — 分层审查
|
|
194
|
-
|
|
195
|
-
```
|
|
196
|
-
├── L0: checkpoint commit 后可直接 accepted (无需 reviewer)
|
|
197
|
-
├── L1: phase 结束后批量 reviewer 审查
|
|
198
|
-
│ → 派发 reviewer 子代理,scope = phase
|
|
199
|
-
└── L2: checkpoint commit 后立即独立审查
|
|
200
|
-
→ 派发 reviewer 子代理,scope = task
|
|
201
|
-
→ 未 accepted 前不释放其下游依赖
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**审查级别运行时重分类:**
|
|
205
|
-
- executor 报告 `contract_changed: true` + 涉及 auth/payment/public API → 自动升级为 L2
|
|
206
|
-
- executor 标注 `[LEVEL-UP]` → 编排器采纳
|
|
207
|
-
- 不主动降级 (安全优先)
|
|
208
|
-
|
|
209
|
-
### 11.6 — 处理 reviewer 结果
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
├── 无 Critical → 更新 accepted 状态 + evidence refs
|
|
213
|
-
└── 有 Critical → 标记返工 task + 失效传播 → 重新审查 (最多 3 轮)
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
**返工失效传播规则:**
|
|
217
|
-
- 返工修改了 contract / schema / shared behavior:
|
|
218
|
-
→ 所有直接和间接依赖 task → `needs_revalidation`
|
|
219
|
-
→ 清空其旧 `evidence_refs`
|
|
220
|
-
→ 已 accepted 则退回到 `checkpointed` 或 `pending_review`
|
|
221
|
-
- 返工只影响局部实现、外部契约未变:
|
|
222
|
-
→ 下游 task 保持现状
|
|
223
|
-
→ 但受影响验证范围必须重跑并刷新 evidence
|
|
224
|
-
- 触发判定: `contract_changed` (executor 运行时报告) 是主触发源
|
|
225
|
-
`invalidate_downstream_on_change` (planner 静态标记) 是预判辅助
|
|
226
|
-
→ executor 报告 `contract_changed: true` → 一定传播
|
|
227
|
-
→ planner 标记但 executor 报告 false → 不传播 (以运行时实际为准)
|
|
228
|
-
|
|
229
|
-
### 11.7 — Phase handoff gate
|
|
230
|
-
|
|
231
|
-
<HARD-GATE id="phase-handoff">
|
|
232
|
-
所有条件必须满足才能进入下一 phase:
|
|
233
|
-
- [ ] 所有 required task = `accepted`
|
|
234
|
-
- [ ] required review = `passed`
|
|
235
|
-
- [ ] critical issues = 0
|
|
236
|
-
- [ ] tests/lint/typecheck 满足计划验证条件
|
|
237
|
-
- [ ] 方向校验: 当前阶段产出是否仍与 plan.md 中的项目目标一致?
|
|
238
|
-
|
|
239
|
-
→ 全部满足 → 自动进入下一阶段
|
|
240
|
-
→ 任一不满足 → 标注问题,尝试修复,3 次失败停止
|
|
241
|
-
→ 方向漂移 → workflow_mode = awaiting_user,展示偏差让用户决定
|
|
242
|
-
</HARD-GATE>
|
|
243
|
-
|
|
244
|
-
### 11.8 — 批量更新 state.json
|
|
245
|
-
|
|
246
|
-
阶段完成后,编排器批量更新 state.json:
|
|
247
|
-
- 更新 phase lifecycle → `accepted`
|
|
248
|
-
- 更新 phase_handoff 信息
|
|
249
|
-
- 归档旧 phase 的 evidence (只保留当前 phase 和上一 phase)
|
|
250
|
-
- 推进 `current_phase` 到下一个 pending phase
|
|
251
|
-
|
|
252
|
-
**规则:** 只有编排器写 state.json,避免并发竞态。
|
|
253
|
-
|
|
254
|
-
### 11.9 — 上下文检查
|
|
255
|
-
|
|
256
|
-
每次派发子代理前和阶段切换时检查上下文健康度:
|
|
257
|
-
|
|
258
|
-
```
|
|
259
|
-
remaining < 35%:
|
|
260
|
-
1. 保存完整状态到 state.json
|
|
261
|
-
2. workflow_mode = awaiting_clear
|
|
262
|
-
3. 输出: "上下文剩余 <35%,已保存进度。请执行 /clear 然后 /gsd:resume 继续"
|
|
263
|
-
4. 停止执行
|
|
264
|
-
|
|
265
|
-
remaining < 25%:
|
|
266
|
-
1. 紧急保存状态到 state.json
|
|
267
|
-
2. workflow_mode = awaiting_clear
|
|
268
|
-
3. 输出: "上下文即将耗尽,已保存进度。请立即执行 /clear 然后 /gsd:resume"
|
|
269
|
-
4. 立即停止
|
|
270
|
-
```
|
|
271
|
-
|
|
131
|
+
编排器必须严格按照该参考文档中的步骤顺序执行:
|
|
132
|
+
加载 phase → 选择 task → 构建上下文 → 派发 executor → 处理结果 → 审查 → phase handoff → 批量更新 → 上下文检查
|
|
272
133
|
</execution_loop>
|
|
273
134
|
|
|
274
135
|
## STEP 12 — 全部完成
|
package/commands/resume.md
CHANGED
|
@@ -68,7 +68,7 @@ description: Resume project execution from saved state with workspace validation
|
|
|
68
68
|
- requires 中每个依赖都满足对应 gate
|
|
69
69
|
- 未超过 retry 上限
|
|
70
70
|
- 构建 executor 上下文 → 派发 executor 子代理
|
|
71
|
-
- 继续自动执行主路径 (按
|
|
71
|
+
- 继续自动执行主路径 (按 references/execution-loop.md 执行循环)
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
package/commands/start.md
CHANGED
|
@@ -146,164 +146,12 @@ argument-hint: Optional feature or project description
|
|
|
146
146
|
进入执行主循环。phase = 管理边界,task = 执行边界。
|
|
147
147
|
|
|
148
148
|
<execution_loop>
|
|
149
|
+
参考 `references/execution-loop.md` 获取完整 9 步执行循环规范 (11.1-11.9) 及依赖门槛语义。
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
```
|
|
153
|
-
for each pending phase:
|
|
154
|
-
加载 phase 计划 + todo DAG
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### 11.2 — 选择 runnable task
|
|
158
|
-
|
|
159
|
-
选择条件:
|
|
160
|
-
- `lifecycle` 属于 `{pending, needs_revalidation}`
|
|
161
|
-
- `requires` 中每个依赖都满足对应 gate
|
|
162
|
-
- 不被 unresolved blocker 阻塞
|
|
163
|
-
- 未超过 retry 上限
|
|
164
|
-
|
|
165
|
-
如果 0 个 runnable task 且 phase 未完成:
|
|
166
|
-
```
|
|
167
|
-
├── 全部 blocked → workflow_mode = awaiting_user,展示所有 blocker
|
|
168
|
-
└── 全部等待 review → 触发 batch review (L1) 或等待 L2 review 完成
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### 11.3 — 构建 executor 上下文 + 串行派发
|
|
172
|
-
|
|
173
|
-
executor 上下文传递协议 (orchestrator → executor):
|
|
174
|
-
```
|
|
175
|
-
├── task_spec: 从 phases/*.md 提取当前 task 的规格段落
|
|
176
|
-
├── research_decisions: 从 research_basis 引用的 decision 摘要
|
|
177
|
-
├── predecessor_outputs: 前置依赖 task 的 files_changed + checkpoint_commit
|
|
178
|
-
├── project_conventions: CLAUDE.md 路径 (executor 自行读取)
|
|
179
|
-
├── workflows: 需加载的工作流文件路径 (如 tdd-cycle.md)
|
|
180
|
-
└── constraints: retry_count / level / review_required
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
派发 `executor` 子代理执行单个 task。
|
|
184
|
-
|
|
185
|
-
### 11.4 — 处理 executor 结果
|
|
186
|
-
|
|
187
|
-
严格按 agent result contract 处理:
|
|
188
|
-
```
|
|
189
|
-
├── checkpointed → 写入 checkpoint commit + evidence refs → 进入审查 (11.5)
|
|
190
|
-
├── blocked → 写入 blocked_reason / unblock_condition
|
|
191
|
-
│ → 编排器检查 decisions 数组,能自动回答则重新派发
|
|
192
|
-
│ → 不能回答 → workflow_mode = awaiting_user,向用户转达
|
|
193
|
-
├── failed → retry_count + 1
|
|
194
|
-
│ → 未超限 → 重新派发 executor
|
|
195
|
-
│ → 超限 (3次) 或返回 [FAILED] 且错误指纹重复
|
|
196
|
-
│ 或修复尝试未收敛 → 触发 debugger (见下方)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
**Debugger 触发流程:**
|
|
200
|
-
1. 编排器派发 `debugger` 子代理,传入: 错误信息 + executor 修复尝试记录 + 相关代码路径
|
|
201
|
-
2. debugger 返回: 根因分析 + 修复方向建议
|
|
202
|
-
3. 编排器决定:
|
|
203
|
-
- 带修复方向重新派发 executor
|
|
204
|
-
- 标记 task failed
|
|
205
|
-
- 标记 phase failed
|
|
206
|
-
|
|
207
|
-
**Decisions 累积:**
|
|
208
|
-
- executor 返回 `[DECISION]` → 编排器追加到 `state.json` 的 `decisions` 数组
|
|
209
|
-
- 每条 decision 记录: `id` / `task` / `summary` / `phase`
|
|
210
|
-
- decisions 跨 task、跨 phase、跨 `/clear` + `/gsd:resume` 持久保留
|
|
211
|
-
- 编排器收到 `[BLOCKED]` 时,先查 `decisions` 数组尝试自动回答
|
|
212
|
-
|
|
213
|
-
### 11.5 — 分层审查
|
|
214
|
-
|
|
215
|
-
```
|
|
216
|
-
├── L0: checkpoint commit 后可直接 accepted (无需 reviewer)
|
|
217
|
-
├── L1: phase 结束后批量 reviewer 审查
|
|
218
|
-
│ → 派发 reviewer 子代理,scope = phase
|
|
219
|
-
└── L2: checkpoint commit 后立即独立审查
|
|
220
|
-
→ 派发 reviewer 子代理,scope = task
|
|
221
|
-
→ 未 accepted 前不释放其下游依赖
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**审查级别运行时重分类:**
|
|
225
|
-
- executor 报告 `contract_changed: true` + 涉及 auth/payment/public API → 自动升级为 L2
|
|
226
|
-
- executor 标注 `[LEVEL-UP]` → 编排器采纳
|
|
227
|
-
- 不主动降级 (安全优先)
|
|
228
|
-
|
|
229
|
-
### 11.6 — 处理 reviewer 结果
|
|
230
|
-
|
|
231
|
-
```
|
|
232
|
-
├── 无 Critical → 更新 accepted 状态 + evidence refs
|
|
233
|
-
└── 有 Critical → 标记返工 task + 失效传播 → 重新审查 (最多 3 轮)
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**返工失效传播规则:**
|
|
237
|
-
- 返工修改了 contract / schema / shared behavior:
|
|
238
|
-
→ 所有直接和间接依赖 task → `needs_revalidation`
|
|
239
|
-
→ 清空其旧 `evidence_refs`
|
|
240
|
-
→ 已 accepted 则退回到 `checkpointed` 或 `pending_review`
|
|
241
|
-
- 返工只影响局部实现、外部契约未变:
|
|
242
|
-
→ 下游 task 保持现状
|
|
243
|
-
→ 但受影响验证范围必须重跑并刷新 evidence
|
|
244
|
-
- 触发判定: `contract_changed` (executor 运行时报告) 是主触发源
|
|
245
|
-
`invalidate_downstream_on_change` (planner 静态标记) 是预判辅助
|
|
246
|
-
→ executor 报告 `contract_changed: true` → 一定传播
|
|
247
|
-
→ planner 标记但 executor 报告 false → 不传播 (以运行时实际为准)
|
|
248
|
-
|
|
249
|
-
### 11.7 — Phase handoff gate
|
|
250
|
-
|
|
251
|
-
<HARD-GATE id="phase-handoff">
|
|
252
|
-
所有条件必须满足才能进入下一 phase:
|
|
253
|
-
- [ ] 所有 required task = `accepted`
|
|
254
|
-
- [ ] required review = `passed`
|
|
255
|
-
- [ ] critical issues = 0
|
|
256
|
-
- [ ] tests/lint/typecheck 满足计划验证条件
|
|
257
|
-
- [ ] 方向校验: 当前阶段产出是否仍与 plan.md 中的项目目标一致?
|
|
258
|
-
|
|
259
|
-
→ 全部满足 → 自动进入下一阶段
|
|
260
|
-
→ 任一不满足 → 标注问题,尝试修复,3 次失败停止
|
|
261
|
-
→ 方向漂移 → workflow_mode = awaiting_user,展示偏差让用户决定
|
|
262
|
-
</HARD-GATE>
|
|
263
|
-
|
|
264
|
-
### 11.8 — 批量更新 state.json
|
|
265
|
-
|
|
266
|
-
阶段完成后,编排器批量更新 state.json:
|
|
267
|
-
- 更新 phase lifecycle → `accepted`
|
|
268
|
-
- 更新 phase_handoff 信息
|
|
269
|
-
- 归档旧 phase 的 evidence (只保留当前 phase 和上一 phase)
|
|
270
|
-
- 推进 `current_phase` 到下一个 pending phase
|
|
271
|
-
|
|
272
|
-
**规则:** 只有编排器写 state.json,避免并发竞态。
|
|
273
|
-
|
|
274
|
-
### 11.9 — 上下文检查
|
|
275
|
-
|
|
276
|
-
每次派发子代理前和阶段切换时检查上下文健康度:
|
|
277
|
-
|
|
278
|
-
```
|
|
279
|
-
remaining < 35%:
|
|
280
|
-
1. 保存完整状态到 state.json
|
|
281
|
-
2. workflow_mode = awaiting_clear
|
|
282
|
-
3. 输出: "上下文剩余 <35%,已保存进度。请执行 /clear 然后 /gsd:resume 继续"
|
|
283
|
-
4. 停止执行
|
|
284
|
-
|
|
285
|
-
remaining < 25%:
|
|
286
|
-
1. 紧急保存状态到 state.json
|
|
287
|
-
2. workflow_mode = awaiting_clear
|
|
288
|
-
3. 输出: "上下文即将耗尽,已保存进度。请立即执行 /clear 然后 /gsd:resume"
|
|
289
|
-
4. 立即停止
|
|
290
|
-
```
|
|
291
|
-
|
|
151
|
+
编排器必须严格按照该参考文档中的步骤顺序执行:
|
|
152
|
+
加载 phase → 选择 task → 构建上下文 → 派发 executor → 处理结果 → 审查 → phase handoff → 批量更新 → 上下文检查
|
|
292
153
|
</execution_loop>
|
|
293
154
|
|
|
294
|
-
### 依赖门槛语义 (Gate-aware dependencies)
|
|
295
|
-
|
|
296
|
-
```json
|
|
297
|
-
{ "kind": "task", "id": "2.2", "gate": "checkpoint" } // 低风险内部串接
|
|
298
|
-
{ "kind": "task", "id": "2.3", "gate": "accepted" } // 默认安全门槛
|
|
299
|
-
{ "kind": "phase", "id": 2, "gate": "phase_complete" } // 跨 phase 依赖
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
- `checkpoint` — 允许依赖未独立验收的实现检查点;只适合低风险内部串接
|
|
303
|
-
- `accepted` — 默认安全门槛;适合共享行为、公共接口、L2 风险任务
|
|
304
|
-
- `phase_complete` — 跨 phase 依赖;只有 phase handoff 完成后才释放
|
|
305
|
-
- 默认值: 如果 planner 没显式放宽,则依赖按 `accepted` 处理
|
|
306
|
-
|
|
307
155
|
## STEP 12 — 最终报告
|
|
308
156
|
|
|
309
157
|
全部 phase 完成后,输出最终报告:
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
// 3. When remaining context drops below thresholds, injects a warning
|
|
10
10
|
// via hookSpecificOutput.additionalContext
|
|
11
11
|
//
|
|
12
|
-
//
|
|
12
|
+
// Only active when GSD project is running (has_gsd = true in bridge file).
|
|
13
|
+
// Non-GSD sessions exit early — Claude's auto-compaction handles context.
|
|
14
|
+
//
|
|
15
|
+
// Thresholds (GSD sessions only):
|
|
13
16
|
// WARNING (remaining <= 35%): Agent should wrap up current task
|
|
14
17
|
// CRITICAL (remaining <= 25%): Agent must stop and save state
|
|
15
18
|
//
|
|
@@ -33,11 +36,13 @@ process.stdin.on('end', () => {
|
|
|
33
36
|
clearTimeout(stdinTimeout);
|
|
34
37
|
try {
|
|
35
38
|
const data = JSON.parse(input);
|
|
36
|
-
const
|
|
39
|
+
const rawSessionId = data.session_id;
|
|
37
40
|
|
|
38
|
-
if (!
|
|
41
|
+
if (!rawSessionId) {
|
|
39
42
|
process.exit(0);
|
|
40
43
|
}
|
|
44
|
+
const sessionId = String(rawSessionId).replace(/[^a-zA-Z0-9_-]/g, '');
|
|
45
|
+
if (!sessionId) process.exit(0);
|
|
41
46
|
|
|
42
47
|
const tmpDir = os.tmpdir();
|
|
43
48
|
const metricsPath = path.join(tmpDir, `gsd-ctx-${sessionId}.json`);
|
|
@@ -56,9 +61,10 @@ process.stdin.on('end', () => {
|
|
|
56
61
|
process.exit(0);
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
// Ignore stale metrics
|
|
64
|
+
// Ignore stale metrics (treat missing timestamp as stale)
|
|
60
65
|
const now = Math.floor(Date.now() / 1000);
|
|
61
|
-
|
|
66
|
+
const metricAge = now - (metrics.timestamp || 0);
|
|
67
|
+
if (metricAge > STALE_SECONDS) {
|
|
62
68
|
process.exit(0);
|
|
63
69
|
}
|
|
64
70
|
|
|
@@ -94,20 +100,19 @@ process.stdin.on('end', () => {
|
|
|
94
100
|
// Use bridge data to avoid extra filesystem check
|
|
95
101
|
const isGsdActive = metrics.has_gsd === true;
|
|
96
102
|
|
|
103
|
+
// Non-GSD sessions: don't interfere — let Claude's auto-compaction handle it
|
|
104
|
+
if (!isGsdActive) {
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
|
|
97
108
|
let message;
|
|
98
109
|
if (isCritical) {
|
|
99
|
-
message =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
+ 'set workflow_mode = awaiting_clear via gsd-state-update, and tell user to /clear then /gsd:resume.'
|
|
103
|
-
: `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. `
|
|
104
|
-
+ 'Context is nearly exhausted. Inform the user that context is low and ask how they want to proceed.';
|
|
110
|
+
message = `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. `
|
|
111
|
+
+ 'Context is nearly exhausted. Complete current task checkpoint immediately, '
|
|
112
|
+
+ 'set workflow_mode = awaiting_clear via gsd-state-update, and tell user to /clear then /gsd:resume.';
|
|
105
113
|
} else {
|
|
106
|
-
message =
|
|
107
|
-
|
|
108
|
-
+ 'Context is getting limited. Avoid starting new complex work. Complete current task then save state.'
|
|
109
|
-
: `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. `
|
|
110
|
-
+ 'Be aware that context is getting limited. Avoid unnecessary exploration or starting new complex work.';
|
|
114
|
+
message = `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. `
|
|
115
|
+
+ 'Context is getting limited. Avoid starting new complex work. Complete current task then save state.';
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
const output = {
|
|
@@ -118,7 +123,8 @@ process.stdin.on('end', () => {
|
|
|
118
123
|
};
|
|
119
124
|
|
|
120
125
|
process.stdout.write(JSON.stringify(output));
|
|
121
|
-
} catch {
|
|
126
|
+
} catch (e) {
|
|
127
|
+
if (process.env.GSD_DEBUG) process.stderr.write(`gsd-context-monitor: ${e.message}\n`);
|
|
122
128
|
process.exit(0);
|
|
123
129
|
}
|
|
124
130
|
});
|
|
@@ -53,7 +53,7 @@ try {
|
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
// Atomic write to avoid corruption
|
|
56
|
-
const tmpPath = settingsPath +
|
|
56
|
+
const tmpPath = settingsPath + `.gsd-tmp-${process.pid}`;
|
|
57
57
|
fs.writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n');
|
|
58
58
|
fs.renameSync(tmpPath, settingsPath);
|
|
59
59
|
} catch {
|
package/hooks/gsd-statusline.cjs
CHANGED
|
@@ -17,7 +17,8 @@ process.stdin.on('end', () => {
|
|
|
17
17
|
const data = JSON.parse(input);
|
|
18
18
|
const model = data.model?.display_name || 'Claude';
|
|
19
19
|
const cwd = data.workspace?.current_dir || process.cwd();
|
|
20
|
-
const session = data.session_id || '';
|
|
20
|
+
const session = String(data.session_id || '').replace(/[^a-zA-Z0-9_-]/g, '');
|
|
21
|
+
if (!session) process.exit(0); // Reject empty session ID to avoid bridge file collision
|
|
21
22
|
const remaining = data.context_window?.remaining_percentage;
|
|
22
23
|
|
|
23
24
|
// Current GSD task from state.json
|
|
@@ -64,26 +65,27 @@ process.stdin.on('end', () => {
|
|
|
64
65
|
}));
|
|
65
66
|
fs.renameSync(tmpBridge, bridgePath);
|
|
66
67
|
}
|
|
67
|
-
} catch {
|
|
68
|
-
|
|
68
|
+
} catch (e) {
|
|
69
|
+
if (process.env.GSD_DEBUG) process.stderr.write(`gsd-statusline: bridge write failed: ${e.message}\n`);
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
// Also write to .gsd/.context-health for MCP server reads (skip if unchanged)
|
|
73
|
+
// Also write to .gsd/.context-health for MCP server reads (atomic, skip if unchanged)
|
|
73
74
|
try {
|
|
74
75
|
const healthPath = path.join(gsdDir, '.context-health');
|
|
75
|
-
|
|
76
|
-
if (current !== String(remaining)) {
|
|
77
|
-
fs.writeFileSync(healthPath, String(remaining));
|
|
78
|
-
}
|
|
79
|
-
} catch {
|
|
80
|
-
// File doesn't exist yet or .gsd/ missing — ensure dir exists then atomic write
|
|
76
|
+
let needsHealthWrite = true;
|
|
81
77
|
try {
|
|
78
|
+
const current = fs.readFileSync(healthPath, 'utf8').trim();
|
|
79
|
+
if (current === String(remaining)) needsHealthWrite = false;
|
|
80
|
+
} catch { /* file doesn't exist yet */ }
|
|
81
|
+
if (needsHealthWrite) {
|
|
82
82
|
fs.mkdirSync(gsdDir, { recursive: true });
|
|
83
|
-
const tmpHealth = path.join(gsdDir, `.context-health.${process.pid}.tmp`);
|
|
83
|
+
const tmpHealth = path.join(gsdDir, `.context-health.${process.pid}-${Date.now()}.tmp`);
|
|
84
84
|
fs.writeFileSync(tmpHealth, String(remaining));
|
|
85
|
-
fs.renameSync(tmpHealth,
|
|
86
|
-
}
|
|
85
|
+
fs.renameSync(tmpHealth, healthPath);
|
|
86
|
+
}
|
|
87
|
+
} catch (e) {
|
|
88
|
+
if (process.env.GSD_DEBUG) process.stderr.write(`gsd-statusline: context-health write failed: ${e.message}\n`);
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
// Progress bar (10 segments)
|
|
@@ -108,7 +110,7 @@ process.stdin.on('end', () => {
|
|
|
108
110
|
} else {
|
|
109
111
|
process.stdout.write(`\x1b[2m${model}\x1b[0m \u2502 \x1b[2m${dirname}\x1b[0m${ctx}`);
|
|
110
112
|
}
|
|
111
|
-
} catch {
|
|
112
|
-
|
|
113
|
+
} catch (e) {
|
|
114
|
+
if (process.env.GSD_DEBUG) process.stderr.write(`gsd-statusline: ${e.message}\n`);
|
|
113
115
|
}
|
|
114
116
|
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Evidence 系统规格参考
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
Evidence 是 GSD-Lite 的验证证据系统,用于记录 task 和 phase 的执行/审查证据。存储在 `state.json` 的 `evidence` 字段中,以 key-value 对象形式组织。
|
|
6
|
+
|
|
7
|
+
## Evidence 对象结构
|
|
8
|
+
|
|
9
|
+
`state.evidence` 是一个扁平对象,key 为 evidence ID,value 为 evidence 数据对象。
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"evidence": {
|
|
14
|
+
"ev:test:phase-1": {
|
|
15
|
+
"id": "ev:test:phase-1",
|
|
16
|
+
"scope": "task:1.2",
|
|
17
|
+
"type": "test",
|
|
18
|
+
...
|
|
19
|
+
},
|
|
20
|
+
"ev:lint:2.3": {
|
|
21
|
+
"id": "ev:lint:2.3",
|
|
22
|
+
"scope": "task:2.3",
|
|
23
|
+
"type": "lint",
|
|
24
|
+
...
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 必需字段
|
|
31
|
+
|
|
32
|
+
| 字段 | 类型 | 约束 | 说明 |
|
|
33
|
+
|------|------|------|------|
|
|
34
|
+
| `id` | string | 非空 | evidence 唯一标识符 |
|
|
35
|
+
| `scope` | string | 非空 | 作用域标识,格式见下方 |
|
|
36
|
+
|
|
37
|
+
### 验证规则
|
|
38
|
+
|
|
39
|
+
`addEvidence()` 入参校验:
|
|
40
|
+
- `id` 必须是非空字符串
|
|
41
|
+
- `data` 必须是非 null 的普通对象
|
|
42
|
+
- `data.scope` 必须是字符串
|
|
43
|
+
|
|
44
|
+
`state.evidence` 整体校验 (`validateState()`):
|
|
45
|
+
- 必须是普通对象 (isPlainObject)
|
|
46
|
+
|
|
47
|
+
## ID 格式约定
|
|
48
|
+
|
|
49
|
+
Evidence ID 采用 `ev:<type>:<scope>` 格式:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
ev:test:phase-1 # phase 级测试证据
|
|
53
|
+
ev:lint:phase-2 # phase 级 lint 证据
|
|
54
|
+
ev:test:users-update # task 级测试证据
|
|
55
|
+
ev:typecheck:phase-2 # phase 级类型检查证据
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
此格式为约定 (convention),由 executor/reviewer 生成时遵守。系统不强制校验 ID 格式。
|
|
59
|
+
|
|
60
|
+
## Scope 格式
|
|
61
|
+
|
|
62
|
+
Scope 标识 evidence 所属的作用域。核心格式为 `task:X.Y`:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
task:1.2 -> phase 1, task 2
|
|
66
|
+
task:2.3 -> phase 2, task 3
|
|
67
|
+
task:3.1 -> phase 3, task 1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### parseScopePhase 解析
|
|
71
|
+
|
|
72
|
+
`parseScopePhase(scope)` 从 scope 字符串提取 phase 编号:
|
|
73
|
+
|
|
74
|
+
- 正则: `/^task:(\d+)\./`
|
|
75
|
+
- `"task:1.2"` -> 返回 `1`
|
|
76
|
+
- `"task:2.3"` -> 返回 `2`
|
|
77
|
+
- `"phase:1"` -> 返回 `null` (不匹配 task: 前缀)
|
|
78
|
+
- `null`/`undefined` -> 返回 `null`
|
|
79
|
+
|
|
80
|
+
此函数用于 evidence 归档时判断 evidence 所属 phase。
|
|
81
|
+
|
|
82
|
+
来源: `parseScopePhase()` in `src/tools/state.js`
|
|
83
|
+
|
|
84
|
+
## 容量限制与自动裁剪
|
|
85
|
+
|
|
86
|
+
### MAX_EVIDENCE_ENTRIES
|
|
87
|
+
|
|
88
|
+
- 硬限制: `200` 条
|
|
89
|
+
- 定义位置: `src/tools/state.js` 顶层常量
|
|
90
|
+
|
|
91
|
+
### 自动裁剪触发
|
|
92
|
+
|
|
93
|
+
`addEvidence()` 每次添加 evidence 后检查:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
if (Object.keys(state.evidence).length > MAX_EVIDENCE_ENTRIES) {
|
|
97
|
+
-> 调用 _pruneEvidenceFromState(state, currentPhase, gsdDir)
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 裁剪逻辑
|
|
102
|
+
|
|
103
|
+
`_pruneEvidenceFromState(state, currentPhase, gsdDir)`:
|
|
104
|
+
|
|
105
|
+
1. 计算阈值: `threshold = currentPhase - 1`
|
|
106
|
+
2. 遍历所有 evidence 条目
|
|
107
|
+
3. 对每条 evidence 调用 `parseScopePhase(entry.scope)` 提取 phase 编号
|
|
108
|
+
4. 如果 `phaseNum !== null && phaseNum < threshold` -> 标记为待归档
|
|
109
|
+
5. 其余保留 (包括 scope 无法解析的条目)
|
|
110
|
+
|
|
111
|
+
规则: 保留当前 phase 和前一个 phase 的 evidence,归档更早 phase 的 evidence。
|
|
112
|
+
|
|
113
|
+
## 归档生命周期
|
|
114
|
+
|
|
115
|
+
### 归档路径
|
|
116
|
+
|
|
117
|
+
`.gsd/evidence-archive.json`
|
|
118
|
+
|
|
119
|
+
### 归档流程
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
_pruneEvidenceFromState()
|
|
123
|
+
-> 分离 toArchive / toKeep
|
|
124
|
+
-> 读取现有 evidence-archive.json (不存在则 {})
|
|
125
|
+
-> Object.assign(archive, toArchive) 合并
|
|
126
|
+
-> writeJson(archivePath, archive) 写入归档文件
|
|
127
|
+
-> state.evidence = toKeep 更新内存中的 state
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 触发时机
|
|
131
|
+
|
|
132
|
+
1. `addEvidence()` — 当 evidence 数量超过 MAX_EVIDENCE_ENTRIES 时自动触发
|
|
133
|
+
2. `phaseComplete()` — phase 完成后主动触发 (在 phase lifecycle 转换为 accepted 之后)
|
|
134
|
+
3. `pruneEvidence()` — 显式调用的外部接口
|
|
135
|
+
|
|
136
|
+
### 归档特性
|
|
137
|
+
|
|
138
|
+
- 归档是追加式的: 新归档条目与已有归档 merge
|
|
139
|
+
- 归档后 state.evidence 中的对应条目被移除
|
|
140
|
+
- 归档文件持久保存,不会被自动清理
|
|
141
|
+
|
|
142
|
+
## Evidence 来源
|
|
143
|
+
|
|
144
|
+
### Executor 结果
|
|
145
|
+
|
|
146
|
+
`handleExecutorResult()` 处理 executor 返回的 evidence:
|
|
147
|
+
|
|
148
|
+
1. `result.evidence` 数组写入 task 的 `evidence_refs`
|
|
149
|
+
2. 对数组中每个符合条件的条目 (有 `id` 和 `scope` 字符串字段) 调用 `addEvidence()` 存入 `state.evidence`
|
|
150
|
+
3. outcome 为 `checkpointed` / `blocked` / `failed` 时均会保存 evidence_refs
|
|
151
|
+
|
|
152
|
+
### Reviewer 结果
|
|
153
|
+
|
|
154
|
+
`handleReviewerResult()` 处理 reviewer 返回的 evidence:
|
|
155
|
+
|
|
156
|
+
1. 同样遍历 `result.evidence` 数组
|
|
157
|
+
2. 对符合条件的条目调用 `addEvidence()` 存入 `state.evidence`
|
|
158
|
+
|
|
159
|
+
### Task 上的 evidence_refs
|
|
160
|
+
|
|
161
|
+
每个 task 对象有 `evidence_refs` 数组字段:
|
|
162
|
+
- 类型: `Array` (validateState 要求)
|
|
163
|
+
- 初始值: `[]`
|
|
164
|
+
- 更新时机: executor checkpointed / blocked / failed 时从 result.evidence 覆写
|
|
165
|
+
- 清空时机: `propagateInvalidation()` 或 reviewer 标记 rework 时清空为 `[]`
|
|
166
|
+
|
|
167
|
+
来源: `addEvidence()`, `_pruneEvidenceFromState()`, `pruneEvidence()`, `phaseComplete()` in `src/tools/state.js`; `handleExecutorResult()`, `handleReviewerResult()` in `src/tools/orchestrator.js`
|