Add working-directory commands to the TUI (#38894)

## What changed

- Add `/cd [path]` for changing an idle local session's working directory while preserving conversation history. Relative paths resolve from the current directory, and omitting the path selects `~`.
- Reload project configuration, instructions, permissions, keybindings, file search, and hooks for the destination before replacing the active session.
- Reject unsafe transitions, including active or queued work, background terminals, remote environments, untrusted destinations, and incompatible permission profiles.
- Add `/pwd` and its `/cwd` alias to display the current working directory, and discard asynchronous results left over from the previous directory.

## Testing

- Cover command parsing, aliases, default paths, session eligibility, transition failures, history preservation, destination policy loading, hooks, and stale events.

GitOrigin-RevId: 1a987c029f157a087ba02c0f26e022260409132b
This commit is contained in:
Benjamin Carlsson authored and copyberry committed 2026-08-16 19:48:07 +00:00
1 parent 375996d3f5
commit ed32158e90
18 files changed
+776 -24

No files matched your search

+10 -1
View File
@@ -263,6 +263,7 @@ pub(crate) enum AppEvent {
SyncThreadGitBranch {
thread_id: ThreadId,
branch: String,
cwd: PathBuf,
},
/// Fetch a persistent cross-session message history entry by offset.
@@ -284,6 +285,12 @@ pub(crate) enum AppEvent {
name: Option<String>,
},
/// Change the working directory of the originating idle primary thread.
ChangeWorkingDirectory {
thread_id: ThreadId,
requested_cwd: PathBuf,
},
/// Result of the fresh startup thread that is attached after the input UI is live.
StartupThreadStarted {
result: Result<AppServerStartedThread, String>,
@@ -504,7 +511,7 @@ pub(crate) enum AppEvent {
},
/// Result of computing a `/diff` command.
DiffResult(String),
DiffResult(PathBuf, String),
/// Open the app link view in the bottom pane.
OpenAppLink {
@@ -748,6 +755,7 @@ pub(crate) enum AppEvent {
/// Result of refreshing plugin mention bindings.
PluginMentionsLoaded {
cwd: PathBuf,
plugins: Option<Vec<PluginCapabilitySummary>>,
},
@@ -778,6 +786,7 @@ pub(crate) enum AppEvent {
/// command path because those callers expect the visible skill state to be current when their command
/// completes.
SkillsListLoaded {
cwd: PathBuf,
result: Result<SkillsListResponse, String>,
},