super-engineer-workflow 0.1.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/CONTRIBUTING.md +34 -0
  3. package/LICENSE +21 -0
  4. package/README.md +300 -0
  5. package/SECURITY.md +21 -0
  6. package/bin/super-engineer.js +19 -0
  7. package/docs/se/345/221/275/344/273/244/345/215/217/350/256/256.md +335 -0
  8. package/docs//344/270/255/346/226/207/344/275/277/347/224/250/346/211/213/345/206/214.md +707 -0
  9. package/docs//345/205/254/345/274/200/345/217/221/345/270/203/346/243/200/346/237/245/346/270/205/345/215/225.md +43 -0
  10. package/docs//345/277/253/351/200/237/345/210/235/345/247/213/345/214/226/345/267/245/344/275/234/345/214/272.md +419 -0
  11. package/docs//351/241/271/347/233/256/346/236/266/346/236/204/344/270/216/350/256/276/350/256/241/350/257/264/346/230/216.md +657 -0
  12. package/package.json +55 -0
  13. package/scripts/se-cli.py +301 -0
  14. package/scripts/se-setup.py +331 -0
  15. package/scripts/se-smoke-test.py +86 -0
  16. package/super-engineer-workflow/SKILL.md +439 -0
  17. package/super-engineer-workflow/adapters/go.yml +8 -0
  18. package/super-engineer-workflow/adapters/java-gradle.yml +8 -0
  19. package/super-engineer-workflow/adapters/java-maven.yml +8 -0
  20. package/super-engineer-workflow/adapters/node-react.yml +8 -0
  21. package/super-engineer-workflow/adapters/node-vue.yml +8 -0
  22. package/super-engineer-workflow/adapters/python.yml +8 -0
  23. package/super-engineer-workflow/agents/openai.yaml +4 -0
  24. package/super-engineer-workflow/assets/config-schema.json +100 -0
  25. package/super-engineer-workflow/assets/config.example.yml +12 -0
  26. package/super-engineer-workflow/assets/plan-schema.json +362 -0
  27. package/super-engineer-workflow/assets/status-schema.json +83 -0
  28. package/super-engineer-workflow/assets/workspace.example.yml +25 -0
  29. package/super-engineer-workflow/config.example.yml +12 -0
  30. package/super-engineer-workflow/references/contracts.md +39 -0
  31. package/super-engineer-workflow/references/execution-modes.md +38 -0
  32. package/super-engineer-workflow/references/java.md +21 -0
  33. package/super-engineer-workflow/references/planning.md +45 -0
  34. package/super-engineer-workflow/references/platform-openclaw.md +10 -0
  35. package/super-engineer-workflow/references/project-docs.md +7 -0
  36. package/super-engineer-workflow/references/review-checklist.md +26 -0
  37. package/super-engineer-workflow/references/se-commands.md +582 -0
  38. package/super-engineer-workflow/references/verify-checklist.md +45 -0
  39. package/super-engineer-workflow/references/workflow.md +208 -0
  40. package/super-engineer-workflow/scripts/archive-openspec.py +110 -0
  41. package/super-engineer-workflow/scripts/bootstrap-openspec.py +42 -0
  42. package/super-engineer-workflow/scripts/common.py +3285 -0
  43. package/super-engineer-workflow/scripts/generate-discovery.py +185 -0
  44. package/super-engineer-workflow/scripts/generate-review-report.py +296 -0
  45. package/super-engineer-workflow/scripts/generate-self-check.py +185 -0
  46. package/super-engineer-workflow/scripts/generate-smart-plan.py +429 -0
  47. package/super-engineer-workflow/scripts/init-workspace.py +68 -0
  48. package/super-engineer-workflow/scripts/prepare-archive-openspec.py +186 -0
  49. package/super-engineer-workflow/scripts/propose-openspec.py +170 -0
  50. package/super-engineer-workflow/scripts/run-verify-and-report.py +399 -0
  51. package/super-engineer-workflow/scripts/run-workflow.py +506 -0
  52. package/super-engineer-workflow/scripts/update-status.py +43 -0
  53. package/super-engineer-workflow/scripts/writeback-openspec.py +311 -0
@@ -0,0 +1,506 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from common import (
10
+ create_session,
11
+ current_session_is_stale,
12
+ current_session_meta,
13
+ data_artifact_path,
14
+ ensure_status,
15
+ load_workspace_config,
16
+ now_iso,
17
+ parse_se_command,
18
+ planned_codebases,
19
+ planned_codebase,
20
+ read_json,
21
+ read_se_state,
22
+ require_se_state,
23
+ report_artifact_path,
24
+ recover_se_state_from_artifacts,
25
+ todo_path,
26
+ update_se_state,
27
+ validate_standard_session,
28
+ validate_se_state,
29
+ workflow_source,
30
+ write_managed_json,
31
+ workspace_root,
32
+ )
33
+
34
+
35
+ SCRIPT_DIR = Path(__file__).resolve().parent
36
+
37
+
38
+ SE_ROUTE_REPLY_CONSTRAINTS: dict[str, dict[str, str]] = {
39
+ "/se:propose": {
40
+ "phase": "proposed",
41
+ "allowed_next": "/se:bridge",
42
+ "forbidden_next": "/se:plan,/se:apply",
43
+ "final_reply_must": "代码暂未修改。下一步只能执行 /se:bridge,把当前 OpenSpec tasks.md 桥接为待审核 todo.md。",
44
+ },
45
+ "/se:bridge": {
46
+ "phase": "bridged",
47
+ "allowed_next": "人工审核 todo.md 后 /se:apply",
48
+ "forbidden_next": "自动执行 /se:plan,自动执行 /se:apply,代码实现",
49
+ "final_reply_must": "桥接 todo 已生成。请先人工审核 todo.md,审核通过后再发送 /se:apply。",
50
+ },
51
+ "/se:plan": {
52
+ "phase": "planned",
53
+ "allowed_next": "/se:apply",
54
+ "forbidden_next": "代码实现,review,verify",
55
+ "final_reply_must": "计划已生成。下一步只有在确认计划后执行 /se:apply。",
56
+ },
57
+ }
58
+
59
+
60
+ def run_python(script_name: str, extra_args: list[str]) -> None:
61
+ script_path = SCRIPT_DIR / script_name
62
+ result = subprocess.run(
63
+ [sys.executable, str(script_path), *extra_args],
64
+ check=False,
65
+ )
66
+ if result.returncode != 0:
67
+ raise SystemExit(result.returncode)
68
+
69
+
70
+ def load_status(workspace: Path | None) -> tuple[dict, Path]:
71
+ config = load_workspace_config(workspace)
72
+ session_meta = current_session_meta(config)
73
+ status_path = data_artifact_path(config, "status.json", session_meta)
74
+ status = ensure_status(config, session_meta, read_json(status_path, {}))
75
+ return status, status_path
76
+
77
+
78
+ def update_status_for_implement(workspace: Path | None, current_task: str, next_action: str, phase: str, progress: int, completed_task: str | None = None) -> None:
79
+ config = load_workspace_config(workspace)
80
+ session_meta = current_session_meta(config)
81
+ status_path = data_artifact_path(config, "status.json", session_meta)
82
+ status = ensure_status(config, session_meta, read_json(status_path, {}))
83
+ completed_tasks = status.get("completed_tasks", [])
84
+ if completed_task and completed_task not in completed_tasks:
85
+ completed_tasks = completed_tasks + [completed_task]
86
+ status.update(
87
+ {
88
+ "phase": phase,
89
+ "current_task": current_task,
90
+ "progress": progress,
91
+ "awaiting_confirmation": phase.startswith("wait_confirm_"),
92
+ "pending_confirmation_for": "review" if phase == "wait_confirm_implement" else "",
93
+ "next_action": next_action,
94
+ "completed_tasks": completed_tasks,
95
+ "blocked_tasks": status.get("blocked_tasks", []),
96
+ "started_at": status.get("started_at") or session_meta.get("started_at", ""),
97
+ "updated_at": now_iso(),
98
+ }
99
+ )
100
+ write_managed_json(config, status_path, status)
101
+
102
+
103
+ def command_status(workspace: Path | None) -> None:
104
+ config = load_workspace_config(workspace)
105
+ recover_se_state_from_artifacts(config)
106
+ try:
107
+ status, _ = load_status(workspace)
108
+ except FileNotFoundError:
109
+ print("尚未创建当前会话,请先执行 plan。")
110
+ status = {}
111
+ if not status:
112
+ print("尚未生成 status.json,请先执行 plan。")
113
+ else:
114
+ for key in (
115
+ "session_id",
116
+ "mode",
117
+ "phase",
118
+ "current_task",
119
+ "progress",
120
+ "awaiting_confirmation",
121
+ "pending_confirmation_for",
122
+ "next_action",
123
+ "started_at",
124
+ "finished_at",
125
+ "duration_seconds",
126
+ "notification_status",
127
+ "notification_message",
128
+ ):
129
+ print(f"{key}={status.get(key, '')}")
130
+ state = read_se_state(config)
131
+ if state:
132
+ print(f"se_phase={state.get('phase', '')}")
133
+ print(f"se_allowed_next={','.join(str(item) for item in state.get('allowed_next', []))}")
134
+ if workflow_source(config) == "todo":
135
+ standard = validate_standard_session(config, require_notification=False)
136
+ print(f"standard_session={str(bool(standard.get('valid'))).lower()}")
137
+ for error in standard.get("errors", []):
138
+ print(f"standard_error={error}")
139
+
140
+
141
+ def command_assert_standard_session(workspace: Path | None, require_notification: bool = False) -> None:
142
+ config = load_workspace_config(workspace)
143
+ result = validate_standard_session(config, require_notification=require_notification)
144
+ print(f"standard_session={str(bool(result.get('valid'))).lower()}")
145
+ if result.get("session_id"):
146
+ print(f"session_id={result.get('session_id')}")
147
+ for error in result.get("errors", []):
148
+ print(f"error={error}")
149
+ if not result.get("valid"):
150
+ raise SystemExit(1)
151
+
152
+
153
+ def command_validate_state(workspace: Path | None, command: str | None) -> None:
154
+ if not command:
155
+ raise SystemExit("缺少要校验的命令,例如 validate-state plan。")
156
+ config = load_workspace_config(workspace)
157
+ result = validate_se_state(config, command)
158
+ print(f"valid={str(bool(result.get('valid'))).lower()}")
159
+ print(f"phase={result.get('phase', '')}")
160
+ print(f"allowed_next={','.join(str(item) for item in result.get('allowed_next', []))}")
161
+ for error in result.get("errors", []):
162
+ print(f"error={error}")
163
+ if not result.get("valid"):
164
+ raise SystemExit(1)
165
+
166
+
167
+ def command_route_se(workspace: Path | None, command_text: str | None, timeout_seconds: int, force: bool = False) -> None:
168
+ if not command_text:
169
+ raise SystemExit("缺少 /se:* 命令文本。")
170
+ parsed = parse_se_command(command_text)
171
+ se_command = parsed["se_command"]
172
+ run_command = parsed["run_command"]
173
+ argument = str(parsed.get("argument", "")).strip()
174
+ print(f"se_command={se_command}")
175
+ print(f"run_command={run_command}")
176
+ if argument:
177
+ print(f"argument={argument}")
178
+ if se_command == "/se:init":
179
+ command_init(workspace)
180
+ elif se_command == "/se:propose":
181
+ command_propose_openspec(workspace, argument or None)
182
+ elif se_command == "/se:bridge":
183
+ command_bootstrap_openspec(workspace, explicit_se_bridge=True)
184
+ elif se_command == "/se:plan":
185
+ command_plan(workspace)
186
+ elif se_command == "/se:apply":
187
+ command_apply(workspace, timeout_seconds)
188
+ elif se_command == "/se:review":
189
+ command_review(workspace)
190
+ elif se_command == "/se:verify":
191
+ command_verify(workspace, timeout_seconds, force)
192
+ elif se_command == "/se:archive-check":
193
+ command_prepare_archive_openspec(workspace)
194
+ elif se_command == "/se:archive":
195
+ command_archive_openspec(workspace)
196
+ elif se_command == "/se:status":
197
+ command_status(workspace)
198
+ else:
199
+ raise SystemExit(f"不支持的 /se:* 命令:{se_command}")
200
+ print_route_reply_constraint(se_command)
201
+
202
+
203
+ def print_route_reply_constraint(se_command: str) -> None:
204
+ constraint = SE_ROUTE_REPLY_CONSTRAINTS.get(se_command)
205
+ if not constraint:
206
+ return
207
+ print("se_reply_constraint_begin")
208
+ for key in ("phase", "allowed_next", "forbidden_next", "final_reply_must"):
209
+ print(f"{key}={constraint[key]}")
210
+ print("se_reply_constraint_end")
211
+
212
+
213
+ def command_next(workspace: Path | None, timeout_seconds: int) -> None:
214
+ config = load_workspace_config(workspace)
215
+ session_meta = current_session_meta(config)
216
+ status = read_json(data_artifact_path(config, "status.json", session_meta), {})
217
+ phase = status.get("phase", "")
218
+
219
+ if phase in ("wait_confirm_plan", "plan"):
220
+ command_start_implement(workspace)
221
+ return
222
+ if phase == "implement":
223
+ command_finish_implement(workspace)
224
+ return
225
+ if phase == "self_check":
226
+ command_review(workspace)
227
+ return
228
+ if phase in ("wait_confirm_implement", "review"):
229
+ command_review(workspace)
230
+ return
231
+ if phase == "wait_confirm_review":
232
+ command_verify(workspace, timeout_seconds)
233
+ return
234
+ print(f"当前阶段无需 next:{phase}")
235
+
236
+
237
+ def command_init(workspace: Path | None) -> None:
238
+ args = ["--workspace", str(workspace)] if workspace else []
239
+ run_python("init-workspace.py", args)
240
+
241
+
242
+ def command_bootstrap_openspec(workspace: Path | None, *, explicit_se_bridge: bool = False) -> None:
243
+ if not explicit_se_bridge:
244
+ raise SystemExit(
245
+ "拒绝执行桥接:bootstrap-openspec 只能由用户显式 /se:bridge 触发。"
246
+ "请通过 route-se --command-text '/se:bridge' 或带 --explicit-se-bridge 的受控入口执行。"
247
+ )
248
+ require_se_state(load_workspace_config(workspace), "bootstrap-openspec")
249
+ args = ["--explicit-se-bridge"]
250
+ if workspace:
251
+ args.extend(["--workspace", str(workspace)])
252
+ run_python("bootstrap-openspec.py", args)
253
+
254
+
255
+ def command_propose_openspec(workspace: Path | None, change_name: str | None = None) -> None:
256
+ args = ["--workspace", str(workspace)] if workspace else []
257
+ if change_name:
258
+ args.append(change_name)
259
+ run_python("propose-openspec.py", args)
260
+ config = load_workspace_config(workspace)
261
+ state = read_se_state(config)
262
+ phase = str(state.get("phase", "")).strip()
263
+ if phase != "proposed":
264
+ raise SystemExit(
265
+ f"/se:propose 后状态必须停留在 proposed,当前 phase={phase}。"
266
+ "请停止当前回复,不要生成 todo.md,不要进入 plan/apply。"
267
+ )
268
+
269
+
270
+ def command_writeback_openspec(workspace: Path | None) -> None:
271
+ args = ["--workspace", str(workspace)] if workspace else []
272
+ run_python("writeback-openspec.py", args)
273
+
274
+
275
+ def command_prepare_archive_openspec(workspace: Path | None) -> None:
276
+ require_se_state(load_workspace_config(workspace), "prepare-archive-openspec")
277
+ args = ["--workspace", str(workspace)] if workspace else []
278
+ run_python("prepare-archive-openspec.py", args)
279
+
280
+
281
+ def command_archive_openspec(workspace: Path | None) -> None:
282
+ require_se_state(load_workspace_config(workspace), "archive-openspec")
283
+ args = ["--workspace", str(workspace)] if workspace else []
284
+ run_python("archive-openspec.py", args)
285
+
286
+
287
+ def command_plan(workspace: Path | None) -> None:
288
+ config = load_workspace_config(workspace)
289
+ require_se_state(config, "plan")
290
+ command_init(workspace)
291
+ config = load_workspace_config(workspace)
292
+ create_session(config)
293
+ command_discover(workspace)
294
+ args = ["--workspace", str(workspace)] if workspace else []
295
+ run_python("generate-smart-plan.py", args)
296
+ update_se_state(
297
+ config,
298
+ phase="planned",
299
+ last_command="/se:plan",
300
+ artifacts={
301
+ "todo": str(todo_path(config)),
302
+ "plan_json": str(data_artifact_path(config, "plan.json")),
303
+ "plan_md": str(report_artifact_path(config, "plan.md")),
304
+ },
305
+ )
306
+
307
+
308
+ def command_discover(workspace: Path | None) -> None:
309
+ args = ["--workspace", str(workspace)] if workspace else []
310
+ run_python("generate-discovery.py", args)
311
+
312
+
313
+ def command_start_implement(workspace: Path | None) -> None:
314
+ config = load_workspace_config(workspace)
315
+ require_se_state(config, "start-implement")
316
+ session_meta = current_session_meta(config)
317
+ codebases = planned_codebases(config, session_meta)
318
+ codebase = planned_codebase(config, session_meta)
319
+ if len(codebases) == 1:
320
+ current_task = f"正在实现代码修改:{codebase}"
321
+ else:
322
+ current_task = "正在实现多仓库代码修改:" + "、".join(str(item) for item in codebases)
323
+ update_status_for_implement(
324
+ workspace,
325
+ current_task=current_task,
326
+ next_action="按 plan.json 完成代码修改,完成后执行 finish-implement。",
327
+ phase="implement",
328
+ progress=45,
329
+ )
330
+ update_se_state(config, phase="implementing", last_command="/se:apply")
331
+
332
+
333
+ def command_finish_implement(workspace: Path | None) -> None:
334
+ config = load_workspace_config(workspace)
335
+ require_se_state(config, "finish-implement")
336
+ args = ["--workspace", str(workspace)] if workspace else []
337
+ run_python("generate-self-check.py", args)
338
+ update_se_state(
339
+ config,
340
+ phase="self_checked",
341
+ last_command="/se:apply",
342
+ artifacts={
343
+ "self_check_json": str(data_artifact_path(config, "self-check.json")),
344
+ "self_check_md": str(report_artifact_path(config, "self-check.md")),
345
+ },
346
+ )
347
+ if config["mode"] == "manual":
348
+ update_status_for_implement(
349
+ workspace,
350
+ current_task="实现阶段已完成。",
351
+ next_action="等待确认后执行代码审查。",
352
+ phase="wait_confirm_implement",
353
+ progress=60,
354
+ completed_task="已完成代码实现",
355
+ )
356
+ return
357
+
358
+ update_status_for_implement(
359
+ workspace,
360
+ current_task="实现阶段已完成。",
361
+ next_action="继续执行代码审查和验证。",
362
+ phase="review",
363
+ progress=60,
364
+ completed_task="已完成代码实现",
365
+ )
366
+ command_review(workspace)
367
+ command_verify(workspace, 300)
368
+ config = load_workspace_config(workspace)
369
+ verify_result = read_json(data_artifact_path(config, "verify.json"), {})
370
+ status_result = read_json(data_artifact_path(config, "status.json"), {})
371
+ if (
372
+ workflow_source(config) == "openspec"
373
+ and str(verify_result.get("result", "")).strip() == "通过"
374
+ and str(status_result.get("phase", "")).strip() == "done"
375
+ ):
376
+ command_prepare_archive_openspec(workspace)
377
+
378
+
379
+ def command_review(workspace: Path | None) -> None:
380
+ config = load_workspace_config(workspace)
381
+ require_se_state(config, "review")
382
+ args = ["--workspace", str(workspace)] if workspace else []
383
+ run_python("generate-review-report.py", args)
384
+ update_se_state(
385
+ config,
386
+ phase="reviewed",
387
+ last_command="/se:review",
388
+ artifacts={
389
+ "review_json": str(data_artifact_path(config, "review.json")),
390
+ "review_md": str(report_artifact_path(config, "review.md")),
391
+ },
392
+ )
393
+ if workflow_source(config) == "openspec":
394
+ run_python("writeback-openspec.py", args)
395
+
396
+
397
+ def command_verify(workspace: Path | None, timeout_seconds: int, force: bool = False) -> None:
398
+ config = load_workspace_config(workspace)
399
+ require_se_state(config, "verify")
400
+ args = ["--timeout-seconds", str(timeout_seconds)]
401
+ if force:
402
+ args.append("--force")
403
+ if workspace:
404
+ args.extend(["--workspace", str(workspace)])
405
+ run_python("run-verify-and-report.py", args)
406
+ verify_result = read_json(data_artifact_path(config, "verify.json"), {})
407
+ status_result = read_json(data_artifact_path(config, "status.json"), {})
408
+ result_text = str(verify_result.get("result", "")).strip()
409
+ status_phase = str(status_result.get("phase", "")).strip()
410
+ next_phase = "blocked"
411
+ if result_text == "通过" and status_phase == "done":
412
+ next_phase = "verified" if workflow_source(config) == "openspec" else "done"
413
+ update_se_state(
414
+ config,
415
+ phase=next_phase,
416
+ last_command="/se:verify",
417
+ artifacts={
418
+ "verify_json": str(data_artifact_path(config, "verify.json")),
419
+ "verify_md": str(report_artifact_path(config, "verify.md")),
420
+ "notification_json": str(data_artifact_path(config, "notification.json")),
421
+ },
422
+ blocked_reason="" if next_phase in ("verified", "done") else result_text or status_result.get("current_task", "") or "验证未通过",
423
+ )
424
+ if workflow_source(config) == "openspec":
425
+ run_python("writeback-openspec.py", ["--workspace", str(workspace)] if workspace else [])
426
+
427
+
428
+ def command_apply(workspace: Path | None, timeout_seconds: int) -> None:
429
+ config = load_workspace_config(workspace)
430
+ require_se_state(config, "apply")
431
+ needs_plan = current_session_is_stale(config)
432
+ if not needs_plan:
433
+ try:
434
+ session_meta = current_session_meta(config)
435
+ plan_path = data_artifact_path(config, "plan.json", session_meta)
436
+ needs_plan = not plan_path.exists()
437
+ except FileNotFoundError:
438
+ needs_plan = True
439
+ if needs_plan:
440
+ command_plan(workspace)
441
+ config = load_workspace_config(workspace)
442
+ if workflow_source(config) == "todo":
443
+ command_assert_standard_session(workspace)
444
+ command_start_implement(workspace)
445
+ print("apply_phase=implementing")
446
+ print("next_action=AI 必须按当前 plan.json 修改业务代码;代码完成后调用 finish-implement。")
447
+ if config["mode"] == "auto":
448
+ print("auto_mode=enabled")
449
+ print("auto_note=实现代码仍需 AI 在 start-implement 与 finish-implement 之间完成,后续 self-check/review/verify 由标准脚本推进。")
450
+
451
+
452
+ def main() -> None:
453
+ parser = argparse.ArgumentParser(description="super-engineer 统一工作流入口。")
454
+ parser.add_argument("command", choices=["route-se", "init", "propose-openspec", "bootstrap-openspec", "writeback-openspec", "prepare-archive-openspec", "archive-openspec", "discover", "plan", "apply", "start-implement", "finish-implement", "self-check", "review", "verify", "status", "next", "validate-state", "assert-standard-session"])
455
+ parser.add_argument("change_name", nargs="?", help="配合 propose-openspec 或 validate-state 使用。")
456
+ parser.add_argument("--command-text", help="配合 route-se 使用,传入完整 /se:* 命令文本。")
457
+ parser.add_argument("--workspace", help="工作空间路径,默认读取当前目录")
458
+ parser.add_argument("--timeout-seconds", type=int, default=300)
459
+ parser.add_argument("--force", action="store_true", help="配合 verify 使用,强制重跑验证并覆盖结果。")
460
+ parser.add_argument("--explicit-se-bridge", action="store_true", help="确认本次 bootstrap-openspec 来自用户显式 /se:bridge 命令。")
461
+ args = parser.parse_args()
462
+
463
+ workspace = Path(args.workspace).expanduser() if args.workspace else None
464
+
465
+ if args.command == "route-se":
466
+ command_route_se(workspace, args.command_text or args.change_name, args.timeout_seconds, args.force)
467
+ elif args.command == "init":
468
+ command_init(workspace)
469
+ elif args.command == "propose-openspec":
470
+ command_propose_openspec(workspace, args.change_name)
471
+ elif args.command == "bootstrap-openspec":
472
+ command_bootstrap_openspec(workspace, explicit_se_bridge=args.explicit_se_bridge)
473
+ elif args.command == "writeback-openspec":
474
+ command_writeback_openspec(workspace)
475
+ elif args.command == "prepare-archive-openspec":
476
+ command_prepare_archive_openspec(workspace)
477
+ elif args.command == "archive-openspec":
478
+ command_archive_openspec(workspace)
479
+ elif args.command == "discover":
480
+ command_discover(workspace)
481
+ elif args.command == "plan":
482
+ command_plan(workspace)
483
+ elif args.command == "apply":
484
+ command_apply(workspace, args.timeout_seconds)
485
+ elif args.command == "start-implement":
486
+ command_start_implement(workspace)
487
+ elif args.command == "finish-implement":
488
+ command_finish_implement(workspace)
489
+ elif args.command == "self-check":
490
+ run_python("generate-self-check.py", ["--workspace", str(workspace)] if workspace else [])
491
+ elif args.command == "review":
492
+ command_review(workspace)
493
+ elif args.command == "verify":
494
+ command_verify(workspace, args.timeout_seconds, args.force)
495
+ elif args.command == "status":
496
+ command_status(workspace)
497
+ elif args.command == "next":
498
+ command_next(workspace, args.timeout_seconds)
499
+ elif args.command == "validate-state":
500
+ command_validate_state(workspace, args.change_name)
501
+ elif args.command == "assert-standard-session":
502
+ command_assert_standard_session(workspace, require_notification=args.force)
503
+
504
+
505
+ if __name__ == "__main__":
506
+ main()
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ from pathlib import Path
6
+
7
+ from common import current_session_meta, data_artifact_path, ensure_status, load_workspace_config, now_iso, read_json, unique, workspace_root, write_managed_json
8
+
9
+
10
+ def main() -> None:
11
+ parser = argparse.ArgumentParser(description="更新 super-engineer 的 status.json。")
12
+ parser.add_argument("--workspace", help="工作空间路径,默认读取当前目录")
13
+ parser.add_argument("--phase", required=True)
14
+ parser.add_argument("--progress", type=int, required=True)
15
+ parser.add_argument("--current-task", default="")
16
+ parser.add_argument("--awaiting-confirmation", action="store_true")
17
+ parser.add_argument("--pending-confirmation-for", default="")
18
+ parser.add_argument("--next-action", default="")
19
+ parser.add_argument("--completed-task", action="append", default=[])
20
+ parser.add_argument("--blocked-task", action="append", default=[])
21
+ args = parser.parse_args()
22
+
23
+ workspace = workspace_root(Path(args.workspace).expanduser() if args.workspace else None)
24
+ config = load_workspace_config(workspace)
25
+ session_meta = current_session_meta(config)
26
+ status_path = data_artifact_path(config, "status.json", session_meta)
27
+ status = ensure_status(config, session_meta, read_json(status_path, {}))
28
+ status["phase"] = args.phase
29
+ status["progress"] = args.progress
30
+ status["current_task"] = args.current_task
31
+ status["awaiting_confirmation"] = args.awaiting_confirmation
32
+ status["pending_confirmation_for"] = args.pending_confirmation_for
33
+ status["next_action"] = args.next_action
34
+ status["completed_tasks"] = unique(status.get("completed_tasks", []) + args.completed_task)
35
+ status["blocked_tasks"] = unique(status.get("blocked_tasks", []) + args.blocked_task)
36
+ status["started_at"] = status.get("started_at") or session_meta.get("started_at", "")
37
+ status["updated_at"] = now_iso()
38
+
39
+ write_managed_json(config, status_path, status)
40
+
41
+
42
+ if __name__ == "__main__":
43
+ main()