Repository navigation
feat(web): rename saved environments without disconnecting - #57
Merged
Merged
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open issues
yield* new ConnectionBlockedError(...)/yield* new PlatformEnvironmentRemovalError(...)will… · Newyield* new ConnectionBlockedError(...)/yield* new PlatformEnvironmentRemovalError(...)will… · New This switch has no explicit exhaustiveness/default handling. IfConnectionTargetever gains… · New UsingPlatformEnvironmentRemovalErrorto represent 'primary environments can’t be renamed' is… · New
What changed in this PR
Adds client-side renaming for saved environments (web/desktop) while preserving the active connection/supervisor session and persisting the name across restarts and route/discovery refreshes.
Changes:
- Introduces an
EnvironmentRegistry.renameoperation and exposes it via the environment catalog runtime commands/atoms. - Persists a user-chosen label via a new
labelSource: "user"marker to prevent discovery refresh from overwriting the name. - Adds the web UI menu action + dialog to rename an environment, plus docs and test updates.
| File | Description |
|---|---|
| packages/client-runtime/src/state/threads-atoms.test.ts | Extends test harness to account for the new rename command. |
| packages/client-runtime/src/state/connections.ts | Adds a serial runtime command for environment-catalog:rename and exports it. |
| packages/client-runtime/src/connection/routes.ts | Preserves labelSource when creating learned routes. |
| packages/client-runtime/src/connection/routes.test.ts | Expands learned-route tests to cover labelSource propagation. |
| packages/client-runtime/src/connection/registry.ts | Implements rename logic, introduces labelSource handling, and refactors entry publishing to keep supervisor/session intact. |
| packages/client-runtime/src/connection/registry.test.ts | Adds coverage for rename persistence, no-disconnect behavior, and failure rollback. |
| packages/client-runtime/src/connection/model.ts | Adds optional labelSource to connection targets to distinguish user-chosen labels. |
| docs/user/remote-access.md | Documents how renaming works on web/desktop and its non-impact on host/agents. |
| apps/web/src/components/settings/SavedEnvironmentRows.tsx | Adds “Rename…” menu item + dialog wiring in saved environment rows. |
| apps/web/src/components/settings/RenameEnvironmentDialog.tsx | New rename dialog UI and save flow calling the atom command. |
Review effort: Lite
Comment on lines
+1081
to
+1087
| const trimmed = label.trim(); | ||
| if (trimmed.length === 0) { | ||
| return yield* new ConnectionBlockedError({ | ||
| reason: "configuration", | ||
| detail: "Environment name cannot be empty.", | ||
| }); | ||
| } |
Comment on lines
+1091
to
+1094
| const entry = yield* userEntry(environmentId); | ||
| if (entry.target._tag === "PrimaryConnectionTarget") { | ||
| return yield* new PlatformEnvironmentRemovalError({ environmentId }); | ||
| } |
Comment on lines
+67
to
+79
| function withUserLabel(target: ConnectionTarget, label: string): ConnectionTarget { | ||
| const fields = { label, labelSource: "user" as const }; | ||
| switch (target._tag) { | ||
| case "PrimaryConnectionTarget": | ||
| return new PrimaryConnectionTarget({ ...target, ...fields }); | ||
| case "BearerConnectionTarget": | ||
| return new BearerConnectionTarget({ ...target, ...fields }); | ||
| case "RelayConnectionTarget": | ||
| return new RelayConnectionTarget({ ...target, ...fields }); | ||
| case "SshConnectionTarget": | ||
| return new SshConnectionTarget({ ...target, ...fields }); | ||
| } | ||
| } |
| Effect.gen(function* () { | ||
| const entry = yield* userEntry(environmentId); | ||
| if (entry.target._tag === "PrimaryConnectionTarget") { | ||
| return yield* new PlatformEnvironmentRemovalError({ environmentId }); |
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.


Saved environments on desktop and web could only use the host's system name. There was no way to give a remote machine a recognizable name without renaming the host.
Add Rename… to the environment's ⋯ menu. The name is saved on this device and survives app restarts, reconnection, route changes, and discovery refreshes. Renaming keeps the active connection and running agents intact. It does not change the hostname, credentials, or other devices' names.
Test plan
vp run check:changed: formatting, lint, both Knip passes, typechecks for all seven affected packages, 74 tests, and changed-component React Compiler checks.Before + After
Before renaming:
New action and dialog:
After saving:
Rollout
Only local connection metadata changes; no database migration or server deployment is needed. Rebuild the desktop app after merging and leave the running app alone for Nicholas to restart.
royal-walnut-flamingo