Address review feedback
- Resolve the type check child process on `close` rather than `exit`, so the
captured stdout/stderr is complete before it is inspected. Resolving on
`exit` could race with the pipes draining and truncate diagnostics.
- Use an explicit type predicate when filtering out unresolved symbols rather
than relying on inferred narrowing of `Symbol | undefined`.
- Drop the redundant second `disallowedTypes.includes()` in toViolations by
splitting the direct name match from the symbol id lookup.
- Fix a collapsed function signature and reword the pass 1 comment, which
described files matched by a rule that disallows nothing as "exempt" and
read as though skipped files were traversed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
docs: fix minor typos and grammar in README
- Fixes spacing and indentation for the VS Code image HTML wrapper.
- Updates "Visual Studio Code's website" to "the Visual Studio Code website" for better readability.
- Changes "help us verify as they are checked in" to "help us verify them as they are checked in".
- Merges "code base" into the modern single-word form "codebase".
- Adds missing commas for introductory clauses (e.g., before "which creates a Docker volume" and "see the Code of Conduct FAQ").
xtab: fix: clamp tagged patch range to document
Tagged prompt content can add lines beyond the source document. Clamp the CustomDiffPatch pseudo-window to the source range to avoid an unexpected failure.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62cca64b-0581-410e-ab89-034e20f02ca7
* Validate workspace trust for notebook links
Route notebook webview resource links through the editor service trust gate while preserving selections and editor group targeting.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Preserve notebook link opener behavior
Keep custom URI, folder, fragment selection, and existing editor handling intact while validating trust for out-of-workspace resources.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix notebook link opener options
Rely on the opener URI fragment for selections instead of passing text editor options through the generic opener API.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The check took ~257s and would sometimes run out of memory. Two separate
bottlenecks were responsible.
layersChecker.ts built a full in-process ts.Program (15s, 2GB) and then
asked the type checker for a symbol at every property access in the
program, ~2.5M identifiers. Each lookup materialized symbol and type
objects, pushing the heap past 3.6GB, and the alias/containment chain was
then walked per symbol.
It now runs on the TS7 native API that the repo already vendors for
build/lib/tsgo.ts:
- updateSnapshot replaces createProgram, so the program lives in the
compiler rather than the V8 heap
- the disallowed types are resolved to symbols once up front, turning the
per-reference check into a local id lookup
- symbol lookups are batched instead of issued one node at a time
- property accesses are prefiltered by member name, so only those that
could name a member of a disallowed type are resolved at all
That brings it from 48.6s and 3.8GB peak to 11.7s and 0.8GB peak.
The six tsconfig.<layer>.json projects were type checked serially with
TS6, which accounted for the remaining ~208s. They move to the native
compiler and run in parallel in the new layersTypeCheck.ts, taking ~11s.
Concurrency is derived from free memory (the largest project peaks at
~3.5GB) so a memory-constrained machine falls back towards serial
execution rather than swapping.
Verified to report byte-identical violations, including line and column,
against a seeded set covering direct references, import aliases,
inherited members, nested member access and ipcMain.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Initial plan
* Only report 'Downloading' model status on an actual cache miss
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
* Initial plan
* Disconnect stale voice session when a fresh new-session composer takes over
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: meganrogge <29464607+meganrogge@users.noreply.github.com>
Co-authored-by: Megan Rogge <merogge@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* agentHost: Sync session read state across all connected clients
Read/unread for an Agent Host session is now a single host-owned fact that
every connected client agrees on.
The host had two parallel representations: the `SessionStatus.IsRead` bit
(persisted under the `isRead` session-database key) and separate
`isRead`/`isArchived` booleans on the local `IAgentSessionMetadata` IPC
shape. Different paths read different ones and they could disagree, so the
booleans are gone and `status` is the sole carrier. The database values now
fold into `status` once, in `AgentService.listSessions()`/`restoreSession()`,
and the redundant re-folds in `protocolServerHandler` and
`remoteAgentHostProtocolClient` are removed.
Persistence of both flags moves onto the existing `onDidEmitEnvelope`
observer, which sees client- and server-dispatched actions alike and skips
rejected envelopes. Previously each dispatch path wrote the database itself,
so any new server-side dispatch would silently skip persistence.
The editor window had its own disconnected read model while the agent window
was already wired to the host, so the two windows disagreed. It now shares
the same state through a bridge mirroring the archive one:
`IChatSessionItem.isRead`, `IChatSessionItemController.setChatSessionItemRead`,
and `canSetChatSessionItemRead`/`setChatSessionItemRead` on
`IChatSessionsService`. `AgentSessionsModel` delegates to it when the
provider owns read state; its local timestamp heuristics now apply only to
providers that do not. `migrateReadStateToProvider` performs a one-time,
additive hand-off of existing local read state so sessions do not resurface
as unread on upgrade, deferring until the provider has actually reported so
a stale startup cache cannot consume the one-shot flag.
Neither the Copilot SDK nor Claude/Codex track read state, and the host
drives it from provider-neutral turn signals, so this works identically for
all three agents.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Trim read-state comments and docs
Cut restatement and over-explanation from the comments added in the previous
commit, keeping only what isn't already obvious from the code. Condenses the
SESSIONS_LIST.md read/unread section to the user-visible behaviour rather
than the implementation detail behind it.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Only report sessions known to be unread
Address PR feedback on #327950.
Folding the read flag into `status` accidentally widened the `unread`
semantics in the session server tools: `isSessionStatusRead(undefined)` is
`false`, so a session with no status was treated as unread. The previous
code required an explicit `isRead === false`. This is reachable and common —
`ClaudeSessionMetadataStore.project()` returns no `status`, so every cold
Claude session would have matched an `unread: true` listing and serialized
as unread. `sessionIsUnread` now requires a known status, restoring the
original semantics.
Also hoists the duplicated read-timestamp comparison out of `isRead` and
`migrateReadStateToProvider` into `localReadDateCoversActivity`, so the
grace window and baseline fallback live in one place.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Don't infer read state from a synthesized status
Address GPT-5.6 review feedback on #327950.
Neither `CopilotAgent.listSessions` nor `ClaudeSessionMetadataStore.project`
projects a `status`, so every cold session that has never been marked read or
archived reaches clients without one. `SessionSummary.status` is required, so
the session-list store synthesized `Idle` — and the editor window then read the
absent `IsRead` bit off that synthesized value and reported the session as
unread, while the agents window treats an absent status as read. The two
windows disagreed on the most common cold session, which is exactly what this
change set out to fix.
The list entry now records whether the status came from the host, and the
controller leaves `IChatSessionItem.isRead` unset when it did not. That keeps
all three surfaces consistent (agents window, editor window, and the
`sessionIsUnread` server-tool helper) and stops the migration from consuming
its one-shot flag for a session whose real state was never reported. The flag
is resolved as soon as a summary carries a status, or when a client mutation
establishes one.
Also moves the migration ledger from workspace to application scope. The state
it hands off to is host-global, so a second workspace that can see the same
session — an empty window lists them all — would otherwise migrate it again and
re-promote a session the user had deliberately marked unread elsewhere.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The renderer minted a client-side `request_<uuid>` id for turns it did not
dispatch itself, so `/btw` sent the agent host a turn id it had never seen and
createChat failed with "side chat source turn ... not found". The same broken
anchor affected selection side chats, Ask in Side Chat, and forking.
Two paths dropped the provider's turn id: the active turn pushed into history
on reconnect, and server-initiated turns surfaced via onDidStartServerRequest.
Both now carry it. The id is required rather than optional so a future caller
cannot silently omit it and fall back to a client-generated id.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The interim decoration was applied correctly but had no visual effect: the
`.monaco-editor .dictation-interim-processing` rule ties on specificity with
Monaco's syntax-token rules (`.monaco-editor .mtkN`), which are injected into the
document after this stylesheet and therefore won, painting the provisional text
in the normal foreground color.
The shimmer never hit this because it colored text through -webkit-text-fill-color
and background-clip rather than `color`, which bypasses the tie entirely.
Qualify the selector with .view-line and the element name so it outranks the
token rules regardless of injection order. Verified in a running Code OSS build:
a span carrying both `mtk1` and the decoration class now computes to the
placeholder color instead of the editor foreground.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Splitting on the recognizer's finalized prefix looked right in principle, but
streaming backends endpoint segments almost as fast as they are spoken. Styling
only the uncommitted tail therefore left nearly every word solid on arrival, so
the provisional state was never visible in practice - dictation appeared to jump
straight from empty to the finished transcript.
Render the whole not-yet-final transcript in the placeholder color instead, and
clear it when dictation ends. This matches the pre-existing visual behavior
minus the animation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Agent Host: Share agent catalog across session adapters
Avoid one root-state listener per cached session by publishing the agent catalog once from the provider. Preserve late capability hydration and cover listener scaling with 200 adapters.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Agent Host: Address shared catalog review feedback
Use public listener lifecycle hooks in the regression test, clear derived root state on errors and disconnects, and precompute the provider capability lookup.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* added classification comments for response events
* Classify forwarded Copilot identifiers as pseudonymous
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Emit toolCallDetails telemetry
Preserve the local per-turn tool-call aggregate on the Microsoft telemetry channel while retaining the restricted peer events. Include Agent Host correlation fields and report successful, cancelled, and failed turns once.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Emit chat.toolApproval telemetry
Emit the workbench-compatible tool-approval event from the agent host on the standard telemetry channel, correlating SDK permission events with each tool invocation. Fires once per tool call at either permission.completed (denied) or tool.execution_start (approved / no permission requested).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Wait for tool permission outcome
Defer chat.toolApproval emission until permission.completed when a permission lifecycle exists. Tool calls without permission requests now emit at completion with no inferred auto-approval reason, preventing premature and contradictory rows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Trims only the end of the selected text when building the side-chat
snippet. The trailing newline browsers append when a line selection
spills into the next block is still dropped, but a selection that
starts mid-indentation (a nested list item, a quoted line) no longer
silently loses the whitespace the user actually selected.
Follow-up to #327931, addressing Copilot review feedback.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
While dictating, the in-progress transcript animated a gradient shimmer over
the words the recognizer had not committed yet. Render that tail in the input
placeholder color instead, so text simply turns solid as the recognizer commits
it.
Because nothing animates any more, the heuristics that existed only to stop the
shimmer looping during a pause are gone: the interim diff, the word-boundary
backoff, and the 700ms idle-settle timer. The split is now driven purely by the
finalized prefix the recognizer reports, so a word can no longer flip from solid
back to placeholder when it is revised.
The terminal voice surface gets the same treatment so all three dictation
surfaces match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Bring back terminal auto approval edit settings.json
* Scope terminal auto-approve actions to rule-eligible Agent Host Copilot confirmations
* Tighten auto-approve rule eligibility and evaluate persisted rules only
* Add gate coverage for canFutureRuleSuppressPrompt
* Extend auto-approve rule test coverage and drop a dead guard
* Preserve focus when chat confirmation buttons update
* Carlify terminal auto-approve rule eligibility
* agentHost: Separate local resource identity
Keep trusted local resource access distinct from remote host addresses and give a remote host named local a collision-free authority.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: Type local resource identity as unique symbol
Make the trusted local sentinel explicitly narrow for control-flow checks.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Scrub the account name only where it identifies a user
Snapshot and capture normalization ended with an unanchored
`replaceAll(userName, '${user}')`. With the GitHub Actions Linux account
name `runner` — an ordinary English word — captured text such as
`the runner completed` was rewritten to `the ${user} completed`.
That is worse than cosmetic. It only misfires on platforms whose account
name happens to be a common word, so the same recording normalizes
differently on macOS and Linux CI, which is exactly the cross-platform
mismatch this normalization exists to prevent.
Replace only the two positions where the name genuinely identifies a
user: after a path separator (including the escaped form found in
embedded JSON), and the owner/group columns of an `ls -l` listing. The
listing case is load-bearing — the committed subagent capture records the
account name there, outside any path — so it cannot simply be dropped.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Enable the git-branches config test on Windows
The test was disabled on Windows because its temporary git repository
could not be deleted, which failed suite teardown even though every
assertion passed. Its assertions were always platform-independent.
Two independent causes, both now addressed:
- Read-only `.git/objects` files. Fixed by clearing read-only attributes
before retrying removal, which also unblocked `inspects git status`.
- Background `git gc` holding handles under `.git` after the test
finishes. `initTestGitRepo` now sets `gc.auto 0`; these repositories
never create enough objects to need it.
Collapse the duplicated init/identity setup in three suites into
`initTestGitRepo` so the gc setting cannot be forgotten by the next test
that needs a repository.
Whether this holds can only be confirmed on a Windows run; the remaining
risk is a handle neither mechanism covers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Enable the worktree working-directory test on Windows
The comment claiming this test could not be made portable was wrong on
two of its three counts:
- The path assertions use `URI.fsPath`, which is platform-native, and the
expected value is derived at runtime from the host's own `sessionAdded`
notification rather than hardcoded as a POSIX path.
- The recorded `pwd` is only reached when the provider routes commands
through the host terminal tool, which on Windows is PowerShell, where
`pwd` is an alias for `Get-Location`.
The third — that pinning a command stops the turn on an unanswered
permission prompt — was observed in a different test. This one already
handles confirmation, dispatching `ChatToolCallConfirmed` when
`toolCallReady` arrives unconfirmed.
Drop `pwd` from the record-time command blocklist for the same reason,
which empties `POSIX_COMMAND_EXCEPTIONS`; a recording now passes the check
without an opt-out.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Record why the worktree test keeps `pwd` rather than a pinned node command
Tried replacing `pwd` with `node -e "console.log(process.cwd())"` on both
of the test's turns. Both stalled on `session/inputNeededSet`: providers
auto-approve `pwd` as a safe read-only command, and an arbitrary `node -e`
invocation is not on that list, so pinning turns a silent tool call into
one that waits for a confirmation this test's flow does not answer — even
on the turn that does dispatch `ChatToolCallConfirmed`.
`pwd` is portable regardless, since PowerShell defines it as an alias for
`Get-Location`, so the test still runs on Windows.
Correct the stale comment, which still claimed the assertions were
POSIX-shaped, and record the general point: pinning a command changes its
permission posture, so prefer steering to a file tool where one exists.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Pin the worktree test command and approve tool calls in a loop
Answers why pinning `node -e` failed here when it works in every other
ported test: those all go through `driveTurnToCompletion`, which confirms
each unconfirmed `chat/toolCallReady` as it arrives. This test drives its
turn by hand, and its host-terminal branch approved exactly once while its
SDK-shell branch already used `startBackgroundApprovalLoop`.
A pinned command is not on the provider's auto-approve list the way `pwd`
is, so it adds an approval round-trip. With single-shot approval a later
request stays pending and the turn stalls on `session/inputNeededSet`,
which reads as a hang rather than a permission problem.
Both branches now use the shared loop, and the command is pinned like
everywhere else. Verified by re-recording both providers.
This also removes the last special case: no test now depends on a command
being auto-approved, and `POSIX_COMMAND_EXCEPTIONS` stays empty.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Revert the worktree test to non-Windows after CI
Windows CI failed it for two reasons, neither about command portability,
and both specific to this test's output assertions:
- The expected path comes from `os.tmpdir()`, which on Windows CI returns
an 8.3 short form (`C:\Users\CLOUDT~1\...`) while the shell reports the
long form, so the `includes()` assertion can never match and the wait
times out. Same class of mismatch as `/var` versus `/private/var` on
macOS, which snapshot normalization already special-cases.
- The Copilot branch waits for a `chat/toolCallContentChanged` carrying a
terminal resource, and on Windows that notification never arrives even
though the tool call starts, is confirmed, and completes.
Keep the pinned command and the shared approval loop from the previous
commit — both are correct regardless of platform — and record what CI
showed so the next attempt starts from evidence rather than a fresh guess.
Reworking this needs `realpathSync.native` on both sides of the path
comparison, and the missing terminal content understood first; neither is
reproducible without a Windows machine.
`session configuration resolves and completes git branches` passed on
Windows in the same run, so the git lock fixes hold.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address E2E review feedback (Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: assert the recorded model request on replay
Response selection stays ordinal, but every replayed turn now compares the
live model request against the one recorded in the capture, through a
projection applied symmetrically to both sides. Captures keep their existing
shape and stay readable.
The request body is the host's own product - prompt assembly, retained
history, truncation, attachment marshalling, and tool-result hand-back - and
none of it was checked before, so a regression replayed green and became the
new expected value at the next re-record.
Asserts host-authored structure (roles and ordering, retained history, system
prompt presence, text and attachment content, tool names/inputs, tool_use_id
wiring) and elides what replay cannot reproduce or what is environment-derived
(tool_result payloads, run-time identifiers, reasoning blocks, the model id).
Switching this on found seven stale captures: four whose prompt text had been
edited without re-recording, one holding a one-off ordering of parallel
tool_result blocks, and one Codex capture still carrying the pre-pinned pwd
prompt - all re-recorded here. The seventh, Claude's side-chat capture, cannot
be refreshed because recording it hits the known provider-context fork defect,
so it is listed as an exception and documented in KNOWN_ISSUES.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: compare paths by filename, not by directory spelling
Windows CI failed three model-request assertions. None was a host regression:
each was the same file addressed differently than the macOS-recorded capture.
Three separate spellings were involved - an unsubstituted \${workdir}, an
unsubstituted \${homedir}, and a backslash separator - which is the point: a
directory has too many per-machine spellings (separator, drive letter, 8.3
short names, /var vs /private/var, and whether the recorder substituted its
placeholder at all) to be compared literally across platforms.
The projection now collapses a path to \${path}/<basename>. Which file the
host referenced stays asserted; where it lives does not. A different filename
is still a mismatch.
Also fixes a real gap in the recorder: \`homeDir\` was normalized only in its
raw form, while \`workDir\` also had a JSON-escaped variant, so a Windows home
directory embedded in a JSON body was never substituted.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: elide filesystem paths from the model-request projection
The remaining Windows failure was a recorded bare `${workdir}` (the workspace
directory itself) against a live raw directory path. Keeping the basename
cannot reconcile those two, because the live basename is the temp directory's
own name.
Paths are now elided entirely rather than reduced to their filename. A path has
too many per-machine spellings to compare literally - separator, drive letter,
8.3 short names, /var vs /private/var, whether the recorder substituted its
placeholder, and whether the value is a file or the directory itself - and two
rounds of Windows CI failures came from exactly those, none a real regression.
This is a deliberate narrowing: the projection no longer asserts which file a
prompt referenced. That is a weaker oracle than it looks, because the tests
that care assert the filesystem effect directly. The instruction wrapped around
the path is still compared.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: compare model-request projections with stable key ordering
A tool call's `input` is JSON the model produced, and its key order is not
guaranteed to survive a re-record or a YAML round-trip. Comparing raw
`JSON.stringify` output reported two semantically identical requests as a
mismatch, which reads as a host regression and is especially confusing because
the two printed values look equivalent.
Both the comparison and the failure message now use a canonical form with keys
sorted, so what is printed is what was compared. Key-order tolerance does not
extend to values: a changed input is still a mismatch.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix duplicate symlink decorations in explorer
The explorer decorations provider was registered per ExplorerView instance.
Since DecorationsService merges all providers' letters into a single badge,
each registration contributed another arrow. In the classic workbench there
is only ever one ExplorerView so this never surfaced, but in the Agents
window the Files view is gated on session context keys and re-created on
session switches, leaving multiple live views and therefore multiple badges.
Register the provider once from ExplorerService instead, which owns the
window wide explorer model the decorations are derived from.
Fixes#324389
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add 1px margin-bottom to workspace picker container
The new-session-workspace-picker-container should have a 1px bottom margin
to provide proper spacing between the workspace picker and the chat input.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Fix agent host diff file paths
Legacy session-db content URIs encode the blob location in the URI path,
so the original side of a diff showed a '.../before/<file>' label and was
flagged as a rename. Canonicalize them into the current layout at the
single consuming choke point, normalizeFileEdit.
Agent host URIs also rendered as '/c:/Code/...' next to 'C:\Code\...' for
the same file, because the label formatter had no drive letter
normalization and a hardcoded posix separator. Register an OS-aware
formatter for the in-process host and normalize drive letters everywhere.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make agent host path handling operating system independent
canonicalizeSessionDbUri rebuilt the path with URI.file, whose backslash
handling follows the client OS, so a legacy Windows session canonicalized
incorrectly on a POSIX client. Take the path from the file URI the host
already resolved instead.
Drop normalizeDriveLetter from the fallback label formatter: '/c:/repo/a.ts'
is a valid POSIX path too, so rewriting it as 'C:/repo/a.ts' would name a
different resource. Drive normalization now only happens for hosts whose
operating system is known.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(agentHost): add multi-root support for Claude agent sessions
- Introduced `AgentHostClaudeMultiRootEnabledSettingId` to enable multi-root capabilities for Claude agent-host sessions.
- Updated configuration schema to include `multiRootEnabled` setting for Claude agent.
- Enhanced `ClaudeAgent` to advertise `multipleWorkingDirectories` capability based on the new setting.
- Modified session handling to support additional working directories, allowing sessions to span multiple directories.
- Implemented persistence of additional directories in session metadata for cold resumes and forks.
- Added tests to verify the correct behavior of multi-root functionality, including session creation, metadata handling, and SDK options projection.
* test: add test for session creation with fork that inherits working directories
* agents: restore message timestamps from persisted agent transcripts
Chat request/response timestamps disappeared after restarting the client because the Copilot and Codex history replay mappers dropped turn timing when rebuilding sessions from persisted transcripts.
Restore Turn.startedAt/duration in both mappers: the Copilot mapper now reads the ISO timestamp from the SDK session event envelopes, and the Codex mapper derives timing from the persisted thread turns.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agents: bound replayed turn duration by the turn's own events
Address PR review feedback: track the last event timestamp per turn builder instead of using the globally previous/current envelope timestamp, so events outside the turn (for example an ignored notification long after assistant.turn_end) no longer inflate its duration. Also shorten the new helper comments to one line.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>