@fitlab-ai/agent-infra 0.7.2 → 0.7.3

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 (94) hide show
  1. package/README.md +7 -1
  2. package/README.zh-CN.md +9 -3
  3. package/dist/lib/defaults.json +0 -1
  4. package/dist/lib/init.js +0 -3
  5. package/dist/lib/sandbox/commands/enter.js +13 -15
  6. package/dist/lib/sandbox/commands/list-running.js +36 -1
  7. package/dist/lib/sandbox/commands/ls.js +9 -4
  8. package/dist/lib/sandbox/commands/start.js +36 -0
  9. package/dist/lib/sandbox/index.js +8 -0
  10. package/dist/lib/table.js +11 -2
  11. package/dist/lib/task/commands/ls.js +1 -1
  12. package/dist/lib/task/short-id.js +10 -0
  13. package/dist/lib/update.js +25 -8
  14. package/lib/defaults.json +0 -1
  15. package/lib/init.ts +0 -10
  16. package/lib/sandbox/commands/enter.ts +33 -14
  17. package/lib/sandbox/commands/list-running.ts +43 -1
  18. package/lib/sandbox/commands/ls.ts +12 -4
  19. package/lib/sandbox/commands/start.ts +61 -0
  20. package/lib/sandbox/index.ts +8 -0
  21. package/lib/table.ts +14 -2
  22. package/lib/task/commands/ls.ts +1 -1
  23. package/lib/task/short-id.ts +10 -0
  24. package/lib/update.ts +28 -10
  25. package/package.json +1 -1
  26. package/templates/.agents/hooks/auto-resume.sh +21 -4
  27. package/templates/.agents/rules/next-step-output.en.md +6 -3
  28. package/templates/.agents/rules/next-step-output.zh-CN.md +6 -3
  29. package/templates/.agents/rules/pr-checks-commands.en.md +5 -0
  30. package/templates/.agents/rules/pr-checks-commands.github.en.md +62 -0
  31. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +62 -0
  32. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +5 -0
  33. package/templates/.agents/rules/pr-sync.github.en.md +7 -0
  34. package/templates/.agents/rules/pr-sync.github.zh-CN.md +7 -0
  35. package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -1
  36. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -1
  37. package/templates/.agents/skills/block-task/SKILL.en.md +8 -1
  38. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +8 -1
  39. package/templates/.agents/skills/cancel-task/SKILL.en.md +8 -1
  40. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +8 -1
  41. package/templates/.agents/skills/check-task/SKILL.en.md +1 -1
  42. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +1 -1
  43. package/templates/.agents/skills/close-codescan/SKILL.en.md +8 -1
  44. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +8 -1
  45. package/templates/.agents/skills/close-dependabot/SKILL.en.md +8 -1
  46. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +8 -1
  47. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  48. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  49. package/templates/.agents/skills/commit/SKILL.en.md +2 -3
  50. package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -3
  51. package/templates/.agents/skills/commit/reference/task-status-update.en.md +31 -23
  52. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +31 -23
  53. package/templates/.agents/skills/complete-task/SKILL.en.md +36 -3
  54. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +36 -3
  55. package/templates/.agents/skills/create-pr/SKILL.en.md +16 -7
  56. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +16 -7
  57. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -0
  58. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -0
  59. package/templates/.agents/skills/create-task/SKILL.en.md +1 -1
  60. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
  61. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  62. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  63. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  64. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  65. package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
  66. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
  67. package/templates/.agents/skills/plan-task/SKILL.en.md +1 -1
  68. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -1
  69. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  70. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
  71. package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
  72. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
  73. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  74. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
  75. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +0 -1
  76. package/templates/.agents/skills/watch-pr/SKILL.en.md +131 -0
  77. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +131 -0
  78. package/templates/.agents/skills/watch-pr/config/verify.json +22 -0
  79. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +43 -0
  80. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +43 -0
  81. package/templates/.agents/templates/task.en.md +1 -0
  82. package/templates/.agents/templates/task.zh-CN.md +1 -0
  83. package/templates/.agents/workflows/bug-fix.en.yaml +6 -4
  84. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +5 -4
  85. package/templates/.agents/workflows/feature-development.en.yaml +6 -4
  86. package/templates/.agents/workflows/feature-development.zh-CN.yaml +5 -4
  87. package/templates/.agents/workflows/refactoring.en.yaml +6 -4
  88. package/templates/.agents/workflows/refactoring.zh-CN.yaml +5 -4
  89. package/templates/.claude/commands/watch-pr.en.md +8 -0
  90. package/templates/.claude/commands/watch-pr.zh-CN.md +8 -0
  91. package/templates/.gemini/commands/_project_/watch-pr.en.toml +8 -0
  92. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +8 -0
  93. package/templates/.opencode/commands/watch-pr.en.md +11 -0
  94. package/templates/.opencode/commands/watch-pr.zh-CN.md +11 -0
@@ -0,0 +1,61 @@
1
+ import { loadConfig } from '../config.ts';
2
+ import {
3
+ assertValidBranchName,
4
+ containerNameCandidates,
5
+ sandboxBranchLabel,
6
+ sandboxLabel
7
+ } from '../constants.ts';
8
+ import { detectEngine } from '../engine.ts';
9
+ import {
10
+ fetchSandboxRows,
11
+ resolveBranchArg,
12
+ selectSandboxContainer,
13
+ startSandboxContainer
14
+ } from './list-running.ts';
15
+
16
+ const USAGE = `Usage: ai sandbox start <branch | TASK-id | N | '#N'>
17
+
18
+ Start an existing sandbox container that has stopped (for example after the
19
+ Docker daemon was restarted or replaced). The container must already exist:
20
+ if none is found, run 'ai sandbox create <branch>' first. A container that is
21
+ already running is left untouched.`;
22
+
23
+ export async function start(args: string[]): Promise<void> {
24
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
25
+ process.stdout.write(`${USAGE}\n`);
26
+ if (args.length === 0) {
27
+ process.exitCode = 1;
28
+ }
29
+ return;
30
+ }
31
+
32
+ const [firstArg = ''] = args;
33
+ const config = loadConfig();
34
+ const engine = detectEngine(config);
35
+ const branch = resolveBranchArg(firstArg, { repoRoot: config.repoRoot });
36
+ assertValidBranchName(branch);
37
+
38
+ const { running, nonRunning } = fetchSandboxRows(
39
+ engine,
40
+ sandboxLabel(config),
41
+ sandboxBranchLabel(config)
42
+ );
43
+ const found = selectSandboxContainer(
44
+ [...running, ...nonRunning],
45
+ containerNameCandidates(config, branch)
46
+ );
47
+
48
+ if (!found) {
49
+ throw new Error(
50
+ `No sandbox container for branch '${branch}'. Run 'ai sandbox create ${branch}' to create one.`
51
+ );
52
+ }
53
+
54
+ if (found.running) {
55
+ process.stdout.write(`Sandbox '${found.name}' is already running.\n`);
56
+ return;
57
+ }
58
+
59
+ startSandboxContainer(engine, found.name);
60
+ process.stdout.write(`Started sandbox '${found.name}'.\n`);
61
+ }
@@ -6,6 +6,9 @@ Commands:
6
6
  Enter sandbox or run a command. N (bare) is the
7
7
  recommended form for task short ids (e.g.
8
8
  'ai sandbox exec 11'); '#N' is also accepted.
9
+ start <branch | TASK-id | N | '#N'>
10
+ Start an existing stopped sandbox container
11
+ (e.g. after the Docker daemon restarted)
9
12
  ls List sandboxes for the current project (the '#'
10
13
  column is a display-only row number; the 'SHORT'
11
14
  column shows the active task short id, '-' if none)
@@ -54,6 +57,11 @@ export async function runSandbox(args: string[]): Promise<void> {
54
57
  }
55
58
  break;
56
59
  }
60
+ case 'start': {
61
+ const { start } = await import('./commands/start.ts');
62
+ await start(rest);
63
+ break;
64
+ }
57
65
  case 'ls': {
58
66
  const { ls } = await import('./commands/ls.ts');
59
67
  ls(rest);
package/lib/table.ts CHANGED
@@ -1,7 +1,11 @@
1
+ import pc from 'picocolors';
2
+
1
3
  function formatTable(
2
4
  headers: readonly string[],
3
- rows: readonly (readonly string[])[]
5
+ rows: readonly (readonly string[])[],
6
+ options: { zebra?: boolean } = {}
4
7
  ): string[] {
8
+ const { zebra = false } = options;
5
9
  const columnCount = headers.length;
6
10
  const widths = headers.map((header, i) => {
7
11
  const headerLen = header.length;
@@ -26,7 +30,15 @@ function formatTable(
26
30
  return parts.join(' ').trimEnd();
27
31
  };
28
32
 
29
- return [renderRow(headers), ...rows.map((row) => renderRow(row))];
33
+ const dataLines = rows.map((row, i) => {
34
+ const line = renderRow(row);
35
+ // Zebra stripes: dim even-numbered data rows (rows 2, 4, 6... -> 0-based
36
+ // odd index). The header and odd rows are left untouched. When zebra is
37
+ // off, pc.dim is never called, so the output is byte-identical to before.
38
+ return zebra && i % 2 === 1 ? pc.dim(line) : line;
39
+ });
40
+
41
+ return [renderRow(headers), ...dataLines];
30
42
  }
31
43
 
32
44
  export { formatTable };
@@ -129,7 +129,7 @@ function ls(args: string[] = []): void {
129
129
  r.branch,
130
130
  r.title
131
131
  ]);
132
- for (const line of formatTable(TABLE_HEADERS, tableRows)) {
132
+ for (const line of formatTable(TABLE_HEADERS, tableRows, { zebra: Boolean(process.stdout.isTTY) })) {
133
133
  process.stdout.write(`${line}\n`);
134
134
  }
135
135
  process.stdout.write(`Total: ${rows.length} tasks\n`);
@@ -70,6 +70,16 @@ function loadShortIdByTaskId(repoRoot: string): Map<string, string> {
70
70
  return map;
71
71
  }
72
72
 
73
+ /**
74
+ * Resolve a branch to its active-task short id (`#NN`), or `null` when no
75
+ * active task is bound to that branch.
76
+ *
77
+ * Two-state semantics: this only consults the active registry
78
+ * (`active/.short-ids.json`) plus each `active/{taskId}/task.md`. Tasks moved
79
+ * to completed/blocked/cancelled/archive have already released their short id,
80
+ * so their branches return `null` — in `ai sandbox ls` that surfaces as `-`,
81
+ * meaning the sandbox is free to remove.
82
+ */
73
83
  function lookupShortIdByBranch(
74
84
  branch: string,
75
85
  repoRoot: string,
package/lib/update.ts CHANGED
@@ -17,7 +17,8 @@ type UpdateConfig = {
17
17
  org: string;
18
18
  language: string;
19
19
  platform?: { type?: string };
20
- requiresPullRequest?: boolean;
20
+ requiresPullRequest?: boolean; // legacy field; read-only, migrated to prFlow then removed
21
+ prFlow?: 'required' | 'disabled';
21
22
  sandbox?: Record<string, unknown>;
22
23
  task?: { shortIdLength: number };
23
24
  labels?: Record<string, unknown>;
@@ -27,7 +28,6 @@ type UpdateConfig = {
27
28
 
28
29
  type Defaults = {
29
30
  platform: { type: string };
30
- requiresPullRequest: boolean;
31
31
  sandbox: Record<string, unknown>;
32
32
  task: { shortIdLength: number };
33
33
  labels: Record<string, unknown>;
@@ -41,6 +41,25 @@ const defaults = JSON.parse(
41
41
  const CONFIG_DIR = '.agents';
42
42
  const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
43
43
 
44
+ // One-time migration of the legacy project-level PR switch to the three-state
45
+ // `prFlow` preference. `true` (the old default / "PR flow on") maps to the
46
+ // strong constraint `required`; `false` maps to `disabled`. A missing or
47
+ // already-migrated config is left untouched (idempotent). Returns the new
48
+ // prFlow value when a migration happened, otherwise null.
49
+ function migratePrFlow(config: UpdateConfig): 'required' | 'disabled' | null {
50
+ if (config.requiresPullRequest === true) {
51
+ delete config.requiresPullRequest;
52
+ config.prFlow = 'required';
53
+ return 'required';
54
+ }
55
+ if (config.requiresPullRequest === false) {
56
+ delete config.requiresPullRequest;
57
+ config.prFlow = 'disabled';
58
+ return 'disabled';
59
+ }
60
+ return null;
61
+ }
62
+
44
63
  function isPathOwnedByOtherPlatform(relativePath: string, platformType: string): boolean {
45
64
  const top = String(relativePath || '').replace(/\\/g, '/').replace(/^\.\//, '').split('/')[0] ?? '';
46
65
  if (!top.startsWith('.')) return false;
@@ -195,7 +214,7 @@ async function cmdUpdate(): Promise<void> {
195
214
  const sandboxAdded = !config.sandbox;
196
215
  const taskAdded = !config.task;
197
216
  const labelsAdded = !config.labels;
198
- const requiresPullRequestAdded = config.requiresPullRequest === undefined;
217
+ const prFlowMigrated = migratePrFlow(config);
199
218
  let configChanged = changed;
200
219
 
201
220
  if (platformAdded) {
@@ -218,8 +237,7 @@ async function cmdUpdate(): Promise<void> {
218
237
  configChanged = true;
219
238
  }
220
239
 
221
- if (requiresPullRequestAdded) {
222
- config.requiresPullRequest = defaults.requiresPullRequest;
240
+ if (prFlowMigrated) {
223
241
  configChanged = true;
224
242
  }
225
243
 
@@ -233,7 +251,7 @@ async function cmdUpdate(): Promise<void> {
233
251
  for (const entry of added.merged) {
234
252
  ok(` merged: ${entry}`);
235
253
  }
236
- } else if (platformAdded || sandboxAdded || taskAdded || labelsAdded || requiresPullRequestAdded) {
254
+ } else if (platformAdded || sandboxAdded || taskAdded || labelsAdded || prFlowMigrated) {
237
255
  if (platformAdded) {
238
256
  info(`Default platform config added to ${CONFIG_PATH}.`);
239
257
  }
@@ -246,8 +264,8 @@ async function cmdUpdate(): Promise<void> {
246
264
  if (labelsAdded) {
247
265
  info(`Default labels.in config added to ${CONFIG_PATH}.`);
248
266
  }
249
- if (requiresPullRequestAdded) {
250
- info(`Default requiresPullRequest=${defaults.requiresPullRequest} added to ${CONFIG_PATH}.`);
267
+ if (prFlowMigrated) {
268
+ info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
251
269
  }
252
270
  } else {
253
271
  info(`File registry changed in ${CONFIG_PATH}.`);
@@ -264,8 +282,8 @@ async function cmdUpdate(): Promise<void> {
264
282
  if (hasNewEntries && platformAdded) {
265
283
  info(`Default platform config added to ${CONFIG_PATH}.`);
266
284
  }
267
- if (hasNewEntries && requiresPullRequestAdded) {
268
- info(`Default requiresPullRequest=${defaults.requiresPullRequest} added to ${CONFIG_PATH}.`);
285
+ if (hasNewEntries && prFlowMigrated) {
286
+ info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
269
287
  }
270
288
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
271
289
  ok(`Updated ${CONFIG_PATH}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitlab-ai/agent-infra",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Bootstrap tool for AI multi-tool collaboration infrastructure — works with Claude Code, Codex, Gemini CLI, and OpenCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -80,8 +80,25 @@ until curl -s -o /dev/null --max-time 3 "$PROBE_URL"; do
80
80
  done
81
81
  log "probe ok after ${waited}s (error=$error)"
82
82
 
83
- # Inject: Escape first to leave any non-input TUI state, then the resume text.
84
- tmux send-keys -t "$TMUX_PANE" Escape 2>/dev/null
85
- tmux send-keys -t "$TMUX_PANE" "$RESUME_TEXT" Enter 2>/dev/null
86
- log "send-keys done (error=$error)"
83
+ # Inject the resume message with a deliberately timing-insensitive sequence:
84
+ # 1. Escape leaves any non-input TUI state.
85
+ # 2. A 1s settle covers every known TUI escape timeout (vim 1000ms,
86
+ # xterm/readline 50ms) so the next bytes are delivered as fresh input
87
+ # instead of being folded into the escape sequence (the dropped-`U` race).
88
+ # 3. The text travels through a NAMED paste buffer pasted with bracketed
89
+ # paste (-p): the TUI ingests it as a single paste rather than per-character
90
+ # keypresses, so no leading char is eaten and the body is not read as a
91
+ # submit. The named buffer (-b) guarantees we paste exactly this text, and
92
+ # -d deletes it afterward so the user's anonymous paste stack is untouched.
93
+ # 4. Enter is a separate send-keys after the paste, so the submit signal is
94
+ # never merged into the pasted content (the must-press-Enter race).
95
+ # Every step stays non-blocking (2>/dev/null, exit 0 below) and logs a WARN on
96
+ # failure so the log can localize which tmux step broke.
97
+ log "tmux inject start (error=$error)"
98
+ tmux send-keys -t "$TMUX_PANE" Escape 2>/dev/null || log "WARN: tmux Escape failed (error=$error)"
99
+ sleep 1
100
+ tmux set-buffer -b auto-resume -- "$RESUME_TEXT" 2>/dev/null || log "WARN: tmux set-buffer failed (error=$error)"
101
+ tmux paste-buffer -t "$TMUX_PANE" -b auto-resume -p -d 2>/dev/null || log "WARN: tmux paste-buffer failed (error=$error)"
102
+ tmux send-keys -t "$TMUX_PANE" Enter 2>/dev/null || log "WARN: tmux Enter failed (error=$error)"
103
+ log "tmux inject done (error=$error)"
87
104
  exit 0
@@ -1,6 +1,9 @@
1
1
  # Next-Step Output Rule
2
2
 
3
- When a skill renders "Next steps" commands and the "Task info" block in its notify-user step, present the task ID consistently per this rule. Read this file before rendering next steps.
3
+ This file defines two **independent** rules for a skill's "notify-user / Next steps" output; read this file before rendering the final output and apply both:
4
+
5
+ 1. **Next-step output structure**: how "Next steps" commands and the "Task info" block present the task ID (placeholders / short-id lookup / fallback).
6
+ 2. **Agent output trailing line (Completed at)**: the **very last line** of user-facing output, **independent of the "Next steps" block**, applying to normal / error / early-return paths alike.
4
7
 
5
8
  ## Placeholder semantics
6
9
 
@@ -46,9 +49,9 @@ process.stdout.write(hit?("#"+hit[0]):full);
46
49
 
47
50
  Short ids are always rendered with a `#` prefix as `#NN`, matching how task.md frontmatter renders `short_id`. `#` starts a comment in bash, so pasting example commands depends on the TUI (both the bare numeric `NN` and `#NN` are accepted by `task-short-id.js resolve`).
48
51
 
49
- ## Completion timestamp line (Completed at)
52
+ ## Agent output trailing line (Completed at)
50
53
 
51
- Every skill that reads this rule and renders "Next steps / Inform user" output appends a single completion-time line as the **very last line** of its user-facing output, so users scanning across tmux windows can tell at a glance which agent finished most recently:
54
+ This section is a standalone rule, **co-equal with the next-step output structure** and **not part of the "Next steps" block**. Every skill that renders user-facing output must append the completion-time line as the **very last line** of that output — including **complete-task, which renders no next-step commands**, and **error / early-return paths** where a precondition is unmet. This lets users scanning across tmux windows tell at a glance which agent finished most recently:
52
55
 
53
56
  ```text
54
57
  Completed at: YYYY-MM-DD HH:mm:ss
@@ -1,6 +1,9 @@
1
1
  # 下一步输出规则
2
2
 
3
- skill 在「告知用户」步骤渲染「下一步」命令与「任务信息」段时,统一按本规则呈现任务 ID 形态。渲染下一步前先读取本文件。
3
+ 本文件定义 skill「告知用户 / 下一步」输出的两类**相互独立**的规则;渲染最终输出前先读取本文件并同时落实两者:
4
+
5
+ 1. **下一步输出结构**:「下一步」命令与「任务信息」段如何呈现任务 ID 形态(占位符 / 取短号 / 回退)。
6
+ 2. **Agent 输出收尾行(Completed at)**:面向用户输出的**绝对最后一行**,**独立于「下一步」块**,正常 / 错误 / 早退路径都适用。
4
7
 
5
8
  ## 占位符语义
6
9
 
@@ -46,9 +49,9 @@ process.stdout.write(hit?("#"+hit[0]):full);
46
49
 
47
50
  短号统一渲染为带 `#` 前缀的 `#NN`,与 task.md frontmatter 的 `short_id` 渲染一致。`#` 在 bash 中是注释起始符,示例命令若直接粘贴需视 TUI 而定(裸数字 `NN` 与 `#NN` 都被 `task-short-id.js resolve` 接受)。
48
51
 
49
- ## 完成时间收尾行(Completed at)
52
+ ## Agent 输出收尾行(Completed at)
50
53
 
51
- 所有读取本规则、并向用户渲染「下一步 / 告知用户」输出的 skill,在面向用户输出的**绝对最后一行**统一追加一行完成时间,便于用户在 tmux 多窗口扫视时一眼判断各 Agent 的完成先后:
54
+ 本节是与「下一步输出结构」**并列的独立规则**,不隶属于「下一步」块。任何向用户渲染输出的 skill 都必须在面向用户输出的**绝对最后一行**追加完成时间收尾行——包括**声明「不渲染下一步命令」的 complete-task**,以及前置条件未满足而提前 return 的**错误 / 早退路径**。便于用户在 tmux 多窗口扫视时一眼判断各 Agent 的完成先后:
52
55
 
53
56
  ```text
54
57
  Completed at: YYYY-MM-DD HH:mm:ss
@@ -0,0 +1,5 @@
1
+ # PR Checks Platform Commands
2
+
3
+ This code platform does not provide built-in pull request check commands.
4
+
5
+ Platform-specific check monitoring is skipped for custom platforms unless you provide matching `.{platform}.en.md` rule templates. Keep local task artifacts as the source of truth, or install a platform-specific template pack before running the `watch-pr` skill.
@@ -0,0 +1,62 @@
1
+ # PR Checks Platform Commands (GitHub)
2
+
3
+ Read this file before watching a PR's required checks, resolving a failing run, pulling failure logs, or reading the current branch's PR. The `watch-pr` skill's platform-specific commands live here; the skill body and `reference/` stay platform-agnostic.
4
+
5
+ ## Current Branch PR / Repository Info
6
+
7
+ ```bash
8
+ gh pr view --json number -q .number # PR number for the current branch
9
+ gh pr view {pr#} --json headRefOid -q .headRefOid # PR head SHA
10
+ gh repo view --json nameWithOwner -q .nameWithOwner # {owner}/{repo}
11
+ ```
12
+
13
+ If `gh` is not authenticated or a command fails, stop or degrade per the calling skill's error handling.
14
+
15
+ ## Watch Required Checks
16
+
17
+ ```bash
18
+ gh pr checks {pr#} --required --watch --fail-fast -i 30 \
19
+ --json name,bucket,link,workflow
20
+ ```
21
+
22
+ - `--required`: include only checks the repository's branch protection marks as required.
23
+ - `--watch`: block until those checks finish; `--fail-fast`: exit watch on the first failure.
24
+ - `-i 30`: poll every 30 seconds (backoff). **Overall time cap default 30 minutes (1800 seconds)**: use the timeout mechanism that matches the execution environment; on timeout, treat as "pending" (exit code 8).
25
+ - POSIX shell: `timeout 1800 gh pr checks {pr#} --required --watch --fail-fast -i 30 …`
26
+ - PowerShell (Windows): use a job timeout —
27
+ ```powershell
28
+ $job = Start-Job { gh pr checks {pr#} --required --watch --fail-fast -i 30 }
29
+ if (Wait-Job $job -Timeout 1800) { Receive-Job $job } else { Stop-Job $job; <treat as "pending"> }
30
+ ```
31
+ - Platform-neutral fallback (no external timeout tool): record the start time, loop `gh pr checks {pr#} --required --json name,bucket,link,workflow` **without** `--watch`, sleeping `-i` seconds each round and checking whether any `bucket` is still `pending`; if the elapsed time reaches 1800 seconds without finishing, exit the loop and treat as "pending".
32
+ - The `bucket` field of `--json` classifies each check as `pass` / `fail` / `pending` / `skipping` / `cancel`.
33
+
34
+ Exit code semantics:
35
+
36
+ | Exit code | Meaning | Outcome class |
37
+ |-----------|---------|---------------|
38
+ | 0 | all required checks passed | all green |
39
+ | 1 | at least one failed / errored | failure |
40
+ | 8 | still pending (watch timed out or was cut off by `timeout`) | pending |
41
+
42
+ Old `gh` (< 2.93) without `--required`: fall back to `gh pr checks {pr#} --watch --fail-fast` (i.e. "all checks must succeed"), and note this degradation in the help/report and suggest upgrading `gh`.
43
+
44
+ ## Resolve a Failing Run id and Pull Logs
45
+
46
+ `gh pr checks --json` does not return a run id directly, but it returns each failing check's `link` (a URL to the run/job). Resolve in this deterministic order:
47
+
48
+ 1. Extract from the failing check's `link` via regex: `https://github.com/{owner}/{repo}/actions/runs/(\d+)(?:/job/(\d+))?` → group 1 is the run id (optional group 2 is the job id).
49
+ 2. When `link` is not a run URL or cannot be parsed, query check-runs by head SHA:
50
+ ```bash
51
+ sha=$(gh pr view {pr#} --json headRefOid -q .headRefOid)
52
+ gh api "repos/{owner}/{repo}/commits/$sha/check-runs" \
53
+ --jq '.check_runs[] | select(.name=="{failed-check-name}") | .details_url'
54
+ ```
55
+ then extract the run id from `details_url` the same way.
56
+ 3. If neither path yields a run id → treat as "unlocatable" and use the skill's help exit; do not self-heal blindly.
57
+
58
+ Once the run id is known, pull the failure logs:
59
+
60
+ ```bash
61
+ gh run view {run-id} --log-failed
62
+ ```
@@ -0,0 +1,62 @@
1
+ # PR 检查平台命令(GitHub)
2
+
3
+ 在监控 PR 的 required checks、解析失败 run、拉取失败日志或读取当前分支 PR 前先读取本文件。`watch-pr` 技能的平台专属命令集中在此,技能正文与 `reference/` 保持平台无关。
4
+
5
+ ## 当前分支 PR / 仓库信息
6
+
7
+ ```bash
8
+ gh pr view --json number -q .number # 当前分支对应的 PR 号
9
+ gh pr view {pr#} --json headRefOid -q .headRefOid # PR head SHA
10
+ gh repo view --json nameWithOwner -q .nameWithOwner # {owner}/{repo}
11
+ ```
12
+
13
+ `gh` 未认证或命令失败时,按调用方技能的错误处理停止或降级。
14
+
15
+ ## 监控 required checks
16
+
17
+ ```bash
18
+ gh pr checks {pr#} --required --watch --fail-fast -i 30 \
19
+ --json name,bucket,link,workflow
20
+ ```
21
+
22
+ - `--required`:只纳入仓库分支保护标记为 required 的 checks。
23
+ - `--watch`:阻塞直到这些 checks 全部跑完;`--fail-fast`:出现首个失败即退出 watch。
24
+ - `-i 30`:轮询间隔 30 秒(退避)。**总时长上限默认 30 分钟(1800 秒)**:按执行环境选用对应的超时方式,超时即按「挂起」处理(退出码 8)。
25
+ - POSIX shell:`timeout 1800 gh pr checks {pr#} --required --watch --fail-fast -i 30 …`
26
+ - PowerShell(Windows):用作业超时——
27
+ ```powershell
28
+ $job = Start-Job { gh pr checks {pr#} --required --watch --fail-fast -i 30 }
29
+ if (Wait-Job $job -Timeout 1800) { Receive-Job $job } else { Stop-Job $job; <按「挂起」处理> }
30
+ ```
31
+ - 平台中立回退(无外部超时工具时):记录开始时间,循环执行**不带** `--watch` 的 `gh pr checks {pr#} --required --json name,bucket,link,workflow`,每轮 sleep `-i` 秒并检查 `bucket` 是否仍有 `pending`;累计时长 ≥ 1800 秒仍未结束 → 退出循环按「挂起」处理。
32
+ - `--json` 的 `bucket` 字段把每个 check 归类为 `pass` / `fail` / `pending` / `skipping` / `cancel`。
33
+
34
+ 退出码语义:
35
+
36
+ | 退出码 | 含义 | 结果分类 |
37
+ |--------|------|----------|
38
+ | 0 | 全部 required checks 通过 | 全绿 |
39
+ | 1 | 至少一个失败 / 出错 | 失败 |
40
+ | 8 | 仍有 pending(watch 超时或被 `timeout` 截断) | 挂起 |
41
+
42
+ 旧版 `gh`(< 2.93)若不支持 `--required`:回退为 `gh pr checks {pr#} --watch --fail-fast`(即「所有 check 必须 success」),并在求助/报告中注明该降级、建议升级 `gh`。
43
+
44
+ ## 解析失败 run id 并拉日志
45
+
46
+ `gh pr checks --json` 不直接返回 run id,但返回失败 check 的 `link`(指向 run/job 的 URL)。按确定性顺序解析:
47
+
48
+ 1. 从失败 check 的 `link` 用正则提取:`https://github.com/{owner}/{repo}/actions/runs/(\d+)(?:/job/(\d+))?` → 第 1 组为 run id(可选第 2 组为 job id)。
49
+ 2. `link` 非 run URL 或无法解析时,用 head SHA 查 check-runs:
50
+ ```bash
51
+ sha=$(gh pr view {pr#} --json headRefOid -q .headRefOid)
52
+ gh api "repos/{owner}/{repo}/commits/$sha/check-runs" \
53
+ --jq '.check_runs[] | select(.name=="{failed-check-name}") | .details_url'
54
+ ```
55
+ 再从 `details_url` 同法提取 run id。
56
+ 3. 两路都拿不到 run id → 视为「不可定位」,按技能的求助出口处理,不盲目自愈。
57
+
58
+ 拿到 run id 后拉失败日志:
59
+
60
+ ```bash
61
+ gh run view {run-id} --log-failed
62
+ ```
@@ -0,0 +1,5 @@
1
+ # PR 检查平台命令
2
+
3
+ 当前代码平台未内置 Pull Request 检查命令支持。
4
+
5
+ 自定义平台会跳过平台专属的检查监控,除非你提供匹配的 `.{platform}.zh-CN.md` 规则模板。请以本地任务产物作为事实来源,或先安装平台专属模板包再运行 `watch-pr` 技能。
@@ -32,6 +32,7 @@ Aggregation rules:
32
32
  - build the review-history table from `review-code*` and `code*`
33
33
  - extract the test summary from `code*`
34
34
  - if one artifact class is missing, treat it as "no data for this stage" and continue
35
+ - Manual verification section: extract items requiring human confirmation/fallback from the "Assumptions"/"Open Questions" of the latest `plan*` and the "Environment-Blocked Findings"/"Self-Doubt" sections (i.e. env-blocked items) of the latest `review-code*`; when there are none, write the explicit placeholder `- None — no items require manual verification`, never leave it empty
35
36
 
36
37
  ## Comment Body Template
37
38
 
@@ -46,6 +47,12 @@ Use this canonical comment body template:
46
47
 
47
48
  **Updated At**: {current-time}
48
49
 
50
+ ### ⚠️ Manual Verification Required
51
+
52
+ > Items in this change that need human confirmation/fallback; reviewers can reply under this comment once verified.
53
+
54
+ - {manual-verify-item}
55
+
49
56
  ### Key Technical Decisions
50
57
 
51
58
  - {decision-1}
@@ -32,6 +32,7 @@
32
32
  - 用 `review-code*` 与 `code*` 构建审查历程表
33
33
  - 从 `code*` 提取测试结果摘要
34
34
  - 某一类产物缺失时,按“无该阶段数据”处理并继续生成
35
+ - 需人工校验段落:从最新 `plan*` 的「假设」「未决问题」与最新 `review-code*` 的「环境性遗留」「自我质疑」提取需人工确认/兜底事项;无任何事项时写显式占位 `- 无需人工校验事项`,不得留空
35
36
 
36
37
  ## 评论体模板
37
38
 
@@ -46,6 +47,12 @@
46
47
 
47
48
  **更新时间**:{当前时间}
48
49
 
50
+ ### ⚠️ 需人工校验
51
+
52
+ > 本次改动中需人工确认/兜底的事项;reviewer 校验后可在本评论下回复收尾。
53
+
54
+ - {manual-verify-item}
55
+
49
56
  ### 关键技术决策
50
57
 
51
58
  - {decision-1}
@@ -189,7 +189,7 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
189
189
 
190
190
  > Execute this step only after the verification gate passes.
191
191
 
192
- > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the "Next steps" commands, read `.agents/rules/next-step-output.md` and use its short-id snippet to render `{task-ref}` in the commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released).
192
+ > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
193
193
 
194
194
  Output format:
195
195
  ```
@@ -188,7 +188,7 @@ node .agents/scripts/validate-artifact.js gate analyze-task .agents/workspace/ac
188
188
 
189
189
  > 仅在校验通过后执行本步骤。
190
190
 
191
- > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染「下一步」命令前,先读取 `.agents/rules/next-step-output.md`,按其取短号片段把命令中的 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id)。
191
+ > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染最终输出前,先读取 `.agents/rules/next-step-output.md` 并落实其两类规则:(1) 「下一步」命令把 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id);(2) 在面向用户输出的绝对最后一行追加 `Completed at` 收尾行(成功、错误、早退等任何面向用户输出都适用,不限于校验通过的成功态)。
192
192
 
193
193
  输出格式:
194
194
  ```
@@ -106,7 +106,9 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
106
106
 
107
107
  > Execute this step only after the verification gate passes.
108
108
 
109
- > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the "Next steps" commands, read `.agents/rules/next-step-output.md` and use its short-id snippet to render `{task-ref}` in the commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released).
109
+ > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
110
+
111
+ > **Optional sandbox-cleanup hint (gated)**: Render the "Optional: clean up this task's sandbox" block — placed after "Archived to" and before "To unblock" in the output below — only when BOTH (1) `.agents/.airc.json` has a `sandbox` field and (2) task.md's `branch` field exists and is not `main` / `master`; otherwise omit the whole block. `{branch}` is the `branch` value from the task.md you already loaded (the task has moved to blocked/, so read it from `.agents/workspace/blocked/{task-id}/task.md`). This block is independent of "Next step" semantics.
110
112
 
111
113
  Output format:
112
114
  ```
@@ -116,6 +118,11 @@ Blocking reason: {summary}
116
118
  Required to unblock: {what's needed}
117
119
  Archived to: .agents/workspace/blocked/{task-id}/
118
120
 
121
+ Optional: clean up this task's sandbox
122
+ (The task is blocked and moved to blocked/; the sandbox container and per-branch config directory are not reclaimed automatically. Run this if you no longer need them:)
123
+
124
+ ai sandbox rm {branch}
125
+
119
126
  To unblock when the issue is resolved:
120
127
  mv .agents/workspace/blocked/{task-id} .agents/workspace/active/{task-id}
121
128
  # Then update task.md: status -> active, remove blocked_at
@@ -105,7 +105,9 @@ node .agents/scripts/validate-artifact.js gate block-task .agents/workspace/bloc
105
105
 
106
106
  > 仅在校验通过后执行本步骤。
107
107
 
108
- > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染「下一步」命令前,先读取 `.agents/rules/next-step-output.md`,按其取短号片段把命令中的 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id)。
108
+ > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染最终输出前,先读取 `.agents/rules/next-step-output.md` 并落实其两类规则:(1) 「下一步」命令把 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id);(2) 在面向用户输出的绝对最后一行追加 `Completed at` 收尾行(成功、错误、早退等任何面向用户输出都适用,不限于校验通过的成功态)。
109
+
110
+ > **可选沙箱清理提示(门控渲染)**:仅当同时满足 (1) `.agents/.airc.json` 存在 `sandbox` 字段、(2) task.md 的 `branch` 字段存在且不是 `main` / `master` 时,才渲染下方输出中「归档路径」之后、「解除阻塞时执行」之前的「可选:清理本任务的沙箱」块;任一不满足则整段省略。`{branch}` 取已读入的 task.md 的 `branch` 值(任务此时已移动到 blocked/,从 `.agents/workspace/blocked/{task-id}/task.md` 读取)。该块独立于「下一步」语义。
109
111
 
110
112
  输出格式:
111
113
  ```
@@ -115,6 +117,11 @@ node .agents/scripts/validate-artifact.js gate block-task .agents/workspace/bloc
115
117
  解除阻塞所需:{需要什么}
116
118
  归档路径:.agents/workspace/blocked/{task-id}/
117
119
 
120
+ 可选:清理本任务的沙箱
121
+ (任务已阻塞并移到 blocked/,沙箱容器和 per-branch 配置目录不会自动回收。如果不再需要可执行:)
122
+
123
+ ai sandbox rm {branch}
124
+
118
125
  解除阻塞时执行:
119
126
  mv .agents/workspace/blocked/{task-id} .agents/workspace/active/{task-id}
120
127
  # 然后更新 task.md:status -> active,移除 blocked_at
@@ -119,7 +119,9 @@ Keep the gate output in your reply as fresh evidence. Do not claim completion wi
119
119
 
120
120
  > Execute this step only after the verification gate passes.
121
121
 
122
- > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the "Next steps" commands, read `.agents/rules/next-step-output.md` and use its short-id snippet to render `{task-ref}` in the commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released).
122
+ > **IMPORTANT**: All TUI command formats listed below must be output in full. Do not show only the format for the current AI agent. If `.agents/.airc.json` configures custom TUIs (via `customTUIs`), read each tool's `name` and `invoke`, then add the matching command line in the same format (`${skillName}` becomes the skill name and `${projectName}` becomes the project name). Before rendering the final output, read `.agents/rules/next-step-output.md` and apply both of its rules: (1) render `{task-ref}` in the "Next steps" commands as the short id `#NN` (falling back to the full TASK-id when unallocated or released); (2) append the `Completed at` line as the very last line of the user-facing output (this applies to every user-facing output — success, error, and early-return paths alike, not only the success path).
123
+
124
+ > **Optional sandbox-cleanup hint (gated)**: Render the "Optional: clean up this task's sandbox" block — placed after "Target path" and before "Next step" in the output below — only when BOTH (1) `.agents/.airc.json` has a `sandbox` field and (2) task.md's `branch` field exists and is not `main` / `master`; otherwise omit the whole block. `{branch}` is the `branch` value from the task.md you already loaded (the task has moved to completed/, so read it from `.agents/workspace/completed/{task-id}/task.md`). This block is independent of "Next steps" semantics.
123
125
 
124
126
  Output format:
125
127
  ```
@@ -129,6 +131,11 @@ Cancellation reason: {reason}
129
131
  Status label: {status-label or skipped}
130
132
  Target path: .agents/workspace/completed/{task-id}/
131
133
 
134
+ Optional: clean up this task's sandbox
135
+ (The task is archived; the sandbox container and per-branch config directory are not reclaimed automatically. Run this if you no longer need them:)
136
+
137
+ ai sandbox rm {branch}
138
+
132
139
  Next step - inspect the moved task:
133
140
  - Claude Code / OpenCode: /check-task {task-ref}
134
141
  - Gemini CLI: /{{project}}:check-task {task-ref}
@@ -118,7 +118,9 @@ node .agents/scripts/validate-artifact.js gate cancel-task .agents/workspace/com
118
118
 
119
119
  > 仅在校验通过后执行本步骤。
120
120
 
121
- > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染「下一步」命令前,先读取 `.agents/rules/next-step-output.md`,按其取短号片段把命令中的 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id)。
121
+ > **重要**:以下「下一步」中列出的所有 TUI 命令格式必须完整输出,不要只展示当前 AI 代理对应的格式。如果 `.agents/.airc.json` 中配置了自定义 TUI(`customTUIs`),读取每个工具的 `name` 和 `invoke`,按同样格式补充对应命令行(`${skillName}` 替换为技能名,`${projectName}` 替换为项目名)。 渲染最终输出前,先读取 `.agents/rules/next-step-output.md` 并落实其两类规则:(1) 「下一步」命令把 `{task-ref}` 渲染为短号 `#NN`(未分配/已释放时回退完整 TASK-id);(2) 在面向用户输出的绝对最后一行追加 `Completed at` 收尾行(成功、错误、早退等任何面向用户输出都适用,不限于校验通过的成功态)。
122
+
123
+ > **可选沙箱清理提示(门控渲染)**:仅当同时满足 (1) `.agents/.airc.json` 存在 `sandbox` 字段、(2) task.md 的 `branch` 字段存在且不是 `main` / `master` 时,才渲染下方输出中「目标路径」之后、「下一步」之前的「可选:清理本任务的沙箱」块;任一不满足则整段省略。`{branch}` 取已读入的 task.md 的 `branch` 值(任务此时已移动到 completed/,从 `.agents/workspace/completed/{task-id}/task.md` 读取)。该块独立于「下一步」语义。
122
124
 
123
125
  输出格式:
124
126
  ```
@@ -128,6 +130,11 @@ node .agents/scripts/validate-artifact.js gate cancel-task .agents/workspace/com
128
130
  状态标签:{status-label 或 skipped}
129
131
  目标路径:.agents/workspace/completed/{task-id}/
130
132
 
133
+ 可选:清理本任务的沙箱
134
+ (任务已归档,沙箱容器和 per-branch 配置目录不会自动回收。如果不再需要可执行:)
135
+
136
+ ai sandbox rm {branch}
137
+
131
138
  下一步 - 查看已转移任务:
132
139
  - Claude Code / OpenCode:/check-task {task-ref}
133
140
  - Gemini CLI:/{{project}}:check-task {task-ref}