Skip to content

Commit e62f99d

Browse files
committed
Merge branch 'main' into sandy081/basic-stoat
2 parents f49afb6 + a437b74 commit e62f99d

File tree

3 files changed

+123
-21
lines changed

3 files changed

+123
-21
lines changed

build/darwin/dmg-settings.py.template

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ format = 'ULMO'
66
badge_icon = {{BADGE_ICON}}
77
background = {{BACKGROUND}}
88

9-
# Volume size (None = auto-calculate)
10-
size = None
9+
# Volume size
10+
size = '1g'
11+
shrink = False
1112

1213
# Files and symlinks
1314
files = [{{APP_PATH}}]

src/vs/sessions/contrib/chat/browser/runScriptAction.ts

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55

66
import { equals } from '../../../../base/common/arrays.js';
77
import { Codicon } from '../../../../base/common/codicons.js';
8+
import { KeyCode } from '../../../../base/common/keyCodes.js';
89
import { Disposable } from '../../../../base/common/lifecycle.js';
910
import { autorun, derivedOpts, IObservable } from '../../../../base/common/observable.js';
1011
import { localize, localize2 } from '../../../../nls.js';
1112
import { MenuId, registerAction2, Action2, MenuRegistry } from '../../../../platform/actions/common/actions.js';
1213
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
14+
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
15+
import { KeybindingsRegistry, KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
1316
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from '../../../../platform/quickinput/common/quickInput.js';
1417
import { IWorkbenchContribution } from '../../../../workbench/common/contributions.js';
1518
import { SessionsCategories } from '../../../common/categories.js';
@@ -26,6 +29,7 @@ export const RunScriptDropdownMenuId = MenuId.for('AgentSessionsRunScriptDropdow
2629

2730
// Action IDs
2831
const RUN_SCRIPT_ACTION_ID = 'workbench.action.agentSessions.runScript';
32+
const RUN_SCRIPT_ACTION_PRIMARY_ID = 'workbench.action.agentSessions.runScriptPrimary';
2933
const CONFIGURE_DEFAULT_RUN_ACTION_ID = 'workbench.action.agentSessions.configureDefaultRunAction';
3034

3135
function getTaskDisplayLabel(task: ITaskEntry): string {
@@ -62,6 +66,7 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
6266

6367
constructor(
6468
@ISessionsManagementService private readonly _activeSessionService: ISessionsManagementService,
69+
@IKeybindingService private readonly _keybindingService: IKeybindingService,
6570
@IQuickInputService private readonly _quickInputService: IQuickInputService,
6671
@ISessionsConfigurationService private readonly _sessionsConfigService: ISessionsConfigurationService,
6772
) {
@@ -94,6 +99,40 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
9499
private _registerActions(): void {
95100
const that = this;
96101

102+
this._register(registerAction2(class extends Action2 {
103+
constructor() {
104+
super({
105+
id: RUN_SCRIPT_ACTION_PRIMARY_ID,
106+
title: { value: localize('runPrimaryScript', 'Run Primary Script'), original: 'Run Primary Script' },
107+
icon: Codicon.play,
108+
category: SessionsCategories.Sessions,
109+
f1: true,
110+
});
111+
}
112+
113+
async run(): Promise<void> {
114+
const activeState = that._activeRunState.get();
115+
if (!activeState) {
116+
return;
117+
}
118+
119+
const { tasks, session, lastRunTaskLabel } = activeState;
120+
if (tasks.length === 0) {
121+
const task = await that._showConfigureQuickPick(session);
122+
if (task) {
123+
await that._sessionsConfigService.runTask(task, session);
124+
}
125+
return;
126+
}
127+
128+
const mruIndex = lastRunTaskLabel !== undefined
129+
? tasks.findIndex(t => t.label === lastRunTaskLabel)
130+
: -1;
131+
const primaryTask = tasks[mruIndex >= 0 ? mruIndex : 0];
132+
await that._sessionsConfigService.runTask(primaryTask, session);
133+
}
134+
}));
135+
97136
this._register(autorun(reader => {
98137
const activeState = this._activeRunState.read(reader);
99138
if (!activeState) {
@@ -112,13 +151,15 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
112151
for (let i = 0; i < tasks.length; i++) {
113152
const task = tasks[i];
114153
const actionId = `${RUN_SCRIPT_ACTION_ID}.${i}`;
154+
const isPrimary = i === (mruIndex >= 0 ? mruIndex : 0);
115155

116156
reader.store.add(registerAction2(class extends Action2 {
117157
constructor() {
118158
super({
119159
id: actionId,
120160
title: getTaskDisplayLabel(task),
121-
tooltip: localize('runActionTooltip', "Run '{0}' in terminal", getTaskDisplayLabel(task)),
161+
tooltip: !isPrimary ? localize('runActionTooltip', "Run '{0}' in terminal", getTaskDisplayLabel(task))
162+
: localize('runActionTooltipKeybinding', "Run '{0}' in terminal ({1})", getTaskDisplayLabel(task), that._keybindingService.lookupKeybinding(RUN_SCRIPT_ACTION_PRIMARY_ID)?.getLabel() ?? ''),
122163
icon: Codicon.play,
123164
category: SessionsCategories.Sessions,
124165
menu: [{
@@ -154,18 +195,20 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
154195
}
155196

156197
async run(): Promise<void> {
157-
await that._showConfigureQuickPick(session);
198+
const task = await that._showConfigureQuickPick(session);
199+
if (task) {
200+
await that._sessionsConfigService.runTask(task, session);
201+
}
158202
}
159203
}));
160204
}));
161205
}
162206

163-
private async _showConfigureQuickPick(session: IActiveSessionItem): Promise<void> {
207+
private async _showConfigureQuickPick(session: IActiveSessionItem): Promise<ITaskEntry | undefined> {
164208
const nonSessionTasks = await this._sessionsConfigService.getNonSessionTasks(session);
165209
if (nonSessionTasks.length === 0) {
166210
// No existing tasks, go straight to custom command input
167-
await this._showCustomCommandInput(session);
168-
return;
211+
return this._showCustomCommandInput(session);
169212
}
170213

171214
interface ITaskPickItem extends IQuickPickItem {
@@ -198,38 +241,36 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr
198241
});
199242

200243
if (!picked) {
201-
return;
244+
return undefined;
202245
}
203246

204247
const pickedItem = picked as ITaskPickItem;
205248
if (pickedItem.task) {
206249
// Existing task — set inSessions: true
207250
await this._sessionsConfigService.addTaskToSessions(pickedItem.task, session, pickedItem.source ?? 'workspace');
251+
return pickedItem.task;
208252
} else {
209253
// Custom command path
210-
await this._showCustomCommandInput(session);
254+
return this._showCustomCommandInput(session);
211255
}
212256
}
213257

214-
private async _showCustomCommandInput(session: IActiveSessionItem): Promise<void> {
258+
private async _showCustomCommandInput(session: IActiveSessionItem): Promise<ITaskEntry | undefined> {
215259
const command = await this._quickInputService.input({
216260
placeHolder: localize('enterCommandPlaceholder', "Enter command (e.g., npm run dev)"),
217261
prompt: localize('enterCommandPrompt', "This command will be run as a task in the integrated terminal")
218262
});
219263

220264
if (!command) {
221-
return;
265+
return undefined;
222266
}
223267

224268
const target = await this._pickStorageTarget(session);
225269
if (!target) {
226-
return;
270+
return undefined;
227271
}
228272

229-
const newTask = await this._sessionsConfigService.createAndAddTask(command, session, target);
230-
if (newTask) {
231-
await this._sessionsConfigService.runTask(newTask, session);
232-
}
273+
return this._sessionsConfigService.createAndAddTask(command, session, target);
233274
}
234275

235276
private async _pickStorageTarget(session: IActiveSessionItem): Promise<TaskStorageTarget | undefined> {
@@ -317,3 +358,13 @@ class RunScriptNotAvailableAction extends Action2 {
317358
}
318359

319360
registerAction2(RunScriptNotAvailableAction);
361+
362+
// Register F5 keybinding at module level to ensure it's in the registry
363+
// before the keybinding resolver is cached. The command handler is
364+
// registered later by RunScriptContribution.
365+
KeybindingsRegistry.registerKeybindingRule({
366+
id: RUN_SCRIPT_ACTION_PRIMARY_ID,
367+
primary: KeyCode.F5,
368+
weight: KeybindingWeight.WorkbenchContrib + 100,
369+
when: IsAuxiliaryWindowContext.toNegated()
370+
});

src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import './media/sessionsTitleBarWidget.css';
7-
import { $, addDisposableListener, EventType, reset } from '../../../../base/browser/dom.js';
7+
import { $, addDisposableListener, EventType, getActiveWindow, reset } from '../../../../base/browser/dom.js';
88

9+
import { Separator } from '../../../../base/common/actions.js';
910
import { Disposable, DisposableStore, MutableDisposable } from '../../../../base/common/lifecycle.js';
11+
import { MarshalledId } from '../../../../base/common/marshallingIds.js';
12+
import { StandardMouseEvent } from '../../../../base/browser/mouseEvent.js';
1013
import { localize } from '../../../../nls.js';
1114
import { IHoverService } from '../../../../platform/hover/browser/hover.js';
1215
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
1316
import { BaseActionViewItem, IBaseActionViewItemOptions } from '../../../../base/browser/ui/actionbar/actionViewItems.js';
1417
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
15-
import { MenuRegistry, SubmenuItemAction } from '../../../../platform/actions/common/actions.js';
16-
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
17-
18+
import { IMenuService, MenuId, MenuRegistry, SubmenuItemAction } from '../../../../platform/actions/common/actions.js';
19+
import { IContextKeyService, ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
20+
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
21+
import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js';
22+
import { IMarshalledAgentSessionContext, getAgentChangesSummary, hasValidDiff } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsModel.js';
23+
import { IChatSessionsService } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
1824
import { Menus } from '../../../browser/menus.js';
1925
import { IWorkbenchContribution } from '../../../../workbench/common/contributions.js';
2026
import { IActionViewItemService } from '../../../../platform/actions/browser/actionViewItemService.js';
@@ -27,7 +33,6 @@ import { autorun } from '../../../../base/common/observable.js';
2733
import { IChatService } from '../../../../workbench/contrib/chat/common/chatService/chatService.js';
2834
import { ThemeIcon } from '../../../../base/common/themables.js';
2935
import { getAgentSessionProvider, getAgentSessionProviderIcon } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessions.js';
30-
import { getAgentChangesSummary, hasValidDiff } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsModel.js';
3136
import { basename } from '../../../../base/common/resources.js';
3237
import { IsAuxiliaryWindowContext } from '../../../../workbench/common/contextkeys.js';
3338
import { SessionsWelcomeVisibleContext } from '../../../common/contextkeys.js';
@@ -66,6 +71,10 @@ export class SessionsTitleBarWidget extends BaseActionViewItem {
6671
@ISessionsManagementService private readonly activeSessionService: ISessionsManagementService,
6772
@IChatService private readonly chatService: IChatService,
6873
@IAgentSessionsService private readonly agentSessionsService: IAgentSessionsService,
74+
@IContextMenuService private readonly contextMenuService: IContextMenuService,
75+
@IMenuService private readonly menuService: IMenuService,
76+
@IContextKeyService private readonly contextKeyService: IContextKeyService,
77+
@IChatSessionsService private readonly chatSessionsService: IChatSessionsService,
6978
) {
7079
super(undefined, action, options);
7180

@@ -197,6 +206,11 @@ export class SessionsTitleBarWidget extends BaseActionViewItem {
197206
e.stopPropagation();
198207
this._showSessionsPicker();
199208
}));
209+
this._dynamicDisposables.add(addDisposableListener(sessionPill, EventType.CONTEXT_MENU, (e) => {
210+
e.preventDefault();
211+
e.stopPropagation();
212+
this._showContextMenu(e);
213+
}));
200214

201215
this._container.appendChild(sessionPill);
202216

@@ -305,6 +319,42 @@ export class SessionsTitleBarWidget extends BaseActionViewItem {
305319
return basename(uri);
306320
}
307321

322+
private _showContextMenu(e: MouseEvent): void {
323+
const activeSession = this.activeSessionService.getActiveSession();
324+
if (!activeSession) {
325+
return;
326+
}
327+
328+
const agentSession = this.agentSessionsService.getSession(activeSession.resource);
329+
if (!agentSession) {
330+
return;
331+
}
332+
333+
this.chatSessionsService.activateChatSessionItemProvider(agentSession.providerType);
334+
335+
const contextOverlay: Array<[string, boolean | string]> = [
336+
[ChatContextKeys.isArchivedAgentSession.key, agentSession.isArchived()],
337+
[ChatContextKeys.isReadAgentSession.key, agentSession.isRead()],
338+
[ChatContextKeys.agentSessionType.key, agentSession.providerType],
339+
];
340+
341+
const menu = this.menuService.createMenu(MenuId.AgentSessionsContext, this.contextKeyService.createOverlay(contextOverlay));
342+
343+
const marshalledContext: IMarshalledAgentSessionContext = {
344+
session: agentSession,
345+
sessions: [agentSession],
346+
$mid: MarshalledId.AgentSessionContext,
347+
};
348+
349+
this.contextMenuService.showContextMenu({
350+
getActions: () => Separator.join(...menu.getActions({ arg: marshalledContext, shouldForwardArgs: true }).map(([, actions]) => actions)),
351+
getAnchor: () => new StandardMouseEvent(getActiveWindow(), e),
352+
getActionsContext: () => marshalledContext
353+
});
354+
355+
menu.dispose();
356+
}
357+
308358
/**
309359
* Get the changes summary for the active session.
310360
*/

0 commit comments

Comments
 (0)