feat(dashboard): multi-panel workspace with terminal, inline diffs, and mentions#291
Merged
feat(dashboard): multi-panel workspace with terminal, inline diffs, and mentions#291
Conversation
…nd mentions Turn the dashboard into a unified workspace that brings Files, multi-session Agent Chats, and an integrated terminal together in a single resizable layout, and layer agent-facing IDE affordances on top. - Add pty-backed terminal WebSocket endpoint (TerminalSession/TerminalConnection) and wire xterm.js TerminalPane + TerminalTabs on the frontend. - Introduce WorkspacePage with react-resizable-panels, persisted layout via workspaceLayoutStore, Ctrl+` terminal toggle, and multi-session chat tabs powered by chatSessionStore + useChatSessionHotkeys. - Ship @-mention file autocomplete in ChatInput driven by getFileTree, inline accept/reject for proposed edits via @codemirror/merge (proposedEditStore + InlineDiffView + ProposedEditsPanel), and a /run command in ChatWindow that routes into the active terminal tab through terminalStore. - Forward ideStore.openedTabs and activePath as chat turn context from chatRuntimeMessageActions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Terminal backend: - TerminalConnection: replace waitFor(1 day) with exit-wait strategy that loops until the pty actually terminates - TerminalSessionLimiter: new per-user lease tracker backing the terminal feature flag, concurrency cap, idle timeout, and max session duration - TerminalWebSocketHandler: gate on bot.dashboard.terminal.enabled, acquire a lease per connection, apply idle timeout via Flux.timeout and absolute cap via Flux.take, release lease in doFinally - BotProperties: add DashboardProperties.terminal with enabled, maxSessionsPerUser, idleTimeout, maxSessionDuration Terminal frontend: - TerminalPane: consolidate duplicated sendInputChunk logic and subscribe to terminalStore with a selector so unrelated state changes no longer re-drain pending input - terminalStore: wrap with subscribeWithSelector middleware File mentions: - useFileMentions: replace eager full-tree fetch with a shallow initial load and lazy per-directory subtree loading, deduped via fetched/in-flight refs - fileMentions: rewrite flattenFileTree as O(n) push/pop traversal Tests added for every behavior above (red->green) including race-free lease release assertions via short polling loop.
- TerminalSessionLimiter: acquire/release via ConcurrentHashMap.compute
so the bin lock serializes concurrent acquire and release. Lease uses
AtomicBoolean for idempotent double-release and delegates decrement
back to the limiter, which now evicts the user entry when the last
lease is released (added trackedUserCount() for test visibility).
- ExitWatcher: extracted from TerminalConnection into its own daemon
helper with a dedicated ExitWatcherTest, eliminating the nullable
TerminalSession and the test-only openWithStrategy seam.
- TerminalConnection: drop null-session guards now that the exit-wait
loop lives in ExitWatcher; emitExit is suppressed after close.
- BotProperties.TerminalProperties: default enabled=true (override via
BOT_DASHBOARD_TERMINAL_ENABLED or bot.dashboard.terminal.enabled) and
document that idle timeout is measured on inbound frames only.
- useFileMentions: remove dead fetchedDirsRef.add('').
- TerminalWebSocketHandlerTest: document why awaitLeaseReleased polls.
Red->green tests:
- shouldEvictUserEntryWhenAllLeasesReleased
- shouldTreatDoubleReleaseAsIdempotentUnderConcurrency (32 threads)
- ExitWatcherTest.shouldLoopUntilStrategySignalsTermination
- ExitWatcherTest.shouldSuppressExitCallbackWhenStoppedBeforeTermination
- ExitWatcher.start() guarded by an AtomicBoolean so a redundant second call is a no-op instead of IllegalThreadStateException. - TerminalSessionLimiter.releaseSlot() simplified to decrementAndGet now that double-release is CAS-gated at the Lease level. - TerminalSessionLimiter.tryAcquire() cap-rejected branch returns the locally-held counter for clarity. - BotProperties.TerminalProperties.enabled javadoc now calls out the production security posture (disable unless browser-shell access is an explicit requirement). - ExitWatcherTest adds a red-to-green idempotent-start test and hardens the stop-before-exit assertion into a 300ms polling window. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
alexk-dev
added a commit
that referenced
this pull request
Apr 15, 2026
Tracks the TDD-driven phases behind PR #291: multi-session chat tabs, the three-pillar workspace (files / chats / terminal), inline diff review, and file-mention autocomplete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tracks the TDD-driven phases behind PR #291: multi-session chat tabs, the three-pillar workspace (files / chats / terminal), inline diff review, and file-mention autocomplete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bd614e8 to
4ed3694
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Turns the dashboard into a unified workspace that combines files, chat, and terminal in one flow.
/ws/terminalwith multi-tab terminal sessions@mentions, and/run <cmd>handoff into terminal