@zhin.js/scaffold-wizard 0.1.2 → 0.1.4

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.
@@ -13,19 +13,19 @@ export const ADAPTERS_ESSENTIALS_URL = 'https://zhin.js.org/essentials/adapters'
13
13
  /** 各适配器文档页(与 docs/adapters/*.md 同步) */
14
14
  export const adapterDocsUrl = (slug: string) => `https://zhin.js.org/adapters/${slug}`;
15
15
 
16
- export interface BotConfigureContext {
16
+ export interface EndpointConfigureContext {
17
17
  envVars: Record<string, string>;
18
18
  markRequiresDatabase: () => void;
19
19
  }
20
20
 
21
- export async function configureTelegramBot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
21
+ export async function configureTelegramEndpoint(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
22
22
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('telegram')));
23
23
 
24
- const { botName } = await inquirer.prompt([
24
+ const { endpointName } = await inquirer.prompt([
25
25
  {
26
26
  type: 'input',
27
- name: 'botName',
28
- message: ' Bot 标识名称:',
27
+ name: 'endpointName',
28
+ message: ' Endpoint 标识名称:',
29
29
  default: 'telegram-bot',
30
30
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
31
31
  },
@@ -35,7 +35,7 @@ export async function configureTelegramBot(ctx: BotConfigureContext): Promise<Re
35
35
  {
36
36
  type: 'password',
37
37
  name: 'token',
38
- message: ' Telegram Bot Token(@BotFather 获取):',
38
+ message: ' Telegram Endpoint Token(@BotFather 获取):',
39
39
  validate: (v: string) => (v.trim() ? true : 'Token 不能为空'),
40
40
  },
41
41
  ]);
@@ -60,9 +60,9 @@ export async function configureTelegramBot(ctx: BotConfigureContext): Promise<Re
60
60
  },
61
61
  ]);
62
62
 
63
- const botConfig: Record<string, unknown> = {
63
+ const endpointConfig: Record<string, unknown> = {
64
64
  context: 'telegram',
65
- name: botName.trim(),
65
+ name: endpointName.trim(),
66
66
  token: '${TELEGRAM_TOKEN}',
67
67
  polling: transport === 'polling',
68
68
  };
@@ -70,7 +70,7 @@ export async function configureTelegramBot(ctx: BotConfigureContext): Promise<Re
70
70
  if (transport === 'webhook') {
71
71
  console.log('');
72
72
  console.log(chalk.yellow(' Webhook 前置条件:'));
73
- console.log(chalk.gray(' • Bot 进程需绑定可被 Telegram 访问的 HTTPS 域名(有效 TLS 证书)'));
73
+ console.log(chalk.gray(' • Endpoint 进程需绑定可被 Telegram 访问的 HTTPS 域名(有效 TLS 证书)'));
74
74
  console.log(chalk.gray(' • 在 @BotFather 可配合 setWebhook,或由 Telegraf 在 launch 时注册'));
75
75
  console.log(chalk.gray(' • 防火墙/反向代理需放行 webhook.port(默认由 Telegraf 监听)'));
76
76
 
@@ -104,26 +104,26 @@ export async function configureTelegramBot(ctx: BotConfigureContext): Promise<Re
104
104
  },
105
105
  ]);
106
106
 
107
- botConfig.polling = false;
108
- botConfig.webhook = {
107
+ endpointConfig.polling = false;
108
+ endpointConfig.webhook = {
109
109
  domain: webhook.domain.trim(),
110
110
  path: webhook.path.trim(),
111
111
  port: parseInt(webhook.port, 10),
112
112
  };
113
113
  }
114
114
 
115
- return botConfig;
115
+ return endpointConfig;
116
116
  }
117
117
 
118
- export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
118
+ export async function configureGitHubEndpoint(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
119
119
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('github')));
120
120
  ctx.markRequiresDatabase();
121
121
 
122
- const { botName } = await inquirer.prompt([
122
+ const { endpointName } = await inquirer.prompt([
123
123
  {
124
124
  type: 'input',
125
- name: 'botName',
126
- message: ' Bot 标识名称:',
125
+ name: 'endpointName',
126
+ message: ' Endpoint 标识名称:',
127
127
  default: 'github-bot',
128
128
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
129
129
  },
@@ -148,9 +148,9 @@ export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Reco
148
148
  },
149
149
  ]);
150
150
 
151
- const botConfig: Record<string, unknown> = {
151
+ const endpointConfig: Record<string, unknown> = {
152
152
  context: 'github',
153
- name: botName.trim(),
153
+ name: endpointName.trim(),
154
154
  };
155
155
 
156
156
  if (authMode === 'github_app') {
@@ -173,8 +173,8 @@ export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Reco
173
173
  ]);
174
174
 
175
175
  ctx.envVars.GITHUB_APP_ID = appConfig.app_id.trim();
176
- botConfig.app_id = '${GITHUB_APP_ID}';
177
- botConfig.private_key = appConfig.private_key.trim();
176
+ endpointConfig.app_id = '${GITHUB_APP_ID}';
177
+ endpointConfig.private_key = appConfig.private_key.trim();
178
178
  } else {
179
179
  console.log(chalk.gray(' 请确保已执行 gh auth login,且 gh 在 PATH 中'));
180
180
  }
@@ -221,8 +221,8 @@ export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Reco
221
221
  ]);
222
222
 
223
223
  ctx.envVars.GITHUB_WEBHOOK_SECRET = webhook.webhook_secret;
224
- botConfig.webhook_secret = '${GITHUB_WEBHOOK_SECRET}';
225
- botConfig.webhook_path = webhook.webhook_path.trim();
224
+ endpointConfig.webhook_secret = '${GITHUB_WEBHOOK_SECRET}';
225
+ endpointConfig.webhook_path = webhook.webhook_path.trim();
226
226
  } else {
227
227
  const { poll_interval } = await inquirer.prompt([
228
228
  {
@@ -237,7 +237,7 @@ export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Reco
237
237
  },
238
238
  },
239
239
  ]);
240
- botConfig.poll_interval = parseInt(poll_interval, 10);
240
+ endpointConfig.poll_interval = parseInt(poll_interval, 10);
241
241
  }
242
242
 
243
243
  const { enableMcp } = await inquirer.prompt([
@@ -261,10 +261,10 @@ export async function configureGitHubBot(ctx: BotConfigureContext): Promise<Reco
261
261
  ctx.envVars.GITHUB_PERSONAL_ACCESS_TOKEN = pat;
262
262
  }
263
263
 
264
- return botConfig;
264
+ return endpointConfig;
265
265
  }
266
266
 
267
- export async function configureOneBot11Bot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
267
+ export async function configureOneBot11Bot(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
268
268
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('onebot11')));
269
269
 
270
270
  const { connection } = await inquirer.prompt([
@@ -273,27 +273,27 @@ export async function configureOneBot11Bot(ctx: BotConfigureContext): Promise<Re
273
273
  name: 'connection',
274
274
  message: ' 连接方式:',
275
275
  choices: [
276
- { name: '正向 WebSocket (ws) — 本 Bot 连接 OneBot 实现', value: 'ws' },
276
+ { name: '正向 WebSocket (ws) — 本 Endpoint 连接 OneBot 实现', value: 'ws' },
277
277
  { name: '反向 WebSocket (wss) — OneBot 实现连本 Bot(需 host-router)', value: 'wss' },
278
278
  ],
279
279
  default: 'ws',
280
280
  },
281
281
  ]);
282
282
 
283
- const { botName } = await inquirer.prompt([
283
+ const { endpointName } = await inquirer.prompt([
284
284
  {
285
285
  type: 'input',
286
- name: 'botName',
287
- message: ' Bot 标识名称:',
286
+ name: 'endpointName',
287
+ message: ' Endpoint 标识名称:',
288
288
  default: 'onebot-bot',
289
289
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
290
290
  },
291
291
  ]);
292
292
 
293
- const botConfig: Record<string, unknown> = {
293
+ const endpointConfig: Record<string, unknown> = {
294
294
  context: 'onebot11',
295
295
  connection,
296
- name: botName.trim(),
296
+ name: endpointName.trim(),
297
297
  };
298
298
 
299
299
  if (connection === 'ws') {
@@ -306,7 +306,7 @@ export async function configureOneBot11Bot(ctx: BotConfigureContext): Promise<Re
306
306
  validate: (v: string) => (v.trim() ? true : '地址不能为空'),
307
307
  },
308
308
  ]);
309
- botConfig.url = url.trim();
309
+ endpointConfig.url = url.trim();
310
310
  } else {
311
311
  console.log(chalk.gray(' 反向 WS 需启用 @zhin.js/host-router,OneBot 实现配置连接到此 Bot'));
312
312
  const { path: wsPath } = await inquirer.prompt([
@@ -318,7 +318,7 @@ export async function configureOneBot11Bot(ctx: BotConfigureContext): Promise<Re
318
318
  validate: (v: string) => (v.trim() ? true : '路径不能为空'),
319
319
  },
320
320
  ]);
321
- botConfig.path = wsPath.trim();
321
+ endpointConfig.path = wsPath.trim();
322
322
  }
323
323
 
324
324
  const { accessToken } = await inquirer.prompt([
@@ -331,20 +331,20 @@ export async function configureOneBot11Bot(ctx: BotConfigureContext): Promise<Re
331
331
  ]);
332
332
  if (accessToken?.trim()) {
333
333
  ctx.envVars.ONEBOT11_ACCESS_TOKEN = accessToken.trim();
334
- botConfig.access_token = '${ONEBOT11_ACCESS_TOKEN}';
334
+ endpointConfig.access_token = '${ONEBOT11_ACCESS_TOKEN}';
335
335
  }
336
336
 
337
- return botConfig;
337
+ return endpointConfig;
338
338
  }
339
339
 
340
- export async function configureQQBot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
340
+ export async function configureQQBot(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
341
341
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('qq')));
342
342
 
343
343
  const credentials = await inquirer.prompt([
344
344
  {
345
345
  type: 'input',
346
346
  name: 'name',
347
- message: ' Bot 标识名称:',
347
+ message: ' Endpoint 标识名称:',
348
348
  default: 'qq-bot',
349
349
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
350
350
  },
@@ -403,7 +403,7 @@ export async function configureQQBot(ctx: BotConfigureContext): Promise<Record<s
403
403
  };
404
404
  }
405
405
 
406
- export async function configureDiscordBot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
406
+ export async function configureDiscordEndpoint(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
407
407
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('discord')));
408
408
 
409
409
  const { connection } = await inquirer.prompt([
@@ -419,27 +419,27 @@ export async function configureDiscordBot(ctx: BotConfigureContext): Promise<Rec
419
419
  },
420
420
  ]);
421
421
 
422
- const { botName, token } = await inquirer.prompt([
422
+ const { endpointName, token } = await inquirer.prompt([
423
423
  {
424
424
  type: 'input',
425
- name: 'botName',
426
- message: ' Bot 标识名称:',
425
+ name: 'endpointName',
426
+ message: ' Endpoint 标识名称:',
427
427
  default: 'discord-bot',
428
428
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
429
429
  },
430
430
  {
431
431
  type: 'password',
432
432
  name: 'token',
433
- message: ' Bot Token:',
433
+ message: ' Endpoint Token:',
434
434
  validate: (v: string) => (v.trim() ? true : 'Token 不能为空'),
435
435
  },
436
436
  ]);
437
437
  ctx.envVars.DISCORD_TOKEN = token;
438
438
 
439
- const botConfig: Record<string, unknown> = {
439
+ const endpointConfig: Record<string, unknown> = {
440
440
  context: 'discord',
441
441
  connection,
442
- name: botName.trim(),
442
+ name: endpointName.trim(),
443
443
  token: '${DISCORD_TOKEN}',
444
444
  };
445
445
 
@@ -465,15 +465,15 @@ export async function configureDiscordBot(ctx: BotConfigureContext): Promise<Rec
465
465
  default: '/discord/interactions',
466
466
  },
467
467
  ]);
468
- botConfig.applicationId = interactions.applicationId.trim();
469
- botConfig.publicKey = interactions.publicKey.trim();
470
- botConfig.interactionsPath = interactions.interactionsPath.trim();
468
+ endpointConfig.applicationId = interactions.applicationId.trim();
469
+ endpointConfig.publicKey = interactions.publicKey.trim();
470
+ endpointConfig.interactionsPath = interactions.interactionsPath.trim();
471
471
  }
472
472
 
473
- return botConfig;
473
+ return endpointConfig;
474
474
  }
475
475
 
476
- export async function configureSlackBot(ctx: BotConfigureContext): Promise<Record<string, unknown>> {
476
+ export async function configureSlackEndpoint(ctx: EndpointConfigureContext): Promise<Record<string, unknown>> {
477
477
  console.log(chalk.gray(' 文档: ' + adapterDocsUrl('slack')));
478
478
 
479
479
  const { socketMode } = await inquirer.prompt([
@@ -489,18 +489,18 @@ export async function configureSlackBot(ctx: BotConfigureContext): Promise<Recor
489
489
  },
490
490
  ]);
491
491
 
492
- const { botName, token, signingSecret } = await inquirer.prompt([
492
+ const { endpointName, token, signingSecret } = await inquirer.prompt([
493
493
  {
494
494
  type: 'input',
495
- name: 'botName',
496
- message: ' Bot 标识名称:',
495
+ name: 'endpointName',
496
+ message: ' Endpoint 标识名称:',
497
497
  default: 'slack-bot',
498
498
  validate: (v: string) => (v.trim() ? true : '名称不能为空'),
499
499
  },
500
500
  {
501
501
  type: 'password',
502
502
  name: 'token',
503
- message: ' Bot Token (xoxb-...):',
503
+ message: ' Endpoint Token (xoxb-...):',
504
504
  validate: (v: string) => (v.trim() ? true : '不能为空'),
505
505
  },
506
506
  {
@@ -514,9 +514,9 @@ export async function configureSlackBot(ctx: BotConfigureContext): Promise<Recor
514
514
  ctx.envVars.SLACK_BOT_TOKEN = token;
515
515
  ctx.envVars.SLACK_SIGNING_SECRET = signingSecret;
516
516
 
517
- const botConfig: Record<string, unknown> = {
517
+ const endpointConfig: Record<string, unknown> = {
518
518
  context: 'slack',
519
- name: botName.trim(),
519
+ name: endpointName.trim(),
520
520
  token: '${SLACK_BOT_TOKEN}',
521
521
  signingSecret: '${SLACK_SIGNING_SECRET}',
522
522
  socketMode: socketMode === 'true',
@@ -532,7 +532,7 @@ export async function configureSlackBot(ctx: BotConfigureContext): Promise<Recor
532
532
  },
533
533
  ]);
534
534
  ctx.envVars.SLACK_APP_TOKEN = appToken;
535
- botConfig.appToken = '${SLACK_APP_TOKEN}';
535
+ endpointConfig.appToken = '${SLACK_APP_TOKEN}';
536
536
  } else {
537
537
  console.log(chalk.yellow(' HTTP 模式需公网可达并配置 Slack Event Subscriptions URL'));
538
538
  const { port } = await inquirer.prompt([
@@ -543,8 +543,8 @@ export async function configureSlackBot(ctx: BotConfigureContext): Promise<Recor
543
543
  default: '3000',
544
544
  },
545
545
  ]);
546
- botConfig.port = parseInt(port, 10);
546
+ endpointConfig.port = parseInt(port, 10);
547
547
  }
548
548
 
549
- return botConfig;
549
+ return endpointConfig;
550
550
  }
package/src/adapter.ts CHANGED
@@ -3,18 +3,18 @@ import chalk from 'chalk';
3
3
  import {
4
4
  ADAPTERS_DOCS_URL,
5
5
  adapterDocsUrl,
6
- configureDiscordBot,
7
- configureGitHubBot,
6
+ configureDiscordEndpoint,
7
+ configureGitHubEndpoint,
8
8
  configureOneBot11Bot,
9
9
  configureQQBot,
10
- configureSlackBot,
11
- configureTelegramBot,
10
+ configureSlackEndpoint,
11
+ configureTelegramEndpoint,
12
12
  } from './adapter-configurers.js';
13
13
 
14
14
  export interface AdapterSetupResult {
15
15
  packages: string[];
16
16
  plugins: string[];
17
- bots: Array<Record<string, any>>;
17
+ endpoints: Array<Record<string, any>>;
18
18
  envVars: Record<string, string>;
19
19
  /** 所选适配器需要 database 插件(如 GitHub 订阅/OAuth 表) */
20
20
  requiresDatabase?: boolean;
@@ -33,7 +33,7 @@ interface AdapterDefinition {
33
33
  /** 文档:zhin.js.org/adapters/<slug>;索引见 ADAPTERS_DOCS_URL */
34
34
  docUrl?: string;
35
35
  requiresDatabase?: boolean;
36
- configure?: (ctx: import('./adapter-configurers.js').BotConfigureContext) => Promise<Record<string, unknown>>;
36
+ configure?: (ctx: import('./adapter-configurers.js').EndpointConfigureContext) => Promise<Record<string, unknown>>;
37
37
  fields: AdapterField[];
38
38
  }
39
39
 
@@ -89,10 +89,10 @@ const ADAPTERS: AdapterDefinition[] = [
89
89
  package: '@zhin.js/adapter-kook',
90
90
  plugin: '@zhin.js/adapter-kook',
91
91
  needsHttp: true,
92
- description: 'KOOK 语音平台 Bot',
93
- setupHint: '在 KOOK 开发者中心创建 Bot 并复制 Token;需配置 Webhook 回调地址(公网或内网穿透)。',
92
+ description: 'KOOK 语音平台 Endpoint',
93
+ setupHint: '在 KOOK 开发者中心创建 Endpoint 并复制 Token;需配置 Webhook 回调地址(公网或内网穿透)。',
94
94
  fields: [
95
- { key: 'token', message: 'KOOK Bot Token:', required: true, type: 'password', envKey: 'KOOK_TOKEN' },
95
+ { key: 'token', message: 'KOOK Endpoint Token:', required: true, type: 'password', envKey: 'KOOK_TOKEN' },
96
96
  ],
97
97
  },
98
98
  {
@@ -104,7 +104,7 @@ const ADAPTERS: AdapterDefinition[] = [
104
104
  description: 'Discord(Gateway 或 Interactions)',
105
105
  setupHint: 'Developer Portal 创建 Bot;Gateway 用 Token,Interactions 需 Application ID + Public Key。',
106
106
  docUrl: adapterDocsUrl('discord'),
107
- configure: configureDiscordBot,
107
+ configure: configureDiscordEndpoint,
108
108
  fields: [],
109
109
  },
110
110
  {
@@ -116,7 +116,7 @@ const ADAPTERS: AdapterDefinition[] = [
116
116
  description: 'Telegram Bot(polling / webhook 可选)',
117
117
  setupHint: '@BotFather 获取 Token;polling 适合本地,webhook 需 HTTPS 公网域名。',
118
118
  docUrl: adapterDocsUrl('telegram'),
119
- configure: configureTelegramBot,
119
+ configure: configureTelegramEndpoint,
120
120
  fields: [],
121
121
  },
122
122
  {
@@ -128,7 +128,7 @@ const ADAPTERS: AdapterDefinition[] = [
128
128
  description: 'Slack(Socket Mode 或 HTTP Events)',
129
129
  setupHint: 'Socket Mode 无需公网;HTTP 模式需配置 Event Subscriptions URL。',
130
130
  docUrl: adapterDocsUrl('slack'),
131
- configure: configureSlackBot,
131
+ configure: configureSlackEndpoint,
132
132
  fields: [],
133
133
  },
134
134
  {
@@ -213,19 +213,19 @@ const ADAPTERS: AdapterDefinition[] = [
213
213
  setupHint: 'GitHub App 或 gh CLI;Webhook 用 /pub/github/webhook;需 database 存订阅与 OAuth。',
214
214
  docUrl: adapterDocsUrl('github'),
215
215
  requiresDatabase: true,
216
- configure: configureGitHubBot,
216
+ configure: configureGitHubEndpoint,
217
217
  fields: [],
218
218
  },
219
219
  ];
220
220
 
221
221
  /**
222
- * 适配器选择与 Bot 配置引导向导
222
+ * 适配器选择与 Endpoint 配置引导向导
223
223
  */
224
224
  export async function configureAdapters(): Promise<AdapterSetupResult> {
225
225
  console.log('');
226
226
  console.log(chalk.blue('🔌 配置聊天适配器'));
227
227
  console.log(chalk.gray(' Sandbox 适合本地调试;生产环境请额外勾选目标 IM 平台。'));
228
- console.log(chalk.gray(' 带 Webhook 的适配器需要 Bot 可被公网访问(或使用内网穿透)。'));
228
+ console.log(chalk.gray(' 带 Webhook 的适配器需要 Endpoint 可被公网访问(或使用内网穿透)。'));
229
229
 
230
230
  const { selectedAdapters } = await inquirer.prompt([
231
231
  {
@@ -266,7 +266,7 @@ export async function configureAdapters(): Promise<AdapterSetupResult> {
266
266
  const result: AdapterSetupResult = {
267
267
  packages: [],
268
268
  plugins: [],
269
- bots: [],
269
+ endpoints: [],
270
270
  envVars: {},
271
271
  requiresDatabase: false,
272
272
  };
@@ -303,7 +303,7 @@ export async function configureAdapters(): Promise<AdapterSetupResult> {
303
303
 
304
304
  if (adapterDef.configure) {
305
305
  let markedDb = false;
306
- const botConfig = await adapterDef.configure({
306
+ const endpointConfig = await adapterDef.configure({
307
307
  envVars: result.envVars,
308
308
  markRequiresDatabase: () => {
309
309
  markedDb = true;
@@ -311,11 +311,11 @@ export async function configureAdapters(): Promise<AdapterSetupResult> {
311
311
  },
312
312
  });
313
313
  if (markedDb) result.requiresDatabase = true;
314
- result.bots.push(botConfig);
314
+ result.endpoints.push(endpointConfig);
315
315
  continue;
316
316
  }
317
317
 
318
- const botConfig: Record<string, any> = {
318
+ const endpointConfig: Record<string, any> = {
319
319
  context: adapterDef.value,
320
320
  };
321
321
 
@@ -343,13 +343,13 @@ export async function configureAdapters(): Promise<AdapterSetupResult> {
343
343
  if (field.envKey) {
344
344
  // 敏感信息存 .env,配置引用环境变量
345
345
  result.envVars[field.envKey] = value || '';
346
- botConfig[field.key] = `\${${field.envKey}}`;
346
+ endpointConfig[field.key] = `\${${field.envKey}}`;
347
347
  } else {
348
- botConfig[field.key] = value;
348
+ endpointConfig[field.key] = value;
349
349
  }
350
350
  }
351
351
 
352
- result.bots.push(botConfig);
352
+ result.endpoints.push(endpointConfig);
353
353
  }
354
354
 
355
355
  return result;
@@ -370,7 +370,7 @@ export function generateAdapterEnvVars(result: AdapterSetupResult): string {
370
370
  }
371
371
 
372
372
  /**
373
- * 将 bot 配置项格式化为 YAML 行
373
+ * 将 Endpoint 配置项格式化为 YAML 行
374
374
  */
375
375
  function appendYamlValue(lines: string[], key: string, value: unknown, indent: number): void {
376
376
  const pad = ' '.repeat(indent);
@@ -405,20 +405,20 @@ function appendYamlValue(lines: string[], key: string, value: unknown, indent: n
405
405
  }
406
406
 
407
407
  /**
408
- * 生成 YAML 格式的 bots 配置段
408
+ * 生成 YAML 格式的 endpoints 配置段
409
409
  */
410
- export function generateBotsConfigYaml(result: AdapterSetupResult): string {
411
- if (result.bots.length === 0) {
410
+ export function generateEndpointsConfigYaml(result: AdapterSetupResult): string {
411
+ if (result.endpoints.length === 0) {
412
412
  return `
413
413
 
414
- # Sandbox:Remote Console 打开「沙盒」页并通过 WebSocket 连接时自动创建 bot
415
- bots: []
414
+ # Sandbox:Remote Console 打开「沙盒」页并通过 WebSocket 连接时自动创建 Endpoint
415
+ endpoints: []
416
416
  `;
417
417
  }
418
418
 
419
- const lines: string[] = ['', 'bots:'];
420
- for (const bot of result.bots) {
421
- const { context, ...config } = bot;
419
+ const lines: string[] = ['', 'endpoints:'];
420
+ for (const entry of result.endpoints) {
421
+ const { context, ...config } = entry;
422
422
  lines.push(` - context: ${context}`);
423
423
  for (const [key, value] of Object.entries(config)) {
424
424
  appendYamlValue(lines, key, value, 2);
@@ -429,15 +429,15 @@ bots: []
429
429
  }
430
430
 
431
431
  /**
432
- * 生成 TOML 格式的 bots 配置段
432
+ * 生成 TOML 格式的 endpoints 配置段
433
433
  */
434
- export function generateBotsConfigToml(result: AdapterSetupResult): string {
435
- if (result.bots.length === 0) return '';
434
+ export function generateEndpointsConfigToml(result: AdapterSetupResult): string {
435
+ if (result.endpoints.length === 0) return '';
436
436
 
437
437
  const lines: string[] = [''];
438
- for (const bot of result.bots) {
439
- lines.push('[[bots]]');
440
- for (const [key, value] of Object.entries(bot)) {
438
+ for (const entry of result.endpoints) {
439
+ lines.push('[[endpoints]]');
440
+ for (const [key, value] of Object.entries(entry)) {
441
441
  if (typeof value === 'string') {
442
442
  lines.push(`${key} = "${value.replace(/"/g, '\\"')}"`);
443
443
  } else {
@@ -450,11 +450,11 @@ export function generateBotsConfigToml(result: AdapterSetupResult): string {
450
450
  }
451
451
 
452
452
  /**
453
- * 生成 JSON 格式的 bots 配置段
453
+ * 生成 JSON 格式的 endpoints 配置段
454
454
  */
455
- export function generateBotsConfigJSON(result: AdapterSetupResult): string {
456
- if (result.bots.length === 0) return '';
457
- return ` "bots": ${JSON.stringify(result.bots, null, 4).replace(/^/gm, ' ').trimStart()},`;
455
+ export function generateEndpointsConfigJSON(result: AdapterSetupResult): string {
456
+ if (result.endpoints.length === 0) return '';
457
+ return ` "endpoints": ${JSON.stringify(result.endpoints, null, 4).replace(/^/gm, ' ').trimStart()},`;
458
458
  }
459
459
 
460
460
  /**
@@ -462,21 +462,21 @@ export function generateBotsConfigJSON(result: AdapterSetupResult): string {
462
462
  */
463
463
  export function getAdapterSetupNotes(result: AdapterSetupResult): string[] {
464
464
  const notes: string[] = [];
465
- for (const bot of result.bots) {
466
- const context = bot.context as string;
467
- if (context === 'telegram' && bot.polling === false) {
465
+ for (const entry of result.endpoints) {
466
+ const context = entry.context as string;
467
+ if (context === 'telegram' && entry.polling === false) {
468
468
  notes.push('Telegram Webhook: 确保 HTTPS 域名可从公网访问,且 webhook.port 已放行');
469
469
  }
470
- if (context === 'telegram' && bot.polling !== false) {
470
+ if (context === 'telegram' && entry.polling !== false) {
471
471
  notes.push('Telegram polling: 本地开发可直接 pnpm dev,无需公网');
472
472
  }
473
473
  if (context === 'github') {
474
- if (bot.webhook_secret) {
474
+ if (entry.webhook_secret) {
475
475
  notes.push('GitHub Webhook: App 设置 URL 为 https://<域名>/pub/github/webhook');
476
476
  } else {
477
477
  notes.push('GitHub polling: 无 Webhook 时将轮询 Events API(默认 60s)');
478
478
  }
479
- if (bot.app_id) {
479
+ if (entry.app_id) {
480
480
  notes.push('GitHub App: 私钥路径需存在,且 App 已安装到目标仓库');
481
481
  } else {
482
482
  notes.push('GitHub gh CLI: 运行 gh auth login 完成认证');
package/src/ai.ts CHANGED
@@ -76,6 +76,22 @@ const PROVIDERS = [
76
76
  },
77
77
  ] as const;
78
78
 
79
+ function providerApiFor(name: string): string {
80
+ switch (name) {
81
+ case 'anthropic':
82
+ return 'anthropic-messages';
83
+ case 'google':
84
+ case 'gemini':
85
+ return 'google-generative-ai';
86
+ case 'ollama':
87
+ return 'ollama-chat';
88
+ case 'cloudflare':
89
+ return 'cloudflare-workers-ai';
90
+ default:
91
+ return 'openai-completions';
92
+ }
93
+ }
94
+
79
95
  function defaultModelForProvider(driver: string): string {
80
96
  const entry = PROVIDERS.find(p => p.value === driver);
81
97
  return entry?.defaultModel ?? '';
@@ -207,7 +223,7 @@ export async function configureAI(): Promise<AISetupConfig> {
207
223
 
208
224
  console.log('');
209
225
  console.log(chalk.blue('⚡ 配置 AI 触发方式'));
210
- console.log(chalk.gray(' 决定 Bot 何时自动调用大模型;命令(/ 开头)不会被 AI 拦截。'));
226
+ console.log(chalk.gray(' 决定 Endpoint 何时自动调用大模型;命令(/ 开头)不会被 AI 拦截。'));
211
227
 
212
228
  const triggerConfig = await inquirer.prompt([
213
229
  {
@@ -332,7 +348,7 @@ export function generateAIConfigYaml(config: AISetupConfig): string {
332
348
  if (config.providers) {
333
349
  for (const [name, providerConfig] of Object.entries(config.providers)) {
334
350
  lines.push(` ${name}:`);
335
- lines.push(` driver: ${name}`);
351
+ lines.push(` api: ${providerApiFor(name)}`);
336
352
  if (providerConfig.apiKey) {
337
353
  lines.push(` apiKey: ${providerConfig.apiKey}`);
338
354
  }
package/src/apply.ts CHANGED
@@ -30,9 +30,9 @@ export function applyAdaptersToConfig(config: Record<string, unknown>, result: A
30
30
  }
31
31
  config.plugins = plugins;
32
32
 
33
- const bots = Array.isArray(config.bots) ? [...config.bots as Record<string, unknown>[]] : [];
34
- bots.push(...result.bots);
35
- config.bots = bots;
33
+ const endpoints = Array.isArray(config.endpoints) ? [...config.endpoints as Record<string, unknown>[]] : [];
34
+ endpoints.push(...result.endpoints);
35
+ config.endpoints = endpoints;
36
36
  }
37
37
 
38
38
  export function applyAIToConfig(config: Record<string, unknown>, ai: AISetupConfig): void {
package/src/index.ts CHANGED
@@ -5,9 +5,9 @@ export type { AdapterSetupResult } from './adapter.js';
5
5
  export {
6
6
  configureAdapters,
7
7
  generateAdapterEnvVars,
8
- generateBotsConfigYaml,
9
- generateBotsConfigJSON,
10
- generateBotsConfigToml,
8
+ generateEndpointsConfigYaml,
9
+ generateEndpointsConfigJSON,
10
+ generateEndpointsConfigToml,
11
11
  getAdapterDependencies,
12
12
  getAdapterSetupNotes,
13
13
  } from './adapter.js';