A stalled sub-agent (provider stream never settling after the final tool
call, or a throwing session-event listener recursing through the SDK's
run-failure path to stack overflow) left the phase stuck in_progress with
no state save, no error, and no completion message — observed twice in
freno-dev, both times after comments wrote findings.md.
- agent-runner: 60-min settle watchdog on every agent phase
(PYGIENIUM_AGENT_TIMEOUT_MS, env-tunable); timeout disposes the session
and fails the phase loudly with a /pygienium-resume hint instead of
hanging the check-runner's await forever.
- agent-runner: applySessionEvent — the session.subscribe listener can no
longer throw into the SDK event pipeline (guards for partial/malformed
events, optional-chained message_update, throwing chat forwarder).
- comments: scan no longer regenerates the full report as its final
message (findings.md is the source of truth); fix phase reads
findings.md with embedded fallback.
- check-runner: failing state-save inside the catch path can't double-
fault or escape as an unhandled rejection; completion posting is
best-effort.
- tests: watchdog timeout test, comments task-text regression tests,
applySessionEvent malformed-shape unit tests. 146 pass, tsc clean.
- README: document PYGIENIUM_AGENT_TIMEOUT_MS.
loadAgents merges <cwd>/agents/*.md on top of the extension's baseline:
a repo agent wins on name collision and may add brand-new agents. The
unknown-agent error now names both searched directories.
/pygienium-<check> is now resume-aware (terminal checks skipped unless
--fresh) and shares run-state with all/resume; every check gets a verify
hook that fails loudly when a sub-agent returns ok with no artifact;
run-state clears stale errors on retry success and reconciles a run as
failed only when every check failed. Drops the superseded
hygiene-state.ts model.
phases.ts becomes a live chat widget (spinner + tool-call tree) and the
check-runner posts per-agent tool-call summaries and an expandable
completion tree through a custom message renderer; footer.ts adds the
static pipeline-overview status strip for single checks and /pygienium-all.
All per-check artifacts, all-summary, and export move from pygienium/ to
.pygienium/; ensureRunStateIgnored appends .pygienium/ to the target
repo's .gitignore on first run (opt out with --no-gitignore), so a run
never stages its own output. Export now reads a single canonical root.
/pygienium-todos inventories TODO/FIXME/HACK markers and stub bodies via a
deterministic pre-scan plus the todos sub-agent; --fix converts silent
stubs (placeholder returns, empty/pass bodies) into loud failures,
never implementing TODOs or deleting markers. Replaces the noop
reference check; the extensibility suite now registers a synthetic
witness. Adds agents/todos.md and tests/todos.test.ts.