agentHost: watch customizations on the host's own filesystem - #333683
agentHost: watch customizations on the host's own filesystem#333683Ryan Ewen (RyanEwen) wants to merge 2 commits into
Conversation
📬 CODENOTIFYThe following users are being notified based on files changed in this PR: TylerLeonhardtMatched files:
|
There was a problem hiding this comment.
Pull request overview
Converts remote workspace URIs to host-local file URIs so Agent Host customization watchers work in remote environments.
Changes:
- Adds
toHostLocalUri. - Uses local roots for Claude customization and MCP discovery watchers.
- Adds URI conversion tests.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
agentHostUri.ts |
Adds host-local URI conversion. |
claudeAgentSession.ts |
Converts watcher roots before registration. |
agentHostFileSystemProvider.test.ts |
Tests URI conversion behavior. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| )); | ||
| store.add(watcher.onDidChange(() => this._onDidCustomizationsChange.fire())); | ||
| this._mcpDiscovery = directories?.length ? store.add(new SessionMcpDiscovery(directories, this._fileService)) : undefined; | ||
| this._mcpDiscovery = roots?.length ? store.add(new SessionMcpDiscovery(roots, this._fileService)) : undefined; |
|
Correct, and specifically because Fixed by comparing in the host-local namespace, since that is the namespace discovery reports in: const primaryCwd = this.workingDirectory;
// Discovery roots are host-local, so compare identities in that namespace.
const primaryRoot = primaryCwd && toHostLocalUri(primaryCwd);Both comparisons now use Added One limitation worth stating: the test identifies the servers by the host-local AI disclosure: this comment and the related code were written with the assistance of AI. |
Fixes #333665
Problem
In a remote window the agent host's customization watchers never attach.
_watchCustomizationsbuilds aClaudeCustomizationWatcherand aSessionMcpDiscoveryover the session's working directories, and in a dev container those arrive in the window's namespace:The host reads its own disk through
file:and registers no provider forvscode-remote, so every one of these watches throws. It fires on each_bindFreshConversation, so a session that binds a few chats logs it repeatedly. I counted 104 occurrences across four days of logs on one machine, 73 in a single day.The watch failing is only half of it. Both watchers also match change events against the URIs they were given, and the events the host receives carry
file:resources:ClaudeCustomizationWatcherfilters ontriggers.some(t => e.affects(t)), where the triggers are built from these rootsSessionMcpDiscoveryresolves.mcp.jsonunder the same rootsSo even where a watch did attach, nothing it produced could ever match. Project customizations and MCP config changes go unnoticed in a remote window.
The error is also invisible to callers:
IFileService.watchruns its work in an async IIFE and logs the failure itself, so notry/catchat any call site sees it, and the stack in the log contains only file service frames.Change
Reinterpret the roots as host-local paths once, at the point the watchers are created.
toHostLocalUriconverts avscode-remote:URI to thefile:path it denotes on this machine and leaves everything else untouched. Applying it inside_watchCustomizationscovers all three call sites, and fixes the event matching at the same time, because the triggers are derived from the roots it now returns.It is deliberately not applied in the
workingDirectoriesgetter: that value is also handed back to the client, which must keep the window's namespace.How to test
Output→Agent Host, or~/.vscode-server/data/logs/<session>/agenthost.log).On
maineach chat bind logsENOPRO: No file system provider foundfor the workspace folder and its.claudedirectory. With this change the log is clean.Verified on a live dev container by patching the shipped bundle with the equivalent change: from roughly two failures per chat bind to zero across four binds. The caller was identified by instrumenting
doWatchto record its stack, since the error itself does not carry one.Unit coverage adds three tests for
toHostLocalUri: a window URI becomes an openable path, anything already openable is untouched, and query and fragment survive.Note
toHostLocalUriis also introduced by #331527, which needs the same conversion for reading project customizations. Whichever lands second should drop the duplicate helper rather than adding a second one.AI disclosure: this pull request and the related code were written with the assistance of AI.