Skip to content

Commit f2ccb57

Browse files
sandy081CopilotmrleemurrayCopilot
authored
Agents welcome: preview/import API for VS Code theme importer (#313454)
* agents welcome: add theme selection step after sign-in After signing in (or for first-launch signed-in users after clicking Get Started), show a theme selection step with 4 theme preview cards (Dark 2026, Dark HC, Light 2026, Light HC). Theme is applied live on card click. Continue button dismisses the overlay. External sign-in via onDidChangeDefaultAccount now transitions to the theme step instead of auto-completing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agents welcome: theme importer restructure and environment improvements - Rename vsCodeThemeImporter folder to vscode, merge interface and service - Rename hostExtensionsPath to hostExtensionsHome returning URI - Move host environment paths to common environmentService Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agents welcome: address PR review feedback - Compare both id and label in theme extension matching - Move VS Code theme radio inside the radiogroup for accessibility - Add touch/tap support (Gesture.addTarget + TouchEventType.Tap) - Add touch-action: manipulation to theme cards and VS Code theme radio - Fix JSDoc for hostUserHome and importVSCodeTheme Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agents welcome: preview/import API for VS Code theme importer - Add previewVSCodeTheme() that installs from host location temporarily and returns IDisposable to uninstall on dispose - importVSCodeTheme() now: installs from host (preview), copies extension to agents app extensions dir, then replaces install from copied location - Walkthrough uses preview on select, import on Continue, dispose on Escape - Address PR feedback: touch support, accessibility, theme matching Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR feedback: fix preview flow and use INativeEnvironmentService - Apply theme in preview even when no extension install is needed - Return no-op disposable when theme is already available - Use @INativeEnvironmentService decorator matching the type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * restore reverted PR changes and polish theme picker - Restore hostUserHome, hostExtensionsHome in common environmentService - Restore showThemeStep() calls in welcome.contribution - Restore vsCodeThemeImporter import in sessions.common.main - Fix preview flow: apply theme even when no install needed - Use @INativeEnvironmentService decorator - Increase theme picker card width to 1000px - Scale up theme preview thumbnails with min-height - Add spacing between tiles and VS Code Theme button Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix compilation error * fix compilation * fix compilations * enhance transition effects in sessions walkthrough overlay * update button styling in sessions walkthrough to include border Co-authored-by: Copilot <copilot@github.com> * refine padding and border styles in sessions walkthrough theme card Co-authored-by: Copilot <copilot@github.com> * feat: update theme previews and paths for sessions walkthrough - Updated the image source paths for theme previews in sessionsWalkthroughOverlay. - Added new SVG files for dark, high contrast dark, high contrast light, and light themes for 2026. * refine theme card dimensions and improve responsive styles in sessions walkthrough Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: mrleemurray <mrleemurray@users.noreply.github.com> Co-authored-by: Copilot <copilot@github.com>
1 parent d94ab67 commit f2ccb57

19 files changed

Lines changed: 1071 additions & 75 deletions

File tree

src/vs/platform/environment/common/environment.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,26 @@ export interface IEnvironmentService {
9494
agentSessionsWorkspace?: URI;
9595

9696
/**
97-
* When running as the embedded Agents app, the user roaming data home of
97+
* When running as the embedded app, the user roaming data home of
9898
* the host VS Code application (i.e. the default profile's settings/User
9999
* directory). `undefined` when not running as embedded.
100100
*/
101-
readonly hostUserRoamingDataHome?: URI;
101+
readonly parentAppUserRoamingDataHome?: URI;
102+
103+
/**
104+
* When running as the embedded app, the data home of the host
105+
* VS Code application (e.g. `~/.vscode-insiders`). This identifies the
106+
* host application's home/data directory and is used alongside other
107+
* host-specific paths such as `hostUserRoamingDataHome` and
108+
* `hostExtensionsHome`. `undefined` when not running as embedded.
109+
*/
110+
readonly parentAppUserHome?: URI;
111+
112+
/**
113+
* When running as the embedded app, the extensions directory of
114+
* the host VS Code application. `undefined` when not running as embedded.
115+
*/
116+
readonly parentAppExtensionsHome?: URI;
102117

103118
// --- Policy
104119
policyFile?: URI;

src/vs/platform/environment/common/environmentService.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ export interface INativeEnvironmentPaths {
3737
* OS tmp dir.
3838
*/
3939
tmpDir: string;
40+
41+
/**
42+
* The parent application user data directory, if the current instance is running as an embedded application.
43+
* This can be used to access data from the parent application that is not shared with the embedded application.
44+
* This is only set when running as an embedded application and is `undefined` otherwise.
45+
*/
46+
parentAppUserDataDir: string | undefined;
47+
48+
/**
49+
* The parent application home directory, if the current instance is running as an embedded application.
50+
* This can be used to access data from the parent application that is not shared with the embedded application.
51+
* This is only set when running as an embedded application and is `undefined` otherwise.
52+
*/
53+
parentAppUserHomeDir: string | undefined;
4054
}
4155

4256
export abstract class AbstractNativeEnvironmentService implements INativeEnvironmentService {
@@ -299,6 +313,24 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
299313
this.args['continueOn'] = value;
300314
}
301315

316+
@memoize
317+
get parentAppUserRoamingDataHome(): URI | undefined {
318+
return this.paths.parentAppUserDataDir ? URI.file(this.paths.parentAppUserDataDir).with({ scheme: Schemas.vscodeUserData }) : undefined;
319+
}
320+
321+
@memoize
322+
get parentAppUserHome(): URI | undefined {
323+
return this.paths.parentAppUserHomeDir ? URI.file(this.paths.parentAppUserHomeDir) : undefined;
324+
}
325+
326+
@memoize
327+
get parentAppExtensionsHome(): URI | undefined {
328+
if (!this.parentAppUserHome) {
329+
return undefined;
330+
}
331+
return joinPath(this.parentAppUserHome, 'extensions');
332+
}
333+
302334
get args(): NativeParsedArgs { return this._args; }
303335

304336
constructor(

src/vs/platform/environment/node/environmentService.ts

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,27 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { homedir, tmpdir } from 'os';
7-
import { memoize } from '../../../base/common/decorators.js';
8-
import { INodeProcess } from '../../../base/common/platform.js';
9-
import { joinPath } from '../../../base/common/resources.js';
10-
import { URI } from '../../../base/common/uri.js';
11-
import { Schemas } from '../../../base/common/network.js';
127
import { NativeParsedArgs } from '../common/argv.js';
138
import { IDebugParams } from '../common/environment.js';
149
import { AbstractNativeEnvironmentService, parseDebugParams } from '../common/environmentService.js';
1510
import { getUserDataPath } from './userDataPath.js';
1611
import { IProductService } from '../../product/common/productService.js';
12+
import { INodeProcess } from '../../../base/common/platform.js';
13+
import { join } from '../../../base/common/path.js';
14+
import { env } from '../../../base/common/process.js';
1715

1816
export class NativeEnvironmentService extends AbstractNativeEnvironmentService {
1917

2018
constructor(args: NativeParsedArgs, productService: IProductService) {
19+
const homeDir = homedir();
2120
super(args, {
22-
homeDir: homedir(),
21+
homeDir,
2322
tmpDir: tmpdir(),
24-
userDataDir: getUserDataPath(args, productService.nameShort)
23+
userDataDir: getUserDataPath(args, productService.nameShort),
24+
parentAppUserDataDir: getParentAppUserDataDir(args, productService),
25+
parentAppUserHomeDir: getParentAppUserHomeDir(homeDir, productService)
2526
}, productService);
2627
}
27-
28-
@memoize
29-
get hostUserRoamingDataHome(): URI | undefined {
30-
if (!(process as INodeProcess).isEmbeddedApp) {
31-
return undefined;
32-
}
33-
if (!this.isBuilt) {
34-
return undefined;
35-
}
36-
const quality = this.productService.quality;
37-
let hostProductName: string;
38-
if (quality === 'stable') {
39-
hostProductName = 'Code';
40-
} else if (quality === 'insider') {
41-
hostProductName = 'Code - Insiders';
42-
} else if (quality === 'exploration') {
43-
hostProductName = 'Code - Exploration';
44-
} else {
45-
return undefined;
46-
}
47-
48-
// Honor the same env-var overrides that the host VS Code itself uses
49-
// (portable mode and VSCODE_APPDATA), but intentionally skip --user-data-dir
50-
// because that CLI arg belongs to the Agents app, not the host.
51-
const hostUserDataPath = getUserDataPath(this.args, hostProductName);
52-
return joinPath(URI.file(hostUserDataPath), 'User').with({ scheme: Schemas.vscodeUserData });
53-
}
5428
}
5529

5630
export function parsePtyHostDebugPort(args: NativeParsedArgs, isBuilt: boolean): IDebugParams {
@@ -64,3 +38,51 @@ export function parseAgentHostDebugPort(args: NativeParsedArgs, isBuilt: boolean
6438
export function parseSharedProcessDebugPort(args: NativeParsedArgs, isBuilt: boolean): IDebugParams {
6539
return parseDebugParams(args['inspect-sharedprocess'], args['inspect-brk-sharedprocess'], 5879, isBuilt, args.extensionEnvironment);
6640
}
41+
42+
43+
function getParentAppUserDataDir(args: NativeParsedArgs, productService: IProductService): string | undefined {
44+
if (!(process as INodeProcess).isEmbeddedApp) {
45+
return undefined;
46+
}
47+
if (env['VSCODE_DEV']) {
48+
return undefined;
49+
}
50+
const quality = productService.quality;
51+
let hostProductName: string;
52+
if (quality === 'stable') {
53+
hostProductName = 'Code';
54+
} else if (quality === 'insider') {
55+
hostProductName = 'Code - Insiders';
56+
} else if (quality === 'exploration') {
57+
hostProductName = 'Code - Exploration';
58+
} else {
59+
return undefined;
60+
}
61+
62+
// Honor the same env-var overrides that the host VS Code itself uses
63+
// (portable mode and VSCODE_APPDATA), but intentionally skip --user-data-dir
64+
// because that CLI arg belongs to the Agents app, not the host.
65+
const hostUserDataPath = getUserDataPath(args, hostProductName);
66+
return join(hostUserDataPath, 'User');
67+
}
68+
69+
function getParentAppUserHomeDir(homeDir: string, productService: IProductService): string | undefined {
70+
if (!(process as INodeProcess).isEmbeddedApp) {
71+
return undefined;
72+
}
73+
if (env['VSCODE_DEV']) {
74+
return undefined;
75+
}
76+
const quality = productService.quality;
77+
let hostDataFolderName: string;
78+
if (quality === 'stable') {
79+
hostDataFolderName = '.vscode';
80+
} else if (quality === 'insider') {
81+
hostDataFolderName = '.vscode-insiders';
82+
} else if (quality === 'exploration') {
83+
hostDataFolderName = '.vscode-exploration';
84+
} else {
85+
return undefined;
86+
}
87+
return join(homeDir, hostDataFolderName);
88+
}

src/vs/platform/storage/electron-main/storageMainService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
208208
// from APPLICATION to APPLICATION_SHARED scope:
209209
// In VS Code: reuse the own application storage (keys are local)
210210
let fallbackStorage: IStorageMain = this.applicationStorage;
211-
const hostUserRoamingDataHome = this.environmentService.hostUserRoamingDataHome;
211+
const hostUserRoamingDataHome = this.environmentService.parentAppUserRoamingDataHome;
212212
if (hostUserRoamingDataHome) {
213213
// - In the Agents App: create a storage backed by the host (VS Code)
214214
// app's application DB so keys are found even if VS Code hasn't

src/vs/platform/userDataProfile/electron-main/userDataProfile.ts

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
4040
@INativeEnvironmentService environmentService: INativeEnvironmentService,
4141
@IFileService fileService: IFileService,
4242
@ILogService logService: ILogService,
43-
@IProductService private readonly productService: IProductService,
43+
@IProductService productService: IProductService,
4444
) {
4545
super(stateService, uriIdentityService, environmentService, fileService, logService);
46-
this.agentPluginsHome = URI.file(getAgentPluginsPath(environmentService.args, environmentService.userHome, productService.dataFolderName));
46+
this.agentPluginsHome = URI.file(getAgentPluginsPath(environmentService.args, joinPath(environmentService.userHome, productService.dataFolderName)));
4747
}
4848

4949
protected override createDefaultProfile(): IUserDataProfile {
@@ -54,11 +54,11 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
5454
if (!(process as INodeProcess).isEmbeddedApp) {
5555
return defaultProfile;
5656
}
57-
const hostUserRoamingDataHome = this.environmentService.hostUserRoamingDataHome;
57+
const hostUserRoamingDataHome = this.environmentService.parentAppUserRoamingDataHome;
5858
if (!hostUserRoamingDataHome) {
5959
return defaultProfile;
6060
}
61-
const hostAgentPluginsHome = getHostAgentPluginsPath(this.nativeEnvironmentService, this.productService);
61+
const hostAgentPluginsHome = getParentAppAgentPluginsPath(this.nativeEnvironmentService);
6262
return {
6363
...defaultProfile,
6464
keybindingsResource: joinPath(hostUserRoamingDataHome, 'keybindings.json'),
@@ -77,30 +77,15 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
7777
}
7878
}
7979

80-
function getHostAgentPluginsPath(environmentService: INativeEnvironmentService, productService: IProductService): string | undefined {
81-
if (!(process as INodeProcess).isEmbeddedApp) {
80+
function getParentAppAgentPluginsPath(environmentService: INativeEnvironmentService): string | undefined {
81+
const hostUserHome = environmentService.parentAppUserHome;
82+
if (!hostUserHome) {
8283
return undefined;
8384
}
84-
if (!environmentService.isBuilt) {
85-
return undefined;
86-
}
87-
88-
const quality = productService.quality;
89-
let hostDataFolderName: string;
90-
if (quality === 'stable') {
91-
hostDataFolderName = '.vscode';
92-
} else if (quality === 'insider') {
93-
hostDataFolderName = '.vscode-insiders';
94-
} else if (quality === 'exploration') {
95-
hostDataFolderName = '.vscode-exploration';
96-
} else {
97-
return undefined;
98-
}
99-
100-
return getAgentPluginsPath(environmentService.args, environmentService.userHome, hostDataFolderName);
85+
return getAgentPluginsPath(environmentService.args, hostUserHome);
10186
}
10287

103-
function getAgentPluginsPath(args: NativeParsedArgs, userHome: URI, dataFolderName: string): string {
88+
function getAgentPluginsPath(args: NativeParsedArgs, userHome: URI): string {
10489
const cliAgentPluginsDir = args['agent-plugins-dir'];
10590
if (cliAgentPluginsDir) {
10691
return resolve(cliAgentPluginsDir);
@@ -116,5 +101,5 @@ function getAgentPluginsPath(args: NativeParsedArgs, userHome: URI, dataFolderNa
116101
return join(vscodePortable, 'agent-plugins');
117102
}
118103

119-
return joinPath(userHome, dataFolderName, 'agent-plugins').fsPath;
104+
return joinPath(userHome, 'agent-plugins').fsPath;
120105
}

src/vs/platform/window/common/window.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native
442442
homeDir: string;
443443
tmpDir: string;
444444
userDataDir: string;
445+
parentAppUserDataDir?: string;
446+
parentAppUserHomeDir?: string;
445447

446448
partsSplash?: IPartsSplash;
447449

src/vs/platform/windows/electron-main/windowsMainService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
15711571
homeDir: this.environmentMainService.userHome.with({ scheme: Schemas.file }).fsPath,
15721572
tmpDir: this.environmentMainService.tmpDir.with({ scheme: Schemas.file }).fsPath,
15731573
userDataDir: this.environmentMainService.userDataPath,
1574+
parentAppUserDataDir: this.environmentMainService.parentAppUserRoamingDataHome?.with({ scheme: Schemas.file }).fsPath,
1575+
parentAppUserHomeDir: this.environmentMainService.parentAppUserHome?.with({ scheme: Schemas.file }).fsPath,
15741576

15751577
remoteAuthority: options.remoteAuthority,
15761578
workspace: options.workspace,

0 commit comments

Comments
 (0)