@codingame/monaco-vscode-mcp-service-override 23.2.2 → 24.1.0

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 (67) hide show
  1. package/index.js +19 -19
  2. package/package.json +2 -15
  3. package/vscode/src/vs/platform/mcp/common/allowedMcpServersService.d.ts +1 -1
  4. package/vscode/src/vs/platform/mcp/common/allowedMcpServersService.js +2 -2
  5. package/vscode/src/vs/platform/mcp/common/mcpGalleryService.d.ts +2 -2
  6. package/vscode/src/vs/platform/mcp/common/mcpGalleryService.js +4 -8
  7. package/vscode/src/vs/platform/mcp/common/mcpManagementIpc.d.ts +2 -2
  8. package/vscode/src/vs/platform/mcp/common/mcpManagementService.d.ts +2 -2
  9. package/vscode/src/vs/platform/mcp/common/mcpManagementService.js +3 -3
  10. package/vscode/src/vs/platform/mcp/common/mcpResourceScannerService.d.ts +2 -2
  11. package/vscode/src/vs/platform/mcp/common/mcpResourceScannerService.js +1 -1
  12. package/vscode/src/vs/workbench/contrib/mcp/browser/mcp.contribution.js +8 -8
  13. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpAddContextContribution.d.ts +3 -2
  14. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpAddContextContribution.js +43 -27
  15. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpCommands.js +70 -70
  16. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpDiscovery.js +1 -1
  17. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpElicitationService.d.ts +10 -4
  18. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpElicitationService.js +198 -35
  19. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpLanguageFeatures.js +21 -21
  20. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpMigration.js +9 -9
  21. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.d.ts +24 -5
  22. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpResourceQuickAccess.js +178 -51
  23. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerActions.d.ts +1 -1
  24. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerActions.js +35 -35
  25. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditor.d.ts +2 -2
  26. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditor.js +37 -37
  27. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerEditorInput.js +2 -2
  28. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerIcons.js +5 -5
  29. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerWidgets.d.ts +1 -1
  30. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServerWidgets.js +7 -7
  31. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServersView.d.ts +3 -3
  32. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpServersView.js +26 -26
  33. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.d.ts +3 -3
  34. package/vscode/src/vs/workbench/contrib/mcp/browser/mcpWorkbenchService.js +12 -12
  35. package/vscode/src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.d.ts +1 -1
  36. package/vscode/src/vs/workbench/contrib/mcp/browser/openPanelChatAndGetWidget.js +1 -1
  37. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/extensionMcpDiscovery.js +5 -5
  38. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/installedMcpServersDiscovery.js +1 -1
  39. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.d.ts +1 -1
  40. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAbstract.js +2 -2
  41. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.d.ts +1 -1
  42. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpDiscoveryAdapters.js +1 -1
  43. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/nativeMcpRemoteDiscovery.js +1 -1
  44. package/vscode/src/vs/workbench/contrib/mcp/common/discovery/workspaceMcpDiscoveryAdapter.js +1 -1
  45. package/vscode/src/vs/workbench/contrib/mcp/common/mcpContextKeys.js +4 -4
  46. package/vscode/src/vs/workbench/contrib/mcp/common/mcpDevMode.js +4 -2
  47. package/vscode/src/vs/workbench/contrib/mcp/common/mcpLanguageModelToolContribution.js +20 -14
  48. package/vscode/src/vs/workbench/contrib/mcp/common/mcpRegistry.js +14 -14
  49. package/vscode/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.d.ts +3 -1
  50. package/vscode/src/vs/workbench/contrib/mcp/common/mcpResourceFilesystem.js +19 -3
  51. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingLog.js +2 -2
  52. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingService.d.ts +1 -1
  53. package/vscode/src/vs/workbench/contrib/mcp/common/mcpSamplingService.js +21 -20
  54. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.d.ts +6 -2
  55. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServer.js +79 -47
  56. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.d.ts +3 -1
  57. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerConnection.js +8 -6
  58. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.d.ts +47 -2
  59. package/vscode/src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.js +229 -14
  60. package/vscode/src/vs/workbench/contrib/mcp/common/mcpService.js +2 -2
  61. package/vscode/src/vs/workbench/contrib/mcp/common/mcpTaskManager.d.ts +68 -0
  62. package/vscode/src/vs/workbench/contrib/mcp/common/mcpTaskManager.js +168 -0
  63. package/vscode/src/vs/workbench/services/authentication/browser/authenticationMcpService.js +10 -10
  64. package/vscode/src/vs/workbench/services/mcp/browser/mcpGalleryManifestService.d.ts +17 -2
  65. package/vscode/src/vs/workbench/services/mcp/browser/mcpGalleryManifestService.js +60 -10
  66. package/vscode/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.d.ts +1 -1
  67. package/vscode/src/vs/workbench/services/mcp/common/mcpWorkbenchManagementService.js +2 -2
@@ -1,5 +1,6 @@
1
1
  import { CancellationToken } from "@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation";
2
- import { DisposableStore, IDisposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
2
+ import { DisposableStore, IDisposable, Disposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
3
+ import { IObservable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/observable";
3
4
  import { URI } from "@codingame/monaco-vscode-api/vscode/vs/base/common/uri";
4
5
  import { IFileService } from "@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service";
5
6
  import { IInstantiationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation";
@@ -11,28 +12,46 @@ import { IEditorService } from "@codingame/monaco-vscode-api/vscode/vs/workbench
11
12
  import { IViewsService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/services/views/common/viewsService.service";
12
13
  import { IChatWidgetService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/chat.service";
13
14
  import { IChatAttachmentResolveService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/chatAttachmentResolveService.service";
14
- import { IChatRequestVariableEntry } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatVariableEntries";
15
15
  import { IMcpResource, IMcpResourceTemplate, IMcpServer } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes";
16
16
  import { IMcpService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes.service";
17
- export declare class McpResourcePickHelper {
17
+ import { ChatContextPickAttachment } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/chatContextPickService";
18
+ export declare class McpResourcePickHelper extends Disposable {
18
19
  private readonly _mcpService;
19
20
  private readonly _fileService;
20
21
  private readonly _quickInputService;
21
22
  private readonly _notificationService;
22
23
  private readonly _chatAttachmentResolveService;
24
+ private _resources;
25
+ private _pickItemsStack;
26
+ private _inDirectory;
23
27
  static sep(server: IMcpServer): IQuickPickSeparator;
28
+ addCurrentMCPQuickPickItemLevel(server: IMcpServer, resources: (IMcpResource | IMcpResourceTemplate)[]): void;
29
+ navigateBack(): boolean;
24
30
  static item(resource: IMcpResource | IMcpResourceTemplate): IQuickPickItem;
25
31
  hasServersWithResources: import("@codingame/monaco-vscode-api/vscode/vs/base/common/observable").IObservableWithChange<boolean, void>;
26
32
  explicitServers?: IMcpServer[];
27
33
  constructor(_mcpService: IMcpService, _fileService: IFileService, _quickInputService: IQuickInputService, _notificationService: INotificationService, _chatAttachmentResolveService: IChatAttachmentResolveService);
28
- toAttachment(resource: IMcpResource | IMcpResourceTemplate): Promise<IChatRequestVariableEntry | undefined>;
34
+ /**
35
+ * Navigate to a resource if it's a directory.
36
+ * Returns true if the resource is a directory with children (navigation succeeded).
37
+ * Returns false if the resource is a leaf file (no navigation).
38
+ * When returning true, statefully updates the picker state to display directory contents.
39
+ */
40
+ navigate(resource: IMcpResource | IMcpResourceTemplate, server: IMcpServer): Promise<boolean>;
41
+ toAttachment(resource: IMcpResource | IMcpResourceTemplate, server: IMcpServer): Promise<ChatContextPickAttachment> | "noop";
42
+ checkIfDirectoryAndPopulate(resource: IMcpResource | IMcpResourceTemplate, server: IMcpServer): Promise<boolean>;
29
43
  toURI(resource: IMcpResource | IMcpResourceTemplate): Promise<URI | undefined>;
44
+ checkIfNestedResources: () => boolean;
30
45
  private _resourceToAttachment;
31
46
  private _resourceTemplateToAttachment;
32
47
  private _verifyUriIfNeeded;
33
48
  private _resourceTemplateToURI;
34
49
  private _promptForTemplateValue;
35
- getPicks(onChange: (value: Map<IMcpServer, (IMcpResourceTemplate | IMcpResource)[]>) => void, token?: CancellationToken): Promise<void[]>;
50
+ private _isDirectoryResource;
51
+ getPicks(token?: CancellationToken): IObservable<{
52
+ picks: Map<IMcpServer, (IMcpResourceTemplate | IMcpResource)[]>;
53
+ isBusy: boolean;
54
+ }>;
36
55
  }
37
56
  export declare abstract class AbstractMcpResourceAccessPick {
38
57
  private readonly _scopeTo;
@@ -4,7 +4,7 @@ import { RunOnceScheduler, disposableTimeout, DeferredPromise } from '@codingame
4
4
  import { CancellationTokenSource, CancellationToken } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
5
5
  import { Codicon } from '@codingame/monaco-vscode-api/vscode/vs/base/common/codicons';
6
6
  import { Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
7
- import { DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
7
+ import { Disposable, DisposableStore, toDisposable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
8
8
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
9
9
  import { ThemeIcon } from '@codingame/monaco-vscode-api/vscode/vs/base/common/themables';
10
10
  import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
@@ -21,11 +21,15 @@ import { IChatWidgetService } from '@codingame/monaco-vscode-api/vscode/vs/workb
21
21
  import { IChatAttachmentResolveService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/chatAttachmentResolveService.service';
22
22
  import { isMcpResourceTemplate, McpCapability, McpResourceURI, McpConnectionState } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes';
23
23
  import { IMcpService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/mcp/common/mcpTypes.service';
24
+ import { McpIcons } from '../common/mcpIcons.js';
24
25
  import { openPanelChatAndGetWidget } from './openPanelChatAndGetWidget.js';
25
- import { derived } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/derived';
26
+ import { LinkedList } from '@codingame/monaco-vscode-api/vscode/vs/base/common/linkedList';
27
+ import { asArray } from '@codingame/monaco-vscode-api/vscode/vs/base/common/arrays';
26
28
  import { autorun } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/reactions/autorun';
29
+ import { observableValue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/observableValue';
30
+ import { derived } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/derived';
27
31
 
28
- let McpResourcePickHelper = class McpResourcePickHelper {
32
+ let McpResourcePickHelper = class McpResourcePickHelper extends Disposable {
29
33
  static sep(server) {
30
34
  return {
31
35
  id: server.definition.id,
@@ -33,6 +37,32 @@ let McpResourcePickHelper = class McpResourcePickHelper {
33
37
  label: server.definition.label,
34
38
  };
35
39
  }
40
+ addCurrentMCPQuickPickItemLevel(server, resources) {
41
+ let isValidPush = false;
42
+ isValidPush = this._pickItemsStack.isEmpty();
43
+ if (!isValidPush) {
44
+ const stackedItem = this._pickItemsStack.peek();
45
+ if (stackedItem?.server === server && stackedItem.resources === resources) {
46
+ isValidPush = false;
47
+ }
48
+ else {
49
+ isValidPush = true;
50
+ }
51
+ }
52
+ if (isValidPush) {
53
+ this._pickItemsStack.push({ server, resources });
54
+ }
55
+ }
56
+ navigateBack() {
57
+ const items = this._pickItemsStack.pop();
58
+ if (items) {
59
+ this._inDirectory.set({ server: items.server, resources: items.resources }, undefined);
60
+ return true;
61
+ }
62
+ else {
63
+ return false;
64
+ }
65
+ }
36
66
  static item(resource) {
37
67
  const iconPath = resource.icons.getUrl(22);
38
68
  if (isMcpResourceTemplate(resource)) {
@@ -40,7 +70,7 @@ let McpResourcePickHelper = class McpResourcePickHelper {
40
70
  id: resource.template.template,
41
71
  label: resource.title || resource.name,
42
72
  description: resource.description,
43
- detail: ( localize(8733, 'Resource template: {0}', resource.template.template)),
73
+ detail: ( localize(8864, 'Resource template: {0}', resource.template.template)),
44
74
  iconPath,
45
75
  };
46
76
  }
@@ -53,11 +83,15 @@ let McpResourcePickHelper = class McpResourcePickHelper {
53
83
  };
54
84
  }
55
85
  constructor(_mcpService, _fileService, _quickInputService, _notificationService, _chatAttachmentResolveService) {
86
+ super();
56
87
  this._mcpService = _mcpService;
57
88
  this._fileService = _fileService;
58
89
  this._quickInputService = _quickInputService;
59
90
  this._notificationService = _notificationService;
60
91
  this._chatAttachmentResolveService = _chatAttachmentResolveService;
92
+ this._resources = observableValue(this, { picks: ( new Map()), isBusy: true });
93
+ this._pickItemsStack = ( new LinkedList());
94
+ this._inDirectory = observableValue(this, undefined);
61
95
  this.hasServersWithResources = derived(reader => {
62
96
  let enabled = false;
63
97
  for (const server of this._mcpService.servers.read(reader)) {
@@ -72,13 +106,62 @@ let McpResourcePickHelper = class McpResourcePickHelper {
72
106
  }
73
107
  return enabled;
74
108
  });
109
+ this.checkIfNestedResources = () => !this._pickItemsStack.isEmpty();
110
+ }
111
+ async navigate(resource, server) {
112
+ if (isMcpResourceTemplate(resource)) {
113
+ return false;
114
+ }
115
+ const uri = resource.uri;
116
+ let stat = undefined;
117
+ try {
118
+ stat = await this._fileService.resolve(uri, { resolveMetadata: false });
119
+ }
120
+ catch (e) {
121
+ return false;
122
+ }
123
+ if (stat && this._isDirectoryResource(resource) && (stat.children?.length ?? 0) > 0) {
124
+ const currentResources = this._resources.get().picks.get(server);
125
+ if (currentResources) {
126
+ this.addCurrentMCPQuickPickItemLevel(server, currentResources);
127
+ }
128
+ const childResources = ( stat.children.map(child => {
129
+ const mcpUri = McpResourceURI.fromServer(server.definition, ( child.resource.toString()));
130
+ return {
131
+ uri: mcpUri,
132
+ mcpUri: child.resource.path,
133
+ name: child.name,
134
+ title: child.name,
135
+ description: resource.description,
136
+ mimeType: undefined,
137
+ sizeInBytes: child.size,
138
+ icons: McpIcons.fromParsed(undefined)
139
+ };
140
+ }));
141
+ this._inDirectory.set({ server, resources: childResources }, undefined);
142
+ return true;
143
+ }
144
+ return false;
75
145
  }
76
- async toAttachment(resource) {
146
+ toAttachment(resource, server) {
147
+ const noop = 'noop';
148
+ if (this._isDirectoryResource(resource)) {
149
+ this.checkIfDirectoryAndPopulate(resource, server);
150
+ return noop;
151
+ }
77
152
  if (isMcpResourceTemplate(resource)) {
78
- return this._resourceTemplateToAttachment(resource);
153
+ return this._resourceTemplateToAttachment(resource).then(val => val || noop);
79
154
  }
80
155
  else {
81
- return this._resourceToAttachment(resource);
156
+ return this._resourceToAttachment(resource).then(val => val || noop);
157
+ }
158
+ }
159
+ async checkIfDirectoryAndPopulate(resource, server) {
160
+ try {
161
+ return !(await this.navigate(resource, server));
162
+ }
163
+ catch (error) {
164
+ return false;
82
165
  }
83
166
  }
84
167
  async toURI(resource) {
@@ -120,7 +203,7 @@ let McpResourcePickHelper = class McpResourcePickHelper {
120
203
  return uri;
121
204
  }
122
205
  this._notificationService.warn(( localize(
123
- 8734,
206
+ 8865,
124
207
  "The resource {0} was not found.",
125
208
  (McpResourceURI.toServer(uri).resourceURL.toString())
126
209
  )));
@@ -161,13 +244,13 @@ let McpResourcePickHelper = class McpResourcePickHelper {
161
244
  }
162
245
  }
163
246
  let placeholder = ( localize(
164
- 8735,
247
+ 8866,
165
248
  "Value for ${0} in {1}",
166
249
  variable.name.toUpperCase(),
167
250
  rt.template.resolve(variablesWithPlaceholders).replaceAll('%24', '$')
168
251
  ));
169
252
  if (variable.optional) {
170
- placeholder += ' (' + ( localize(8736, "Optional")) + ')';
253
+ placeholder += ' (' + ( localize(8867, "Optional")) + ')';
171
254
  }
172
255
  input.placeholder = placeholder;
173
256
  input.value = '';
@@ -180,11 +263,12 @@ let McpResourcePickHelper = class McpResourcePickHelper {
180
263
  items.unshift({ id: currentID, label: value });
181
264
  }
182
265
  else if (variable.optional) {
183
- items.unshift({ id: currentID, label: ( localize(8737, "<Empty>")) });
266
+ items.unshift({ id: currentID, label: ( localize(8868, "<Empty>")) });
184
267
  }
185
268
  input.items = items;
186
269
  };
187
- let changeCancellation = store.add(( new CancellationTokenSource()));
270
+ let changeCancellation = ( new CancellationTokenSource());
271
+ store.add(toDisposable(() => changeCancellation.dispose(true)));
188
272
  const getCompletionItems = () => {
189
273
  const inputValue = input.value;
190
274
  let promise = completions.get(inputValue);
@@ -222,8 +306,7 @@ let McpResourcePickHelper = class McpResourcePickHelper {
222
306
  store.add(input.onDidChangeValue(value => {
223
307
  input.busy = true;
224
308
  changeCancellation.dispose(true);
225
- store.delete(changeCancellation);
226
- changeCancellation = store.add(( new CancellationTokenSource()));
309
+ changeCancellation = ( new CancellationTokenSource());
227
310
  getCompletionItemsScheduler.cancel();
228
311
  setItems(value);
229
312
  if (( completions.has(input.value))) {
@@ -236,12 +319,23 @@ let McpResourcePickHelper = class McpResourcePickHelper {
236
319
  getCompletionItems();
237
320
  })).finally(() => store.dispose());
238
321
  }
239
- getPicks(onChange, token) {
322
+ _isDirectoryResource(resource) {
323
+ if (resource.mimeType && resource.mimeType === 'inode/directory') {
324
+ return true;
325
+ }
326
+ else if (isMcpResourceTemplate(resource)) {
327
+ return resource.template.template.endsWith('/');
328
+ }
329
+ else {
330
+ return resource.uri.path.endsWith('/');
331
+ }
332
+ }
333
+ getPicks(token) {
240
334
  const cts = ( new CancellationTokenSource(token));
241
- const store = ( new DisposableStore());
242
- store.add(toDisposable(() => cts.dispose(true)));
335
+ let isBusyLoadingPicks = true;
336
+ this._register(toDisposable(() => cts.dispose(true)));
243
337
  let showInSequence = true;
244
- store.add(disposableTimeout(() => {
338
+ this._register(disposableTimeout(() => {
245
339
  showInSequence = false;
246
340
  publish();
247
341
  }, 5_000));
@@ -261,10 +355,10 @@ let McpResourcePickHelper = class McpResourcePickHelper {
261
355
  break;
262
356
  }
263
357
  }
264
- onChange(output);
358
+ this._resources.set({ picks: output, isBusy: isBusyLoadingPicks }, undefined);
265
359
  };
266
360
  const servers = ( new Map());
267
- return Promise.all(( (this.explicitServers || this._mcpService.servers.get()).map(async (server) => {
361
+ Promise.all(( (this.explicitServers || this._mcpService.servers.get()).map(async (server) => {
268
362
  let cap = server.capabilities.get();
269
363
  const rec = {
270
364
  templates: ( new DeferredPromise()),
@@ -279,8 +373,8 @@ let McpResourcePickHelper = class McpResourcePickHelper {
279
373
  resolve(undefined);
280
374
  }
281
375
  });
282
- store.add(cts.token.onCancellationRequested(() => resolve(undefined)));
283
- store.add(autorun(reader => {
376
+ this._register(cts.token.onCancellationRequested(() => resolve(undefined)));
377
+ this._register(autorun(reader => {
284
378
  const cap2 = server.capabilities.read(reader);
285
379
  if (cap2 !== undefined) {
286
380
  resolve(cap2);
@@ -303,9 +397,15 @@ let McpResourcePickHelper = class McpResourcePickHelper {
303
397
  rec.templates.complete([]);
304
398
  rec.resources.complete([]);
305
399
  }
306
- publish();
307
400
  }))).finally(() => {
308
- store.dispose();
401
+ isBusyLoadingPicks = false;
402
+ publish();
403
+ });
404
+ return derived(this, reader => {
405
+ const directoryResource = this._inDirectory.read(reader);
406
+ return directoryResource
407
+ ? { picks: ( new Map([[directoryResource.server, directoryResource.resources]])), isBusy: false }
408
+ : this._resources.read(reader);
309
409
  });
310
410
  }
311
411
  };
@@ -328,51 +428,78 @@ let AbstractMcpResourceAccessPick = class AbstractMcpResourceAccessPick {
328
428
  picker.canAcceptInBackground = true;
329
429
  picker.busy = true;
330
430
  picker.keepScrollPosition = true;
331
- const attachButton = ( localize(8738, "Attach to chat"));
332
- const helper = this._instantiationService.createInstance(McpResourcePickHelper);
431
+ const store = ( new DisposableStore());
432
+ const goBackId = '_goback_';
433
+ const attachButton = ( localize(8869, "Attach to chat"));
434
+ const helper = store.add(this._instantiationService.createInstance(McpResourcePickHelper));
333
435
  if (this._scopeTo) {
334
436
  helper.explicitServers = [this._scopeTo];
335
437
  }
336
- helper.getPicks(servers => {
438
+ const picksObservable = helper.getPicks(token);
439
+ store.add(autorun(reader => {
440
+ const pickItems = picksObservable.read(reader);
441
+ const isBusy = pickItems.isBusy;
337
442
  const items = [];
338
- for (const [server, resources] of servers) {
443
+ for (const [server, resources] of pickItems.picks) {
339
444
  items.push(McpResourcePickHelper.sep(server));
340
445
  for (const resource of resources) {
341
446
  const pickItem = McpResourcePickHelper.item(resource);
342
447
  pickItem.buttons = [{ iconClass: ThemeIcon.asClassName(Codicon.attach), tooltip: attachButton }];
343
- items.push({ ...pickItem, resource });
448
+ items.push({ ...pickItem, resource, server });
344
449
  }
345
450
  }
451
+ if (helper.checkIfNestedResources()) {
452
+ const goBackItem = {
453
+ id: goBackId,
454
+ label: ( localize(8870, 'Go back ↩')),
455
+ alwaysShow: true
456
+ };
457
+ items.push(goBackItem);
458
+ }
346
459
  picker.items = items;
347
- }, token).finally(() => {
348
- picker.busy = false;
349
- });
350
- const store = ( new DisposableStore());
460
+ picker.busy = isBusy;
461
+ }));
351
462
  store.add(picker.onDidTriggerItemButton(event => {
352
463
  if (event.button.tooltip === attachButton) {
353
464
  picker.busy = true;
354
- helper.toAttachment(event.item.resource).then(async (a) => {
355
- if (a) {
356
- const widget = await openPanelChatAndGetWidget(this._viewsService, this._chatWidgetService);
357
- widget?.attachmentModel.addContext(a);
358
- }
359
- picker.hide();
360
- });
465
+ const resourceItem = event.item;
466
+ const attachment = helper.toAttachment(resourceItem.resource, resourceItem.server);
467
+ if (attachment instanceof Promise) {
468
+ attachment.then(async (a) => {
469
+ if (a !== 'noop') {
470
+ const widget = await openPanelChatAndGetWidget(this._viewsService, this._chatWidgetService);
471
+ widget?.attachmentModel.addContext(...asArray(a));
472
+ }
473
+ picker.hide();
474
+ });
475
+ }
361
476
  }
362
477
  }));
478
+ store.add(picker.onDidHide(() => {
479
+ helper.dispose();
480
+ }));
363
481
  store.add(picker.onDidAccept(async (event) => {
364
- if (!event.inBackground) {
365
- picker.hide();
366
- }
367
- if (runOptions?.handleAccept) {
368
- runOptions.handleAccept?.(picker.activeItems[0], event.inBackground);
369
- }
370
- else {
482
+ try {
483
+ picker.busy = true;
371
484
  const [item] = picker.selectedItems;
372
- const uri = await helper.toURI(item.resource);
373
- if (uri) {
374
- this._editorService.openEditor({ resource: uri, options: { preserveFocus: event.inBackground } });
485
+ if (item.id === goBackId) {
486
+ helper.navigateBack();
487
+ picker.busy = false;
488
+ return;
375
489
  }
490
+ const resourceItem = item;
491
+ const resource = resourceItem.resource;
492
+ const isNested = await helper.navigate(resource, resourceItem.server);
493
+ if (!isNested) {
494
+ const uri = await helper.toURI(resource);
495
+ if (uri) {
496
+ picker.hide();
497
+ this._editorService.openEditor({ resource: uri, options: { preserveFocus: event.inBackground } });
498
+ }
499
+ }
500
+ }
501
+ finally {
502
+ picker.busy = false;
376
503
  }
377
504
  }));
378
505
  return store;
@@ -392,7 +519,7 @@ let McpResourceQuickPick = class McpResourceQuickPick extends AbstractMcpResourc
392
519
  async pick(token = CancellationToken.None) {
393
520
  const store = ( new DisposableStore());
394
521
  const qp = store.add(this._quickInputService.createQuickPick({ useSeparators: true }));
395
- qp.placeholder = ( localize(8739, "Search for resources"));
522
+ qp.placeholder = ( localize(8871, "Search for resources"));
396
523
  store.add(this.applyToPick(qp, token));
397
524
  store.add(qp.onDidHide(() => store.dispose()));
398
525
  qp.show();
@@ -19,7 +19,7 @@ import { IWorkspaceContextService } from "@codingame/monaco-vscode-api/vscode/vs
19
19
  import { IQuickInputService } from "@codingame/monaco-vscode-api/vscode/vs/platform/quickinput/common/quickInput.service";
20
20
  import { IWorkbenchEnvironmentService } from "@codingame/monaco-vscode-api/vscode/vs/workbench/services/environment/common/environmentService.service";
21
21
  import { ILabelService } from "@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service";
22
- import { ExtensionAction } from "@codingame/monaco-vscode-9ed6fe06-a052-57c2-a234-5d9b94d2e7e0-common/vscode/vs/workbench/contrib/extensions/browser/extensionsActions";
22
+ import { ExtensionAction } from "@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/extensions/browser/extensionsActions";
23
23
  import { ActionWithDropdownActionViewItem, IActionWithDropdownActionViewItemOptions } from "@codingame/monaco-vscode-api/vscode/vs/base/browser/ui/dropdown/dropdownActionViewItem";
24
24
  import { IContextMenuProvider } from "@codingame/monaco-vscode-api/vscode/vs/base/browser/contextmenu";
25
25
  export interface IMcpServerActionChangeEvent extends IActionChangeEvent {