Conversation
…ervisor Move the process layer from apps/cli into packages/shared/src/node/process.ts (@lody/shared/node/process), a single module with no relative imports so Electron's node --test can load it, together with its Promise facades and the fake process table. The CLI keeps its session containers and a facade that only adds its logger. Migrate the remaining direct process users: Electron main (CLI spawn and quit, protocol client, shell env, updater, app icon, hang diagnostics, path launcher), the CLI supervisor's SIGTERM/SIGKILL loop, and the shared cli-detection, local-project and file-lock helpers. Delete their unused CommonJS twins, add a three-state pid probe so file-lock keeps treating a foreign-owned pid as a dead owner, and add signalChildTreeNow for exit handlers. Extend the boundary guard to apps/electron/src/main, packages/cli-supervisor and packages/shared/src/node (including .cjs) and to direct child kill calls; move the process rules next to the code in packages/shared/src/node/AGENTS.md. Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- childTree never signals a child without a pid: until Node reports a failed spawn, child.kill() reaches pid 0, the caller's own process group. - Abandoned commands get a 2 s SIGTERM grace, so a timed-out git removes its index.lock instead of locking the repository. - Waits inside finalizers are bounded by the clock (waitUntilGone) and the taskkill deadline completes its Deferred from a timer fiber, so a tree that survives SIGKILL can no longer hang runCommand forever. - EPERM from a group signal waits instead of failing (macOS zombie leader). - Windows commands resolve through absolute PATH entries only, never the working directory; an unresolvable one reports ENOENT via Node's spawn. - Session.terminate escalates an in-flight graceful termination, does not wait on terminals when forced, and re-terminates processes started after a finished termination. - Archive releases a Session even when a process tree survives. - PTY: hangup, 2 s grace, SIGKILL. Shell-env probe: 15 s, failures not cached. rundll32 visible. cgroup: no spawn after cleanup, nested cgroups count as alive. Supervisor: no shared never-settling promise. Process warnings reach a real logger by default. Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the CommandSpec.onSpawned hook main's Codex profile logout needs into the shared process layer (with a test), and point main's new Codex profile login test at the nodeProcess test seam. Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ayer # Conflicts: # apps/cli/AGENTS.md
Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
Refs #429
Stack
mainMerge in order, and retarget the next PR to
mainafter each merge.Problem / pressure
After #1069 the CLI had a single process implementation. Four places outside
apps/clistill spawned and killed processes directly with their own escalation loops:packages/cli-supervisor's SIGTERM/SIGKILL loop;packages/shared's git, CLI-detection and lock helpers, which the CLI itself calls;.cjstwins of those helpers.These packages cannot import
apps/cli, so the repository still had several implementations.Summary
packages/shared/src/node/process.ts(@lody/shared/node/process):node --test --experimental-strip-typescannot resolve extensionless relative imports.process-testing.ts(the fake process table).apps/cli/src/platformkeeps only the session containers, the logger bridge and a facade that adds the CLI logger.processGroup.cli-detection,local-projectandfile-lock..cjstwins are deleted. A repository search found only their own parity tests loading them. Their unique test cases were moved onto the TypeScript modules.probePid/probePidSyncreturn three states. With them,file-lockkeeps treating an EPERM (foreign-owned) pid as a dead owner, as before.signalChildTreeNowis a synchronous signal forprocess.on('exit')handlers.apps/cli/src,apps/electron/src/main,packages/cli-supervisor/srcandpackages/shared/src/node(including.cjs). It now also flags<child>.kill(.packages/shared/src/node/AGENTS.md(with aCLAUDE.mdsymlink).apps/cli/AGENTS.mdandapps/electron/src/AGENTS.mdpoint to it.Visual explanation
flowchart TD CLI["apps/cli (containers, facade + logger)"] --> P["@lody/shared/node/process"] E["apps/electron/src/main"] --> P S["packages/cli-supervisor"] --> P H["shared node helpers: local-project, cli-detection, file-lock"] --> P P --> OS["NodeProcess: the only child_process / kill access"] G["check:cli-process-boundary"] -.guards.-> CLI & E & S & HBefore / after
apps/clipackages/shared, used by CLI, Electron main, supervisor and shared helperschild.kill.cjstwins duplicating process logicapps/cliimportschild.killTest plan
corepack pnpm checkpasses end to end:node --test: 195 passed;signalChildTreeNowdelivering its signal synchronously.file-lock: it takes over a lock whose pid is foreign (pid 1) and keeps one held by our own live process.cli-detectionwith a fake binary on PATH.@lody/shared/node/processandprocess-testingunder plainnode --experimental-strip-typesworks.@lody/sharedandeffect, but no packaged app was built here.Context handoff
The Lody team asked to finish removing the duplicate process implementations ("继续"), after #1069 had covered
apps/cli.Review fixes (9589a39)
A deep correctness review of the whole stack found regressions against the code it replaced. They are fixed here, each with a test that fails without its fix:
index.lockbehind;runCommandin its finalizer;TerminationFailed;git.cmdfrom cwd and lost ENOENT (unit-tested only, not run on Windows);Session.terminatewaited behind graceful work;Smaller changes, most without new tests:
rundll32runs with a visible window state;Details are in the process-tree-layer note.
pnpm checkpasses when the session's injectedGIT_CONFIG_*variables are removed; with them, one git-remote test fails for environmental reasons.🤖 Generated with Claude Code