Add screen orientation polyfill, refactor provider launch config, and update desktop runtime manager
- Add .claude schedule tasks to .gitignore - Add screen-orientation polyfill for Expo web - Refactor agent provider launch config into shared utility - Update desktop runtime manager with improved binary management - Update desktop release workflow
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { execFileSync, execSync } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { platform } from "node:os";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { AgentProvider } from "./agent-sdk-types.js";
|
||||
@@ -88,24 +89,63 @@ export function applyProviderEnv(
|
||||
};
|
||||
}
|
||||
|
||||
export function isCommandAvailable(command: string): boolean {
|
||||
const normalized = command.trim();
|
||||
if (!normalized) {
|
||||
return false;
|
||||
/**
|
||||
* Resolve an executable name to its absolute path the way the user's shell would.
|
||||
*
|
||||
* On Unix we first try `$SHELL -lic "which <name>"` so that rc-file PATH
|
||||
* additions (asdf, nvm, homebrew, nix, etc.) are visible — exactly as if the
|
||||
* user opened a terminal and typed the command. If that fails (e.g. the login
|
||||
* shell itself errors) we fall back to a plain `which`.
|
||||
*
|
||||
* On Windows the system PATH is always available, so `where.exe` is sufficient.
|
||||
*/
|
||||
export function findExecutable(name: string): string | null {
|
||||
const trimmed = name.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (normalized.includes("/") || normalized.includes("\\")) {
|
||||
return existsSync(normalized);
|
||||
if (trimmed.includes("/") || trimmed.includes("\\")) {
|
||||
return existsSync(trimmed) ? trimmed : null;
|
||||
}
|
||||
|
||||
if (platform() === "win32") {
|
||||
try {
|
||||
const out = execSync(`where.exe ${trimmed}`, { encoding: "utf8" }).trim();
|
||||
const firstLine = out.split(/\r?\n/)[0]?.trim();
|
||||
return firstLine || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Unix: try the user's login shell so rc-file PATH entries are visible.
|
||||
const shell = process.env["SHELL"];
|
||||
if (shell) {
|
||||
try {
|
||||
const out = execSync(`${shell} -lic "which ${trimmed}"`, {
|
||||
encoding: "utf8",
|
||||
timeout: 5000,
|
||||
}).trim();
|
||||
if (out) {
|
||||
return out;
|
||||
}
|
||||
} catch {
|
||||
// Login shell failed (broken rc, etc.) — fall through to plain which.
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const output = execFileSync("which", [normalized], { encoding: "utf8" }).trim();
|
||||
return output.length > 0;
|
||||
return execFileSync("which", [trimmed], { encoding: "utf8" }).trim() || null;
|
||||
} catch {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function isCommandAvailable(command: string): boolean {
|
||||
return findExecutable(command) !== null;
|
||||
}
|
||||
|
||||
export function isProviderCommandAvailable(
|
||||
commandConfig: ProviderCommand | undefined,
|
||||
resolveDefaultCommand: () => string
|
||||
|
||||
@@ -69,6 +69,7 @@ import type {
|
||||
} from "../agent-sdk-types.js";
|
||||
import {
|
||||
applyProviderEnv,
|
||||
findExecutable,
|
||||
isProviderCommandAvailable,
|
||||
type ProviderRuntimeSettings,
|
||||
} from "../provider-launch-config.js";
|
||||
@@ -363,16 +364,8 @@ type ClaudeAgentSessionOptions = {
|
||||
logger: Logger;
|
||||
};
|
||||
|
||||
function whichClaude(): string | null {
|
||||
try {
|
||||
return execSync("which claude", { encoding: "utf8" }).trim() || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveClaudeBinary(): string {
|
||||
const claudePath = whichClaude();
|
||||
const claudePath = findExecutable("claude");
|
||||
if (claudePath) {
|
||||
return claudePath;
|
||||
}
|
||||
@@ -1414,7 +1407,7 @@ export class ClaudeAgentClient implements AgentClient {
|
||||
this.defaults = options.defaults;
|
||||
this.logger = options.logger.child({ module: "agent", provider: "claude" });
|
||||
this.runtimeSettings = options.runtimeSettings;
|
||||
this.claudePath = whichClaude();
|
||||
this.claudePath = findExecutable("claude");
|
||||
if (this.claudePath) {
|
||||
try {
|
||||
const version = execSync(`${this.claudePath} --version`, { encoding: "utf8" }).trim();
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
} from "./codex/tool-call-mapper.js";
|
||||
import {
|
||||
applyProviderEnv,
|
||||
findExecutable,
|
||||
isProviderCommandAvailable,
|
||||
resolveProviderCommandPrefix,
|
||||
type ProviderRuntimeSettings,
|
||||
@@ -150,13 +151,9 @@ function mergeCodexConfiguredDefaults(
|
||||
}
|
||||
|
||||
function resolveCodexBinary(): string {
|
||||
try {
|
||||
const codexPath = execSync("which codex", { encoding: "utf8" }).trim();
|
||||
if (codexPath) {
|
||||
return codexPath;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to error
|
||||
const codexPath = findExecutable("codex");
|
||||
if (codexPath) {
|
||||
return codexPath;
|
||||
}
|
||||
throw new Error(
|
||||
"Codex CLI not found. Please install codex globally: npm install -g @openai/codex"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { execSync, spawn, type ChildProcess } from "node:child_process";
|
||||
import { spawn, type ChildProcess } from "node:child_process";
|
||||
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
||||
import net from "node:net";
|
||||
import type { Logger } from "pino";
|
||||
@@ -29,6 +29,7 @@ import type {
|
||||
} from "../agent-sdk-types.js";
|
||||
import {
|
||||
applyProviderEnv,
|
||||
findExecutable,
|
||||
isProviderCommandAvailable,
|
||||
resolveProviderCommandPrefix,
|
||||
type ProviderRuntimeSettings,
|
||||
@@ -150,13 +151,9 @@ const OpencodeToolPartToTimelineItemSchema = OpencodeToolPartTimelineEnvelopeSch
|
||||
);
|
||||
|
||||
function resolveOpenCodeBinary(): string {
|
||||
try {
|
||||
const opencodePath = execSync("which opencode", { encoding: "utf8" }).trim();
|
||||
if (opencodePath) {
|
||||
return opencodePath;
|
||||
}
|
||||
} catch {
|
||||
// fall through
|
||||
const opencodePath = findExecutable("opencode");
|
||||
if (opencodePath) {
|
||||
return opencodePath;
|
||||
}
|
||||
throw new Error(
|
||||
"OpenCode CLI not found. Please install opencode globally so Paseo can launch the provider."
|
||||
|
||||
Reference in New Issue
Block a user