478418f602
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.
52 lines
1.9 KiB
JavaScript
52 lines
1.9 KiB
JavaScript
/**
|
|
* @file Tests that the server drops the variables describing the Claude Code
|
|
* session that started it (always the case on macOS, where there is no
|
|
* systemd unit to give it a clean env) — tmux and every lane pane inherit the
|
|
* server's env, so a leaked CLAUDECODE made each pane look like a nested
|
|
* session. User configuration (CLAUDE_CONFIG_DIR, ANTHROPIC_*, …) must survive.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const { it, after } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
|
|
const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-envscrub-"));
|
|
process.env.DASHBOARD_DB_PATH = path.join(TMP, "dashboard.db");
|
|
process.env.CLAUDE_HOME = path.join(TMP, "home");
|
|
process.env.DASHBOARD_DATA_DIR = path.join(TMP, "data");
|
|
|
|
process.env.CLAUDECODE = "1";
|
|
process.env.CLAUDE_CODE_ENTRYPOINT = "cli";
|
|
process.env.CLAUDE_CODE_SESSION_ID = "abc";
|
|
process.env.CLAUDE_CODE_MESSAGING_SOCKET = "/tmp/x.sock";
|
|
process.env.CLAUDE_PLUGIN_ROOT = "/some/cache/dir";
|
|
process.env.CLAUDE_CONFIG_DIR = "/Users/x/.claude-work";
|
|
process.env.CLAUDE_CODE_USE_BEDROCK = "1";
|
|
process.env.ANTHROPIC_BASE_URL = "https://example.invalid";
|
|
|
|
require("../index");
|
|
const { db } = require("../db");
|
|
|
|
after(() => {
|
|
db.close();
|
|
fs.rmSync(TMP, { recursive: true, force: true });
|
|
});
|
|
|
|
it("strips the parent session's variables and keeps user configuration", () => {
|
|
for (const k of [
|
|
"CLAUDECODE",
|
|
"CLAUDE_CODE_ENTRYPOINT",
|
|
"CLAUDE_CODE_SESSION_ID",
|
|
"CLAUDE_CODE_MESSAGING_SOCKET",
|
|
"CLAUDE_PLUGIN_ROOT",
|
|
]) {
|
|
assert.equal(process.env[k], undefined, k);
|
|
}
|
|
assert.equal(process.env.CLAUDE_CONFIG_DIR, "/Users/x/.claude-work");
|
|
assert.equal(process.env.CLAUDE_CODE_USE_BEDROCK, "1");
|
|
assert.equal(process.env.ANTHROPIC_BASE_URL, "https://example.invalid");
|
|
});
|