@bitseek/hermes-webui 0.1.1 → 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
@@ -1,9 +1,6 @@
1
- # Bitseek Hermes WebUI
1
+ # BitSeek Claw WebUI
2
2
 
3
- `@bitseek/hermes-webui` 用来在本机启动和管理 Bitseek Hermes WebUI。
4
-
5
- 它是一个轻量级 npm 包装器,负责进程生命周期、健康检查、日志和运行时状态。
6
- WebUI 本体来自 vendored `agent-frontend-shell` 运行时。
3
+ `@bitseek/hermes-webui` 用来在本机启动和管理 BitSeek Claw WebUI。
7
4
 
8
5
  ## 快速开始
9
6
 
@@ -39,7 +36,7 @@ hermes-webui start --port 8788 --open
39
36
  - 如果 WebUI 要调用 Hermes Agent,需要准备 Hermes Agent checkout,并确保其中有
40
37
  `run_agent.py`。
41
38
 
42
- 默认情况下,包装器会尝试从以下位置查找 Hermes Agent:
39
+ 默认情况下,WebUI 会尝试从以下位置查找 Hermes Agent:
43
40
 
44
41
  ```text
45
42
  $HERMES_HOME/hermes-agent
@@ -79,13 +76,16 @@ hermes-webui doctor
79
76
 
80
77
  ## 首次启动会做什么
81
78
 
82
- 第一次运行 `hermes-webui start` 时,包装器会:
79
+ 第一次运行 `hermes-webui start` 时,WebUI 会:
83
80
 
84
81
  - 创建运行时状态目录。
85
82
  - 创建并管理 Python venv。
86
- - vendored WebUI `requirements.txt` 安装 Python 依赖。
83
+ - 安装 WebUI 所需的 Python 依赖。
84
+ - 检查当前 Python 是否能导入 Hermes Agent;如果不能,会把
85
+ `HERMES_WEBUI_AGENT_DIR` 指向的 Hermes Agent 以 editable 模式安装到 WebUI
86
+ venv。
87
87
  - 默认启用 BitSeek 外观和扩展入口,包括 “AI 同事” 页面。
88
- - 启动 vendored `agent-frontend-shell/server.py`。
88
+ - 启动 BitSeek Claw WebUI 服务。
89
89
  - 等待 `/health` 健康检查通过。
90
90
  - 把 PID、日志路径和运行时信息写入状态目录。
91
91
 
@@ -140,9 +140,8 @@ HERMES_WEBUI_EXTENSION_SCRIPT_URLS 默认 /extensions/themes/bitseek/inde
140
140
  HERMES_WEBUI_BOT_NAME 默认 BitSeek Claw
141
141
  ```
142
142
 
143
- 这些默认值在 macOS、Linux、Windows 上都可用。`./extensions` 会由 vendored
144
- WebUI 按运行时源码目录解析,不依赖当前 shell 的工作目录。显式设置同名环境变量
145
- 可以覆盖默认值。
143
+ 这些默认值在 macOS、Linux、Windows 上都可用。显式设置同名环境变量可以覆盖
144
+ 默认值。
146
145
 
147
146
  示例:
148
147
 
@@ -152,7 +151,7 @@ export HERMES_WEBUI_AGENT_DIR="$HERMES_HOME/hermes-agent"
152
151
  hermes-webui start --port 8787 --open
153
152
  ```
154
153
 
155
- 如果不想使用包装器管理的 venv,可以指定已有 Python:
154
+ 如果不想使用默认 venv,可以指定已有 Python:
156
155
 
157
156
  ```bash
158
157
  export HERMES_WEBUI_PYTHON=/usr/bin/python3
@@ -174,23 +173,14 @@ hermes-webui doctor
174
173
  `HERMES_WEBUI_PYTHON`。
175
174
  - `Hermes Agent dir: not found`:设置 `HERMES_WEBUI_AGENT_DIR` 指向包含
176
175
  `run_agent.py` 的 Hermes Agent 目录。
177
- - `Vendored agent-frontend-shell runtime is missing`:发布包缺少 vendored
178
- 运行时,需要维护者重新同步并发布包。
176
+ - `AIAgent importable: fail`:当前 WebUI Python 不能导入 Hermes Agent。运行
177
+ `hermes-webui start` 会自动尝试修复;如果仍失败,请查看 `server.log` 和
178
+ `pip install -e` 的错误输出。
179
+ - `WebUI runtime is missing`:发布包缺少必要文件,需要维护者重新打包并发布。
179
180
 
180
181
  ## 维护者说明
181
182
 
182
- 打包的 WebUI 运行时来自:
183
-
184
- ```text
185
- repo: adv-org/agent-frontend-shell
186
- branch: dev-zkp
187
- source checkout: /home/boj/hermes/agent-frontend-shell
188
- ```
189
-
190
- 该包装器不会把 Python + 原生 JavaScript WebUI 重写成 Node 应用,只负责用 npm
191
- 包形式分发和启动 vendored 运行时。
192
-
193
- 更新 vendored 运行时:
183
+ 同步 WebUI 文件:
194
184
 
195
185
  ```bash
196
186
  npm run sync:vendor
@@ -209,7 +199,7 @@ npm pack --dry-run
209
199
  bin/
210
200
  scripts/
211
201
  templates/
212
- vendor/agent-frontend-shell/
202
+ vendor/
213
203
  README.md
214
204
  ```
215
205
 
@@ -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,8 +1,8 @@
1
1
  {
2
2
  "name": "@bitseek/hermes-webui",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
- "description": "Npm wrapper for Bitseek Hermes WebUI runtime.",
5
+ "description": "BitSeek Claw WebUI launcher.",
6
6
  "bin": {
7
7
  "hermes-webui": "bin/hermes-webui.mjs"
8
8
  },