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.
171 lines
5.5 KiB
TypeScript
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);
|
|
}
|