fix(rebase): migrate the replayed stack onto current master APIs

The linear replay carried each commit's own lineage, so this checkpoint
restores the master-owned surfaces the conflicted regions clobbered and
migrates branch-owned code to master's post-rebase APIs:

- rebuild subprocess-local spawn.ts on master's tree-exit-observer
  machinery, keeping the branch's win32 childEnv key semantics and the
  Linux zombie-quiescence probe; the zombie test reaps its survivor
  directly since a confirmed-absent verdict is a permanent
  no-more-signals boundary
- migrate pty-local test stubs to the Inbox-model Agent interface,
  Session.create, runnerFailureRules, and the new turn/start payload
- implement the seam's resolveExecutable/spawnTerminal abstracts in the
  new pwsh-local and tool-fs-search test fakes
- restore code-runtime, atomic-write, pwsh-local, and app-boot to
  master's exact content (the net-zero code-runtime churn is pruned
  from this history) and drop rename-detection graft debris
- re-apply the PR's architecture rows and execution-world paragraph,
  re-record bilingual pairings, regenerate catalogs, and reconcile the
  lockfile
This commit is contained in:
Tianyi Cui
2026-08-07 20:34:31 +08:00
parent e385c11e8e
commit 18ab9f6db2
35 changed files with 582 additions and 673 deletions
@@ -280,18 +280,18 @@ describe('spawnSubprocess', () => {
it('does not wait for a Linux group that has only zombie members', async () => {
const pidFile = join(spillDir, `zombie-group-${Date.now()}.pid`)
let hasLiveMembers = false
const running = spawnSubprocess(spec(`sleep 60 & echo $! > ${pidFile}; echo leader-done`, { graceMs: 100 }), {
platform: 'linux',
linuxProcessGroupHasLiveMembers: () => hasLiveMembers,
linuxProcessGroupHasLiveMembers: () => false,
})
const descendant = await waitForPidFile(pidFile)
try {
await running.done
await expect(running.waitForExit()).resolves.toBe(true)
} finally {
hasLiveMembers = true
running.terminate()
// The confirmed-absent verdict is a permanent no-more-signals boundary,
// so terminate() must stay inert here; reap the live survivor directly.
process.kill(descendant, 'SIGKILL')
await waitGone(descendant)
}
})