diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6d6e19ce..5f2cbbd2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -39,23 +39,12 @@ jobs:
exit 1
fi
- - name: Build and publish macOS artifacts
+ - name: Build and publish ad-hoc macOS artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- CSC_LINK: ${{ secrets.CSC_LINK }}
- CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
- APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
- APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
- APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
- APPLE_ID: ${{ secrets.APPLE_ID }}
- APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- APPLE_KEYCHAIN: ${{ secrets.APPLE_KEYCHAIN }}
- APPLE_KEYCHAIN_PROFILE: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
run: |
- node build/macos-release-preflight.mjs
npm run build:assets
- npx electron-builder --mac --publish always
+ npx electron-builder --config build/electron-builder.local.cjs --mac --publish always
windows:
name: Windows
diff --git a/examples/plugins/claude-design-plugin.cjs b/examples/plugins/claude-design-plugin.cjs
index c97dc6b5..da9fbd8d 100644
--- a/examples/plugins/claude-design-plugin.cjs
+++ b/examples/plugins/claude-design-plugin.cjs
@@ -7904,6 +7904,7 @@ function renderDefaultDesignIndex(me, scriptPath, stylePath, options = {}) {
Claude Design
+ ${claudeAppDesktopFeaturesScript()}
`;
+ return ``;
}
function designModelPreferenceResetScript(me) {
diff --git a/src/main/claude-app-cdp.ts b/src/main/claude-app-cdp.ts
index ddf27600..e9596fab 100644
--- a/src/main/claude-app-cdp.ts
+++ b/src/main/claude-app-cdp.ts
@@ -45,7 +45,14 @@ const claudeAppDesignCdpConnectTimeoutMs = 15_000;
const claudeAppDesignCdpKeepAliveMs = 45_000;
const claudeAppDesignCdpPollIntervalMs = 250;
+export function shouldEnableClaudeAppDesignCdp(): boolean {
+ return process.env.CCR_CLAUDE_APP_DESIGN_CDP?.trim().toLowerCase() === "true";
+}
+
export async function reserveClaudeAppCdpPort(logger: ClaudeAppCdpLogger = console): Promise {
+ if (!shouldEnableClaudeAppDesignCdp()) {
+ return undefined;
+ }
const configured = Number(process.env.CCR_CLAUDE_APP_CDP_PORT);
if (Number.isInteger(configured) && configured > 0 && configured <= 65535) {
return configured;
@@ -63,7 +70,7 @@ export function prepareClaudeAppCdpUserDataDir(userDataDir: string): void {
}
export function scheduleClaudeAppDesignCdp(options: ClaudeAppDesignCdpOptions): void {
- if (process.env.CCR_CLAUDE_APP_DESIGN_CDP?.trim().toLowerCase() === "false") {
+ if (!shouldEnableClaudeAppDesignCdp()) {
return;
}
const logger = options.logger || console;
@@ -215,19 +222,30 @@ function claudeAppDesignFeatureScript(): string {
} catch (_) {
globalThis.desktopBootFeatures = bootFeatures;
}
+ function patchAppFeatures(container) {
+ if (!container) {
+ return;
+ }
+ const existing = container.AppFeatures || {};
+ if (existing.__ccrClaudeDesignPatched) {
+ return;
+ }
+ const previous = existing.getSupportedFeatures;
+ container.AppFeatures = Object.assign({}, existing, {
+ __ccrClaudeDesignPatched: true,
+ getSupportedFeatures() {
+ if (typeof previous === "function") {
+ return Promise.resolve(previous.call(existing)).then(merge, () => merge());
+ }
+ return Promise.resolve(merge());
+ }
+ });
+ }
+ globalThis["claude.settings"] = globalThis["claude.settings"] || {};
+ patchAppFeatures(globalThis["claude.settings"]);
globalThis.claude = globalThis.claude || {};
globalThis.claude.settings = globalThis.claude.settings || {};
- const existing = globalThis.claude.settings.AppFeatures || {};
- const previous = existing.getSupportedFeatures;
- globalThis.claude.settings.AppFeatures = Object.assign({}, existing, {
- __ccrClaudeDesignPatched: true,
- getSupportedFeatures() {
- if (typeof previous === "function") {
- return Promise.resolve(previous.call(existing)).then(merge, () => merge());
- }
- return Promise.resolve(merge());
- }
- });
+ patchAppFeatures(globalThis.claude.settings);
})();`;
}
diff --git a/src/main/codex-cli-middleware-runtime.ts b/src/main/codex-cli-middleware-runtime.ts
index 308cc5de..6791ffb6 100644
--- a/src/main/codex-cli-middleware-runtime.ts
+++ b/src/main/codex-cli-middleware-runtime.ts
@@ -1984,11 +1984,12 @@ function collaborationModes() {
function modelList(params, existingResult) {
const runtimeAgent = codexRuntimeAgent();
const isClaudeCodeRuntime = normalizeRemoteFrontendMode(agentEnv(runtimeAgent, "REMOTE_FRONTEND_MODE", "CORE_MODE")) === "claude-code";
- const configured = normalizeModelSelector(agentEnv(runtimeAgent, "MODEL") || nonEmptyEnv("CODEXL_CLAUDE_CODE_MODEL") || (isClaudeCodeRuntime ? DEFAULT_MODEL : ""));
+ const configured = normalizeModelSelector(agentEnv(runtimeAgent, "MODEL") || nonEmptyEnv("CODEXL_CLAUDE_CODE_MODEL"));
+ const selected = configured || (isClaudeCodeRuntime ? DEFAULT_MODEL : "");
const fallbackIds = isClaudeCodeRuntime
- ? [configured, DEFAULT_MODEL, "claude-opus-4-5", "claude-haiku-4-5"].filter(Boolean)
+ ? [configured].filter(Boolean)
: [configured].filter((model) => model && !isClaudeCodeOnlyModel(model));
- const models = mergeModelListItems(extractModelListItems(existingResult), [...catalogModelIds(), ...fallbackIds], configured);
+ const models = mergeModelListItems(extractModelListItems(existingResult), [...catalogModelIds(), ...fallbackIds], selected);
const offset = Number(params.cursor || 0) || 0;
const limit = Number(params.limit || models.length) || models.length;
const data = models.slice(offset, offset + limit);
diff --git a/src/main/profile-launch-service.ts b/src/main/profile-launch-service.ts
index 250a984c..b6d3ef53 100644
--- a/src/main/profile-launch-service.ts
+++ b/src/main/profile-launch-service.ts
@@ -140,7 +140,18 @@ async function openClaudeAppProfile(config: AppConfig, profile: ReturnType,
options: ClaudeAppGatewayModelRouteOptions = {}
): ClaudeAppGatewayModelRoute[] {
- const targetModels = claudeAppGatewayTargetModels(config).slice(0, CLAUDE_APP_ROUTE_NAMES.length);
+ const targetModels = claudeAppGatewayTargetModels(config);
const displayNames = claudeAppGatewayDisplayNames(targetModels);
return targetModels.map((rawTargetModel, index) => {
const targetModel = stripClaudeAppGatewayOneMillionContextSuffix(rawTargetModel);
const oneMillionContext = claudeAppGatewaySupportsOneMillionContext(rawTargetModel, options);
- const routeId = claudeAppGatewayRouteId(index);
+ const routeId = claudeAppGatewayRouteId(rawTargetModel);
return {
displayName: oneMillionContext ? `${displayNames[index]} (1M context)` : displayNames[index],
id: routeId,
+ legacyId: claudeAppGatewayLegacyRouteId(index),
oneMillionContext,
targetModel
};
@@ -63,8 +65,11 @@ export function resolveClaudeAppGatewayRouteModel(
const normalized = model.trim().toLowerCase();
return buildClaudeAppGatewayModelRoutes(config, options).find((route) => {
const routeId = route.id.toLowerCase();
+ const legacyRouteId = route.legacyId?.toLowerCase();
return routeId === normalized ||
- stripClaudeAppGatewayOneMillionContextSuffix(routeId).toLowerCase() === normalized;
+ stripClaudeAppGatewayOneMillionContextSuffix(routeId).toLowerCase() === normalized ||
+ legacyRouteId === normalized ||
+ (legacyRouteId ? stripClaudeAppGatewayOneMillionContextSuffix(legacyRouteId).toLowerCase() === normalized : false);
})?.targetModel;
}
@@ -153,8 +158,13 @@ function claudeAppGatewaySupportsOneMillionContext(
Boolean(options.supportsOneMillionContext?.(baseModel));
}
-function claudeAppGatewayRouteId(index: number): string {
- return CLAUDE_APP_ROUTE_NAMES[index] ?? CLAUDE_APP_FALLBACK_MODEL;
+function claudeAppGatewayLegacyRouteId(index: number): string | undefined {
+ return CLAUDE_APP_LEGACY_ROUTE_NAMES[index];
+}
+
+function claudeAppGatewayRouteId(model: string): string {
+ const normalized = model.trim();
+ return normalized.toLowerCase().startsWith("claude-") ? normalized : `claude-${normalized}`;
}
function claudeAppGatewayDisplayNames(models: string[]): string[] {