feat(dashboard): Phase 3 — embedded web dashboard #138

Merged
xiaomo merged 2 commits from feat/133-phase3-web-dashboard into main 2026-04-25 07:53:05 +00:00
Owner

What

Phase 3 of RFC #133: Embedded single-page web dashboard for daemon monitoring and control.

Why

Phase 1+2 built the HTTP API + auth + CLI remote access. Phase 3 adds a visual interface — open http://host:port/ in a browser to see daemon status, senses, and workflows at a glance, with trigger/kill controls.

Changes

packages/daemon/src/dashboard.html (NEW — 569 lines)

  • Single-file dark-theme dashboard, zero external dependencies
  • Header: hostname, version, auto-updating uptime, connection status (green/red dot)
  • Health card: version, uptime (formatted "2h 34m"), startedAt, hostname
  • Senses table: name, type, triggers, with "Trigger" button per sense
  • Workflows table: name, active threads, queued threads, concurrency, active runIds with "Kill" button
  • Auto-poll every 5s (health + senses + workflows)
  • Loading state on first load, error banner on disconnect with auto-retry
  • Trigger/Kill: confirm dialog + toast notification for result
  • Bearer token input at top, persisted in localStorage
  • Responsive layout (works on mobile)

packages/daemon/src/load-dashboard-html.ts (NEW)

  • getDashboardHtml(): reads dashboard.html via fs.readFileSync + import.meta.url

packages/daemon/src/http-api.ts

  • GET / serves dashboard HTML (text/html, Cache-Control: no-store)
  • Dashboard route bypasses Bearer auth (token is handled client-side in JS fetch calls)

packages/daemon/rslib.config.ts

  • output.copy copies src/dashboard.html to dist/ alongside bundled JS

packages/core/src/sense-trigger-labels.ts (NEW)

  • Utility to derive human-readable trigger labels from nerve.yaml reflexes

packages/core/src/sense.ts

  • SenseInfo gains triggers: string[] field

packages/core/src/daemon-ipc-protocol.ts

  • WorkflowStatus gains activeRunIds: string[] field

packages/daemon/src/workflow-manager.ts

  • listWorkflows() populates activeRunIds (sorted)

packages/daemon/src/kernel.ts

  • Passes trigger labels to sense info builder

packages/cli/src/commands/sense.ts and workflow.ts

  • CLI output shows new triggers and runIds fields

Test updates

  • http-api.test.ts: GET / returns 200 HTML even when token is configured
  • daemon-ipc.test.ts, sense-list.test.ts: updated fixtures for new fields

Ref

  • Refs #133 (Phase 3: Web Dashboard)
  • Build: passed. Tests: 324/324 passed (core 33 + cli 127 + daemon 164).
## What Phase 3 of RFC #133: Embedded single-page web dashboard for daemon monitoring and control. ## Why Phase 1+2 built the HTTP API + auth + CLI remote access. Phase 3 adds a visual interface — open `http://host:port/` in a browser to see daemon status, senses, and workflows at a glance, with trigger/kill controls. ## Changes ### `packages/daemon/src/dashboard.html` (NEW — 569 lines) - Single-file dark-theme dashboard, zero external dependencies - **Header**: hostname, version, auto-updating uptime, connection status (green/red dot) - **Health card**: version, uptime (formatted "2h 34m"), startedAt, hostname - **Senses table**: name, type, triggers, with "Trigger" button per sense - **Workflows table**: name, active threads, queued threads, concurrency, active runIds with "Kill" button - Auto-poll every 5s (health + senses + workflows) - Loading state on first load, error banner on disconnect with auto-retry - Trigger/Kill: confirm dialog + toast notification for result - Bearer token input at top, persisted in localStorage - Responsive layout (works on mobile) ### `packages/daemon/src/load-dashboard-html.ts` (NEW) - `getDashboardHtml()`: reads dashboard.html via `fs.readFileSync` + `import.meta.url` ### `packages/daemon/src/http-api.ts` - `GET /` serves dashboard HTML (text/html, Cache-Control: no-store) - Dashboard route bypasses Bearer auth (token is handled client-side in JS fetch calls) ### `packages/daemon/rslib.config.ts` - `output.copy` copies `src/dashboard.html` to `dist/` alongside bundled JS ### `packages/core/src/sense-trigger-labels.ts` (NEW) - Utility to derive human-readable trigger labels from nerve.yaml reflexes ### `packages/core/src/sense.ts` - `SenseInfo` gains `triggers: string[]` field ### `packages/core/src/daemon-ipc-protocol.ts` - `WorkflowStatus` gains `activeRunIds: string[]` field ### `packages/daemon/src/workflow-manager.ts` - `listWorkflows()` populates `activeRunIds` (sorted) ### `packages/daemon/src/kernel.ts` - Passes trigger labels to sense info builder ### `packages/cli/src/commands/sense.ts` and `workflow.ts` - CLI output shows new triggers and runIds fields ### Test updates - `http-api.test.ts`: GET / returns 200 HTML even when token is configured - `daemon-ipc.test.ts`, `sense-list.test.ts`: updated fixtures for new fields ## Ref - Refs #133 (Phase 3: Web Dashboard) - Build: passed. Tests: 324/324 passed (core 33 + cli 127 + daemon 164).
xingyue added 1 commit 2026-04-25 07:01:48 +00:00
- Single-file dark-theme HTML dashboard (569 lines, zero deps)
- GET / serves dashboard HTML (no auth required, token handled in JS)
- Auto-poll every 5s: health, senses, workflows
- Trigger/Kill buttons with confirmation + toast notifications
- Bearer token input persisted in localStorage
- Connection status indicator (green/red dot)
- Responsive layout for mobile
- SenseInfo gains triggers[] field, WorkflowStatus gains activeRunIds[]
- rslib copies dashboard.html to dist/

Refs #133
xiaomo reviewed 2026-04-25 07:09:26 +00:00
xiaomo left a comment
Owner

LGTM with one bug 🐛

Bug: dashboard.htmlonKillWorkflow{ threadId, name }/api/kill-workflow 端点期望 { runId },Kill 按钮会永远 400。修复:body: JSON.stringify({ runId: threadId }) 即可。

其余很漂亮:

  • XSS 防护到位(escapeHtml)
  • GET / 免 auth、API 走 Bearer — 分层合理
  • dashboard.html 缓存 + rslib copy 到 dist — 部署路径干净
  • SenseInfo.triggers + WorkflowStatus.activeRunIds 扩展自然
  • 5s polling + toast 反馈体验好

修完那个字段名就可以合了。

LGTM with one bug 🐛 **Bug:** `dashboard.html` 的 `onKillWorkflow` 发 `{ threadId, name }` 但 `/api/kill-workflow` 端点期望 `{ runId }`,Kill 按钮会永远 400。修复:`body: JSON.stringify({ runId: threadId })` 即可。 其余很漂亮: - XSS 防护到位(escapeHtml) - GET / 免 auth、API 走 Bearer — 分层合理 - dashboard.html 缓存 + rslib copy 到 dist — 部署路径干净 - `SenseInfo.triggers` + `WorkflowStatus.activeRunIds` 扩展自然 - 5s polling + toast 反馈体验好 修完那个字段名就可以合了。
xiaoju added 1 commit 2026-04-25 07:51:09 +00:00
The /api/kill-workflow endpoint and all callers (dashboard, HttpTransport)
now consistently use 'runId' instead of 'threadId', matching the handler
name killWorkflowByRunId.

Fixes review feedback on PR #138.
xiaomo approved these changes 2026-04-25 07:53:03 +00:00
xiaomo left a comment
Owner

LGTM runId 字段已统一,三处修复干净利落。RFC #133 三个 Phase 全部完成,漂亮!🎉

LGTM ✅ runId 字段已统一,三处修复干净利落。RFC #133 三个 Phase 全部完成,漂亮!🎉
xiaomo merged commit 83163d9974 into main 2026-04-25 07:53:05 +00:00
This repo is archived. You cannot comment on pull requests.
No Reviewers
No Label
3 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: uncaged/nerve#138