|
|
|
@@ -20,7 +20,8 @@
|
|
|
|
|
# phase and is the commit point. Children never commit — by default
|
|
|
|
|
# (PHASE_COMMIT=1) the harness makes ONE atomic commit per completed phase
|
|
|
|
|
# (code changes + the file move + the executor reports), scoped so the
|
|
|
|
|
# owner's pre-existing worktree changes are left alone (see commit_phase).
|
|
|
|
|
# owner's pre-existing worktree changes are left alone, and pushes it when
|
|
|
|
|
# the repo has a remote (PHASE_PUSH=1; see commit_phase / push_phase).
|
|
|
|
|
|
|
|
|
|
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
|
EXECUTOR_PROMPT_FILE="$SKILL_DIR/assets/executor-prompt.md"
|
|
|
|
@@ -303,12 +304,13 @@ run_validation() {
|
|
|
|
|
bash .agents/validate.sh >"$1" 2>&1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- phase commit -------------------------------------------------------------
|
|
|
|
|
# --- phase commit + push ------------------------------------------------------
|
|
|
|
|
# Commit ownership: child executors NEVER commit (their prompts forbid it,
|
|
|
|
|
# overriding any project instruction to commit per task/phase). By default
|
|
|
|
|
# (PHASE_COMMIT=1) the harness therefore makes ONE atomic commit per
|
|
|
|
|
# completed phase — the phase's code changes, the todo→complete file move,
|
|
|
|
|
# and the executor reports, together — at the phase's commit point.
|
|
|
|
|
# and the executor reports, together — at the phase's commit point, and
|
|
|
|
|
# pushes it right after (PHASE_PUSH=1, default — see push_phase).
|
|
|
|
|
#
|
|
|
|
|
# Staging is scoped so the owner's unrelated work is not swept in:
|
|
|
|
|
# stage = (everything dirty now)
|
|
|
|
@@ -334,9 +336,11 @@ phase_dirty_snapshot() {
|
|
|
|
|
# Returns 0 on success, when there is nothing left to commit, or outside a
|
|
|
|
|
# git work tree. Returns 1 (after printing a ✗ ERROR block with the git
|
|
|
|
|
# error and the hand-fix command) when the phase's own artifacts could not
|
|
|
|
|
# be committed. The phase stays COMPLETE either way — the work passed
|
|
|
|
|
# validation; the caller stops the run so a commit miss is visible, never
|
|
|
|
|
# retried as a task and never swept into a later phase's commit.
|
|
|
|
|
# be committed, or the push of the phase commit failed (the commit is local
|
|
|
|
|
# and safe — the next phase's push sweeps it in once the push works). The
|
|
|
|
|
# phase stays COMPLETE either way — the work passed validation; the caller
|
|
|
|
|
# stops the run so a commit/push miss is visible, never retried as a task
|
|
|
|
|
# and never swept into a later phase's commit.
|
|
|
|
|
commit_phase() {
|
|
|
|
|
local unit="$1" report="${2:-}"
|
|
|
|
|
local phase pre curf paths lits moved staged addout commitout subject msgf
|
|
|
|
@@ -441,6 +445,49 @@ commit_phase() {
|
|
|
|
|
fi
|
|
|
|
|
rm -f "$msgf" "$pre"
|
|
|
|
|
echo " (committed: $(git log -1 --oneline))"
|
|
|
|
|
# Hand the commit to the remote (PHASE_PUSH, default on). A push failure
|
|
|
|
|
# returns 1 so the run stops — same contract as a commit failure.
|
|
|
|
|
if ! push_phase "$phase"; then
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# push_phase <phase>
|
|
|
|
|
# Pushes the phase commit made by commit_phase (PHASE_PUSH=1, default).
|
|
|
|
|
# No remote configured → notice and success (the commit stays local).
|
|
|
|
|
# Branch with an upstream → `git push`; without → `git push -u <first
|
|
|
|
|
# remote> <branch>`. On failure prints a ✗ ERROR block with the git error
|
|
|
|
|
# and the hand-fix command and returns 1 — the commit is local and safe,
|
|
|
|
|
# and the next phase's push sweeps the unpushed commit in once the push
|
|
|
|
|
# works.
|
|
|
|
|
push_phase() {
|
|
|
|
|
local phase="$1" remote branch cmd pushout
|
|
|
|
|
[[ "${PHASE_PUSH:-1}" == "1" ]] || { echo " (PHASE_PUSH=0 — commit not pushed, left local)"; return 0; }
|
|
|
|
|
remote="$(git remote 2>/dev/null | head -n1)"
|
|
|
|
|
if [[ -z "$remote" ]]; then
|
|
|
|
|
echo " (no git remote configured — skipping push)"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
branch="$(git symbolic-ref --short -q HEAD || true)"
|
|
|
|
|
if [[ -z "$branch" ]]; then
|
|
|
|
|
echo "✗ ERROR: phase push for $phase — detached HEAD, nothing to push." >&2
|
|
|
|
|
echo " the phase commit is local; push by hand once you are on a branch." >&2
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
if git rev-parse --abbrev-ref --disambiguate '@{u}' >/dev/null 2>&1; then
|
|
|
|
|
cmd=(git push)
|
|
|
|
|
else
|
|
|
|
|
cmd=(git push -u "$remote" "$branch")
|
|
|
|
|
fi
|
|
|
|
|
if ! pushout="$("${cmd[@]}" 2>&1)"; then
|
|
|
|
|
echo "✗ ERROR: phase push for $phase FAILED — the phase is committed LOCALLY but NOT PUSHED." >&2
|
|
|
|
|
printf '%s\n' "$pushout" | sed 's/^/ /' >&2
|
|
|
|
|
echo " finish by hand: ${cmd[*]}" >&2
|
|
|
|
|
echo " re-running will NOT re-push it now — the next phase's push sweeps it in once the push works; fix the push first." >&2
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
echo " (pushed: $(git log -1 --oneline))"
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -482,8 +529,8 @@ notify_task() {
|
|
|
|
|
# execute_unit <unit>
|
|
|
|
|
# Returns 0 and moves the unit to complete/ on success; returns 1 after
|
|
|
|
|
# MAX_FIX_ATTEMPTS failed attempts (unit file is left in todo/), or 1 when
|
|
|
|
|
# the phase commit fails at a phase's commit point (unit stays in
|
|
|
|
|
# complete/ — the work is done; the commit must be finished by hand).
|
|
|
|
|
# the phase commit or its push fails at a phase's commit point (unit stays
|
|
|
|
|
# in complete/ — the work is done; the commit/push must be finished by hand).
|
|
|
|
|
execute_unit() {
|
|
|
|
|
local unit="$1"
|
|
|
|
|
local base attempt=1 errors=""
|
|
|
|
@@ -544,7 +591,7 @@ execute_unit() {
|
|
|
|
|
# The work is done and validated; the unit stays in complete/ and
|
|
|
|
|
# re-running will NOT re-execute this phase. Stop the run so the
|
|
|
|
|
# commit miss is visible — commit_phase printed the hand-fix.
|
|
|
|
|
echo " phase work is UNCOMMITTED — fix the commit first (see above); re-running continues at the next phase" >&2
|
|
|
|
|
echo " phase commit/push did not complete — fix it first (see above); re-running continues at the next phase" >&2
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|