Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions src/brands/alibaba.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import type { TweakccConfig, Theme } from './types.js';
import { DEFAULT_THEMES } from './defaultThemes.js';
import { buildBrandMiscConfig } from './miscDefaults.js';
import { buildDiffPalette } from './diffPalette.js';
import { formatUserMessage, getUserLabel } from './userLabel.js';

type Rgb = { r: number; g: number; b: number };

const clamp = (value: number) => Math.max(0, Math.min(255, Math.round(value)));

const hexToRgb = (hex: string): Rgb => {
const normalized = hex.replace('#', '').trim();
if (normalized.length === 3) {
const [r, g, b] = normalized.split('');
return {
r: clamp(parseInt(r + r, 16)),
g: clamp(parseInt(g + g, 16)),
b: clamp(parseInt(b + b, 16)),
};
}
if (normalized.length !== 6) {
throw new Error(`Unsupported hex color: ${hex}`);
}
return {
r: clamp(parseInt(normalized.slice(0, 2), 16)),
g: clamp(parseInt(normalized.slice(2, 4), 16)),
b: clamp(parseInt(normalized.slice(4, 6), 16)),
};
};

const rgb = (hex: string) => {
const { r, g, b } = hexToRgb(hex);
return `rgb(${r},${g},${b})`;
};

const mix = (hexA: string, hexB: string, weight: number) => {
const a = hexToRgb(hexA);
const b = hexToRgb(hexB);
const w = Math.max(0, Math.min(1, weight));
return `rgb(${clamp(a.r + (b.r - a.r) * w)},${clamp(a.g + (b.g - a.g) * w)},${clamp(a.b + (b.b - a.b) * w)})`;
};

const lighten = (hex: string, weight: number) => mix(hex, '#ffffff', weight);

// Alibaba Cloud palette: purple, dark blue, aqua, white
const palette = {
base: '#0d1117',
surface: '#161b22',
panel: '#21262d',
border: '#30363d',
borderStrong: '#484f58',
text: '#f0f6fc',
textMuted: '#8b949e',
textDim: '#6e7681',
purple: '#a371f7',
purpleSoft: '#c9a8ff',
purpleDeep: '#7c3aed',
darkBlue: '#1f6feb',
darkBlueSoft: '#58a6ff',
darkBlueDeep: '#0d419d',
aqua: '#2dd4bf',
aquaSoft: '#5eead4',
aquaDeep: '#14b8a6',
white: '#ffffff',
green: '#3fb950',
red: '#f85149',
orange: '#d29922',
};

const theme: Theme = {
name: 'Alibaba Aurora',
id: 'alibaba',
colors: {
autoAccept: rgb(palette.green),
bashBorder: rgb(palette.aqua),
claude: rgb(palette.purple),
claudeShimmer: rgb(palette.purpleSoft),
claudeBlue_FOR_SYSTEM_SPINNER: rgb(palette.darkBlue),
claudeBlueShimmer_FOR_SYSTEM_SPINNER: rgb(palette.darkBlueSoft),
permission: rgb(palette.darkBlue),
permissionShimmer: rgb(palette.darkBlueSoft),
planMode: rgb(palette.green),
ide: rgb(palette.darkBlueSoft),
promptBorder: rgb(palette.border),
promptBorderShimmer: rgb(palette.borderStrong),
text: rgb(palette.text),
inverseText: rgb(palette.base),
inactive: rgb(palette.textDim),
subtle: rgb(palette.border),
suggestion: rgb(palette.darkBlueSoft),
remember: rgb(palette.purple),
background: rgb(palette.base),
success: rgb(palette.green),
error: rgb(palette.red),
warning: rgb(palette.orange),
warningShimmer: rgb(palette.aquaSoft),
...buildDiffPalette(),
red_FOR_SUBAGENTS_ONLY: rgb(palette.red),
blue_FOR_SUBAGENTS_ONLY: rgb(palette.darkBlueDeep),
green_FOR_SUBAGENTS_ONLY: rgb(palette.green),
yellow_FOR_SUBAGENTS_ONLY: rgb(palette.orange),
purple_FOR_SUBAGENTS_ONLY: rgb(palette.purple),
orange_FOR_SUBAGENTS_ONLY: rgb(palette.orange),
pink_FOR_SUBAGENTS_ONLY: rgb(palette.purpleSoft),
cyan_FOR_SUBAGENTS_ONLY: rgb(palette.aqua),
professionalBlue: rgb(palette.darkBlueSoft),
rainbow_red: rgb(palette.red),
rainbow_orange: rgb(palette.orange),
rainbow_yellow: rgb(palette.aqua),
rainbow_green: rgb(palette.green),
rainbow_blue: rgb(palette.darkBlue),
rainbow_indigo: rgb(palette.purpleDeep),
rainbow_violet: rgb(palette.purple),
rainbow_red_shimmer: lighten(palette.red, 0.35),
rainbow_orange_shimmer: lighten(palette.orange, 0.35),
rainbow_yellow_shimmer: lighten(palette.aqua, 0.25),
rainbow_green_shimmer: lighten(palette.green, 0.35),
rainbow_blue_shimmer: lighten(palette.darkBlue, 0.35),
rainbow_indigo_shimmer: lighten(palette.purpleDeep, 0.35),
rainbow_violet_shimmer: lighten(palette.purple, 0.35),
clawd_body: rgb(palette.purple),
clawd_background: rgb(palette.base),
userMessageBackground: mix(palette.panel, palette.purple, 0.15),
bashMessageBackgroundColor: mix(palette.panel, palette.aqua, 0.08),
memoryBackgroundColor: mix(palette.panel, palette.darkBlue, 0.12),
rate_limit_fill: rgb(palette.purple),
rate_limit_empty: rgb(palette.borderStrong),
},
};

export const buildAlibabaTweakccConfig = (): TweakccConfig => ({
ccVersion: '',
ccInstallationPath: null,
lastModified: new Date().toISOString(),
changesApplied: false,
hidePiebaldAnnouncement: true,
settings: {
themes: [theme, ...DEFAULT_THEMES.filter((t) => t.id !== theme.id)],
thinkingVerbs: {
format: '{}... ',
verbs: [
'Computing',
'Processing',
'Analyzing',
'Optimizing',
'Routing',
'Mapping',
'Synthesizing',
'Compiling',
'Refining',
'Validating',
'Aligning',
'Delivering',
],
},
thinkingStyle: {
updateInterval: 120,
phases: ['·', '•', '◦', '•'],
reverseMirror: false,
},
userMessageDisplay: {
format: formatUserMessage(getUserLabel()),
styling: ['bold'],
foregroundColor: 'default',
backgroundColor: 'default',
borderStyle: 'topBottomBold',
borderColor: rgb(palette.purple),
paddingX: 1,
paddingY: 0,
fitBoxToContent: true,
},
inputBox: {
removeBorder: true,
},
misc: buildBrandMiscConfig(),
claudeMdAltNames: null,
},
});
7 changes: 7 additions & 0 deletions src/brands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { buildOllamaTweakccConfig } from './ollama.js';
import { buildGatewayzTweakccConfig } from './gatewayz.js';
import { buildVercelTweakccConfig } from './vercel.js';
import { buildNanoGPTTweakccConfig } from './nanogpt.js';
import { buildAlibabaTweakccConfig } from './alibaba.js';

export interface BrandPreset {
key: string;
Expand Down Expand Up @@ -78,6 +79,12 @@ const BRAND_PRESETS: Record<string, BrandPreset> = {
description: 'Reflective silver/chrome theme for pure Claude Code experience.',
buildTweakccConfig: buildMirrorTweakccConfig,
},
alibaba: {
key: 'alibaba',
label: 'Alibaba Aurora',
description: 'Purple, dark blue, and aqua palette for Alibaba Cloud Coding Plan.',
buildTweakccConfig: buildAlibabaTweakccConfig,
},
};

export const listBrandPresets = (): BrandPreset[] => Object.values(BRAND_PRESETS);
Expand Down
7 changes: 5 additions & 2 deletions src/cli/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ FOCUS
QUICK START
npx cc-mirror quick --provider mirror # Fastest path to Claude
npx cc-mirror quick --provider zai # Z.ai with GLM models
npx cc-mirror quick --provider alibaba # Alibaba Cloud Coding Plan
npx cc-mirror quick --provider ollama # Ollama local + cloud models
npx cc-mirror # Interactive TUI

Expand All @@ -34,10 +35,10 @@ COMMANDS

OPTIONS (create/quick)
--name <name> Variant name (becomes CLI command)
--provider <name> Provider: kimi | minimax | zai | openrouter | vercel | ollama | nanogpt | ccrouter | mirror | gatewayz
--provider <name> Provider: kimi | minimax | zai | alibaba | openrouter | vercel | ollama | nanogpt | ccrouter | mirror | gatewayz
--api-key <key> Provider API key
--auth-token <token> Alias for --api-key (auth-token providers)
--brand <preset> Theme: auto | none | kimi | minimax | zai | openrouter | vercel | ollama | nanogpt | ccrouter | mirror | gatewayz
--brand <preset> Theme: auto | none | kimi | minimax | zai | alibaba | openrouter | vercel | ollama | nanogpt | ccrouter | mirror | gatewayz
--tui / --no-tui Force TUI on/off

OPTIONS (advanced)
Expand All @@ -62,6 +63,7 @@ PROVIDERS
kimi kimi-for-coding via Kimi Code
minimax MiniMax via MiniMax Cloud
zai GLM-5/4.7/4.5-Air via Z.ai Coding Plan
alibaba Alibaba Cloud Coding Plan (DashScope)
openrouter 100+ models via OpenRouter
vercel Vercel AI Gateway
ollama Local + cloud models via Ollama
Expand All @@ -72,6 +74,7 @@ PROVIDERS
EXAMPLES
npx cc-mirror quick --provider mirror --name mclaude
npx cc-mirror quick --provider zai --api-key "$Z_AI_API_KEY"
npx cc-mirror quick --provider alibaba --api-key "$ALIBABA_API_KEY"
npx cc-mirror apply mclaude
npx cc-mirror update mclaude --claude-version latest
npx cc-mirror doctor
Expand Down
30 changes: 30 additions & 0 deletions src/core/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ const C = {
olSecondary: '\x1b[38;5;223m', // Light tan
olAccent: '\x1b[38;5;137m', // Deep brown
olDim: '\x1b[38;5;101m', // Muted brown
// Alibaba: Purple/Dark Blue/Aqua gradient (brand: #a371f7, #1f6feb, #2dd4bf)
alPrimary: '\x1b[38;5;141m', // Purple
alSecondary: '\x1b[38;5;33m', // Dark blue
alAccent: '\x1b[38;5;50m', // Aqua
alDim: '\x1b[38;5;97m', // Muted purple
// Default: White/Gray
defPrimary: '\x1b[38;5;255m', // White
defDim: '\x1b[38;5;245m', // Gray
Expand Down Expand Up @@ -228,6 +233,24 @@ const SPLASH_ART: SplashArt = {
`${C.olSecondary} Run Models Locally${C.reset}`,
'',
],
// Alibaba: Cloud + block letters
alibaba: [
'',
`${C.alDim} ◈━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━◈${C.reset}`,
`${C.alSecondary} A L I B A B A C L O U D${C.reset}`,
`${C.alDim} ◈━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━◈${C.reset}`,
'',
`${C.alPrimary} ██████╗ ██████╗ █████╗ ██╗ ██╗███████╗██████╗ ${C.alAccent}███████╗███████╗${C.reset}`,
`${C.alPrimary} ██╔════╝ ██╔═══██╗██╔══██╗╚██╗██╔╝██╔════╝██╔══██╗${C.alAccent}╚══███╔╝╚══███╔╝${C.reset}`,
`${C.alSecondary} ██║ ███╗██║ ██║███████║ ╚███╔╝ █████╗ ██████╔╝${C.alAccent} ███╔╝ ███╔╝${C.reset}`,
`${C.alSecondary} ██║ ██║██║ ██║██╔══██║ ██╔██╗ ██╔══╝ ██╔══██╗${C.alAccent} ███╔╝ ███╔╝${C.reset}`,
`${C.alAccent} ╚██████╔╝╚██████╔╝██║ ██║██╔╝ ██╗███████╗██║ ██║${C.alAccent}███████╗███████╗${C.reset}`,
`${C.alAccent} ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝${C.alAccent}╚══════╝╚══════╝${C.reset}`,
'',
`${C.alDim} ━━━━━━━━━━━━━━━━━━━━━━━${C.alPrimary}◆${C.alDim}━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`,
`${C.alSecondary} Coding Plan ${C.alDim}━${C.alSecondary} DashScope${C.reset}`,
'',
],
default: [
'',
`${C.defPrimary} ██████╗ ██████╗ ${C.defDim}━━ M I R R O R${C.reset}`,
Expand All @@ -244,6 +267,7 @@ const KNOWN_SPLASH_STYLES = [
'zai',
'minimax',
'kimi',
'alibaba',
'openrouter',
'ccrouter',
'mirror',
Expand Down Expand Up @@ -489,6 +513,12 @@ export const writeWrapper = (
'CCMOL',
' __cc_show_label="0"',
' ;;',
' alibaba)',
" cat <<'CCMAL'",
...SPLASH_ART.alibaba,
'CCMAL',
' __cc_show_label="0"',
' ;;',
' *)',
" cat <<'CCMGEN'",
...SPLASH_ART.default,
Expand Down
17 changes: 17 additions & 0 deletions src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const PROVIDER_DISPLAY_ORDER = [
'kimi',
'minimax',
'zai',
'alibaba',
'openrouter',
'vercel',
'ollama',
Expand Down Expand Up @@ -89,6 +90,22 @@ const PROVIDERS: Record<string, ProviderTemplate> = {
},
apiKeyLabel: 'Zai API key',
},
alibaba: {
key: 'alibaba',
label: 'Alibaba Cloud',
description: 'Alibaba Cloud Coding Plan (DashScope Anthropic-compatible)',
baseUrl: 'https://coding-intl.dashscope.aliyuncs.com/apps/anthropic',
env: {
API_TIMEOUT_MS: DEFAULT_TIMEOUT_MS,
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'qwen3.5-plus',
ANTHROPIC_DEFAULT_SONNET_MODEL: 'kimi-k2.5',
ANTHROPIC_DEFAULT_OPUS_MODEL: 'glm-5',
CC_MIRROR_SPLASH: 1,
CC_MIRROR_PROVIDER_LABEL: 'Alibaba Cloud',
CC_MIRROR_SPLASH_STYLE: 'alibaba',
},
apiKeyLabel: 'Alibaba Cloud API key',
},
minimax: {
key: 'minimax',
label: 'MiniMax Cloud',
Expand Down