Files
clawdbot/src/commands/doctor-platform-notes.ts
Peter Steinberger 33d17957e5 test: cover doctor launchctl env overrides (#1037)
* test: cover doctor launchctl env overrides

* style(macos): fix swiftformat lint
2026-01-16 19:40:45 +00:00

82 lines
3.0 KiB
TypeScript

import { execFile } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { promisify } from "node:util";
import type { ClawdbotConfig } from "../config/config.js";
import { note } from "../terminal/note.js";
const execFileAsync = promisify(execFile);
function resolveHomeDir(): string {
return process.env.HOME ?? os.homedir();
}
export async function noteMacLaunchAgentOverrides() {
if (process.platform !== "darwin") return;
const markerPath = path.join(resolveHomeDir(), ".clawdbot", "disable-launchagent");
const hasMarker = fs.existsSync(markerPath);
if (!hasMarker) return;
const lines = [
`- LaunchAgent writes are disabled via ${markerPath}.`,
"- To restore default behavior:",
` rm ${markerPath}`,
].filter((line): line is string => Boolean(line));
note(lines.join("\n"), "Gateway (macOS)");
}
async function launchctlGetenv(name: string): Promise<string | undefined> {
try {
const result = await execFileAsync("/bin/launchctl", ["getenv", name], { encoding: "utf8" });
const value = String(result.stdout ?? "").trim();
return value.length > 0 ? value : undefined;
} catch {
return undefined;
}
}
function hasConfigGatewayCreds(cfg: ClawdbotConfig): boolean {
const localToken =
typeof cfg.gateway?.auth?.token === "string" ? cfg.gateway?.auth?.token.trim() : "";
const localPassword =
typeof cfg.gateway?.auth?.password === "string" ? cfg.gateway?.auth?.password.trim() : "";
const remoteToken =
typeof cfg.gateway?.remote?.token === "string" ? cfg.gateway?.remote?.token.trim() : "";
const remotePassword =
typeof cfg.gateway?.remote?.password === "string" ? cfg.gateway?.remote?.password.trim() : "";
return Boolean(localToken || localPassword || remoteToken || remotePassword);
}
export async function noteMacLaunchctlGatewayEnvOverrides(
cfg: ClawdbotConfig,
deps?: {
platform?: NodeJS.Platform;
getenv?: (name: string) => Promise<string | undefined>;
noteFn?: typeof note;
},
) {
const platform = deps?.platform ?? process.platform;
if (platform !== "darwin") return;
if (!hasConfigGatewayCreds(cfg)) return;
const getenv = deps?.getenv ?? launchctlGetenv;
const envToken = await getenv("CLAWDBOT_GATEWAY_TOKEN");
const envPassword = await getenv("CLAWDBOT_GATEWAY_PASSWORD");
if (!envToken && !envPassword) return;
const lines = [
"- launchctl environment overrides detected (can cause confusing unauthorized errors).",
envToken ? "- `CLAWDBOT_GATEWAY_TOKEN` is set; it overrides config tokens." : undefined,
envPassword
? "- `CLAWDBOT_GATEWAY_PASSWORD` is set; it overrides config passwords."
: undefined,
"- Clear overrides and restart the app/gateway:",
envToken ? " launchctl unsetenv CLAWDBOT_GATEWAY_TOKEN" : undefined,
envPassword ? " launchctl unsetenv CLAWDBOT_GATEWAY_PASSWORD" : undefined,
].filter((line): line is string => Boolean(line));
(deps?.noteFn ?? note)(lines.join("\n"), "Gateway (macOS)");
}