openpencil/server/utils/copilot-client.ts
Kayshen Xu e25feb56fc V0.4.3 (#50)
* chore(ai): update dependencies and enhance logging functionality

- Bump version of `@github/copilot-sdk` and related packages to `0.1.32` and `1.0.7` for improved features and bug fixes.
- Update Discord invite links across multiple README files to the new server.
- Introduce a new logging utility in `server/utils/server-logger.ts` for better server process logging, including automatic log cleanup and directory management.
- Enhance the `connect-agent.ts` and `install-agent.ts` files to improve OpenCode binary resolution and installation commands.
- Refactor `resolve-claude-cli.ts` and `resolve-copilot-cli.ts` to include detailed logging for CLI binary resolution processes.

This update improves dependency management, enhances user experience with updated links, and provides better insights into server operations through logging.

* chore: bump version from 0.4.0 to 0.4.3 in package.json
2026-03-18 21:34:58 +08:00

65 lines
2.5 KiB
TypeScript

import { execSync } from 'node:child_process'
import { existsSync } from 'node:fs'
import { join } from 'node:path'
import { serverLog } from './server-logger'
const isWindows = process.platform === 'win32'
/** Resolve the standalone copilot CLI binary path to avoid Bun's node:sqlite issue */
export function resolveCopilotCli(): string | undefined {
serverLog.info(`[resolve-copilot] platform=${process.platform}, isWindows=${isWindows}`)
// 1. Try PATH lookup
try {
const cmd = isWindows ? 'where copilot 2>nul' : 'which copilot 2>/dev/null'
serverLog.info(`[resolve-copilot] PATH lookup: ${cmd}`)
const result = execSync(cmd, { encoding: 'utf-8', timeout: 5000 }).trim()
// `where` on Windows may return multiple lines
const path = result.split(/\r?\n/)[0]?.trim()
serverLog.info(`[resolve-copilot] PATH result: "${path}" (exists=${path ? existsSync(path) : false})`)
if (path && existsSync(path)) return path
} catch (err) {
serverLog.info(`[resolve-copilot] PATH lookup failed: ${err instanceof Error ? err.message : err}`)
}
// 2. Try `npm prefix -g` on Windows (npm install -g creates .cmd wrappers)
if (isWindows) {
try {
serverLog.info('[resolve-copilot] trying npm.cmd prefix -g')
const prefix = execSync('npm.cmd prefix -g', {
encoding: 'utf-8',
timeout: 5000,
}).trim()
serverLog.info(`[resolve-copilot] npm global prefix: "${prefix}"`)
if (prefix) {
const bin = join(prefix, 'copilot.cmd')
serverLog.info(`[resolve-copilot] npm global bin: "${bin}" (exists=${existsSync(bin)})`)
if (existsSync(bin)) return bin
}
} catch (err) {
serverLog.info(`[resolve-copilot] npm prefix -g failed: ${err instanceof Error ? err.message : err}`)
}
}
// 3. Common install locations
if (isWindows) {
const candidates = [
// npm global
join(process.env.APPDATA || '', 'npm', 'copilot.cmd'),
// nvm-windows / fnm
join(process.env.NVM_SYMLINK || '', 'copilot.cmd'),
join(process.env.FNM_MULTISHELL_PATH || '', 'copilot.cmd'),
// winget / native
join(process.env.LOCALAPPDATA || '', 'Microsoft', 'WinGet', 'Links', 'copilot.exe'),
]
for (const c of candidates) {
const exists = c ? existsSync(c) : false
serverLog.info(`[resolve-copilot] candidate: "${c}" (exists=${exists})`)
if (c && exists) return c
}
}
serverLog.warn('[resolve-copilot] no copilot binary found')
return undefined
}