session.ts ×10

Frontier kind: Code frontier

unlabeled · c_32bf1270a996

26 tests · 8498 LOC · 39 files · introduces 0 tests · 681 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
10 ranges681 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
860 ranges8498 lines · 39 files · Browse complete extent
All tests (intent)
26 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Introduced files, introduced tests, and structurally relevant concept specializationsessionContextKeys.test|title=Session Context Keys publishes Git availability independently to scoped context key services|occurrence=1 · 0 introduced LOCsessionContextKeys.test|…session.ts ×1 · 48 introduced LOCsession.ts ×1contextkey.ts ×1 · 2 introduced LOCcontextkey.ts ×1sessionContextKeys.ts ×2 · 293 introduced LOCsessionContextKeys.ts ×2session.ts ×3 · 9 introduced LOCsession.ts ×3session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×6 · 17 introduced LOCsession.ts ×6session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×9 · 27 introduced LOCsession.ts ×9session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 7 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×5 · 10 introduced LOCsession.ts ×5session.ts ×1 · 3 introduced LOCsession.ts ×1session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1session.ts ×2 · 2 introduced LOCsession.ts ×2session.ts ×1 · 1 introduced LOCsession.ts ×1session.ts ×1 · 2 introduced LOCsession.ts ×1agentHostSessionsProvider.ts ×2 · 32 introduced LOCagentHostSessionsProvide…session.ts ×1 · 5 introduced LOCsession.ts ×1agentHostSessionsProvider.ts ×5 · 255 introduced LOCagentHostSessionsProvide…chatSessionsService.ts ×12 · 1029 introduced LOCchatSessionsService.ts ×…resources.ts ×23 · 253 introduced LOCresources.ts ×23network.ts ×20 · 292 introduced LOCnetwork.ts ×20extpath.ts ×17 · 91 introduced LOCextpath.ts ×17strings.ts ×101 · 542 introduced LOCstrings.ts ×101cancellation.ts ×18 · 90 introduced LOCcancellation.ts ×18event.ts ×93 · 864 introduced LOCevent.ts ×93themables.ts ×14 · 65 introduced LOCthemables.ts ×14agentHostSessionType.ts ×7 · 51 introduced LOCagentHostSessionType.ts …codicons.ts ×2 · 846 introduced LOCcodicons.ts ×2platform.ts ×1 · 6 introduced LOCplatform.ts ×1utils.ts ×3 · 9 introduced LOCutils.ts ×3nls.ts ×1 · 1 introduced LOCnls.ts ×1linkedList.ts ×13 · 44 introduced LOClinkedList.ts ×13nls.ts ×6 · 13 introduced LOCnls.ts ×6instantiation.ts ×5 · 111 introduced LOCinstantiation.ts ×5platform.ts ×5 · 46 introduced LOCplatform.ts ×5types.ts ×1 · 2 introduced LOCtypes.ts ×1lifecycle.ts ×2 · 4 introduced LOClifecycle.ts ×2types.ts ×1 · 2 introduced LOCtypes.ts ×1assert.ts ×2 · 2 introduced LOCassert.ts ×2types.ts ×2 · 5 introduced LOCtypes.ts ×2types.ts ×1 · 2 introduced LOCtypes.ts ×1lifecycle.ts ×4 · 8 introduced LOClifecycle.ts ×4lifecycle.ts ×6 · 16 introduced LOClifecycle.ts ×6lazy.ts ×1 · 2 introduced LOClazy.ts ×1lazy.ts ×3 · 37 introduced LOClazy.ts ×3lifecycle.ts ×1 · 2 introduced LOClifecycle.ts ×1lifecycle.ts ×1 · 2 introduced LOClifecycle.ts ×1uint.ts ×2 · 43 introduced LOCuint.ts ×2lifecycle.ts ×1 · 3 introduced LOClifecycle.ts ×1map.ts ×97 · 3334 introduced LOCmap.ts ×97src/vs/base/common/arrays.ts · 949 LOCcommon/arrays.tssrc/vs/base/common/arraysFind.ts · 226 LOCcommon/arraysFind.tssrc/vs/base/common/assert.ts · 91 LOCcommon/assert.tssrc/vs/base/common/cache.ts · 153 LOCcommon/cache.tssrc/vs/base/common/cancellation.ts · 206 LOCcommon/cancellation.tssrc/vs/base/common/charCode.ts · 450 LOCcommon/charCode.tssrc/vs/base/common/codicons.ts · 66 LOCcommon/codicons.tssrc/vs/base/common/codiconsLibrary.ts · 758 LOCcommon/codiconsLibrary.t…src/vs/base/common/codiconsUtil.ts · 28 LOCcommon/codiconsUtil.tssrc/vs/base/common/collections.ts · 176 LOCcommon/collections.tssrc/vs/base/common/errors.ts · 357 LOCcommon/errors.tssrc/vs/base/common/event.ts · 1964 LOCcommon/event.tssrc/vs/base/common/extpath.ts · 433 LOCcommon/extpath.tssrc/vs/base/common/functional.ts · 32 LOCcommon/functional.tssrc/vs/base/common/iterator.ts · 194 LOCcommon/iterator.tssrc/vs/base/common/lazy.ts · 57 LOCcommon/lazy.tssrc/vs/base/common/lifecycle.ts · 974 LOCcommon/lifecycle.tssrc/vs/base/common/linkedList.ts · 151 LOCcommon/linkedList.tssrc/vs/base/common/map.ts · 1016 LOCcommon/map.tssrc/vs/base/common/marshallingIds.ts · 33 LOCcommon/marshallingIds.tssrc/vs/base/common/network.ts · 440 LOCcommon/network.tssrc/vs/base/common/path.ts · 1589 LOCcommon/path.tssrc/vs/base/common/platform.ts · 281 LOCcommon/platform.tssrc/vs/base/common/process.ts · 76 LOCcommon/process.tssrc/vs/base/common/resources.ts · 444 LOCcommon/resources.tssrc/vs/base/common/stopwatch.ts · 41 LOCcommon/stopwatch.tssrc/vs/base/common/strings.ts · 1413 LOCcommon/strings.tssrc/vs/base/common/themables.ts · 117 LOCcommon/themables.tssrc/vs/base/common/types.ts · 410 LOCcommon/types.tssrc/vs/base/common/uint.ts · 59 LOCcommon/uint.tssrc/vs/base/common/uri.ts · 754 LOCcommon/uri.tssrc/vs/base/test/common/utils.ts · 107 LOCcommon/utils.tssrc/vs/nls.ts · 244 LOCvs/nls.tssrc/vs/platform/agentHost/common/agentHostConnectionsService.ts · 126 LOCcommon/agentHostConnecti…src/vs/platform/agentHost/common/agentHostSessionType.ts · 91 LOCcommon/agentHostSessionT…src/vs/platform/contextkey/common/contextkey.ts · 2183 LOCcommon/contextkey.tssrc/vs/platform/instantiation/common/instantiation.ts · 130 LOCcommon/instantiation.tssrc/vs/platform/registry/common/platform.ts · 63 LOCcommon/platform.tssrc/vs/sessions/common/agentHostSessionsProvider.ts · 313 LOCcommon/agentHostSessions…src/vs/sessions/common/contextkeys.ts · 123 LOCcommon/contextkeys.tssrc/vs/sessions/services/sessions/common/session.ts · 812 LOCcommon/session.tssrc/vs/sessions/services/sessions/common/sessionContextKeys.ts · 217 LOCcommon/sessionContextKey…src/vs/workbench/contrib/chat/common/chatSessionsService.ts · 945 LOCcommon/chatSessionsServi…session.test|title=getUntitledSessionTitle returns "New Chat" for a quick chat|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=getUntitledSessionTitle returns "New Chat" for a quick chat|occurrence=1session.test|title=getUn…session.test|title=getUntitledSessionTitle returns "New Session" for a non-quick-chat session|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=getUntitledSessionTitle returns "New Session" for a non-quick-chat session|occurrence=1session.test|title=getUn…session.test|title=isActiveSessionStatus treats in-progress and needs-input sessions as active|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=isActiveSessionStatus treats in-progress and needs-input sessions as active|occurrence=1session.test|title=isAct…session.test|title=sessionFileChangesEqual returns false when deletions differ|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when deletions differ|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when insertions differ|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when insertions differ|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when lengths differ|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when lengths differ|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when one entry is v1 and the other is v2|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when originalUri differs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when originalUri differs|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when v1 modifiedUri differs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when v1 modifiedUri differs|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when v2 modifiedUri differs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when v2 modifiedUri differs|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns false when v2 uri differs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns false when v2 uri differs|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns true for structurally equal v1 entries|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns true for structurally equal v1 entries|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns true for structurally equal v2 entries|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns true for structurally equal v2 entries|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns true for the same array reference|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns true for the same array reference|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns true for two empty arrays|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns true for two empty arrays|occurrence=1session.test|title=sessi…session.test|title=sessionFileChangesEqual returns true when entries are the same reference (short-circuit)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionFileChangesEqual returns true when entries are the same reference (short-circuit)|occurrence=1session.test|title=sessi…session.test|title=sessionWorkspaceEqual returns false when folder repository metadata changes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionWorkspaceEqual returns false when folder repository metadata changes|occurrence=1session.test|title=sessi…session.test|title=sessionWorkspaceEqual returns true for rebuilt workspace objects with equivalent GitHub info values|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionWorkspaceEqual returns true for rebuilt workspace objects with equivalent GitHub info values|occurrence=1session.test|title=sessi…session.test|title=sessionWorkspaceEqual returns true for rebuilt workspace objects with the same values|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/session.test|title=sessionWorkspaceEqual returns true for rebuilt workspace objects with the same values|occurrence=1session.test|title=sessi…sessionContextKeys.test|title=Session Context Keys publishes Git availability independently to scoped context key services|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/sessionContextKeys.test|title=Session Context Keys publishes Git availability independently to scoped context key services|occurrence=1sessionContextKeys.test|…sessionContextKeys.test|title=setSessionContextKeys - side chat counts side chats as committed chats but still excludes tool-origin chats|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/sessionContextKeys.test|title=setSessionContextKeys - side chat counts side chats as committed chats but still excludes tool-origin chats|occurrence=1sessionContextKeys.test|…sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat defaults to false when the capability is omitted|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat defaults to false when the capability is omitted|occurrence=1sessionContextKeys.test|…sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat reflects the session capability|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat reflects the session capability|occurrence=1sessionContextKeys.test|…sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat resets to false for an undefined session|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/services/sessions/test/common/sessionContextKeys.test|title=setSessionContextKeys - side chat supportsSideChat resets to false for an undefined session|occurrence=1sessionContextKeys.test|…agentHostSessionsProvider.test|title=buildMutableConfigSchema derives per-value schema entries and special-cases autoApprove|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/test/common/agentHostSessionsProvider.test|title=buildMutableConfigSchema derives per-value schema entries and special-cases autoApprove|occurrence=1agentHostSessionsProvide…agentHostSessionsProvider.test|title=effectiveChatInteractivity archived sessions force interactive chats read-only, preserve hidden, and leave active chats unchanged|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/sessions/test/common/agentHostSessionsProvider.test|title=effectiveChatInteractivity archived sessions force interactive chats read-only, preserve hidden, and leave active chats unchanged|occurrence=1agentHostSessionsProvide…Focused concept · session.ts ×10 · 681 introduced LOCsession.ts ×10

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 681 introduced LOC across 10 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/sessions/services/sessions/common/session.ts 681 introduced LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- session.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CancellationToken } from '../../../../base/common/cancellation.js';
7 > import { IMarkdownString } from '../../../../base/common/htmlContent.js';
8 > import { IObservable, IReader } from '../../../../base/common/observable.js';
9 > import { isEqual } from '../../../../base/common/resources.js';
10 > import { ThemeIcon } from '../../../../base/common/themables.js';
11 > import { URI } from '../../../../base/common/uri.js';
12 > import { localize } from '../../../../nls.js';
13 > import { IChatSessionFileChange, IChatSessionFileChange2, isIChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
14 >
15 > export interface ISessionType {
16 > /** Unique identifier (e.g., 'copilot-cli', 'copilot-cloud', 'claude-code'). */
17 > readonly id: string;
18 > /** Display label (e.g., 'Copilot CLI', 'Cloud'). */
19 > readonly label: string;
20 > /** Icon for this session type. */
21 > readonly icon: ThemeIcon;
22 > /** Whether new sessions of this type support Worktree isolation and base-branch selection. */
23 > readonly supportsWorktreeConfiguration?: boolean;
24 > /**
25 > * The workbench chat session type (contribution id) this session type maps
26 > * to, when it differs from {@link id}. Agent-host providers use a bare agent
27 > * provider name as {@link id} (e.g. `claude`) but register their chat session
28 > * contribution and models under `agent-host-<provider>`, so they set this to
29 > * bridge the two (e.g. for entitlement/model availability lookups). Defaults
30 > * to {@link id} when omitted.
31 > */
32 > readonly chatSessionType?: string;
33 > }
34 >
35 > export const GITHUB_REMOTE_FILE_SCHEME = 'github-remote-file';
36 >
37 > /**
38 > * Status of an agent session as reported by the sessions provider.
39 > */
40 > export const enum SessionStatus {
41 > /** Session has not been sent yet (new/untitled). */
42 > Untitled = 0,
43 > /** Agent is actively working. */
44 > InProgress = 1,
45 > /** Agent is waiting for user input. */
46 > NeedsInput = 2,
47 > /** Session has completed successfully. */
48 > Completed = 3,
49 > /** Session encountered an error. */
50 > Error = 4,
51 > }
52 >
53 > /** Whether a session still has active work, including work blocked on user input. */
54 > export function isActiveSessionStatus(status: SessionStatus): boolean {
55 return status === SessionStatus.InProgress || status === SessionStatus.NeedsInput;
56 }
57 > session.ts
58 > /**
59 > * Provider-agnostic interactivity of a chat within a session. Mirrors the agent
60 > * host protocol's notion of chat interactivity but is decoupled from it so that
61 > * non-agent-host providers can report it too.
62 > *
63 > * Supports the agent-team pattern where a lead chat is fully interactive while
64 > * worker chats are read-only (visible for observability) or hidden (internal
65 > * implementation detail).
66 > */
67 > export const enum ChatInteractivity {
68 > /** The user can send messages to the chat (default when unspecified). */
69 > Full = 'full',
70 > /** The chat is visible but read-only — the user can watch but not send messages. */
71 > ReadOnly = 'read-only',
72 > /** The chat is an internal worker that should not be shown in the UI at all. */
73 > Hidden = 'hidden',
74 > }
75 >
76 > /**
77 > * The effective interactivity of a chat given its session's archived state.
78 > *
79 > * An archived session is read-only: its interactive chats must hide their
80 > * composer. `Hidden` chats are internal workers filtered out of the UI, so they
81 > * stay hidden — archiving only downgrades `Full` chats to `ReadOnly`. When not
82 > * archived, the chat keeps its own interactivity.
83 > */
84 > export function effectiveChatInteractivity(isArchived: boolean, interactivity: ChatInteractivity): ChatInteractivity {
85 if (interactivity === ChatInteractivity.Hidden) {
86 return ChatInteractivity.Hidden;
88 return isArchived ? ChatInteractivity.ReadOnly : interactivity;
89 }
90 > session.ts
91 > export interface ISessionGitRepository {
92 > /** The source repository URI. */
93 > readonly uri: URI;
94 > /** The working directory URI (e.g., a git worktree or checkout path). */
95 > readonly workTreeUri: URI | undefined;
96 > /** Current branch name. */
97 > readonly branchName?: string;
98 > /** Name of the base branch. */
99 > readonly baseBranchName: string | undefined;
100 > /** Whether the base branch is protected (drives PR vs merge workflow). */
101 > readonly baseBranchProtected?: boolean;
102 > /** Whether the repository has a github.com remote. */
103 > readonly hasGitHubRemote?: boolean;
104 > /** Upstream tracking branch name (e.g. `origin/feature`). */
105 > readonly upstreamBranchName?: string;
106 > /** Number of commits the upstream branch is ahead of the local branch. */
107 > readonly incomingChanges?: number;
108 > /** Number of commits the local branch is ahead of the upstream branch. */
109 > readonly outgoingChanges?: number;
110 > /** Number of files with uncommitted changes. */
111 > readonly uncommittedChanges?: number;
112 > /** Whether a Git operation is currently in progress. */
113 > readonly hasGitOperationInProgress?: boolean;
114 > /** GitHub information associated with the repository. */
115 > readonly gitHubInfo: IObservable<IGitHubInfo | undefined>;
116 > }
117 >
118 > /**
119 > * A folder within a session workspace.
120 > */
121 > export interface ISessionFolder {
122 > /** Canonical URI of the folder. */
123 > readonly root: URI;
124 > /** Working directory used for file operations. */
125 > readonly workingDirectory: URI;
126 > /** Display name for the folder (e.g., repository or directory basename). */
127 > readonly name: string;
128 > /** Optional description shown alongside the name (e.g., parent folder path). */
129 > readonly description: string | undefined;
130 > /** Git repository information associated with this folder. */
131 > readonly gitRepository?: ISessionGitRepository;
132 > }
133 >
134 > /**
135 > * Workspace information for a session, encapsulating one or more repositories.
136 > */
137 > export interface ISessionWorkspace {
138 > /** URI identifying the workspace. */
139 > readonly uri: URI;
140 > /** Display label for the workspace (e.g., "my-app", "org/repo", "host:/path"). */
141 > readonly label: string;
142 > /** Optional description shown alongside the label (e.g., parent folder path "~/work"). */
143 > readonly description?: string;
144 > /**
145 > * Optional group label for categorizing this workspace in pickers. The
146 > * workspace picker uses this to bucket entries into top-level tabs
147 > * (e.g. `"Local"`, `"Cloud"`, `"Remote"`). Providers contribute the
148 > * label — the picker just renders whatever values are present.
149 > */
150 > readonly group?: string;
151 > /** Icon for the workspace. */
152 > readonly icon: ThemeIcon;
153 > /** Folders in this session workspace. */
154 > readonly folders: ISessionFolder[];
155 > /** Whether the session requires workspace trust to operate. */
156 > readonly requiresWorkspaceTrust: boolean;
157 > /**
158 > * Whether this workspace is a virtual
159 > */
160 > readonly isVirtualWorkspace: boolean;
161 > }
162 >
163 > /**
164 > * GitHub information associated with a session.
165 > */
166 > export interface IGitHubInfo {
167 > /** GitHub repository owner. */
168 > readonly owner: string;
169 > /** GitHub repository name. */
170 > readonly repo: string;
171 > /** Pull request associated with this session, if any. */
172 > readonly pullRequest?: {
173 > /** Pull request number. */
174 > readonly number: number;
175 > /** URI of the pull request. */
176 > readonly uri: URI;
177 > /** Icon reflecting the PR state. */
178 > readonly icon?: ThemeIcon;
179 > /** Object ID of the base ref (merge target) commit. */
180 > readonly baseRefOid?: string;
181 > /** Object ID of the head ref (PR branch) commit. */
182 > readonly headRefOid?: string;
183 > };
184 > }
185 >
186 > export interface ISessionChangesSummary {
187 > readonly files: number;
188 > readonly additions: number;
189 > readonly deletions: number;
190 > }
191 >
192 > export type ISessionFileChange = IChatSessionFileChange | IChatSessionFileChange2;
193 >
194 > /**
195 > * The kind of change applied to a {@link ISessionFile}.
196 > *
197 > * A file that is first created and then edited during the session is reported
198 > * as {@link Created}. A file that is deleted is reported as {@link Deleted}
199 > * regardless of any earlier creation or edit.
200 > */
201 > export const enum SessionFileOperation {
202 > /** The file was created during the session (and possibly edited afterwards). */
203 > Created = 'created',
204 > /** The file existed before the session and was modified during it. */
205 > Modified = 'modified',
206 > /** The file was deleted during the session. */
207 > Deleted = 'deleted',
208 > }
209 >
210 > /**
211 > * A file that was created, edited or deleted **outside** the session workspace
212 > * folders during the session. These are surfaced separately from
213 > * {@link ISession.changes} because they are not part of the workspace and will
214 > * not be committed.
215 > */
216 > export interface ISessionFile {
217 > /** The file URI (after-state for create/modify, the deleted path for delete). */
218 > readonly uri: URI;
219 > /** The kind of change applied to the file during the session. */
220 > readonly operation: SessionFileOperation;
221 > /**
222 > * URI from which the file's pre-session content can be read, when known.
223 > * Used to render a diff for {@link SessionFileOperation.Modified} files.
224 > */
225 > readonly originalUri?: URI;
226 > }
227 >
228 > /**
229 > * Well-known id of the changeset that holds the diff between a session's branch
230 > * and its base (e.g. `main...feature`). Shared so that consumers which always
231 > * want the branch diff — regardless of the changeset currently selected in the
232 > * Changes view — can locate it in {@link ISession.changesets} by id.
233 > */
234 > export const BRANCH_CHANGES_CHANGESET_ID = 'branchChanges';
235 >
236 > /**
237 > * Well-known id of the changeset that holds the diff made during the session's
238 > * **last turn** only (as opposed to the cumulative session diff). Consumers that
239 > * want to reflect just the most recent turn — e.g. the chat input status pills —
240 > * can locate it in {@link ISession.changesets} by id.
241 > *
242 > * Must match the agent host provider's `ChangesetKind.Turn` value.
243 > */
244 > export const TURN_CHANGES_CHANGESET_ID = 'turn';
245 >
246 > export interface ISessionChangeset {
247 > /** Unique identifier for the changeset. */
248 > readonly id: string;
249 > /** Display label for the changeset. */
250 > readonly label: string;
251 > /** Optional description for the changeset. */
252 > readonly description?: string;
253 > /** Optional category for the changeset. */
254 > readonly category?: string;
255 > /** Whether the changeset is enabled. */
256 > readonly isEnabled: IObservable<boolean>;
257 > /**
258 > * Whether this changeset should be selected by default when the UI
259 > * switches to its session. May change with session state (e.g. an
260 > * archived session may default to a snapshot changeset rather than a
261 > * live one). Producers should ensure at most one changeset in a
262 > * session reports `true` at any time.
263 > */
264 > readonly isDefault: IObservable<boolean>;
265 > /**
266 > * Whether this changeset is currently loading its file changes.
267 > */
268 > readonly isLoadingChanges: IObservable<boolean>;
269 > /** Observable for the file changes in this changeset. */
270 > readonly changes: IObservable<readonly ISessionFileChange[]>;
271 > /** Observable for the operations in this changeset. */
272 > readonly operations: IObservable<readonly ISessionChangesetOperation[]>;
273 > /** Reference to the original checkpoint for this changeset. */
274 > readonly originalCheckpointRef: IObservable<string | undefined>;
275 > /** Reference to the modified checkpoint for this changeset. */
276 > readonly modifiedCheckpointRef: IObservable<string | undefined>;
277 > /** The capabilities of this changeset. */
278 > readonly capabilities?: ISessionChangesetCapabilities;
279 >
280 > /**
281 > * Invoke an operation declared in {@link operations}. `target` must be
282 > * provided for resource-scoped operations and omitted for changeset-
283 > * scoped ones — implementations are expected to validate this against
284 > * the corresponding {@link ISessionChangesetOperation.scopes}.
285 > */
286 > invokeOperation(operationId: string, target?: ISessionChangesetOperationTarget): Promise<void>;
287 >
288 > /**
289 > * Sets the review state for a list of resources when the changeset supports review.
290 > */
291 > setReviewState?(resources: readonly URI[], reviewed: boolean): void;
292 > }
293 >
294 > export type ISessionChangesetOperationTarget =
295 > | { readonly kind: 'resource'; readonly resource: URI };
296 >
297 > export const enum SessionChangesetOperationScope {
298 > Changeset = 'changeset',
299 > Resource = 'resource',
300 > Range = 'range',
301 > }
302 >
303 > /**
304 > * Execution status of a changeset operation.
305 > */
306 > export const enum SessionChangesetOperationStatus {
307 > /** The operation is ready to be invoked. */
308 > Idle = 'idle',
309 > /** An invocation is currently in flight. */
310 > Running = 'running',
311 > /** The most recent invocation failed. */
312 > Error = 'error',
313 > /** The operation is currently disabled and cannot be invoked. */
314 > Disabled = 'disabled',
315 > }
316 >
317 > export interface ISessionChangesetOperation {
318 > /** Unique identifier for the operation. */
319 > readonly id: string;
320 > /** Display label for the operation. */
321 > readonly label: string;
322 > /** Optional description for the operation. */
323 > readonly description?: string;
324 > /** Optional icon for the operation. */
325 > readonly icon?: ThemeIcon;
326 > /** Optional group identifier, used to group related operations together. */
327 > readonly group?: string;
328 > /** The scopes to which this operation applies. */
329 > readonly scopes: SessionChangesetOperationScope[];
330 > /** Current execution status for this operation. */
331 > readonly status: SessionChangesetOperationStatus;
332 > /**
333 > * Optional confirmation prompt to display before invoking the operation.
334 > * When present, callers MUST show this message to the user (typically in
335 > * a confirmation dialog) and only invoke the operation after the user
336 > * accepts. The presence of this field also signals that the operation
337 > * is destructive — callers SHOULD style the affirmative button
338 > * accordingly. The message may contain `{0}` which will be substituted
339 > * with the target resource's basename when applicable.
340 > */
341 > readonly confirmation?: string | IMarkdownString;
342 > }
343 >
344 > export interface ISessionChangesetCapabilities {
345 > /** Whether the changeset supports review workflow. */
346 > readonly review?: boolean;
347 > }
348 >
349 > /**
350 > * A custom agent reference used by session-level selection. Mirrors the Agent
351 > * Host protocol's `AgentSelection` shape but lives in the sessions layer so the
352 > * sessions service API does not leak the protocol type to non-Agent-Host
353 > * consumers.
354 > */
355 > export interface ISessionAgentRef {
356 > /** Stable agent URI (matches the contributing customization's agent ref). */
357 > readonly uri: string;
358 > /** Agent name. */
359 > readonly name: string;
360 > }
361 >
362 > export interface IChatCheckpoints {
363 > /** Reference to the first checkpoint in the chat. */
364 > readonly firstCheckpointRef: string;
365 > /** Reference to the last checkpoint in the chat. */
366 > readonly lastCheckpointRef: string;
367 > }
368 >
369 > export const enum ChatOriginKind {
370 > Tool = 'tool',
371 > User = 'user',
372 > Fork = 'fork',
373 > SideChat = 'sideChat',
374 > }
375 >
376 > export interface ISideChatSelection {
377 > readonly text: string;
378 > readonly responsePartId?: string;
379 > }
380 >
381 > export interface IChatOrigin {
382 > readonly kind: ChatOriginKind;
383 > /**
384 > * For a chat spawned by another chat (e.g. a subagent worker chat, kind
385 > * {@link ChatOriginKind.Tool}, or a {@link ChatOriginKind.Fork}), the
386 > * resource of the chat that spawned it. Undefined for user-originated chats.
387 > */
388 > readonly parentChat?: URI;
389 > readonly selection?: ISideChatSelection;
390 > }
391 >
392 > /**
393 > * Per-chat capabilities. Consumers gate chat-management UI (rename, delete) on
394 > * these flags rather than on the chat's origin/provider, so the affordances are
395 > * offered exactly where the backing chat supports them. A worker (subagent)
396 > * chat, for example, is neither renameable nor deletable.
397 > */
398 > export interface IChatCapabilities {
399 > /** Whether this chat's title can be renamed. */
400 > readonly canRename: boolean;
401 > /** Whether this chat can be permanently deleted. */
402 > readonly canDelete: boolean;
403 > }
404 >
405 > /** Capabilities assumed for a chat that does not advertise its own. */
406 > export const DEFAULT_CHAT_CAPABILITIES: IChatCapabilities = { canRename: true, canDelete: true };
407 >
408 > /**
409 > * A single chat within a session, produced by the sessions management layer.
410 > */
411 > export interface IChat {
412 > /** Resource URI identifying this chat. */
413 > readonly resource: URI;
414 > /** When the chat was created. */
415 > readonly createdAt: Date;
416 >
417 > // Reactive properties
418 >
419 > /** Chat display title (changes when auto-titled or renamed). */
420 > readonly title: IObservable<string>;
421 > /** When the chat was last updated. */
422 > readonly updatedAt: IObservable<Date>;
423 > /** Current chat status. */
424 > readonly status: IObservable<SessionStatus>;
425 > /** File changes produced by the chat. */
426 > readonly changes: IObservable<readonly ISessionFileChange[]>;
427 > /**
428 > * File changes produced by the chat's **last turn** only (as opposed to the
429 > * cumulative chat {@link changes}). Derived from the chat's live output
430 > * stream so consumers — e.g. the chat input status pills — can reflect just
431 > * what the most recent request produced. Providers that cannot determine
432 > * this omit the observable.
433 > */
434 > readonly lastTurnChanges?: IObservable<readonly ISessionFileChange[]>;
435 > /** Checkpoints associated with the chat. */
436 > readonly checkpoints: IObservable<IChatCheckpoints | undefined>;
437 > /** Currently selected model identifier. */
438 > readonly modelId: IObservable<string | undefined>;
439 > /** Currently selected mode identifier and kind. */
440 > readonly mode: IObservable<{ readonly id: string; readonly kind: string } | undefined>;
441 > /** Whether the chat is archived. */
442 > readonly isArchived: IObservable<boolean>;
443 > /** Whether the chat has been read. */
444 > readonly isRead: IObservable<boolean>;
445 > /**
446 > * Whether and how the user can interact with this chat. Providers that do
447 > * not distinguish read-only chats report {@link ChatInteractivity.Full}.
448 > *
449 > * - {@link ChatInteractivity.Full}: the user can send messages (default).
450 > * - {@link ChatInteractivity.ReadOnly}: the chat is shown but the composer is
451 > * hidden (e.g. an agent-team worker chat the user can watch but not steer).
452 > * - {@link ChatInteractivity.Hidden}: the chat is an internal worker that
453 > * should not be surfaced in the UI at all; the visible session model filters
454 > * these out of the tab strip and never makes them the active chat.
455 > */
456 > readonly interactivity: IObservable<ChatInteractivity>;
457 > /** Status description shown while the chat is active (e.g., current agent action). */
458 > readonly description: IObservable<IMarkdownString | undefined>;
459 > /** Timestamp of when the last agent turn ended, if any. */
460 > readonly lastTurnEnd: IObservable<Date | undefined>;
461 > /** How the chat came into existence, if provided by the backend. */
462 > readonly origin?: IChatOrigin;
463 > /**
464 > * Capabilities of this chat (rename/delete). Absent means the chat inherits
465 > * {@link DEFAULT_CHAT_CAPABILITIES} (fully capable); read via
466 > * {@link getChatCapabilities}.
467 > */
468 > readonly capabilities?: IObservable<IChatCapabilities>;
469 > }
470 >
471 > /**
472 > * Resolve a chat's effective capabilities. Combines the chat's own advertised
473 > * {@link IChat.capabilities} (falling back to {@link DEFAULT_CHAT_CAPABILITIES})
474 > * with the session-level invariant that a session's main chat can never be
475 > * deleted — it lives and dies with the session. Pass the owning session so the
476 > * main-chat rule applies; omit it to read only the chat's own capabilities.
477 > */
478 > export function getChatCapabilities(chat: IChat, session: ISession | undefined, reader: IReader | undefined): IChatCapabilities {
479 const own = chat.capabilities?.read(reader) ?? DEFAULT_CHAT_CAPABILITIES;
480 if (session && isEqual(chat.resource, session.mainChat.read(reader).resource)) {
483 return own;
484 }
485 > session.ts
486 > /**
487 > * A session groups one or more chats together.
488 > * All {@link ISessionData} fields are propagated from the primary (first) chat.
489 > */
490 > export interface ISession {
491 > /** Globally unique session ID (`providerId:localId`). */
492 > readonly sessionId: string;
493 > /** Resource URI identifying this session. */
494 > readonly resource: URI;
495 > /** ID of the provider that owns this session. */
496 > readonly providerId: string;
497 > /** Session type ID (e.g., 'copilot-cli', 'copilot-cloud', 'local'). */
498 > readonly sessionType: string;
499 > /** Icon for this session. */
500 > readonly icon: ThemeIcon;
501 > /** When the session was created. */
502 > readonly createdAt: Date;
503 > /** Workspace this session operates on. */
504 > readonly workspace: IObservable<ISessionWorkspace | undefined>;
505 > /** Whether the session has a usable Git repository. Providers may refine this beyond workspace metadata. */
506 > readonly hasGitRepository?: IObservable<boolean>;
507 > /** Whether this is a workspace-less "quick chat". Only quick-chat-capable providers set this; absent means `false`. */
508 > readonly isQuickChat?: IObservable<boolean>;
509 >
510 > // Reactive properties
511 >
512 > /** Session display title (changes when auto-titled or renamed). */
513 > readonly title: IObservable<string>;
514 > /** When the session was last updated. */
515 > readonly updatedAt: IObservable<Date>;
516 > /** Current session status. */
517 > readonly status: IObservable<SessionStatus>;
518 > /** Summary of file changes produced by the session. */
519 > readonly changesSummary?: IObservable<ISessionChangesSummary | undefined>;
520 > /** File changes produced by the session. */
521 > readonly changes: IObservable<readonly ISessionFileChange[]>;
522 > /** Changesets produced by the session. */
523 > readonly changesets: IObservable<readonly ISessionChangeset[] | undefined>;
524 > /**
525 > * Files created, edited or deleted **outside** the session workspace folders
526 > * during the session (e.g. config files in the user's home directory). These
527 > * are not part of {@link changes} and will not be committed. Providers that
528 > * cannot determine this report an empty array (or omit the observable).
529 > */
530 > readonly externalChanges?: IObservable<readonly ISessionFile[]>;
531 > /** Currently selected model identifier. */
532 > readonly modelId: IObservable<string | undefined>;
533 > readonly mode: IObservable<{ readonly id: string; readonly kind: string } | undefined>;
534 > /** Whether the session is still initializing (e.g., resolving git repository). */
535 > readonly loading: IObservable<boolean>;
536 > /** Whether the session is archived. */
537 > readonly isArchived: IObservable<boolean>;
538 > /** Whether the session has been read. */
539 > readonly isRead: IObservable<boolean>;
540 > /** Status description shown while the session is active (e.g., current agent action). */
541 > readonly description: IObservable<IMarkdownString | undefined>;
542 > /** Timestamp of when the last agent turn ended, if any. */
543 > readonly lastTurnEnd: IObservable<Date | undefined>;
544 > /** The chats belonging to this session group. */
545 > readonly chats: IObservable<readonly IChat[]>;
546 > /** The main (first) chat of this session. Providers may replace it for a new session via {@link ISessionsProvider.createNewChat}. */
547 > readonly mainChat: IObservable<IChat>;
548 > /**
549 > * Capabilities of this session. Observable so consumers (context keys, chat
550 > * catalog) react when a provider's advertised capabilities hydrate or change
551 > * after the session is first surfaced (e.g. an agent host whose root state
552 > * arrives after the session's first state update).
553 > */
554 > readonly capabilities: IObservable<ISessionCapabilities>;
555 > }
556 >
557 > /**
558 > * Build the canonical {@link ISession.sessionId} from a provider id and
559 > * session resource URI.
560 > *
561 > * This is the single source of truth for the `providerId:resourceUri`
562 > * string format used by every sessions provider (agent-host and
563 > * Copilot chat sessions). Consumers that only have a provider id and a
564 > * resource URI (e.g. a filesystem provider reconstructing a sessionId
565 > * from a synthetic URI) should call this rather than rebuilding the
566 > * string inline.
567 > */
568 > export function toSessionId(providerId: string, resource: URI): string {
569 return `${providerId}:${resource.toString()}`;
570 }
571 > session.ts
572 > /**
573 > * Capabilities declared per session.
574 > * Consumers check these before surfacing session-specific features in the UI.
575 > */
576 > export interface ISessionCapabilities {
577 > /** Whether this session supports multiple chats. */
578 > readonly supportsMultipleChats: boolean;
579 > /**
580 > * Whether this session supports forking a chat from a turn into a new peer
581 > * chat. The agents-window fork gesture gates on this flag rather than on the
582 > * provider id, so fork is offered exactly where the backing agent supports
583 > * it. Defaults to falsy (no fork) when omitted.
584 > */
585 > readonly supportsFork?: boolean;
586 > /**
587 > * Whether this session supports creating a side chat from a turn (via
588 > * `/btw`). Side chats inherit the source chat's model/agent and are shown
589 > * as ordinary peer chats in the session's standard chat tabs. Defaults to
590 > * falsy (no side chat) when omitted.
591 > */
592 > readonly supportsSideChat?: boolean;
593 > /**
594 > * Whether this session's title can be renamed. The agents-window UI
595 > * (session header inline edit, sessions-list `Rename...` action) gates
596 > * editing on this flag rather than on the provider id, so that rename is
597 > * offered exactly where the backing provider actually supports it.
598 > * Defaults to falsy (not renameable) when omitted.
599 > */
600 > readonly supportsRename?: boolean;
601 > /**
602 > * Whether this session can be deleted. The agents-window sessions-list
603 > * `Delete...` action gates on this flag rather than on the provider id,
604 > * so delete is offered exactly where the backing provider supports it.
605 > * Defaults to falsy (not deletable) when omitted.
606 > */
607 > readonly supportsDelete?: boolean;
608 > /**
609 > * Whether the session's underlying runtime (e.g. a cloud agent host)
610 > * already runs `runOptions.runOn === 'worktreeCreated'` tasks during
611 > * environment provisioning. When `true`, the agents-window
612 > * client-side dispatcher must NOT run those tasks itself to avoid
613 > * double-execution. Defaults to `false` for sessions backed by local
614 > * or remote agent hosts, where the client is the only thing that
615 > * could trigger them.
616 > */
617 > readonly runsWorktreeCreatedTasks?: boolean;
618 > }
619 >
620 > /**
621 > * Well-known workspace group labels used by the workspace picker to bucket
622 > * recents and browse actions into top-level tabs. Providers contribute one
623 > * of these (or any custom string) on each `ISessionWorkspace` and
624 > * `ISessionWorkspaceBrowseAction`; the picker discovers tabs from the union
625 > * of contributed values.
626 > */
627 > export const SESSION_WORKSPACE_GROUP_LOCAL = localize('sessionWorkspaceGroup.local', "Local");
628 > export const SESSION_WORKSPACE_GROUP_REMOTE = localize('sessionWorkspaceGroup.remote', "Remote");
629 >
630 > /**
631 > * The fallback title for an untitled session: "New Chat" for a quick chat,
632 > * otherwise "New Session". Callers pass the boolean so they control how they
633 > * read `isQuickChat` (reader-tracked vs `.get()`).
634 > */
635 > export function getUntitledSessionTitle(isQuickChat: boolean): string {
636 return isQuickChat
637 ? localize('agentSessions.newChat', "New Chat")
638 : localize('agentSessions.newSession', "New Session");
639 }
640 > session.ts
641 > export interface ISessionWorkspaceBrowseAction {
642 > /** Display label for the browse action. */
643 > readonly label: string;
644 > /** Optional description shown alongside the label in the workspace picker. */
645 > readonly description?: string;
646 > /**
647 > * Optional group label used by the workspace picker to bucket browse
648 > * actions into top-level tabs (e.g. `"Local"`, `"Cloud"`, `"Remote"`).
649 > * Providers contribute the label — the picker dynamically renders tabs
650 > * for whichever values are present and filters items accordingly.
651 > */
652 > readonly group?: string;
653 > /** Icon for the browse action. */
654 > readonly icon: ThemeIcon;
655 > /** The provider that owns this action. */
656 > readonly providerId: string;
657 > /** Execute the browse action and return the selected workspace, or undefined if cancelled. */
658 > run(): Promise<ISessionWorkspace | undefined>;
659 > /**
660 > * Optional method to enumerate folders inline (e.g. for a phone-friendly
661 > * picker that shows a folder list with search-as-you-type instead of
662 > * opening a separate file dialog). Implementations should respect the
663 > * cancellation token so stale queries can be aborted as the user types.
664 > *
665 > * @param query Case-insensitive substring filter (empty string returns the default set).
666 > * @param token Cancellation token; the implementation should resolve with
667 > * a partial result or empty array once cancelled.
668 > */
669 > listFolders?(query: string, token: CancellationToken): Promise<readonly ISessionWorkspace[]>;
670 > }
671 >
672 > /**
673 > * Structural equality for arrays of {@link ISessionFileChange}. Used as an
674 > * `equalsFn` on the `changes` observables so that providers can re-publish a
675 > * freshly-built array without notifying observers when the underlying file
676 > * changes have not actually changed.
677 > */
678 > export function sessionFileChangesEqual(a: readonly ISessionFileChange[], b: readonly ISessionFileChange[]): boolean {
679 if (a === b) {
680 return true;
724 return true;
725 }
726 > session.ts
727 > /**
728 > * Structural equality for {@link IGitHubInfo}. Used as an `equalsFn` on the `gitHubInfo` observable
729 > * so that providers can re-publish updated info without notifying observers when the underlying GitHub
730 > * info has not actually changed.
731 > */
732 > export function gitHubInfoEqual(a: IGitHubInfo | undefined, b: IGitHubInfo | undefined): boolean {
733 if (a === b) {
734 return true;
750 a.pullRequest?.headRefOid === b.pullRequest?.headRefOid;
751 }
752 > session.ts
753 > /**
754 > * Structural equality for {@link ISessionWorkspace}.
755 > */
756 > export function sessionWorkspaceEqual(a: ISessionWorkspace | undefined, b: ISessionWorkspace | undefined): boolean {
757 if (a === b) {
758 return true;
776 return true;
777 }
778 > session.ts
779 > /**
780 > * Structural equality for {@link ISessionFolder}.
781 > */
782 > export function sessionFolderEqual(a: ISessionFolder, b: ISessionFolder): boolean {
783 return isEqual(a.root, b.root)
784 && isEqual(a.workingDirectory, b.workingDirectory)
787 && sessionGitRepositoryEqual(a.gitRepository, b.gitRepository);
788 }
789 > session.ts
790 > /**
791 > * Structural equality for {@link ISessionGitRepository}.
792 > */
793 > export function sessionGitRepositoryEqual(a: ISessionGitRepository | undefined, b: ISessionGitRepository | undefined): boolean {
794 if (a === b) {
795 return true;