agent-exec transport b918a843562d4d29b3efc3da6ee19803/557f53579497

This commit is contained in:
agent-exec-transport
2026-10-16 16:21:24 +00:00
parent 16569d38cb
commit 602cba9373
6 changed files with 1181 additions and 94 deletions
+40 -21
View File
@@ -74,7 +74,7 @@ cmd_precheck() {
[ -n "$done_open" ] && echo "[cards] 已完成但未归档:$(echo $done_open)"
local initiatives
initiatives=$(active_initiatives | cut -d'|' -f1)
echo "[initiatives] active: $([ -n "$initiatives" ] && echo $initiatives || echo none)"
echo "[initiatives] local cards (not authoritative): $([ -n "$initiatives" ] && echo $initiatives || echo none)"
now=$(date +%s)
while read -r ref ts; do
[ -n "$ref" ] || continue
@@ -152,10 +152,28 @@ cmd_start() {
echo "$initiative" | grep -qE '^(feature|fix|hotfix|release)/[A-Za-z0-9._-]+$' || die "invalid parent initiative branch"
case "${name#*/}" in "${initiative#*/}"-?*) ;; *) die "child slug must start with parent initiative slug plus '-'" ;; esac
fi
[ -n "${TRIAGE_RECEIPT:-}" ] || die "TRIAGE_RECEIPT required: make task-triage REQ='<需求>' TRIAGE_RECEIPT=<path> and decide first (no branch created)"
fetch_target
[ -n "${PRECHECK_RECEIPT:-}" ] || die "PRECHECK_RECEIPT required: capture RECEIPT=/tmp/task-precheck.json CMD='make precheck' make evidence first"
PRECHECK_RECEIPT=$(realpath -- "$PRECHECK_RECEIPT")
VALIDATE_RECEIPT="$PRECHECK_RECEIPT" VALIDATE_RECEIPT_PURPOSE=start bash "${SCRIPT_DIR}/evidence.sh"
# 分流核验必须先于任何 worktree/分支创建:收据与当前远端候选不一致则无副作用拒绝。
[ -f "$TRIAGE_RECEIPT" ] || die "triage receipt missing: ${TRIAGE_RECEIPT} (no branch created)"
TRIAGE_RECEIPT=$(realpath -- "$TRIAGE_RECEIPT")
local -a triage_args=(verify --receipt "$TRIAGE_RECEIPT" --kind "$kind")
if [ "$kind" = child ]; then triage_args+=(--initiative "$initiative"); fi
local triage_out triage_line triage_verdict triage_init triage_rsha triage_digest triage_note
if ! triage_out=$(python3 "${SCRIPT_DIR}/task_triage.py" "${triage_args[@]}"); then
printf '%s\n' "$triage_out" >&2
die "triage receipt rejected; no worktree or branch was created"
fi
triage_line=$(printf '%s\n' "$triage_out" | sed -n 's/^\[triage-verified\] //p')
triage_verdict=$(triage_field verdict "$triage_line")
triage_init=$(triage_field selected_initiative "$triage_line")
triage_rsha=$(triage_field requirement_sha256 "$triage_line")
triage_digest=$(triage_field receipt_sha256 "$triage_line")
[ -n "$triage_verdict" ] && [ -n "$triage_rsha" ] && [ -n "$triage_digest" ] || die "triage verification output unparsable; no branch created"
triage_note="- 需求分流:verdict=${triage_verdict};selected_initiative=${triage_init:-无};requirement_sha256=${triage_rsha};triage_receipt=${TRIAGE_RECEIPT};receipt_sha256=${triage_digest}"
check_worktree before-sync
# 已合入的同名分支不得重建(2026-10-05 实测:合入后再 task-start 同名会从新 main 长出
# 第二段历史,空卡覆盖已合入任务卡,两轮证据差点丢失)。复核/追加沿用原分支或换新 slug。
@@ -220,6 +238,7 @@ cmd_start() {
- 权威仓:$(git -C "$wt" remote get-url origin 2>/dev/null || echo '(local)');目标分支:${TARGET_BRANCH};R0(initial_base_sha)= ${rmain}
- 工作区:${wt}(worktree);分支:${name}
${branch_meta}
${triage_note}
${parent_note}
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进)
@@ -473,28 +492,27 @@ resolve_parent_ref() { # $1=父 initiative 分支 → 打印用于同步/核验
fi
}
# 需求分流以 origin 为准(scripts/task_triage.py):远端 open PR + 远端分支卡片;本地 .task/ 不参与发现。
# 计数不自动选择 JOIN;候选存在时必须经 triage-decide 记录显式决策。
cmd_triage() {
need_repo
local req="${*:-}" list n line b id c
[ -n "$req" ] && echo "[triage] requirement: ${req}"
list=$(active_initiatives)
n=$(printf '%s' "$list" | grep -c '|' || true)
echo "[triage] active initiatives: ${n}"
while IFS= read -r line; do
[ -n "$line" ] || continue
IFS='|' read -r b id c <<<"$line"
echo "[initiative] branch=${b} initiative_id=${id:-无} card=${c}"
done <<<"$list"
if [ "$n" -eq 0 ]; then
echo "[verdict] NEW — no active initiative; start one with make task-start NAME=feature/<slug> KIND=initiative (or KIND=standalone)"
elif [ "$n" -eq 1 ]; then
b=${list%%|*}
echo "[verdict] JOIN — join initiative ${b}: make task-start NAME=${b}-<topic> KIND=child INITIATIVE=${b}"
else
echo "[verdict] DECISION_REQUIRED — ${n} active initiatives; the user must choose which one receives this requirement (or approve a new one)"
return 5
fi
[ -n "${TRIAGE_RECEIPT:-}" ] || die "TRIAGE_RECEIPT required: make task-triage REQ='<需求>' TRIAGE_RECEIPT=/tmp/<name>.json"
local req="${*:-}"
[ -n "$req" ] || die "requirement text required: make task-triage REQ='<需求>' TRIAGE_RECEIPT=<path>"
python3 "${SCRIPT_DIR}/task_triage.py" discover --receipt "$TRIAGE_RECEIPT" --requirement "$req"
}
cmd_triage_decide() {
need_repo
[ -n "${TRIAGE_RECEIPT:-}" ] || die "TRIAGE_RECEIPT required: make task-triage-decide TRIAGE_RECEIPT=<path> VERDICT=JOIN|NEW REASON='<理由>'"
local -a args=(decide --receipt "$TRIAGE_RECEIPT" --verdict "${VERDICT:-}" --reason "${REASON:-}")
if [ -n "${INITIATIVE:-}" ]; then args+=(--initiative "$INITIATIVE"); fi
python3 "${SCRIPT_DIR}/task_triage.py" "${args[@]}"
}
# triage_field KEY "key=value key2=value2" → value(值不含空格)
triage_field() { printf '%s\n' "$2" | tr ' ' '\n' | sed -n "s/^$1=//p"; }
card_merge() { # $1=branch → "sha|subject|pr"(该分支合入 origin/<target> 的记录;兼容 merge 提交与 squash 落地)
local hit pr
hit=$(git log --merges --format='%H|%s' "origin/${TARGET_BRANCH}" 2>/dev/null \
@@ -769,10 +787,11 @@ cmd_finish() {
case "${1:-}" in
precheck) shift; cmd_precheck "$@" ;;
triage) shift; cmd_triage "$@" ;;
triage-decide) shift; cmd_triage_decide "$@" ;;
start) shift; cmd_start "$@" ;;
resume) shift; cmd_resume "$@" ;;
sync) shift; cmd_sync "$@" ;;
close) shift; cmd_close "$@" ;;
finish) shift; cmd_finish "$@" ;;
*) echo "usage: task.sh <precheck|triage|start|resume|sync|close|finish> [args]"; exit 2 ;;
*) echo "usage: task.sh <precheck|triage|triage-decide|start|resume|sync|close|finish> [args]"; exit 2 ;;
esac