Skip to content

Commit 075c424

Browse files
committed
chore: release v1.2.10
1 parent 3cd13f6 commit 075c424

8 files changed

Lines changed: 454 additions & 382 deletions

File tree

.github/workflows/release.yml

Lines changed: 75 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,75 @@
1-
name: Release
2-
3-
on:
4-
push:
5-
tags:
6-
- 'v*'
7-
8-
jobs:
9-
build:
10-
strategy:
11-
matrix:
12-
include:
13-
- os: ubuntu-latest
14-
target: bun-linux-x64
15-
artifact: cc-linux-x64
16-
- os: macos-latest
17-
target: bun-darwin-arm64
18-
artifact: cc-darwin-arm64
19-
- os: windows-latest
20-
target: bun-windows-x64
21-
artifact: cc-windows-x64.exe
22-
23-
runs-on: ${{ matrix.os }}
24-
25-
steps:
26-
- uses: actions/checkout@v4
27-
28-
- uses: oven-sh/setup-bun@v2
29-
30-
- name: Install dependencies
31-
run: bun install
32-
33-
- name: Inject version into src/version.ts
34-
shell: bash
35-
env:
36-
VER: ${{ github.ref_name }}
37-
run: |
38-
node -e "const fs=require('node:fs'); const path='src/version.ts'; const ver=(process.env.VER || '').replace(/^v/, ''); if(!ver) throw new Error('VER missing'); const text=fs.readFileSync(path,'utf8'); const pattern=/export const VERSION = '[^']+'/u; if(!pattern.test(text)) throw new Error('VERSION anchor not found in src/version.ts'); const next=text.replace(pattern, \"export const VERSION = '\" + ver + \"'\"); fs.writeFileSync(path,next,'utf8')"
39-
40-
- name: Stub react-devtools-core (not available in standalone binary)
41-
shell: bash
42-
run: |
43-
mkdir -p node_modules/react-devtools-core
44-
echo 'module.exports = {}' > node_modules/react-devtools-core/index.js
45-
echo '{"name":"react-devtools-core","version":"0.0.0","main":"index.js"}' > node_modules/react-devtools-core/package.json
46-
47-
- name: Build standalone binary
48-
run: bun build src/app.tsx --compile --target=${{ matrix.target }} --outfile ${{ matrix.artifact }}
49-
50-
- name: Upload artifact
51-
uses: actions/upload-artifact@v4
52-
with:
53-
name: ${{ matrix.artifact }}
54-
path: ${{ matrix.artifact }}
55-
56-
release:
57-
needs: build
58-
runs-on: ubuntu-latest
59-
permissions:
60-
contents: write
61-
62-
steps:
63-
- name: Download all build artifacts
64-
uses: actions/download-artifact@v4
65-
with:
66-
merge-multiple: true
67-
68-
- name: Publish GitHub Release
69-
uses: softprops/action-gh-release@v2
70-
with:
71-
generate_release_notes: true
72-
files: |
73-
cc-linux-x64
74-
cc-darwin-arm64
75-
cc-windows-x64.exe
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
build:
10+
strategy:
11+
matrix:
12+
include:
13+
- os: ubuntu-latest
14+
target: bun-linux-x64
15+
artifact: cc-linux-x64
16+
- os: macos-latest
17+
target: bun-darwin-arm64
18+
artifact: cc-darwin-arm64
19+
- os: windows-latest
20+
target: bun-windows-x64
21+
artifact: cc-windows-x64.exe
22+
23+
runs-on: ${{ matrix.os }}
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- uses: oven-sh/setup-bun@v2
29+
30+
- name: Install dependencies
31+
run: bun install
32+
33+
- name: Inject version into src/version.ts
34+
shell: bash
35+
env:
36+
VER: ${{ github.ref_name }}
37+
run: |
38+
node -e "const fs=require('node:fs'); const path='src/version.ts'; const ver=(process.env.VER || '').replace(/^v/, ''); if(!ver) throw new Error('VER missing'); const text=fs.readFileSync(path,'utf8'); const pattern=/export const VERSION = '[^']+'/u; if(!pattern.test(text)) throw new Error('VERSION anchor not found in src/version.ts'); const next=text.replace(pattern, \"export const VERSION = '\" + ver + \"'\"); fs.writeFileSync(path,next,'utf8')"
39+
40+
- name: Stub react-devtools-core (not available in standalone binary)
41+
shell: bash
42+
run: |
43+
mkdir -p node_modules/react-devtools-core
44+
echo 'module.exports = {}' > node_modules/react-devtools-core/index.js
45+
echo '{"name":"react-devtools-core","version":"0.0.0","main":"index.js"}' > node_modules/react-devtools-core/package.json
46+
47+
- name: Build standalone binary
48+
run: bun build src/app.tsx --compile --target=${{ matrix.target }} --outfile ${{ matrix.artifact }}
49+
50+
- name: Upload artifact
51+
uses: actions/upload-artifact@v4
52+
with:
53+
name: ${{ matrix.artifact }}
54+
path: ${{ matrix.artifact }}
55+
56+
release:
57+
needs: build
58+
runs-on: ubuntu-latest
59+
permissions:
60+
contents: write
61+
62+
steps:
63+
- name: Download all build artifacts
64+
uses: actions/download-artifact@v4
65+
with:
66+
merge-multiple: true
67+
68+
- name: Publish GitHub Release
69+
uses: softprops/action-gh-release@v2
70+
with:
71+
generate_release_notes: true
72+
files: |
73+
cc-linux-x64
74+
cc-darwin-arm64
75+
cc-windows-x64.exe

CLAUDE.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ src/ - 源码根目录
2020
version.ts - 版本常量 VERSION,CI 编译前自动注入 tag 版本号
2121
updater.ts - 更新模块:查 GitHub Releases API、归一化版本号、纠正升级后的缓存状态,并启动独立二进制自更新
2222
components/ - 通用组件
23-
Banner.tsx - figlet ANSI Shadow 大字 ASCII art,进入首屏时显示
23+
Banner.tsx - 首屏顶部品牌字标,按终端宽度在大字 / 小字 / 纯文本间切换,避免窄窗口 ASCII 断裂
2424
screens/ - 四个屏幕组件
2525
ProviderSelect.tsx - 入口屏:Banner + 检测到的所有安装实例列表
2626
ProviderList.tsx - 供应商列表:展示/激活/删除/跳转添加,ATO 模式默认走 18653,端口被占用时自动顺延空闲端口并回写存储
@@ -83,11 +83,10 @@ bin/
8383
- `tsx` — TypeScript 直接运行
8484

8585
## 变更日志
86+
- v1.2.10 交互修复:顶部 Banner 按终端宽度自动切到紧凑字标,避免窄窗口 ASCII 断裂;同步统一发布版本号来源
8687
- v1.2.6 发布修复:GitHub Actions 改为稳定注入 tag 版本,避免产物出现 当前版本: vundefined
8788
- v1.2.5 修复尝试:补上版本归一化与发布注入,但 Actions 中的 heredoc 脚本失败,未生成有效产物
8889
- v1.2.4 体验修复:首屏显示当前版本,加入一键自更新 u,并清理升级后仍提示更新的缓存误判
8990
- v1.2.3 ATO 修复:递归规范化 tool schema,补齐 object/properties,避免上游 400 invalid_function_parameters
9091
- v2.0.0 架构重构:多环境检测(Windows + WSL),工具配置适配器,直接编辑安装实例配置
9192
- v1.0.0 初始实现:四提供商选择、模型增删改激活、ASCII banner
92-
93-

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cc-switch-cli",
3-
"version": "1.2.9",
3+
"version": "1.2.10",
44
"description": "TUI for switching models in Claude Code, Codex, Gemini, and OpenClaw",
55
"type": "module",
66
"bin": {

src/components/Banner.tsx

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,108 @@
11
/**
2-
* [INPUT]: 依赖 react/ink 的渲染能力,依赖 figlet,依赖 assets/ansiShadowFont 的内嵌字体
2+
* [INPUT]: 依赖 react 的 useEffect/useState,依赖 ink 的 Box/Text/useStdout,依赖 figlet,依赖 assets/ansiShadowFont 的内嵌字体
33
* [OUTPUT]: 对外提供 Banner 组件
4-
* [POS]: 通用组件,被 ProviderSelect 顶部消费,品牌标识层
4+
* [POS]: 通用组件,被 ProviderSelect 顶部消费,按终端宽度切换品牌字标
55
* [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
66
*/
77

8-
import React from 'react'
9-
import { Box, Text } from 'ink'
8+
import React, { useEffect, useState } from 'react'
9+
import { Box, Text, useStdout } from 'ink'
1010
import figlet from 'figlet'
1111
import { ANSI_SHADOW_FONT } from '../assets/ansiShadowFont.js'
1212

13+
type BannerVariant = {
14+
lines: string[]
15+
colors: string[]
16+
minWidth: number
17+
bold?: boolean
18+
}
19+
1320
// 内嵌字体注册,消除对文件系统的依赖(bun 独立二进制中无 node_modules)
1421
figlet.parseFont('ANSI Shadow', ANSI_SHADOW_FONT as unknown as figlet.Fonts)
1522

16-
// 构建时同步生成 ASCII art,避免运行时延迟
17-
const ART = figlet.textSync('CC Switch', {
23+
// 预生成三档字标,避免运行时再去读字体文件或等待计算。
24+
const LARGE_ART = figlet.textSync('CC Switch', {
1825
font: 'ANSI Shadow',
1926
horizontalLayout: 'default',
2027
})
2128

22-
// 将 art 按行分割,逐行渲染以支持渐变色效果
23-
const LINES = ART.split('\n')
29+
const MEDIUM_ART = [
30+
' ___ ___ ___ _ _ _',
31+
' / __|/ __| / __|__ __ __(_)| |_ __ | |_',
32+
" | (__| (__ \\__ \\\\ V V /| || _|/ _|| ' \\",
33+
' \\___|\\___| |___/ \\_/\\_/ |_| \\__|\\__||_||_|',
34+
].join('\n')
35+
36+
const SMALL_ART = [
37+
' _ _ __ ',
38+
' / / (_ o _|_ _ |_ ',
39+
' \\_ \\_ __) \\/\\/ | |_ (_ | | ',
40+
].join('\n')
41+
42+
const INLINE_ART = 'CC Switch'
43+
const HORIZONTAL_PADDING = 4
44+
45+
function normalizeLines(art: string): string[] {
46+
const lines = art.split('\n').map(line => line.replace(/\s+$/u, ''))
47+
48+
while (lines.length > 0 && lines.at(-1) === '') {
49+
lines.pop()
50+
}
51+
52+
return lines
53+
}
54+
55+
function createVariant(art: string, colors: string[], bold = false): BannerVariant {
56+
const lines = normalizeLines(art)
57+
58+
return {
59+
lines,
60+
colors,
61+
bold,
62+
minWidth: lines.reduce((max, line) => Math.max(max, line.length), 0),
63+
}
64+
}
65+
66+
const VARIANTS: BannerVariant[] = [
67+
createVariant(LARGE_ART, ['white', 'white', 'cyan', 'cyan', 'blueBright', 'blue']),
68+
createVariant(MEDIUM_ART, ['white', 'cyan', 'cyan', 'blue']),
69+
createVariant(SMALL_ART, ['white', 'cyan', 'blue']),
70+
createVariant(INLINE_ART, ['cyan'], true),
71+
]
2472

25-
// 每行对应的颜色,从亮到暗,模拟截图中的立体光影
26-
const LINE_COLORS = ['white', 'white', 'cyan', 'cyan', 'blueBright', 'blue']
73+
function getAvailableWidth(stdout: NodeJS.WriteStream | undefined): number {
74+
const columns = stdout?.columns ?? 80
75+
return Math.max(columns - HORIZONTAL_PADDING, 0)
76+
}
77+
78+
function pickVariant(availableWidth: number): BannerVariant {
79+
return VARIANTS.find(variant => availableWidth >= variant.minWidth) ?? VARIANTS.at(-1)!
80+
}
2781

2882
export function Banner() {
83+
const { stdout } = useStdout()
84+
const [availableWidth, setAvailableWidth] = useState(() => getAvailableWidth(stdout))
85+
86+
useEffect(() => {
87+
const syncWidth = () => {
88+
const nextWidth = getAvailableWidth(stdout)
89+
setAvailableWidth(currentWidth => (currentWidth === nextWidth ? currentWidth : nextWidth))
90+
}
91+
92+
syncWidth()
93+
stdout?.on('resize', syncWidth)
94+
95+
return () => {
96+
stdout?.removeListener('resize', syncWidth)
97+
}
98+
}, [stdout])
99+
100+
const variant = pickVariant(availableWidth)
101+
29102
return (
30103
<Box flexDirection="column" marginBottom={1}>
31-
{LINES.map((line, i) => (
32-
<Text key={i} color={(LINE_COLORS[i] ?? 'gray') as any}>
104+
{variant.lines.map((line, i) => (
105+
<Text key={i} color={(variant.colors[i] ?? 'gray') as any} bold={variant.bold}>
33106
{line}
34107
</Text>
35108
))}

src/components/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
> L2 | 父级: ../CLAUDE.md
33
44
## 成员清单
5-
Banner.tsx: figlet ANSI Shadow 字体渲染 "CC Switch",6行渐变色(white→cyan→blue),字体数据来自 assets/ansiShadowFont.ts 内嵌常量,无文件系统依赖
5+
Banner.tsx: 顶部品牌字标组件,按终端宽度在 ANSI Shadow / 紧凑 ASCII / 纯文本之间切换,监听 resize 避免窄窗口乱码,字体数据来自 assets/ansiShadowFont.ts 内嵌常量
66

77
[PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md

0 commit comments

Comments
 (0)