feat(host): capture HostEnvironment once at entry points

TH
2h ago
+1945-781

Summary

Part of #3747. Closes #3749.

HostEnvironment = { env, cwd } now has one owner. Entry points capture it once, and the daemon runtime, request scope and command spawning receive it instead of reading process. 178 files changed, about 2,150 gross lines, most of them test call sites.

  • Type and capture: HostEnvironment is in @agent-device/kernel/source-value. captureHostEnvironment(process) is in @agent-device/host-kit/process. It copies the environment.
  • Entry points: src/bin.ts, src/cli.ts (runCli(argv, deps, host)), src/daemon.ts and createAgentDeviceClient(config, { host }) capture once. The client keeps its process default.
  • Daemon: startDaemonRuntime requires host. DaemonRuntimeDepsInput.host replaces env. RequestRouterDeps.host and RequestExecutionScope.host carry it.
  • Command spawning: withCommandHost({ host, requestEnv }, fn) replaces withRequestCommandEnv. Spawned commands start from host.env. commandHostEnvironment() gives platform code that host and throws outside one.
  • Explicit inputs: whichCmd, resolveUserPath, expandSessionPath, the device-claim functions, loadDaemonPolicy, launchDaemonProcess and kernel allowlist and simulator-set resolvers take env or cwd as parameters.
  • Done when: host-kit, kernel and daemon-contracts non-test sources have no process.env or process.cwd().

Behavior changes: a relative state dir without a cwd is refused (relative_state_dir_without_cwd); callers now pass one. Unit tests enter the live process environment as their host (src/__tests__/host-environment-setup.ts).

Non-owned packages keep their direct reads as inline process.env / process.cwd() for #3750 and #3751 to migrate.

Validation

pnpm check:affected --run --head 2ebb8869c7 (exactCommit) passed. GitHub-authoritative lanes (coverage, integration, native) are not run locally. No device-facing behavior changed.

🤖 Generated with Claude Code