fix(macos): scrub parent-session env, survive node upgrades and reboots, store lanes by real path (#22)
What broke (code audit, untested on a Mac): - Without systemd the server is always spawned from inside a Claude Code session, so it inherited CLAUDECODE, CLAUDE_CODE_SESSION_ID, CLAUDE_PLUGIN_ROOT, ... and tmux handed them to every lane pane (a codex pane even resolved as `claude` in `agenthub`'s harness check). - The ~/.local/bin/agenthub launcher pinned a versioned node path that `brew upgrade`/nvm deletes, leaving the CLI dead until the next bootstrap. - A discovery entry left over from before a reboot could name a recycled pid, so the bootstrap's fast path believed a dashboard was live and stopDashboard could signal an unrelated process. - Lanes were stored under the typed cwd; macOS reports /private/tmp and the on-disk case, so sessions never bound to a /tmp or differently-cased lane. What changed: - server/index.js deletes a DENYLIST of parent-session variables at startup; user config (CLAUDE_CONFIG_DIR, CLAUDE_CODE_USE_BEDROCK, ANTHROPIC_*) stays. - linkCli's launcher falls back to `node` on PATH when the pinned one is gone. - liveServers ignores entries whose startedAt predates this boot (60 s margin). - createLane and POST /api/lanes/ensure store/look up fs.realpathSync.native of an existing cwd; the liveness reaper also tries the realpath. Existing rows are untouched. - session-liveness gains an exec seam so the darwin ps+lsof branch is tested. - plugin-doctor names ~/.zshrc on darwin; INSTALL.md gains a macOS section with the Mac verification checklist, mirrored in both READMEs and PLUGINS.md. No launchd, no macOptionIsMeta, engines stays >=20.
This commit is contained in:
@@ -5,6 +5,18 @@
|
||||
|
||||
if (!process.env.NODE_ENV) process.env.NODE_ENV = "production";
|
||||
|
||||
// A server started from inside a Claude Code session (the bootstrap fallback,
|
||||
// always the case on macOS) inherits that session's own variables, and tmux
|
||||
// hands them to every lane pane — whose `claude` then believes it is nested.
|
||||
// ponytail: a DENYLIST of parent-session variables only, so user config
|
||||
// (CLAUDE_CONFIG_DIR, CLAUDE_CODE_USE_BEDROCK, ANTHROPIC_*) passes through;
|
||||
// it must grow when Claude Code adds a new per-session variable.
|
||||
const PARENT_SESSION_VARS =
|
||||
/^(CLAUDECODE|CLAUDE_PID|CLAUDE_PROJECT_DIR|CLAUDE_ENV_FILE|CLAUDE_PLUGIN_(ROOT|DATA)|CLAUDE_CODE_(ENTRYPOINT|SESSION_ID|CHILD_SESSION|SESSION_ATTENDED|EXECPATH|MESSAGING_.*))$/;
|
||||
for (const k of Object.keys(process.env)) {
|
||||
if (PARENT_SESSION_VARS.test(k)) delete process.env[k];
|
||||
}
|
||||
|
||||
// Load .env file (simple key=value, no external dependency needed)
|
||||
(function loadDotEnv() {
|
||||
const fs = require("fs");
|
||||
|
||||
Reference in New Issue
Block a user