Skip to content

feat(dashboard): Add authenticated Junior dashboard#448

Merged
dcramer merged 26 commits into
mainfrom
feat/junior-dashboard
May 31, 2026
Merged

feat(dashboard): Add authenticated Junior dashboard#448
dcramer merged 26 commits into
mainfrom
feat/junior-dashboard

Conversation

@dcramer
Copy link
Copy Markdown
Member

@dcramer dcramer commented May 30, 2026

Add a packaged Junior dashboard that runs as a Nitro plugin with Better Auth-protected routes, a React command center, conversation lists, and permalinked transcript views. This replaces the old diagnostics dashboard surface with a deployable dashboard package and wires the example app for local development.

Dashboard Package

The new @sentry/junior-dashboard package exposes Nitro and handler entry points, dashboard APIs, route tests, docs, and a dark-mode UI for command center stats, turn duration history, and conversation details. Dashboard points and conversation rows link to stable conversation permalinks, and Sentry links appear when the runtime has enough Sentry configuration.

Conversation Privacy

Junior now classifies conversation privacy and redacts private message, thinking, tool argument, and tool result content before exposing dashboard APIs or trace metadata. Private views keep safe metadata such as actor, status, message counts, tool names, timing, and byte sizes without leaking raw transcript content.

Instrumentation And Packaging

Turn tracing captures more OpenTelemetry-aligned conversation metadata while respecting redaction policy. @sentry/node and @sentry/starlight-theme concrete versions are pinned through pnpm catalogs, and Junior owns its Sentry SDK dependency directly instead of requiring apps to install it separately.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview, Comment May 31, 2026 2:26pm

Request Review

Comment thread packages/junior-dashboard/src/app.ts Fixed
Comment thread packages/junior-dashboard/src/nitro.ts Fixed
Comment thread packages/junior-dashboard/src/handler.ts
Comment thread packages/junior-dashboard/src/app.ts
Comment thread packages/junior-dashboard/src/client/format.ts
Comment thread packages/junior/src/reporting.ts
Comment thread packages/junior/src/chat/respond.ts
Comment thread packages/junior/src/reporting.ts
Comment thread packages/junior-dashboard/src/app.ts
Comment thread packages/junior-dashboard/src/client/App.tsx Outdated
dcramer and others added 8 commits May 30, 2026 21:06
Add a packaged Junior dashboard with Better Auth, reporting APIs, conversation views, transcript redaction, and Sentry links. Replace the old diagnostics dashboard routes with the dashboard package and wire the example app to run it locally.

Capture safer conversation metadata for dashboard and trace reporting while redacting private conversation inputs and outputs. Add dashboard docs, policy coverage, and tests for the route and reporting behavior.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Replace dashboard path and auth URL slash-trimming regexes with linear helpers so CodeQL does not flag route inputs as polynomial regular expression risks.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Cache standalone dashboard handler initialization through a single promise so concurrent first requests do not create duplicate dashboard app instances.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
- Extend auth middleware to cover page sub-routes when basePath is "/";
  app.use("/", ...) only matches the exact root in Hono, leaving
  /conversations, /sessions, and their children unprotected
- Make the initial recordAgentTurnSessionSummary(state='running') call
  fire-and-forget so it does not delay reply generation; the 'running'
  state record is best-effort tracking and must not block the turn
- Add GEN_AI_SERVER_ADDRESS to @/chat/pi/client mocks in four unit test
  files that mock the module without this export; respond.ts uses the
  constant and vitest strict mocks reject missing exports

Action taken on behalf of David Cramer.

---
[View Session in Sentry](https://sentry.sentry.io/traces/?project=4510944073809921&query=gen_ai.conversation.id%3A%22slack%3AC0B595QDZLL%3A1780119001.371349%22)

Co-authored-by: David Cramer <david@sentry.io>
Missed GEN_AI_SERVER_PORT=443 in the previous mock patch. The export
was added alongside GEN_AI_SERVER_ADDRESS in this PR; respond.ts uses
both at line 1165 and vitest strict mocks reject any missing export.

Action taken on behalf of David Cramer.

---
[View Session in Sentry](https://sentry.sentry.io/traces/?project=4510944073809921&query=gen_ai.conversation.id%3A%22slack%3AC0B595QDZLL%3A1780119001.371349%22)

Co-authored-by: David Cramer <david@sentry.io>
When resolveConversationPrivacy returns undefined (no recognizable Slack
channel identifier), privacy checks using === "private" incorrectly take
the expose-content path. traced-stream.ts already uses the correct
pattern (=== "public" to expose, else redact). Align respond.ts input
and output message serialization and reporting.ts session title/channel
redaction to use !== "public", so undefined falls to the safe
metadata-only path.

Fixes Warden finding EZN-84H.

Action taken on behalf of David Cramer.

---
[View Session in Sentry](https://sentry.sentry.io/traces/?project=4510944073809921&query=gen_ai.conversation.id%3A%22slack%3AC0B595QDZLL%3A1780119001.371349%22)

Co-authored-by: David Cramer <david@sentry.io>
- Change advisor/tool.ts privacy guards from === "private" to !== "public"
  to match the fail-closed pattern mandated by specs/data-redaction-policy.md
  and used in respond.ts, reporting.ts, and traced-stream.ts; the existing
  ?? "private" default made it functionally safe but the pattern was
  inconsistent and fragile
- Add dashboard-routes test covering unauthenticated access to /conversations,
  /conversations/:id, /sessions, and /sessions/:id at root basePath; the
  previous test only verified / and would not have caught the Hono routing
  gap where app.use("/", ...) skips sub-routes

Action taken on behalf of David Cramer.

---
[View Session in Sentry](https://sentry.sentry.io/traces/?project=4510944073809921&query=gen_ai.conversation.id%3A%22slack%3AC0B595QDZLL%3A1780119001.371349%22)

Co-authored-by: David Cramer <david@sentry.io>
Keep loaded skill metadata available when timeout and auth-pause persistence runs outside the active skill scope. Add dashboard reporting coverage for the session-record-backed transcript path.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Comment thread packages/junior-dashboard/src/config.ts Outdated
Move dashboard-specific presentation out of the HTML stylesheet and into Tailwind-styled React components. Use a simpler black Junior mark and keep only the logo/title link target in the header.

Add the frontend component policy and update dashboard reporting language for turn-session records. Tighten turn-session parsing to the current session-log storage contract and keep summary updates projection-only.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Require dashboard sessions to have a verified email before matching explicit allowedEmails entries. This keeps email exceptions aligned with the hosted-domain authorization path and the dashboard spec.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Comment thread packages/junior/src/reporting.ts
Keep auth-resume records materialized with projection-tail host observations while terminal turn transcripts stay pinned to their committed prefix. Avoid adding a conversation-specific turn-session API for dashboard detail reads by reusing the existing summary feed with a dashboard-scoped limit.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Mark non-public conversation turns as privacy redacted even after the transcript checkpoint expires. This keeps expired private turns from looking like generic missing transcripts.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep the best-effort running turn summary write off the critical path while still capturing failures. This avoids unhandled promise rejections from dashboard checkpoint recording.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Read conversation detail from a conversation-scoped turn-session index so permalink pages do not depend on the capped global recent feed. Keep a global-index fallback for records written before the conversation index existed.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Comment thread packages/junior-dashboard/src/client/api.ts
Redirect dashboard API callers back through the dashboard login route when an authenticated request returns 401. This prevents expired sessions from leaving the SPA in a polling error state.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 9 total unresolved issues (including 8 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d16817f. Configure here.

Comment thread packages/junior-dashboard/src/handler.ts
Clear the cached standalone dashboard app promise when config or app creation rejects so a transient startup failure does not pin the handler until process restart.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Keep the dashboard fallback HTML aligned with the frontend component policy by using Tailwind classes instead of inline styles.

Co-Authored-By: GPT-5 Codex <codex@openai.com>
Disable Better Auth account-data cookies for dashboard OAuth sessions.

Bound private payload key metadata and add coverage for the denied-page shell.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Separate dashboard-owned routes from the public runtime health route.

Document that private conversation APIs expose redacted metadata instead of raw transcript payloads.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Strip Better Auth session internals before dashboard routes store identity in request context. This keeps the /api/dashboard/me response limited to display-safe user fields even when the auth provider returns a broader session object.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Require dashboard auth by default in the example app and only disable it for local development outside Vercel. This keeps Vercel preview and production deployments authenticated while preserving a low-friction pnpm dev path.

Co-Authored-By: GPT-5 Codex <noreply@openai.com>
@dcramer dcramer merged commit 8a47b0a into main May 31, 2026
16 checks passed
@dcramer dcramer deleted the feat/junior-dashboard branch May 31, 2026 14:40
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