Merge branch 'main' into dev
Surgical merge of 74 commits from main into dev. Key features ported: - Provider visibility gating (appVersion filtering for Pi/Copilot) - Pi agent provider + Copilot re-enabled - Provider-declared features system (Codex fast mode) - Workspace dedup by worktree root (adapted to integer IDs) - Bulk close archiving fix for stored agents - Agent creation timeout increase to 60s - Audio/voice crash fixes (external buffer copies) - Multi-host setup fix - Reload agent tab action Dev architecture preserved: SQLite storage, service proxy, workspace setup dialog, hover cards, removed launcher tabs.
This commit is contained in:
@@ -21,6 +21,7 @@ export interface LocalDaemonPidInfo {
|
||||
hostname?: string;
|
||||
uid?: number;
|
||||
listen?: string;
|
||||
desktopManaged?: boolean;
|
||||
}
|
||||
|
||||
export interface LocalDaemonState {
|
||||
@@ -173,6 +174,7 @@ function readPidFile(pidPath: string): LocalDaemonPidInfo | null {
|
||||
: typeof parsed.sockPath === "string"
|
||||
? parsed.sockPath
|
||||
: undefined,
|
||||
desktopManaged: parsed.desktopManaged === true ? true : undefined,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
@@ -34,6 +34,8 @@ interface DaemonStatus {
|
||||
daemonNode: string;
|
||||
cliNode: string;
|
||||
cliVersion: string;
|
||||
daemonVersion: string | null;
|
||||
desktopManaged: boolean;
|
||||
providers: ProviderBinaryStatus[];
|
||||
note?: string;
|
||||
}
|
||||
@@ -129,6 +131,7 @@ function toStatusRows(status: DaemonStatus): StatusRow[] {
|
||||
{ key: "Daemon Node", value: status.daemonNode },
|
||||
{ key: "CLI Node", value: status.cliNode },
|
||||
{ key: "CLI", value: status.cliVersion },
|
||||
{ key: "Daemon Version", value: status.daemonVersion ?? "-" },
|
||||
];
|
||||
|
||||
if (status.runningAgents !== null && status.idleAgents !== null) {
|
||||
@@ -229,6 +232,7 @@ export async function runStatusCommand(
|
||||
let connectedDaemon: DaemonStatus["connectedDaemon"] = "not_probed";
|
||||
let runningAgents: number | null = null;
|
||||
let idleAgents: number | null = null;
|
||||
let daemonVersion: string | null = null;
|
||||
let note: string | undefined;
|
||||
|
||||
if (!state.running && state.stalePidFile && state.pidInfo) {
|
||||
@@ -240,6 +244,7 @@ export async function runStatusCommand(
|
||||
const client = await tryConnectToDaemon({ host, timeout: 1500 });
|
||||
if (client) {
|
||||
connectedDaemon = "reachable";
|
||||
daemonVersion = client.getLastServerInfoMessage()?.version ?? null;
|
||||
try {
|
||||
const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } });
|
||||
const agents = agentsPayload.entries.map((entry) => entry.agent);
|
||||
@@ -308,6 +313,8 @@ export async function runStatusCommand(
|
||||
daemonNode,
|
||||
cliNode,
|
||||
cliVersion,
|
||||
daemonVersion,
|
||||
desktopManaged: state.pidInfo?.desktopManaged === true,
|
||||
providers,
|
||||
note,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { spawn } from "node:child_process";
|
||||
import { homedir } from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
function findDesktopApp(): string | null {
|
||||
if (process.platform === "darwin") {
|
||||
const candidates = [
|
||||
"/Applications/Paseo.app",
|
||||
path.join(homedir(), "Applications", "Paseo.app"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (process.platform === "linux") {
|
||||
const candidates = [
|
||||
"/usr/bin/Paseo",
|
||||
"/opt/Paseo/Paseo",
|
||||
path.join(homedir(), "Applications", "Paseo.AppImage"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const localAppData = process.env.LOCALAPPDATA;
|
||||
if (!localAppData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const candidate = path.join(localAppData, "Programs", "Paseo", "Paseo.exe");
|
||||
return existsSync(candidate) ? candidate : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function cleanEnvForDesktopLaunch(): NodeJS.ProcessEnv {
|
||||
const env = { ...process.env };
|
||||
// The CLI runs via ELECTRON_RUN_AS_NODE=1. On Linux/Windows the spawned
|
||||
// desktop process inherits the env directly, so we must strip it or the
|
||||
// desktop app would start as a bare Node process instead of Electron.
|
||||
delete env.ELECTRON_RUN_AS_NODE;
|
||||
return env;
|
||||
}
|
||||
|
||||
function spawnDetached(command: string, args: string[]): void {
|
||||
spawn(command, args, {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
env: cleanEnvForDesktopLaunch(),
|
||||
}).unref();
|
||||
}
|
||||
|
||||
export async function openDesktopWithProject(projectPath: string): Promise<void> {
|
||||
try {
|
||||
if (process.env.PASEO_DESKTOP_CLI === "1") {
|
||||
throw new Error(
|
||||
"Cannot open a desktop project while running in desktop CLI passthrough mode.",
|
||||
);
|
||||
}
|
||||
|
||||
const desktopApp = findDesktopApp();
|
||||
if (!desktopApp) {
|
||||
throw new Error(
|
||||
"Paseo desktop app not found. Install it from https://github.com/getpaseo/paseo/releases",
|
||||
);
|
||||
}
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
// -n forces a new instance even if the app is already running.
|
||||
// The new instance hits requestSingleInstanceLock(), fails, and relays
|
||||
// the argv to the first instance via the second-instance event.
|
||||
// -g keeps the terminal in the foreground (better CLI UX).
|
||||
// Without -n, macOS just activates the existing window and drops --args.
|
||||
spawnDetached("open", ["-n", "-g", "-a", desktopApp, "--args", projectPath]);
|
||||
return;
|
||||
}
|
||||
|
||||
spawnDetached(desktopApp, [projectPath]);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
process.stderr.write(`${message}\n`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user