@cc-x/cc-x 0.4.11 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,8 +37,8 @@ export const messages = {
37
37
  // —— 菜单通用 ——
38
38
  'menu.prompt': { zh: '输入序号 (q 取消): ', en: 'Enter number (q to cancel): ' },
39
39
  'menu.mainTitle': {
40
- zh: 'CC-X v{0} · Claude Code API 切换器 默认:{1}',
41
- en: 'CC-X v{0} · Claude Code API switcher Default: {1}',
40
+ zh: 'CC-X v{0} 默认:{1}',
41
+ en: 'CC-X v{0} Default: {1}',
42
42
  },
43
43
  'menu.mainHint': {
44
44
  zh: '↑↓ 选择 · Enter 进入 · e 编辑 · s 启动 · d 设默认 · Shift+↑↓ 排序 · q 退出',
package/dist/ui/menus.js CHANGED
@@ -7,10 +7,9 @@
7
7
  */
8
8
  import { launchSession } from '../actions.js';
9
9
  import { checkProfile } from '../check.js';
10
- import { getProviderEnvMap, getProviderState, isOfficial, reconcileCurrent, saveStore } from '../config/store.js';
10
+ import { getProviderState, isOfficial, reconcileCurrent, saveStore } from '../config/store.js';
11
11
  import { persistDefaultEnv, setDefault } from '../env/default.js';
12
12
  import { getLang, providerDisplayName, setLang, T } from '../i18n/index.js';
13
- import { currentTerminalLine, hostOf } from '../runtime-info.js';
14
13
  import { banner as updateBanner, maybeRefresh, MODE_NOTIFY, upgradeCommand } from '../update/update.js';
15
14
  import { paint } from '../utils/ansi.js';
16
15
  import { displayWidth, padDisplay } from '../utils/display.js';
@@ -26,7 +25,7 @@ export async function openMenu(paths, store, scope, version, catalog) {
26
25
  for (;;) {
27
26
  const n = store.providers.length;
28
27
  // 更新检查(仅 notify 模式):首轮触发一次后台刷新;横幅永远读缓存(瞬时、不阻塞)。
29
- const notices = [currentTerminalLine(store)];
28
+ const notices = [];
30
29
  if (needsFirstRunHint(store))
31
30
  notices.push(T('menu.firstRunHint'));
32
31
  if (warnFlash)
@@ -63,7 +62,7 @@ export async function openMenu(paths, store, scope, version, catalog) {
63
62
  notice: notices.join('\n'),
64
63
  ...(flash ? { status: flash } : {}),
65
64
  items: buildItems(),
66
- colors: { [n + 1]: 'yellow' },
65
+ colors: { [n + 1]: 'yellow', [n + 2]: 'dim', [n + 3]: 'dim' },
67
66
  start: sel,
68
67
  movableCount: n,
69
68
  onMove,
@@ -237,44 +236,48 @@ function applyDefault(paths, store, p, scope) {
237
236
  return defaultResultMessage(defaultWarning(p), name, setDefault(paths, store, p, scope));
238
237
  }
239
238
  const ROW_NAME_W = 13; // 名字列宽(显示宽度,CJK 计 2);状态/备注列宽按内容动态算
240
- // profileRows 把所有配置格式化成定宽分栏的菜单行:名字为主信息(默认项加粗),
241
- // 状态/备注/host 一律 dim 退为次要信息,让备注、host 各自对齐成竖列。
242
- // 状态、备注列宽按当前配置实际内容动态取最大值——自动兜住任何语言/文案。
239
+ // profileRows 把所有配置格式化成三列菜单行:名字(主信息,默认项加粗、缺密钥变灰)
240
+ // + 备注(紧跟名字、dim,同名配置靠它区分)+ 状态(effort/缺密钥告警,dim,锚成最右一列)。
241
+ // 备注列宽按当前配置实际内容动态取最大值;状态列在最右,无需补宽。
243
242
  // TUI 主菜单与 xx --list 共用此函数,保证两处呈现一致。与 Go 版 menu.go ProfileRows 对齐。
244
243
  export function profileRows(providers, current) {
245
- let stateW = 0;
246
244
  let noteW = 0;
247
245
  for (const p of providers) {
248
- stateW = Math.max(stateW, displayWidth(stateLabel(p)));
249
246
  noteW = Math.max(noteW, displayWidth(p.note ?? ''));
250
247
  }
251
- stateW += 2; // 状态列尾留出与备注列的间距(最宽行否则会与备注贴死)
252
248
  if (noteW > 0)
253
- noteW += 2; // 有备注时留出与 host 的列间距
254
- return providers.map((p) => profileRow(p, p.name === current, stateW, noteW));
249
+ noteW += 2; // 备注列尾留出与状态列的间距
250
+ return providers.map((p) => profileRow(p, p.name === current, noteW));
255
251
  }
256
- // profileRow 组成一行:定宽分栏 + 次要信息 dim + 默认项加粗。
257
- // 加粗用 1m/22m(reset 不动颜色),不会破坏 selectMenu 选中行的外层绿色。
258
- function profileRow(p, isDefault, stateW, noteW) {
252
+ // rowStateText 行内状态段:只保留 effort 与「缺密钥」告警。
253
+ // 「登录态/密钥已设/密钥·API_KEY」等可用态不再用文字表达——能不能用由配置名的亮/灰区分。
254
+ function rowStateText(p) {
255
+ const st = getProviderState(p);
256
+ const parts = [];
257
+ if (st.effort)
258
+ parts.push(`effort=${st.effort}`);
259
+ if (st.key === 'noKey')
260
+ parts.push(T('state.noKey'));
261
+ return parts.join(' · ');
262
+ }
263
+ // profileRow 组成一行:名字 + 备注 + 状态三列,次要信息 dim、默认项加粗、缺密钥变灰。
264
+ // 默认项只靠名字加粗标识(不再额外画 ● 符号,与光标 ▶ 重叠冗余);选中行由 selectMenu 整行绿。
265
+ // 亮/灰用加粗(1m)与 dim(2m),reset 都用 22m 不动颜色,不会破坏选中行的外层绿色。
266
+ function profileRow(p, isDefault, noteW) {
267
+ const noKey = getProviderState(p).key === 'noKey';
259
268
  let name = padDisplay(providerDisplayName(p), ROW_NAME_W);
260
- let marker = ' ';
261
- if (isDefault) {
262
- marker = paint('● ', 'bold');
263
- name = paint(name, 'bold');
264
- }
265
- const state = paint(` · ${padDisplay(stateLabel(p), stateW)}`, 'dim');
266
- // 空备注=定宽空白,撑出 host 前的列间距
269
+ if (noKey)
270
+ name = paint(name, 'dim'); // 灰掉=当前不可用(缺密钥)
271
+ else if (isDefault)
272
+ name = paint(name, 'bold'); // 加粗=默认配置
273
+ // 空备注=定宽空白,撑出状态列前的间距
267
274
  const note = (p.note ?? '').trim()
268
275
  ? paint(padDisplay(p.note ?? '', noteW), 'dim')
269
276
  : padDisplay('', noteW);
270
- return `${marker}${name}${state}${note}${hostCol(p)}`;
271
- }
272
- // hostCol 返回行尾 dim host(无 base 返回空)。超宽时由 selectMenu ANSI-aware 截断裁掉。
273
- function hostCol(p) {
274
- const base = (getProviderEnvMap(p).ANTHROPIC_BASE_URL ?? '').trim();
275
- if (!base)
276
- return '';
277
- return paint(hostOf(base), 'dim');
277
+ // 状态在最右一列,可用且无 effort 时整列省略
278
+ const seg = rowStateText(p);
279
+ const state = seg ? paint(` · ${seg}`, 'dim') : '';
280
+ return `${name}${note}${state}`;
278
281
  }
279
282
  function needsFirstRunHint(store) {
280
283
  let hasThirdParty = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-x/cc-x",
3
- "version": "0.4.11",
3
+ "version": "0.4.12",
4
4
  "description": "Claude Code API 切换器(命令 xx):在官方账号与第三方 Anthropic 兼容 API 间切换,纯环境变量、不碰 Claude Code 配置文件。",
5
5
  "keywords": [
6
6
  "claude",