From 471948c59cfabff36c018f219998139fea3757fe Mon Sep 17 00:00:00 2001 From: agent-exec-transport Date: Sun, 18 Oct 2026 15:46:44 +0000 Subject: [PATCH] agent-exec transport 7bc7519fb1dc6e9f12e152359a795c89/731d7f5ba3a5 --- scripts/task.sh | 51 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/scripts/task.sh b/scripts/task.sh index da30cc4a..164cafa4 100755 --- a/scripts/task.sh +++ b/scripts/task.sh @@ -18,10 +18,30 @@ fetch_target() { git rev-parse --verify "refs/remotes/origin/${TARGET_BRANCH}^{commit}" >/dev/null \ || { echo "[verdict] REMOTE_UNVERIFIED — target commit missing" >&2; return 6; } } -target_history() { # $1=可选基线(无缓存目标时代替比较,如任务 R0)→ 输出 ok(远端不可查询/通告提交为基线后代)、rewound(回退或分叉)或 uncomparable(远端可查询但目标 ref 缺失、无基线、通告提交本地缺失或无法比较) +origin_transport_unavailable() { # $1=失败的远端命令 stderr → 仅明确的传输失败(DNS/连接超时/拒绝/重置/无路由,或本地缺失仓库路径)返回 0;认证/授权/权限与未知错误返回 1 + local err=$1 url path + if printf '%s\n' "$err" | grep -qiE 'authentication failed|permission denied|unauthori[sz]ed|forbidden|HTTP[^0-9]*40[13]|\b40[13]\b|could not read (username|password)|terminal prompts disabled|invalid credentials|access denied|host key verification failed'; then + return 1 + fi + if printf '%s\n' "$err" | grep -qiE 'could not resolve (host|hostname|proxy)|name or service not known|temporary failure in name resolution|nodename nor servname|connection timed out|operation timed out|timed out after|connection refused|connection reset|no route to host|network is unreachable|couldn.t connect to server'; then + return 0 + fi + printf '%s\n' "$err" | grep -qF 'does not appear to be a git repository' || return 1 + url=$(git remote get-url origin 2>/dev/null) || return 1 + case "$url" in + file://*) path=${url#file://} ;; + /*|./*|../*) path=$url ;; + *) return 1 ;; + esac + [ ! -e "$path" ] +} +target_history() { # $1=可选基线(无缓存目标时代替比较,如任务 R0)→ 输出 ok(远端传输不可达/通告提交为基线后代)、rewound(回退或分叉)或 uncomparable(认证/授权/未知错误、目标 ref 缺失、无基线、通告提交本地缺失或无法比较) local cached listing advertised rc=0 cached=$(git rev-parse -q --verify "refs/remotes/origin/${TARGET_BRANCH}^{commit}" 2>/dev/null) || cached=${1:-} - listing=$(git ls-remote origin "refs/heads/${TARGET_BRANCH}" 2>/dev/null) || { echo ok; return 0; } + if ! listing=$(git ls-remote origin "refs/heads/${TARGET_BRANCH}" 2>&1); then + if origin_transport_unavailable "$listing"; then echo ok; else echo uncomparable; fi + return 0 + fi advertised=$(printf '%s\n' "$listing" \ | awk -v ref="refs/heads/${TARGET_BRANCH}" '$2 == ref && !seen { print $1; seen = 1 }') [ -n "$advertised" ] && [ -n "$cached" ] || { echo uncomparable; return 0; } @@ -70,7 +90,10 @@ cmd_precheck() { echo "[tree] $([ "$dirty" -eq 0 ] && echo clean || echo "dirty(${dirty})") submodules_drift=${sub_drift} uninit=${sub_uninit}" local wt merged wt=$(git worktree list | tail -n +2 | wc -l) - merged=$(git branch --merged "origin/${TARGET_BRANCH}" 2>/dev/null | { grep -vE 'main|master|\*' || true; } | tr -d ' +') + merged="" + if git rev-parse -q --verify "refs/remotes/origin/${TARGET_BRANCH}^{commit}" >/dev/null 2>&1; then + merged=$(git branch --merged "origin/${TARGET_BRANCH}" 2>/dev/null | { grep -vE 'main|master|\*' || true; } | tr -d ' +') + fi [ "${sub_uninit:-0}" -gt 0 ] && echo "[warn] ${sub_uninit} 个子模块未初始化——构建/测试前需物化(不阻断写入)" echo "[worktrees] linked=${wt}" [ -n "$merged" ] && echo "[recycle] merged un-recycled branches: $(echo $merged)" @@ -518,8 +541,18 @@ cmd_resume() { fi fi if [ "$immediate" != "${TARGET_BRANCH}" ]; then - observed=$(resolve_parent_ref "$immediate") || die "immediate target ${immediate} unavailable; receipt not imported" recorded=$(card_field "$card" parent_head_sha) + if [ "$mode" = local ]; then + # local 续作只以登记的父头为比较基准:缺失、非完整 SHA 或本地无此提交时不得回落到本地父分支。 + local sha_len=40 + [ "$(git rev-parse --show-object-format 2>/dev/null)" = sha256 ] && sha_len=64 + if ! [[ "$recorded" =~ ^[0-9a-f]+$ ]] || [ "${#recorded}" -ne "$sha_len" ] \ + || ! git cat-file -e "${recorded}^{commit}" 2>/dev/null; then + echo "[verdict] REMOTE_UNVERIFIED — registered parent_head_sha for ${immediate} is missing, malformed or not available locally; preserve local work, receipt not imported" >&2 + return 6 + fi + fi + observed=$(resolve_parent_ref "$immediate") || die "immediate target ${immediate} unavailable; receipt not imported" if [ -n "$recorded" ] && ! git merge-base --is-ancestor "$recorded" "$observed"; then die "immediate target ${immediate} no longer contains recorded parent head ${recorded}; receipt not imported" fi @@ -676,8 +709,8 @@ resolve_parent_ref() { # $1=父 initiative 分支 → 打印用于同步/核验 printf '%s\n' "$remote_head" return 0 fi - local remote="" local_ref="" rc=0 - git ls-remote --exit-code --heads origin "refs/heads/$1" >/dev/null 2>&1 || rc=$? + local remote="" local_ref="" rc=0 ls_err + ls_err=$(git ls-remote --exit-code --heads origin "refs/heads/$1" 2>&1 >/dev/null) || rc=$? if [ "$rc" -eq 0 ]; then if ! git fetch -q origin "refs/heads/$1:refs/remotes/origin/$1"; then echo "[verdict] REMOTE_UNVERIFIED — cannot refresh origin/$1; preserve local work and retry" >&2 @@ -688,8 +721,12 @@ resolve_parent_ref() { # $1=父 initiative 分支 → 打印用于同步/核验 # 远端可达而登记的父分支缺失:权威侧已不认该父分支,本地同名分支不得替代。 echo "[verdict] REMOTE_UNVERIFIED — origin is reachable but $1 is missing; preserve local work and reconcile the parent initiative" >&2 return 6 + elif ! origin_transport_unavailable "$ls_err"; then + # 认证/授权/权限或未知错误不等于远端不可达:权威侧状态未知,不得以本地父分支替代。 + echo "[verdict] REMOTE_UNVERIFIED — cannot verify origin/$1 (non-transport remote error); preserve local work and retry" >&2 + return 6 else - # 远端不可查询时只把已登记的本地父分支作为局部续作参考;不声称其为最新或可交付,调用方仍核验 parent_head_sha。 + # 远端传输不可达时只把已登记的本地父分支作为局部续作参考;不声称其为最新或可交付,调用方仍核验 parent_head_sha。 local_ref=$(git rev-parse -q --verify "refs/heads/$1^{commit}" 2>/dev/null || true) if [ -z "$local_ref" ]; then echo "[verdict] REMOTE_UNVERIFIED — cannot query origin/$1 and no local $1 exists; preserve local work and retry" >&2