@seandong/seno 0.1.0

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.
Files changed (104) hide show
  1. package/README.md +70 -0
  2. package/dist/agent/conversation.d.ts +39 -0
  3. package/dist/agent/conversation.js +60 -0
  4. package/dist/agent/conversation.js.map +1 -0
  5. package/dist/agent/loop.d.ts +41 -0
  6. package/dist/agent/loop.js +203 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/session.d.ts +63 -0
  9. package/dist/agent/session.js +135 -0
  10. package/dist/agent/session.js.map +1 -0
  11. package/dist/cli/commands.d.ts +52 -0
  12. package/dist/cli/commands.js +667 -0
  13. package/dist/cli/commands.js.map +1 -0
  14. package/dist/cli/logger.d.ts +38 -0
  15. package/dist/cli/logger.js +79 -0
  16. package/dist/cli/logger.js.map +1 -0
  17. package/dist/cli/output.d.ts +75 -0
  18. package/dist/cli/output.js +305 -0
  19. package/dist/cli/output.js.map +1 -0
  20. package/dist/cli/prompt.d.ts +30 -0
  21. package/dist/cli/prompt.js +196 -0
  22. package/dist/cli/prompt.js.map +1 -0
  23. package/dist/cli/repl.d.ts +27 -0
  24. package/dist/cli/repl.js +485 -0
  25. package/dist/cli/repl.js.map +1 -0
  26. package/dist/commands/init.d.ts +4 -0
  27. package/dist/commands/init.js +170 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/model.d.ts +10 -0
  30. package/dist/commands/model.js +270 -0
  31. package/dist/commands/model.js.map +1 -0
  32. package/dist/config/manager.d.ts +67 -0
  33. package/dist/config/manager.js +194 -0
  34. package/dist/config/manager.js.map +1 -0
  35. package/dist/config/types.d.ts +98 -0
  36. package/dist/config/types.js +2 -0
  37. package/dist/config/types.js.map +1 -0
  38. package/dist/errors.d.ts +37 -0
  39. package/dist/errors.js +54 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +185 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/llm/anthropic.d.ts +27 -0
  45. package/dist/llm/anthropic.js +189 -0
  46. package/dist/llm/anthropic.js.map +1 -0
  47. package/dist/llm/factory.d.ts +47 -0
  48. package/dist/llm/factory.js +163 -0
  49. package/dist/llm/factory.js.map +1 -0
  50. package/dist/llm/openai-codex.d.ts +45 -0
  51. package/dist/llm/openai-codex.js +398 -0
  52. package/dist/llm/openai-codex.js.map +1 -0
  53. package/dist/llm/openai.d.ts +16 -0
  54. package/dist/llm/openai.js +288 -0
  55. package/dist/llm/openai.js.map +1 -0
  56. package/dist/llm/provider.d.ts +19 -0
  57. package/dist/llm/provider.js +2 -0
  58. package/dist/llm/provider.js.map +1 -0
  59. package/dist/llm/types.d.ts +102 -0
  60. package/dist/llm/types.js +2 -0
  61. package/dist/llm/types.js.map +1 -0
  62. package/dist/mcp/bridge.d.ts +30 -0
  63. package/dist/mcp/bridge.js +73 -0
  64. package/dist/mcp/bridge.js.map +1 -0
  65. package/dist/mcp/config.d.ts +6 -0
  66. package/dist/mcp/config.js +26 -0
  67. package/dist/mcp/config.js.map +1 -0
  68. package/dist/mcp/manager.d.ts +54 -0
  69. package/dist/mcp/manager.js +171 -0
  70. package/dist/mcp/manager.js.map +1 -0
  71. package/dist/prompts/system.d.ts +14 -0
  72. package/dist/prompts/system.js +194 -0
  73. package/dist/prompts/system.js.map +1 -0
  74. package/dist/skills/loader.d.ts +7 -0
  75. package/dist/skills/loader.js +81 -0
  76. package/dist/skills/loader.js.map +1 -0
  77. package/dist/skills/registry.d.ts +48 -0
  78. package/dist/skills/registry.js +104 -0
  79. package/dist/skills/registry.js.map +1 -0
  80. package/dist/skills/sync.d.ts +34 -0
  81. package/dist/skills/sync.js +179 -0
  82. package/dist/skills/sync.js.map +1 -0
  83. package/dist/skills/types.d.ts +29 -0
  84. package/dist/skills/types.js +2 -0
  85. package/dist/skills/types.js.map +1 -0
  86. package/dist/tools/ask.d.ts +16 -0
  87. package/dist/tools/ask.js +57 -0
  88. package/dist/tools/ask.js.map +1 -0
  89. package/dist/tools/registry.d.ts +54 -0
  90. package/dist/tools/registry.js +114 -0
  91. package/dist/tools/registry.js.map +1 -0
  92. package/dist/tools/shell.d.ts +10 -0
  93. package/dist/tools/shell.js +131 -0
  94. package/dist/tools/shell.js.map +1 -0
  95. package/dist/tools/ssh.d.ts +40 -0
  96. package/dist/tools/ssh.js +302 -0
  97. package/dist/tools/ssh.js.map +1 -0
  98. package/dist/tools/types.d.ts +20 -0
  99. package/dist/tools/types.js +2 -0
  100. package/dist/tools/types.js.map +1 -0
  101. package/dist/utils/retry.d.ts +20 -0
  102. package/dist/utils/retry.js +33 -0
  103. package/dist/utils/retry.js.map +1 -0
  104. package/package.json +51 -0
@@ -0,0 +1,170 @@
1
+ import { createInterface } from 'node:readline';
2
+ import chalk from 'chalk';
3
+ import { loadConfig, saveConfig, getConfigPath, isInitialized, formatModelId } from '../config/manager.js';
4
+ import { PROVIDER_REGISTRY } from '../llm/factory.js';
5
+ import { codexOAuthLogin } from '../llm/openai-codex.js';
6
+ import { promptQuestion, promptChoice, questionSecret, CancelError } from '../cli/prompt.js';
7
+ /**
8
+ * 验证 URL 格式
9
+ */
10
+ function validateUrl(url) {
11
+ if (!url) {
12
+ return 'URL 不能为空';
13
+ }
14
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
15
+ return 'URL 格式不正确,应以 http:// 或 https:// 开头';
16
+ }
17
+ return null;
18
+ }
19
+ /**
20
+ * seno init 命令实现
21
+ */
22
+ export async function initCommand() {
23
+ const rl = createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout,
26
+ });
27
+ try {
28
+ // 检查是否已初始化
29
+ if (await isInitialized()) {
30
+ const existingConfig = await loadConfig();
31
+ console.log(`\n配置文件已存在:${getConfigPath()}`);
32
+ console.log(` Model: ${existingConfig?.model || 'N/A'}`);
33
+ console.log(` MCP URL: ${existingConfig?.ones_mcp_url}`);
34
+ const overwrite = await promptQuestion(rl, '\n是否覆盖现有配置?(y/N) ');
35
+ if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {
36
+ console.log('已取消。');
37
+ return;
38
+ }
39
+ }
40
+ console.log('\n🔧 SENO CLI 初始化配置\n');
41
+ // ── Step 1: 选择 LLM Provider ──────────────────────────
42
+ console.log(chalk.cyan(' 选择 LLM Provider:'));
43
+ const providerOptions = PROVIDER_REGISTRY.map((p) => p.displayName);
44
+ const providerIdx = await promptChoice(rl, '', providerOptions, 0);
45
+ const selectedProvider = PROVIDER_REGISTRY[providerIdx ?? 0];
46
+ // ── Step 2: 授权方式(只有一种时跳过) ────────────────────
47
+ let selectedAuthMode = selectedProvider.authModes[0];
48
+ if (selectedProvider.authModes.length > 1) {
49
+ const authOptions = selectedProvider.authModes.map((a) => a.displayName);
50
+ console.log();
51
+ console.log(chalk.cyan(' 选择授权方式:'));
52
+ const authIdx = await promptChoice(rl, '', authOptions, 0);
53
+ selectedAuthMode = selectedProvider.authModes[authIdx ?? 0];
54
+ }
55
+ // ── Step 3: 凭证输入 ──────────────────────────────────────
56
+ let apiKey;
57
+ if (selectedAuthMode.mode === 'api_key') {
58
+ // 关闭 rl 以便在 questionSecret 中直接操作 stdin
59
+ rl.close();
60
+ console.log();
61
+ while (true) {
62
+ apiKey = await questionSecret(` ${selectedProvider.displayName} API Key: `);
63
+ if (selectedProvider.validateKey) {
64
+ const err = selectedProvider.validateKey(apiKey);
65
+ if (err) {
66
+ console.log(chalk.red(` ❌ ${err}`));
67
+ continue;
68
+ }
69
+ }
70
+ break;
71
+ }
72
+ // 重新创建 rl 用于后续普通输入(questionSecret 需要 raw mode)
73
+ const rl2 = createInterface({
74
+ input: process.stdin,
75
+ output: process.stdout,
76
+ });
77
+ // 继续后续流程使用 rl2
78
+ await completeInit(rl2, selectedProvider, selectedAuthMode.mode, apiKey);
79
+ rl2.close();
80
+ return;
81
+ }
82
+ else {
83
+ // OAuth 模式
84
+ console.log();
85
+ console.log(chalk.gray(' 正在启动 OAuth 授权流程...'));
86
+ console.log();
87
+ try {
88
+ await codexOAuthLogin();
89
+ console.log(chalk.green(' ✓ OAuth 授权成功'));
90
+ }
91
+ catch (error) {
92
+ console.log(chalk.red(` ✗ OAuth 授权失败: ${error instanceof Error ? error.message : String(error)}`));
93
+ return;
94
+ }
95
+ await completeInit(rl, selectedProvider, selectedAuthMode.mode, undefined);
96
+ return;
97
+ }
98
+ }
99
+ catch (error) {
100
+ if (error instanceof CancelError) {
101
+ console.log('\n已取消。');
102
+ return;
103
+ }
104
+ if (error.code === 'ERR_USE_AFTER_CLOSE') {
105
+ return;
106
+ }
107
+ throw error;
108
+ }
109
+ finally {
110
+ rl.close();
111
+ }
112
+ }
113
+ /**
114
+ * 完成初始化流程的后半部分(模型选择 + MCP URL + 保存)
115
+ */
116
+ async function completeInit(rl, provider, authMode, apiKey) {
117
+ // ── Step 4: 选择模型 ────────────────────────────────────
118
+ console.log();
119
+ console.log(chalk.cyan(' 选择模型:'));
120
+ const modelOptions = provider.models.map((m) => `${m.displayName} (${m.id})`);
121
+ modelOptions.push(chalk.gray('自定义模型 ID'));
122
+ const modelIdx = await promptChoice(rl, '', modelOptions, 0);
123
+ let selectedModelId;
124
+ if (modelIdx === null) {
125
+ // 无效输入,使用第一个模型
126
+ selectedModelId = provider.models[0].id;
127
+ }
128
+ else if (modelIdx === provider.models.length) {
129
+ // 自定义模型 ID
130
+ selectedModelId = await promptQuestion(rl, chalk.cyan(' 模型 ID: '));
131
+ if (!selectedModelId) {
132
+ selectedModelId = provider.models[0].id;
133
+ }
134
+ }
135
+ else {
136
+ selectedModelId = provider.models[modelIdx].id;
137
+ }
138
+ // ── Step 5: ONES MCP URL ────────────────────────────────
139
+ console.log();
140
+ let mcpUrl = '';
141
+ while (true) {
142
+ mcpUrl = await promptQuestion(rl, chalk.cyan(' ONES MCP URL: '));
143
+ const err = validateUrl(mcpUrl);
144
+ if (!err)
145
+ break;
146
+ console.log(chalk.red(` ❌ ${err}`));
147
+ }
148
+ // ── Step 6: 保存配置 ────────────────────────────────────
149
+ const config = {
150
+ model: formatModelId(provider.name, selectedModelId),
151
+ ones_mcp_url: mcpUrl,
152
+ debug: false,
153
+ llm: {
154
+ providers: {
155
+ [provider.name]: {
156
+ mode: authMode,
157
+ ...(apiKey ? { api_key: apiKey } : {}),
158
+ },
159
+ },
160
+ },
161
+ ones_skills: {
162
+ repository: 'https://github.com/seandong/ones-skills.git',
163
+ },
164
+ };
165
+ await saveConfig(config);
166
+ console.log(`\n${chalk.green('✅')} 配置已保存到 ${getConfigPath()}`);
167
+ console.log(` Model: ${config.model}`);
168
+ console.log(' 运行 seno 开始使用。\n');
169
+ }
170
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import * as readline from 'readline';
2
+ import type { SenoConfig } from '../config/types.js';
3
+ import type { LLMProvider } from '../llm/provider.js';
4
+ /**
5
+ * switchLLMProvider 回调类型
6
+ */
7
+ export type SwitchLLMFn = (provider: LLMProvider, model: string) => void;
8
+ export declare function modelInfo(config: SenoConfig): Promise<void>;
9
+ export declare function modelSet(rl: readline.Interface, config: SenoConfig, switchFn: SwitchLLMFn): Promise<void>;
10
+ export declare function modelAuth(rl: readline.Interface, config: SenoConfig, switchFn: SwitchLLMFn): Promise<void>;
@@ -0,0 +1,270 @@
1
+ import chalk from 'chalk';
2
+ import { parseModelId, formatModelId, saveConfig } from '../config/manager.js';
3
+ import { PROVIDER_REGISTRY, getProviderInfo, createLLMProvider, fetchAvailableModels, } from '../llm/factory.js';
4
+ import { codexOAuthLogin, getCodexAccessToken } from '../llm/openai-codex.js';
5
+ import { promptQuestion, promptChoice } from '../cli/prompt.js';
6
+ // ─── /model — 查看当前配置 ──────────────────────────────────
7
+ export async function modelInfo(config) {
8
+ console.log();
9
+ if (!config.model) {
10
+ console.log(chalk.yellow(' LLM 未配置,请运行 /model auth 配置'));
11
+ console.log();
12
+ return;
13
+ }
14
+ const { provider, model } = parseModelId(config.model);
15
+ const providerInfo = getProviderInfo(provider);
16
+ const providerConfig = config.llm?.providers?.[provider];
17
+ console.log(chalk.bold(' 当前模型: ') + chalk.green(config.model));
18
+ console.log();
19
+ console.log(' Provider: ' + (providerInfo?.displayName || provider));
20
+ console.log(' Model: ' + model);
21
+ console.log(' Auth: ' + (providerConfig?.mode || 'N/A'));
22
+ // 显示凭证摘要
23
+ if (providerConfig?.mode === 'api_key' && providerConfig.api_key) {
24
+ const masked = providerConfig.api_key.slice(0, 12) + '...';
25
+ console.log(' API Key: ' + chalk.gray(masked));
26
+ }
27
+ // 已授权的 Provider 列表
28
+ console.log();
29
+ console.log(chalk.bold(' 已授权的 Providers:'));
30
+ for (const reg of PROVIDER_REGISTRY) {
31
+ const pc = config.llm?.providers?.[reg.name];
32
+ const isAuthed = pc && (pc.mode === 'oauth' || !!pc.api_key);
33
+ const isCurrent = reg.name === provider;
34
+ const bullet = isCurrent ? chalk.green('●') : (isAuthed ? chalk.cyan('●') : chalk.gray('○'));
35
+ const mode = pc?.mode || '-';
36
+ const label = isCurrent
37
+ ? chalk.green(`${reg.name.padEnd(16)}(${mode})`)
38
+ : `${reg.name.padEnd(16)}(${mode})`;
39
+ console.log(` ${bullet} ${label}`);
40
+ }
41
+ console.log();
42
+ }
43
+ // ─── /model set — 切换 Provider + 模型 ─────────────────────
44
+ export async function modelSet(rl, config, switchFn) {
45
+ console.log();
46
+ console.log(chalk.gray(' 切换模型 [按 ESC 键取消]'));
47
+ console.log();
48
+ // 1. 筛选已授权的 Provider
49
+ const authedProviders = PROVIDER_REGISTRY.filter((reg) => {
50
+ const pc = config.llm?.providers?.[reg.name];
51
+ if (!pc)
52
+ return false;
53
+ if (pc.mode === 'api_key')
54
+ return !!pc.api_key;
55
+ if (pc.mode === 'oauth')
56
+ return true;
57
+ return false;
58
+ });
59
+ if (authedProviders.length === 0) {
60
+ console.log(chalk.yellow(' 没有已授权的 Provider,请先运行 /model auth'));
61
+ console.log();
62
+ return;
63
+ }
64
+ // 2. 选择 Provider(只有一个时跳过)
65
+ let selectedProvider;
66
+ if (authedProviders.length === 1) {
67
+ selectedProvider = authedProviders[0];
68
+ console.log(chalk.gray(` Provider: ${selectedProvider.displayName}`));
69
+ }
70
+ else {
71
+ const { provider: currentProvider } = config.model
72
+ ? parseModelId(config.model)
73
+ : { provider: '' };
74
+ const options = authedProviders.map((p) => {
75
+ const mark = p.name === currentProvider ? chalk.green(' (当前)') : '';
76
+ return `${p.displayName}${mark}`;
77
+ });
78
+ console.log(chalk.cyan(' 选择 Provider:'));
79
+ const currentIdx = authedProviders.findIndex((p) => p.name === currentProvider);
80
+ const idx = await promptChoice(rl, '', options, currentIdx >= 0 ? currentIdx : 0);
81
+ if (idx === null) {
82
+ console.log(chalk.yellow(' 无效选择'));
83
+ return;
84
+ }
85
+ selectedProvider = authedProviders[idx];
86
+ }
87
+ // 3. 获取模型列表
88
+ const providerConfig = config.llm?.providers?.[selectedProvider.name];
89
+ let credential;
90
+ if (providerConfig?.mode === 'oauth') {
91
+ try {
92
+ credential = await getCodexAccessToken();
93
+ }
94
+ catch { /* fallback to hardcoded */ }
95
+ }
96
+ else {
97
+ credential = providerConfig?.api_key;
98
+ }
99
+ const models = await fetchAvailableModels(selectedProvider.name, credential);
100
+ // 4. 显示模型选择
101
+ const currentModelId = config.model ? parseModelId(config.model).model : '';
102
+ const modelOptions = models.map((m) => {
103
+ const mark = m.id === currentModelId ? chalk.green(' (当前)') : '';
104
+ return `${m.displayName || m.id}${mark}`;
105
+ });
106
+ modelOptions.push(chalk.gray('自定义模型 ID'));
107
+ const currentModelIdx = models.findIndex((m) => m.id === currentModelId);
108
+ console.log();
109
+ console.log(chalk.cyan(' 选择模型:'));
110
+ const modelIdx = await promptChoice(rl, '', modelOptions, currentModelIdx >= 0 ? currentModelIdx : 0);
111
+ if (modelIdx === null) {
112
+ console.log(chalk.yellow(' 无效选择'));
113
+ return;
114
+ }
115
+ let selectedModelId;
116
+ if (modelIdx === models.length) {
117
+ // 自定义模型 ID
118
+ selectedModelId = await promptQuestion(rl, chalk.cyan(' 模型 ID: '));
119
+ if (!selectedModelId) {
120
+ console.log(chalk.yellow(' 模型 ID 不能为空'));
121
+ return;
122
+ }
123
+ }
124
+ else {
125
+ selectedModelId = models[modelIdx].id;
126
+ }
127
+ // 5. 更新配置
128
+ config.model = formatModelId(selectedProvider.name, selectedModelId);
129
+ await saveConfig(config);
130
+ // 6. 热切换
131
+ const newProvider = await createLLMProvider(providerConfig, selectedProvider.name);
132
+ switchFn(newProvider, selectedModelId);
133
+ console.log();
134
+ console.log(chalk.green(` ✓ 已切换为 ${config.model}`));
135
+ console.log();
136
+ }
137
+ // ─── /model auth — 授权管理 ────────────────────────────────
138
+ export async function modelAuth(rl, config, switchFn) {
139
+ console.log();
140
+ console.log(chalk.gray(' 配置 Provider 授权 [按 ESC 键取消]'));
141
+ console.log();
142
+ // 1. 列出所有 Provider
143
+ const options = PROVIDER_REGISTRY.map((p) => {
144
+ const pc = config.llm?.providers?.[p.name];
145
+ const isAuthed = pc && (pc.mode === 'oauth' || !!pc.api_key);
146
+ const status = isAuthed ? chalk.green(' ✓') : '';
147
+ return `${p.displayName}${status}`;
148
+ });
149
+ console.log(chalk.cyan(' 选择 Provider:'));
150
+ const providerIdx = await promptChoice(rl, '', options, 0);
151
+ if (providerIdx === null) {
152
+ console.log(chalk.yellow(' 无效选择'));
153
+ return;
154
+ }
155
+ const selectedProvider = PROVIDER_REGISTRY[providerIdx];
156
+ // 2. 选择授权方式(只有一种时跳过)
157
+ let selectedAuthMode = selectedProvider.authModes[0];
158
+ if (selectedProvider.authModes.length > 1) {
159
+ const authOptions = selectedProvider.authModes.map((a) => a.displayName);
160
+ console.log();
161
+ console.log(chalk.cyan(' 选择授权方式:'));
162
+ const authIdx = await promptChoice(rl, '', authOptions, 0);
163
+ if (authIdx === null) {
164
+ console.log(chalk.yellow(' 无效选择'));
165
+ return;
166
+ }
167
+ selectedAuthMode = selectedProvider.authModes[authIdx];
168
+ }
169
+ // 3. 执行授权
170
+ let newProviderConfig;
171
+ if (selectedAuthMode.mode === 'api_key') {
172
+ // API Key 输入
173
+ const keyHint = selectedProvider.keyPlaceholder
174
+ ? chalk.gray(` (${selectedProvider.keyPlaceholder})`)
175
+ : '';
176
+ console.log(`\n ${selectedProvider.displayName} API Key${keyHint}:`);
177
+ const apiKey = await promptQuestion(rl, ' > ');
178
+ // 校验
179
+ if (selectedProvider.validateKey) {
180
+ const err = selectedProvider.validateKey(apiKey);
181
+ if (err) {
182
+ console.log(chalk.red(` ✗ ${err}`));
183
+ return;
184
+ }
185
+ }
186
+ newProviderConfig = {
187
+ mode: 'api_key',
188
+ api_key: apiKey,
189
+ base_url: config.llm?.providers?.[selectedProvider.name]?.base_url,
190
+ };
191
+ }
192
+ else {
193
+ // OAuth
194
+ console.log();
195
+ console.log(chalk.gray(' 正在启动 OAuth 授权流程...'));
196
+ console.log();
197
+ // 暂停 rl 防止 stdin 被 readline 和子进程同时读取
198
+ rl.pause();
199
+ try {
200
+ await codexOAuthLogin();
201
+ }
202
+ catch (error) {
203
+ console.log(chalk.red(` ✗ OAuth 授权失败: ${error instanceof Error ? error.message : String(error)}`));
204
+ return;
205
+ }
206
+ finally {
207
+ // 清除子进程残留的 stdin 数据,防止泄漏到 readline
208
+ if (process.stdin.readable) {
209
+ process.stdin.read();
210
+ }
211
+ rl.resume();
212
+ }
213
+ newProviderConfig = {
214
+ mode: 'oauth',
215
+ base_url: config.llm?.providers?.[selectedProvider.name]?.base_url,
216
+ };
217
+ }
218
+ // 4. 保存到 config
219
+ if (!config.llm) {
220
+ config.llm = { providers: {} };
221
+ }
222
+ config.llm.providers[selectedProvider.name] = newProviderConfig;
223
+ console.log();
224
+ console.log(chalk.green(` ✓ ${selectedProvider.displayName} 授权成功`));
225
+ // 5. 获取模型列表并选择
226
+ let credential;
227
+ if (newProviderConfig.mode === 'oauth') {
228
+ try {
229
+ credential = await getCodexAccessToken();
230
+ }
231
+ catch { /* fallback to hardcoded */ }
232
+ }
233
+ else {
234
+ credential = newProviderConfig.api_key;
235
+ }
236
+ const models = await fetchAvailableModels(selectedProvider.name, credential);
237
+ const modelOptions = models.map((m) => m.displayName || m.id);
238
+ modelOptions.push(chalk.gray('自定义模型 ID'));
239
+ console.log();
240
+ console.log(chalk.cyan(' 选择默认模型:'));
241
+ const modelIdx = await promptChoice(rl, '', modelOptions, 0);
242
+ let selectedModelId;
243
+ if (modelIdx === null || modelIdx === models.length) {
244
+ if (modelIdx === models.length) {
245
+ selectedModelId = await promptQuestion(rl, chalk.cyan(' 模型 ID: '));
246
+ if (!selectedModelId) {
247
+ selectedModelId = models[0].id;
248
+ }
249
+ }
250
+ else {
251
+ selectedModelId = models[0].id;
252
+ }
253
+ }
254
+ else {
255
+ selectedModelId = models[modelIdx].id;
256
+ }
257
+ // 6. 询问是否切换为当前使用
258
+ console.log();
259
+ console.log(chalk.cyan(' 是否切换为当前使用的模型?'));
260
+ const switchIdx = await promptChoice(rl, '', ['是', '否'], 0);
261
+ if (switchIdx === 0) {
262
+ config.model = formatModelId(selectedProvider.name, selectedModelId);
263
+ const newProvider = await createLLMProvider(newProviderConfig, selectedProvider.name);
264
+ switchFn(newProvider, selectedModelId);
265
+ console.log(chalk.green(` ✓ 已切换为 ${config.model}`));
266
+ }
267
+ await saveConfig(config);
268
+ console.log();
269
+ }
270
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/commands/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { SenoConfig, ServersConfig, LLMProviderName, ProviderConfig } from './types.js';
2
+ /**
3
+ * 获取配置目录路径 ~/.seno/
4
+ */
5
+ export declare function getConfigDir(): string;
6
+ /**
7
+ * 获取配置文件路径 ~/.seno/config.json
8
+ */
9
+ export declare function getConfigPath(): string;
10
+ /**
11
+ * 获取服务器配置文件路径 ~/.seno/servers.json
12
+ */
13
+ export declare function getServersPath(): string;
14
+ /**
15
+ * 获取日志目录路径 ~/.seno/logs/
16
+ */
17
+ export declare function getLogsDir(): string;
18
+ /**
19
+ * 确保配置目录存在(包括 logs 子目录)
20
+ */
21
+ export declare function ensureConfigDir(): Promise<void>;
22
+ /**
23
+ * 解析 "provider/model_name" 格式的模型 ID
24
+ */
25
+ export declare function parseModelId(modelId: string): {
26
+ provider: LLMProviderName;
27
+ model: string;
28
+ };
29
+ /**
30
+ * 拼接 provider 和 model 为 "provider/model_name"
31
+ */
32
+ export declare function formatModelId(provider: LLMProviderName, model: string): string;
33
+ /**
34
+ * 从 config 中获取当前活跃的 provider 信息
35
+ * @returns null 表示未配置或凭证缺失
36
+ */
37
+ export declare function getActiveProvider(config: SenoConfig): {
38
+ name: LLMProviderName;
39
+ model: string;
40
+ providerConfig: ProviderConfig;
41
+ } | null;
42
+ /**
43
+ * 读取配置文件 ~/.seno/config.json
44
+ * 自动检测并迁移旧格式配置
45
+ * @returns 配置对象,文件不存在返回 null
46
+ */
47
+ export declare function loadConfig(): Promise<SenoConfig | null>;
48
+ /**
49
+ * 保存配置文件 ~/.seno/config.json
50
+ * 文件权限设置为 0o600(仅用户可读写)
51
+ */
52
+ export declare function saveConfig(config: SenoConfig): Promise<void>;
53
+ /**
54
+ * 检查是否已完成初始化
55
+ * 配置文件存在且包含必需字段即视为已初始化
56
+ * 兼容新格式(model + llm.providers)和旧格式(anthropic_api_key)
57
+ */
58
+ export declare function isInitialized(): Promise<boolean>;
59
+ /**
60
+ * 读取 SSH 服务器配置 ~/.seno/servers.json
61
+ * @returns 服务器列表,文件不存在返回空列表
62
+ */
63
+ export declare function loadServers(): Promise<ServersConfig>;
64
+ /**
65
+ * 保存 SSH 服务器配置 ~/.seno/servers.json
66
+ */
67
+ export declare function saveServers(config: ServersConfig): Promise<void>;