feat(M2): Client Detection & Configuration
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user