gsd-lite 0.4.0 → 0.4.2

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.
@@ -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.4.0",
16
+ "version": "0.4.2",
17
17
  "keywords": [
18
18
  "orchestration",
19
19
  "mcp",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "AI orchestration tool for Claude Code — GSD management shell + Superpowers quality core",
5
5
  "author": {
6
6
  "name": "sdsrss",
package/commands/prd.md CHANGED
@@ -134,6 +134,15 @@ argument-hint: File path to requirements doc, or inline description text
134
134
 
135
135
  编排器必须严格按照该参考文档中的步骤顺序执行:
136
136
  加载 phase → 选择 task → 构建上下文 → 派发 executor → 处理结果 → 审查 → phase handoff → 批量更新 → 上下文检查
137
+
138
+ **自动执行循环:** 进入执行后,持续循环直到遇到终止条件:
139
+ 1. 调用 `orchestrator-resume` 获取 action
140
+ 2. 按 action 派发对应子代理 (executor/reviewer/researcher/debugger)
141
+ 3. 收到结果后调用对应 `orchestrator-handle-*-result`
142
+ 4. 回到步骤 1
143
+ 5. 终止: action ∈ {idle, awaiting_user, completed, failed, await_manual_intervention}
144
+
145
+ 不要在循环中间停下来等用户确认 — 让编排器驱动。`complete_phase` action → 调 `phase-complete` MCP tool → 自动推进下一 phase。
137
146
  </execution_loop>
138
147
 
139
148
  ## STEP 12 — 全部完成
@@ -212,6 +212,79 @@ description: Resume project execution from saved state with workspace validation
212
212
 
213
213
  所有展示数据从 canonical fields 实时推导,不使用 derived fields。
214
214
 
215
+ ## STEP 5: 自动执行循环
216
+
217
+ <HARD-GATE id="auto-execution-loop">
218
+ STEP 3 完成初次恢复后,进入自动执行循环。这是编排器的核心 —— 不要停在某一步等待用户,除非遇到终止条件。
219
+
220
+ ```
221
+ 循环入口:
222
+ 1. 调用 MCP tool `orchestrator-resume` 获取 action
223
+ 2. 根据 action 分派:
224
+
225
+ dispatch_executor:
226
+ → 使用 Agent tool 派发 executor 子代理 (subagent_type: gsd:executor)
227
+ → 传入 orchestrator 返回的 executor_context
228
+ → 收到 executor 结果后 → 调用 MCP tool `orchestrator-handle-executor-result`
229
+ → 回到步骤 1
230
+
231
+ dispatch_reviewer:
232
+ → 使用 Agent tool 派发 reviewer 子代理 (subagent_type: gsd:reviewer)
233
+ → 传入 review_targets / current_review
234
+ → 收到 reviewer 结果后 → 调用 MCP tool `orchestrator-handle-reviewer-result`
235
+ → 回到步骤 1
236
+
237
+ dispatch_researcher:
238
+ → 使用 Agent tool 派发 researcher 子代理 (subagent_type: gsd:researcher)
239
+ → 传入过期的研究信息
240
+ → 收到 researcher 结果后 → 调用 MCP tool `orchestrator-handle-researcher-result`
241
+ → 回到步骤 1
242
+
243
+ dispatch_debugger:
244
+ → 使用 Agent tool 派发 debugger 子代理 (subagent_type: gsd:debugger)
245
+ → 传入 debug_target
246
+ → 收到 debugger 结果后 → 调用 MCP tool `orchestrator-handle-debugger-result`
247
+ → 回到步骤 1
248
+
249
+ trigger_review:
250
+ → 直接派发 reviewer,scope 和 targets 从 action 响应中获取
251
+ → 回到步骤 1
252
+
253
+ complete_phase:
254
+ → 调用 MCP tool `phase-complete`,传入 phase_id + run_verify: true
255
+ → 回到步骤 1 (编排器会自动推进到下一 phase)
256
+
257
+ retry_executor:
258
+ → 重新调用 orchestrator-resume 获取更新后的 executor 上下文
259
+ → 回到步骤 1
260
+
261
+ rollback_to_dirty_phase:
262
+ → 编排器已自动回滚 current_phase,输出回滚通知
263
+ → 回到步骤 1
264
+
265
+ continue_execution:
266
+ → 直接回到步骤 1
267
+
268
+ 3. 终止条件 — 遇到以下 action 时退出循环:
269
+
270
+ idle → 输出 "无可执行任务",停止
271
+ awaiting_user → 展示 blockers / drift 信息,等待用户输入
272
+ await_manual_intervention → 展示需要人工干预的信息,停止
273
+ noop (completed) → 展示完成报告,停止
274
+ await_recovery_decision (failed) → 展示失败信息和恢复选项,停止
275
+
276
+ 4. 上下文安全阀:
277
+ 每次循环迭代前检查上下文健康度
278
+ remaining <= 35% → 保存状态 + 输出 "请 /clear 后 /gsd:resume" → 退出循环
279
+ ```
280
+
281
+ **关键原则:**
282
+ - 循环是连续的: dispatch → handle result → resume → dispatch → ...
283
+ - 不在中间步骤停下来等用户确认(除非是终止条件)
284
+ - 每次 handle result 后立即 resume,让编排器决定下一步
285
+ - Phase 审查通过后 → complete_phase → 自动推进下一 phase → 继续执行
286
+ </HARD-GATE>
287
+
215
288
  </process>
216
289
 
217
290
  <EXTREMELY-IMPORTANT>
@@ -221,4 +294,5 @@ description: Resume project execution from saved state with workspace validation
221
294
  - awaiting_user / reconcile_workspace / replan_required 模式下不自动执行代码
222
295
  - 只有编排器写 state.json,子代理不直接写
223
296
  - 上下文 < 35% → 保存状态 + workflow_mode = awaiting_clear + 停止执行
297
+ - **进入自动执行循环后,不要在循环中间停下来等用户 — 让编排器驱动**
224
298
  </EXTREMELY-IMPORTANT>
package/commands/start.md CHANGED
@@ -162,6 +162,15 @@ argument-hint: Optional feature or project description
162
162
 
163
163
  编排器必须严格按照该参考文档中的步骤顺序执行:
164
164
  加载 phase → 选择 task → 构建上下文 → 派发 executor → 处理结果 → 审查 → phase handoff → 批量更新 → 上下文检查
165
+
166
+ **自动执行循环:** 进入执行后,持续循环直到遇到终止条件:
167
+ 1. 调用 `orchestrator-resume` 获取 action
168
+ 2. 按 action 派发对应子代理 (executor/reviewer/researcher/debugger)
169
+ 3. 收到结果后调用对应 `orchestrator-handle-*-result`
170
+ 4. 回到步骤 1
171
+ 5. 终止: action ∈ {idle, awaiting_user, completed, failed, await_manual_intervention}
172
+
173
+ 不要在循环中间停下来等用户确认 — 让编排器驱动。`complete_phase` action → 调 `phase-complete` MCP tool → 自动推进下一 phase。
165
174
  </execution_loop>
166
175
 
167
176
  ## STEP 12 — 最终报告
package/install.js CHANGED
@@ -136,7 +136,7 @@ export function main() {
136
136
  copyDir(localNM, join(RUNTIME_DIR, 'node_modules'), 'runtime/node_modules (copied)');
137
137
  } else if (!DRY_RUN) {
138
138
  log(' ⧗ Installing runtime dependencies...');
139
- execSync('npm install --omit=dev', { cwd: RUNTIME_DIR, stdio: 'pipe' });
139
+ execSync('npm ci --omit=dev', { cwd: RUNTIME_DIR, stdio: 'pipe' });
140
140
  log(' ✓ runtime dependencies installed');
141
141
  } else {
142
142
  log(' [dry-run] Would install runtime dependencies');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-lite",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "AI orchestration tool for Claude Code — GSD management shell + Superpowers quality core",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,7 +39,8 @@
39
39
  "cli.js",
40
40
  "launcher.js",
41
41
  "install.js",
42
- "uninstall.js"
42
+ "uninstall.js",
43
+ "package-lock.json"
43
44
  ],
44
45
  "engines": {
45
46
  "node": ">=20.0.0"
package/src/schema.js CHANGED
@@ -387,6 +387,37 @@ export function validateState(state) {
387
387
  }
388
388
  }
389
389
  }
390
+ // P2-9: workflow_mode consistency — reviewing modes require matching current_review
391
+ if (state.workflow_mode === 'reviewing_phase' || state.workflow_mode === 'reviewing_task') {
392
+ const expectedScope = state.workflow_mode === 'reviewing_phase' ? 'phase' : 'task';
393
+ if (!state.current_review || state.current_review.scope !== expectedScope) {
394
+ errors.push(`workflow_mode "${state.workflow_mode}" requires current_review with scope="${expectedScope}"`);
395
+ }
396
+ }
397
+ // P2-9: current_review.scope_id must reference an existing phase or task
398
+ if (state.current_review && state.current_review.scope_id != null && Array.isArray(state.phases)) {
399
+ if (state.current_review.scope === 'phase') {
400
+ if (!state.phases.some(p => p.id === state.current_review.scope_id)) {
401
+ errors.push(`current_review.scope_id ${state.current_review.scope_id} references non-existent phase`);
402
+ }
403
+ } else if (state.current_review.scope === 'task') {
404
+ const curPhase = state.phases.find(p => p.id === state.current_phase);
405
+ if (curPhase && Array.isArray(curPhase.todo) && !curPhase.todo.some(t => t.id === state.current_review.scope_id)) {
406
+ errors.push(`current_review.scope_id "${state.current_review.scope_id}" references non-existent task in phase ${state.current_phase}`);
407
+ }
408
+ }
409
+ }
410
+ // P2-9: accepted phase must not contain non-accepted tasks
411
+ if (Array.isArray(state.phases)) {
412
+ for (const phase of state.phases) {
413
+ if (phase.lifecycle === 'accepted' && Array.isArray(phase.todo)) {
414
+ const nonAccepted = phase.todo.filter(t => t.lifecycle !== 'accepted');
415
+ if (nonAccepted.length > 0) {
416
+ errors.push(`Accepted phase ${phase.id} contains non-accepted tasks: ${nonAccepted.map(t => `${t.id}:${t.lifecycle}`).join(', ')}`);
417
+ }
418
+ }
419
+ }
420
+ }
390
421
  if (Array.isArray(state.phases)) {
391
422
  if (typeof state.total_phases === 'number' && state.total_phases !== state.phases.length) {
392
423
  errors.push(`total_phases (${state.total_phases}) does not match phases.length (${state.phases.length})`);