Remove runtime mode selection & have unified setup flow for node.js + API access
This commit is contained in:
@@ -209,43 +209,6 @@ async function executeAppLocalNode({
|
||||
});
|
||||
}
|
||||
|
||||
function checkCommandExists(command: string): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
let output = "";
|
||||
const process = spawn(command, ["--version"], {
|
||||
shell: true,
|
||||
stdio: ["ignore", "pipe", "pipe"], // ignore stdin, pipe stdout/stderr
|
||||
});
|
||||
|
||||
process.stdout?.on("data", (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
process.stderr?.on("data", (data) => {
|
||||
// Log stderr but don't treat it as a failure unless the exit code is non-zero
|
||||
console.warn(
|
||||
`Stderr from "${command} --version": ${data.toString().trim()}`
|
||||
);
|
||||
});
|
||||
|
||||
process.on("error", (error) => {
|
||||
console.error(`Error executing command "${command}":`, error.message);
|
||||
resolve(null); // Command execution failed
|
||||
});
|
||||
|
||||
process.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve(output.trim()); // Command succeeded, return trimmed output
|
||||
} else {
|
||||
console.error(
|
||||
`Command "${command} --version" failed with code ${code}`
|
||||
);
|
||||
resolve(null); // Command failed
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Helper to kill process on a specific port (cross-platform, using kill-port)
|
||||
async function killProcessOnPort(port: number): Promise<void> {
|
||||
try {
|
||||
@@ -256,21 +219,6 @@ async function killProcessOnPort(port: number): Promise<void> {
|
||||
}
|
||||
|
||||
export function registerAppHandlers() {
|
||||
ipcMain.handle(
|
||||
"nodejs-status",
|
||||
async (): Promise<{
|
||||
nodeVersion: string | null;
|
||||
npmVersion: string | null;
|
||||
}> => {
|
||||
// Run checks in parallel
|
||||
const [nodeVersion, npmVersion] = await Promise.all([
|
||||
checkCommandExists("node"),
|
||||
checkCommandExists("npm"),
|
||||
]);
|
||||
return { nodeVersion, npmVersion };
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
"get-app-sandbox-config",
|
||||
async (_, { appId }: { appId: number }): Promise<SandboxConfig> => {
|
||||
|
||||
136
src/ipc/handlers/node_handlers.ts
Normal file
136
src/ipc/handlers/node_handlers.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { spawn } from "child_process";
|
||||
import { platform } from "os";
|
||||
import { InstallNodeResult } from "../ipc_types";
|
||||
type ShellResult =
|
||||
| {
|
||||
success: true;
|
||||
output: string;
|
||||
}
|
||||
| {
|
||||
success: false;
|
||||
errorMessage: string;
|
||||
};
|
||||
|
||||
function runShell(command: string): Promise<ShellResult> {
|
||||
return new Promise((resolve) => {
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
const process = spawn(command, {
|
||||
shell: true,
|
||||
stdio: ["ignore", "pipe", "pipe"], // ignore stdin, pipe stdout/stderr
|
||||
});
|
||||
|
||||
process.stdout?.on("data", (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
|
||||
process.stderr?.on("data", (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
|
||||
process.on("error", (error) => {
|
||||
console.error(`Error executing command "${command}":`, error.message);
|
||||
resolve({ success: false, errorMessage: error.message });
|
||||
});
|
||||
|
||||
process.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve({ success: true, output: stdout.trim() });
|
||||
} else {
|
||||
const errorMessage =
|
||||
stderr.trim() || `Command failed with code ${code}`;
|
||||
console.error(
|
||||
`Command "${command}" failed with code ${code}: ${stderr.trim()}`
|
||||
);
|
||||
resolve({ success: false, errorMessage });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkCommandExists(command: string): Promise<string | null> {
|
||||
return new Promise((resolve) => {
|
||||
let output = "";
|
||||
const process = spawn(command, ["--version"], {
|
||||
shell: true,
|
||||
stdio: ["ignore", "pipe", "pipe"], // ignore stdin, pipe stdout/stderr
|
||||
});
|
||||
|
||||
process.stdout?.on("data", (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
|
||||
process.stderr?.on("data", (data) => {
|
||||
// Log stderr but don't treat it as a failure unless the exit code is non-zero
|
||||
console.warn(
|
||||
`Stderr from "${command} --version": ${data.toString().trim()}`
|
||||
);
|
||||
});
|
||||
|
||||
process.on("error", (error) => {
|
||||
console.error(`Error executing command "${command}":`, error.message);
|
||||
resolve(null); // Command execution failed
|
||||
});
|
||||
|
||||
process.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
resolve(output.trim()); // Command succeeded, return trimmed output
|
||||
} else {
|
||||
console.error(
|
||||
`Command "${command} --version" failed with code ${code}`
|
||||
);
|
||||
resolve(null); // Command failed
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function registerNodeHandlers() {
|
||||
ipcMain.handle(
|
||||
"nodejs-status",
|
||||
async (): Promise<{
|
||||
nodeVersion: string | null;
|
||||
npmVersion: string | null;
|
||||
}> => {
|
||||
// Run checks in parallel
|
||||
const [nodeVersion, npmVersion] = await Promise.all([
|
||||
checkCommandExists("node"),
|
||||
checkCommandExists("npm"),
|
||||
]);
|
||||
return { nodeVersion, npmVersion };
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle("install-node", async (): Promise<InstallNodeResult> => {
|
||||
console.log("Installing Node.js...");
|
||||
if (platform() === "win32") {
|
||||
let result = await runShell("winget install Volta.Volta");
|
||||
if (!result.success) {
|
||||
return { success: false, errorMessage: result.errorMessage };
|
||||
}
|
||||
} else {
|
||||
let result = await runShell("curl https://get.volta.sh | bash");
|
||||
if (!result.success) {
|
||||
return { success: false, errorMessage: result.errorMessage };
|
||||
}
|
||||
}
|
||||
console.log("Installed Volta");
|
||||
|
||||
process.env.PATH = ["~/.volta/bin", process.env.PATH].join(":");
|
||||
console.log("Updated PATH");
|
||||
let result = await runShell("volta install node");
|
||||
if (!result.success) {
|
||||
return { success: false, errorMessage: result.errorMessage };
|
||||
}
|
||||
console.log("Installed Node.js (via Volta)");
|
||||
|
||||
result = await runShell("node --version");
|
||||
if (!result.success) {
|
||||
return { success: false, errorMessage: result.errorMessage };
|
||||
}
|
||||
console.log("Node.js is setup with version");
|
||||
|
||||
return { success: true, version: result.output };
|
||||
});
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
ChatStreamParams,
|
||||
CreateAppParams,
|
||||
CreateAppResult,
|
||||
InstallNodeResult,
|
||||
ListAppsResponse,
|
||||
SandboxConfig,
|
||||
Version,
|
||||
@@ -520,6 +521,17 @@ export class IpcClient {
|
||||
}
|
||||
}
|
||||
|
||||
// Install Node.js and npm
|
||||
public async installNode(): Promise<InstallNodeResult> {
|
||||
try {
|
||||
const result = await this.ipcRenderer.invoke("install-node");
|
||||
return result;
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// --- GitHub Device Flow ---
|
||||
public startGithubDeviceFlow(appId: number | null): void {
|
||||
this.ipcRenderer.invoke("github:start-flow", { appId });
|
||||
|
||||
@@ -5,6 +5,7 @@ import { registerSettingsHandlers } from "./handlers/settings_handlers";
|
||||
import { registerShellHandlers } from "./handlers/shell_handler";
|
||||
import { registerDependencyHandlers } from "./handlers/dependency_handlers";
|
||||
import { registerGithubHandlers } from "./handlers/github_handlers";
|
||||
import { registerNodeHandlers } from "./handlers/node_handlers";
|
||||
|
||||
export function registerIpcHandlers() {
|
||||
// Register all IPC handlers by category
|
||||
@@ -15,4 +16,5 @@ export function registerIpcHandlers() {
|
||||
registerShellHandlers();
|
||||
registerDependencyHandlers();
|
||||
registerGithubHandlers();
|
||||
registerNodeHandlers();
|
||||
}
|
||||
|
||||
@@ -65,3 +65,13 @@ export interface SandboxConfig {
|
||||
dependencies: Record<string, string>;
|
||||
entry: string;
|
||||
}
|
||||
|
||||
export type InstallNodeResult =
|
||||
| {
|
||||
success: true;
|
||||
version: string;
|
||||
}
|
||||
| {
|
||||
success: false;
|
||||
errorMessage: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user