- name
- process-lifecycle
- description
- Use when changing subprocess execution, cancellation, process-tree cleanup, orphan reaping, or Windows child hardening.
- user-invocable
- false
- metadata
- {"internal":true}
**Context, Concurrency, and Processes**
- Thread `context.Context` through long-running, subprocess, and networked work; prefer `exec.CommandContext`; use derived contexts and timeouts for cleanup and HTTP calls.
- Route every long-lived subprocess spawned for a cancellable step or agent invocation through the appropriate `shellenv` lifecycle configurator. Agents and other subprocesses use `ConfigureShellCommand`: it creates a process-tree boundary and installs `cmd.Cancel` to kill the whole tree, so grandchildren (test workers, build watchers) cannot outlive cancellation and hold the next run's worktree locked. Repository `commands.*` and custom gates use `ConfigureCooperativeShellCommand`: on Windows it sends targeted `CTRL_BREAK`, preserves up to a three-second cleanup window, then retains the same forced Job Object fallback. Regressions: `TestConfigureCooperativeShellCommandCancelAllowsCleanup`, `TestConfigureCooperativeShellCommandCancelForcesNonCooperatingTree`.
- `cmd.Cancel` covers only cancellation; on clean exit or error the group is not reaped, and leaked grandchildren accumulate until the OS OOM-kills the daemon (surfacing as `daemon crashed during execution` with no stack trace). Use `shellenv.RunShellCommand` / `OutputShellCommand` / `CombinedOutputShellCommand` for one-shot commands, or `StartShellCommand` plus `TerminateShellCommandGroup` when handling pipes manually; the helper doc comments in `internal/shellenv` own the details. `ConfigureShellCommand` also installs a 5s `cmd.WaitDelay` backstop so a grandchild holding an inherited pipe cannot wedge `cmd.Wait` forever. Regressions: `TestCodexAgent_Run_ReapsLeakedGrandchildOnCleanExit`, `TestRunShellCommandWithEnv_ReapsGrandchildOnCleanExit`, `TestTerminateShellCommandGroup_*`.
- A process group is a lineage container, not a sandbox: a descendant that calls `setsid(2)`/`setpgid(2)` (agent CLIs sandboxing their tool runners, any daemonizing worker script) leaves the group, and after its parent exits nothing lineage-based can name it again - it burns CPU and holds a deleted worktree's cwd forever. `internal/procreap` is the identity-based backstop: it matches a process by the run worktree its **cwd** resolves under (deliberately never argv, which a legitimate `git worktree remove` also carries), never touches pid<=1/itself/its ancestors, spares worktrees whose run is still pending or running, and escalates SIGTERM to SIGKILL only after a grace period. Reach is `<NM_HOME>/worktrees` by path shape plus exactly the run worktrees a caller names from run records (`Options.Worktrees`), never a configured worktree root by shape - an operator's own directory is unmatchable unless a run row names it. Every site that removes a run worktree sweeps it first through `procreap.SweepRunWorktree(s)` (run cleanup and setup failure via `RunManager.removeRunWorktree`, startup cleanup, eject), scoped and therefore without age floor or run-active check; the unscoped startup sweep in `recoverOnStartup` keeps the `orphanProcessMinAge` floor. All best effort. Windows needs none of this - job objects contain the whole tree - so the platform layer reports an empty table. Regressions: `internal/procreap`, `TestSweepOrphanRunProcessesReapsFinishedRunAndSparesActiveOne`, `TestSweepRunWorktreeProcessesReapsLeakedChildAtRunCleanup`, `TestTerminateShellCommandGroup_AsksBeforeKilling`, `TestTerminateShellCommandGroup_EscalatesWhenSIGTERMIsIgnored`.
- On Windows the daemon runs console-less, so route every console child through `winproc.Harden(cmd)` (no-op elsewhere, idempotent, preserves existing creation flags) or a console window flashes per child (#287). `shellenv.ConfigureShellCommand` already calls it; one-shot commands built directly must call it themselves. Regressions: `TestHarden*` in `internal/winproc`.
- Protect shared mutable state with the standard sync/atomic tools, and be explicit about ownership and cleanup of goroutines, worktrees, temp dirs, and channels.
عرض على GitHub