🐛 fix(vscode): GUI 下解析 claude 绝对路径(含 ~/.local/bin 官方安装)

This commit is contained in:
2026-08-05 14:57:48 +08:00
parent 81ab00bdba
commit 9255b55625
4 changed files with 127 additions and 14 deletions
+25 -13
View File
@@ -19,6 +19,8 @@
*/
import { spawn } from 'node:child_process'
import * as path from 'node:path'
import { resolveClaudeBin } from './claudeBin'
const DEFAULT_TIMEOUT_MS = 300_000
const MAX_BUFFER_BYTES = 10 * 1024 * 1024
@@ -206,7 +208,9 @@ function buildStreamJsonLine(prompt: string, images: ClaudeImage[]): string {
* - CLAUDECODE / CLAUDE_CODE_ENTRYPOINT / CLAUDE_CODE_SESSION_ID / CLAUDE_CODE_SESSION
* 从父 Claude 会话继承会让子进程当成嵌套会话直接静默退出、零输出。
*/
function buildClaudeChildEnv(): NodeJS.ProcessEnv {
const CLAUDE_MISSING_MSG = '未检测到 claude CLI,请确认已安装并在 PATH 中(常见位置 ~/.local/bin'
function buildClaudeChildEnv(bin?: string): NodeJS.ProcessEnv {
// 剔除所有 ANTHROPIC_* 是为了让 `--settings` profile 成为 provider/鉴权的唯一来源
// profile 没配则回落 ~/.claude 订阅 OAuth),避免宿主 env 残留的 BASE_URL/TOKEN
// 覆盖 profile 导致 403。同时清除嵌套 Claude 会话标记,避免后台 `claude -p` 误判处于嵌套会话。
@@ -224,6 +228,12 @@ function buildClaudeChildEnv(): NodeJS.ProcessEnv {
continue
out[k] = v
}
// claude 再 spawn 子工具时仍要能找到自己所在目录
if (bin) {
const dir = path.dirname(bin)
const prev = out.PATH ?? ''
out.PATH = prev ? `${dir}${path.delimiter}${prev}` : dir
}
return out
}
@@ -265,15 +275,19 @@ function spawnClaudeText(
'json',
]
const bin = resolveClaudeBin()
if (!bin)
return Promise.reject(new ClaudeError(CLAUDE_MISSING_MSG, ''))
return new Promise<ClaudeResult>((resolve, reject) => {
let stdout = ''
let stderr = ''
let stdoutBytes = 0
let settled = false
const child = spawn('claude', args, {
const child = spawn(bin, args, {
cwd,
env: buildClaudeChildEnv(),
env: buildClaudeChildEnv(bin),
stdio: ['ignore', 'pipe', 'pipe'],
})
@@ -295,10 +309,7 @@ function spawnClaudeText(
clearTimeout(timer)
const errCode = (err as NodeJS.ErrnoException).code
if (errCode === 'ENOENT') {
reject(new ClaudeError(
'未检测到 claude CLI,请确认已安装并在 PATH 中',
stderr,
))
reject(new ClaudeError(CLAUDE_MISSING_MSG, stderr))
return
}
reject(new ClaudeError(
@@ -385,15 +396,19 @@ function spawnClaudeStreamed(
]
const ndjson = buildStreamJsonLine(prompt, images)
const bin = resolveClaudeBin()
if (!bin)
return Promise.reject(new ClaudeError(CLAUDE_MISSING_MSG, ''))
return new Promise<ClaudeResult>((resolve, reject) => {
let stdout = ''
let stderr = ''
let stdoutBytes = 0
let settled = false
const child = spawn('claude', args, {
const child = spawn(bin, args, {
cwd,
env: buildClaudeChildEnv(),
env: buildClaudeChildEnv(bin),
stdio: ['pipe', 'pipe', 'pipe'],
})
@@ -415,10 +430,7 @@ function spawnClaudeStreamed(
clearTimeout(timer)
const errCode = (err as NodeJS.ErrnoException).code
if (errCode === 'ENOENT') {
reject(new ClaudeError(
'未检测到 claude CLI,请确认已安装并在 PATH 中',
stderr,
))
reject(new ClaudeError(CLAUDE_MISSING_MSG, stderr))
return
}
reject(new ClaudeError(