Skip to content

Add local servers to the thread context panel#5

Merged
Eccentric-jamaican merged 4 commits into
mainfrom
codex/project-panel-local-servers
Jun 12, 2026
Merged

Add local servers to the thread context panel#5
Eccentric-jamaican merged 4 commits into
mainfrom
codex/project-panel-local-servers

Conversation

@Eccentric-jamaican

@Eccentric-jamaican Eccentric-jamaican commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Problem statement

The thread context panel had grown into a useful place for project state, but it was still missing two practical pieces during day-to-day work:

  • users could not see or stop project-local servers that were already running outside the in-app terminal
  • quick actions existed as a concept, but the panel experience around them was not persistent or polished enough for repeated use inside a project

A few follow-on issues surfaced while building this:

  • the local-servers surface could get stuck in a loading state when the backend route was missing or stale
  • the first empty state could appear before the initial check had actually completed
  • the add-action inputs were hosted inside a menu surface, so typing did not persist
  • external server rows exposed noisy raw command text instead of a clean, readable label
  • the branch panel had no lightweight repository row for opening the repo from the same context surface

What changed

This PR turns the thread context panel into a more complete project control surface.

  • adds a Local servers section to the panel
  • detects both app-managed terminal servers and project-local listening servers that were started outside the app
  • lets users copy recent output and stop detected servers directly from the panel
  • adds persistent per-project quick actions with add, edit, delete, and run flows
  • moves the quick-action form onto a proper popover surface so typing works normally
  • improves loading and empty states so the panel distinguishes checking, empty, and error conditions
  • adds a repository row that opens the repo remote directly from the panel
  • polishes the local-server cards so they use cleaner labels, compact badges, and tighter actions

Implementation notes

  • extends terminal contracts and websocket plumbing with terminal.list
  • tags in-app quick-action terminal launches with project and script metadata
  • merges project-local external listening servers into the terminal list on the backend
  • reads remote.origin.url through the existing git status path so the repository row does not require a second query
  • adds focused tests around terminal listing and external project-local server handling

Verification

  • bun run typecheck
  • bun run lint
  • node ../../scripts/run-vitest.cjs run src/terminal/Layers/Manager.test.ts -t "external project-local"

Summary by CodeRabbit

  • New Features
    • Terminal session listing and management (view, stop, recent output)
    • Local server discovery and stop controls surfaced in the chat sidebar
    • Project-aware terminal sessions with metadata for attribution and quick actions
    • Project script run/create/edit UI with inline controls and feedback
    • Repository URL detection shown in context where available

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab371d22-206f-43a7-8acf-8d6d6d0758c3

📥 Commits

Reviewing files that changed from the base of the PR and between 3869cbd and f5edc45.

📒 Files selected for processing (4)
  • apps/server/src/terminal/Layers/Manager.test.ts
  • apps/server/src/terminal/Layers/Manager.ts
  • apps/server/src/wsServer.ts
  • apps/web/src/components/ChatView.tsx

📝 Walkthrough

Walkthrough

This PR introduces terminal session listing with external server discovery, session metadata tracking, and a local-server management UI. It extends the terminal contract with metadata and list types, implements platform-specific external server discovery for Windows and POSIX systems, adds repository URL extraction to git status, and wires a new chat sidebar section for managing local-run project scripts and viewing repository links.

Changes

Terminal List Feature with Metadata and Local Servers

Layer / File(s) Summary
Terminal contracts, schemas, and WebSocket method definitions
packages/contracts/src/terminal.ts, packages/contracts/src/terminal.test.ts, packages/contracts/src/git.ts, packages/contracts/src/ws.ts, packages/contracts/src/ipc.ts
Defines TerminalSessionMetadata struct with optional project/root/script/title/command fields; extends TerminalOpenInput with optional metadata; introduces TerminalListInput (with optional filters), TerminalSessionSummary (includes status/pid/recent output/metadata), and TerminalListResult; adds repositoryUrl to GitStatusResult; registers WS_METHODS.terminalList and corresponding request/response schemas in WebSocket and IPC contracts.
Terminal manager service interface with session metadata and list operation
apps/server/src/terminal/Services/Manager.ts
Adds nullable metadata: TerminalSessionMetadata field to TerminalSessionState; introduces list(input: TerminalListInput): Effect<TerminalListResult, TerminalError> method on TerminalManagerShape.
Terminal manager runtime: metadata handling, external server discovery, and list implementation
apps/server/src/terminal/Layers/Manager.ts, apps/server/src/terminal/Layers/Manager.test.ts
Implements metadata normalization (merging input + runtime env), open/restart apply normalized metadata to sessions; adds helpers for capped recent-output tailing, path/project-root matching, and metadata/metadata-aware session conversion. Implements platform-specific external server discovery: Windows via PowerShell/CIM queries listening TCP ports and filters by project root from command line; POSIX via lsof socket discovery with ps parent-PID/command-line resolution. Adds list() method aggregating managed in-memory sessions and discovered external servers, deduplicating by port and returning sorted combined summaries. Updates close() to detect and kill external processes by PID. Extends TerminalManagerLive to expose list handler. Test helper makeManager accepts optional externalServerDiscoverer and externalProcessKiller callbacks.
Git manager: repository URL extraction
apps/server/src/git/Layers/GitManager.ts
Reads remote.origin.url from git config in makeGitManager status effect, conditionally spreads repositoryUrl into result when present.
WebSocket server: terminal list endpoint and test mocking
apps/server/src/wsServer.ts, apps/server/src/wsServer.test.ts
Adds WS_METHODS.terminalList handler extracting request payload and delegating to terminalManager.list(); extends MockTerminalManager in tests with list() method returning TerminalSessionSummary array from in-memory snapshots.
Frontend: native API and WebSocket transport for terminal listing
apps/web/src/wsNativeApi.ts, apps/web/src/wsTransport.ts
Adds api.terminal.list(input) method issuing WebSocket request; introduces TERMINAL_LIST_TIMEOUT_MS = 5000 constant and updates requestTimeoutMs to apply it for WS_METHODS.terminalList.
Chat UI: local server management, project scripts, repository links
apps/web/src/components/ChatView.tsx
Adds LocalServersPopoverControl component implementing React Query-backed polling of local terminal sessions filtered by active project/workspace, with session-to-project attribution, recent-output copy/stop actions, and quick-action form for creating/editing/deleting project scripts. Implements helpers for ANSI escape stripping, filesystem path normalization, terminal-label building from TerminalSessionSummary + metadata, and GitHub repository link resolution. Adds deleteProjectScript callback filtering scripts and persisting updates. Extends ThreadContextPanel props to receive active project identity (id/cwd/scripts) and onDeleteProjectScript handler. Updates sidebar rendering to show optional "Repository" section with GitHub/Git links and conditional "Local servers" section via LocalServersPopoverControl when applicable. Includes form validation, toast-based error/success feedback, and updated icon imports for UI controls.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibble logs and chase the recent lines,
Discover sockets where the local server pines,
Metadata stitched to every terminal's name,
Repo links gleam, and quick-actions play their game,
The rabbit hops—your sidebar wakes aflame!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add local servers to the thread context panel' accurately reflects the main change: introducing local servers section and management UI to the thread context panel component.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/project-panel-local-servers

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/src/terminal/Layers/Manager.ts`:
- Around line 867-875: The close method currently calls externalProcessKiller
for any terminalId parsed as external:<pid> without authorization; modify close
(and/or externalPidFromTerminalId) to validate that the resolved externalPid is
owned/allowed for the current thread/caller/project before killing it: after
decoding input via decodeTerminalCloseInput and inside runWithThreadLock use the
threadId (and any caller/project context available) to look up a trusted
registry/mapping of discovered external PIDs (or check an ownership set stored
by the terminal manager) and only call externalProcessKiller(externalPid) if the
PID is present and belongs to that thread/caller; otherwise reject/throw and do
not call externalProcessKiller. Ensure you reference/validate via the same
identifiers used elsewhere (threadId, terminalId) so arbitrary external:<pid>
requests cannot kill unrelated processes.
- Around line 349-357: commandMatchesProjectRoot currently uses
normalizedCommandLine.includes(root) which allows substring collisions (e.g.
"/repo" matching "/repo2"); change the matching to enforce path-boundary checks:
normalize both commandLine and each project root (use "/" separators and ensure
roots end with a trailing "/"), then check for either exact equality or that
normalizedCommandLine has the root followed by a path separator or end-of-string
(or split normalizedCommandLine into path segments and compare segment-wise).
Update the logic inside commandMatchesProjectRoot to use this stricter
comparison instead of includes to avoid false positives.

In `@apps/server/src/wsServer.ts`:
- Around line 2599-2602: The terminalList websocket handler
(WS_METHODS.terminalList -> terminalManager.list) is missing the terminal
permission gating and therefore falls back to orchestration:read; update the
permission check mapping used by the WS method dispatcher (the structure that
defines requiredRemoteAccessScope for each WS_METHODS value) to include
WS_METHODS.terminalList and require the "terminal:operate" scope, or add an
explicit permission check before calling terminalManager.list that enforces
"terminal:operate"; ensure you reference WS_METHODS.terminalList and
terminalManager.list so the route is protected by the same terminal permission
logic as other terminal methods.

In `@apps/web/src/components/ChatView.tsx`:
- Around line 554-567: normalizeLocalServerPath currently forces lowercase which
can break case-sensitive filesystems; remove the final .toLowerCase() so the
function returns the normalized path with original case (keep slash
normalization, trim, and trailing slash removal), and ensure
localServerPathMatches uses those case-preserved normalized values for equality
and startsWith checks (i.e., compare normalizedCandidate === normalizedRoot and
normalizedCandidate.startsWith(`${normalizedRoot}/`) without lowercasing).
- Around line 705-708: The current sshLikeMatch regex in ChatView.tsx is too
permissive and treats ssh://git@... with ports as scp-style remotes; update the
pattern used for sshLikeMatch to only match scp-style SSH remotes (e.g.
git@host:org/repo.git) by removing the ssh://git@ alternative and using a
pattern like ^git@([^/:]+):([^?#]+?)(?:\.git)?\/?$ so host and path are parsed
correctly; keep the existing replacement logic that returns
`https://${sshLikeMatch[1]}/${sshLikeMatch[2].replace(/\.git$/i, "")}` and
ensure any ssh://... cases are left to the other parsing path instead of this
scp-only branch.
- Around line 7990-8014: The query is polling regardless of the popover state;
update the terminalSessionsQuery to stop polling when the local-servers popover
is closed by adding the popover open state to its enabled condition and query
identity and only applying refetchInterval when open. Concretely: include the
popover boolean (e.g., localServersPopoverOpen or isLocalServersOpen) in the
queryKey and change enabled to Boolean(activeThreadId &&
localServersPopoverOpen), and set refetchInterval to LOCAL_SERVER_REFRESH_MS
only when localServersPopoverOpen is true (otherwise disable or set to false) so
readNativeApi / api.terminal.list() is only called while the popover is open.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 217576bf-1313-42f1-9528-53035d3f9ef0

📥 Commits

Reviewing files that changed from the base of the PR and between 9e9e7b6 and 3869cbd.

📒 Files selected for processing (14)
  • apps/server/src/git/Layers/GitManager.ts
  • apps/server/src/terminal/Layers/Manager.test.ts
  • apps/server/src/terminal/Layers/Manager.ts
  • apps/server/src/terminal/Services/Manager.ts
  • apps/server/src/wsServer.test.ts
  • apps/server/src/wsServer.ts
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/wsNativeApi.ts
  • apps/web/src/wsTransport.ts
  • packages/contracts/src/git.ts
  • packages/contracts/src/ipc.ts
  • packages/contracts/src/terminal.test.ts
  • packages/contracts/src/terminal.ts
  • packages/contracts/src/ws.ts

Comment thread apps/server/src/terminal/Layers/Manager.ts Outdated
Comment thread apps/server/src/terminal/Layers/Manager.ts
Comment thread apps/server/src/wsServer.ts
Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/components/ChatView.tsx
@Eccentric-jamaican Eccentric-jamaican merged commit c92670d into main Jun 12, 2026
0 of 2 checks passed
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.

1 participant