mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-10 05:01:28 -10:00
* [LOCAL PR-Y] CLI: graceful shutdown of headless exec runs (Ctrl+C) zero exec wrapped agent.Run in context.Background(), so Ctrl+C/SIGTERM killed the process abruptly — leaking the in-flight provider request and any spawned children. runExec now wraps the run in a signal-aware context (signalContext): a signal cancels the run, the loop returns cleanly, and exec reports 'Interrupted.' with exit 130 (stream-json: an 'interrupted' run-end). Scoped to runExec — no dispatch-wide signature churn. NOTE: SIGINT runtime delivery needs a manual Ctrl+C check before PR; unit tests cover the helper + the no-regression of the exec suite. * [LOCAL PR-Y] Observability: crash capture (panic -> saved report) New internal/observability package: a recovered top-level panic is written to a local crash report (timestamp, label, full stack) under ~/.zero/crashes and surfaced as a brief notice instead of a raw stack trace. Wired into runWithDeps via a named-return defer. Fail-open and dependency-free; this is the hook a Sentry/OTEL adapter attaches to for remote reporting (deferred, needs a real endpoint to verify). Tested: report formatting/writing, panic capture sets the crash exit code + writes one report, and the no-panic path is a no-op. --------- Co-authored-by: KRATOS <[email protected]>
20 lines
739 B
Go
20 lines
739 B
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
)
|
|
|
|
// signalContext returns a context that is cancelled when the process receives an
|
|
// interrupt (Ctrl+C / SIGINT) or SIGTERM, plus a stop function that releases the
|
|
// signal handler (call it when the operation completes). The agent loop honors
|
|
// context cancellation, so wrapping a long run in this context turns a Ctrl+C
|
|
// into a clean shutdown — the in-flight provider call is cancelled and the run
|
|
// returns context.Canceled — instead of an abrupt process kill that leaks the
|
|
// HTTP request and any spawned children.
|
|
func signalContext() (context.Context, context.CancelFunc) {
|
|
return signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
}
|