Files
AgentCompany/src/main/connector-auth-service.ts
T
ZacharyZhang-NY c71d033b0c refactor: prune dead IPC surface and orphaned modules
Drop code that nothing consumed. Verified by full renderer+shared grep:
every removed channel had zero callers via window.agentCompany.* and
zero references from desktop-api types. No backend internal use either —
the database/API-server layers keep their methods, only the IPC exposure
goes.

Removed IPC handlers (26 total):

  Thread CRUD surface (12) — writes happen inside the backend
    createThread, listThreads, addThreadEvent,
    setThreadWaitState, resolveThreadWaitState,
    addParticipant, removeParticipant, listParticipants,
    subscribeThread, unsubscribeThread,
    listSubscriptions, listSubscribedThreads
    (kept reads: getThread, listThreadEvents, listThreadWaitStates)

  Half-implemented features (13)
    saveSecret, listComments, getAgentMetrics, getApiPort,
    listWakeupRequests, listAgentMessages, autoAssignTask,
    listRunEvents, recoveryDismiss,
    getHeartbeatPolicy, setHeartbeatPolicy,
    getRuntimeState, setRuntimeState

  Whole vertical slice: openConnectorAuthTerminal
    IPC handler + channel + preload + DesktopApi type +
    connector-auth-service function + useConnectorCallbacks
    handleLoginConnector + OnboardingContext.onLoginConnector +
    OnboardingWizard wiring. Pi-mono has no CLI auth flow;
    the no-op that "returned false for legacy UI compatibility"
    had no legacy UI left.

Orphaned modules (zero importers in repo):
  src/main/runtime-env.ts
  src/main/database-stale-recovery.ts

Dead schema files (only referenced by their own barrel re-export):
  schemas-participants, schemas-subscriptions, schemas-heartbeat,
  schemas-run-events, schemas-runtime-state, schemas-wakeup

Renderer leftovers:
  .activity-row-enter CSS + its two unreferenced keyframes
  5 orphan i18n keys (app.console, app.refresh, app.expand,
  activity.timeline, auto.trigger) left over from earlier feature
  deletions

Also update two unit tests that mocked openConnectorAuthTerminal in
the RegisterCoreHandlersDependencies pick.
2026-04-17 22:38:10 -04:00

171 lines
5.5 KiB
TypeScript

import { spawn } from "node:child_process";
import { writeFileSync } from "node:fs";
import { homedir, tmpdir } from "node:os";
import { join } from "node:path";
import { randomBytes } from "node:crypto";
import { spawnSync } from "node:child_process";
import log from "electron-log/main.js";
function quoteShell(value: string) {
return `'${value.replace(/'/g, `'"'"'`)}'`;
}
function escapeAppleScript(value: string) {
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}
/* ------------------------------------------------------------------ */
/* Shared terminal spawning — used by generic install flows */
/* ------------------------------------------------------------------ */
function writeWindowsBatchFile(lines: string[]): string {
const fileName = `agent-company-${randomBytes(6).toString("hex")}.bat`;
const batchPath = join(tmpdir(), fileName);
writeFileSync(batchPath, lines.join("\r\n"), { encoding: "utf8" });
return batchPath;
}
function spawnTerminalWithScript(script: string, _title: string, _cwd: string): boolean {
if (process.platform === "darwin") {
const appleScript = `tell application "Terminal" to do script "${escapeAppleScript(script)}"\ntell application "Terminal" to activate`;
const child = spawn("osascript", ["-e", appleScript], {
detached: true,
stdio: "ignore",
});
child.unref();
return true;
}
if (process.platform === "win32") {
const child = spawn("cmd.exe", ["/c", "start", "", "cmd.exe", "/k", script], {
detached: true,
stdio: "ignore",
shell: false,
});
child.unref();
return true;
}
// Linux — try $TERMINAL first, then a broad list of common emulators.
// Supported list documented in docs/platform-support.md.
const linuxCandidates: Array<[string, string[]]> = [];
const envTerminal = process.env.TERMINAL?.trim();
if (envTerminal) {
linuxCandidates.push([envTerminal, ["-e", "sh", "-lc", script]]);
}
linuxCandidates.push(
["x-terminal-emulator", ["-e", "sh", "-lc", script]],
["gnome-terminal", ["--", "sh", "-lc", script]],
["konsole", ["-e", "sh", "-lc", script]],
["xfce4-terminal", ["-e", `sh -lc ${quoteShell(script)}`]],
["kitty", ["sh", "-lc", script]],
["alacritty", ["-e", "sh", "-lc", script]],
["wezterm", ["start", "--", "sh", "-lc", script]],
["tilix", ["-e", "sh", "-lc", script]],
["terminator", ["-e", `sh -lc ${quoteShell(script)}`]],
);
for (const [binary, args] of linuxCandidates) {
const availability = spawnSync("sh", ["-lc", `command -v ${quoteShell(binary)}`], {
stdio: "ignore",
});
if ((availability.status ?? 1) !== 0) {
continue;
}
try {
const child = spawn(binary, args, {
detached: true,
stdio: "ignore",
});
child.unref();
return true;
} catch (err) {
log.warn(`[connector-auth] Failed to spawn terminal ${binary}; trying next candidate:`, err instanceof Error ? err.message : String(err));
}
}
throw new Error("No supported terminal application was found.");
}
/* ------------------------------------------------------------------ */
/* Generic terminal command (for install flows, etc.) */
/* ------------------------------------------------------------------ */
const TERMINAL_COMMAND_MAP: Record<string, { title: string; unix: string | null; win32: string | null }> = {
install_node_darwin: {
title: "Install Node.js",
unix: "brew install node@22",
win32: null,
},
install_node_win32: {
title: "Install Node.js",
unix: null,
win32: "winget install -e --id OpenJS.NodeJS.LTS",
},
install_node_linux: {
title: "Install Node.js",
unix: `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash && \\. "$HOME/.nvm/nvm.sh" && nvm install 22`,
win32: null,
},
install_claude_unix: {
title: "Install Claude Code",
unix: "curl -fsSL https://claude.ai/install.sh | bash",
win32: null,
},
install_claude_win32: {
title: "Install Claude Code",
unix: null,
win32: "irm https://claude.ai/install.ps1 | iex",
},
install_codex: {
title: "Install Codex",
unix: "npm i -g @openai/codex",
win32: "npm i -g @openai/codex",
},
install_gemini: {
title: "Install Gemini CLI",
unix: "npm install -g @google/gemini-cli",
win32: "npm install -g @google/gemini-cli",
},
};
export async function openGenericTerminal(input: { commandKey: string }) {
const spec = TERMINAL_COMMAND_MAP[input.commandKey];
if (!spec) {
throw new Error(`Unknown terminal command key: ${input.commandKey}`);
}
const cwd = process.env.HOME || homedir() || process.cwd();
const command = process.platform === "win32" ? spec.win32 : spec.unix;
if (!command) {
throw new Error(`Command "${input.commandKey}" is not available on this platform.`);
}
if (process.platform === "win32") {
const batchPath = writeWindowsBatchFile([
`@echo off`,
`echo AgentCompany - ${spec.title}`,
`echo.`,
`cd /d "${cwd}"`,
command,
`echo.`,
`echo Done. You can close this terminal.`,
`pause`,
]);
return spawnTerminalWithScript(`"${batchPath}"`, spec.title, cwd);
}
const shell = process.env.SHELL || "/bin/zsh";
const script = [
"clear",
`echo ${quoteShell(`AgentCompany — ${spec.title}`)}`,
"echo",
`cd ${quoteShell(cwd)}`,
command,
"echo",
`echo ${quoteShell("Done. You can close this terminal.")}`,
`exec ${quoteShell(shell)} -l`,
].join("; ");
return spawnTerminalWithScript(script, spec.title, cwd);
}