关于 swain-teardown
swain-teardown 是用于结束会话的技能,可检查仓库和工作树状态、补做未完成的收尾步骤,并协调交接与清理。它会在未提交更改、未合并分支和工作树移除方面执行安全检查。
主要功能
- 01检查孤立工作树
- 02提示未提交的更改
- 03补做缺失的完成步骤
- 04提示同步工单
- 05生成会话交接摘要
适用场景
- 01结束会话前检查仓库状态
- 02查找缺少会话书签的工作树
- 03交接前补做测试或回顾
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cristoslc/ swain --skill swain-teardown安装后在 Claude Code 中输入/swain-teardown确认已加载。
详细介绍
会话拆解
结束会话的统一入口。运行完整的关停流程:总结、复盘、合并、清理、关闭、提交。取代原有的 swain-session 关闭处理程序(ADR-023)。
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-check.sh" 2>/dev/null
如果未传入 session-chain,且 JSON 输出中的 "status" 不是 "active",请告知操作人员:“没有活动会话可拆解。”并以代码 0 正常退出。
此技能的作用
会话拆解会在会话关闭前运行一系列卫生检查:
- 孤立工作树检测 — 查找没有对应会话书签的工作树(SPEC-233:带安全检查的可操作项)
- Git 脏状态检查 — 在操作人员离开前,显示未提交的更改
- 完成流水线检查 — 验证 BDD、冒烟测试和复盘是否已运行;执行缺失步骤(SPEC-258)
- 工单同步提示 — 提示操作人员确认工单与实际完成的工作一致(SPEC-234:无会话时记录降级状态)
- 交接摘要 — 将会话摘要追加到 SESSION-ROADMAP.md
**关于复盘的说明:**SPEC 级复盘现在作为完成流水线的一部分运行(第 3 步 / swain-do 第 2d 步)。EPIC 级复盘由 swain-session 的关闭处理程序调用。仅当流水线的复盘步骤遗漏时,拆解流程才会调用复盘来补做。
第 0 步 — 释放当前锁文件声明(SPEC-247)
如果当前会话在具有活动锁文件的工作树中运行,请释放该声明。此步骤最先运行,以便后续的孤立工作树检测不会将当前工作树标记为活动状态。
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
LOCKFILE_SCRIPT="$REPO_ROOT/.agents/bin/swain-lockfile.sh"
GIT_COMMON=$(git rev-parse --git-common-dir 2>/dev/null)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
if [ "$GIT_COMMON" != "$GIT_DIR" ] && [ -f "$LOCKFILE_SCRIPT" ]; then
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
bash "$LOCKFILE_SCRIPT" release "$BRANCH" 2>/dev/null || true
fi
第 1 步 — 孤立工作树检查(SPEC-233、SPEC-247)
此步骤从 session.json 的 worktrees 数组中读取工作树书签,并交叉核对锁文件状态(SPEC-247)。对于孤立工作树,流程会在安全检查后征求操作人员确认是否移除。此步骤始终运行,不受 --session-chain 影响。
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SESSION_FILE="$REPO_ROOT/.agents/session.json"
LOCKFILE_SCRIPT="$REPO_ROOT/.agents/bin/swain-lockfile.sh"
# Build a list of bookmarked worktree paths from session.json
bookmarked_wts=$(jq -r '(.worktrees // [])[] | .path' "$SESSION_FILE" 2>/dev/null)
orphan_candidates=()
orphan_results=()
ready_candidates=()
# Get all physical worktrees
git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
wt_path="${line#worktree }"
wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"
# Skip trunk (protected)
if [ "$wt_path" = "$REPO_ROOT" ]; then
echo "protected: $wt_path (trunk)"
continue
fi
# Check lockfile state (SPEC-247)
if [ -f "$LOCKFILE_SCRIPT" ]; then
lock_branch="${wt_branch##*/}" # strip refs/heads/ prefix
lockfile="$REPO_ROOT/.agents/worktrees/${lock_branch}.lock"
if [ -f "$lockfile" ]; then
# Check if ready_for_cleanup — safe to remove without confirmation
if grep -q 'ready_for_cleanup=true' "$lockfile" 2>/dev/null; then
echo "ready: $wt_path ($wt_branch) — marked ready_for_cleanup"
ready_candidates+=("$wt_path|$wt_branch|$lockfile")
continue
fi
# Check if actively claimed by another session
if ! bash "$LOCKFILE_SCRIPT" is-stale "$lock_branch" >/dev/null 2>&1; then
echo "claimed: $wt_path ($wt_branch) — active lockfile, skip"
continue
fi
fi
fi
# Check if bookmarked in session.json
is_orphan=true
reason=""
if echo "$bookmarked_wts" | grep -qF "$wt_path"; then
is_orphan=false
echo "linked: $wt_path ($wt_branch)"
fi
if [ "$is_orphan" = true ]; then
# Safety checks per SPEC-233 AC1-AC3
if [ "$wt_path" = "$(pwd)" ]; then
reason="current directory"
elif [ -n "$(git -C "$wt_path" status --porcelain 2>/dev/null)" ]; then
reason="uncommitted changes"
elif ! git merge-base --is-ancestor "$wt_branch" trunk 2>/dev/null; then
reason="branch not fully merged"
else
reason="safe to remove"
orphan_candidates+=("$wt_path|$wt_branch")
fi
echo "orphan: $wt_path ($wt_branch) — $reason"
orphan_results+=("$wt_path|$wt_branch|$reason")
fi
done
如果发现孤立工作树,请显示消息:“以下工作树没有活动会话书签 — 请考虑将其移除。”
自动移除 ready_for_cleanup 工作树(SPEC-247)
标记为 ready_for_cleanup 的工作树已合并并推送 — 可安全移除,无需操作人员确认。请先归档 session.json(SPEC-248):
ARCHIVE_SCRIPT="$REPO_ROOT/.agents/bin/swain-session-archive.sh"
for candidate in "${ready_candidates[@]}"; do
IFS='|' read -r wt_path wt_branch lockfile <<< "$candidate"
# Archive session.json before deletion
if [ -f "$ARCHIVE_SCRIPT" ]; then
bash "$ARCHIVE_SCRIPT" save "$wt_path" 2>/dev/null || true
fi
if git worktree remove "$wt_path" 2>/dev/null; then
rm -f "$lockfile" # Clean up lockfile (SPEC-247 AC3)
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path" 2>/dev/null || true
echo "Auto-removed (ready_for_cleanup): $wt_path"
fi
done
针对安全孤立工作树征求操作人员确认
仅提供 reason="safe to remove" 的孤立工作树供移除。对于每个安全的孤立工作树:
removed_worktrees=()
for candidate in "${orphan_candidates[@]}"; do
wt_path="${candidate%%|*}"
wt_branch="${candidate##*|}"
echo "> Remove orphan worktree $wt_path ($wt_branch)? [y/N]"
read -r response
if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
# Archive session.json before deletion (SPEC-248)
if [ -f "$ARCHIVE_SCRIPT" ]; then
bash "$ARCHIVE_SCRIPT" save "$wt_path" 2>/dev/null || true
fi
if git worktree remove "$wt_path" 2>/dev/null; then
removed_worktrees+=("$wt_path|$wt_branch")
# Clean up lockfile if present (SPEC-247 AC3)
lock_branch="${wt_branch##*/}"
rm -f "$REPO_ROOT/.agents/worktrees/${lock_branch}.lock" 2>/dev/null || true
# Clear the bookmark from session.json
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path"
echo "Removed: $wt_path"
else
echo "ERROR: Failed to remove $wt_path — skipping bookmark cleanup"
fi
fi
done
安全规则(SPEC-233 AC1-AC3、AC7)
- **当前目录:**绝不提供移除选项。标记为
reason="current directory"。 - **未提交的更改:**绝不提供移除选项。标记为
reason="uncommitted changes"。 - **未合并的分支:**绝不提供移除选项。标记为
reason="branch not fully merged"。 - **Trunk:**绝不提供移除选项。始终显示为
protected: <repo_root> (trunk)。 - **必须确认:**始终提示操作人员。绝不自动移除。
第 2 步 — Git 脏状态检查
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$REPO_ROOT"
git_status=$(git status --porcelain 2>/dev/null)
if [ -n "$git_status" ]; then
echo "WARN: Dirty git working tree — uncommitted changes detected."
echo "Changes:"
echo "$git_status" | head -20
else
echo "OK: Working tree is clean."
fi
报告检查结果,并给出可执行的建议。
第 3 步 — 完成流水线检查(SPEC-258)
继续进行工单同步前,请确认此工作树中任何已完成工作的完成流水线均已运行。如果有遗漏的步骤,现在就运行。
3a — 检测流水线状态
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
STATE_FILE="$REPO_ROOT/.agents/completion-state.json"
SWAIN_TEST="$REPO_ROOT/.agents/bin/swain-test.sh"
**如果 completion-state.json 存在:**读取该文件并查找未完成的步骤:
PENDING_STEPS=$(jq -r '.steps | to_entries[] | select(.value.status == "pending" or .value.status == "failed") | .key' "$STATE_FILE" 2>/dev/null)
SPEC_ID=$(jq -r '.spec_id // empty' "$STATE_FILE" 2>/dev/null)
- 如果
PENDING_STEPS为空 → 所有步骤均已通过或已跳过。显示“完成流水线:所有步骤均已完成。”并继续。 - 如果
PENDING_STEPS不为空 → 显示需要处理的步骤,并运行这些步骤(见 3b)。
**如果 completion-state.json 不存在:**检查工作树中是否有已关闭的任务:
export PATH="$REPO_ROOT/.agents/bin:$PATH"
CLOSED_COUNT=$(ticket-query '.status == "closed"' 2>/dev/null | wc -l | tr -d ' ')
- 如果
CLOSED_COUNT > 0→ 已完成工作,但流水线从未启动。创建状态文件,将所有步骤设为pending,并运行这些步骤:# Try to find the SPEC ID from the plan epic EPIC_ID=$(ticket-query '.type == "epic"' 2>/dev/null | head -1 | jq -r '.id // empty') SPEC_ID=$(tk show "$EPIC_ID" 2>/dev/null | grep -i 'external_ref' | awk '{print $NF}') mkdir -p "$REPO_ROOT/.agents" jq -n --arg spec "${SPEC_ID:-unknown}" --arg branch "$(git branch --show-current)" \ '{spec_id: $spec, branch: $branch, pipeline_started: (now | todate), steps: {bdd_tests: {status: "pending", timestamp: null, detail: null}, smoke_test: {status: "pending", timestamp: null, detail: null}, retro: {status: "pending", timestamp: null, detail: null}}}' \ > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE" - 如果
CLOSED_COUNT == 0→ 没有已完成的工作,静默跳过此步骤。
3b — 运行缺失步骤
按流水线顺序(bdd_tests → smoke_test → retro)检查每个步骤的状态。跳过状态为 passed 或 skipped 的步骤。运行状态为 pending 或 failed 的步骤。
bdd_tests:
BDD_STATUS=$(jq -r '.steps.bdd_tests.status' "$STATE_FILE")
如果 BDD_STATUS 为 pending 或 failed:
-
如果
swain-test.sh存在:BDD_OUTPUT=$(bash "$SWAIN_TEST" --artifacts "$SPEC_ID" 2>&1) BDD_EXIT=$?- 退出码为 0 → 将状态更新为
passed,详情填写输出的前 5 行。 - 非零 → 将状态更新为
failed,详情填写最后 10 行。询问:“BDD 失败。retry、skip 还是 abort?”- retry → 重新运行此步骤
- skip → 将状态设为
skipped,详情填写“操作员在 teardown 期间跳过” - abort → 完全停止 teardown,不继续同步
- 退出码为 0 → 将状态更新为
-
**如果
swain-test.sh不存在:**将状态设为skipped,详情填写“swain-test.sh 不可用”。显示警告。
所有状态写入均使用 DESIGN-018 中的原子 jq 更新模式:
jq --arg step "$STEP" --arg status "$STATUS" --arg detail "$DETAIL" \
'.steps[$step].status = $status | .steps[$step].timestamp = (now | todate) | .steps[$step].detail = $detail' \
"$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
smoke_test:
如果状态为 pending 或 failed:
-
**如果
swain-test.sh存在:**从 swain-test 输出中提取## SMOKE部分并展示给操作员。询问:“冒烟测试是否通过?(yes / no / skip)”- yes → 将状态设为
passed,详情填写“操作员在 teardown 期间确认” - no → 将状态设为
failed。询问:“retry、skip 还是 abort?” - skip → 将状态设为
skipped,详情填写“操作员在 teardown 期间跳过”
- yes → 将状态设为
-
**如果
swain-test.sh不存在:**将状态设为skipped,详情填写“swain-test.sh 不可用”。
retro:
如果状态为 pending 或 failed:
使用 Skill 工具调用 swain-retro:
使用 Skill 工具:调用
swain-retro,参数为:"Teardown catch-up — run retro for before sync."
- 成功时 → 将状态设为
passed,详情填写“在 teardown 期间记录了 retro” - 失败时 → 询问:“Retro 失败。retry 还是 abort?”(retro 不能跳过)
3c — 强制绕过
如果操作员调用 teardown 时使用了 --force(通过调用参数中包含 "force" 或 "--force" 检测):
# Mark all pending steps as skipped
for step in bdd_tests smoke_test retro; do
STEP_STATUS=$(jq -r ".steps.$step.status" "$STATE_FILE")
if [ "$STEP_STATUS" = "pending" ] || [ "$STEP_STATUS" = "failed" ]; then
jq --arg step "$step" \
'.steps[$step].status = "skipped" | .steps[$step].timestamp = (now | todate) | .steps[$step].detail = "operator forced bypass"' \
"$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
fi
done
显示:“强制绕过 — 所有待处理的流水线步骤均标记为已跳过。”继续执行步骤 4。
3d — 流水线门控
运行或跳过所有步骤后,进行验证:
REMAINING=$(jq -r '.steps | to_entries[] | select(.value.status == "pending" or .value.status == "failed") | .key' "$STATE_FILE")
- 如果为空 → 继续执行步骤 4
- 如果不为空 → teardown 被阻止。显示仍未完成的步骤并停止。
步骤 4 — 工单同步提示(SPEC-234 AC3,由步骤 3 重新编号而来)
始终运行此步骤。如果没有活动会话,则注明状态降级:
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
session_check=$(bash "$REPO_ROOT/.agents/bin/swain-session-check.sh" 2>/dev/null)
session_status=$(echo "$session_check" | jq -r '.status // "none"')
如果 session_status 不为 "active":
- 如果传入了
--session-chain,则继续执行(调用方已确认)。 - 否则,告知操作员:“没有活动会话。运行
/swain-init启动会话,还是仅继续清理?”如果他们选择继续,则跳过步骤 1-2(摘要/retro 需要会话状态),并跳转到步骤 3(合并)。
步骤 1 — 会话摘要
在会话仍处于活动状态时生成会话摘要。
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SESSION_ID="$(jq -r '.session_id // empty' "$REPO_ROOT/.agents/session-state.json" 2>/dev/null)"
if [ -n "$SESSION_ID" ]; then
bash "$REPO_ROOT/.agents/bin/swain-session-digest.sh" \
--session-id "$SESSION_ID" \
--output "$REPO_ROOT/.agents/session-log.jsonl" 2>/dev/null
fi
如果摘要脚本缺失或运行失败,记录警告并继续。摘要很有用,但不是阻塞条件。
步骤 2 — Retro(会话仍处于活动状态)
**关键:**运行 retro 时会话必须仍处于活动状态,以便读取会话状态。在此步骤之前不要关闭会话。
调用 swain-retro:
Skill("swain-retro", "Session is closing. Run retro to capture learnings before session state is cleared.")
如果 swain-retro 不可用,记录“未找到 Retro 技能 — 正在跳过”并继续。不能因为缺少技能而导致关机序列失败。
步骤 3 — 合并工作树分支
对每个活动工作树(不包括 trunk),询问是否将其分支合并到 trunk。这是旧版 teardown 中缺失的步骤——如果不执行此步骤,工作树的分支就永远不会合并,因此工作树永远无法达到“可安全移除”的状态。
3.1 — 枚举工作树
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")
git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
wt_path="${line#worktree }"
# Skip trunk
[ "$wt_path" = "$REPO_ROOT" ] && continue
wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"
echo "$wt_path|$wt_branch"
done
3.2 — 逐个检查工作树
对于每个工作树,判断其状态:
| 状态 | 条件 | 操作 |
|---|---|---|
| 已合并 | git merge-base --is-ancestor "$wt_branch" "$TRUNK" | 跳过合并,标记为可安全清理 |
| 干净,未合并 | 没有未提交的更改,分支尚未合并 | 提议合并 |
| 有未提交更改 | git -C "$wt_path" status --porcelain 有输出 | 警告操作员,提议先提交 |
| 当前目录 | "$wt_path" = "$(pwd)" | 必须先通过 ExitWorktree 退出 |
3.3 — 合并未合并的分支
对于每个“干净,未合并”的工作树,询问操作员:
工作树
{path}(分支{branch})有尚未合并的更改。选项:
- 合并 — 现在将分支合并到 {trunk}
- PR — 推送分支并创建拉取请求
- 跳过 — 保留分支现状(工作树将予以保留)
如果选择合并:
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")
# Link safety — scan for worktree-specific path links before merging
DETECT_SCRIPT="$REPO_ROOT/.agents/bin/detect-worktree-links.sh"
RESOLVE_SCRIPT="$REPO_ROOT/.agents/bin/resolve-worktree-links.sh"
if [ -x "$DETECT_SCRIPT" ]; then
MERGE_BASE=$(git -C "$wt_path" merge-base HEAD "origin/$TRUNK" 2>/dev/null || true)
CHANGED_FILES=$([ -n "$MERGE_BASE" ] && git -C "$wt_path" diff --name-only "$MERGE_BASE" HEAD 2>/dev/null || true)
if [ -n "$CHANGED_FILES" ]; then
if ! echo "$CHANGED_FILES" | xargs "$DETECT_SCRIPT" --repo-root "$REPO_ROOT" > /dev/null 2>&1; then
echo "[link-safety] Found suspicious links in $wt_branch. Resolving..."
echo "$CHANGED_FILES" | xargs "$RESOLVE_SCRIPT" --repo-root "$REPO_ROOT" 2>/dev/null || true
fi
fi
fi
# Merge into trunk from the main worktree
cd "$REPO_ROOT"
git fetch origin 2>/dev/null
git merge "$wt_branch" --no-edit
如果合并发生冲突,向操作员报告并跳过此工作树。不要强行解决冲突。
如果选择 PR:
cd "$wt_path"
git push -u origin "$wt_branch" 2>/dev/null
SUBJECT=$(git log -1 --pretty=format:'%s')
gh pr create --base "$TRUNK" --head "$wt_branch" --title "$SUBJECT" --body "Teardown PR — branch from session teardown."
报告 PR URL。
如果选择跳过: 将工作树标记为保留。第 4 步不会移除它。
3.4 — 处理“当前目录”工作树
如果操作员当前位于某个工作树中,最后处理该工作树。处理完所有其他工作树后:
- 询问他们是否也要合并此分支(选项与 3.3 相同)。
- 如果选择合并或 PR:先提交所有未提交的更改,然后调用
ExitWorktree返回主干。 - 如果选择跳过:调用
ExitWorktree并设置action: "keep",以保留该分支。
第 4 步 — 清理工作树
完成合并后,清理分支现已合并的工作树。
4.1 — 重新枚举并检查合并状态
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")
git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
wt_path="${line#worktree }"
[ "$wt_path" = "$REPO_ROOT" ] && continue
wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"
# Safety checks
if [ "$wt_path" = "$(pwd)" ]; then
echo "SKIP: $wt_path — current directory"
continue
fi
if [ -n "$(git -C "$wt_path" status --porcelain 2>/dev/null)" ]; then
echo "SKIP: $wt_path — uncommitted changes"
continue
fi
if ! git merge-base --is-ancestor "$wt_branch" "$TRUNK" 2>/dev/null; then
echo "SKIP: $wt_path — branch not merged"
continue
fi
echo "SAFE: $wt_path|$wt_branch"
done
4.2 — 移除可安全清理的工作树
对每个可安全清理的工作树,无需询问即可将其移除。该分支已合并,没有未提交的更改,而且它不是当前目录。操作员已在第 3 步批准合并。
git worktree remove "$wt_path" 2>/dev/null && echo "Removed: $wt_path ($wt_branch)"
# Clear bookmark
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path" 2>/dev/null
如果移除失败,请报告并继续。
4.3 — 清理过期的工作树引用
git worktree prune 2>/dev/null
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree prune 2>/dev/null
第 5 步 — 关闭会话状态
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
WALKAWAY_NOTE="${WALKAWAY:-Session closed via teardown}"
bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" close \
--walkaway "$WALKAWAY_NOTE" \
--session-roadmap "$(pwd)/SESSION-ROADMAP.md" 2>/dev/null
收尾记录应总结已完成的工作。根据会话工作内容推断(已合并的分支、已关闭的任务、回顾输出),或请操作员用一句话概括。
第 6 步 — 提交交接内容
暂存并提交拆解过程中发生更改的所有会话产物。
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
# Stage session artifacts
git add SESSION-ROADMAP.md 2>/dev/null
git add docs/swain-retro/ 2>/dev/null
git add .agents/session-state.json 2>/dev/null
git add .agents/session-log.jsonl 2>/dev/null
# Check if there's anything to commit
# Resolve model name from the system prompt. When subagents ran under a
# different model, include one Co-Authored-By trailer per model (see
# AGENTS.md Model attribution).
if [ -n "$(git diff --cached --name-only 2>/dev/null)" ]; then
git commit -m "chore: session teardown handoff
Co-Authored-By: <model-name-from-system-prompt> <noreply@unknown>"
fi
摘要报告
完成所有步骤后,显示摘要:
=== Session Teardown Complete ===
Retro: {fired / skipped / not available}
Branches: {N merged, M PRs created, K preserved}
Worktrees: {N removed, M preserved}
Session state: closed
Handoff commit: {hash or "nothing to commit"}
除非发生严重错误,否则以代码 0 退出。
错误处理
| 情况 | 响应 |
|---|---|
| 没有活动会话(未使用 --session-chain) | 提议仅清理模式(步骤 3–4),跳过摘要/回顾 |
| 摘要脚本缺失 | 发出警告并继续 |
| 回顾技能缺失 | 发出警告并继续 |
| 合并冲突 | 报告冲突文件,跳过该工作树 |
| 工作树移除失败 | 报告并继续 |
| 会话状态脚本缺失 | 发出警告,跳过关闭会话 |
| 第 6 步没有可提交内容 | 报告“干净”并退出 |
| Git 不可用 | 严重错误 — 无法继续 |
集成
由 swain-init 调用(决策预算)
会话达到决策预算时,swain-init 可以调用拆解流程:
Skill("swain-teardown", "Decision budget reached. Run teardown sequence.")
由 meta-router 调用
swain meta-router 会将“完成”“收尾”“关闭会话”“拆解”等请求路由到此技能。
独立调用
操作员可以随时运行 /swain-teardown。如果没有活动会话,则会提供仅清理模式。