Skip to content

[feat] Add local web dashboard - #77

Open
vinilana wants to merge 7 commits into
mainfrom
feat/web-interface
Open

[feat] Add local web dashboard#77
vinilana wants to merge 7 commits into
mainfrom
feat/web-interface

Conversation

@vinilana

@vinilana vinilana commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a bundled local web dashboard for dotcontext and wires it into the CLI, development workflow, packaging, smoke checks, and documentation.

What changed

  • Adds the dotcontext web CLI surface, including --port, --host, --no-open, and --api-only for local Vite development.
  • Adds web development scripts: dev:web, dev:web-api, dev:web-ui, and build:web-ui.
  • Packages web-ui/dist into the generated @dotcontext/cli bundle and makes package smoke tests fail if the dashboard assets are missing.
  • Updates user and contributor documentation, including English and Portuguese dotcontext.dev guide/reference pages.
  • Completes and syncs the dotcontext PREVC workflow plan for the web interface.

Impact

Developers can run the dashboard locally with npm run dev:web, validate the packaged version with node dist/index.js web --no-open, and publish CLI bundles that include the built dashboard UI.

Users can run the published CLI dashboard with dotcontext web or npx -y @dotcontext/cli@latest web.

Validation

  • npm run build
  • npm run build:web-ui
  • npm test -- --runInBand
  • npm run build:packages
  • npm run smoke:packages
  • npm --prefix docs run build
  • Packaged runtime check from .release/packages/cli: node dist/index.js web --port 4527 --no-open, then fetched / and /api/docs

Note: docs build completed with existing duplicate-ID warnings for localized pages.

vinilana and others added 7 commits June 30, 2026 16:53
Co-Authored-By: AI Context Agent <noreply@anthropic.com>
Co-Authored-By: AI Context Agent <noreply@anthropic.com>
Co-Authored-By: AI Context Agent <noreply@anthropic.com>
…interface

Co-Authored-By: AI Context Agent <noreply@anthropic.com>
Co-Authored-By: AI Context Agent <noreply@anthropic.com>
Co-Authored-By: AI Context Agent <noreply@anthropic.com>
- Added icons to navigation items in the Layout component for better visual representation.
- Updated sidebar title to include a mark for branding.
- Introduced new common components: CopyButton, DownloadButton, ToolBadge, and SearchInput for enhanced functionality.
- Implemented front matter handling in markdown files for better content management.
- Enhanced various views (Agents, Docs, Skills, Session, Workflow) with new UI components and improved search functionality.
- Updated CSS variables for a more cohesive design and improved scrollbar styling.
- Added support for displaying tool information in session and workflow views.
@vinilana vinilana changed the title [codex] Add local web dashboard [feat] Add local web dashboard Jul 1, 2026
@vinilana
vinilana marked this pull request as ready for review July 1, 2026 15:34
@vinilana
vinilana requested a review from Copilot July 9, 2026 23:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new local web dashboard surface to dotcontext: a src/web Node HTTP/SSE adapter over the harness runtime plus a bundled web-ui/ React+Vite SPA, wired into the CLI (dotcontext web), packaging, smoke tests, and docs.

Changes:

  • Introduces src/web (HTTP REST + SSE + static SPA serving) and the dotcontext web CLI command with dev-friendly flags.
  • Adds web-ui/ workspace (Vite + React router UI) to browse docs/skills/agents/sessions/workflow, with SSE-driven refetch.
  • Updates packaging/smoke validation to bundle web-ui/dist, plus documentation and architecture boundary enforcement.

Reviewed changes

Copilot reviewed 72 out of 78 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
web-ui/vite.config.ts Configures Vite dev server and /api proxy to the local backend.
web-ui/tsconfig.node.json Adds TS config for Vite config/node tooling.
web-ui/tsconfig.json Adds TS project references for app + node configs.
web-ui/tsconfig.app.json Adds browser/React TS config for the SPA source.
web-ui/src/views/WorkflowView.tsx Renders workflow summary, PREVC phase tracker, harness binding, and linked plan details.
web-ui/src/views/SkillsView.tsx Adds skills browsing UI with search + content panel and export actions.
web-ui/src/views/SessionView.tsx Adds session browsing UI with trace/artifact/checkpoint detail panes.
web-ui/src/views/DocsView.tsx Adds docs browsing UI with search + markdown rendering and export actions.
web-ui/src/views/AgentsView.tsx Adds agents browsing UI and exposes agent info/docs in the dashboard.
web-ui/src/types/api.ts Defines the UI’s typed contract for /api/* endpoints and SSE payloads.
web-ui/src/main.tsx Boots the React app with router + StrictMode.
web-ui/src/lib/markdown.ts Builds a downloadable “frontmatter + markdown” representation for docs/skills.
web-ui/src/lib/api.ts Implements fetch wrapper for { data } / { error } API envelope.
web-ui/src/index.css Adds base UI styles and design tokens.
web-ui/src/hooks/useEventStream.ts Adds a shared/ref-counted SSE client that bumps a version counter on events.
web-ui/src/hooks/useApi.ts Adds generic REST hooks that refetch on selection changes and SSE bumps.
web-ui/src/components/Layout.tsx Adds dashboard shell layout, navigation, and SSE connection badge.
web-ui/src/components/icons.tsx Adds shared inline SVG icon components.
web-ui/src/components/common.tsx Adds reusable UI primitives (panels, pills, markdown, copy/download, etc.).
web-ui/src/App.tsx Defines SPA routes for docs/skills/agents/session/workflow.
web-ui/src/App.css Adds comprehensive styles for shell, lists, workflow tracker, etc.
web-ui/README.md Documents dev workflow, production build, and package validation for the dashboard.
web-ui/public/favicon.svg Adds dashboard favicon asset.
web-ui/package.json Defines SPA dependencies and scripts (dev/build/lint/preview).
web-ui/index.html Adds SPA HTML entrypoint and favicon wiring.
web-ui/.oxlintrc.json Adds web-ui lint config for React + TS hooks/export rules.
web-ui/.gitignore Adds web-ui workspace ignores.
templates/packages/cli.README.md Documents that the published CLI bundle includes the web dashboard assets.
src/web/server.ts Implements Node HTTP server: routes /api/*, serves web-ui/dist, SPA fallback, bind warning.
src/web/routes/workflow.ts Adds workflow REST routes backed by harness workflow services.
src/web/routes/skills.ts Adds skills REST routes backed by harness skill action service.
src/web/routes/sessions.ts Adds sessions REST routes backed by harness runtime state service.
src/web/routes/events.ts Adds SSE route emitting hello + debounced runtime-change events.
src/web/routes/docs.ts Adds docs REST routes backed by the new harness docs service.
src/web/routes/agents.ts Adds agents REST routes backed by harness agent action service.
src/web/router.ts Adds small route table + (method, pathname) matcher for src/web.
src/web/response.ts Adds { data } / { error: { message } } envelope helpers.
src/web/index.ts Exposes web boundary exports (server + defaults).
src/web/events/runtimeWatcher.ts Adds chokidar-based watcher to coalesce .context/runtime/** writes.
src/web/events/tests/runtimeWatcher.test.ts Adds unit tests for watcher batching + relative path formatting + close behavior.
src/web/tests/server.test.ts Adds integration tests for REST endpoints, static SPA fallback, and SSE hello event.
src/web/tests/router.test.ts Adds router unit tests (matching + decoding + error handling).
src/tests/architecture/tests/boundaries.test.ts Enforces src/web boundary independence from src/cli and src/mcp.
src/harness/index.ts Re-exports new harness services/types used by the web adapter.
src/harness/domain/workflow/plans/planLinker.ts Exposes agent content retrieval for dashboard agent inspection.
src/harness/application/workflow/index.ts Exports guide service/types via workflow application index.
src/harness/application/index.ts Exports the new docs application module.
src/harness/application/docs/index.ts Adds docs module barrel export.
src/harness/application/docs/HarnessDocsService.ts Adds a harness service to list/get .context/docs/*.md with frontmatter parsing.
src/harness/application/docs/tests/HarnessDocsService.test.ts Adds unit tests for docs listing/content parsing + traversal rejection.
src/harness/application/agents/agentsService.ts Includes agent playbook content in agent info responses (for dashboard).
src/bin/dotcontext.ts Adds dotcontext web CLI command + browser auto-open + dist checks.
src/tests/cli.test.ts Ensures CLI help exposes web command and flags.
scripts/smoke-package-bundles.js Adds smoke assertion that CLI bundle includes web-ui/dist/index.html.
scripts/dev-web.js Adds combined dev runner for web API + Vite UI.
scripts/build-package-bundles.js Copies web-ui/dist into CLI bundle and adds runtime deps (incl. chokidar).
README.md Documents the new dashboard surface and how to run it.
package.json Adds dev/build scripts for web dashboard and bundles web-ui/dist for publish.
package-lock.json Adds chokidar + transitive deps to lockfile.
docs/src/content/docs/pt-br/reference/cli-commands.md Documents web CLI command and flags (pt-BR).
docs/src/content/docs/pt-br/index.mdx Adds dashboard link card (pt-BR).
docs/src/content/docs/pt-br/guides/web-dashboard.md Adds full dashboard guide (pt-BR).
docs/src/content/docs/pt-br/guides/using-the-cli.md Adds dashboard usage section (pt-BR).
docs/src/content/docs/en/reference/cli-commands.md Documents web CLI command and flags (en).
docs/src/content/docs/en/index.mdx Adds dashboard link card (en).
docs/src/content/docs/en/guides/web-dashboard.md Adds full dashboard guide (en).
docs/src/content/docs/en/guides/using-the-cli.md Adds dashboard usage section (en).
CONTRIBUTING.md Adds contributor workflow for dashboard dev/build/package validation.
CHANGELOG.md Notes new dashboard and packaging changes in Unreleased.
ARCHITECTURE.md Updates architecture to include web + web-ui surfaces.
.context/docs/web-interface-architecture.md Adds ADRs and authoritative API/SSE contract for the dashboard.
.context/docs/tooling.md Documents new scripts for web dashboard development/building.
.context/docs/README.md Adds web interface architecture doc to .context index.
.context/docs/development-workflow.md Adds dashboard dev loop and build guidance.
.claude/settings.json Adds Claude hook dispatch configuration (related to runtime visibility in dashboard).
Files not reviewed (2)
  • pnpm-lock.yaml: Generated file
  • web-ui/pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/web/server.ts
Comment on lines +28 to +30
try {
const session = await runtimeStateService(ctx).getSession(params.id);
sendData(res, 200, session);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified this against the branch — the finding is real, and the same root cause covers all four session-route comments (getSession, listTraces, listArtifacts, listCheckpoints):

  1. matchRoute in src/web/router.ts calls decodeURIComponent() on :param segments, so GET /api/sessions/..%2F..%2F..%2Fx/traces still matches the 4-segment pattern and hands the handler params.id === "../../../x".
  2. Nothing validates the id from there down: HarnessRuntimeStateService delegates to resolveRuntimeLayout (src/shared/fs/pathHelpers.ts), which raw-joins — sessionDir: (id) => path.join(sessionsDir, id).

Impact is bounded, but not theoretical. The trailing filename is fixed (session.json, trace.jsonl, artifacts/*.json), so this doesn't give arbitrary file read — but it does allow probing/enumerating directories anywhere on disk and reading any JSON file with those names (e.g. sessions from other dotcontext repos on the same machine). And since the API has no auth and doesn't validate the Host header, "localhost-only" doesn't fully neutralize it: a DNS-rebinding page can reach these endpoints from a browser, and --host explicitly supports non-localhost binds.

The fix is cheap because session ids are always randomUUID() (see createSession in runtimeStateService.ts): reject any params.id that doesn't match a strict allowlist (e.g. /^[0-9a-fA-F-]{1,64}$/) with a 400 before calling the service.

Two notes on where to put the guard:

  • HarnessDocsService.getContent already resolves /api/docs/:name through PathValidator specifically so traversal names can't escape .context/docs — so the sessions routes are the one param surface that reaches a path.join unguarded. Reusing the same pattern keeps the adapter consistent.
  • Beyond the web adapter, I'd also consider a defense-in-depth check inside resolveRuntimeLayout's sessionDir/sessionFile/sessionTraceFile/sessionArtifactsDir helpers (reject ids containing /, \, .., or absolute paths). That protects every current and future adapter (MCP, hooks) at the shared layer instead of relying on each transport to remember the guard.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed as high relevance for dotcontext. The new web surface accepts an explicit non-local --host while this decoded value crosses from HTTP into the filesystem-backed runtime without an identifier invariant. Please make this a single shared/session-boundary validation (not four route-local patches) and reject it before resolving any runtime path. This should block merge.

Comment on lines +37 to +40
try {
const traces = await runtimeStateService(ctx).listTraces(params.id);
sendData(res, 200, traces);
} catch (error) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same boundary flaw as the session-detail route and should be fixed by the shared session-ID guard. Add a regression request with encoded traversal/separators to prove listTraces rejects it before HarnessRuntimeStateService receives an ID.

Comment on lines +46 to +49
try {
const artifacts = await runtimeStateService(ctx).listArtifacts(params.id);
sendData(res, 200, artifacts);
} catch (error) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This endpoint makes the impact especially clear because it can enumerate JSON artifacts after the decoded parameter reaches the path layout. Cover it through the shared guard, including %2e%2e, encoded /, and \\, rather than maintaining a route-specific blacklist.

Comment on lines +55 to +58
try {
const checkpoints = await runtimeStateService(ctx).listCheckpoints(params.id);
sendData(res, 200, checkpoints);
} catch (error) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Treat all four sessions/:id routes as one merge-blocking contract: only a valid session identifier may cross into the runtime-state service. The regression suite should cover each endpoint and both rejected dependency outcomes (404/400 as chosen by the API contract).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants