Replace session picker modal with instance welcome view
Transform the session picker from a modal into a comprehensive welcome screen that displays instance metadata, session history, and creation options. The new view provides full keyboard navigation, shows MCP server status, OpenCode binary path, and project information in a compact, space-efficient layout. Key features: - Instance metadata sidebar showing folder, project, VCS, version, binary path, MCP status, and server info - Session list with keyboard navigation (↑↓, PgUp/PgDn, Home/End, Enter) - Cmd+Enter shortcut to create new session from anywhere - Compact design with efficient space usage - Visual MCP server status indicators (running/stopped/error) - Scrollable layout that keeps "New Session" section accessible
This commit is contained in:
@@ -35,13 +35,13 @@ export function setupInstanceIPC(mainWindow: BrowserWindow) {
|
||||
instances.set(id, instance)
|
||||
|
||||
try {
|
||||
const { pid, port } = await processManager.spawn(folder, id)
|
||||
const { pid, port, binaryPath } = await processManager.spawn(folder, id)
|
||||
|
||||
instance.port = port
|
||||
instance.pid = pid
|
||||
instance.status = "ready"
|
||||
|
||||
mainWindow.webContents.send("instance:started", { id, port, pid })
|
||||
mainWindow.webContents.send("instance:started", { id, port, pid, binaryPath })
|
||||
|
||||
const meta = processManager.getAllProcesses().get(pid)
|
||||
if (meta) {
|
||||
@@ -51,7 +51,7 @@ export function setupInstanceIPC(mainWindow: BrowserWindow) {
|
||||
})
|
||||
}
|
||||
|
||||
return { id, port, pid }
|
||||
return { id, port, pid, binaryPath }
|
||||
} catch (error) {
|
||||
instance.status = "error"
|
||||
instance.error = error instanceof Error ? error.message : String(error)
|
||||
|
||||
@@ -6,6 +6,7 @@ import { execSync } from "child_process"
|
||||
export interface ProcessInfo {
|
||||
pid: number
|
||||
port: number
|
||||
binaryPath: string
|
||||
}
|
||||
|
||||
interface ProcessMeta {
|
||||
@@ -51,7 +52,7 @@ class ProcessManager {
|
||||
|
||||
async spawn(folder: string, instanceId: string): Promise<ProcessInfo> {
|
||||
this.validateFolder(folder)
|
||||
this.validateOpenCodeBinary()
|
||||
const binaryPath = this.validateOpenCodeBinary()
|
||||
|
||||
this.sendLog(instanceId, "info", `Starting OpenCode server for ${folder}...`)
|
||||
|
||||
@@ -102,7 +103,7 @@ class ProcessManager {
|
||||
}
|
||||
|
||||
this.processes.set(child.pid!, meta)
|
||||
resolve({ pid: child.pid!, port })
|
||||
resolve({ pid: child.pid!, port, binaryPath })
|
||||
}
|
||||
|
||||
const meta = this.processes.get(child.pid!)
|
||||
@@ -208,10 +209,12 @@ class ProcessManager {
|
||||
}
|
||||
}
|
||||
|
||||
private validateOpenCodeBinary(): void {
|
||||
private validateOpenCodeBinary(): string {
|
||||
const command = process.platform === "win32" ? "where opencode" : "which opencode"
|
||||
try {
|
||||
execSync(command, { stdio: "pipe" })
|
||||
const output = execSync(command, { stdio: "pipe", encoding: "utf-8" })
|
||||
const paths = output.trim().split("\n")
|
||||
return paths[0].trim()
|
||||
} catch {
|
||||
throw new Error(
|
||||
"opencode binary not found in PATH. Please install OpenCode CLI first: npm install -g @opencode/cli",
|
||||
|
||||
@@ -2,9 +2,9 @@ import { contextBridge, ipcRenderer } from "electron"
|
||||
|
||||
export interface ElectronAPI {
|
||||
selectFolder: () => Promise<string | null>
|
||||
createInstance: (id: string, folder: string) => Promise<{ id: string; port: number; pid: number }>
|
||||
createInstance: (id: string, folder: string) => Promise<{ id: string; port: number; pid: number; binaryPath: string }>
|
||||
stopInstance: (pid: number) => Promise<void>
|
||||
onInstanceStarted: (callback: (data: { id: string; port: number; pid: number }) => void) => void
|
||||
onInstanceStarted: (callback: (data: { id: string; port: number; pid: number; binaryPath: string }) => void) => void
|
||||
onInstanceError: (callback: (data: { id: string; error: string }) => void) => void
|
||||
onInstanceStopped: (callback: (data: { id: string }) => void) => void
|
||||
onInstanceLog: (
|
||||
|
||||
Reference in New Issue
Block a user