fix(phased-execution): resume failed session on retry, surface errors, thinking/compaction indicators

- retries now resume the failed executor's session (pre/post session
  tracking replaces the broken mtime-vs-ref check)
- report recovery from the session file when the JSON stream loses its
  tail (child signaled mid-flush)
- progress.mjs: thinking indicators (◐ thinking… / ◑ thought for Ns),
  compaction (⧉ …) and provider auto-retry lines; trims trailing
  whitespace so no blank lines after LLM text; exits 1 on truncated
  stream, model error, or missing final text (pi --mode json always
  exits 0 even on errors)
- explicit ✗ ERROR lines + exit codes: 0 ok, 1 phase failed, 130/143
  interrupted (INT/TERM traps; post-pipeline check covers the case
  where bash suppresses the INT trap after a job dies from SIGINT)
- PIPESTATUS captured in a single statement (any following command
  resets it)
- skills dir: .gitignore README.md so pi's skill scanner (which honors
  .gitignore) stops warning 'description is required'
This commit is contained in:
2026-08-21 11:00:21 -04:00
parent f96ee9382e
commit 3bacbff874
7 changed files with 279 additions and 159 deletions
+27 -8
View File
@@ -14,11 +14,20 @@ Phase state lives in files, not chat:
- `.agent/validate.sh` — the pass/fail gate for every phase
The scripts run each phase in a **separate pi process** (fresh context) with
bounded fixer retries (the failed executor's session is resumed, so retries
keep its work). A phase only moves to `complete/` after the child exits 0
**and** `.agent/validate.sh` passes. This chat only dispatches and relays
results — do not implement phase code yourself; that is what the subprocess
is for.
bounded fixer retries. A phase only moves to `complete/` after the child exits
0, the child's stream ends with a clean final report, **and**
`.agent/validate.sh` passes. This chat only dispatches and relays results —
do not implement phase code yourself; that is what the subprocess is for.
## Live display
While a phase runs, `scripts/progress.mjs` relays the child's JSON stream to
the terminal: tool calls, assistant text, `◐ thinking…` / `◑ thought for Ns`
indicators, yellow `⧉ compacting context` lines (these can take minutes —
not a hang), and provider auto-retry notices. If the child dies mid-flush and
the stream loses the final message, the report is recovered from the
child's session file (`.agent/phase-sessions/`), so a completed phase is
never lost to a truncated stream.
## Commands
@@ -42,11 +51,17 @@ Re-running `auto-phase.sh` after a failure continues where it stopped.
## After a run
Exit codes: `0` = success (or nothing to run), `1` = phase failed after all
attempts / no pending phases error, `130`/`143` = interrupted (Ctrl+C / SIGTERM).
Failures always print a `✗ ERROR:` line with the last error output — if the
script's output looks like it ended abruptly, re-run it; the failed executor's
session is resumed automatically (retries continue the child's own session,
keeping its work).
Relay to the user: the phase name, its executor report (printed at the end of
the script output), and the validation outcome. On failure, point the user at
`.agent/reports/<phase>.a*.{md,err,validate}` and offer to resume the failed
executor's session: `pi --session-dir .agent/phase-sessions -c` (or suggest
running the script again to retry automatically).
`.agent/reports/<phase>.a*.{md,err,validate}` — the script also prints a ready
to run `pi --session … -c “…”` command to continue the failed session manually.
## Configuration (environment variables)
@@ -69,3 +84,7 @@ running the script again to retry automatically).
and `/new-python-*` prompt templates.
- Child executor sessions are kept in `.agent/phase-sessions/`; add it to
`.gitignore` if the project is versioned.
- If you keep non-skill markdown (e.g. a `README.md`) in a skills directory
(like `~/.pi/agent/skills/`), pi warns “description is required” for it.
Add a `.gitignore` in that directory listing the file — pi's skill scanner
honors `.gitignore`, so the file is skipped.