From 26b6024286ee4f7a3ce0da548ebdc53c505d5aa1 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega Date: Tue, 3 Mar 2026 15:43:40 -0800 Subject: [PATCH] Using merge strategy --- extensions/git/src/commands.ts | 23 +- extensions/github/package.json | 2 +- src/vs/platform/actions/common/actions.ts | 1 + .../browser/applyChangesToParentRepo.ts | 201 ++++++++++++++++ .../browser/applyToParentRepo.contribution.ts | 216 ------------------ .../changesView/browser/changesView.ts | 5 +- .../changesView/browser/media/changesView.css | 24 ++ src/vs/sessions/sessions.desktop.main.ts | 2 +- .../actions/common/menusExtensionPoint.ts | 6 + 9 files changed, 254 insertions(+), 226 deletions(-) create mode 100644 src/vs/sessions/contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.ts delete mode 100644 src/vs/sessions/contrib/applyToParentRepo/browser/applyToParentRepo.contribution.ts diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 010d34e4b01..cb54a17fbae 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1075,6 +1075,22 @@ export class CommandCenter { } } + @command('_git.revParseAbbrevRef') + async revParseAbbrevRef(repositoryPath: string): Promise { + const dotGit = await this.git.getRepositoryDotGit(repositoryPath); + const repo = new GitRepository(this.git, repositoryPath, undefined, dotGit, this.logger); + const result = await repo.exec(['rev-parse', '--abbrev-ref', 'HEAD']); + return result.stdout.trim(); + } + + @command('_git.mergeBranch') + async mergeBranch(repositoryPath: string, branch: string): Promise { + const dotGit = await this.git.getRepositoryDotGit(repositoryPath); + const repo = new GitRepository(this.git, repositoryPath, undefined, dotGit, this.logger); + const result = await repo.exec(['merge', branch, '--no-edit']); + return result.stdout.trim(); + } + @command('git.init') async init(skipFolderPrompt = false): Promise { let repositoryPath: string | undefined = undefined; @@ -5653,15 +5669,14 @@ export class CommandCenter { options.modal = false; break; default: { - const hint = (err.stderr || err.message || String(err)) + const hint = (err.stderr || err.stdout || err.message || String(err)) .replace(/^error: /mi, '') .replace(/^> husky.*$/mi, '') .split(/[\r\n]/) - .filter((line: string) => !!line) - [0]; + .filter((line: string) => !!line); message = hint - ? l10n.t('Git: {0}', hint) + ? l10n.t('Git: {0}', err.stdout ? hint[hint.length - 1] : hint[0]) : l10n.t('Git error'); break; diff --git a/extensions/github/package.json b/extensions/github/package.json index bce90fe1812..815c6452706 100644 --- a/extensions/github/package.json +++ b/extensions/github/package.json @@ -183,7 +183,7 @@ "when": "github.hasGitHubRepo && timelineItem =~ /git:file:commit\\b/" } ], - "chat/input/editing/sessionToolbar": [ + "chat/input/editing/sessionApplyActions": [ { "command": "github.createPullRequest", "group": "navigation", diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 1b3e9d595c8..f7168ac83af 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -259,6 +259,7 @@ export class MenuId { static readonly ChatModePicker = new MenuId('ChatModePicker'); static readonly ChatEditingWidgetToolbar = new MenuId('ChatEditingWidgetToolbar'); static readonly ChatEditingSessionChangesToolbar = new MenuId('ChatEditingSessionChangesToolbar'); + static readonly ChatEditingSessionApplySubmenu = new MenuId('ChatEditingSessionApplySubmenu'); static readonly ChatEditingEditorContent = new MenuId('ChatEditingEditorContent'); static readonly ChatEditingEditorHunk = new MenuId('ChatEditingEditorHunk'); static readonly ChatEditingDeletedNotebookCell = new MenuId('ChatEditingDeletedNotebookCell'); diff --git a/src/vs/sessions/contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.ts b/src/vs/sessions/contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.ts new file mode 100644 index 00000000000..5cd8f78d9b7 --- /dev/null +++ b/src/vs/sessions/contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.ts @@ -0,0 +1,201 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { toAction } from '../../../../base/common/actions.js'; +import { Disposable, DisposableStore, MutableDisposable } from '../../../../base/common/lifecycle.js'; +import { Schemas } from '../../../../base/common/network.js'; +import { autorun } from '../../../../base/common/observable.js'; +import { Codicon } from '../../../../base/common/codicons.js'; +import { localize, localize2 } from '../../../../nls.js'; +import { Action2, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { ICommandService } from '../../../../platform/commands/common/commands.js'; +import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; +import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; +import { IOpenerService } from '../../../../platform/opener/common/opener.js'; +import { IProductService } from '../../../../platform/product/common/productService.js'; +import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../../workbench/common/contributions.js'; +import { IsSessionsWindowContext } from '../../../../workbench/common/contextkeys.js'; +import { CHAT_CATEGORY } from '../../../../workbench/contrib/chat/browser/actions/chatActions.js'; +import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js'; +import { IGitService } from '../../../../workbench/contrib/git/common/gitService.js'; +import { ISessionsManagementService } from '../../sessions/browser/sessionsManagementService.js'; +import { ILogService } from '../../../../platform/log/common/log.js'; +import { URI } from '../../../../base/common/uri.js'; + +const hasWorktreeAndRepositoryContextKey = new RawContextKey('agentSessionHasWorktreeAndRepository', false, { + type: 'boolean', + description: localize('agentSessionHasWorktreeAndRepository', "True when the active agent session has both a worktree and a parent repository.") +}); + +const hasAheadCommitsContextKey = new RawContextKey('agentSessionHasAheadCommits', false, { + type: 'boolean', + description: localize('agentSessionHasAheadCommits', "True when the active agent session worktree has commits ahead of its upstream.") +}); + +class ApplyChangesToParentRepoContribution extends Disposable implements IWorkbenchContribution { + + static readonly ID = 'sessions.contrib.applyChangesToParentRepo'; + + private readonly _gitRepoDisposables = this._register(new MutableDisposable()); + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @ISessionsManagementService sessionManagementService: ISessionsManagementService, + @IGitService private readonly gitService: IGitService, + ) { + super(); + + const worktreeAndRepoKey = hasWorktreeAndRepositoryContextKey.bindTo(contextKeyService); + const aheadCommitsKey = hasAheadCommitsContextKey.bindTo(contextKeyService); + + this._register(autorun(reader => { + const activeSession = sessionManagementService.activeSession.read(reader); + const hasWorktreeAndRepo = !!activeSession?.worktree && !!activeSession?.repository; + worktreeAndRepoKey.set(hasWorktreeAndRepo); + + this._gitRepoDisposables.clear(); + + if (!hasWorktreeAndRepo || !activeSession?.worktree) { + aheadCommitsKey.set(false); + return; + } + + const repoDisposables = this._gitRepoDisposables.value = new DisposableStore(); + this.gitService.openRepository(activeSession.worktree).then(repository => { + if (repoDisposables.isDisposed || !repository) { + aheadCommitsKey.set(false); + return; + } + repoDisposables.add(autorun(innerReader => { + const state = repository.state.read(innerReader); + const ahead = state.HEAD?.ahead ?? 0; + aheadCommitsKey.set(ahead > 0); + })); + }); + })); + } +} + +class ApplyChangesToParentRepoAction extends Action2 { + static readonly ID = 'chatEditing.applyChangesToParentRepo'; + + constructor() { + super({ + id: ApplyChangesToParentRepoAction.ID, + title: localize2('applyChangesToParentRepo', 'Apply Changes to Parent Repo'), + icon: Codicon.desktopDownload, + category: CHAT_CATEGORY, + precondition: ContextKeyExpr.and( + IsSessionsWindowContext, + hasWorktreeAndRepositoryContextKey, + ), + menu: [ + { + id: MenuId.ChatEditingSessionApplySubmenu, + group: 'navigation', + order: 2, + when: ContextKeyExpr.and( + IsSessionsWindowContext, + hasWorktreeAndRepositoryContextKey, + ), + }, + ], + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const sessionManagementService = accessor.get(ISessionsManagementService); + const commandService = accessor.get(ICommandService); + const notificationService = accessor.get(INotificationService); + const logService = accessor.get(ILogService); + const openerService = accessor.get(IOpenerService); + const productService = accessor.get(IProductService); + + const activeSession = sessionManagementService.getActiveSession(); + if (!activeSession?.worktree || !activeSession?.repository) { + return; + } + + const worktreeRoot = activeSession.worktree; + const repoRoot = activeSession.repository; + + const openFolderAction = toAction({ + id: 'applyChangesToParentRepo.openFolder', + label: localize('openInVSCode', "Open in VS Code"), + run: () => { + const scheme = productService.quality === 'stable' + ? 'vscode' + : productService.quality === 'exploration' + ? 'vscode-exploration' + : 'vscode-insiders'; + + const params = new URLSearchParams(); + params.set('windowId', '_blank'); + params.set('session', activeSession.resource.toString()); + + openerService.open(URI.from({ + scheme, + authority: Schemas.file, + path: repoRoot.path, + query: params.toString(), + }), { openExternal: true }); + } + }); + + try { + // Get the worktree branch name. Since the worktree and parent repo + // share the same git object store, the parent can directly reference + // this branch for a merge. + const worktreeBranch = await commandService.executeCommand( + '_git.revParseAbbrevRef', + worktreeRoot.fsPath + ); + + if (!worktreeBranch) { + notificationService.notify({ + severity: Severity.Warning, + message: localize('applyChangesNoBranch', "Could not determine worktree branch name."), + }); + return; + } + + // Merge the worktree branch into the parent repo. + // This is idempotent: if already merged, git says "Already up to date." + // If new commits exist, they're brought in. Handles partial applies naturally. + const result = await commandService.executeCommand('_git.mergeBranch', repoRoot.fsPath, worktreeBranch); + if (!result) { + logService.warn('[ApplyChangesToParentRepo] No result from merge command'); + } else { + notificationService.notify({ + severity: Severity.Info, + message: typeof result === 'string' && result.startsWith('Already up to date') + ? localize('alreadyUpToDate', 'Parent repository is up to date with worktree.') + : localize('applyChangesSuccess', 'Applied changes to parent repository.'), + actions: { primary: [openFolderAction] } + }); + } + } catch (err) { + logService.error('[ApplyChangesToParentRepo] Failed to apply changes', err); + notificationService.notify({ + severity: Severity.Warning, + message: localize('applyChangesConflict', "Failed to apply changes to parent repo. The parent repo may have diverged — resolve conflicts manually."), + actions: { primary: [openFolderAction] } + }); + } + } +} + +registerAction2(ApplyChangesToParentRepoAction); +registerWorkbenchContribution2(ApplyChangesToParentRepoContribution.ID, ApplyChangesToParentRepoContribution, WorkbenchPhase.AfterRestored); + +// Register the apply submenu in the session changes toolbar +MenuRegistry.appendMenuItem(MenuId.ChatEditingSessionChangesToolbar, { + submenu: MenuId.ChatEditingSessionApplySubmenu, + title: localize2('applyActions', 'Apply Actions'), + group: 'navigation', + order: 1, + when: ContextKeyExpr.and(IsSessionsWindowContext, ChatContextKeys.hasAgentSessionChanges), +}); diff --git a/src/vs/sessions/contrib/applyToParentRepo/browser/applyToParentRepo.contribution.ts b/src/vs/sessions/contrib/applyToParentRepo/browser/applyToParentRepo.contribution.ts deleted file mode 100644 index 47a5b66183a..00000000000 --- a/src/vs/sessions/contrib/applyToParentRepo/browser/applyToParentRepo.contribution.ts +++ /dev/null @@ -1,216 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { toAction } from '../../../../base/common/actions.js'; -import { Disposable } from '../../../../base/common/lifecycle.js'; -import { Schemas } from '../../../../base/common/network.js'; -import { autorun } from '../../../../base/common/observable.js'; -import { Codicon } from '../../../../base/common/codicons.js'; -import { localize, localize2 } from '../../../../nls.js'; -import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; -import { ICommandService } from '../../../../platform/commands/common/commands.js'; -import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; -import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; -import { IFileService } from '../../../../platform/files/common/files.js'; -import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js'; -import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { IProductService } from '../../../../platform/product/common/productService.js'; -import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../../workbench/common/contributions.js'; -import { CHAT_CATEGORY } from '../../../../workbench/contrib/chat/browser/actions/chatActions.js'; -import { generateUnifiedDiff } from '../../../../workbench/contrib/chat/browser/chatRepoInfo.js'; -import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js'; -import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js'; -import { isIChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js'; -import { ISessionsManagementService } from '../../sessions/browser/sessionsManagementService.js'; -import { IsSessionsWindowContext } from '../../../../workbench/common/contextkeys.js'; -import { isEqualOrParent, relativePath } from '../../../../base/common/resources.js'; -import { ILogService } from '../../../../platform/log/common/log.js'; -import { URI } from '../../../../base/common/uri.js'; - -/** - * Normalizes a URI to the `file` scheme so that path comparisons work - * even when the source URI uses a different scheme (e.g. `github-remote-file`). - */ -function toFileUri(uri: URI): URI { - return uri.scheme === 'file' ? uri : URI.file(uri.path); -} - -const hasWorktreeAndRepositoryContextKey = new RawContextKey('agentSessionHasWorktreeAndRepository', false, { - type: 'boolean', - description: localize('agentSessionHasWorktreeAndRepository', "True when the active agent session has both a worktree and a parent repository.") -}); - -class ApplyToParentRepoContribution extends Disposable implements IWorkbenchContribution { - - static readonly ID = 'sessions.contrib.applyToParentRepo'; - - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ISessionsManagementService sessionManagementService: ISessionsManagementService, - ) { - super(); - - const contextKey = hasWorktreeAndRepositoryContextKey.bindTo(contextKeyService); - - this._register(autorun(reader => { - const activeSession = sessionManagementService.activeSession.read(reader); - const hasWorktreeAndRepo = !!activeSession?.worktree && !!activeSession?.repository; - contextKey.set(hasWorktreeAndRepo); - })); - } -} - -class ApplyToParentRepoAction extends Action2 { - static readonly ID = 'chatEditing.applyToParentRepo'; - - constructor() { - super({ - id: ApplyToParentRepoAction.ID, - title: localize2('applyToParentRepo', 'Apply to Parent Repo'), - icon: Codicon.desktopDownload, - category: CHAT_CATEGORY, - precondition: ContextKeyExpr.and(IsSessionsWindowContext, hasWorktreeAndRepositoryContextKey, ChatContextKeys.hasAgentSessionChanges), - menu: [ - { - id: MenuId.ChatEditingSessionChangesToolbar, - group: 'navigation', - order: 4, - when: ContextKeyExpr.and(IsSessionsWindowContext, hasWorktreeAndRepositoryContextKey, ChatContextKeys.hasAgentSessionChanges), - }, - ], - }); - } - - override async run(accessor: ServicesAccessor): Promise { - const sessionManagementService = accessor.get(ISessionsManagementService); - const agentSessionsService = accessor.get(IAgentSessionsService); - const fileService = accessor.get(IFileService); - const notificationService = accessor.get(INotificationService); - const logService = accessor.get(ILogService); - const openerService = accessor.get(IOpenerService); - const productService = accessor.get(IProductService); - const commandService = accessor.get(ICommandService); - - const activeSession = sessionManagementService.getActiveSession(); - if (!activeSession?.worktree || !activeSession?.repository) { - return; - } - - const worktreeRoot = activeSession.worktree; - const repoRoot = activeSession.repository; - - const agentSession = agentSessionsService.getSession(activeSession.resource); - const changes = agentSession?.changes; - if (!changes || !(changes instanceof Array)) { - return; - } - - // Generate a combined unified diff patch from all changes - const patchParts: string[] = []; - let fileCount = 0; - - for (const change of changes) { - try { - const modifiedUri = isIChatSessionFileChange2(change) - ? change.modifiedUri ?? change.uri - : change.modifiedUri; - const isDeletion = isIChatSessionFileChange2(change) - ? change.modifiedUri === undefined - : false; - - const originalUri = change.originalUri; - let relPath: string | undefined; - - if (isDeletion) { - if (originalUri && isEqualOrParent(toFileUri(originalUri), worktreeRoot)) { - relPath = relativePath(worktreeRoot, toFileUri(originalUri)); - } - } else { - if (isEqualOrParent(toFileUri(modifiedUri), worktreeRoot)) { - relPath = relativePath(worktreeRoot, toFileUri(modifiedUri)); - } - } - - if (!relPath) { - continue; - } - - const changeType: 'added' | 'modified' | 'deleted' = isDeletion - ? 'deleted' - : originalUri ? 'modified' : 'added'; - - const diff = await generateUnifiedDiff( - fileService, - relPath, - originalUri, - modifiedUri, - changeType - ); - - if (diff) { - patchParts.push(diff); - fileCount++; - } - } catch (err) { - logService.error('[ApplyToParentRepo] Failed to generate diff for change', err); - } - } - - if (patchParts.length === 0) { - notificationService.notify({ - severity: Severity.Info, - message: localize('applyToParentRepoNoDiffs', "No applicable changes to apply to parent repo."), - }); - return; - } - - const combinedPatch = patchParts.join('\n') + '\n'; - - const openFolderAction = toAction({ - id: 'applyToParentRepo.openFolder', - label: localize('openInVSCode', "Open in VS Code"), - run: () => { - const scheme = productService.quality === 'stable' - ? 'vscode' - : productService.quality === 'exploration' - ? 'vscode-exploration' - : 'vscode-insiders'; - - const params = new URLSearchParams(); - params.set('windowId', '_blank'); - params.set('session', activeSession.resource.toString()); - - openerService.open(URI.from({ - scheme, - authority: Schemas.file, - path: repoRoot.path, - query: params.toString(), - }), { openExternal: true }); - } - }); - - try { - await commandService.executeCommand('_git.applyPatch', repoRoot.fsPath, combinedPatch); - - notificationService.notify({ - severity: Severity.Info, - message: fileCount === 1 - ? localize('applyToParentRepoSuccess1', "Applied 1 file to parent repo.") - : localize('applyToParentRepoSuccessN', "Applied {0} files to parent repo.", fileCount), - actions: { primary: [openFolderAction] } - }); - } catch (err) { - logService.error('[ApplyToParentRepo] git apply failed', err); - notificationService.notify({ - severity: Severity.Warning, - message: localize('applyToParentRepoConflict', "Failed to apply patch to parent repo. The parent repo may have diverged — resolve conflicts manually."), - actions: { primary: [openFolderAction] } - }); - } - } -} - -registerAction2(ApplyToParentRepoAction); -registerWorkbenchContribution2(ApplyToParentRepoContribution.ID, ApplyToParentRepoContribution, WorkbenchPhase.AfterRestored); diff --git a/src/vs/sessions/contrib/changesView/browser/changesView.ts b/src/vs/sessions/contrib/changesView/browser/changesView.ts index 47eca5b0933..94cef1215c4 100644 --- a/src/vs/sessions/contrib/changesView/browser/changesView.ts +++ b/src/vs/sessions/contrib/changesView/browser/changesView.ts @@ -576,10 +576,7 @@ export class ChangesViewPane extends ViewPane { return { showIcon: true, showLabel: true, isSecondary: true, customClass: 'working-set-diff-stats', customLabel: diffStatsLabel }; } if (action.id === 'github.createPullRequest' || action.id === 'github.openPullRequest') { - return { showIcon: true, showLabel: true, isSecondary: true, customClass: 'flex-grow' }; - } - if (action.id === 'chatEditing.applyToParentRepo') { - return { showIcon: true, showLabel: false, isSecondary: true }; + return { showIcon: true, showLabel: true, isSecondary: true }; } if (action.id === 'chatEditing.synchronizeChanges') { return { showIcon: true, showLabel: true, isSecondary: true }; diff --git a/src/vs/sessions/contrib/changesView/browser/media/changesView.css b/src/vs/sessions/contrib/changesView/browser/media/changesView.css index 1300b886cbc..05c1f461efc 100644 --- a/src/vs/sessions/contrib/changesView/browser/media/changesView.css +++ b/src/vs/sessions/contrib/changesView/browser/media/changesView.css @@ -114,6 +114,29 @@ flex: 1; } +/* ButtonWithDropdown container grows to fill available space */ +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown { + flex: 1; + display: flex; +} + +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button { + flex: 1; + box-sizing: border-box; +} + +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button-dropdown-separator { + flex: 0; +} + +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button.monaco-dropdown-button { + flex: 0 0 auto; + padding: 4px; + width: auto; + min-width: 0; + border-radius: 0px 4px 4px 0px; +} + .changes-view-body .chat-editing-session-actions.outside-card .monaco-button.secondary.monaco-text-button.codicon { padding: 4px 8px; font-size: 16px !important; @@ -134,6 +157,7 @@ .changes-view-body .chat-editing-session-actions .monaco-button.secondary.monaco-text-button { background-color: var(--vscode-button-secondaryBackground); color: var(--vscode-button-secondaryForeground); + border-radius: 4px 0px 0px 4px; } .changes-view-body .chat-editing-session-actions .monaco-button.secondary:hover { diff --git a/src/vs/sessions/sessions.desktop.main.ts b/src/vs/sessions/sessions.desktop.main.ts index 406ea03e508..99ac51a5695 100644 --- a/src/vs/sessions/sessions.desktop.main.ts +++ b/src/vs/sessions/sessions.desktop.main.ts @@ -208,7 +208,7 @@ import './contrib/sessions/browser/customizationsToolbar.contribution.js'; import './contrib/changesView/browser/changesView.contribution.js'; import './contrib/files/browser/files.contribution.js'; import './contrib/gitSync/browser/gitSync.contribution.js'; -import './contrib/applyToParentRepo/browser/applyToParentRepo.contribution.js'; +import './contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.js'; import './contrib/fileTreeView/browser/fileTreeView.contribution.js'; // view registration disabled; filesystem provider still needed import './contrib/configuration/browser/configuration.contribution.js'; diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index 7f5c8e64d14..3fb7f02494e 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -479,6 +479,12 @@ const apiMenus: IAPIMenu[] = [ description: localize('menus.chatEditingSessionChangesToolbar', "The Chat Editing widget toolbar menu for session changes."), proposed: 'chatSessionsProvider' }, + { + key: 'chat/input/editing/sessionApplyActions', + id: MenuId.ChatEditingSessionApplySubmenu, + description: localize('menus.chatEditingSessionApplySubmenu', "Submenu for apply actions in the Chat Editing session changes toolbar."), + proposed: 'chatSessionsProvider' + }, { // TODO: rename this to something like: `chatSessions/item/inline` key: 'chat/chatSessions',