mirror of
https://github.com/coder/code-server.git
synced 2026-10-24 01:57:00 +08:00
Update Code to 1.141.0 (#8040)
* Update Code to 1.141.0 * Allow pull_request_target * Add e2e tests for remote storage * Fix Typescript extension not loading * Remove unused imports
This commit is contained in:
@@ -79,6 +79,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
with:
|
||||
@@ -173,6 +176,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
- run: quilt push -a
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
||||
with:
|
||||
@@ -233,6 +239,9 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
||||
with:
|
||||
submodules: true
|
||||
# When an update/ branch is merged, a release is automatically created
|
||||
# which requires secrets.
|
||||
allow-unsafe-pr-checkout: true
|
||||
|
||||
# quilt has no windows build. The patches are ordinary -p1 diffs
|
||||
# against the repository root, so git applies them in series order.
|
||||
|
||||
@@ -22,6 +22,23 @@ Code v99.99.999
|
||||
|
||||
## Unreleased
|
||||
|
||||
Code v1.141.0
|
||||
|
||||
### Added
|
||||
|
||||
- A new `--enable-remote-storage` flag can be used to make code-server persist
|
||||
workbench storage on the remote server instead of browser storage. Use this if
|
||||
you want to share storage between multiple devices.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The Typescript extension was trying to load as a browser extension even though
|
||||
we build the remote server version, causing it to fail to activate.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Code 1.141.0
|
||||
|
||||
## [4.140.0](https://github.com/coder/code-server/releases/tag/v4.140.0) - 2026-10-02
|
||||
|
||||
Code v1.140.0
|
||||
|
||||
@@ -58,10 +58,17 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add the date, our name, links, enable telemetry (this just makes telemetry
|
||||
# available; telemetry can still be disabled by flag or setting), and
|
||||
# configure trusted extensions (since some, like github.copilot-chat, never
|
||||
# ask to be trusted and this is the only way to get auth working).
|
||||
# Modify the product.json:
|
||||
# - Add the date
|
||||
# - Set the code-server name.
|
||||
# - Add our links
|
||||
# - Enable telemetry (this just makes telemetry available; telemetry can still
|
||||
# be disabled by flag or setting)
|
||||
# - Configure trusted extensions (since some, like github.copilot-chat, never
|
||||
# ask to be trusted and this is the only way to get auth working).
|
||||
# - Make Typescript server plugins run in the workspace. We build the remote
|
||||
# server version, so there is no browser distribution, and this key is not
|
||||
# added automatically.
|
||||
#
|
||||
# This needs to be done before building as Code will read this file and embed
|
||||
# it into the client-side code.
|
||||
@@ -103,6 +110,9 @@ main() {
|
||||
],
|
||||
"aiConfig": {
|
||||
"ariaKey": "code-server"
|
||||
},
|
||||
"extensionPointExtensionKind": {
|
||||
"typescriptServerPlugins": ["workspace"]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
+1
-1
Submodule lib/vscode updated: 07f806f999...2a59476c9b
@@ -48,8 +48,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
|
||||
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
|
||||
<style id="vscode-css-modules" type="text/css" media="screen"></style>
|
||||
|
||||
</head>
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
|
||||
@@ -85,8 +85,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
+ <link rel="manifest" href="{{VS_BASE}}/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
|
||||
|
||||
</head>
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script nonce="{{WORKBENCH_SCRIPT_NONCE}}">
|
||||
@@ -281,8 +281,8 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
-
|
||||
(function () {
|
||||
|
||||
// Find config by checking for DOM
|
||||
@@ -610,8 +600,8 @@ function readCookie(name: string): strin
|
||||
// This script running at all means the page scripts were not blocked or rewritten.
|
||||
@@ -614,8 +604,8 @@ function readCookie(name: string): strin
|
||||
if (!configElement || !configElementAttribute) {
|
||||
throw new Error('Missing web configuration element');
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
|
||||
@@ -475,9 +475,6 @@ export class InstallAction extends Exten
|
||||
@@ -479,9 +479,6 @@ export class InstallAction extends Exten
|
||||
if (this.extension.isBuiltin) {
|
||||
return;
|
||||
}
|
||||
@@ -282,7 +282,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
if (this.extension.state !== ExtensionState.Uninstalled) {
|
||||
return;
|
||||
}
|
||||
@@ -782,7 +779,7 @@ export abstract class InstallInOtherServ
|
||||
@@ -786,7 +783,7 @@ export abstract class InstallInOtherServ
|
||||
}
|
||||
|
||||
if (isLanguagePackExtension(this.extension.local.manifest)) {
|
||||
@@ -291,7 +291,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
}
|
||||
|
||||
// Prefers to run on UI
|
||||
@@ -2281,17 +2278,6 @@ export class SetLanguageAction extends E
|
||||
@@ -2285,17 +2282,6 @@ export class SetLanguageAction extends E
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = SetLanguageAction.DisabledClass;
|
||||
@@ -309,7 +309,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
}
|
||||
|
||||
override async run(): Promise<any> {
|
||||
@@ -2308,7 +2294,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2312,7 +2298,6 @@ export class ClearLanguageAction extends
|
||||
private static readonly DisabledClass = `${this.EnabledClass} disabled`;
|
||||
|
||||
constructor(
|
||||
@@ -317,7 +317,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/extensions/browser/extens
|
||||
@ILocaleService private readonly localeService: ILocaleService,
|
||||
) {
|
||||
super(ClearLanguageAction.ID, ClearLanguageAction.TITLE.value, ClearLanguageAction.DisabledClass, false);
|
||||
@@ -2318,17 +2303,6 @@ export class ClearLanguageAction extends
|
||||
@@ -2322,17 +2307,6 @@ export class ClearLanguageAction extends
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = ClearLanguageAction.DisabledClass;
|
||||
|
||||
@@ -225,7 +225,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html
|
||||
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<style id="vscode-css-modules" type="text/css" media="screen"></style>
|
||||
|
||||
</head>
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
@@ -251,7 +251,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.html
|
||||
+ <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="stylesheet" href="{{WORKBENCH_WEB_BASE_URL}}/out/vs/code/browser/workbench/workbench.css">
|
||||
|
||||
</head>
|
||||
<!-- Startup fallback: shown only if the scripts below never run, e.g. because a proxy,
|
||||
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
|
||||
@@ -110,7 +110,7 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
import type { IURLCallbackProvider } from '../../../workbench/services/url/browser/urlService.js';
|
||||
import { create } from '../../../workbench/workbench.web.main.internal.js';
|
||||
|
||||
@@ -612,6 +613,44 @@ class WorkspaceProvider implements IWork
|
||||
@@ -616,6 +617,44 @@ class WorkspaceProvider implements IWork
|
||||
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
|
||||
workspaceProvider: WorkspaceProvider.create(config),
|
||||
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
|
||||
@@ -159,7 +159,7 @@ Index: code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExpl
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts
|
||||
@@ -99,8 +99,8 @@ export class ForwardedPortsView extends
|
||||
@@ -100,8 +100,8 @@ export class ForwardedPortsView extends
|
||||
private async enableForwardedPortsFeatures() {
|
||||
this.contextKeyListener.clear();
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
+++ code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
@@ -139,8 +139,13 @@ export class BaseSecretStorageService ex
|
||||
@@ -144,8 +144,13 @@ export class BaseSecretStorageService ex
|
||||
return await readEncryptedSecret(
|
||||
key,
|
||||
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
|
||||
(fullKey) => this.getValueFromStorage(key, fullKey, storageService),
|
||||
- // If the storage service is in-memory, we don't need to decrypt
|
||||
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.decrypt(v),
|
||||
+ // Don't decrypt if storage is in-memory or if encryption service is not available
|
||||
@@ -19,10 +19,10 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._logService,
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -160,8 +165,13 @@ export class BaseSecretStorageService ex
|
||||
@@ -168,8 +173,13 @@ export class BaseSecretStorageService ex
|
||||
key,
|
||||
value,
|
||||
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
|
||||
(fullKey, encrypted) => this.setValueInStorage(key, fullKey, encrypted, storageService),
|
||||
- // If the storage service is in-memory, we don't need to encrypt
|
||||
- this._type === 'in-memory' ? (v) => Promise.resolve(v) : (v) => this._encryptionService.encrypt(v),
|
||||
+ // Don't encrypt if storage is in-memory or if encryption service is not available
|
||||
@@ -35,7 +35,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._logService,
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -194,8 +204,9 @@ export class BaseSecretStorageService ex
|
||||
@@ -224,8 +234,9 @@ export class BaseSecretStorageService ex
|
||||
|
||||
private async initialize(): Promise<IStorageService> {
|
||||
let storageService;
|
||||
@@ -47,7 +47,7 @@ Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
|
||||
this._type = 'persisted';
|
||||
storageService = this._storageService;
|
||||
} else {
|
||||
@@ -203,7 +214,7 @@ export class BaseSecretStorageService ex
|
||||
@@ -233,7 +244,7 @@ export class BaseSecretStorageService ex
|
||||
if (this._type === 'in-memory') {
|
||||
return this._storageService;
|
||||
}
|
||||
@@ -77,10 +77,14 @@ Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
|
||||
@@ -625,2 +625,2 @@
|
||||
@@ -655,8 +655,8 @@ class WorkspaceProvider implements IWork
|
||||
})
|
||||
}
|
||||
},
|
||||
- secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath
|
||||
- ? undefined /* with a remote without embedder-preferred storage, store on the remote */
|
||||
+ secretStorageProvider: config.remoteStorageEnabled || (config.remoteAuthority && !secretStorageKeyPath)
|
||||
+ ? undefined /* with remote storage enabled, or without embedder-prefered storage, store on the remote */
|
||||
: new LocalStorageSecretStorageProvider(secretStorageCrypto),
|
||||
});
|
||||
})();
|
||||
|
||||
+146
-22
@@ -1,8 +1,13 @@
|
||||
Reuse VS Code's Electron storage service for remote persistence
|
||||
|
||||
Index: code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
+++ code-server/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts
|
||||
@@ -14 +14,6 @@
|
||||
@@ -11,7 +11,12 @@ import { IStorage } from '../../../base/
|
||||
import { INativeEnvironmentService } from '../../environment/common/environment.js';
|
||||
import { IFileService } from '../../files/common/files.js';
|
||||
import { createDecorator } from '../../instantiation/common/instantiation.js';
|
||||
-import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
|
||||
+import type { ILifecycleMainService, ShutdownReason } from '../../lifecycle/electron-main/lifecycleMainService.js';
|
||||
+
|
||||
@@ -10,44 +15,110 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+// that module imports Electron, which is not present in the code-server server image.
|
||||
+const LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN = 3;
|
||||
+const SHUTDOWN_REASON_KILL = 2;
|
||||
@@ -101 +101 @@
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
import { AbstractStorageService, isProfileUsingDefaultStorage, IStorageService, StorageScope, StorageTarget } from '../common/storage.js';
|
||||
import { ApplicationStorageMain, ApplicationSharedStorageMain, ProfileStorageMain, InMemoryStorageMain, IStorageMain, IStorageMainOptions, WorkspaceStorageMain, IStorageChangeEvent } from './storageMain.js';
|
||||
@@ -92,7 +97,7 @@ export class StorageMainService extends
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@IUserDataProfilesMainService private readonly userDataProfilesService: IUserDataProfilesMainService,
|
||||
- @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
+ private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@@ -117 +117 @@
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
) {
|
||||
@@ -114,7 +119,7 @@ export class StorageMainService extends
|
||||
|
||||
// Application Storage: Warmup when any window opens
|
||||
(async () => {
|
||||
- await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen);
|
||||
+ await this.lifecycleMainService.when(LIFECYCLE_MAIN_PHASE_AFTER_WINDOW_OPEN);
|
||||
@@ -256 +256 @@
|
||||
|
||||
this.applicationStorage.init();
|
||||
this.applicationSharedStorage.init();
|
||||
@@ -253,7 +258,7 @@ export class StorageMainService extends
|
||||
}
|
||||
|
||||
private createProfileStorage(profile: IUserDataProfile): IStorageMain {
|
||||
- if (this.shutdownReason === ShutdownReason.KILL) {
|
||||
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
|
||||
@@ -295 +295 @@
|
||||
|
||||
// Workaround for native crashes that we see when
|
||||
// SQLite DBs are being created even after shutdown
|
||||
@@ -292,7 +297,7 @@ export class StorageMainService extends
|
||||
}
|
||||
|
||||
private createWorkspaceStorage(workspace: IAnyWorkspaceIdentifier): IStorageMain {
|
||||
- if (this.shutdownReason === ShutdownReason.KILL) {
|
||||
+ if (this.shutdownReason === SHUTDOWN_REASON_KILL) {
|
||||
|
||||
|
||||
// Workaround for native crashes that we see when
|
||||
// SQLite DBs are being created even after shutdown
|
||||
Index: code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/services/storage/electron-browser/storageService.ts
|
||||
@@ -6 +6 @@
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
-import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';
|
||||
+import { IRemoteService } from '../../../../platform/ipc/common/services.js';
|
||||
@@ -22 +22 @@
|
||||
import { IStorage, Storage, MigratingStorage } from '../../../../base/parts/storage/common/storage.js';
|
||||
import { RemoteStorageService } from '../../../../platform/storage/common/storageService.js';
|
||||
import { FallbackApplicationStorageDatabaseClient, ApplicationSharedStorageDatabaseClient } from '../../../../platform/storage/common/storageIpc.js';
|
||||
@@ -19,10 +19,10 @@ export class NativeWorkbenchStorageServi
|
||||
workspace: IAnyWorkspaceIdentifier | undefined,
|
||||
private readonly userDataProfileService: IUserDataProfileService,
|
||||
userDataProfilesService: IUserDataProfilesService,
|
||||
- mainProcessService: IMainProcessService,
|
||||
+ remoteService: Pick<IRemoteService, 'getChannel'>,
|
||||
@@ -25 +25 @@
|
||||
private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
) {
|
||||
- super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, mainProcessService, workbenchEnvironmentService);
|
||||
+ super(workspace, { currentProfile: userDataProfileService.currentProfile, defaultProfile: userDataProfilesService.defaultProfile }, remoteService as IRemoteService, workbenchEnvironmentService);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts
|
||||
@@ -68,0 +69 @@
|
||||
@@ -66,6 +66,7 @@ export const serverOptions: OptionDescri
|
||||
'disable-experiments': OPTIONS['disable-experiments'],
|
||||
'disable-workspace-trust': OPTIONS['disable-workspace-trust'],
|
||||
'file-watcher-polling': { type: 'string', deprecates: ['fileWatcherPolling'] },
|
||||
+ 'enable-remote-storage': { type: 'boolean', cat: 'o', description: nls.localize('enable-remote-storage', 'Persist browser storage (settings, state, etc.) on the server instead of browser IndexedDB. Enables state portability across browsers/devices.') },
|
||||
@@ -214,0 +216 @@
|
||||
'log': OPTIONS['log'],
|
||||
'logsPath': OPTIONS['logsPath'],
|
||||
'force-disable-user-env': OPTIONS['force-disable-user-env'],
|
||||
@@ -212,6 +213,7 @@ export interface ServerParsedArgs {
|
||||
'logsPath'?: string;
|
||||
|
||||
'force-disable-user-env'?: boolean;
|
||||
+ 'enable-remote-storage'?: boolean;
|
||||
'enable-proposed-api'?: string[];
|
||||
|
||||
/* ----- vs code web options ----- */
|
||||
Index: code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/serverServices.ts
|
||||
@@ -107,0 +108,4 @@
|
||||
@@ -105,6 +105,10 @@ import { McpManagementChannel } from '..
|
||||
import { AllowedMcpServersService } from '../../platform/mcp/common/allowedMcpServersService.js';
|
||||
import { IMcpGalleryManifestService } from '../../platform/mcp/common/mcpGalleryManifest.js';
|
||||
import { McpGalleryManifestIPCService } from '../../platform/mcp/common/mcpGalleryManifestServiceIpc.js';
|
||||
+import { StorageDatabaseChannel } from '../../platform/storage/electron-main/storageIpc.js';
|
||||
+import { StorageMainService } from '../../platform/storage/electron-main/storageMainService.js';
|
||||
+import type { ILifecycleMainService } from '../../platform/lifecycle/electron-main/lifecycleMainService.js';
|
||||
+import type { IUserDataProfilesMainService } from '../../platform/userDataProfile/electron-main/userDataProfile.js';
|
||||
@@ -240,0 +245,15 @@
|
||||
import { SANDBOX_HELPER_CHANNEL_NAME, SandboxHelperChannel } from '../../platform/sandbox/common/sandboxHelperIpc.js';
|
||||
import { SandboxHelperService } from '../../platform/sandbox/node/sandboxHelper.js';
|
||||
|
||||
@@ -238,6 +242,21 @@ export async function setupServerService
|
||||
services.set(IMcpGatewayService, new SyncDescriptor(McpGatewayService));
|
||||
|
||||
const instantiationService: IInstantiationService = new InstantiationService(services);
|
||||
+ // Reuse the Electron storage service on the remote. The server has no
|
||||
+ // windows, so its lifecycle is always ready and never loads a window.
|
||||
+ const storageMainService = disposables.add(new StorageMainService(
|
||||
@@ -63,7 +134,10 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+ uriIdentityService,
|
||||
+ ));
|
||||
+
|
||||
@@ -419,6 +439,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
|
||||
services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService));
|
||||
|
||||
const ptyHostStarter = instantiationService.createInstance(
|
||||
@@ -420,6 +439,7 @@ export async function setupServerService
|
||||
|
||||
const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
|
||||
socketServer.registerChannel('languagePacks', languagePackChannel);
|
||||
@@ -71,28 +145,61 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
|
||||
// clean up extensions folder
|
||||
remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp());
|
||||
Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
+++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts
|
||||
@@ -411 +411,2 @@
|
||||
@@ -451,7 +451,8 @@ export class WebClientServer {
|
||||
folderUri: resolveWorkspaceURI(this._environmentService.args['default-folder']),
|
||||
workspaceUri: resolveWorkspaceURI(this._environmentService.args['default-workspace']),
|
||||
productConfiguration,
|
||||
- callbackRoute: callbackRoute
|
||||
+ callbackRoute: callbackRoute,
|
||||
+ remoteStorageEnabled: this._environmentService.args['enable-remote-storage'] ? true : undefined
|
||||
};
|
||||
|
||||
const cookies = cookie.parse(req.headers.cookie || '');
|
||||
Index: code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.api.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/browser/web.api.ts
|
||||
@@ -413,0 +414,5 @@
|
||||
@@ -411,6 +411,11 @@ export interface IWorkbenchConstructionO
|
||||
readonly authenticationProviders?: readonly IAuthenticationProvider[];
|
||||
|
||||
//#endregion
|
||||
+ /**
|
||||
+ * Persist workbench storage on the remote server instead of browser IndexedDB.
|
||||
+ */
|
||||
+ readonly remoteStorageEnabled?: boolean;
|
||||
+
|
||||
|
||||
//#region Development options
|
||||
|
||||
Index: code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
+++ code-server/lib/vscode/src/vs/workbench/browser/web.main.ts
|
||||
@@ -35,0 +36 @@
|
||||
@@ -33,6 +33,7 @@ import { ISignService } from '../../plat
|
||||
import { SignService } from '../../platform/sign/browser/signService.js';
|
||||
import { IWorkbenchConstructionOptions, IWorkbench, IWorkspace, ITunnel } from './web.api.js';
|
||||
import { BrowserStorageService } from '../services/storage/browser/storageService.js';
|
||||
+import { NativeWorkbenchStorageService } from '../services/storage/electron-browser/storageService.js';
|
||||
@@ -479 +480 @@
|
||||
import { IStorageService } from '../../platform/storage/common/storage.js';
|
||||
import { toLocalISOString } from '../../base/common/date.js';
|
||||
import { isWorkspaceToOpen, isFolderToOpen } from '../../platform/window/common/window.js';
|
||||
@@ -482,7 +483,7 @@ export class BrowserMain extends Disposa
|
||||
serviceCollection.set(IWorkbenchConfigurationService, service);
|
||||
return service;
|
||||
}),
|
||||
- this.createStorageService(workspace, logService, userDataProfileService).then(service => {
|
||||
+ this.createStorageService(workspace, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService).then(service => {
|
||||
@@ -601 +602,15 @@
|
||||
serviceCollection.set(IStorageService, service);
|
||||
return service;
|
||||
})
|
||||
@@ -604,7 +605,21 @@ export class BrowserMain extends Disposa
|
||||
}));
|
||||
}
|
||||
|
||||
- protected async createStorageService(workspace: IAnyWorkspaceIdentifier, logService: ILogService, userDataProfileService: IUserDataProfileService): Promise<IStorageService> {
|
||||
+ protected async createStorageService(workspace: IAnyWorkspaceIdentifier, environmentService: IBrowserWorkbenchEnvironmentService, logService: ILogService, userDataProfileService: IUserDataProfileService, userDataProfilesService: IUserDataProfilesService, remoteAgentService: IRemoteAgentService): Promise<IStorageService> {
|
||||
+ const connection = remoteAgentService.getConnection();
|
||||
@@ -109,14 +216,31 @@ Reuse VS Code's Electron storage service for remote persistence
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
const storageService = new BrowserStorageService(workspace, userDataProfileService, logService);
|
||||
|
||||
try {
|
||||
Index: code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
===================================================================
|
||||
--- code-server.orig/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
+++ code-server/lib/vscode/src/vs/sessions/browser/web.main.ts
|
||||
@@ -42 +42 @@
|
||||
@@ -39,9 +39,9 @@ export class SessionsBrowserMain extends
|
||||
_workspace: IAnyWorkspaceIdentifier,
|
||||
environmentService: IBrowserWorkbenchEnvironmentService,
|
||||
userDataProfileService: IUserDataProfileService,
|
||||
- _userDataProfilesService: BrowserUserDataProfilesService,
|
||||
+ userDataProfilesService: BrowserUserDataProfilesService,
|
||||
@@ -44 +44 @@
|
||||
fileService: FileService,
|
||||
- _remoteAgentService: IRemoteAgentService,
|
||||
+ remoteAgentService: IRemoteAgentService,
|
||||
@@ -85 +85 @@
|
||||
uriIdentityService: IUriIdentityService,
|
||||
policyService: IPolicyService,
|
||||
logService: ILogService,
|
||||
@@ -82,7 +82,7 @@ export class SessionsBrowserMain extends
|
||||
serviceCollection.set(IWorkbenchConfigurationService, configurationService);
|
||||
|
||||
// Storage
|
||||
- const storageService = await this.createStorageService(workspaceIdentifier, logService, userDataProfileService);
|
||||
+ const storageService = await this.createStorageService(workspaceIdentifier, environmentService, logService, userDataProfileService, userDataProfilesService, remoteAgentService);
|
||||
serviceCollection.set(IStorageService, storageService);
|
||||
|
||||
// Workspace Trust Service
|
||||
|
||||
+1
-1
@@ -24,6 +24,6 @@ trusted-domains.diff
|
||||
signature-verification.diff
|
||||
copilot.diff
|
||||
app-name.diff
|
||||
csp-hashes.diff
|
||||
remote-storage.diff
|
||||
remote-secret-storage.diff
|
||||
csp-hashes.diff
|
||||
|
||||
@@ -2,7 +2,8 @@ import * as vscode from "vscode"
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
vscode.window.showInformationMessage("test extension loaded")
|
||||
// Test extension
|
||||
|
||||
// Prints the current proxy URI into a notification.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.proxyUri", () => {
|
||||
if (process.env.VSCODE_PROXY_URI) {
|
||||
@@ -13,7 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}),
|
||||
)
|
||||
|
||||
// asExternalUri extension
|
||||
// Asks for a URI, then runs it through asExternalUri and prints the result
|
||||
// into a notification.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.asExternalUri", async () => {
|
||||
const input = await vscode.window.showInputBox({
|
||||
@@ -28,4 +30,29 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const secretKey = "code-server-test-secret"
|
||||
|
||||
// Asks for a string, then stores it as a secret.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.setSecret", async () => {
|
||||
const input = await vscode.window.showInputBox({
|
||||
prompt: "Secret to store",
|
||||
})
|
||||
|
||||
if (input) {
|
||||
await context.secrets.store(secretKey, input)
|
||||
vscode.window.showInformationMessage(`set secret: ${input}`)
|
||||
} else {
|
||||
vscode.window.showErrorMessage(`Failed to run test case. No input provided.`)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
// Prints the current secret, if any.
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand("codeServerTest.getSecret", async () => {
|
||||
vscode.window.showInformationMessage(`get secret: ${await context.secrets.get(secretKey)}`)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
"command": "codeServerTest.asExternalUri",
|
||||
"title": "asExternalUri test",
|
||||
"category": "code-server"
|
||||
},
|
||||
{
|
||||
"command": "codeServerTest.setSecret",
|
||||
"title": "Set test secret",
|
||||
"category": "code-server"
|
||||
},
|
||||
{
|
||||
"command": "codeServerTest.getSecret",
|
||||
"title": "Get test secret",
|
||||
"category": "code-server"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -363,13 +363,14 @@ export class CodeServerPage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the test extension loaded
|
||||
* Checks if the test extension loaded by waiting for its notification. Once
|
||||
* it appears, dismiss the notification.
|
||||
*/
|
||||
async waitForTestExtensionLoaded(): Promise<void> {
|
||||
const selector = "text=test extension loaded"
|
||||
this.codeServer.logger.debug("Waiting for test extension to load...")
|
||||
|
||||
await this.page.waitForSelector(selector)
|
||||
const locator = this.page.getByRole("dialog", { name: "Info: test extension loaded" })
|
||||
await locator.hover()
|
||||
await locator.getByLabel("Clear Notification (Del)").click()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { clean } from "../utils/helpers"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
const tests = [
|
||||
{
|
||||
name: "browser storage",
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
name: "remote storage",
|
||||
args: ["--enable-remote-storage"],
|
||||
},
|
||||
]
|
||||
|
||||
for (const tc of tests) {
|
||||
const args = ["--disable-workspace-trust", "--extensions-dir", path.join(__dirname, "./extensions"), ...tc.args]
|
||||
describe(tc.name, args, {}, () => {
|
||||
test("should store workbench state and secrets", async ({ codeServerPage }) => {
|
||||
// Create and open a file.
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const file = path.join(dir, "foo")
|
||||
await fs.writeFile(file, "bar")
|
||||
await codeServerPage.openFile(file)
|
||||
|
||||
// Store a secret.
|
||||
const secret = "foo-bar-baz"
|
||||
await codeServerPage.waitForTestExtensionLoaded()
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Set test secret")
|
||||
await codeServerPage.page.waitForSelector(".quick-input-widget:focus-within")
|
||||
await codeServerPage.page.keyboard.type(secret)
|
||||
await codeServerPage.page.keyboard.press("Enter")
|
||||
await expect(codeServerPage.page.getByText(`Info: set secret: ${secret}`)).toBeVisible()
|
||||
|
||||
// There should be a workspace storage directory.
|
||||
const userDir = path.join(dir, "User/workspaceStorage")
|
||||
const dirs = await fs.readdir(userDir)
|
||||
expect(dirs.length).toBe(1)
|
||||
|
||||
const storageFile = path.join(userDir, dirs[0], "state.vscdb")
|
||||
if (tc.args.includes("--enable-remote-storage")) {
|
||||
// The sqlite database should exist.
|
||||
fs.stat(storageFile)
|
||||
} else {
|
||||
// But no sqlite database.
|
||||
expect(() => fs.stat(storageFile)).rejects.toThrow("ENOENT")
|
||||
}
|
||||
|
||||
// Reload using a command so it has a chance to flush storage.
|
||||
await codeServerPage.executeCommandViaMenus("Developer: Reload Window")
|
||||
await codeServerPage.waitForTestExtensionLoaded()
|
||||
|
||||
// Should see the same file.
|
||||
await codeServerPage.waitForTab(file)
|
||||
|
||||
// Should be able to retrieve the secret.
|
||||
await codeServerPage.executeCommandViaMenus("code-server: Get test secret")
|
||||
await expect(codeServerPage.page.getByText(`Info: get secret: ${secret}`)).toBeVisible()
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { promises as fs } from "fs"
|
||||
import * as path from "path"
|
||||
import { describe, test, expect } from "./baseFixture"
|
||||
|
||||
const args = ["--disable-workspace-trust"]
|
||||
|
||||
describe("typescript extension", args, {}, () => {
|
||||
test("should load as a workspace extension", async ({ codeServerPage }) => {
|
||||
const dir = await codeServerPage.workspaceDir
|
||||
const file = path.join(dir, "foo.ts")
|
||||
await fs.writeFile(file, 'const n: number = "x"')
|
||||
await codeServerPage.openFile(file)
|
||||
|
||||
await codeServerPage.executeCommandViaMenus("Developer: Show Running Extensions")
|
||||
await expect(
|
||||
codeServerPage.page.getByLabel("typescript-language-features").getByText(/localhost:\d+/),
|
||||
).toBeVisible()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user