@bitseek/hermes-webui 0.1.2 → 0.1.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/README.md CHANGED
@@ -81,6 +81,9 @@ hermes-webui doctor
81
81
  - 创建运行时状态目录。
82
82
  - 创建并管理 Python venv。
83
83
  - 安装 WebUI 所需的 Python 依赖。
84
+ - 检查当前 Python 是否能导入 Hermes Agent;如果不能,会把
85
+ `HERMES_WEBUI_AGENT_DIR` 指向的 Hermes Agent 以 editable 模式安装到 WebUI
86
+ venv。
84
87
  - 默认启用 BitSeek 外观和扩展入口,包括 “AI 同事” 页面。
85
88
  - 启动 BitSeek Claw WebUI 服务。
86
89
  - 等待 `/health` 健康检查通过。
@@ -170,6 +173,9 @@ hermes-webui doctor
170
173
  `HERMES_WEBUI_PYTHON`。
171
174
  - `Hermes Agent dir: not found`:设置 `HERMES_WEBUI_AGENT_DIR` 指向包含
172
175
  `run_agent.py` 的 Hermes Agent 目录。
176
+ - `AIAgent importable: fail`:当前 WebUI Python 不能导入 Hermes Agent。运行
177
+ `hermes-webui start` 会自动尝试修复;如果仍失败,请查看 `server.log` 和
178
+ `pip install -e` 的错误输出。
173
179
  - `WebUI runtime is missing`:发布包缺少必要文件,需要维护者重新打包并发布。
174
180
 
175
181
  ## 维护者说明
@@ -218,6 +218,54 @@ function pythonImportsOk(python) {
218
218
  return result.status === 0
219
219
  }
220
220
 
221
+ function aiAgentImportCheck(python, agentDir) {
222
+ if (!python || !agentDir) {
223
+ return { ok: false, error: 'python or Hermes Agent dir not found' }
224
+ }
225
+ const env = {
226
+ ...process.env,
227
+ HERMES_WEBUI_AGENT_DIR: agentDir,
228
+ PYTHONPATH: process.env.PYTHONPATH
229
+ ? `${agentDir}${delimiter}${process.env.PYTHONPATH}`
230
+ : agentDir,
231
+ }
232
+ const result = spawnSync(python, ['-c', 'from run_agent import AIAgent; print("ok")'], {
233
+ stdio: ['ignore', 'pipe', 'pipe'],
234
+ env,
235
+ encoding: 'utf8',
236
+ })
237
+ return {
238
+ ok: result.status === 0,
239
+ error: (result.stderr || result.stdout || '').trim(),
240
+ }
241
+ }
242
+
243
+ function ensureAiAgentImportable(python, agentDir) {
244
+ if (!agentDir) return
245
+
246
+ let check = aiAgentImportCheck(python, agentDir)
247
+ if (check.ok) return
248
+
249
+ const pyprojectPath = join(agentDir, 'pyproject.toml')
250
+ if (!existsSync(pyprojectPath)) {
251
+ throw new Error(`Hermes Agent cannot be imported and pyproject.toml was not found: ${pyprojectPath}`)
252
+ }
253
+
254
+ console.log(`Installing Hermes Agent into WebUI Python env: ${agentDir}`)
255
+ const install = spawnSync(python, ['-m', 'pip', 'install', '-e', agentDir], {
256
+ stdio: 'inherit',
257
+ env: process.env,
258
+ })
259
+ if (install.status !== 0) {
260
+ throw new Error(`Failed to install Hermes Agent into WebUI Python env (exit ${install.status})`)
261
+ }
262
+
263
+ check = aiAgentImportCheck(python, agentDir)
264
+ if (!check.ok) {
265
+ throw new Error(`Hermes Agent still cannot be imported after install:\n${check.error}`)
266
+ }
267
+ }
268
+
221
269
  function preparePython() {
222
270
  if (process.env.HERMES_WEBUI_PYTHON) {
223
271
  return resolve(expandHome(process.env.HERMES_WEBUI_PYTHON))
@@ -311,7 +359,7 @@ async function waitForHealth(host, port, child, timeoutMs = 30000) {
311
359
 
312
360
  async function start(options) {
313
361
  if (!existsSync(bootstrapPath) || !existsSync(serverPath)) {
314
- throw new Error('Vendored agent-frontend-shell runtime is missing. Run npm run sync:vendor.')
362
+ throw new Error('WebUI runtime is missing. Run npm run sync:vendor.')
315
363
  }
316
364
 
317
365
  const existing = readPid()
@@ -329,6 +377,7 @@ async function start(options) {
329
377
  mkdirSync(paths.dir, { recursive: true })
330
378
  const python = preparePython()
331
379
  const env = buildEnv(python, options)
380
+ ensureAiAgentImportable(python, env.HERMES_WEBUI_AGENT_DIR)
332
381
  const args = [serverPath]
333
382
 
334
383
  if (options.foreground) {
@@ -383,7 +432,7 @@ async function start(options) {
383
432
  started_at: new Date().toISOString(),
384
433
  })
385
434
 
386
- console.log(`Starting Bitseek Hermes WebUI (PID ${child.pid}, port ${options.port})...`)
435
+ console.log(`Starting BitSeek Claw WebUI (PID ${child.pid}, port ${options.port})...`)
387
436
  const health = await waitForHealth(options.host, options.port, child)
388
437
  if (!health.ok) {
389
438
  console.log(`Health check failed: ${health.error || health.status || 'unknown error'}`)
@@ -391,7 +440,7 @@ async function start(options) {
391
440
  process.exit(1)
392
441
  }
393
442
 
394
- console.log('Bitseek Hermes WebUI started')
443
+ console.log('BitSeek Claw WebUI started')
395
444
  console.log(`URL: http://${options.host === '127.0.0.1' ? 'localhost' : options.host}:${options.port}`)
396
445
  console.log(`Log: ${paths.log}`)
397
446
  if (options.open) openBrowser(options.host, options.port)
@@ -408,13 +457,13 @@ async function stop() {
408
457
  process.exit(1)
409
458
  }
410
459
  }
411
- console.log('Bitseek Hermes WebUI is not running')
460
+ console.log('BitSeek Claw WebUI is not running')
412
461
  return
413
462
  }
414
463
 
415
464
  if (!isRunning(pid)) {
416
465
  removePid()
417
- console.log(`Bitseek Hermes WebUI was not running; cleaned stale PID ${pid}`)
466
+ console.log(`BitSeek Claw WebUI was not running; cleaned stale PID ${pid}`)
418
467
  return
419
468
  }
420
469
 
@@ -427,7 +476,7 @@ async function stop() {
427
476
  process.kill(pid, 'SIGKILL')
428
477
  }
429
478
  removePid()
430
- console.log(`Bitseek Hermes WebUI stopped (PID ${pid})`)
479
+ console.log(`BitSeek Claw WebUI stopped (PID ${pid})`)
431
480
  }
432
481
 
433
482
  async function restart(options) {
@@ -510,11 +559,17 @@ async function doctor(options) {
510
559
  const agentDir = resolveAgentDir()
511
560
  add('Hermes Agent dir', Boolean(agentDir), agentDir || 'not found')
512
561
  add('run_agent.py', Boolean(agentDir && existsSync(join(agentDir, 'run_agent.py'))), agentDir ? join(agentDir, 'run_agent.py') : 'not found')
562
+ if (python && agentDir) {
563
+ const importCheck = aiAgentImportCheck(python, agentDir)
564
+ add('AIAgent importable', importCheck.ok, importCheck.ok ? python : importCheck.error || python)
565
+ } else {
566
+ add('AIAgent importable', false, 'python or Hermes Agent dir not found')
567
+ }
513
568
  add('port available', !(await portOccupied(options.host, options.port)), `${options.host}:${options.port}`)
514
- add('no vendored .env', !existsSync(join(vendorRoot, '.env')), join(vendorRoot, '.env'))
515
- add('no vendored .git', !existsSync(join(vendorRoot, '.git')), join(vendorRoot, '.git'))
516
- add('no vendored .venv', !existsSync(join(vendorRoot, '.venv')), join(vendorRoot, '.venv'))
517
- add('no vendored node_modules', !existsSync(join(vendorRoot, 'node_modules')), join(vendorRoot, 'node_modules'))
569
+ add('no bundled .env', !existsSync(join(vendorRoot, '.env')), join(vendorRoot, '.env'))
570
+ add('no bundled .git', !existsSync(join(vendorRoot, '.git')), join(vendorRoot, '.git'))
571
+ add('no bundled .venv', !existsSync(join(vendorRoot, '.venv')), join(vendorRoot, '.venv'))
572
+ add('no bundled node_modules', !existsSync(join(vendorRoot, 'node_modules')), join(vendorRoot, 'node_modules'))
518
573
 
519
574
  for (const check of checks) {
520
575
  console.log(`${check.ok ? 'ok' : 'fail'} - ${check.name}${check.detail ? `: ${check.detail}` : ''}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitseek/hermes-webui",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "BitSeek Claw WebUI launcher.",
6
6
  "bin": {