feat(dashboard): merge web chat into dashboard app#476
Conversation
Consolidate @corvus/chat into @corvus/dashboard, making dashboard the sole operator-facing Vue/Vite app. Chat becomes a first-class tab alongside Config, Sessions, and Memory views. - Create ChatWorkspace component from chat App.vue - Add useChatGateway adapter bridging useConfig auth to ChatGateway interface - Port useChat composable with ChatGateway interface instead of useGateway - Move chat components (ChatMessage, ToolApprovalCard, HealthIndicator, SessionSidebar) - Add Chat tab to dashboard navigation - Port all chat tests (47 files, 306 tests passing) - Remove @corvus/chat package and all chat-specific scripts/targets - Update Makefile, build.gradle.kts, package.json, README, AGENTS.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deploying corvus with
|
| Latest commit: |
45bf359
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://767f76ce.corvus-42x.pages.dev |
| Branch Preview URL: | https://feat-merge-chat-into-dashboa.corvus-42x.pages.dev |
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughSummary by CodeRabbit
WalkthroughRemoved the standalone Changes
Sequence DiagramsequenceDiagram
actor User
participant DashboardApp as "Dashboard App"
participant ChatWorkspace as "ChatWorkspace"
participant useChatGateway as "useChatGateway"
participant useChat as "useChat"
participant ChatGateway as "Gateway API"
participant SessionStorage as "sessionStorage"
User->>DashboardApp: open Dashboard → select Chat tab
DashboardApp->>ChatWorkspace: render ChatWorkspace
ChatWorkspace->>useChatGateway: init gateway(adapter)
useChatGateway->>useChatGateway: normalize baseUrl, build authHeaders
User->>ChatWorkspace: Click "Start Session"
ChatWorkspace->>useChat: startSession()
useChat->>ChatGateway: POST /session (create)
ChatGateway-->>useChat: { sessionId }
useChat->>SessionStorage: persist sessionId
ChatWorkspace->>ChatWorkspace: show message input
User->>ChatWorkspace: Send message
ChatWorkspace->>useChat: streamMessage(content)
useChat->>ChatGateway: POST /stream (SSE)
loop streaming chunks
ChatGateway-->>useChat: StreamChunkEvent (text)
useChat->>ChatWorkspace: update assistant message (partial)
end
ChatGateway-->>useChat: StreamDoneEvent
useChat->>SessionStorage: persist messages
ChatWorkspace->>User: display final assistant message
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Contributor ReportUser: @yacosta738
Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-04-10 to 2026-04-10 |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
clients/web/README.md (1)
3-3:⚠️ Potential issue | 🟡 MinorStale references to standalone chat app in structure and intro.
The intro (line 3) still mentions "chat" as a separate app, and the structure diagram (line 12) still lists
apps/chat/. These should be updated since the chat directory was deleted.📝 Proposed fix
-Monorepo for Corvus web apps, including docs, marketing, chat, and dashboard. +Monorepo for Corvus web apps, including docs, marketing, and dashboard.And update the structure diagram:
├── apps/ │ ├── docs/ # Documentation (Astro + Starlight) │ ├── marketing/ # Marketing landing and campaign pages (Astro) -│ ├── chat/ # ChatGPT-style conversational chat (Vue 3 + Vite) -│ └── dashboard/ # Secure gateway dashboard (Vue 3 + Vite) +│ └── dashboard/ # Secure gateway dashboard with embedded chat (Vue 3 + Vite)Also applies to: 12-12
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/README.md` at line 3, Update the README intro and project structure diagram to remove stale references to the standalone chat app: edit the sentence that mentions "chat" as a separate app (around the intro line) to reflect that chat was consolidated or removed, and remove `apps/chat/` from the ASCII/markdown structure diagram (and any other occurrences in this file) so the README accurately represents current directories and apps..agents/AGENTS.md (1)
137-137:⚠️ Potential issue | 🟡 MinorStale command reference:
make chat-checkno longer exists.This line still references
make chat-check, but that target was removed from the Makefile. Update to remove the stale reference.📝 Proposed fix
-- `make docs-check`, `make chat-check`, `make dashboard-check`, `make marketing-check` +- `make docs-check`, `make dashboard-check`, `make marketing-check`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/AGENTS.md at line 137, The README reference to the removed make target includes a stale `make chat-check` entry; update the documentation to remove `make chat-check` from the comma-separated list (the line that currently reads "`make docs-check`, `make chat-check`, `make dashboard-check`, `make marketing-check`") so it lists only existing targets (e.g., "`make docs-check`, `make dashboard-check`, `make marketing-check`").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@clients/web/apps/dashboard/src/components/chat/ChatWorkspace.vue`:
- Around line 209-218: The approval flow is broken because the new approval card
stores result.sessionId as approvalId and handlers only mutate local text, so
approvals never get sent upstream and subsequent approvals collide. Fix by
assigning a unique approval identifier per approval message (use a distinct
field from result like result.approvalId or generate a new id via
nextMessageId()) when creating the message in the block that calls
updateAssistantMessage and pushes to messages.value; then update the approval
handlers (the functions that send approve/reject events — e.g., the
approve/reject/handleApproval functions referenced around the same component) to
include and send that approvalId (and sessionId if required by the server
contract) upstream instead of only rewriting local content, and ensure they
target messages by that per-card approvalId when updating message state.
- Around line 242-259: The persisted messages are keyed only by
chat.currentSessionId (messagesStorageKey) which can expose another operator's
cached transcript; update messagesStorageKey() and persistMessages() to include
a non-secret auth scope (e.g., current user's id/tenant or authContext.scope) or
to clear stored entries when credentials change: modify messagesStorageKey() to
concat a safe auth identifier from the auth store (not secrets), ensure
persistMessages() returns early if authContext missing, and add a listener that
wipes sessionStorage entries for this key when the auth/credentials change;
reference functions/messagesStorageKey, persistMessages, chat.currentSessionId
and sessionStorage in the implementation.
- Around line 117-120: The startNewSession flow currently clears the session
before pending writes are flushed, causing the latest turn to be lost; update
startNewSession so it calls and awaits the existing persistMessages() (or the
equivalent message-flush function used by handleSidebarNewChat) before invoking
chat.clearSession(), ensuring any debounced writes are persisted to the current
session id, then proceed to await beginSession(false); also propagate or handle
errors from persistMessages() so failures don’t silently drop data.
In `@clients/web/apps/dashboard/src/composables/useChatGateway.ts`:
- Around line 95-108: The response handling currently trusts data.sessions and
data.total; update the parsing to drop malformed session rows and clamp total to
a non-negative integer: validate each element of data.sessions (ensure it is an
object with id:string, started_at:string, ended_at:string|null,
message_count:number, last_activity:string) and only include those in the
returned sessions array instead of using Array.isArray(data.sessions) alone, and
coerce/limit data.total to Math.max(0, Math.floor(Number(data.total) || 0))
before returning; adjust the logic around the variables data, sessions and total
in this function so downstream consumers only receive well-typed rows and a safe
non-negative total.
---
Outside diff comments:
In @.agents/AGENTS.md:
- Line 137: The README reference to the removed make target includes a stale
`make chat-check` entry; update the documentation to remove `make chat-check`
from the comma-separated list (the line that currently reads "`make docs-check`,
`make chat-check`, `make dashboard-check`, `make marketing-check`") so it lists
only existing targets (e.g., "`make docs-check`, `make dashboard-check`, `make
marketing-check`").
In `@clients/web/README.md`:
- Line 3: Update the README intro and project structure diagram to remove stale
references to the standalone chat app: edit the sentence that mentions "chat" as
a separate app (around the intro line) to reflect that chat was consolidated or
removed, and remove `apps/chat/` from the ASCII/markdown structure diagram (and
any other occurrences in this file) so the README accurately represents current
directories and apps.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 78f2b297-689a-45c4-b703-be688fcbe2fc
⛔ Files ignored due to path filters (2)
clients/web/apps/chat/public/favicon-light.svgis excluded by!**/*.svgclients/web/apps/chat/public/favicon.svgis excluded by!**/*.svg
📒 Files selected for processing (43)
.agents/AGENTS.mdMakefileclients/web/README.mdclients/web/apps/chat/README.mdclients/web/apps/chat/components.jsonclients/web/apps/chat/index.htmlclients/web/apps/chat/package.jsonclients/web/apps/chat/src/App.spec.tsclients/web/apps/chat/src/App.vueclients/web/apps/chat/src/components/ConfigPanel.vueclients/web/apps/chat/src/composables/useGateway.spec.tsclients/web/apps/chat/src/composables/useGateway.tsclients/web/apps/chat/src/i18n.tsclients/web/apps/chat/src/lib/utils.tsclients/web/apps/chat/src/main.tsclients/web/apps/chat/src/onboardingContract.spec.tsclients/web/apps/chat/src/raw-imports.d.tsclients/web/apps/chat/src/style.cssclients/web/apps/chat/src/types/chat.tsclients/web/apps/chat/tsconfig.app.jsonclients/web/apps/chat/tsconfig.jsonclients/web/apps/chat/tsconfig.node.jsonclients/web/apps/chat/vite.config.jsclients/web/apps/chat/vite.config.tsclients/web/apps/dashboard/src/App.vueclients/web/apps/dashboard/src/components/chat/ChatMessage.spec.tsclients/web/apps/dashboard/src/components/chat/ChatMessage.vueclients/web/apps/dashboard/src/components/chat/ChatWorkspace.spec.tsclients/web/apps/dashboard/src/components/chat/ChatWorkspace.vueclients/web/apps/dashboard/src/components/chat/HealthIndicator.spec.tsclients/web/apps/dashboard/src/components/chat/HealthIndicator.vueclients/web/apps/dashboard/src/components/chat/SessionSidebar.spec.tsclients/web/apps/dashboard/src/components/chat/SessionSidebar.vueclients/web/apps/dashboard/src/components/chat/ToolApprovalCard.spec.tsclients/web/apps/dashboard/src/components/chat/ToolApprovalCard.vueclients/web/apps/dashboard/src/composables/chatOnboardingContract.spec.tsclients/web/apps/dashboard/src/composables/useChat.spec.tsclients/web/apps/dashboard/src/composables/useChat.tsclients/web/apps/dashboard/src/composables/useChatGateway.spec.tsclients/web/apps/dashboard/src/composables/useChatGateway.tsclients/web/apps/dashboard/src/types/chat.tsclients/web/build.gradle.ktsclients/web/package.json
💤 Files with no reviewable changes (22)
- clients/web/apps/chat/components.json
- clients/web/apps/chat/README.md
- clients/web/apps/chat/tsconfig.json
- clients/web/build.gradle.kts
- clients/web/apps/chat/index.html
- clients/web/apps/chat/src/lib/utils.ts
- clients/web/apps/chat/tsconfig.app.json
- clients/web/apps/chat/src/main.ts
- clients/web/apps/chat/vite.config.ts
- clients/web/apps/chat/package.json
- clients/web/apps/chat/src/App.spec.ts
- clients/web/apps/chat/src/raw-imports.d.ts
- clients/web/apps/chat/vite.config.js
- clients/web/apps/chat/src/i18n.ts
- clients/web/apps/chat/src/style.css
- clients/web/apps/chat/src/onboardingContract.spec.ts
- clients/web/apps/chat/src/composables/useGateway.spec.ts
- clients/web/apps/chat/src/types/chat.ts
- clients/web/apps/chat/tsconfig.node.json
- clients/web/apps/chat/src/components/ConfigPanel.vue
- clients/web/apps/chat/src/App.vue
- clients/web/apps/chat/src/composables/useGateway.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: pr-checks
- GitHub Check: sonar
- GitHub Check: submit-gradle
- GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (4)
**/*
⚙️ CodeRabbit configuration file
**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.
Files:
clients/web/apps/dashboard/src/components/chat/SessionSidebar.spec.tsclients/web/apps/dashboard/src/components/chat/HealthIndicator.spec.tsclients/web/apps/dashboard/src/composables/useChat.tsclients/web/README.mdclients/web/package.jsonclients/web/apps/dashboard/src/App.vueMakefileclients/web/apps/dashboard/src/composables/useChatGateway.spec.tsclients/web/apps/dashboard/src/components/chat/ChatWorkspace.spec.tsclients/web/apps/dashboard/src/composables/chatOnboardingContract.spec.tsclients/web/apps/dashboard/src/components/chat/ChatWorkspace.vueclients/web/apps/dashboard/src/composables/useChatGateway.tsclients/web/apps/dashboard/src/types/chat.tsclients/web/apps/dashboard/src/composables/useChat.spec.ts
.agents/AGENTS.md
📄 CodeRabbit inference engine (AGENTS.md)
.agents/AGENTS.md: Document agent configurations and capabilities in AGENTS.md
Maintain comprehensive agent metadata including name, description, purpose, and capabilities
Include version information and compatibility details for agents
Files:
.agents/AGENTS.md
**/*.{md,mdx}
⚙️ CodeRabbit configuration file
**/*.{md,mdx}: Verify technical accuracy and that docs stay aligned with code changes.
For user-facing docs, check EN/ES parity or explicitly note pending translation gaps.
Files:
clients/web/README.md
**/*.vue
⚙️ CodeRabbit configuration file
**/*.vue: Enforce Vue 3 Composition API with <script setup>.
Ensure accessibility (A11y) and proper use of Tailwind CSS classes.
Check for proper prop validation and emitted events documentation.
Files:
clients/web/apps/dashboard/src/App.vueclients/web/apps/dashboard/src/components/chat/ChatWorkspace.vue
🧠 Learnings (3)
📚 Learning: 2026-02-17T07:28:38.934Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-17T07:28:38.934Z
Learning: Applies to .agents/AGENTS.md : Document agent configurations and capabilities in AGENTS.md
Applied to files:
.agents/AGENTS.md
📚 Learning: 2026-02-17T07:28:38.934Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-17T07:28:38.934Z
Learning: Applies to .agents/AGENTS.md : Include version information and compatibility details for agents
Applied to files:
.agents/AGENTS.md
📚 Learning: 2026-02-17T12:31:17.076Z
Learnt from: CR
Repo: dallay/corvus PR: 0
File: clients/agent-runtime/AGENTS.md:0-0
Timestamp: 2026-02-17T12:31:17.076Z
Learning: Applies to clients/agent-runtime/**/*.rs : Run `cargo fmt --all -- --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` for code validation, or document which checks were skipped and why
Applied to files:
Makefile
🔇 Additional comments (12)
clients/web/apps/dashboard/src/components/chat/HealthIndicator.spec.ts (1)
5-5: Import path update is correct for the migration.Line 5 now targets the relocated component under
@/components/chat/HealthIndicator.vue, which aligns with the chat-to-dashboard consolidation and preserves test behavior.clients/web/apps/dashboard/src/components/chat/SessionSidebar.spec.ts (1)
6-6: LGTM!Import path correctly updated to reflect the component's new location under
components/chat/.Makefile (1)
210-214: LGTM!Chat-specific Makefile targets correctly removed. The
web-check-alltarget now only runs checks for docs, dashboard, and marketing—consistent with the chat consolidation into dashboard.Also applies to: 384-384
clients/web/apps/dashboard/src/composables/useChat.ts (1)
3-3: LGTM!Type import correctly updated to use the shared
ChatGatewayinterface from@/types/chat, enabling clean dependency injection betweenuseChatGatewayanduseChat.clients/web/package.json (1)
5-5: LGTM!Description and scripts correctly updated to reflect the removal of the standalone chat app.
clients/web/README.md (1)
39-43: LGTM on the dashboard description updates.The framework and chat section descriptions accurately reflect the consolidation.
clients/web/apps/dashboard/src/App.vue (3)
222-231: LGTM!Chat navigation tab correctly implements the same accessibility pattern as sibling tabs:
role="tab",aria-selectedbinding, active class, anddata-testidfor testing.
613-618: LGTM!Chat page section properly guards on
config.isOperatorReady.value, consistent with other protected pages (sessions, memory). TheChatWorkspacereceives the full config object as expected.
938-943: LGTM!Chat section styling provides reasonable height constraints (
min-height: 520px,max-height: 75vh) to ensure usable chat area while preventing overflow.clients/web/apps/dashboard/src/components/chat/ChatWorkspace.spec.ts (3)
1-94: LGTM!Well-structured test setup with proper mocking strategy. Good practices:
- Typed fetch mock
- Cleanup in
beforeEach(reset mock, clear sessionStorage)- Mock config factory matching
useConfigreturn type
241-272: Good security test coverage for persisted message validation.This test validates that messages with non-finite IDs (e.g.,
Infinity) are rejected, preventing potential injection of malformed data from sessionStorage. This aligns with the XSS-safe rendering requirement noted in the PR objectives.
195-239: LGTM!SSE streaming test correctly validates chunk accumulation behavior—ensuring "Hello" and " World" are concatenated rather than overwritten.
- Fix approval ID collision: use unique ID per approval card instead of session ID, preventing multiple approvals from overwriting each other - Flush pending writes in startNewSession before clearing session, preventing loss of the latest turn when debounce timer hasn't fired - Scope message storage key by gateway URL and clear stored messages on credential change, preventing cross-operator transcript leakage - Validate session list rows in useChatGateway: drop malformed entries and clamp total to non-negative integer - Remove stale make chat-check from AGENTS.md - Remove stale chat references from README intro and directory diagram Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
@corvus/chatinto@corvus/dashboard, making dashboard the sole operator-facing Vue/Vite appKey Changes
App.vueinto a self-containedChatWorkspace.vuethat renders inside the dashboard shelluseConfigauth/onboarding state to theChatGatewayinterface expected byuseChat, avoiding duplication of gateway logicChatGatewayinterface (intypes/chat.ts) instead of coupling toReturnType<typeof useGateway>dashboard/src/components/chat/ChatWorkspacewhen selected@corvus/chatpackage, all chat-specific scripts (build:chat,dev:chat,test:chat), Makefile targets, andbuild.gradle.ktsentryWhat's Preserved
/web/chat/stream,/webhook,/session/list)Test Plan
🤖 Generated with Claude Code