@codingame/monaco-vscode-xterm-common 31.0.1 → 32.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. package/package.json +4 -4
  2. package/vscode/src/vs/platform/agentHost/common/state/protocol/actions.d.ts +154 -90
  3. package/vscode/src/vs/platform/agentHost/common/state/protocol/actions.js +4 -1
  4. package/vscode/src/vs/platform/agentHost/common/state/protocol/notifications.d.ts +9 -9
  5. package/vscode/src/vs/platform/agentHost/common/state/sessionState.d.ts +82 -19
  6. package/vscode/src/vs/platform/agentHost/common/state/sessionState.js +5 -1
  7. package/vscode/src/vs/workbench/contrib/terminal/browser/agentHostPty.d.ts +12 -1
  8. package/vscode/src/vs/workbench/contrib/terminal/browser/agentHostPty.js +52 -1
  9. package/vscode/src/vs/workbench/contrib/terminal/browser/agentHostTerminalService.d.ts +11 -0
  10. package/vscode/src/vs/workbench/contrib/terminal/browser/agentHostTerminalService.js +55 -10
  11. package/vscode/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.js +5 -5
  12. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalActions.js +61 -61
  13. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstance.d.ts +0 -2
  14. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstance.js +42 -38
  15. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.js +2 -2
  16. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalResizeDebouncer.js +15 -0
  17. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalTabsList.js +14 -14
  18. package/vscode/src/vs/workbench/contrib/terminal/browser/terminalTooltip.js +3 -3
  19. package/vscode/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollColorRegistry.js +3 -3
  20. package/vscode/src/vs/workbench/contrib/terminalContrib/stickyScroll/browser/terminalStickyScrollOverlay.js +3 -3
  21. package/vscode/src/vs/platform/agentHost/common/state/protocol/state.d.ts +0 -1418
  22. package/vscode/src/vs/platform/agentHost/common/state/protocol/state.js +0 -118
@@ -36,10 +36,13 @@ var ActionType;
36
36
  ActionType["SessionCustomizationToggled"] = "session/customizationToggled";
37
37
  ActionType["SessionTruncated"] = "session/truncated";
38
38
  ActionType["SessionIsReadChanged"] = "session/isReadChanged";
39
- ActionType["SessionIsDoneChanged"] = "session/isDoneChanged";
39
+ ActionType["SessionIsArchivedChanged"] = "session/isArchivedChanged";
40
+ ActionType["SessionActivityChanged"] = "session/activityChanged";
40
41
  ActionType["SessionDiffsChanged"] = "session/diffsChanged";
41
42
  ActionType["SessionConfigChanged"] = "session/configChanged";
43
+ ActionType["SessionMetaChanged"] = "session/metaChanged";
42
44
  ActionType["RootTerminalsChanged"] = "root/terminalsChanged";
45
+ ActionType["RootConfigChanged"] = "root/configChanged";
43
46
  ActionType["TerminalData"] = "terminal/data";
44
47
  ActionType["TerminalInput"] = "terminal/input";
45
48
  ActionType["TerminalResized"] = "terminal/resized";
@@ -1,4 +1,4 @@
1
- import type { URI, ISessionSummary } from "./state.js";
1
+ import type { URI, SessionSummary } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state";
2
2
  /**
3
3
  * Reason why authentication is required.
4
4
  *
@@ -47,10 +47,10 @@ export declare enum NotificationType {
47
47
  * }
48
48
  * ```
49
49
  */
50
- export interface ISessionAddedNotification {
50
+ export interface SessionAddedNotification {
51
51
  type: NotificationType.SessionAdded;
52
52
  /** Summary of the new session */
53
- summary: ISessionSummary;
53
+ summary: SessionSummary;
54
54
  }
55
55
  /**
56
56
  * Broadcast to all connected clients when a session is disposed.
@@ -71,7 +71,7 @@ export interface ISessionAddedNotification {
71
71
  * }
72
72
  * ```
73
73
  */
74
- export interface ISessionRemovedNotification {
74
+ export interface SessionRemovedNotification {
75
75
  type: NotificationType.SessionRemoved;
76
76
  /** URI of the removed session */
77
77
  session: URI;
@@ -99,7 +99,7 @@ export interface ISessionRemovedNotification {
99
99
  * replayed on reconnect. On reconnect, clients should re-fetch the full
100
100
  * catalog via `listSessions()` as usual.
101
101
  * - The server SHOULD emit this notification whenever any mutable field on
102
- * {@link ISessionSummary | `ISessionSummary`} changes for a session the
102
+ * {@link SessionSummary | `SessionSummary`} changes for a session the
103
103
  * server has surfaced via `listSessions()` or `notify/sessionAdded`.
104
104
  * Servers MAY coalesce or debounce updates for noisy fields (for example,
105
105
  * `modifiedAt` bumps while a turn is streaming, or rapidly changing
@@ -128,7 +128,7 @@ export interface ISessionRemovedNotification {
128
128
  * }
129
129
  * ```
130
130
  */
131
- export interface ISessionSummaryChangedNotification {
131
+ export interface SessionSummaryChangedNotification {
132
132
  type: NotificationType.SessionSummaryChanged;
133
133
  /** URI of the session whose summary changed */
134
134
  session: URI;
@@ -138,7 +138,7 @@ export interface ISessionSummaryChangedNotification {
138
138
  * Identity fields (`resource`, `provider`, `createdAt`) never change and
139
139
  * MUST be omitted by senders; receivers SHOULD ignore them if present.
140
140
  */
141
- changes: Partial<ISessionSummary>;
141
+ changes: Partial<SessionSummary>;
142
142
  }
143
143
  /**
144
144
  * Sent by the server when a protected resource requires (re-)authentication.
@@ -166,7 +166,7 @@ export interface ISessionSummaryChangedNotification {
166
166
  * }
167
167
  * ```
168
168
  */
169
- export interface IAuthRequiredNotification {
169
+ export interface AuthRequiredNotification {
170
170
  type: NotificationType.AuthRequired;
171
171
  /** The protected resource identifier that requires authentication */
172
172
  resource: string;
@@ -176,4 +176,4 @@ export interface IAuthRequiredNotification {
176
176
  /**
177
177
  * Discriminated union of all protocol notifications.
178
178
  */
179
- export type IProtocolNotification = ISessionAddedNotification | ISessionRemovedNotification | ISessionSummaryChangedNotification | IAuthRequiredNotification;
179
+ export type ProtocolNotification = SessionAddedNotification | SessionRemovedNotification | SessionSummaryChangedNotification | AuthRequiredNotification;
@@ -1,8 +1,9 @@
1
- import { IToolResultFileEditContent, type IActiveTurn, type IRootState, type ISessionState, type ISessionSummary, type IToolCallCancelledState, type IToolCallCompletedState, type IToolCallResult, type IToolCallState, type IToolResultContent, type IToolResultSubagentContent, type IUserMessage, ITerminalState } from "./protocol/state.js";
2
- export { type IActiveTurn, type IAgentInfo, type IConfigPropertySchema, type IConfigSchema, type IContentRef, type IErrorInfo, type IProjectInfo, type IMarkdownResponsePart, type IMessageAttachment, type IReasoningResponsePart, type IResponsePart, type IRootState, type ISessionActiveClient, type ISessionConfigState, type IFileEdit as ISessionFileDiff, type IModelSelection, type ISessionModelInfo, type ISessionState, type ISessionSummary, type ISnapshot, type ITerminalState, type IToolAnnotations, type IToolCallCancelledState, type IToolCallCompletedState, type IToolCallPendingConfirmationState, type IToolCallPendingResultConfirmationState, type IToolCallResponsePart, type IToolCallResult, type IToolCallRunningState, type IToolCallState, type IToolCallStreamingState, type IToolDefinition, type ICustomizationRef, type ISessionCustomization, type IToolResultEmbeddedResourceContent as IToolResultBinaryContent, type IToolResultContent, type IToolResultFileEditContent, type IToolResultSubagentContent, type IToolResultTextContent, type ITurn, type IUsageInfo, type IUserMessage, type IPendingMessage, type StringOrMarkdown, type URI, type ISessionInputRequest, type ISessionInputQuestion, type ISessionInputAnswer, type ISessionInputOption, AttachmentType, CustomizationStatus, PendingMessageKind, PolicyState, ResponsePartKind, SessionInputAnswerState, SessionInputAnswerValueKind, SessionInputQuestionKind, SessionInputResponseKind, SessionLifecycle, SessionStatus, ToolCallConfirmationReason, ToolCallCancellationReason, ToolCallStatus, ToolResultContentType, TurnState, } from "./protocol/state.js";
1
+ import { URI as ResourceURI } from "@codingame/monaco-vscode-api/vscode/vs/base/common/uri";
2
+ import { ToolResultFileEditContent, type ActiveTurn, type RootState, type SessionState, type SessionSummary, type ToolCallCancelledState, type ToolCallCompletedState, type ToolCallResult, type ToolCallState, type ToolResultContent, type ToolResultSubagentContent, type URI as ProtocolURI, type UserMessage, TerminalState } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state";
3
+ export { type ActiveTurn, type AgentInfo, type ConfigPropertySchema, type ConfigSchema, type ContentRef, type ErrorInfo, type ProjectInfo, type MarkdownResponsePart, type MessageAttachment, type MessageResourceAttachment, type ReasoningResponsePart, type ResponsePart, type RootState, type SessionActiveClient, type SessionConfigState, type FileEdit as ISessionFileDiff, type ModelSelection, type SessionModelInfo, type SessionState, type SessionSummary, type Snapshot, type TerminalState, type ToolAnnotations, type ToolCallCancelledState, type ToolCallCompletedState, type ToolCallPendingConfirmationState, type ToolCallPendingResultConfirmationState, type ToolCallResponsePart, type ToolCallResult, type ToolCallRunningState, type ToolCallState, type ToolCallStreamingState, type ToolDefinition, type CustomizationRef, type SessionCustomization, type ToolResultEmbeddedResourceContent as IToolResultBinaryContent, type ToolResultContent, type ToolResultFileEditContent, type ToolResultSubagentContent, type ToolResultTextContent, type Turn, type UsageInfo, type UserMessage, type PendingMessage, type StringOrMarkdown, type URI, type SessionInputRequest, type SessionInputQuestion, type SessionInputAnswer, type SessionInputOption, CustomizationStatus, MessageAttachmentKind, PendingMessageKind, PolicyState, ResponsePartKind, SessionInputAnswerState, SessionInputAnswerValueKind, SessionInputQuestionKind, SessionInputResponseKind, SessionLifecycle, SessionStatus, ToolCallConfirmationReason, ToolCallCancellationReason, ToolCallStatus, ToolResultContentType, TurnState, } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state";
3
4
  /**
4
5
  * The kind of file edit operation. Derived from the presence/absence of
5
- * `before`/`after` in {@link IToolResultFileEditContent}.
6
+ * `before`/`after` in {@link ToolResultFileEditContent}.
6
7
  */
7
8
  export declare enum FileEditKind {
8
9
  /** Content edit (same file URI, different content). */
@@ -19,58 +20,120 @@ export declare const ROOT_STATE_URI = "agenthost:/root";
19
20
  /**
20
21
  * A tool call in a terminal state, stored in completed turns.
21
22
  */
22
- export type ICompletedToolCall = IToolCallCompletedState | IToolCallCancelledState;
23
+ export type ICompletedToolCall = ToolCallCompletedState | ToolCallCancelledState;
23
24
  /**
24
25
  * Derived status type for the tool call lifecycle.
25
26
  */
26
- export type ToolCallStatusString = IToolCallState["status"];
27
+ export type ToolCallStatusString = ToolCallState["status"];
27
28
  /**
28
29
  * Extracts a plain-text tool output string from a tool call result's `content`
29
30
  * array. Joins all text-type content parts into a single string.
30
31
  *
31
32
  * Returns `undefined` if there are no text content parts.
32
33
  */
33
- export declare function getToolOutputText(result: IToolCallResult): string | undefined;
34
+ export declare function getToolOutputText(result: ToolCallResult): string | undefined;
34
35
  /**
35
36
  * Extracts file edit content entries from a tool call result's `content` array.
36
37
  * Returns an empty array if there are no file edit content parts.
37
38
  */
38
- export declare function getToolFileEdits(result: IToolCallResult): IToolResultFileEditContent[];
39
+ export declare function getToolFileEdits(result: ToolCallResult): ToolResultFileEditContent[];
39
40
  /**
40
41
  * Extracts the first subagent content entry from a tool call's `content` array.
41
42
  * Works with both completed tool call results and running tool call states.
42
43
  * Returns `undefined` if there are no subagent content parts.
43
44
  */
44
45
  export declare function getToolSubagentContent(result: {
45
- content?: readonly IToolResultContent[];
46
- }): IToolResultSubagentContent | undefined;
46
+ content?: readonly ToolResultContent[];
47
+ }): ToolResultSubagentContent | undefined;
47
48
  /**
48
49
  * Builds a subagent session URI from a parent session URI and tool call ID.
49
50
  * Convention: `{parentSessionUri}/subagent/{toolCallId}`
50
51
  */
51
- export declare function buildSubagentSessionUri(parentSession: string, toolCallId: string): string;
52
+ export declare function buildSubagentSessionUri(parentSession: ProtocolURI | ResourceURI, toolCallId: string): string;
52
53
  /**
53
54
  * Parses a subagent session URI into its parent session URI and tool call ID.
54
55
  * Returns `undefined` if the URI does not follow the subagent convention.
55
56
  */
56
- export declare function parseSubagentSessionUri(uri: string): {
57
- parentSession: string;
57
+ export declare function parseSubagentSessionUri(uri: ProtocolURI | ResourceURI): {
58
+ parentSession: ResourceURI;
58
59
  toolCallId: string;
59
60
  } | undefined;
60
61
  /**
61
62
  * Returns whether a session URI represents a subagent session.
62
63
  */
63
- export declare function isSubagentSession(uri: string): boolean;
64
- export declare function createRootState(): IRootState;
65
- export declare function createSessionState(summary: ISessionSummary): ISessionState;
66
- export declare function createActiveTurn(id: string, userMessage: IUserMessage): IActiveTurn;
64
+ export declare function isSubagentSession(uri: ProtocolURI | ResourceURI): boolean;
65
+ /**
66
+ * Builds the string prefix used by the state manager for cached subagent sessions.
67
+ */
68
+ export declare function buildSubagentSessionUriPrefix(parentSession: ProtocolURI | ResourceURI): string;
69
+ export declare function createRootState(): RootState;
70
+ export declare function createSessionState(summary: SessionSummary): SessionState;
71
+ export declare function createActiveTurn(id: string, userMessage: UserMessage): ActiveTurn;
67
72
  export declare enum StateComponents {
68
73
  Root = 0,
69
74
  Session = 1,
70
75
  Terminal = 2
71
76
  }
72
77
  export type ComponentToState = {
73
- [StateComponents.Root]: IRootState;
74
- [StateComponents.Session]: ISessionState;
75
- [StateComponents.Terminal]: ITerminalState;
78
+ [StateComponents.Root]: RootState;
79
+ [StateComponents.Session]: SessionState;
80
+ [StateComponents.Terminal]: TerminalState;
76
81
  };
82
+ /**
83
+ * VS Code-side alias for the protocol's open `_meta` property bag on
84
+ * {@link SessionState}. Keys SHOULD be namespaced (e.g. `git`, `vscode.foo`)
85
+ * to avoid collisions; values MUST be JSON-serializable.
86
+ */
87
+ export type SessionMeta = Record<string, unknown>;
88
+ /**
89
+ * Reserved key under {@link SessionMeta} for the well-known git-state
90
+ * payload. Value at this key, when present, MUST be shaped like
91
+ * {@link ISessionGitState}. This is a VS Code-specific convention layered
92
+ * on top of the protocol's generic `_meta` bag — the protocol itself does
93
+ * not know about git state.
94
+ */
95
+ export declare const SESSION_META_GIT_KEY = "git";
96
+ /**
97
+ * Git state of a session's working directory, carried under
98
+ * {@link SessionMeta} at {@link SESSION_META_GIT_KEY}. Used by clients to
99
+ * drive source-control affordances (e.g. PR/merge buttons in the Agents
100
+ * app).
101
+ *
102
+ * All fields are optional — agents that do not track a particular field
103
+ * should omit it rather than send a placeholder, so clients can distinguish
104
+ * "unknown" from "known to be zero".
105
+ */
106
+ export interface ISessionGitState {
107
+ /** Whether the working directory has a `github.com` git remote. */
108
+ readonly hasGitHubRemote?: boolean;
109
+ /** Current branch name. */
110
+ readonly branchName?: string;
111
+ /** Base branch the work targets (e.g. `main`). */
112
+ readonly baseBranchName?: string;
113
+ /** Upstream tracking branch (e.g. `origin/feature`). */
114
+ readonly upstreamBranchName?: string;
115
+ /** Number of commits the upstream branch has ahead of the local branch. */
116
+ readonly incomingChanges?: number;
117
+ /** Number of commits the local branch has ahead of the upstream branch. */
118
+ readonly outgoingChanges?: number;
119
+ /** Number of files with uncommitted changes. */
120
+ readonly uncommittedChanges?: number;
121
+ /** GitHub repository owner parsed from the working copy's GitHub remote (preferring `origin`, falling back to the first GitHub remote). */
122
+ readonly githubOwner?: string;
123
+ /** GitHub repository name parsed from the working copy's GitHub remote (preferring `origin`, falling back to the first GitHub remote). */
124
+ readonly githubRepo?: string;
125
+ }
126
+ /**
127
+ * Reads the well-known git-state payload from {@link SessionMeta}, if
128
+ * present. Returns `undefined` when the meta bag is absent or the value at
129
+ * the git key is not a plain object (e.g. an array or a primitive).
130
+ * Individual fields with wrong types are silently dropped so partial state
131
+ * still propagates.
132
+ */
133
+ export declare function readSessionGitState(meta: SessionMeta | undefined): ISessionGitState | undefined;
134
+ /**
135
+ * Returns a new {@link SessionMeta} with the git-state payload set to
136
+ * `gitState`, or with the git slot removed if `gitState` is `undefined`.
137
+ * Returns `undefined` if the result would be empty.
138
+ */
139
+ export declare function withSessionGitState(meta: SessionMeta | undefined, gitState: ISessionGitState | undefined): SessionMeta | undefined;
@@ -1,6 +1,10 @@
1
1
 
2
2
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
3
- export { AttachmentType, CustomizationStatus, PendingMessageKind, PolicyState, ResponsePartKind, SessionInputAnswerState, SessionInputAnswerValueKind, SessionInputQuestionKind, SessionInputResponseKind, SessionLifecycle, SessionStatus, ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallStatus, ToolResultContentType, TurnState } from './protocol/state.js';
3
+ import '@codingame/monaco-vscode-api/vscode/vs/base/common/charCode';
4
+ import '@codingame/monaco-vscode-api/vscode/vs/base/common/marshallingIds';
5
+ import '@codingame/monaco-vscode-api/vscode/vs/base/common/path';
6
+ import '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
7
+ export { CustomizationStatus, MessageAttachmentKind, PendingMessageKind, PolicyState, ResponsePartKind, SessionInputAnswerState, SessionInputAnswerValueKind, SessionInputQuestionKind, SessionInputResponseKind, SessionLifecycle, SessionStatus, ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallStatus, ToolResultContentType, TurnState } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state';
4
8
 
5
9
  var FileEditKind;
6
10
  (function(FileEditKind) {
@@ -54,7 +54,7 @@ export declare function getAhpCommandMarkId(commandId: string, kind: AhpCommandM
54
54
  * shutdown() → disposeTerminal command
55
55
  */
56
56
  export declare class AgentHostPty extends BasePty implements ITerminalChildProcess {
57
- private readonly _connection;
57
+ private _connection;
58
58
  private readonly _terminalUri;
59
59
  private readonly _options?;
60
60
  private readonly _startBarrier;
@@ -102,5 +102,16 @@ export declare class AgentHostPty extends BasePty implements ITerminalChildProce
102
102
  sendSignal(_signal: string): void;
103
103
  refreshProperty<T extends ProcessPropertyType>(type: T): Promise<IProcessPropertyMap[T]>;
104
104
  updateProperty<T extends ProcessPropertyType>(_type: T, _value: IProcessPropertyMap[T]): Promise<void>;
105
+ /**
106
+ * Reconnect this pty to a new agent host connection. Tears down the
107
+ * old subscription and re-subscribes with the new connection, replaying
108
+ * content from the server-side snapshot. Terminal output during the
109
+ * disconnect gap is a stream (not state), so some loss is expected.
110
+ *
111
+ * @returns `true` if reconnection succeeded, `false` otherwise.
112
+ */
113
+ reconnect(newConnection: IAgentConnection): Promise<boolean>;
114
+ /** The terminal URI this pty is subscribed to. */
115
+ get terminalUri(): URI;
105
116
  dispose(): void;
106
117
  }
@@ -6,7 +6,7 @@ import { ProcessPropertyType } from '@codingame/monaco-vscode-api/vscode/vs/plat
6
6
  import { AGENT_HOST_SCHEME, fromAgentHostUri } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/agentHostUri';
7
7
  import { ActionType } from '../../../../platform/agentHost/common/state/protocol/actions.js';
8
8
  import '../../../../platform/agentHost/common/state/protocol/notifications.js';
9
- import { TerminalClaimKind } from '../../../../platform/agentHost/common/state/protocol/state.js';
9
+ import { TerminalClaimKind } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state';
10
10
  import { StateComponents } from '../../../../platform/agentHost/common/state/sessionState.js';
11
11
  import { BasePty } from '../common/basePty.js';
12
12
 
@@ -266,6 +266,57 @@ class AgentHostPty extends BasePty {
266
266
  return this._properties[type];
267
267
  }
268
268
  async updateProperty(_type, _value) {}
269
+ async reconnect(newConnection) {
270
+ this._subscriptionDisposables.clear();
271
+ this._subscriptionRef?.dispose();
272
+ this._subscriptionRef = undefined;
273
+ this._connection = newConnection;
274
+ try {
275
+ this._subscriptionRef = this._connection.getSubscription(StateComponents.Terminal, this._terminalUri);
276
+ const subscription = this._subscriptionRef.object;
277
+ if (subscription.value === undefined) {
278
+ const RECONNECT_HYDRATE_TIMEOUT_MS = 10_000;
279
+ await ( new Promise((resolve, reject) => {
280
+ const timer = setTimeout(() => {
281
+ listener.dispose();
282
+ reject(( new Error("Reconnect hydration timed out")));
283
+ }, RECONNECT_HYDRATE_TIMEOUT_MS);
284
+ const listener = subscription.onDidChange(() => {
285
+ clearTimeout(timer);
286
+ listener.dispose();
287
+ resolve();
288
+ });
289
+ this._subscriptionDisposables.add(listener);
290
+ }));
291
+ }
292
+ const state = subscription.value;
293
+ if (state.supportsCommandDetection && !this._supportsCommandDetection) {
294
+ this._supportsCommandDetection = true;
295
+ this._onSupportsCommandDetection.fire();
296
+ }
297
+ this.handleData("\u001b[2J\u001b[3J\u001b[H");
298
+ this._replayContent(state.content);
299
+ if (state.cwd) {
300
+ this._properties.cwd = ( state.cwd.toString());
301
+ }
302
+ if (state.title) {
303
+ this._properties.title = state.title;
304
+ }
305
+ this._subscriptionDisposables.add(subscription.onDidApplyAction(envelope => {
306
+ this._handleAction(envelope);
307
+ }));
308
+ return true;
309
+ } catch (err) {
310
+ console.warn(
311
+ "[AgentHostPty] Reconnection failed:",
312
+ err instanceof Error ? err.message : String(err)
313
+ );
314
+ return false;
315
+ }
316
+ }
317
+ get terminalUri() {
318
+ return this._terminalUri;
319
+ }
269
320
  dispose() {
270
321
  this._subscriptionRef?.dispose();
271
322
  this._subscriptionRef = undefined;
@@ -44,6 +44,12 @@ export declare class AgentHostTerminalService extends Disposable implements IAge
44
44
  private _defaultCwd;
45
45
  /** Revived terminal instances, keyed by terminal URI string. */
46
46
  private readonly _revivedInstances;
47
+ /**
48
+ * Active AgentHostPty instances with their owning connection clientId,
49
+ * keyed by terminal URI string. Used for reconnection scoping.
50
+ */
51
+ private readonly _activePtys;
52
+ private readonly _reviveSequencer;
47
53
  constructor(_terminalService: ITerminalService, _terminalChatService: ITerminalChatService, _terminalProfileService: ITerminalProfileService, _quickInputService: IQuickInputService);
48
54
  registerEntry(entry: IAgentHostEntry): IDisposable;
49
55
  getProfileForConnection(address: string): IAgentHostTerminalProfileInfo | undefined;
@@ -53,4 +59,9 @@ export declare class AgentHostTerminalService extends Disposable implements IAge
53
59
  createTerminalForEntry(address: string, options?: IAgentHostTerminalCreateOptions): Promise<ITerminalInstance | undefined>;
54
60
  createTerminal(connection: IAgentConnection, options?: IAgentHostTerminalCreateOptions): Promise<ITerminalInstance>;
55
61
  reviveTerminal(connection: IAgentConnection, terminalUri: URI, terminalToolSessionId: string): Promise<ITerminalInstance>;
62
+ private _doReviveTerminal;
63
+ reconnectTerminals(newConnection: IAgentConnection, oldClientId: string): Promise<{
64
+ recovered: number;
65
+ total: number;
66
+ }>;
56
67
  }
@@ -1,5 +1,6 @@
1
1
 
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
+ import { SequencerByKey } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
3
4
  import { Disposable, DisposableMap, toDisposable, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
4
5
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
5
6
  import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
@@ -32,6 +33,8 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
32
33
  this._profiles = observableValue("agentHostTerminalProfiles", []);
33
34
  this.profiles = this._profiles;
34
35
  this._revivedInstances = ( new Map());
36
+ this._activePtys = ( new Map());
37
+ this._reviveSequencer = ( new SequencerByKey());
35
38
  }
36
39
  registerEntry(entry) {
37
40
  this._entries.push(entry);
@@ -80,7 +83,7 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
80
83
  }
81
84
  } else if (displaying < entries.length) {
82
85
  desiredProfiles.set("__quickpick__", {
83
- name: ( localize(13463, "Agent Host…")),
86
+ name: ( localize(13777, "Agent Host…")),
84
87
  address: "__quickpick__",
85
88
  getConnection: () => undefined
86
89
  });
@@ -101,7 +104,7 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
101
104
  infos.push({
102
105
  extensionIdentifier: AGENT_HOST_PROFILE_EXT_ID,
103
106
  profileId: key,
104
- title: key === "__quickpick__" ? ( localize(13463, "Agent Host…")) : ( localize(13464, "Agent Host ({0})", desiredProfiles.get(key).name)),
107
+ title: key === "__quickpick__" ? ( localize(13777, "Agent Host…")) : ( localize(13778, "Agent Host ({0})", desiredProfiles.get(key).name)),
105
108
  address: key
106
109
  });
107
110
  }
@@ -116,12 +119,12 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
116
119
  let displayName = entry.name;
117
120
  if (key === "__quickpick__") {
118
121
  const picks = ( allEntries.map(e => ({
119
- label: ( localize(13464, "Agent Host ({0})", e.name)),
122
+ label: ( localize(13778, "Agent Host ({0})", e.name)),
120
123
  address: e.address,
121
124
  hostName: e.name
122
125
  })));
123
126
  const pick = await this._quickInputService.pick(picks, {
124
- placeHolder: ( localize(13465, "Select an agent host to open a terminal on"))
127
+ placeHolder: ( localize(13779, "Select an agent host to open a terminal on"))
125
128
  });
126
129
  if (!pick) {
127
130
  return;
@@ -137,13 +140,13 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
137
140
  return;
138
141
  }
139
142
  await this.createTerminal(connection, {
140
- name: ( localize(13464, "Agent Host ({0})", displayName)),
143
+ name: ( localize(13778, "Agent Host ({0})", displayName)),
141
144
  cwd: options.cwd ? (typeof options.cwd === "string" ? URI.file(options.cwd) : options.cwd) : this._defaultCwd,
142
145
  location: options.location
143
146
  });
144
147
  }
145
148
  };
146
- const title = key === "__quickpick__" ? ( localize(13463, "Agent Host…")) : ( localize(13464, "Agent Host ({0})", entry.name));
149
+ const title = key === "__quickpick__" ? ( localize(13777, "Agent Host…")) : ( localize(13778, "Agent Host ({0})", entry.name));
147
150
  const store = ( new DisposableStore());
148
151
  store.add(
149
152
  this._terminalProfileService.registerTerminalProfileProvider(AGENT_HOST_PROFILE_EXT_ID, key, provider)
@@ -172,8 +175,9 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
172
175
  scheme: "agenthost-terminal",
173
176
  path: `/${generateUuid()}`
174
177
  }));
175
- const name = options?.name ?? ( localize(13466, "Agent Host Terminal"));
176
- return this._terminalService.createTerminal({
178
+ const name = options?.name ?? ( localize(13780, "Agent Host Terminal"));
179
+ const key = ( terminalUri.toString());
180
+ const instance = await this._terminalService.createTerminal({
177
181
  config: {
178
182
  customPtyImplementation: (id, cols, rows) => {
179
183
  const pty = ( new AgentHostPty(id, connection, terminalUri, {
@@ -183,6 +187,10 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
183
187
  if (cols > 0 && rows > 0) {
184
188
  pty.resize(cols, rows);
185
189
  }
190
+ this._activePtys.set(key, {
191
+ pty,
192
+ clientId: connection.clientId
193
+ });
186
194
  return pty;
187
195
  },
188
196
  name,
@@ -193,9 +201,19 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
193
201
  },
194
202
  location: options?.location
195
203
  });
204
+ this._register(instance.onDisposed(() => {
205
+ this._activePtys.delete(key);
206
+ }));
207
+ return instance;
196
208
  }
197
209
  async reviveTerminal(connection, terminalUri, terminalToolSessionId) {
198
210
  const key = ( terminalUri.toString());
211
+ return this._reviveSequencer.queue(
212
+ key,
213
+ () => this._doReviveTerminal(connection, terminalUri, terminalToolSessionId, key)
214
+ );
215
+ }
216
+ async _doReviveTerminal(connection, terminalUri, terminalToolSessionId, key) {
199
217
  const existing = this._revivedInstances.get(key);
200
218
  if (existing) {
201
219
  return existing;
@@ -217,10 +235,15 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
217
235
  if (!store.isDisposed) {
218
236
  commandSource.connect(instance, pty);
219
237
  }
238
+ this._activePtys.set(key, {
239
+ pty,
240
+ clientId: connection.clientId
241
+ });
220
242
  return pty;
221
243
  },
222
- name: ( localize(13467, "Agent Host Terminal")),
223
- isFeatureTerminal: true
244
+ name: ( localize(13781, "Agent Host Terminal")),
245
+ isFeatureTerminal: true,
246
+ hideFromUser: true
224
247
  }
225
248
  });
226
249
  this._terminalChatService.registerTerminalInstanceWithToolSession(terminalToolSessionId, instance);
@@ -228,9 +251,31 @@ let AgentHostTerminalService = class AgentHostTerminalService extends Disposable
228
251
  instance.store.add(store);
229
252
  this._register(instance.onDisposed(() => {
230
253
  this._revivedInstances.delete(key);
254
+ this._activePtys.delete(key);
231
255
  }));
232
256
  return instance;
233
257
  }
258
+ async reconnectTerminals(newConnection, oldClientId) {
259
+ const entries = [...this._activePtys.entries()].filter(([, entry]) => entry.clientId === oldClientId);
260
+ const total = entries.length;
261
+ let recovered = 0;
262
+ const promises = [];
263
+ for (const [key, entry] of entries) {
264
+ promises.push(entry.pty.reconnect(newConnection).then(success => {
265
+ if (success) {
266
+ recovered++;
267
+ entry.clientId = newConnection.clientId;
268
+ } else {
269
+ console.warn(`[AgentHostTerminalService] Failed to reconnect terminal: ${key}`);
270
+ }
271
+ }));
272
+ }
273
+ await Promise.all(promises);
274
+ return {
275
+ recovered,
276
+ total
277
+ };
278
+ }
234
279
  };
235
280
  AgentHostTerminalService = ( __decorate([( __param(0, ITerminalService)), ( __param(1, ITerminalChatService)), ( __param(2, ITerminalProfileService)), ( __param(3, IQuickInputService))], AgentHostTerminalService));
236
281
 
@@ -24,7 +24,7 @@ let EnvironmentVariableInfoStale = class EnvironmentVariableInfoStale {
24
24
  addExtensionIdentifiers(extSet, ( this._diff.removed.values()));
25
25
  addExtensionIdentifiers(extSet, ( this._diff.changed.values()));
26
26
  let message = ( localize(
27
- 13472,
27
+ 13786,
28
28
  "The following extensions want to relaunch the terminal to contribute to its environment:"
29
29
  ));
30
30
  message += getMergedDescription(this._collection, scope, this._extensionService, extSet);
@@ -32,7 +32,7 @@ let EnvironmentVariableInfoStale = class EnvironmentVariableInfoStale {
32
32
  }
33
33
  _getActions() {
34
34
  return [{
35
- label: ( localize(13473, "Relaunch Terminal")),
35
+ label: ( localize(13787, "Relaunch Terminal")),
36
36
  run: () => this._terminalService.getInstanceFromId(this._terminalId)?.relaunch(),
37
37
  commandId: TerminalCommandId.Relaunch
38
38
  }];
@@ -59,7 +59,7 @@ let EnvironmentVariableInfoChangesActive = class EnvironmentVariableInfoChangesA
59
59
  const extSet = ( new Set());
60
60
  addExtensionIdentifiers(extSet, ( this._collection.getVariableMap(scope).values()));
61
61
  let message = ( localize(
62
- 13474,
62
+ 13788,
63
63
  "The following extensions have contributed to this terminal's environment:"
64
64
  ));
65
65
  message += getMergedDescription(this._collection, scope, this._extensionService, extSet);
@@ -67,7 +67,7 @@ let EnvironmentVariableInfoChangesActive = class EnvironmentVariableInfoChangesA
67
67
  }
68
68
  _getActions(scope) {
69
69
  return [{
70
- label: ( localize(13475, "Show Environment Contributions")),
70
+ label: ( localize(13789, "Show Environment Contributions")),
71
71
  run: () => this._commandService.executeCommand(TerminalCommandId.ShowEnvironmentContributions, scope),
72
72
  commandId: TerminalCommandId.ShowEnvironmentContributions
73
73
  }];
@@ -95,7 +95,7 @@ function getMergedDescription(collection, scope, extensionService, extSet) {
95
95
  }
96
96
  const workspaceDescription = workspaceDescriptions.get(ext);
97
97
  if (workspaceDescription) {
98
- const workspaceSuffix = globalDescription ? ` (${( localize(13476, "workspace"))})` : "";
98
+ const workspaceSuffix = globalDescription ? ` (${( localize(13790, "workspace"))})` : "";
99
99
  message.push(`\n- \`${getExtensionName(ext, extensionService)}${workspaceSuffix}\``);
100
100
  message.push(`: ${workspaceDescription}`);
101
101
  }