swain-sync
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<!-- swain-model-hint: sonnet, effort: low -->
Run through the following steps in order without pausing for confirmation unless a decision point is explicitly marked as requiring one.
Delegate this to a sub-agent so the main conversation thread stays clean. Include the full text of these instructions in the agent prompt, since sub-agents cannot read skill files directly.
<!-- swain-model-hint: sonnet, effort: low -->
按顺序执行以下步骤,除非明确标记为需要确认的决策点,否则无需暂停等待确认。
将此任务委托给子Agent,以保持主对话线程整洁。由于子Agent无法直接读取skill文件,请在Agent提示词中包含本说明的全文。
Step 1 — Detect worktree context and fetch/rebase upstream
步骤1 — 检测工作树上下文并拉取/变基上游代码
First, detect whether you are running in a git linked worktree:
bash
GIT_COMMON=$(git rev-parse --git-common-dir)
GIT_DIR=$(git rev-parse --git-dir)
IN_WORKTREE=$( [ "$GIT_COMMON" != "$GIT_DIR" ] && echo "yes" || echo "no" )
REPO_ROOT=$(git rev-parse --show-toplevel)IN_WORKTREE=yes.claude/worktrees/agent-abc123Next, check whether the current branch has an upstream tracking branch:
bash
git --no-pager rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/nullIf there is an upstream, fetch and rebase to incorporate upstream changes BEFORE staging or committing:
bash
git fetch originIf there are local changes (dirty working tree), stash them first:
bash
BRANCH=$(git rev-parse --abbrev-ref HEAD)
git stash push -m "swain-sync: auto-stash [$BRANCH]"
git --no-pager rebase origin/$BRANCH
git stash popIf the rebase has conflicts after stash pop, abort and report:
bash
git rebase --abort # if rebase itself conflicts
git stash pop # recover stashed changesShow the user the conflicting files and stop. Do not force-push or drop changes.
If there is no upstream ( returns an error) and , the worktree branch has no remote tracking counterpart. Rebase onto so the commits apply cleanly as a fast-forward:
@{u}IN_WORKTREE=yesorigin/mainbash
git fetch origin
git rebase origin/mainIf cannot be fetched, skip fetch/rebase and proceed to Step 2.
originIf there is no upstream and (main worktree, new branch), skip this step entirely.
IN_WORKTREE=no首先,检测当前是否运行在Git链接工作树中:
bash
GIT_COMMON=$(git rev-parse --git-common-dir)
GIT_DIR=$(git rev-parse --git-dir)
IN_WORKTREE=$( [ "$GIT_COMMON" != "$GIT_DIR" ] && echo "yes" || echo "no" )
REPO_ROOT=$(git rev-parse --show-toplevel)IN_WORKTREE=yes.claude/worktrees/agent-abc123接下来,检查当前分支是否有上游跟踪分支:
bash
git --no-pager rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null如果存在上游分支,请在暂存或提交之前先拉取并变基以合并上游变更:
bash
git fetch origin如果存在本地变更(工作树未干净),请先暂存:
bash
BRANCH=$(git rev-parse --abbrev-ref HEAD)
git stash push -m "swain-sync: auto-stash [$BRANCH]"
git --no-pager rebase origin/$BRANCH
git stash pop如果恢复暂存后变基出现冲突,请中止并报告:
bash
git rebase --abort # 如果变基本身冲突
git stash pop # 恢复暂存的变更向用户显示冲突文件并停止操作。请勿强制推送或丢弃变更。
如果没有上游分支( 返回错误)且 ,则该工作树分支没有远程跟踪对应分支。请变基到 ,以便提交可以作为快进合并干净应用:
@{u}IN_WORKTREE=yesorigin/mainbash
git fetch origin
git rebase origin/main如果无法拉取 ,请跳过拉取/变基步骤,直接进入步骤2。
origin如果没有上游分支且 (主工作树,新分支),请完全跳过此步骤。
IN_WORKTREE=noStep 2 — Survey the working tree
步骤2 — 检查工作树状态
bash
git --no-pager status
git --no-pager diff # unstaged changes
git --no-pager diff --cached # already-staged changesIf the working tree is completely clean and there is nothing to push, report that and stop.
bash
git --no-pager status
git --no-pager diff # 未暂存的变更
git --no-pager diff --cached # 已暂存的变更如果工作树完全干净且没有需要推送的内容,请报告此情况并停止操作。
Step 3 — Stage changes
步骤3 — 暂存变更
Identify files that look like secrets (, , , , ). If any are present, warn the user and exclude them from staging.
.env*.pem*_rsacredentials.*secrets.*If there are 10 or fewer changed files (excluding secrets), stage them individually:
bash
git add file1 file2 ...If there are more than 10 changed files, stage everything and then unstage secrets:
bash
git add -A
git reset HEAD -- <secret-file-1> <secret-file-2> ...识别看起来像敏感信息的文件(、、、、)。如果存在此类文件,请警告用户并将其排除在暂存范围之外。
.env*.pem*_rsacredentials.*secrets.*如果变更文件数量≤10个(排除敏感文件),请逐个暂存:
bash
git add file1 file2 ...如果变更文件数量>10个,请暂存所有文件然后取消暂存敏感文件:
bash
git add -A
git reset HEAD -- <secret-file-1> <secret-file-2> ...Step 3.5 — Gitignore check
步骤3.5 — Gitignore检查
Before committing, verify hygiene. This step is blocking — if relevant patterns are missing, stop and require the user to fix before proceeding.
.gitignore.gitignore提交前,请验证 的规范性。此步骤为阻塞式 — 如果缺少相关规则,请停止操作并要求用户在继续前修复 。
.gitignore.gitignore1. Check existence
1. 检查文件是否存在
If no file exists in the repo root:
.gitignoreSTOP: Nofile found. Create one before committing — without it, secrets, build artifacts, and OS files can enter git history. Minimal starting point:.gitignorecurl -sL https://www.toptal.com/developers/gitignore/api/macos,linux,node,python > .gitignore
Stop execution. Do not commit.
如果仓库根目录下没有 文件:
.gitignore停止操作:未找到文件。请在提交前创建该文件 — 没有它,敏感信息、构建产物和系统文件可能会进入Git历史。 最小化初始模板:.gitignorecurl -sL https://www.toptal.com/developers/gitignore/api/macos,linux,node,python > .gitignore
停止执行,请勿提交。
2. Detect relevant patterns
2. 检测相关规则
Check which patterns are relevant to this repo, based on what actually exists on disk:
| Pattern | Relevant if |
|---|---|
| |
| |
| any |
| same as |
| repo is on macOS ( |
For each relevant pattern, check if contains it (exact match or substring). Collect missing ones.
.gitignore根据磁盘上实际存在的内容,检查哪些规则与当前仓库相关:
| 规则 | 相关条件 |
|---|---|
| 存在 |
| 仓库根目录或任何子目录中存在 |
| 仓库中存在任何 |
| 与 |
| 仓库位于macOS系统( |
对于每个相关规则,检查 中是否包含它(完全匹配或子串匹配)。收集缺失的规则。
.gitignore3. Decide whether to block
3. 决定是否阻塞
-
If no relevant patterns are missing: this step is silent. Continue to Step 3.7.
-
If any relevant patterns are missing: stop and report:STOP:is missing patterns relevant to this repo:
.gitignore- —
.envfound; without this, a local.env.examplefile could be committed.env - —
node_modules/foundpackage.json
Add the missing patterns before committing: echo ".env" >> .gitignore echo "node_modules/" >> .gitignoreTo permanently suppress a specific pattern check (intentional omission), add a comment to:.gitignoreswain-sync: allow .env
Stop execution. Do not commit until the user resolves this.
-
如果没有缺失相关规则:此步骤无提示,继续执行步骤3.7。
-
如果存在缺失的相关规则:停止操作并报告:停止操作:缺少与当前仓库相关的规则:
.gitignore- — 检测到
.env;如果没有此规则,本地.env.example文件可能会被提交.env - — 检测到
node_modules/package.json
请在提交前添加缺失的规则: echo ".env" >> .gitignore echo "node_modules/" >> .gitignore如果要永久忽略特定规则检查(有意不添加),请在中添加注释:.gitignoreswain-sync: allow .env
停止执行,在用户解决此问题前请勿提交。
4. Skip logic
4. 跳过逻辑
If contains for a given pattern, treat that pattern as intentionally omitted and do not flag it.
.gitignore# swain-sync: allow <pattern>如果 中包含 注释,则该规则被视为有意忽略,不会标记为缺失。
.gitignore# swain-sync: allow <pattern>Step 3.7 — ADR compliance check
步骤3.7 — ADR合规性检查
If modified files include any swain artifacts (, , , , , , , ), run an ADR compliance check against each modified artifact:
docs/spec/docs/epic/docs/vision/docs/research/docs/journey/docs/persona/docs/runbook/docs/design/bash
bash skills/swain-design/scripts/adr-check.sh <artifact-path>For each artifact with findings (exit code 1 — DEAD_REF or STALE), collect the output and present a single consolidated warning after all checks complete:
ADR compliance: N artifact(s) have findings that may need attention. <condensed findings summary>
This step is advisory — it warns but never blocks the commit. Continue to Step 4 regardless.
If the script is not found or fails with exit code 2, skip silently — the check is only available in repos with swain-design installed.
adr-check.sh如果修改的文件包含任何swain工件(、、、、、、、),请对每个修改的工件运行ADR合规性检查:
docs/spec/docs/epic/docs/vision/docs/research/docs/journey/docs/persona/docs/runbook/docs/design/bash
bash skills/swain-design/scripts/adr-check.sh <artifact-path>对于每个有问题的工件(退出码1 — DEAD_REF或STALE),收集输出结果,并在所有检查完成后呈现一个合并后的警告:
ADR合规性检查:N个工件存在需要关注的问题。 <精简的问题摘要>
此步骤为建议性 — 仅发出警告,不会阻止提交。无论结果如何,继续执行步骤4。
如果未找到 脚本或脚本以退出码2失败,请静默跳过此步骤 — 该检查仅在安装了swain-design的仓库中可用。
adr-check.shStep 4 — Generate a commit message
步骤4 — 生成提交信息
Read the staged diff () and write a commit message that:
git --no-pager diff --cached- Opens with a conventional-commit prefix matching the dominant change type:
- — new feature or capability
feat - — bug fix
fix - — documentation only
docs - — tooling, deps, config with no behavior change
chore - — restructuring without behavior change
refactor - — test additions or fixes
test
- Includes a concise imperative-mood subject line (≤ 72 chars).
- Adds a short body (2–5 lines) summarising why, not just what, when the diff is non-trivial.
- Appends a trailer identifying the model that generated the commit. Use the model name from your system prompt (e.g.,
Co-Authored-By,Claude Opus 4.6). If you can't determine the model name, useGemini 2.5 Proas a fallback.AI Assistant
Example shape:
feat(terraform): add Cloudflare DNS module for hub provisioning
Operators can now point DNS at Cloudflare without migrating their zone.
Module is activated by dns_provider=cloudflare and requires only
CLOUDFLARE_API_TOKEN — no other provider credentials are validated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>读取已暂存的差异()并撰写提交信息,要求:
git --no-pager diff --cached- 以约定式提交前缀开头,匹配主要变更类型:
- — 新功能或能力
feat - — bug修复
fix - — 仅文档变更
docs - — 工具、依赖、配置变更,无行为变化
chore - — 代码重构,无行为变化
refactor - — 测试用例添加或修复
test
- 包含简洁的祈使语气主题行(≤72字符)。
- 当差异非 trivial 时,添加简短的正文(2-5行),总结原因而非仅内容。
- 追加 尾注,标识生成此提交的模型。使用系统提示词中的模型名称(例如
Co-Authored-By、Claude Opus 4.6)。如果无法确定模型名称,请使用Gemini 2.5 Pro作为备选。AI Assistant
示例格式:
feat(terraform): add Cloudflare DNS module for hub provisioning
Operators can now point DNS at Cloudflare without migrating their zone.
Module is activated by dns_provider=cloudflare and requires only
CLOUDFLARE_API_TOKEN — no other provider credentials are validated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>Step 4.5 — Pre-commit hook check
步骤4.5 — 预提交钩子检查
Check if pre-commit hooks are configured:
bash
test -f .pre-commit-config.yaml && command -v pre-commit >/dev/null 2>&1 && echo "hooks-configured" || echo "no-hooks"If , emit a one-time warning (do not repeat if the same session already warned):
no-hooksWARN: No pre-commit hooks configured. Runto set up security scanning./swain-init
Continue to Step 5 regardless — hooks are recommended but not required.
检查是否配置了预提交钩子:
bash
test -f .pre-commit-config.yaml && command -v pre-commit >/dev/null 2>&1 && echo "hooks-configured" || echo "no-hooks"如果结果为 ,发出一次性警告(如果同一会话已警告过则不再重复):
no-hooks警告:未配置预提交钩子。运行以设置安全扫描。/swain-init
无论结果如何,继续执行步骤5 — 钩子是推荐项而非必需项。
Step 5 — Commit
步骤5 — 提交
bash
git --no-pager commit -m "$(cat <<'EOF'
<generated message here>
EOF
)"Use a heredoc so multi-line messages survive the shell without escaping issues.
IMPORTANT: Never use . If pre-commit hooks are installed, they MUST run. There is no bypass.
--no-verifyIf the commit fails because a pre-commit hook rejected it:
- Parse the output to identify which hook(s) failed and what was found
- Present findings clearly:
Pre-commit hook failed: gitleaks: 2 findings (describe what was flagged)Fix the findings and runagain. Suppress false positives: add to
/swain-sync.gitleaksignore - Stop execution — do not push. Do not retry automatically.
bash
git --no-pager commit -m "$(cat <<'EOF'
<generated message here>
EOF
)"使用here-document确保多行消息在shell中无需转义即可正常使用。
重要提示: 请勿使用 。如果安装了预提交钩子,必须运行。无法绕过。
--no-verify如果提交因预提交钩子拒绝而失败:
- 解析输出以确定哪些钩子失败以及发现了什么问题
- 清晰呈现问题:
预提交钩子失败: gitleaks: 2个问题(描述被标记的内容)请修复问题后重新运行。 抑制误报:添加到
/swain-sync.gitleaksignore - 停止执行 — 请勿推送,请勿自动重试。
Step 6 — Push
步骤6 — 推送
If : push the worktree's commits directly to rather than creating a remote worktree branch:
IN_WORKTREE=yesmainbash
git push origin HEAD:mainIf this push is rejected with a non-fast-forward error:
- Check whether the rejection message mentions branch protection rules or required reviews.
- If branch protection is the cause, open a PR instead:
Report the PR URL. Do not retry the push. Proceed to worktree pruning below.bash
BRANCH=$(git rev-parse --abbrev-ref HEAD) SUBJECT=$(git log -1 --pretty=format:'%s') BODY=$(git log -1 --pretty=format:'%b') gh pr create --base main --head "$BRANCH" --title "$SUBJECT" --body "$BODY" - If diverged history is the cause (not branch protection), report the conflict and stop. Do not force-push.
- If branch protection is the cause, open a PR instead:
After a successful push or PR creation, remove the worktree:
bash
WORKTREE_PATH=$(git worktree list --porcelain | grep -B2 "HEAD" | awk '/worktree/{print $2}' | grep -v "$(git rev-parse --git-common-dir | sed 's|/.git$||')")
git -C "$(git rev-parse --show-toplevel 2>/dev/null || git rev-parse --git-common-dir | sed 's|/.git||')" worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
git -C "$(git rev-parse --git-common-dir | sed 's|/.git||')" worktree prune 2>/dev/null || trueIf (main worktree, normal case):
IN_WORKTREE=nobash
git push # or: git push -u origin HEAD (if no upstream)If push fails due to divergent history (shouldn't happen after Step 1 rebase, but as a safety net):
bash
git --no-pager pull --rebase
git push如果 : 将工作树的提交直接推送到 分支,而不是创建远程工作树分支:
IN_WORKTREE=yesmainbash
git push origin HEAD:main如果推送因非快进错误被拒绝:
- 检查拒绝消息是否提到分支保护规则或必需的审核。
- 如果分支保护是原因,请改为创建PR:
报告PR链接。请勿重试推送。继续执行下方的工作树清理步骤。bash
BRANCH=$(git rev-parse --abbrev-ref HEAD) SUBJECT=$(git log -1 --pretty=format:'%s') BODY=$(git log -1 --pretty=format:'%b') gh pr create --base main --head "$BRANCH" --title "$SUBJECT" --body "$BODY" - 如果历史分歧是原因(非分支保护),请报告冲突并停止。请勿强制推送。
- 如果分支保护是原因,请改为创建PR:
推送成功或PR创建完成后,删除工作树:
bash
WORKTREE_PATH=$(git worktree list --porcelain | grep -B2 "HEAD" | awk '/worktree/{print $2}' | grep -v "$(git rev-parse --git-common-dir | sed 's|/.git$||')")
git -C "$(git rev-parse --show-toplevel 2>/dev/null || git rev-parse --git-common-dir | sed 's|/.git||')" worktree remove --force "$WORKTREE_PATH" 2>/dev/null || true
git -C "$(git rev-parse --git-common-dir | sed 's|/.git||')" worktree prune 2>/dev/null || true如果 (主工作树,常规情况):
IN_WORKTREE=nobash
git push # 或:git push -u origin HEAD(如果没有上游分支)如果推送因历史分歧失败(步骤1的变基后不应发生,但作为安全措施):
bash
git --no-pager pull --rebase
git pushStep 7 — Verify
步骤7 — 验证
Run and to verify the push landed and show the user the final state. Do not prompt for confirmation — just report the result.
git --no-pager statusgit --no-pager log --oneline -3运行 和 以验证推送是否成功,并向用户显示最终状态。无需等待确认,直接报告结果。
git --no-pager statusgit --no-pager log --oneline -3Index rebuild (SPEC-047)
索引重建(SPEC-047)
Before committing (after staging, before Step 5), check whether any artifact index files () are stale. If exists, run it for each artifact type that had changes staged:
list-*.mdskills/swain-design/scripts/rebuild-index.shbash
REBUILD_SCRIPT="$REPO_ROOT/skills/swain-design/scripts/rebuild-index.sh"
if [[ -x "$REBUILD_SCRIPT" ]]; then
# Detect which types had staged changes
for type in spec epic spike adr persona runbook design vision journey; do
if git diff --cached --name-only | grep -q "^docs/$type/"; then
bash "$REBUILD_SCRIPT" "$type"
git add "docs/$type/list-${type}.md" 2>/dev/null || true
fi
done
fiThis ensures the index is current when the session's commits land.
提交前(暂存后,步骤5之前),检查是否有工件索引文件()已过期。如果存在 ,请为每个有变更暂存的工件类型运行该脚本:
list-*.mdskills/swain-design/scripts/rebuild-index.shbash
REBUILD_SCRIPT="$REPO_ROOT/skills/swain-design/scripts/rebuild-index.sh"
if [[ -x "$REBUILD_SCRIPT" ]]; then
# 检测哪些类型有暂存的变更
for type in spec epic spike adr persona runbook design vision journey; do
if git diff --cached --name-only | grep -q "^docs/$type/"; then
bash "$REBUILD_SCRIPT" "$type"
git add "docs/$type/list-${type}.md" 2>/dev/null || true
fi
done
fi这可以确保会话的提交完成后索引是最新的。
Session bookmark
会话书签
After a successful push, update the bookmark. Use (set in Step 1) as the search root so this works from both main and linked worktrees:
$REPO_ROOTbash
bash "$(find "$REPO_ROOT" -path '*/swain-session/scripts/swain-bookmark.sh' -print -quit 2>/dev/null)" "Pushed {n} commits to {branch}"推送成功后,更新书签。使用步骤1中设置的 作为搜索根,以便在主工作树和链接工作树中都能正常工作:
$REPO_ROOTbash
bash "$(find "$REPO_ROOT" -path '*/swain-session/scripts/swain-bookmark.sh' -print -quit 2>/dev/null)" "Pushed {n} commits to {branch}"