fix(client): CLI launcher recognises new heicode-sidecar binary name

resolveBundledCliPathFromExecPath / resolveClaudeCliLauncher hardcoded
startsWith('claude-sidecar') / startsWith('claude-server') checks. After
the 3a358ba rebrand the bundled binary is heicode-sidecar-*.exe — the
match fails, the function returns null, and resolveCliArgs falls back
to the Windows --preload script branch which spawns the bun-compiled
sidecar with arguments it doesn't understand. The process exits 2
silently (empty stderr), surfacing in the UI as:

    Error: CLI 进程启动失败。
    CLI exited during startup with code 2.

Symptom user report: pilac69779@codoteam.com freshly registered, OAuth
login succeeded but every chat attempt failed at sidecar startup.

Fix: accept both `heicode-` and legacy `claude-` prefixes for sidecar /
server / cli binaries so MSI #15+ launchers work AND
CLAUDE_CLI_PATH=/path/to/legacy/claude-sidecar still works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 21:13:43 +08:00
co-authored by Claude Opus 4.7
parent a2deeb61b0
commit da218ebbe5
+24 -5
View File
@@ -7,19 +7,38 @@ export type ClaudeCliLauncher = {
requiresAppRoot: boolean
}
// The sidecar binary was renamed claude-sidecar → heicode-sidecar in
// commit 3a358ba (full Claude→Heicode rebrand). Keep recognising the legacy
// names so unbundled CLAUDE_CLI_PATH overrides and historical installers keep
// working, but new MSI builds ship `heicode-sidecar-*.exe` — without the
// heicode-* prefix below `resolveClaudeCliLauncher` returns null and the
// caller falls back to the `--preload` script branch, which doesn't work
// against a bun-compiled binary and silently exits with code 2 at startup.
const SIDECAR_PREFIXES = ['heicode-sidecar', 'claude-sidecar']
const SERVER_PREFIXES = ['heicode-server', 'claude-server']
function startsWithAny(name: string, prefixes: readonly string[]): string | null {
for (const p of prefixes) {
if (name.startsWith(p)) return p
}
return null
}
export function resolveBundledCliPathFromExecPath(
execPath: string = process.execPath,
): string | null {
const execName = path.basename(execPath)
if (execName.startsWith('claude-sidecar')) {
if (startsWithAny(execName, SIDECAR_PREFIXES)) {
return execPath
}
if (execName.startsWith('claude-server')) {
const serverPrefix = startsWithAny(execName, SERVER_PREFIXES)
if (serverPrefix) {
const cliPrefix = serverPrefix.replace(/-server$/, '-cli')
const bundledCliPath = path.join(
path.dirname(execPath),
execName.replace(/^claude-server/, 'claude-cli'),
execName.replace(new RegExp(`^${serverPrefix}`), cliPrefix),
)
return fs.existsSync(bundledCliPath) ? bundledCliPath : null
}
@@ -47,7 +66,7 @@ export function resolveClaudeCliLauncher(options?: {
}
const cliBaseName = path.basename(command)
if (cliBaseName.startsWith('claude-sidecar')) {
if (startsWithAny(cliBaseName, SIDECAR_PREFIXES)) {
return {
command,
kind: 'sidecar',
@@ -55,7 +74,7 @@ export function resolveClaudeCliLauncher(options?: {
}
}
if (cliBaseName.startsWith('claude-cli')) {
if (cliBaseName.startsWith('heicode-cli') || cliBaseName.startsWith('claude-cli')) {
return {
command,
kind: 'binary',