You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The terminal dashboard (src/dashboard/) already renders main-view, sessions-view, tabs-view, and connect-view against the live activity tracker. Once the task ledger from issue A (#855) and the skill-replay results from issue B (#856) exist, an operator running a long-lived daemon needs to see them at a glance rather than greping JSON files. Without a dashboard surface, the new persistent state remains invisible during day-to-day operation, which significantly reduces the perceived value of the underlying ledger / replay work.
The dashboard is a TERMINAL ANSI renderer (src/dashboard/renderer.ts), not web. Adding two more views matches an established pattern (each existing view file is ~100-300 lines and read-only over a typed data source).
What
Add two new ANSI views to the existing terminal dashboard:
Both views are READ-ONLY. No code path inside src/dashboard/ writes to the task ledger or skill-memory store.
Data is fetched on view activation and on a periodic refresh (≥1 s, ≤2 s) — never per-keystroke. The refresh uses the same ledger / store APIs as the MCP tools (no shadow read paths).
When the task-ledger root or skill-memory root is missing or empty, the view renders an empty-state line ((no tasks) / (no recorded skills)) without throwing.
Live progress overlay: a row whose task_id has an entry in liveProgress shows progress/total (or progress if total is undefined) appended to the status column.
Hotkey t selects tasks view, k selects skills view, m returns to main (existing). Hotkey conflicts MUST be checked against existing bindings before merge.
Rendering uses only ANSI-safe characters; no truecolor sequences (consistent with existing views).
last_replay_failed_at > last_replay_passed_at rows render with the existing ANSI.yellow (NOT red — failure here is a soft demotion signal, not an error).
Both views fall back gracefully if the dependencies (#A, #B) are not yet merged at the time this issue lands (loader silently no-ops; views render the empty-state line).
Acceptance criteria
src/dashboard/views/tasks-view.ts lands with the documented TasksViewData contract and renders correctly at three terminal sizes (80×24, 120×40, 200×60) — fixture-based snapshot tests under tests/dashboard/tasks-view.test.ts.
src/dashboard/views/skills-view.ts lands with the documented SkillsViewData contract and the same three-size snapshot test.
t and k hotkeys wired in src/dashboard/keyboard-handler.ts; conflict-with-existing-binding test in tests/dashboard/key-bindings.test.ts.
Empty-state test: when ~/.openchrome/tasks/ does not exist, tasks view renders (no tasks) and does NOT throw.
Empty-state test: when no skill files exist under ~/.openchrome/skill-memory/, skills view renders (no recorded skills).
Refresh-rate test: with one running task, the tasks view's progress column updates at least every 2 s (timing test under tests/dashboard/tasks-view-refresh.test.ts).
Read-only invariant test: instrumented mock of the task ledger and skill store rejects all write calls during a 30 s dashboard run.
No new dependencies in package.json (zero diff).
npm run build && npm test green.
Real verification (post-merge, via openchrome MCP)
Launch openchrome with --pilot and the dashboard enabled.
Kick off a long-running task: mcp__openchrome__oc_task_start with { kind: "crawl", args: { url: "https://news.ycombinator.com/", maxPages: 10, sameOrigin: true } }.
Press t in the dashboard → assert the tasks view shows one row with kind=crawl, status=RUNNING, a non-empty progress column updating over time.
Cancel via mcp__openchrome__oc_task_cancel → within ≤2 s the row's status flips to CANCELLED in the dashboard without manual refresh.
Press k in the dashboard → assert the skills view shows a row for domain the-internet.herokuapp.com with the recorded skill name and usage_count >= 1.
Run mcp__openchrome__oc_skill_replay against that skill → after replay, the skills view row shows the new last_replay_passed_at (or last_replay_failed_at for the tampered fixture) within ≤2 s.
Resize the terminal mid-session (80→200 columns); both views re-render without artifacts (manual visual check; record a snapshot in the PR).
A reproducer script lives at scripts/verify/dashboard-tasks-skills.mjs (drives the dashboard via tmux send-keys + screencap diff).
Out of scope
Web dashboard (this is a terminal dashboard — explicitly noted to forestall scope drift).
Mutating actions in the dashboard (cancel, replay, delete). Stay read-only; mutations remain MCP-tool calls.
Real-time streaming via WebSockets / SSE inside the dashboard (periodic refresh is sufficient).
New skill-memory or task-ledger query APIs beyond what #A / #B already expose.
2026-05-12 r2: Critic-driven revision. Added explicit "TERMINAL dashboard, not web" guard against scope drift. Forced read-only invariant with an instrumented test. Specified soft-dep degradation behaviour so this issue can land in the same release cycle as B/D without a serialised merge order. Constrained refresh rate to a bounded interval (1-2 s) — the original draft's "live" wording was ambiguous. Added terminal-resize verification step.
Curated scope, overlap handling, and verification checklist
Scope classification
Canonical lane: terminal dashboard observability.
Primary deliverable: terminal dashboard task ledger and skill ledger views over existing persisted state.
Why
The terminal dashboard (
src/dashboard/) already rendersmain-view,sessions-view,tabs-view, andconnect-viewagainst the live activity tracker. Once the task ledger from issue A (#855) and the skill-replay results from issue B (#856) exist, an operator running a long-lived daemon needs to see them at a glance rather than greping JSON files. Without a dashboard surface, the new persistent state remains invisible during day-to-day operation, which significantly reduces the perceived value of the underlying ledger / replay work.The dashboard is a TERMINAL ANSI renderer (
src/dashboard/renderer.ts), not web. Adding two more views matches an established pattern (each existing view file is ~100-300 lines and read-only over a typed data source).What
Add two new ANSI views to the existing terminal dashboard:
src/dashboard/views/tasks-view.ts— read-only display of the task ledger (issue A (feat(core): oc_task_ledger — persistent async task table with cancel & wait (mcp-browser-use adoption A) #855)). Lists active and recent tasks with kind, status, age, and live progress (from issue D (feat(core): MCP progress notifications for long-running tools (mcp-browser-use adoption D) #863)).src/dashboard/views/skills-view.ts— read-only display of~/.openchrome/skill-memory/<domain>/skills.json(existing storage from feat(skill-memory): MCP tools oc_skill_record + oc_skill_recall (read-only / explicit-write core API) #785). Lists skills per domain with usage counts and last-replay status (from issue B (feat(pilot): oc_skill_replay — deterministic CDP-step replay with oc_assert contract gate (mcp-browser-use adoption B) #856)).Boundary:
src/dashboard/views/.src/dashboard/keyboard-handler.tsextended witht(tasks view) andk(skills view) hotkeys; existing key bindings unchanged.src/dashboard/index.tsregister the two new views in the view router.ANSI,formatTime,formatDuration,pad,truncate,BOXhelpers fromsrc/dashboard/ansi.ts.Contract
Invariants:
src/dashboard/writes to the task ledger or skill-memory store.(no tasks)/(no recorded skills)) without throwing.task_idhas an entry inliveProgressshowsprogress/total(orprogressiftotalis undefined) appended to the status column.tselects tasks view,kselects skills view,mreturns to main (existing). Hotkey conflicts MUST be checked against existing bindings before merge.last_replay_failed_at > last_replay_passed_atrows render with the existingANSI.yellow(NOT red — failure here is a soft demotion signal, not an error).Acceptance criteria
src/dashboard/views/tasks-view.tslands with the documentedTasksViewDatacontract and renders correctly at three terminal sizes (80×24, 120×40, 200×60) — fixture-based snapshot tests undertests/dashboard/tasks-view.test.ts.src/dashboard/views/skills-view.tslands with the documentedSkillsViewDatacontract and the same three-size snapshot test.tandkhotkeys wired insrc/dashboard/keyboard-handler.ts; conflict-with-existing-binding test intests/dashboard/key-bindings.test.ts.~/.openchrome/tasks/does not exist, tasks view renders(no tasks)and does NOT throw.~/.openchrome/skill-memory/, skills view renders(no recorded skills).progresscolumn updates at least every 2 s (timing test undertests/dashboard/tasks-view-refresh.test.ts).package.json(zero diff).npm run build && npm testgreen.Real verification (post-merge, via openchrome MCP)
--pilotand the dashboard enabled.mcp__openchrome__oc_task_startwith{ kind: "crawl", args: { url: "https://news.ycombinator.com/", maxPages: 10, sameOrigin: true } }.tin the dashboard → assert the tasks view shows one row withkind=crawl,status=RUNNING, a non-emptyprogresscolumn updating over time.mcp__openchrome__oc_task_cancel→ within ≤2 s the row's status flips toCANCELLEDin the dashboard without manual refresh.mcp__openchrome__oc_skill_recordagainsthttps://the-internet.herokuapp.com/login.kin the dashboard → assert the skills view shows a row for domainthe-internet.herokuapp.comwith the recorded skill name andusage_count >= 1.mcp__openchrome__oc_skill_replayagainst that skill → after replay, the skills view row shows the newlast_replay_passed_at(orlast_replay_failed_atfor the tampered fixture) within ≤2 s.A reproducer script lives at
scripts/verify/dashboard-tasks-skills.mjs(drives the dashboard via tmux send-keys + screencap diff).Out of scope
Dependencies
last_replay_*columns render empty until B lands; the rest of the view works without B.progress/totaloverlay degrades gracefully to "RUNNING" if D is absent.Effort
M (~3-5 dev days). Two view files (~150-250 lines each), keyboard wiring, snapshot tests, refresh-rate tests, dashboard reproducer.
References
src/dashboard/views/main-view.ts— view pattern reference.src/dashboard/views/sessions-view.ts— multi-row table reference.src/dashboard/keyboard-handler.ts— existing hotkey routing.Revision history
Curated scope, overlap handling, and verification checklist
Scope classification
feat/865-dashboard-ledger-views). Continue there; avoid duplicate work.Overlap and conflict resolution
Implementation checklist
Success criteria
Post-merge OpenChrome live verification checklist