bhg-helper 1.0.1 → 1.0.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/api/app.ts CHANGED
@@ -14,7 +14,6 @@ import backupRoutes from './routes/backups.js'
14
14
  import logRoutes from './routes/logs.js'
15
15
  import providerRoutes from './routes/providers.js'
16
16
  import relayRoutes from './routes/relay.js'
17
- import installRoutes from './routes/install.js'
18
17
 
19
18
  const app: express.Application = express()
20
19
 
@@ -35,13 +34,13 @@ app.use('/api/backups', backupRoutes)
35
34
  app.use('/api/logs', logRoutes)
36
35
  app.use('/api/providers', providerRoutes)
37
36
  app.use('/api/relay', relayRoutes)
38
- app.use('/api/install', installRoutes)
39
37
 
40
38
  app.get('/api/health', (_req: Request, res: Response) => {
41
39
  res.json({ ok: true, data: { bhgHelperDir: BHG_HELPER_DIR } })
42
40
  })
43
41
 
44
42
  app.use((error: Error, _req: Request, res: Response, _next: NextFunction) => {
43
+ void _next
45
44
  log('ERR', 'http', error.message)
46
45
  res.status(500).json({ ok: false, error: error.message })
47
46
  })
@@ -239,8 +239,6 @@ export interface AnthropicStreamEvent {
239
239
  [key: string]: unknown
240
240
  }
241
241
 
242
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
243
-
244
242
  function makeId(): string {
245
243
  // 用 crypto.randomUUID 如果存在
246
244
  if (typeof globalThis.crypto?.randomUUID === 'function') {
@@ -278,7 +276,6 @@ export function* openAIStreamToAnthropicEvents(
278
276
  let finishReason: string | null = null
279
277
  let hasText = false
280
278
  let toolBlockIndex = -1
281
- let toolInputBuffer = ''
282
279
  let toolId: string | null = null
283
280
  let toolName: string | null = null
284
281
  const usedModel = openAIChunks[0]?.model ?? model
@@ -357,7 +354,6 @@ export function* openAIStreamToAnthropicEvents(
357
354
  }
358
355
  }
359
356
  if (tc.function?.arguments) {
360
- toolInputBuffer += tc.function.arguments
361
357
  yield {
362
358
  type: 'content_block_delta',
363
359
  index: toolBlockIndex,
package/cli/cli.js CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * BHG-helper CLI — 命令行交互菜单
4
- * 一级菜单:模型选择 / 工具配置 / 语言配置 / BHG-helper UI / 退出
4
+ * 一级菜单:模型选择 / 工具配置 / 语言配置 / 退出
5
5
  */
6
6
 
7
7
  import { select, confirm, input } from '@inquirer/prompts'
8
- import { execSync } from 'node:child_process'
8
+ import { execSync, spawn } from 'node:child_process'
9
9
  import os from 'node:os'
10
10
  import path from 'node:path'
11
11
  import fs from 'node:fs'
12
+ import { fileURLToPath } from 'node:url'
12
13
 
13
14
  // ── 色彩 ──────────────────────────────────────────────────────
14
15
  const C = { r: '\x1b[0m', bold: '\x1b[1m', cyan: '\x1b[36m', green: '\x1b[32m', yellow: '\x1b[33m', dim: '\x1b[2m', red: '\x1b[31m' }
@@ -16,7 +17,8 @@ const theme = { prefix: `${C.cyan}?${C.r}` }
16
17
 
17
18
  // ── 常量 ──────────────────────────────────────────────────────
18
19
  const RELAY_PORT = 8787
19
- const UI_URL = 'http://localhost:5173'
20
+ const API_URL = 'http://127.0.0.1:3001'
21
+ const PROJECT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
20
22
  const BHG_HELPER_DIR = path.join(os.homedir(), '.bhg-helper')
21
23
  const RELAY_CONFIG_FILE = path.join(BHG_HELPER_DIR, 'relay.config.json')
22
24
  const CLAUDE_SETTINGS_FILE = path.join(os.homedir(), '.claude', 'settings.json')
@@ -108,10 +110,40 @@ function checkInstalled(cmd) {
108
110
  } catch { return false }
109
111
  }
110
112
 
111
- function openBrowser(url) {
113
+ async function apiPost(pathname) {
114
+ const res = await fetch(`${API_URL}${pathname}`, { method: 'POST' })
115
+ return res.ok
116
+ }
117
+
118
+ async function apiHealth() {
112
119
  try {
113
- execSync(`start "" "${url}"`, { shell: true })
114
- } catch { /* */ }
120
+ const controller = new AbortController()
121
+ const timer = setTimeout(() => controller.abort(), 800)
122
+ const res = await fetch(`${API_URL}/api/health`, { signal: controller.signal })
123
+ clearTimeout(timer)
124
+ return res.ok
125
+ } catch {
126
+ return false
127
+ }
128
+ }
129
+
130
+ async function ensureBackend() {
131
+ if (await apiHealth()) return true
132
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
133
+ const child = spawn(npmCmd, ['run', 'server:raw'], {
134
+ cwd: PROJECT_ROOT,
135
+ detached: true,
136
+ stdio: 'ignore',
137
+ shell: false,
138
+ })
139
+ child.unref()
140
+ await new Promise(resolve => setTimeout(resolve, 1500))
141
+ return await apiHealth()
142
+ }
143
+
144
+ async function ensureRelay() {
145
+ if (!(await ensureBackend())) return false
146
+ return await apiPost('/api/relay/start')
115
147
  }
116
148
 
117
149
  // ── 打印头部 ──────────────────────────────────────────────────
@@ -121,8 +153,7 @@ function printHeader() {
121
153
  const apiOk = hasApiConfig()
122
154
  const model = getCurrentModel()
123
155
  console.log(` ${C.dim}API${C.r} ${apiOk ? `${C.green}已配置${C.r}` : `${C.red}未配置${C.r}`}`)
124
- console.log(` ${C.dim}模型${C.r} ${C.cyan}${model}${C.r}`)
125
- console.log(` ${C.dim}UI${C.r} ${UI_URL}\n`)
156
+ console.log(` ${C.dim}模型${C.r} ${C.cyan}${model}${C.r}\n`)
126
157
  }
127
158
 
128
159
  // ── 一级菜单 ──────────────────────────────────────────────────
@@ -133,7 +164,6 @@ async function mainMenu() {
133
164
  { name: '模型选择', value: 'model', description: '切换模型 / 输入 API Key' },
134
165
  { name: '工具配置', value: 'tools', description: '配置各 AI 编程工具' },
135
166
  { name: '语言配置', value: 'lang', description: '界面语言设置' },
136
- { name: `${C.yellow}BHG-helper 网页界面${C.r}`, value: 'ui', description: '打开网页控制台' },
137
167
  { name: `${C.dim}──────────${C.r}`, value: '---', disabled: true },
138
168
  { name: '退出', value: 'exit' },
139
169
  ],
@@ -224,7 +254,12 @@ async function modelMenu() {
224
254
 
225
255
  const next = { ...(cfg || {}), deepseekApiKey: newKey, port: cfg?.port || RELAY_PORT, deepseekBaseUrl: cfg?.deepseekBaseUrl || 'https://api.deepseek.com', modelMap: cfg?.modelMap || { 'deepseek-v4-pro': 'deepseek-v4-pro', 'deepseek-chat': 'deepseek-v4-pro' }, spoofProvider: cfg?.spoofProvider || 'deepseek', verbose: cfg?.verbose ?? true }
226
256
  saveConfig(next)
227
- console.log(`\n ${C.green}✓ API Key 已保存${C.r}\n`)
257
+ console.log(`\n ${C.green}✓ API Key 已保存${C.r}`)
258
+
259
+ // 自动启动中转服务
260
+ console.log(` ${C.dim}正在启动中转服务...${C.r}`)
261
+ const relayOk = await ensureRelay()
262
+ console.log(` ${relayOk ? C.green + '✓ 中转服务已启动' + C.r : C.yellow + '中转服务启动失败(可稍后手动启动)' + C.r}\n`)
228
263
  await confirm({ message: '按回车继续...', theme })
229
264
  return 'back'
230
265
  }
@@ -254,13 +289,6 @@ async function toolsMenu() {
254
289
  if (choice === 'exit') return 'exit'
255
290
  if (choice === 'back') return 'back'
256
291
 
257
- if (choice === 'ui') {
258
- openBrowser(UI_URL)
259
- console.log(`\n ${C.green}✓ 浏览器已打开 → ${UI_URL}${C.r}\n`)
260
- await confirm({ message: '按回车继续...', theme })
261
- return 'back'
262
- }
263
-
264
292
  return await toolDetailMenu(choice)
265
293
  }
266
294
 
@@ -268,18 +296,11 @@ async function toolsMenu() {
268
296
  async function toolDetailMenu(toolKey) {
269
297
  const tool = TOOLS[toolKey]
270
298
 
271
- // Cursor / Continue / Trae — 无 CLI,只引导去 UI
299
+ // Cursor / Continue / Trae — 无 CLI,显示安装方式
272
300
  if (!tool.cmd) {
273
301
  console.log(`\n ${C.bold}${tool.name}${C.r} — ${tool.desc}`)
274
302
  console.log(` ${C.dim}安装方式:${tool.install}${C.r}`)
275
- console.log(` ${C.yellow}${tool.name} 需要在 BHG-helper 网页界面配置${C.r}\n`)
276
-
277
- const openUi = await confirm({ message: '打开 BHG-helper 网页界面?', default: true, theme })
278
- if (openUi) {
279
- openBrowser(UI_URL)
280
- console.log(` ${C.green}✓ 浏览器已打开${C.r}`)
281
- }
282
- console.log()
303
+ console.log(` ${C.yellow}当前纯命令行版暂不自动配置 ${tool.name}${C.r}\n`)
283
304
  await confirm({ message: '按回车继续...', theme })
284
305
  return 'back'
285
306
  }
@@ -330,6 +351,13 @@ async function toolDetailMenu(toolKey) {
330
351
  return 'back'
331
352
  }
332
353
 
354
+ const relayOk = await ensureRelay()
355
+ if (!relayOk) {
356
+ console.log(`\n ${C.red}中转服务启动失败,请重新运行 BHG-helper。${C.r}\n`)
357
+ await confirm({ message: '按回车继续...', theme })
358
+ return 'back'
359
+ }
360
+
333
361
  // 写入 ~/.claude/settings.json(Claude Code 专用)
334
362
  if (toolKey === 'claude') {
335
363
  const currentModel = getCurrentModel()
@@ -435,11 +463,6 @@ async function main() {
435
463
  break
436
464
  }
437
465
 
438
- case 'ui':
439
- openBrowser(UI_URL)
440
- console.log(`\n ${C.green}✓ 浏览器已打开 → ${UI_URL}${C.r}\n`)
441
- await confirm({ message: '按回车继续...', theme })
442
- break
443
466
  }
444
467
  }
445
468
  }