claude-code writes its managed files from a staged file, not /dev/stdin

Node hands a child its input over a socket, which /dev/stdin cannot open
(ENXIO): on the first assignment nothing under /etc/claude-code was written.
This commit is contained in:
jochen
2026-10-04 11:31:44 +02:00
parent 0a78d130e5
commit 5003dc0377
+10 -3
View File
@@ -8,7 +8,8 @@
// module's `servers` state — every node's MCP server registrations (novox/hq ADR 0201). node.ts holds the // module's `servers` state — every node's MCP server registrations (novox/hq ADR 0201). node.ts holds the
// logic. // logic.
import { readFileSync, watchFile } from "node:fs"; import { mkdtempSync, readFileSync, rmSync, watchFile, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { spawnSync } from "node:child_process"; import { spawnSync } from "node:child_process";
import { join } from "node:path"; import { join } from "node:path";
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools"; import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
@@ -41,9 +42,15 @@ const writeManaged: WriteManaged = (name, content) => {
} catch { } catch {
/* absent */ /* absent */
} }
// From a file, never /dev/stdin: Node hands a child its input over a socket, which /dev/stdin cannot
// open (ENXIO) — found on the first assignment, where nothing under /etc/claude-code was ever written.
const staged = mkdtempSync(join(tmpdir(), "claude-code-"));
const source = join(staged, name);
writeFileSync(source, content, { mode: 0o644 });
const asRoot = process.getuid?.() === 0; const asRoot = process.getuid?.() === 0;
const cmd = asRoot ? ["install", "-D", "-m", "0644", "/dev/stdin", path] : ["sudo", "-n", "install", "-D", "-m", "0644", "/dev/stdin", path]; const cmd = asRoot ? ["install", "-D", "-m", "0644", source, path] : ["sudo", "-n", "install", "-D", "-m", "0644", source, path];
const r = spawnSync(cmd[0], cmd.slice(1), { input: content, encoding: "utf8" }); const r = spawnSync(cmd[0], cmd.slice(1), { encoding: "utf8" });
rmSync(staged, { recursive: true, force: true });
if (r.status !== 0) { if (r.status !== 0) {
throw new Error(`${name}: could not be written to ${MANAGED_DIR} (${(r.stderr || r.error?.message || "").trim()}); ` + throw new Error(`${name}: could not be written to ${MANAGED_DIR} (${(r.stderr || r.error?.message || "").trim()}); ` +
`the module writes there through the operator account's passwordless sudo`); `the module writes there through the operator account's passwordless sudo`);