fix: preserve profile preparation before TTY dispatch

This commit is contained in:
jesieleo
2026-07-11 10:07:46 +08:00
parent 1389ff5c75
commit faa721fed8
3 changed files with 56 additions and 9 deletions
+4
View File
@@ -57,6 +57,7 @@ const serviceStopTimeoutMs = 10_000;
const webAuthHeader = "x-ccr-web-auth";
const webAuthQueryParam = "ccr_web_token";
const defaultCliCommandName = "ccr";
const prepareProfileOnlyEnv = "CCR_CLI_PREPARE_PROFILE_ONLY";
async function main(): Promise<void> {
const options = parseArgs(process.argv.slice(2));
@@ -123,6 +124,9 @@ async function main(): Promise<void> {
throw new Error(runtimeResult.message);
}
}
if (resolvedSurface === "cli" && process.env[prepareProfileOnlyEnv] === "1") {
return;
}
if (profile.agent === "claude-code" && resolvedSurface === "app") {
applyClaudeAppGatewayConfig(launchConfig);
applyClaudeAppGatewayConfig(launchConfig, {
+15 -9
View File
@@ -1183,20 +1183,12 @@ function posixCcrLauncher(runtimeFile: string): string {
].join("\n") + "\n";
}
function windowsCcrLauncher(runtimeFile: string, config?: AppConfig): string {
export function windowsCcrLauncher(runtimeFile: string, config?: AppConfig): string {
const nodePath = bundledNodePath();
const dispatches = config ? windowsProfileCliDispatches(config) : [];
return [
"@echo off",
"setlocal",
...(dispatches.length > 0
? [
"if /I \"%~2\"==\"app\" goto ccr_run_cli",
"if /I \"%~2\"==\"--app\" goto ccr_run_cli",
...dispatches.map((dispatch, index) => `if /I \"%~1\"==\"${cmdValue(dispatch.profileRef)}\" goto ccr_profile_${index}`),
":ccr_run_cli"
]
: []),
`set "${desktopCliCommandNameEnv}=${desktopCliCommandName}"`,
`set "CCR_CLI_RUNTIME=${cmdEnvValue(runtimeFile)}"`,
`set "CCR_CLI_NODE_PATH=${cmdEnvValue(nodePath)}"`,
@@ -1205,6 +1197,14 @@ function windowsCcrLauncher(runtimeFile: string, config?: AppConfig): string {
") else (",
" set \"NODE_PATH=%CCR_CLI_NODE_PATH%\"",
")",
...(dispatches.length > 0
? [
"if /I \"%~2\"==\"app\" goto ccr_run_cli",
"if /I \"%~2\"==\"--app\" goto ccr_run_cli",
...dispatches.map((dispatch, index) => `if /I \"%~1\"==\"${cmdValue(dispatch.profileRef)}\" goto ccr_profile_${index}`),
":ccr_run_cli"
]
: []),
"if defined CCR_NODE_BIN (",
' "%CCR_NODE_BIN%" "%CCR_CLI_RUNTIME%" %*',
" exit /b %ERRORLEVEL%",
@@ -1214,6 +1214,12 @@ function windowsCcrLauncher(runtimeFile: string, config?: AppConfig): string {
"exit /b %ERRORLEVEL%",
...dispatches.flatMap((dispatch, index) => [
`:ccr_profile_${index}`,
"set \"CCR_CLI_PREPARE_PROFILE_ONLY=1\"",
"set \"ELECTRON_RUN_AS_NODE=1\"",
`${cmdQuote(process.execPath)} "%CCR_CLI_RUNTIME%" %*`,
"if errorlevel 1 exit /b %ERRORLEVEL%",
"set \"CCR_CLI_PREPARE_PROFILE_ONLY=\"",
"set \"ELECTRON_RUN_AS_NODE=\"",
"set \"CCR_CLI_DIRECT_PROFILE_DISPATCH=1\"",
`call ${cmdQuote(dispatch.launcher)} %*`,
"exit /b %ERRORLEVEL%"
+37
View File
@@ -0,0 +1,37 @@
import assert from "node:assert/strict";
import path from "node:path";
import test from "node:test";
import { windowsCcrLauncher } from "../../packages/core/src/profiles/launch-service.ts";
test("Windows CCR launcher prepares CLI profiles before direct TTY dispatch", { skip: process.platform !== "win32" }, () => {
const config = {
profile: {
profiles: [
{
agent: "claude-code",
enabled: true,
id: "claude-main",
model: "provider/model",
name: "Claude Main",
scope: "ccr",
surface: "cli"
}
]
}
};
const runtimeFile = path.join("C:\\CCR", "ccr-cli.js");
const launcher = windowsCcrLauncher(runtimeFile, config);
assert.match(launcher, /if \/I "%~1"=="Claude Main" goto ccr_profile_0/);
assert.match(launcher, /set "CCR_CLI_PREPARE_PROFILE_ONLY=1"/);
assert.match(launcher, /set "ELECTRON_RUN_AS_NODE=1"/);
assert.match(launcher, /set "CCR_CLI_DIRECT_PROFILE_DISPATCH=1"/);
assert.match(launcher, /call ".*ccr-claude-code-wrapper-claude-main\.cmd" %\*/);
const prepareIndex = launcher.indexOf('set "CCR_CLI_PREPARE_PROFILE_ONLY=1"');
const directDispatchIndex = launcher.indexOf('set "CCR_CLI_DIRECT_PROFILE_DISPATCH=1"');
const wrapperIndex = launcher.indexOf("ccr-claude-code-wrapper-claude-main.cmd");
assert.equal(prepareIndex >= 0, true);
assert.equal(directDispatchIndex > prepareIndex, true);
assert.equal(wrapperIndex > directDispatchIndex, true);
});