Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/vs/platform/environment/common/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ export interface IEnvironmentService {
// --- agent sessions workspace
agentSessionsWorkspace?: URI;

/**
* When running as the embedded Agents app, the user roaming data home of
* the host VS Code application (i.e. the default profile's settings/User
* directory). `undefined` when not running as embedded.
*/
readonly hostUserRoamingDataHome?: URI;
Comment thread
sandy081 marked this conversation as resolved.

// --- Policy
policyFile?: URI;

Expand Down
32 changes: 32 additions & 0 deletions src/vs/platform/environment/node/environmentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
*--------------------------------------------------------------------------------------------*/

import { homedir, tmpdir } from 'os';
import { memoize } from '../../../base/common/decorators.js';
import { INodeProcess } from '../../../base/common/platform.js';
import { joinPath } from '../../../base/common/resources.js';
import { URI } from '../../../base/common/uri.js';
import { Schemas } from '../../../base/common/network.js';
import { NativeParsedArgs } from '../common/argv.js';
import { IDebugParams } from '../common/environment.js';
import { AbstractNativeEnvironmentService, parseDebugParams } from '../common/environmentService.js';
Expand All @@ -19,6 +24,33 @@ export class NativeEnvironmentService extends AbstractNativeEnvironmentService {
userDataDir: getUserDataPath(args, productService.nameShort)
}, productService);
}

@memoize
get hostUserRoamingDataHome(): URI | undefined {
if (!(process as INodeProcess).isEmbeddedApp) {
return undefined;
}
if (!this.isBuilt) {
return undefined;
}
const quality = this.productService.quality;
let hostProductName: string;
if (quality === 'stable') {
hostProductName = 'Code';
} else if (quality === 'insider') {
hostProductName = 'Code - Insiders';
} else if (quality === 'exploration') {
hostProductName = 'Code - Exploration';
} else {
return undefined;
}

// Honor the same env-var overrides that the host VS Code itself uses
// (portable mode and VSCODE_APPDATA), but intentionally skip --user-data-dir
// because that CLI arg belongs to the Agents app, not the host.
const hostUserDataPath = getUserDataPath(this.args, hostProductName);
return joinPath(URI.file(hostUserDataPath), 'User').with({ scheme: Schemas.vscodeUserData });
}
Comment thread
sandy081 marked this conversation as resolved.
}

export function parsePtyHostDebugPort(args: NativeParsedArgs, isBuilt: boolean): IDebugParams {
Expand Down
10 changes: 3 additions & 7 deletions src/vs/platform/storage/electron-main/storageMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import { IAnyWorkspaceIdentifier } from '../../workspace/common/workspace.js';
import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
import { Schemas } from '../../../base/common/network.js';
import { ICrossAppIPCService } from '../../crossAppIpc/electron-main/crossAppIpcService.js';
import { IProductService } from '../../product/common/productService.js';
import { INodeProcess } from '../../../base/common/platform.js';
import { getUserDataPath } from '../../environment/node/userDataPath.js';

//#region Storage Main Service (intent: make application, profile and workspace storage accessible to windows from main process)

Expand Down Expand Up @@ -100,7 +97,6 @@ export class StorageMainService extends Disposable implements IStorageMainServic
@IFileService private readonly fileService: IFileService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
@ICrossAppIPCService private readonly crossAppIPCService: ICrossAppIPCService,
@IProductService private readonly productService: IProductService
) {
super();

Expand Down Expand Up @@ -212,14 +208,14 @@ export class StorageMainService extends Disposable implements IStorageMainServic
// from APPLICATION to APPLICATION_SHARED scope:
// In VS Code: reuse the own application storage (keys are local)
let fallbackStorage: IStorageMain = this.applicationStorage;
if (this.environmentService.isBuilt && (process as INodeProcess).isEmbeddedApp) {
const hostUserRoamingDataHome = this.environmentService.hostUserRoamingDataHome;
if (hostUserRoamingDataHome) {
// - In the Agents App: create a storage backed by the host (VS Code)
// app's application DB so keys are found even if VS Code hasn't
// migrated them to the shared DB yet.
// We use ProfileStorageMain (not ApplicationStorageMain) to avoid
// writing telemetry state into the host app's DB — this is read-only.
const hostUserDataPath = getUserDataPath(this.environmentService.args, this.productService.quality === 'stable' ? 'Code' : this.productService.quality === 'insider' ? 'Code - Insiders' : 'Code - Exploration');
const hostApplicationStoragePath = join(hostUserDataPath, 'User', 'globalStorage', 'state.vscdb');
const hostApplicationStoragePath = join(hostUserRoamingDataHome.with({ scheme: Schemas.file }).fsPath, 'globalStorage', 'state.vscdb');
this.logService.info(`StorageMainService: creating application shared storage with host app fallback at '${hostApplicationStoragePath}'`);
fallbackStorage = this._register(new HostApplicationStorageMain(
hostApplicationStoragePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ suite('StorageMainService', function () {
const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService);
const fileService = disposables.add(new FileService(new NullLogService()));
const uriIdentityService = disposables.add(new UriIdentityService(fileService));
const testStorageService = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(uriIdentityService), environmentService, fileService, new NullLogService())), lifecycleMainService, fileService, uriIdentityService, nullCrossAppIPCService, productService));
const testStorageService = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(uriIdentityService), environmentService, fileService, new NullLogService())), lifecycleMainService, fileService, uriIdentityService, nullCrossAppIPCService));

disposables.add(testStorageService.applicationStorage);

Expand Down Expand Up @@ -300,7 +300,7 @@ suite('StorageMainService', function () {
const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService);
const fileService = disposables.add(new FileService(new NullLogService()));
const uriIdentityService = disposables.add(new UriIdentityService(fileService));
const storageMainService = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(uriIdentityService), environmentService, fileService, new NullLogService())), new TestLifecycleMainService(), fileService, uriIdentityService, crossAppIPCService, productService));
const storageMainService = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(uriIdentityService), environmentService, fileService, new NullLogService())), new TestLifecycleMainService(), fileService, uriIdentityService, crossAppIPCService));

const storage = storageMainService.applicationSharedStorage;
disposables.add(storage);
Expand Down Expand Up @@ -336,7 +336,7 @@ suite('StorageMainService', function () {
onDidReceiveMessage: onDidReceiveMessage2.event,
};

const storageMainService2 = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(new UriIdentityService(fileService)), environmentService, fileService, new NullLogService())), new TestLifecycleMainService(), fileService, disposables.add(new UriIdentityService(fileService)), crossAppIPCService2, productService));
const storageMainService2 = disposables.add(new TestStorageMainService(new NullLogService(), environmentService, disposables.add(new UserDataProfilesMainService(disposables.add(new StateService(SaveStrategy.DELAYED, environmentService, new NullLogService(), fileService)), disposables.add(new UriIdentityService(fileService)), environmentService, fileService, new NullLogService())), new TestLifecycleMainService(), fileService, disposables.add(new UriIdentityService(fileService)), crossAppIPCService2));

const storage2 = storageMainService2.applicationSharedStorage;
disposables.add(storage2);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/userDataProfile/common/userDataProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf
return false;
}

private createDefaultProfile() {
protected createDefaultProfile() {
const defaultProfile = toUserDataProfile('__default__profile__', localize('defaultProfile', "Default"), this.environmentService.userRoamingDataHome, this.profilesCacheHome);
return { ...defaultProfile, extensionsResource: this.getDefaultProfileExtensionsLocation() ?? defaultProfile.extensionsResource, isDefault: true };
}
Expand Down
19 changes: 19 additions & 0 deletions src/vs/platform/userDataProfile/electron-main/userDataProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import { Event } from '../../../base/common/event.js';
import { INodeProcess } from '../../../base/common/platform.js';
import { joinPath } from '../../../base/common/resources.js';
import { INativeEnvironmentService } from '../../environment/common/environment.js';
import { IFileService } from '../../files/common/files.js';
import { refineServiceDecorator } from '../../instantiation/common/instantiation.js';
Expand Down Expand Up @@ -35,6 +37,23 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
super(stateService, uriIdentityService, environmentService, fileService, logService);
}

protected override createDefaultProfile(): IUserDataProfile {
const defaultProfile = super.createDefaultProfile();
if (!(process as INodeProcess).isEmbeddedApp) {
return defaultProfile;
}
const hostUserRoamingDataHome = this.environmentService.hostUserRoamingDataHome;
if (!hostUserRoamingDataHome) {
return defaultProfile;
Comment thread
sandy081 marked this conversation as resolved.
}
return {
...defaultProfile,
keybindingsResource: joinPath(hostUserRoamingDataHome, 'keybindings.json'),
promptsHome: joinPath(hostUserRoamingDataHome, 'prompts'),
mcpResource: joinPath(hostUserRoamingDataHome, 'mcp.json'),
};
}

getAssociatedEmptyWindows(): IEmptyWorkspaceIdentifier[] {
const emptyWindows: IEmptyWorkspaceIdentifier[] = [];
for (const id of this.profilesObject.emptyWindows.keys()) {
Expand Down
Loading