跳到主要内容
知仓学习社ZHICANG

stack-mode

Detects shared stack membership and iterates a command across all PRs in base-to-tip order. Use when a command supports --stack flag for multi-PR it…

不碰外部(只输出文字)无严重或高危命中athola/claude-night-market

它会碰到什么

扫了多少1 个文本文件,10 KB
它会碰到什么不碰外部(只输出文字)
命中总数0 处
命中统计严重 0 · 高 0 · 中 0 · 低 0

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

Stack Mode

Shared contract for commands that need to operate across a

whole stack of dependent PRs in one invocation.

Used by /pr-review --stack and /fix-pr --stack.

The goal is one simple thing: when a PR is part of a stack

targeting a common base branch, loop the command's normal

workflow across every PR in the stack in base-to-tip order

and emit one consolidated summary on the stack root.

When To Use

Load this skill when a command accepts a --stack flag

(or auto-detects stack membership) and needs to iterate

its normal workflow across multiple PRs.

Do NOT load this skill for single-PR workflows. The

per-PR workflow stays unchanged; stack mode wraps it.

When NOT To Use

  • Creating the stack (use sanctum:stack-create)
  • Cascading a rebase through it (use sanctum:stack-rebase)

Contract

A calling command MUST:

  1. Accept a --stack boolean flag AND a --base <branch>

override (default: master).

  1. Call Step 1 below to resolve stack membership BEFORE

running its main workflow.

  1. Run its main workflow per PR in the resolved order.
  2. Emit per-PR outputs unchanged (thread replies, issue

links, etc.).

  1. Emit ONE stack-level summary comment on the root PR

using the format in Step 4.

  1. Respect per-PR Gate rules (every PR still needs its own

thread resolution and issue tracking).

A calling command MAY:

  • Auto-detect stack membership and prompt the user rather

than requiring --stack explicitly.

  • Short-circuit iteration when a per-PR failure leaves

downstream PRs with stale context.

Required Progress Tracking

The caller creates TodoWrite items:

  1. stack-mode:membership-resolved
  2. stack-mode:iteration-complete
  3. stack-mode:root-summary-posted

Step 1: Resolve Stack Membership (membership-resolved)

Given a starting PR number $PR_NUM and optional base

$BASE (default: master), try three strategies in

order and stop at the first that yields a stack of size

>= 2.

Strategy A: Branch-name convention (cheapest)

START_HEAD=$(gh pr view "$PR_NUM" \
  --json headRefName -q .headRefName)

# stack/<feature-name>/<slice-name>
if [[ "$START_HEAD" =~ ^stack/([^/]+)/.+$ ]]; then
  FEATURE="${BASH_REMATCH[1]}"
  PREFIX="stack/${FEATURE}/"

  # All local branches with the same prefix
  STACK_BRANCHES=$(git branch --list "${PREFIX}*" \
    | sed 's/^[* ]*//' | sort)

  # Map branches -> PR numbers (skip branches with no PR)
  STACK_PRS=()
  for branch in $STACK_BRANCHES; do
    pr=$(gh pr list --head "$branch" \
      --json number --jq '.[0].number')
    [ -n "$pr" ] && STACK_PRS+=("$pr")
  done

  echo "strategy=A prs=${STACK_PRS[*]}"
fi

Strategy B: Stack summary comment (most reliable)

stack-push posts a ## Stack markdown table on the

root PR with columns # | Branch | PR. Parse it:

# Find the root PR of the stack containing $PR_NUM
# The current PR may be the root, or may link to it via
# a "Part of stack `stack/<feature>`" phrase in its body
BODY=$(gh pr view "$PR_NUM" --json body -q .body)

# Look for a "## Stack" table in THIS PR's comments
TABLE=$(gh pr view "$PR_NUM" --json comments \
  --jq '.comments[] | select(.body | contains("## Stack"))
        | .body' | head -1)

# If not on this PR, look for the root PR reference
if [ -z "$TABLE" ]; then
  ROOT_REF=$(echo "$BODY" \
    | grep -oE 'stack/[^ `]+' | head -1)
  # ... resolve ROOT_REF -> root PR number and re-fetch
fi

# Parse the table: extract all `#<num>` from the PR column
STACK_PRS=($(echo "$TABLE" \
  | grep -oE '#[0-9]+' | tr -d '#' | sort -un))

echo "strategy=B prs=${STACK_PRS[*]}"

Strategy C: Base-chain walk (fallback)

Walk both directions from $PR_NUM:

  • Up: repeatedly resolve baseRefName until it equals

$BASE. Each visited head is a stack member.

  • Down: find open PRs whose baseRefName equals one of

the visited heads. Recurse.

# Ascend from $PR_NUM to the root
CUR=$PR_NUM
CHAIN=($CUR)
while true; do
  BASE_REF=$(gh pr view "$CUR" \
    --json baseRefName -q .baseRefName)
  [ "$BASE_REF" = "$BASE" ] && break

  PARENT=$(gh pr list --head "$BASE_REF" \
    --state open --json number --jq '.[0].number')
  [ -z "$PARENT" ] && break

  CHAIN=("$PARENT" "${CHAIN[@]}")
  CUR=$PARENT
done

# Descend from the root collecting children
ROOT=${CHAIN[0]}
FRONTIER=("$ROOT")
while [ ${#FRONTIER[@]} -gt 0 ]; do
  PARENT=${FRONTIER[0]}
  FRONTIER=("${FRONTIER[@]:1}")

  PARENT_HEAD=$(gh pr view "$PARENT" \
    --json headRefName -q .headRefName)

  CHILDREN=($(gh pr list --base "$PARENT_HEAD" \
    --state open --json number --jq '.[].number'))

  for c in "${CHILDREN[@]}"; do
    CHAIN+=("$c")
    FRONTIER+=("$c")
  done
done

STACK_PRS=("${CHAIN[@]}")
echo "strategy=C prs=${STACK_PRS[*]}"

Ordering

Regardless of strategy, order the final list base-to-tip

(root PR first, leaf PR last). The root is the PR whose

baseRefName equals $BASE.

ROOT_PR=""
for p in "${STACK_PRS[@]}"; do
  base=$(gh pr view "$p" --json baseRefName -q .baseRefName)
  if [ "$base" = "$BASE" ]; then
    ROOT_PR=$p
    break
  fi
done

If the stack size is 1, the command MUST fall back to

single-PR mode and emit a warning: `stack-mode: only one

PR found; --stack has no effect, proceeding as single-PR`.

GitLab / Bitbucket

See Skill(leyline:git-platform) for glab / Bitbucket

equivalents of the gh calls above. The three strategies

translate directly: GitLab MR dependencies replace

base-chain walks, and the glab mr view --output json

shape matches gh pr view.

Step 2: Confirm With User (if not explicit)

When the caller did NOT pass --stack but Step 1 resolved

a stack of size >= 2, print the stack and ask:

Detected stack of N PRs rooted at #<root>:
  1. #<root>   <title>
  2. #<p2>     <title>
  ...

Run the workflow on the full stack? [y/N]

Default to "N" (single-PR mode). With --stack explicit,

skip this prompt.

Step 3: Iterate (iteration-complete)

Run the caller's main workflow once per PR in base-to-tip

order:

FAILED_PRS=()
for p in "${STACK_PRS[@]}"; do
  echo "=== stack-mode: PR #$p ($(($idx+1))/${#STACK_PRS[@]}) ==="

  # Caller hook: run the single-PR workflow on $p
  # This includes Gate 1 (thread resolution) and
  # Gate 2 (issue tracking) per the caller's contract.
  if ! run_single_pr_workflow "$p"; then
    FAILED_PRS+=("$p")
    # Stop iteration: downstream PRs may now be stale
    break
  fi
done

If any PR fails, the command MUST stop and report

stack-mode: halted at #<pr>; downstream PRs untouched.

Downstream PRs are intentionally left alone because

their context may have shifted.

Step 4: Post Stack Summary on Root (root-summary-posted)

After successful iteration, post ONE consolidated summary

comment on the root PR. This does NOT replace per-PR

summaries: it links them together.

## Stack <Command Name> Summary

**Stack**: N PRs rooted at #<root>, base `<base-branch>`
**Command**: <command> (e.g., /fix-pr, /pr-review)
**Run**: <timestamp>

| # | PR | Branch | Status | Per-PR Summary |
|---|----|--------|--------|----------------|
| 1 | #<root> | `stack/<feat>/<root-slice>` | <done/skipped/failed> | [link to comment] |
| 2 | #<p2>   | `stack/<feat>/<slice-2>`    | <done/skipped/failed> | [link to comment] |
| ... | ... | ... | ... | ... |

### Cross-PR Notes

- <Any observations that spanned multiple PRs>
- <Issues created that reference multiple stack PRs>
- <Base-PR-merged cascade reminders, if any>

### Next Steps

- If root PR merges, run `Skill(sanctum:stack-rebase)` to
  cascade the base update through descendants.
- Reviewers: rebase-triggered stale-review flags on
  descendants are expected after any force-push.

Post via gh pr comment "$ROOT_PR" --body-file <file>.

Failure Modes and Recovery

| Failure | Detection | Recovery |

|---------|-----------|----------|

| Stack of size 1 | Step 1 returns one PR | Emit warning, fall back to single-PR mode |

| Base chain loops | Visited set on ascent | Halt, report stack-mode: cycle detected |

| Mid-stack PR failed its Gates | Caller raises | Halt iteration, leave downstream untouched |

| Strategy B table malformed | Parse fails | Fall through to Strategy C |

| Auth scope insufficient | gh returns 403 | Halt with clear error; caller surfaces to user |

Notes

  • Stack mode is ADDITIVE: single-PR behavior is unchanged.

Only the iteration and root summary are new.

  • Per-PR Gate 1 (thread resolution) and Gate 2 (issue

tracking) remain unchanged: each PR still passes its

own gates independently.

  • Never merge Gate 1 across the stack. A resolved thread

on one PR is not a resolved thread on another.

  • The root summary is idempotent: re-running stack mode

should update (not duplicate) the summary comment.

Match on ## Stack <Command Name> Summary as the key.

  • stack-mode is a read/orchestration skill; it does NOT

push, rebase, or edit branches. Those concerns are in

stack-create, stack-push, and stack-rebase.

Exit Criteria

  • [ ] Stack membership resolved using at least one of the three

strategies (A: branch names, B: stack comment, C: base-chain

walk) and PRs ordered base-to-tip before iteration starts

  • [ ] The 3 required TodoWrite items (stack-mode:membership-resolved,

stack-mode:iteration-complete, stack-mode:root-summary-posted)

are created and marked complete in sequence

  • [ ] Root PR receives exactly one consolidated `## Stack <Command>

Summary` comment after all PRs are processed

  • [ ] If stack size is 1, warning `stack-mode: only one PR found;

--stack has no effect` is emitted and single-PR mode used

  • [ ] If a PR fails its gates, iteration halts and downstream PRs

are left untouched with a stack-mode: halted at #<pr> report

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。