@wayfarer35/ccs 0.2.2
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.
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +490 -0
- package/dist/completion.d.ts +27 -0
- package/dist/completion.js +116 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.js +73 -0
- package/dist/form.d.ts +66 -0
- package/dist/form.js +269 -0
- package/dist/formUi.d.ts +30 -0
- package/dist/formUi.js +608 -0
- package/dist/i18n.d.ts +24 -0
- package/dist/i18n.js +195 -0
- package/dist/inkPrompts.d.ts +25 -0
- package/dist/inkPrompts.js +176 -0
- package/dist/launch.d.ts +27 -0
- package/dist/launch.js +108 -0
- package/dist/picker.d.ts +24 -0
- package/dist/picker.js +153 -0
- package/dist/presets.d.ts +13 -0
- package/dist/presets.js +29 -0
- package/dist/presets.json +314 -0
- package/dist/screen.d.ts +12 -0
- package/dist/screen.js +14 -0
- package/dist/tui.d.ts +24 -0
- package/dist/tui.js +25 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.js +9 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +35 -0
- package/package.json +49 -0
package/dist/picker.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Box, render, Text, useInput, useStdout } from 'ink';
|
|
2
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { t } from './i18n.js';
|
|
4
|
+
import { Cancel } from './tui.js';
|
|
5
|
+
import { clearScreen } from './screen.js';
|
|
6
|
+
const h = React.createElement;
|
|
7
|
+
function PickerApp({ message, items, actions, initialIndex, maxItems, statusMessage, onDone, onCancel }) {
|
|
8
|
+
const [filter, setFilter] = useState('');
|
|
9
|
+
const [index, setIndex] = useState(initialIndex);
|
|
10
|
+
const { stdout } = useStdout();
|
|
11
|
+
const cols = stdout && stdout.columns ? stdout.columns : 60;
|
|
12
|
+
// items 区按 label+hint 大小写不敏感包含匹配;actions 区不过滤。
|
|
13
|
+
const filtered = useMemo(() => {
|
|
14
|
+
const q = filter.trim().toLowerCase();
|
|
15
|
+
if (!q)
|
|
16
|
+
return items;
|
|
17
|
+
return items.filter((it) => {
|
|
18
|
+
const hay = `${it.label} ${it.hint ?? ''}`.toLowerCase();
|
|
19
|
+
return hay.includes(q);
|
|
20
|
+
});
|
|
21
|
+
}, [items, filter]);
|
|
22
|
+
// 合并可见列表:过滤后的 items ++ 全部 actions(单一光标贯穿)。
|
|
23
|
+
const combined = useMemo(() => [...filtered, ...actions], [filtered, actions]);
|
|
24
|
+
// 光标闪烁
|
|
25
|
+
const [blinkOn, setBlinkOn] = useState(true);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const id = setInterval(() => setBlinkOn((b) => !b), 530);
|
|
28
|
+
return () => clearInterval(id);
|
|
29
|
+
}, []);
|
|
30
|
+
useInput((input, key) => {
|
|
31
|
+
if (key.escape) {
|
|
32
|
+
onCancel();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (key.return) {
|
|
36
|
+
const it = combined[Math.min(index, combined.length - 1)];
|
|
37
|
+
if (it)
|
|
38
|
+
onDone(it.value);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Tab:在 items 区与 actions 区之间跳转(区域捷径,免得供应商多时连续 ↓)。
|
|
42
|
+
// 区域由当前光标位置派生(index < filtered.length ⇒ items 区),无需单独状态。
|
|
43
|
+
if (key.tab) {
|
|
44
|
+
const cur = Math.min(index, combined.length - 1);
|
|
45
|
+
const inItems = cur < filtered.length;
|
|
46
|
+
if (inItems) {
|
|
47
|
+
if (actions.length)
|
|
48
|
+
setIndex(filtered.length);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
if (filtered.length)
|
|
52
|
+
setIndex(0);
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (key.upArrow) {
|
|
57
|
+
setIndex((i) => Math.max(0, i - 1));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (key.downArrow) {
|
|
61
|
+
setIndex((i) => Math.min(combined.length - 1, i + 1));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// ink 把 \x7f(Linux/WSL 的 Backspace)映射成 key.delete;与 Delete 一并按退格处理。
|
|
65
|
+
// 打字/退格只影响 filter(仅过滤 items 区);光标重置到首位(标准 fuzzy 行为)。
|
|
66
|
+
if (key.backspace || key.delete) {
|
|
67
|
+
setFilter((f) => f.slice(0, -1));
|
|
68
|
+
setIndex(0);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (input && !key.ctrl && !key.meta) {
|
|
72
|
+
let s = '';
|
|
73
|
+
for (const ch of input) {
|
|
74
|
+
if (ch.charCodeAt(0) >= 32)
|
|
75
|
+
s += ch;
|
|
76
|
+
}
|
|
77
|
+
if (s) {
|
|
78
|
+
setFilter((f) => f + s);
|
|
79
|
+
setIndex(0);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const safeIndex = combined.length ? Math.min(index, combined.length - 1) : 0;
|
|
84
|
+
// items 区滚动窗口:仅在 items 区滚动,actions 区始终全部显示。
|
|
85
|
+
const cursorInItems = safeIndex < filtered.length;
|
|
86
|
+
let startIdx = 0;
|
|
87
|
+
if (filtered.length > maxItems) {
|
|
88
|
+
if (cursorInItems) {
|
|
89
|
+
startIdx = Math.max(0, Math.min(safeIndex - Math.floor(maxItems / 2), filtered.length - maxItems));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// 光标在 actions 区 → 显示 items 区最后一页,紧接 actions。
|
|
93
|
+
startIdx = Math.max(0, filtered.length - maxItems);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const visibleFiltered = filtered.slice(startIdx, startIdx + maxItems);
|
|
97
|
+
const renderRow = (it, abs, sel) => {
|
|
98
|
+
const style = sel ? { backgroundColor: 'cyan', color: 'black' } : {};
|
|
99
|
+
return h(Box, { key: abs, flexDirection: 'row' }, h(Text, style, `${sel ? '▸ ' : ' '}${it.label}`), it.hint
|
|
100
|
+
? h(Text, sel ? { backgroundColor: 'cyan', color: 'black' } : { dimColor: true }, ` ${it.hint}`)
|
|
101
|
+
: null);
|
|
102
|
+
};
|
|
103
|
+
const hasItems = items.length > 0;
|
|
104
|
+
return h(Box, { flexDirection: 'column' }, statusMessage
|
|
105
|
+
? h(Text, { color: 'green' }, `✓ ${statusMessage}`)
|
|
106
|
+
: null, h(Text, { color: 'cyan', bold: true }, message), h(Text, { dimColor: true }, '─'.repeat(Math.min(cols, 64))),
|
|
107
|
+
// 过滤输入框:仅当存在可过滤的 items 时显示。
|
|
108
|
+
hasItems
|
|
109
|
+
? h(Box, { flexDirection: 'row' }, h(Text, { color: 'cyan' }, '▸ '), filter
|
|
110
|
+
? h(Text, { color: 'cyan' }, filter)
|
|
111
|
+
: h(Text, { dimColor: true }, t('picker.placeholder')), h(Text, { color: 'cyan' }, blinkOn ? '▏' : ' '))
|
|
112
|
+
: null,
|
|
113
|
+
// items 区(可过滤、可滚动)
|
|
114
|
+
hasItems
|
|
115
|
+
? h(Box, { flexDirection: 'column' }, h(Text, { dimColor: true }, t('picker.providers', { count: filtered.length })), visibleFiltered.length
|
|
116
|
+
? visibleFiltered.map((it, i) => renderRow(it, startIdx + i, startIdx + i === safeIndex))
|
|
117
|
+
: h(Text, { dimColor: true }, ' ' + t('picker.noMatch')), filtered.length > maxItems
|
|
118
|
+
? h(Text, { dimColor: true }, ` (${startIdx + 1}-${startIdx + visibleFiltered.length}/${filtered.length})`)
|
|
119
|
+
: null)
|
|
120
|
+
: null,
|
|
121
|
+
// actions 区(固定、不过滤)
|
|
122
|
+
actions.length
|
|
123
|
+
? h(Box, { flexDirection: 'column' }, h(Text, { dimColor: true }, t('picker.actions')), ...actions.map((it, i) => renderRow(it, filtered.length + i, filtered.length + i === safeIndex)))
|
|
124
|
+
: null, h(Text, { dimColor: true }, t('picker.help')));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 搜索选择器(ink):items 区可过滤可滚动,actions 区固定不过滤。
|
|
128
|
+
* ↑↓ 选择、Enter 确认、Esc 取消(抛 Cancel)。
|
|
129
|
+
*/
|
|
130
|
+
export async function runPicker(opts) {
|
|
131
|
+
const { message, items, actions = [], initialValue, maxItems = 5, statusMessage } = opts;
|
|
132
|
+
const arr = [...items];
|
|
133
|
+
const act = [...actions];
|
|
134
|
+
const combined = [...arr, ...act];
|
|
135
|
+
let initialIndex = 0;
|
|
136
|
+
if (initialValue !== undefined) {
|
|
137
|
+
const i = combined.findIndex((it) => it.value === initialValue);
|
|
138
|
+
if (i >= 0)
|
|
139
|
+
initialIndex = i;
|
|
140
|
+
}
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
let inst;
|
|
143
|
+
const onDone = (v) => { inst.unmount(); resolve(v); };
|
|
144
|
+
const onCancel = () => { inst.unmount(); reject(new Cancel()); };
|
|
145
|
+
// 泛型函数组件在 createElement 处无法推断 T,显式具化后再渲染。
|
|
146
|
+
const App = PickerApp;
|
|
147
|
+
const props = { message, items: arr, actions: act, initialIndex, maxItems, onDone, onCancel };
|
|
148
|
+
if (statusMessage !== undefined)
|
|
149
|
+
props.statusMessage = statusMessage;
|
|
150
|
+
clearScreen();
|
|
151
|
+
inst = render(h(App, props));
|
|
152
|
+
});
|
|
153
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Preset } from './types.js';
|
|
2
|
+
export declare const CUSTOM_KEY = "__custom__";
|
|
3
|
+
export declare function loadBuiltinPresets(): Record<string, Preset>;
|
|
4
|
+
export declare function loadUserPresets(): Record<string, Preset>;
|
|
5
|
+
/**
|
|
6
|
+
* 合并内置预设与用户预设(~/.ccs/presets.json),用户可覆盖同名预设或新增。
|
|
7
|
+
* 返回 { key: preset },附带 CUSTOM 选项由调用方处理。
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPresets(): Record<string, Preset>;
|
|
10
|
+
export declare function getPreset(key: string): Preset | null;
|
|
11
|
+
export declare function presetList(): Array<{
|
|
12
|
+
key: string;
|
|
13
|
+
} & Preset>;
|
package/dist/presets.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readJSON } from './config.js';
|
|
2
|
+
import builtinPresets from './presets.json' with { type: 'json' };
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
const USER_PRESETS_FILE = join(homedir(), '.ccs', 'presets.json');
|
|
6
|
+
export const CUSTOM_KEY = '__custom__';
|
|
7
|
+
export function loadBuiltinPresets() {
|
|
8
|
+
return builtinPresets;
|
|
9
|
+
}
|
|
10
|
+
export function loadUserPresets() {
|
|
11
|
+
return readJSON(USER_PRESETS_FILE, {}) || {};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 合并内置预设与用户预设(~/.ccs/presets.json),用户可覆盖同名预设或新增。
|
|
15
|
+
* 返回 { key: preset },附带 CUSTOM 选项由调用方处理。
|
|
16
|
+
*/
|
|
17
|
+
export function getPresets() {
|
|
18
|
+
const user = loadUserPresets();
|
|
19
|
+
return { ...builtinPresets, ...user };
|
|
20
|
+
}
|
|
21
|
+
export function getPreset(key) {
|
|
22
|
+
if (key === CUSTOM_KEY || !key)
|
|
23
|
+
return null;
|
|
24
|
+
return getPresets()[key] || null;
|
|
25
|
+
}
|
|
26
|
+
export function presetList() {
|
|
27
|
+
const all = getPresets();
|
|
28
|
+
return Object.entries(all).map(([key, p]) => ({ key, ...p }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ark-coding-plan": {
|
|
3
|
+
"label": "Ark 火山引擎 Coding Plan",
|
|
4
|
+
"baseUrl": "https://ark.cn-beijing.volces.com/api/coding",
|
|
5
|
+
"model": {
|
|
6
|
+
"support": [
|
|
7
|
+
"ark-code-latest",
|
|
8
|
+
"doubao-seed-2.0-code",
|
|
9
|
+
"doubao-seed-2.0-pro",
|
|
10
|
+
"doubao-seed-2.0-lite",
|
|
11
|
+
"doubao-seed-code",
|
|
12
|
+
"minimax-m2.7",
|
|
13
|
+
"minimax-m3",
|
|
14
|
+
"glm-5.2",
|
|
15
|
+
"deepseek-v4-flash",
|
|
16
|
+
"deepseek-v4-pro",
|
|
17
|
+
"kimi-k2.6",
|
|
18
|
+
"kimi-k2.7"
|
|
19
|
+
],
|
|
20
|
+
"default": "ark-code-latest",
|
|
21
|
+
"tier": "opus",
|
|
22
|
+
"tiers": {
|
|
23
|
+
"haiku": "minimax-m3",
|
|
24
|
+
"sonnet": "deepseek-v4-pro[1m]",
|
|
25
|
+
"opus": "glm-5.2[1m]",
|
|
26
|
+
"fable": ""
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"options": {
|
|
30
|
+
"attributionHeader": false,
|
|
31
|
+
"disableNonEssentialTraffic": true,
|
|
32
|
+
"autoCompactWindow": 1000000
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"ark-agent-plan": {
|
|
36
|
+
"label": "Ark 火山引擎 Agent Plan",
|
|
37
|
+
"baseUrl": "https://ark.cn-beijing.volces.com/api/plan",
|
|
38
|
+
"model": {
|
|
39
|
+
"support": [
|
|
40
|
+
"ark-code-latest",
|
|
41
|
+
"doubao-seed-2.0-code",
|
|
42
|
+
"doubao-seed-2.0-pro",
|
|
43
|
+
"doubao-seed-2.0-lite",
|
|
44
|
+
"doubao-seed-2.0-mini",
|
|
45
|
+
"doubao-seed-code",
|
|
46
|
+
"doubao-seed-2.0-pro",
|
|
47
|
+
"minimax-m2.7",
|
|
48
|
+
"minimax-m3",
|
|
49
|
+
"glm-5.2",
|
|
50
|
+
"deepseek-v4-flash",
|
|
51
|
+
"deepseek-v4-pro",
|
|
52
|
+
"kimi-k2.6",
|
|
53
|
+
"kimi-k2.7"
|
|
54
|
+
],
|
|
55
|
+
"default": "ark-code-latest",
|
|
56
|
+
"tier": "opus",
|
|
57
|
+
"tiers": {
|
|
58
|
+
"haiku": "minimax-m3",
|
|
59
|
+
"sonnet": "deepseek-v4-pro[1m]",
|
|
60
|
+
"opus": "glm-5.2[1m]",
|
|
61
|
+
"fable": ""
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"options": {
|
|
65
|
+
"attributionHeader": false,
|
|
66
|
+
"disableNonEssentialTraffic": true,
|
|
67
|
+
"autoCompactWindow": 1000000
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"bigmodel-coding-plan": {
|
|
71
|
+
"label": "Bigmodel 智谱 Coding Plan",
|
|
72
|
+
"baseUrl": "https://open.bigmodel.cn/api/anthropic",
|
|
73
|
+
"model": {
|
|
74
|
+
"default": "glm-5.2[1m]",
|
|
75
|
+
"tier": "opus",
|
|
76
|
+
"tiers": {
|
|
77
|
+
"haiku": "glm-4.7",
|
|
78
|
+
"sonnet": "glm-5.2[1m]",
|
|
79
|
+
"opus": "glm-5.2[1m]",
|
|
80
|
+
"fable": ""
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"options": {
|
|
84
|
+
"attributionHeader": false,
|
|
85
|
+
"disableNonEssentialTraffic": true,
|
|
86
|
+
"autoCompactWindow": 1000000
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"bailian-coding-plan": {
|
|
90
|
+
"label": "Bailian 阿里百炼 Coding Plan",
|
|
91
|
+
"baseUrl": "https://coding.dashscope.aliyuncs.com/apps/anthropic",
|
|
92
|
+
"model": {
|
|
93
|
+
"support": [
|
|
94
|
+
"qwen3.7-plus",
|
|
95
|
+
"qwen3.6-plus",
|
|
96
|
+
"kimi-k2.5",
|
|
97
|
+
"glm-5",
|
|
98
|
+
"MiniMax-M2.5",
|
|
99
|
+
"qwen3.5-plus",
|
|
100
|
+
"qwen3-max-2026-01-23",
|
|
101
|
+
"qwen3-coder-next",
|
|
102
|
+
"qwen3-coder-plus",
|
|
103
|
+
"glm-4.7"
|
|
104
|
+
],
|
|
105
|
+
"default": "qwen3.6-plus",
|
|
106
|
+
"tier": "opus",
|
|
107
|
+
"tiers": {
|
|
108
|
+
"haiku": "MiniMax-M2.5",
|
|
109
|
+
"sonnet": "qwen3.6-plus",
|
|
110
|
+
"opus": "qwen3.7-plus",
|
|
111
|
+
"fable": ""
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"options": {
|
|
115
|
+
"attributionHeader": false,
|
|
116
|
+
"disableNonEssentialTraffic": true,
|
|
117
|
+
"autoCompactWindow": 1000000
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"bailian-token-plan": {
|
|
121
|
+
"label": "Bailian 阿里百炼 Token Plan",
|
|
122
|
+
"baseUrl": "https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic",
|
|
123
|
+
"model": {
|
|
124
|
+
"support": [
|
|
125
|
+
"qwen3.7-max",
|
|
126
|
+
"qwen3.7-plus",
|
|
127
|
+
"qwen3.6-plus",
|
|
128
|
+
"qwen3.6-flash",
|
|
129
|
+
"deepseek-v4-pro",
|
|
130
|
+
"deepseek-v4-flash",
|
|
131
|
+
"deepseek-v3.2",
|
|
132
|
+
"kimi-k2.7-code",
|
|
133
|
+
"kimi-k2.6",
|
|
134
|
+
"kimi-k2.5",
|
|
135
|
+
"glm-5.2",
|
|
136
|
+
"glm-5.1",
|
|
137
|
+
"glm-5",
|
|
138
|
+
"MiniMax-M2.5"
|
|
139
|
+
],
|
|
140
|
+
"default": "qwen3.7-max",
|
|
141
|
+
"tier": "opus",
|
|
142
|
+
"tiers": {
|
|
143
|
+
"haiku": "qwen3.6-flash",
|
|
144
|
+
"sonnet": "qwen3.7-max",
|
|
145
|
+
"opus": "qwen3.7-max",
|
|
146
|
+
"fable": ""
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
"options": {
|
|
150
|
+
"attributionHeader": false,
|
|
151
|
+
"disableNonEssentialTraffic": true,
|
|
152
|
+
"autoCompactWindow": 1000000
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"deepseek-api": {
|
|
156
|
+
"label": "DeepSeek 深度求索 Api",
|
|
157
|
+
"baseUrl": "https://api.deepseek.com/anthropic",
|
|
158
|
+
"model": {
|
|
159
|
+
"default": "deepseek-v4-flash",
|
|
160
|
+
"tier": "opus",
|
|
161
|
+
"tiers": {
|
|
162
|
+
"haiku": "deepseek-v4-flash",
|
|
163
|
+
"sonnet": "deepseek-v4-pro[1m]",
|
|
164
|
+
"opus": "deepseek-v4-pro[1m]",
|
|
165
|
+
"fable": ""
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"options": {
|
|
169
|
+
"attributionHeader": false,
|
|
170
|
+
"disableNonEssentialTraffic": true,
|
|
171
|
+
"autoCompactWindow": 1000000
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"mimo-api": {
|
|
175
|
+
"label": "MiMo 小米 Api",
|
|
176
|
+
"baseUrl": "https://api.xiaomimimo.com/anthropic",
|
|
177
|
+
"model": {
|
|
178
|
+
"default": "mimo-v2.5-flash",
|
|
179
|
+
"tier": "opus",
|
|
180
|
+
"tiers": {
|
|
181
|
+
"haiku": "mimo-v2.5-flash",
|
|
182
|
+
"sonnet": "mimo-v2.5-pro[1m]",
|
|
183
|
+
"opus": "mimo-v2.5-pro[1m]",
|
|
184
|
+
"fable": ""
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"options": {
|
|
188
|
+
"attributionHeader": false,
|
|
189
|
+
"disableNonEssentialTraffic": true,
|
|
190
|
+
"autoCompactWindow": 1000000
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"mimo-token-plan": {
|
|
194
|
+
"label": "MiMo 小米 Token Plan",
|
|
195
|
+
"baseUrl": "https://token-plan-cn.xiaomimimo.com/anthropic",
|
|
196
|
+
"model": {
|
|
197
|
+
"default": "mimo-v2.5-flash",
|
|
198
|
+
"tier": "opus",
|
|
199
|
+
"tiers": {
|
|
200
|
+
"haiku": "mimo-v2.5-flash",
|
|
201
|
+
"sonnet": "mimo-v2.5-pro[1m]",
|
|
202
|
+
"opus": "mimo-v2.5-pro[1m]",
|
|
203
|
+
"fable": ""
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"options": {
|
|
207
|
+
"attributionHeader": false,
|
|
208
|
+
"disableNonEssentialTraffic": true,
|
|
209
|
+
"autoCompactWindow": 1000000
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"qianfan-coding-plan": {
|
|
213
|
+
"label": "Qianfan 百度千帆 Coding Plan",
|
|
214
|
+
"baseUrl": "https://qianfan.baidubce.com/anthropic/coding",
|
|
215
|
+
"model": {
|
|
216
|
+
"support": [
|
|
217
|
+
"deepseek-v3.2",
|
|
218
|
+
"deepseek-v4-flash",
|
|
219
|
+
"deepseek-v4-pro",
|
|
220
|
+
"ernie-4.5-turbo-20260402",
|
|
221
|
+
"glm-5",
|
|
222
|
+
"glm-5.1",
|
|
223
|
+
"kimi-k2.5"
|
|
224
|
+
],
|
|
225
|
+
"default": "deepseek-v4-flash",
|
|
226
|
+
"tier": "opus",
|
|
227
|
+
"tiers": {
|
|
228
|
+
"haiku": "deepseek-v4-flash",
|
|
229
|
+
"sonnet": "glm-5.1",
|
|
230
|
+
"opus": "deepseek-v4-pro[1m]",
|
|
231
|
+
"fable": ""
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"options": {
|
|
235
|
+
"attributionHeader": false,
|
|
236
|
+
"disableNonEssentialTraffic": true,
|
|
237
|
+
"autoCompactWindow": 1000000
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"spark-coding-plan": {
|
|
241
|
+
"label": "Spark 讯飞星辰 Coding Plan",
|
|
242
|
+
"baseUrl": "https://maas-coding-api.cn-huabei-1.xf-yun.com/anthropic",
|
|
243
|
+
"model": {
|
|
244
|
+
"support": [
|
|
245
|
+
"astron-code-latest",
|
|
246
|
+
"xsparkx2",
|
|
247
|
+
"xsparkx2flash",
|
|
248
|
+
"xopglm51",
|
|
249
|
+
"xopglm5",
|
|
250
|
+
"xopdeepseekv4pro",
|
|
251
|
+
"xopdeepseekv4flash",
|
|
252
|
+
"xopdeepseekv32",
|
|
253
|
+
"xopkimik26",
|
|
254
|
+
"xopkimik25",
|
|
255
|
+
"xminimaxm25",
|
|
256
|
+
"xopqwen35397b",
|
|
257
|
+
"xopqwen36v35b",
|
|
258
|
+
"xopqwen35v35b",
|
|
259
|
+
"xop3qwencodernext",
|
|
260
|
+
"xopglmv47flash"
|
|
261
|
+
],
|
|
262
|
+
"default": "astron-code-latest",
|
|
263
|
+
"tier": "opus",
|
|
264
|
+
"tiers": {
|
|
265
|
+
"haiku": "astron-code-latest",
|
|
266
|
+
"sonnet": "xopglm51",
|
|
267
|
+
"opus": "xopdeepseekv4pro[1m]",
|
|
268
|
+
"fable": ""
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"options": {
|
|
272
|
+
"attributionHeader": false,
|
|
273
|
+
"disableNonEssentialTraffic": true,
|
|
274
|
+
"autoCompactWindow": 1000000
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"spark-token-plan": {
|
|
278
|
+
"label": "Spark 讯飞星辰 Token Plan",
|
|
279
|
+
"baseUrl": "https://maas-token-api.cn-huabei-1.xf-yun.com/anthropic",
|
|
280
|
+
"model": {
|
|
281
|
+
"support": [
|
|
282
|
+
"astron-code-latest",
|
|
283
|
+
"xsparkx2",
|
|
284
|
+
"xsparkx2flash",
|
|
285
|
+
"xopglm51",
|
|
286
|
+
"xopglm5",
|
|
287
|
+
"xopdeepseekv4pro",
|
|
288
|
+
"xopdeepseekv4flash",
|
|
289
|
+
"xopdeepseekv32",
|
|
290
|
+
"xopkimik26",
|
|
291
|
+
"xopkimik25",
|
|
292
|
+
"xminimaxm25",
|
|
293
|
+
"xopqwen35397b",
|
|
294
|
+
"xopqwen36v35b",
|
|
295
|
+
"xopqwen35v35b",
|
|
296
|
+
"xop3qwencodernext",
|
|
297
|
+
"xopglmv47flash"
|
|
298
|
+
],
|
|
299
|
+
"default": "astron-code-latest",
|
|
300
|
+
"tier": "opus",
|
|
301
|
+
"tiers": {
|
|
302
|
+
"haiku": "astron-code-latest",
|
|
303
|
+
"sonnet": "xopglm51",
|
|
304
|
+
"opus": "xopdeepseekv4pro[1m]",
|
|
305
|
+
"fable": ""
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"options": {
|
|
309
|
+
"attributionHeader": false,
|
|
310
|
+
"disableNonEssentialTraffic": true,
|
|
311
|
+
"autoCompactWindow": 1000000
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
package/dist/screen.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 清屏 helper:擦除当前视口并将光标归位,**保留 scrollback**(历史可上滚)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要:ink 默认(非 experimental)模式不在首次渲染时清屏,且卸载时
|
|
5
|
+
* 保留最后一帧(log.done())。连续的 ink 屏幕(picker → 选预设 → 表单 …)
|
|
6
|
+
* 因此向下堆叠。每个顶层屏幕在 render() 前调用本函数,即可让视口一次只见一屏。
|
|
7
|
+
*
|
|
8
|
+
* 用 `\x1b[2J\x1b[H`(擦视口 + 归位)而非 `\x1b[3J`(清 scrollback)——
|
|
9
|
+
* 后者会抹掉终端历史,过度破坏;"页面独占"只需视口干净。
|
|
10
|
+
* 直接写 process.stdout,绕过 ink 的 patchConsole。
|
|
11
|
+
*/
|
|
12
|
+
export declare function clearScreen(): void;
|
package/dist/screen.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 清屏 helper:擦除当前视口并将光标归位,**保留 scrollback**(历史可上滚)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要:ink 默认(非 experimental)模式不在首次渲染时清屏,且卸载时
|
|
5
|
+
* 保留最后一帧(log.done())。连续的 ink 屏幕(picker → 选预设 → 表单 …)
|
|
6
|
+
* 因此向下堆叠。每个顶层屏幕在 render() 前调用本函数,即可让视口一次只见一屏。
|
|
7
|
+
*
|
|
8
|
+
* 用 `\x1b[2J\x1b[H`(擦视口 + 归位)而非 `\x1b[3J`(清 scrollback)——
|
|
9
|
+
* 后者会抹掉终端历史,过度破坏;"页面独占"只需视口干净。
|
|
10
|
+
* 直接写 process.stdout,绕过 ink 的 patchConsole。
|
|
11
|
+
*/
|
|
12
|
+
export function clearScreen() {
|
|
13
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
14
|
+
}
|
package/dist/tui.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { runPicker } from './picker.js';
|
|
2
|
+
import { inkSelect, inkText, inkConfirm } from './inkPrompts.js';
|
|
3
|
+
/** 用户取消时抛出,由顶层捕获统一退出。 */
|
|
4
|
+
export declare class Cancel extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare const ui: {
|
|
8
|
+
/** 取消提示(如顶层 Cancel 兜底)。纯 console 输出一行。 */
|
|
9
|
+
cancel: (t: string) => void;
|
|
10
|
+
log: {
|
|
11
|
+
message: (t: string) => void;
|
|
12
|
+
info: (t: string) => void;
|
|
13
|
+
step: (t: string) => void;
|
|
14
|
+
warning: (t: string) => void;
|
|
15
|
+
error: (t: string) => void;
|
|
16
|
+
};
|
|
17
|
+
/** 搜索选择器(ink):输入过滤 + 可滚动下拉。 */
|
|
18
|
+
picker: typeof runPicker;
|
|
19
|
+
/** ink 版 select/text/confirm:交互提示一律用 ink。 */
|
|
20
|
+
inkSelect: typeof inkSelect;
|
|
21
|
+
inkText: typeof inkText;
|
|
22
|
+
inkConfirm: typeof inkConfirm;
|
|
23
|
+
};
|
|
24
|
+
export type { PickerItem, PickerOpts } from './picker.js';
|
package/dist/tui.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { runPicker } from './picker.js';
|
|
2
|
+
import { inkSelect, inkText, inkConfirm } from './inkPrompts.js';
|
|
3
|
+
/** 用户取消时抛出,由顶层捕获统一退出。 */
|
|
4
|
+
export class Cancel extends Error {
|
|
5
|
+
constructor() { super('cancel'); this.name = 'Cancel'; }
|
|
6
|
+
}
|
|
7
|
+
// 交互层完全由 ink 承担(runPicker / inkSelect / inkText / inkConfirm / 表单)。
|
|
8
|
+
// 此处仅保留 ui 表面:cancel/log 走纯 console(不进 raw mode),其余交互一律 ink。
|
|
9
|
+
export const ui = {
|
|
10
|
+
/** 取消提示(如顶层 Cancel 兜底)。纯 console 输出一行。 */
|
|
11
|
+
cancel: (t) => console.log(t),
|
|
12
|
+
log: {
|
|
13
|
+
message: (t) => console.log(t),
|
|
14
|
+
info: (t) => console.info(t),
|
|
15
|
+
step: (t) => console.log(t),
|
|
16
|
+
warning: (t) => console.warn(t),
|
|
17
|
+
error: (t) => console.error(t),
|
|
18
|
+
},
|
|
19
|
+
/** 搜索选择器(ink):输入过滤 + 可滚动下拉。 */
|
|
20
|
+
picker: runPicker,
|
|
21
|
+
/** ink 版 select/text/confirm:交互提示一律用 ink。 */
|
|
22
|
+
inkSelect,
|
|
23
|
+
inkText,
|
|
24
|
+
inkConfirm,
|
|
25
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享类型契约。
|
|
3
|
+
*
|
|
4
|
+
* ccs 的数据模型三层边界:
|
|
5
|
+
* - Preset / ProviderOptions:从 presets.json / 用户 presets 读入的预设结构
|
|
6
|
+
* - FormState:表单状态机,判别联合 mode: 'alias' | 'single'
|
|
7
|
+
* - ProviderSettings:写进 provider 配置、最终透传给 claude --settings 的片段
|
|
8
|
+
*/
|
|
9
|
+
/** Claude Code 模型档位(与 /model 选择器对应)。 */
|
|
10
|
+
export type Tier = 'opus' | 'sonnet' | 'haiku' | 'fable';
|
|
11
|
+
/** 推理强度档位(对应 CLAUDE_CODE_EFFORT_LEVEL)。 */
|
|
12
|
+
export type EffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
13
|
+
/** 三项 CLAUDE_CODE_* 配置 + ccs 启动开关,存于 provider 配置。 */
|
|
14
|
+
export interface ProviderOptions {
|
|
15
|
+
attributionHeader: boolean;
|
|
16
|
+
disableNonEssentialTraffic: boolean;
|
|
17
|
+
autoCompactWindow: number;
|
|
18
|
+
effort: EffortLevel;
|
|
19
|
+
}
|
|
20
|
+
/** 模型元信息:供应商支持列表、默认模型、档位配置。 */
|
|
21
|
+
export interface ModelMeta {
|
|
22
|
+
/** 供应商支持的全部模型列表(用于 UI 展示)。 */
|
|
23
|
+
support?: string[];
|
|
24
|
+
/** 单模型模式的主模型。 */
|
|
25
|
+
default?: string;
|
|
26
|
+
/** 默认档位(如 'opus')。 */
|
|
27
|
+
tier?: string;
|
|
28
|
+
/** 档位别名:haiku/sonnet/opus/fable → modelId。 */
|
|
29
|
+
tiers?: Partial<Record<Tier, string>>;
|
|
30
|
+
}
|
|
31
|
+
/** 内置/用户预设结构。model 字段统一为 ModelMeta。 */
|
|
32
|
+
export interface Preset {
|
|
33
|
+
label: string;
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
model?: ModelMeta;
|
|
36
|
+
options?: Partial<ProviderOptions>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 写进 provider 配置、最终透传给 claude --settings 的片段。
|
|
40
|
+
* - env:环境变量(API key、base url、各档位别名、CLAUDE_CODE_* 等)
|
|
41
|
+
* - model:仅 alias 模式下记录初始档位(供 ccs 启动参数与菜单展示)
|
|
42
|
+
*/
|
|
43
|
+
export interface ProviderSettings {
|
|
44
|
+
env: Record<string, string>;
|
|
45
|
+
model?: Tier;
|
|
46
|
+
}
|
|
47
|
+
/** 表单模式:档位别名(多模型)或单一模型。 */
|
|
48
|
+
export type FormMode = 'alias' | 'single';
|
|
49
|
+
/** 认证方式。 */
|
|
50
|
+
export type AuthMethod = 'auth_token' | 'api_key';
|
|
51
|
+
/** 表单运行态。initState 构造、buildResult 消费、validateState 校验。 */
|
|
52
|
+
export interface FormState {
|
|
53
|
+
baseUrl: string;
|
|
54
|
+
existingKey: string;
|
|
55
|
+
apiKey: string;
|
|
56
|
+
keepExistingKey: boolean;
|
|
57
|
+
mode: FormMode;
|
|
58
|
+
authMethod: AuthMethod;
|
|
59
|
+
tier: string;
|
|
60
|
+
/** ALIAS_TIERS → 模型 id(别名模式)。 */
|
|
61
|
+
aliases: Record<string, string>;
|
|
62
|
+
singleModel: string;
|
|
63
|
+
options: ProviderOptions;
|
|
64
|
+
/** 原始 JSON 字符串,提交时解析合并到 env。 */
|
|
65
|
+
customParams: string;
|
|
66
|
+
}
|
|
67
|
+
/** 表单提交结果,等价于 ProviderSettings 片段。 */
|
|
68
|
+
export type FormResult = ProviderSettings;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getVersion(): string;
|