feat(M2): Client Detection & Configuration

This commit is contained in:
2026-05-18 17:53:47 -05:00
parent 185083ace8
commit 82fcd3363c
5 changed files with 46 additions and 14 deletions
+6 -5
View File
@@ -5,8 +5,7 @@ import {
} from "node:fs";
import { spawnSync } from "node:child_process";
import type { ClientName } from "./types.js";
const CLIENT_NAMES: ClientName[] = ["codex", "claude", "opencode"];
import { CLIENT_NAMES, isWindows } from "./constants.js";
export interface ResolvedConfig {
paths: Partial<Record<ClientName, string>>;
@@ -23,8 +22,7 @@ export interface ResolveConfigOptions {
}
function defaultWhichSync(cmd: string): string | undefined {
const isWin = process.platform === "win32";
const result = spawnSync(isWin ? "where" : "which", [cmd], {
const result = spawnSync(isWindows() ? "where" : "which", [cmd], {
encoding: "utf-8",
});
if (result.status === 0) {
@@ -85,7 +83,10 @@ export function resolveConfig(
fileDefault;
const result: ResolvedConfig = { paths };
if (defaultClient !== undefined) {
if (
defaultClient !== undefined &&
CLIENT_NAMES.includes(defaultClient as ClientName)
) {
result.defaultClient = defaultClient as ClientName;
}
return result;
+7
View File
@@ -0,0 +1,7 @@
import type { ClientName } from "./types.js";
export const CLIENT_NAMES: ClientName[] = ["codex", "claude", "opencode"];
export function isWindows(): boolean {
return process.platform === "win32";
}
+5 -8
View File
@@ -2,8 +2,7 @@ import { spawnSync as defaultSpawnSync } from "node:child_process";
import { existsSync as defaultExistsSync } from "node:fs";
import { join } from "node:path";
import { type ClientName, type ClientInfo } from "./types.js";
const CLIENT_NAMES: ClientName[] = ["codex", "claude", "opencode"];
import { CLIENT_NAMES, isWindows } from "./constants.js";
export interface DetectOptions {
pathEnv?: string;
@@ -13,7 +12,7 @@ export interface DetectOptions {
function parseVersion(stdout: string): string | undefined {
const match = stdout.match(/v?\d+\.\d+\.\d+(?:[-+.]\w+)*/);
return match ? match[0] : undefined;
return match ? match[0].replace(/^v/, "") : undefined;
}
function findBinary(
@@ -22,10 +21,8 @@ function findBinary(
spawnSyncImpl: typeof defaultSpawnSync,
existsSyncImpl: typeof defaultExistsSync
): string | undefined {
const isWin = process.platform === "win32";
// Try system `which` / `where` first
const whichResult = spawnSyncImpl(isWin ? "where" : "which", [name], {
const whichResult = spawnSyncImpl(isWindows() ? "where" : "which", [name], {
encoding: "utf-8",
env: { ...process.env, PATH: pathEnv },
});
@@ -35,8 +32,8 @@ function findBinary(
}
// Fallback: walk PATH directories manually
const sep = isWin ? ";" : ":";
const ext = isWin ? ".exe" : "";
const sep = isWindows() ? ";" : ":";
const ext = isWindows() ? ".exe" : "";
const dirs = pathEnv.split(sep);
for (const dir of dirs) {
if (!dir) continue;