imtoagent 0.3.2 → 0.3.3
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/bin/imtoagent-real +2 -2
- package/modules/cli/setup.ts +154 -19
- package/package.json +1 -1
package/bin/imtoagent-real
CHANGED
|
@@ -158,7 +158,7 @@ async function cmdStart() {
|
|
|
158
158
|
const pkgDir = path.resolve(import.meta.dirname, '..');
|
|
159
159
|
const indexFile = path.join(pkgDir, 'index.ts');
|
|
160
160
|
|
|
161
|
-
const child = Bun.spawn([
|
|
161
|
+
const child = Bun.spawn([process.execPath, 'run', indexFile], {
|
|
162
162
|
cwd: dataDir,
|
|
163
163
|
env: { ...process.env, IMTOAGENT_HOME: dataDir },
|
|
164
164
|
stdout: 'pipe',
|
|
@@ -384,7 +384,7 @@ async function cmdDaemon(): Promise<void> {
|
|
|
384
384
|
|
|
385
385
|
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
|
|
386
386
|
|
|
387
|
-
const child = Bun.spawn([
|
|
387
|
+
const child = Bun.spawn([process.execPath, 'run', indexFile], {
|
|
388
388
|
cwd: dataDir,
|
|
389
389
|
env: { ...process.env, IMTOAGENT_HOME: dataDir },
|
|
390
390
|
stdout: 'pipe',
|
package/modules/cli/setup.ts
CHANGED
|
@@ -107,7 +107,7 @@ async function promptText(label: string, defaultValue = ''): Promise<string> {
|
|
|
107
107
|
while (true) {
|
|
108
108
|
const key = await readKey();
|
|
109
109
|
|
|
110
|
-
if (key === KEY.ENTER) {
|
|
110
|
+
if (key === KEY.ENTER || key === '\n') {
|
|
111
111
|
break;
|
|
112
112
|
} else if (key === KEY.ESC) {
|
|
113
113
|
process.stdout.write('\x1B[0K\n');
|
|
@@ -119,13 +119,13 @@ async function promptText(label: string, defaultValue = ''): Promise<string> {
|
|
|
119
119
|
}
|
|
120
120
|
} else if (key === KEY.UP || key === KEY.DOWN) {
|
|
121
121
|
// 忽略方向键
|
|
122
|
-
} else if (key.length === 1 && key !== KEY.SPACE) {
|
|
123
|
-
// 普通字符(空格单独处理)
|
|
124
|
-
buf.push(key);
|
|
125
|
-
process.stdout.write(key);
|
|
126
122
|
} else if (key === KEY.SPACE) {
|
|
127
123
|
buf.push(' ');
|
|
128
124
|
process.stdout.write(' ');
|
|
125
|
+
} else if (key.length >= 1 && !key.startsWith('\x1b')) {
|
|
126
|
+
// 普通字符 / 粘贴的多字符块(不含转义序列的文本)
|
|
127
|
+
buf.push(key);
|
|
128
|
+
process.stdout.write(key);
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
} finally {
|
|
@@ -171,6 +171,91 @@ async function confirm(label: string, defaultYes = true): Promise<boolean | -1>
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
// ================================================================
|
|
175
|
+
// 供应商预设
|
|
176
|
+
// ================================================================
|
|
177
|
+
|
|
178
|
+
interface ProviderPreset {
|
|
179
|
+
name: string;
|
|
180
|
+
baseUrl: string;
|
|
181
|
+
format: 'openai' | 'anthropic';
|
|
182
|
+
models: string[];
|
|
183
|
+
hint?: string; // 额外说明
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const PROVIDER_PRESETS: ProviderPreset[] = [
|
|
187
|
+
{
|
|
188
|
+
name: 'DashScope(阿里百炼)',
|
|
189
|
+
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
190
|
+
format: 'openai',
|
|
191
|
+
models: ['qwen-max', 'qwen-plus', 'qwen-turbo'],
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: 'DeepSeek',
|
|
195
|
+
baseUrl: 'https://api.deepseek.com/v1',
|
|
196
|
+
format: 'openai',
|
|
197
|
+
models: ['deepseek-chat', 'deepseek-reasoner'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: '智谱 AI(Zhipu)',
|
|
201
|
+
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
|
|
202
|
+
format: 'openai',
|
|
203
|
+
models: ['glm-4-plus', 'glm-4-flash', 'glm-4'],
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: 'MiniMax',
|
|
207
|
+
baseUrl: 'https://api.minimax.io/v1',
|
|
208
|
+
format: 'openai',
|
|
209
|
+
models: ['MiniMax-M2.5', 'MiniMax-M1'],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: '硅基流动(SiliconFlow)',
|
|
213
|
+
baseUrl: 'https://api.siliconflow.cn/v1',
|
|
214
|
+
format: 'openai',
|
|
215
|
+
models: ['Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-V3'],
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'Moonshot(月之暗面)',
|
|
219
|
+
baseUrl: 'https://api.moonshot.cn/v1',
|
|
220
|
+
format: 'openai',
|
|
221
|
+
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'OpenAI',
|
|
225
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
226
|
+
format: 'openai',
|
|
227
|
+
models: ['gpt-4o', 'gpt-4o-mini', 'o3', 'o4-mini'],
|
|
228
|
+
hint: '需要代理才能访问',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'Anthropic',
|
|
232
|
+
baseUrl: 'https://api.anthropic.com',
|
|
233
|
+
format: 'anthropic',
|
|
234
|
+
models: ['claude-sonnet-4-20250514', 'claude-haiku-4-20250514', 'claude-opus-4-20250514'],
|
|
235
|
+
hint: '需要代理才能访问',
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: 'Gemini(Google)',
|
|
239
|
+
baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',
|
|
240
|
+
format: 'openai',
|
|
241
|
+
models: ['gemini-2.5-pro', 'gemini-2.5-flash'],
|
|
242
|
+
hint: '需要代理才能访问',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'xAI(Grok)',
|
|
246
|
+
baseUrl: 'https://api.x.ai/v1',
|
|
247
|
+
format: 'openai',
|
|
248
|
+
models: ['grok-3', 'grok-3-mini'],
|
|
249
|
+
hint: '需要代理才能访问',
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'Ollama(本地)',
|
|
253
|
+
baseUrl: 'http://localhost:11434/v1',
|
|
254
|
+
format: 'openai',
|
|
255
|
+
models: ['qwen2.5', 'llama3.2', 'deepseek-r1'],
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
|
|
174
259
|
// ================================================================
|
|
175
260
|
// IM 平台配置定义
|
|
176
261
|
// ================================================================
|
|
@@ -399,26 +484,76 @@ export async function runSetupWizard(): Promise<void> {
|
|
|
399
484
|
let addingProviders = true;
|
|
400
485
|
while (addingProviders) {
|
|
401
486
|
console.log('--- 添加新供应商 ---\n');
|
|
402
|
-
const provName = await promptText('供应商名称 (如 deepseek, dashscope)');
|
|
403
|
-
if ((provName as any) === -1) { addingProviders = false; continue; }
|
|
404
|
-
if (!provName) { addingProviders = false; continue; }
|
|
405
487
|
|
|
406
|
-
|
|
407
|
-
|
|
488
|
+
// 选择预设 or 自定义
|
|
489
|
+
const presetOptions = PROVIDER_PRESETS.map(p => {
|
|
490
|
+
const tag = p.hint ? ` ${p.hint}` : '';
|
|
491
|
+
return `${p.name}${tag}`;
|
|
492
|
+
});
|
|
493
|
+
presetOptions.push('自定义...');
|
|
494
|
+
|
|
495
|
+
const presetIdx = await selectMenu('选择供应商', presetOptions);
|
|
496
|
+
if (presetIdx === -1) { addingProviders = false; continue; }
|
|
497
|
+
|
|
498
|
+
let provName: string, baseUrl: string, format: 'openai' | 'anthropic', models: string[];
|
|
499
|
+
|
|
500
|
+
if (presetIdx < PROVIDER_PRESETS.length) {
|
|
501
|
+
// 使用预设
|
|
502
|
+
const preset = PROVIDER_PRESETS[presetIdx];
|
|
503
|
+
provName = preset.name.split('(')[0].trim().toLowerCase(); // 取简短名称
|
|
504
|
+
baseUrl = preset.baseUrl;
|
|
505
|
+
format = preset.format;
|
|
506
|
+
models = [...preset.models];
|
|
507
|
+
|
|
508
|
+
console.log(`\n✅ 预设已加载:`);
|
|
509
|
+
console.log(` 名称: ${provName}`);
|
|
510
|
+
console.log(` URL: ${preset.baseUrl}`);
|
|
511
|
+
console.log(` 格式: ${preset.format}`);
|
|
512
|
+
console.log(` 模型: ${preset.models.join(', ')}\n`);
|
|
513
|
+
|
|
514
|
+
// 确认/修改简短名称
|
|
515
|
+
const nameEdit = await promptText('供应商名称(留空确认)', provName);
|
|
516
|
+
if ((nameEdit as any) === -1) continue;
|
|
517
|
+
provName = nameEdit || provName;
|
|
518
|
+
|
|
519
|
+
// 确认/修改 Base URL
|
|
520
|
+
const urlEdit = await promptText('Base URL', baseUrl);
|
|
521
|
+
if ((urlEdit as any) === -1) continue;
|
|
522
|
+
baseUrl = urlEdit || baseUrl;
|
|
523
|
+
|
|
524
|
+
// 确认/修改模型列表
|
|
525
|
+
const modelsEdit = await promptText('模型列表(逗号分隔)', models.join(', '));
|
|
526
|
+
if ((modelsEdit as any) === -1) continue;
|
|
527
|
+
if (modelsEdit) models = modelsEdit.split(',').map(s => s.trim()).filter(Boolean);
|
|
528
|
+
|
|
529
|
+
if (providers[provName]) {
|
|
530
|
+
console.log(`⚠️ 供应商 "${provName}" 已存在,将覆盖\n`);
|
|
531
|
+
}
|
|
532
|
+
} else {
|
|
533
|
+
// 自定义
|
|
534
|
+
provName = await promptText('供应商名称 (如 deepseek, dashscope)');
|
|
535
|
+
if ((provName as any) === -1) { addingProviders = false; continue; }
|
|
536
|
+
if (!provName) { addingProviders = false; continue; }
|
|
537
|
+
if (providers[provName]) {
|
|
538
|
+
console.log(`⚠️ 供应商 "${provName}" 已存在,将覆盖\n`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
baseUrl = await promptText('Base URL (如 https://api.deepseek.com/v1)');
|
|
542
|
+
if ((baseUrl as any) === -1) continue;
|
|
543
|
+
const modelsStr = await promptText('模型列表 (逗号分隔)');
|
|
544
|
+
if ((modelsStr as any) === -1) continue;
|
|
545
|
+
models = (modelsStr || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
546
|
+
|
|
547
|
+
const formatIdx = await selectMenu('API 格式', ['openai', 'anthropic']);
|
|
548
|
+
if (formatIdx === -1) continue;
|
|
549
|
+
format = ['openai', 'anthropic'][formatIdx];
|
|
408
550
|
}
|
|
409
551
|
|
|
410
|
-
|
|
411
|
-
if ((baseUrl as any) === -1) continue;
|
|
552
|
+
// API Key(所有路径都需要)
|
|
412
553
|
const apiKey = await promptText('API Key');
|
|
413
554
|
if ((apiKey as any) === -1) continue;
|
|
414
|
-
const modelsStr = await promptText('模型列表 (逗号分隔,如 deepseek-v4-pro,deepseek-v4-flash)');
|
|
415
|
-
if ((modelsStr as any) === -1) continue;
|
|
416
|
-
const models = (modelsStr || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
417
|
-
|
|
418
|
-
const formatIdx = await selectMenu('API 格式', ['openai', 'anthropic']);
|
|
419
|
-
if (formatIdx === -1) continue;
|
|
420
|
-
const format = ['openai', 'anthropic'][formatIdx];
|
|
421
555
|
|
|
556
|
+
// 价格(可选)
|
|
422
557
|
const priceInput = await promptText('价格 (入/出 每百万 Token,如 0.55,2.19,留空跳过)');
|
|
423
558
|
if ((priceInput as any) === -1) continue;
|
|
424
559
|
|