microsoft/vscode
github.com/microsoft/vscode ↗ · 3994 files · 39.4 MB · scan capped
Visual Studio Code - Open Source ("Code - OSS") The Repository This repository ("Code - OSS") is where we (Microsoft) develop the Visual Studio Code product together with the community.
Overview
This is the open-source core of Visual Studio Code (code-oss-dev v1.140.0): a TypeScript/Electron desktop code editor that also runs in the browser and as a remote server. It is organized as a strict layered architecture (base → platform → editor → workbench) glued together by constructor-injected services, registries, and a large built-in extension set under extensions/. Distinctive traits visible in the source: a single-instance Electron main process that multiplexes ~30 IPC channels to renderer, shared, pty-host, extension-host and agent-host processes; a Rust CLI (cli/) for tunnels/serve-web; and a new src/vs/sessions workbench variant dedicated to agentic workflows.
System map
The system is a multi-process Electron application with parallel web and server builds. src/main.ts is the Electron main entry that reads argv.json, configures sandboxing and privileged schemes, then loads src/vs/code/electron-main/main.ts, which manually assembles a DI ServiceCollection, claims a single-instance IPC socket, and hands off to CodeApplication. The renderer boots the workbench through import-barrel entrypoints (workbench.desktop.main.ts / workbench.web.main.ts / workbench.common.main.ts) that register singleton services and contributions. Auxiliary processes — shared process, pty host, extension hosts, agent host — are spawned as Electron utility processes or Node forks and communicate over named IPC channels. A separate Rust crate under cli/ implements the `code` command-line launcher, tunnel daemon, and web server host, while src/vs/server and remote/ implement the remote extension host agent (vscode-reh).
- src/main.ts is the real Electron main entry: it configures portable mode, parses CLI args, reads/creates argv.json, toggles the Chromium sandbox, registers the privileged schemes vscode-webview/vscode-file/vscode-remote-resource/vscode-managed-remote-resource, and on app 'ready' calls bootstrapESM() then imports ./vs/code/electron-main/main.js.
- CodeMain.startup() in src/vs/code/electron-main/main.ts builds a ServiceCollection by hand (EnvironmentMainService, LoggerMainService, FileService+DiskFileSystemProvider, UriIdentityService, StateService, UserDataProfilesMainService, policy services, ConfigurationService) and wraps it in an InstantiationService before creating CodeApplication.
- Single-instance behavior is enforced by claimInstance(): the first process serves a node IPC socket at environmentMainService.mainIPCHandle (exported to child processes as VSCODE_IPC_HOOK) and writes a pid lockfile; a second instance forwards args to the running one and quits.
- CodeApplication.startup() creates an ElectronIPCServer, resolves machineId/sqmId/devDeviceId, spawns the SharedProcess via a MessagePortClient, installs ErrorTelemetry, lazily starts the AgentHostProcessManager, then calls initChannels() which registers roughly 30 channels (storage, policy, nativeManagedSettings, fileManagedSettings, local file system, userDataProfiles, update, encryption, nativeHost, webview, workspaces, menubar, url, localPty, externalTerminal, sandboxHelper, mcpGateway, extensionHostStarter, utilityProcessWorker, …) on both the renderer server and the shared-process client.
- The workbench ships three parallel entrypoint barrels: workbench.common.main.ts holds shared imports/singletons, workbench.web.main.ts adds web-only services and contribs, and workbench.desktop.main.ts layers desktop-only ones; comments in workbench.ts explicitly forbid registering services locally and direct authors to registerSingleton().
- Architectural layering base→platform→editor→workbench is machine-enforced: 'npm run valid-layers-check' invokes build/checker/layersChecker.ts, and 'npm run check-cyclic-dependencies' runs build/lib/checkCyclicDependencies.ts over out/.
- Process model: main process (electron-main), one renderer per window, a shared process for cross-window work (sharedProcessMain.ts), a pty host for terminals (ptyHostMain.ts/PtyService), extension hosts (local process, web worker, or remote), and an agent host utility process managed by AgentHostProcessManager/ElectronAgentHostStarter.
- A remote-server variant lives in src/vs/server (server.main.ts, serverServices.ts, remoteExtensionHostAgentServer.ts) packaged as vscode-reh via remote/package.json, and web serving is driven by the Rust CLI's serve_web command.
- The Rust CLI crate 'code' (cli/Cargo.toml, cli/src/bin/code/main.rs) parses args with clap, distinguishes integrated vs standalone mode, and dispatches subcommands including tunnel, serve-web, update, and a family of agent_* commands (agent_host, agent_ps, agent_kill, agent_logs, agent_relay, agent_stop, agent_endpoints).
- src/vs/sessions is a separate workbench layer ('agent sessions window') with its own entry barrels (sessions.desktop.main.ts, sessions.web.main.ts) that may import from vs/workbench but not vice versa, per the documented layering rules.
- product.json is the branding/config manifest (nameShort 'Code - OSS', dataFolderName '.vscode-oss', urlProtocol 'code-oss', win32/darwin ids, builtInExtensions list with sha256 pins); build commands are npm scripts wrapping gulp (npm run compile → gulp compile via gulpfile.mjs; npm run watch; npm run typecheck-client).
- Runtime boundaries are bridged by a channel abstraction: ProxyChannel/IPCServer in src/vs/base/parts/ipc, validatedIpcMain for renderer→main calls, and getDelayedChannel(ProxyChannel.toService(...)) used to lazily expose shared-process services like diagnostics and telemetryAppender as local DI services.
Feature catalog
User-facing surface is delivered two ways: hard-coded workbench contributions under src/vs/workbench/contrib and src/vs/sessions, and built-in extensions under extensions/. Major features include the Monaco-based editor, files/explorer, search, SCM/git, debugging, integrated terminal, notebooks, tasks, settings/preferences UI, extensions viewlet + marketplace integration, remote development (SSH/containers/tunnels), settings sync, MCP support, and an extensive chat/agent subsystem. The `code` CLI adds tunnel, serve-web, update and agent-management commands.
- The text editor is Monaco: src/vs/editor contains the editor implementation (editor.main.ts entry, language services, diff editor via @vscode/diff dependency) and is a standalone publishable layer with its own tsconfig.monaco.json.
- Debugging support lives in src/vs/workbench/contrib/debug with the debug.contribution.ts barrel, extension-host debug broadcast channel 'extensionhostdebugservice' registered in app.ts, and js-debug shipped as a pinned builtInExtension in product.json.
- The integrated terminal is backed by a dedicated pty-host process: PtyHostService in the renderer talks over the 'localPty' IPC channel to ptyHostMain/PtyService, which spawns shells via terminalProcess.ts; terminal contribs register via terminal.contribution.ts.
- Chat/agent AI features are first-class contribs: src/vs/workbench/contrib/chat contains chat.contribution.ts, agentSessions, agentPlugins, aiCustomization and dozens of browser modules; extension-side integration goes through ExtHostChatAgents2/ExtHostChatSessions registered in the ext-host API factory.
- MCP (Model Context Protocol) is integrated at platform and workbench level: platform/mcp has a native discovery helper service, a McpGatewayService in the main process exposed via McpGatewayChannel, a workbench management service, and mcpServerDefinitionProviders is a declared extension point.
- SCM and Git support: the workbench provides the generic SCM contrib while git is a built-in extension (extensions/git) together with git-base, github, and github-authentication for the GitHub auth provider.
- Remote development is a core feature: IRemoteAuthorityResolverService.resolveAuthority drives connections to vscode-remote authorities, RemoteFileSystemProviderClient mounts remote files, and the Rust CLI implements `code tunnel` (dev tunnels via @microsoft/dev-tunnels-* SDKs also used in cli/src/tunnels/dev_tunnels.rs).
- Settings Sync ships in the OSS build: UserDataSyncService/UserDataAutoSyncService/UserDataSyncStoreService are registered as eager/delayed singletons in workbench.web.main.ts.
- Extension management UI + engine: contrib/extensions provides the viewlet while IWorkbenchExtensionManagementService (ExtensionManagementService) handles install/uninstall against the gallery manifest service; webExtensionsScannerService handles web extensions.
- The `code` CLI exposes user-facing commands: opening folders/files, --install-extension/--uninstall-extension via cliProcessMain.ts in the node CLI entry, `code tunnel`/`tunnel service`/`tunnel rename`/`tunnel forward`, `serve-web`, `update`, `version`, and agent management subcommands.
- Notebooks are a built-in workbench feature (contrib/notebook) plus renderer extensions (extensions/notebook-renderers, extensions/ipynb) with ExtHostNotebook* RPC actors bridging kernels and renderers.
- Webviews are a sandboxed feature surface: vscode-webview is registered as a privileged scheme in main.ts and WebviewMainService in the main process manages embedding, while extHostWebviews/extHostWebviewPanels expose the API to extensions.
Data flow
Data moves through explicit service boundaries. On disk, IFileService is the single funnel: scheme-based IFileSystemProviders are registered for file:, vscode-userdata:, vscode-remote:, in-memory and IndexedDB backends. Settings flow through a layered ConfigurationService (defaults → policy → user → workspace → folder) fed by NativePolicyService/FilePolicyService/MultiplexPolicyService. Workbench state persists through IStorageService whose desktop implementation proxies reads/writes to the main-process StorageMainService over the 'storage' IPC channel. Secrets go through ISecretStorageService → IEncryptionService → OS keyring. Extension APIs are pure RPC: extHost.* objects are registered as addressable ExtHostContext instances and call MainContext.MainThread* proxies over the extension-host protocol. Telemetry is appended in the shared process via a 'telemetryAppender' channel.
- FileService.registerProvider(scheme, provider) is the input boundary for all file IO: main registers DiskFileSystemProvider for 'file' and FileUserDataProvider for 'vscode-userdata'; the workbench additionally registers IndexedDB, in-memory, HTML File System Access, and remote providers.
- Desktop workbench persistence goes over IPC: StorageDatabaseChannel wrapping IStorageMainService/StorageMainService is registered on the 'storage' channel for both renderer and shared-process clients; main-process state itself uses StateService with SaveStrategy.DELAYED.
- Configuration is layered: ConfigurationService is constructed with the default profile's settingsResource, the FileService, and an IPolicyService that multiplexes OS-native policies (registry/plist via NativePolicyService) and file policies (Linux system path or --policy-file), plus separate native/file managed-settings services for Copilot policy.
- Extension-host RPC is symmetric: createApiFactoryAndRegisterActors registers ~40 ExtHostContext.* actors (ExtHostCommands, ExtHostDocuments, ExtHostTerminalService, ExtHostChatAgents2, ExtHostMpcService…) and obtains MainContext.MainThread* proxies; shapes are declared in extHost.protocol.ts and marshalled by RPCProtocol.
- Secrets flow: extension secret storage calls ISecretStorageService → IEncryptionService which picks an OS keyring provider (gnome-libsecret/kwallet via Electron safeStorage, or Windows/macOS stores) with an explicit 'use weaker encryption' plaintext fallback and a --use-inmemory-secretstorage argv.json escape hatch.
- Telemetry is funneled to the shared process: the main-process TelemetryService uses a TelemetryAppenderClient over the shared-process 'telemetryAppender' channel; PII paths are computed via getPiiPathsFromEnvironment and the 1DS SDK packages are dependencies.
- Text file persistence path: dirty TextFileEditorModel instances are saved through TextFileService with TextFileSaveParticipant hooks (e.g., format-on-save, trim) before FileService.writeFile hits the disk provider; working-copy backups are handled separately by workingCopyBackupService.
- Remote authority flow: workbench asks IRemoteAuthorityResolverService to resolve 'vscode-remote://…' authorities; resolution is delegated to a resolver extension in the extension host, after which RemoteAgentService channels (file system, terminals, extension management, extension host) run over the remote socket via IRemoteSocketFactoryService.
- URL/protocol input boundary: vscode:// deep links are received by ElectronURLListener in the main process, routed via the 'url' channel and URLHandlerRouter to window or extension handlers; initial protocol URLs are captured before the first window opens.
- Extension scanning/activation data flow: ExtensionsScannerService (main) + ExtensionsProfileScannerService feed ExtensionDescriptionRegistry in the workbench; ImplicitActivationEvents computes activation events, ExtensionRunningLocationTracker assigns local/remote/web-worker locations, and deltas stream through _onDidChangeExtensions.
Behavior traces
Three flows were walked end-to-end in source: desktop cold start, renderer workbench bring-up, and extension activation/RPC. Startup is heavily instrumented with perf.mark() checkpoints (code/didStartMain … code/didOpenFirstWindow). The workbench uses phased lifecycle (Starting→Ready→Restored→Eventually) so contributions register against phases rather than blocking startup. Extension activation is lazy and event-driven; the extension host is spawned through a main-process IPC channel and bridges API calls via RPCProtocol proxies.
- Desktop cold start (ordered): src/main.ts top-level → configurePortable → parseCLIArgs → configureCommandlineSwitchesSync(readArgvConfigSync) → app.enableSandbox (or append 'no-sandbox') → app.setPath('userData') → protocol.registerSchemesAsPrivileged → app.once('ready') → onReady → startup() sets VSCODE_NLS_CONFIG/VSCODE_CODE_CACHE_PATH → bootstrapESM() → import('./vs/code/electron-main/main.js').
- Main-process startup (ordered): CodeMain.main → startup → createServices (ServiceCollection + InstantiationService) → initServices (mkdir user-data dirs, stateService.init, configurationService.initialize, userDataProfilesMainService.init) → claimInstance (nodeIPCServe on mainIPCHandle + write mainLockfile) → createInstance(CodeApplication).startup().
- App startup inside CodeApplication (ordered): ElectronIPCServer → resolveMachineId/resolveSqmId/resolveDevDeviceId → setupSharedProcess → initServices → ErrorTelemetry → ElectronAgentHostStarter + AgentHostProcessManager → initChannels → setupProtocolUrlHandlers → lifecycleMainService.phase=Ready → openFirstWindow → phase=AfterWindowOpen → afterWindowOpen → Eventually phase scheduled on idle (2.5–5s).
- Renderer workbench bring-up (ordered): workbench.desktop.main.ts barrel → electron-browser workbench.ts → BrowserMain/BrowserWorkbench open() → initServices → new Workbench(parent, options, serviceCollection) → startup() → initServices merges getSingletonServiceDescriptors() → Registry.as(WorkbenchExtensions.Workbench).start(accessor) and EditorFactory registry start → WorkbenchContextKeysHandler → renderWorkbench → createWorkbenchLayout → layout() → restore(lifecycleService).
- Workbench contributions are phase-gated: WorkbenchContributionsRegistry maps WorkbenchPhase.BlockStartup/BlockRestore/AfterRestored/Eventually onto ILifecycleService LifecyclePhase.Starting/Ready/Restored/Eventually and tracks per-contribution creation timings.
- Extension activation (ordered): an event such as file open triggers fileService.onWillActivateFileSystemProvider → AbstractExtensionService.activateByEvent(`onFileSystem:${scheme}`) → the LockableExtensionDescriptionRegistry finds matching extensions → ExtensionRunningLocationTracker picks a host → LazyCreateExtensionHostManager spawns the host via the 'extensionHostStarter' IPC channel → bootstrap-fork → extHostExtensionService loads the extension module and calls activate() with the API built by createApiFactoryAndRegisterActors.
- Extension API creation (ordered): ExtensionHostMain establishes IExtHostRpcService → ErrorHandler.installEarlyHandler forwards unexpected errors to MainThreadErrors → createApiFactoryAndRegisterActors(accessor) registers all ExtHostContext actors and returns the apiFactory that produces the `vscode` module namespace per-extension (gated by ExtensionsProposedApi for proposed APIs).
- Terminal spawn (ordered): terminal contrib in renderer → PtyHostService → ElectronPtyHostStarter launches a utility process running ptyHostMain.ts → PtyService accepts IPC requests on the 'localPty' channel → terminalProcess.ts spawns the shell (node-pty semantics), with LocalReconnectConstants supporting reconnection.
- CLI tunnel flow (ordered): `code tunnel` → clap parse in bin/code/main.rs → tunnels.rs → AppMutex(TUNNEL_CLI_LOCK_NAME) → singleton server (singleton_server) → DevTunnels host via @microsoft/dev-tunnels-equivalent Rust SDK → code_server/spawn of serve-web control server on CONTROL_PORT, with legal banner and machine_status reporting.
- Save flow (ordered): editor commands → ITextFileService.save → TextFileEditorModel.save → TextFileSaveParticipant chain (progress notification + participants like format/trim) → FileService.writeFile → DiskFileSystemProvider (direct in desktop; over LOCAL_FILE_SYSTEM_CHANNEL_NAME when proxied) → versioned write + backup integration via workingCopy services.
Testing signals
Unit tests are colocated in src/vs/*/test folders (2041 *.test.ts files under src/vs) and run with mocha in TDD style under three runners: inside the built Electron binary (scripts/test.sh → test/unit/electron/index.js), in real browsers via Playwright (test/unit/browser/index.js, npm run test-browser), and in plain node (npm run test-node). Integration tests exercise the extension host via vscode-test (test/integration, scripts/test-integration.sh), and a Playwright-driven smoke suite lives in test/smoke with a test/automation driver library. CI runs per-OS test workflows plus compile/hygiene, layers, and cyclic-dependency gates.
- Unit tests live next to sources in src/vs/**/test directories and use mocha with the tdd UI; npm run test-node runs mocha test/unit/node/index.js with --ui=tdd --timeout=5000.
- Browser unit tests run under real browsers via Playwright: test/unit/browser/index.js requires @playwright/test, spins a yaserver http server, and defaults to chromium+firefox+webkit.
- Electron unit tests run inside the built product: scripts/test.sh downloads Electron (npm run electron / .build/electron) then executes the binary against test/unit/electron/index.js with ELECTRON_ENABLE_LOGGING=1.
- Smoke tests in test/smoke are Playwright-based end-to-end tests driven by the test/automation package, launched via npm run smoketest which prelaunches, compiles test/smoke, then runs test/index.js.
- Extension integration tests run via vscode-test (npm run test-extension, scripts/test-integration.sh) with API surface exercised by the extensions/vscode-api-tests built-in test extension.
- CI gating: .github/workflows/pr.yml runs a 'Compile & Hygiene' job on self-hosted 1ES pools with node_modules caching; sibling workflows pr-darwin-test.yml, pr-linux-test.yml, pr-win32-test.yml and pr-node-modules.yml run per-OS tests; codeql.yml runs static analysis.
- Static quality gates are first-class scripts: hygiene (build/hygiene.ts via precommit), eslint (build/eslint.ts with local rules in .eslint-plugin-local), stylelint, valid-layers-check, check-cyclic-dependencies, define-class-fields-check, tsec-compile-check, and vscode-dts compile checks.
- Coverage: platform services and base utilities have deep unit coverage (e.g., src/vs/code/test covers cliArgs, bootstrapESM, partsSplash, sharedProcess contribs), but renderer UI contribs are comparatively under-unit-tested and rely on the smoke suite (inference from test distribution). (inferred)
- Repo conventions for tests are documented: prefer snapshot-style assert.deepStrictEqual over many assertions, don't stub globals — inject fakes via optional constructor params, and use --grep selectors for targeted runs (scripts/test.sh).
- Performance signals are treated as tests: perf.mark() instrumentation throughout startup, npm run perf (scripts/code-perf.js), plus dedicated chat perf/leak scripts (perf:chat, perf:chat-leak) and a chat-perf GitHub workflow.
Risk map
The largest blast radius is the IPC/channel surface: renderer and shared-process clients reach privileged main-process services over ~30 channels, so any renderer compromise (webview, extension UI) inherits capabilities like file IO, pty spawn, storage, and native host calls — mitigated by validatedIpcMain and sandboxing, but the surface is huge. Secrets have a deliberate weak fallback (plaintext encryption) and an in-memory storage flag. The main process performs privileged file writes (argv.json auto-creation, lockfiles) and spawns shells/extensions/agent processes. Remote debugging and proposed-API flags in argv.json lower security postures when enabled. Untested or thinly-tested areas include much of electron-main orchestration and many UI contribs.
- Renderer→main IPC is a broad privilege boundary: channels registered in initChannels include 'storage', 'nativeHost', 'localPty', 'webview', 'externalTerminal', 'extensionHostStarter' and LOCAL_FILE_SYSTEM_CHANNEL_NAME — validatedIpcMain exists to vet senders, so new channels must use it or they bypass sender validation.
- Secret storage can silently degrade: when no OS keyring is found, the user is offered 'Use weaker encryption' (plaintext) via secretStorageService, and argv.json's use-inmemory-secretstorage drops persistence entirely.
- The extension host executes arbitrary third-party extension code with Node.js capabilities; proposed APIs are gated by ExtensionsProposedApi and --enable-proposed-api in argv.json is a documented escape that can enable unstable surface globally or per-extension.
- Shell-out surface: PtyService/terminalProcess spawn arbitrary shells from user settings, externalTerminalService launches OS terminals, and the main process exposes 'externalTerminal' and localPty channels; task runners (contrib/tasks) execute workspace-defined commands — a classic workspace-trust risk mitigated by IWorkspaceTrustManagementService.
- argv.json is auto-created with comments and supports remote-debugging-port, js-flags, and enable-proposed-api — powerful persisted flags an attacker or misconfiguration could abuse; the file is parsed synchronously before app ready.
- Privileged custom schemes vscode-webview/vscode-file/vscode-remote-resource are registered with fetch/CORS/service-worker privileges before app ready; webview content is additionally isolated to a CDN base template in product.json (webviewContentExternalBaseUrlTemplate).
- Windows UNC paths are selectively allow-listed via addUNCHostToAllowlist for user-data and extension paths — a security-sensitive gate that would be easy to weaken accidentally in environment/path handling code.
- Telemetry collects PII-adjacent identifiers: resolveMachineId/resolveSqmId/resolveDevDeviceId plus getPiiPathsFromEnvironment and a large OSProxyConfig telemetry event enumerating proxy configuration states — all routed through shared-process appenders and controlled by TelemetryLevel.
- Import-barrel coupling is fragile: workbench.*.main.ts ordering determines singleton registration and contrib loading; the banner comment in workbench.web.main.ts and the 'do NOT register services here' note in workbench.ts indicate this has bitten contributors before.
- Single-instance lock + lockfile handling (claimInstance, mainLockfile unlink on shutdown) is a known-fragile area: onWillShutdown joins async lockfile deletion, and the Inno Setup mutex check can release the IPC server mid-startup — race-prone code with historically linked GitHub issues.
- Agent host processes (ElectronAgentHostStarter/AgentHostProcessManager, platform/agentHost) spawn utility processes that talk to external AI services; combined with AgentNetworkFilterService and MCP gateway, this is a new, fast-moving attack surface with sparse test coverage (inference). (inferred)
Extension points
VS Code is essentially a registry machine. Internal code plugs in through: (1) registerSingleton for DI services with eager/delayed instantiation; (2) the generic Registry.as() pattern for typed contribution registries; (3) WorkbenchContributionsRegistry keyed by lifecycle phase; (4) registerAction2/MenuId for commands+menus; (5) ConfigurationRegistry for settings schema; (6) ExtensionsRegistry/ExtensionPoint<T> which materializes the 59 declared contribution points in extensionPoints.json. External extensions plug in through package.json contributions plus the `vscode` API built per-extension by createApiFactoryAndRegisterActors, with proposed APIs gated by extensionsApiProposals.
- registerSingleton(id, ctor, InstantiationType.Eager|Delayed) in platform/instantiation/common/extensions.ts is how all shared services register; getSingletonServiceDescriptors() is consumed by Workbench.initServices to seed the ServiceCollection.
- The platform Registry (platform/registry/common/platform.ts) provides the add/as/knows primitive behind every contribution registry; workbench features call Registry.as<...>(SomeExtensionPointId) to contribute.
- ExtensionPoint<T>/ExtensionsRegistry in extensionsRegistry.ts implement package.json contribution points: handlers receive ExtensionPointUserDelta (added/removed) so contributions can hot-update when extensions install/uninstall.
- extensionPoints.json enumerates all 59 supported contribution points — including commands, menus, configuration, grammars, themes, languages, views/viewsContainers, notebooks, customEditors, debuggers, chatAgents/chatParticipants/chatSessions/chatSkills, languageModelTools, mcpServerDefinitionProviders, terminalQuickFixes and walkthroughs.
- Commands and menus are contributed via Action2/registerAction2 and MenuId from platform/actions/common/actions.ts — used inside the workbench itself (e.g., web.main.ts registers actions) as well as surfaced to extensions through the commands/menus extension points.
- Settings schema is an extension point: ConfigurationRegistry (platform/configuration/common/configurationRegistry.ts) accepts 'configuration' contributions which the layered ConfigurationService then resolves across default/policy/user/workspace/folder scopes.
- File system providers are an extension point: IFileService.registerProvider lets extensions (and core) mount arbitrary schemes, and the extension service auto-activates extensions on 'onFileSystem:<scheme>' events.
- The public extension API surface is generated from src/vscode-dts/vscode.d.ts (+ proposed d.ts files, compile-checked by npm run vscode-dts-compile-check) and materialized per-extension by createApiFactoryAndRegisterActors in extHost.api.impl.ts.
- Proposed/unstable APIs are an explicit extension-point gate: extensionsApiProposals.ts maintains allApiProposals which extensionsRegistry consults, and ExtensionsProposedApi enforces enablement per extension/product rules.
- Extension host placement is pluggable: ExtensionHostKind + ExtensionRunningLocationTracker + IExtensionHostKindPicker decide whether an extension runs in the local process host, a web worker host, or on the remote agent.
- Built-in extensions are themselves extension-point consumers: each extensions/*/package.json declares contributes blocks (grammars, themes, languages, commands) loaded through the same ExtensionsRegistry as third-party extensions.
- New IPC surfaces are added by registering channels: Server.registerChannel(name, channel) on ElectronIPCServer/NodeIPCServer/IPCServer — e.g., McpGatewayChannelName and NativeMcpDiscoveryHelperChannelName were added for MCP support.
Contributor handoff
Before editing, read .github/copilot-instructions.md (the canonical conventions doc referenced by AGENTS.md): tabs not spaces, DI rules (services only via constructor params, never IInstantiationService lookups later), strict disposable discipline (DisposableStore/MutableDisposable), nls.localize for all user strings, no cross-component storage-key access, prefer IEditorService for opening editors, and events are for broadcasting not control flow. Respect the layering (base→platform→editor→workbench; sessions may import workbench, not vice versa) enforced by valid-layers-check. New shared services go through registerSingleton in the right workbench.*.main.ts barrel — never in Workbench.initServices. Test with scripts/test.sh --grep for unit tests; use npm run typecheck-client or the watch tasks for validation, and transpile-client when you only need fresh output.
- Read .github/copilot-instructions.md first — it is the canonical agent doc (AGENTS.md just points to it) covering layers, DI rules, coding style, disposable rules, and validation strategy.
- Layer rule: vs/sessions may import vs/workbench but not vice versa; platform code must not import workbench; layering is machine-checked by npm run valid-layers-check (build/checker/layersChecker.ts) — run it when changing module dependencies.
- Service registration trap: Workbench.initServices has an explicit 'do NOT register services here' comment — use registerSingleton() in workbench.common.main.ts (or web/desktop main for platform-specific services) with InstantiationType.Delayed unless eager startup is required.
- Common-import rule: the banner in workbench.web.main.ts says add common imports to workbench.common.main.ts; import order in these barrels controls module side effects, so keep the regioned structure intact.
- ESM import convention: all in-repo imports use explicit '.js' extensions on TypeScript sources (e.g., '../../base/common/uri.js'); the codebase is 'type: module' and bootstrapped via bootstrapESM.
- Disposable discipline is enforced in review: register disposables immediately (DisposableStore/DisposableMap/MutableDisposable); don't register method-created disposables on the containing class to avoid leaks — return IDisposable to the caller instead.
- Unit tests: put tests in the sibling test/ folder of the layer (e.g., src/vs/platform/x/test), use mocha tdd describe/test style, run via scripts/test.sh --grep on desktop or npm run test-node / test-browser for the relevant suite.
- Validation hierarchy: prefer existing watch-task diagnostics; use npm run transpile-client when tests just need fresh output; npm run typecheck-client for broad src changes; npm run gulp compile-extensions for built-in extensions; avoid redundant typecheck+compile runs.
- User-facing strings must go through vs/nls (nls.localize/localize2) with placeholders, never concatenation; command/menu labels use title-case per the UI-label rules.
- Every file needs the Microsoft copyright header (MIT) — enforced by hygiene (build/hygiene.ts run as precommit).
- Do not read another component's storage keys to mutate its state — add a proper API instead; use IEditorService (not IEditorGroupsService.activeGroup.openEditor) to open editors so revealIfOpened/preserveFocus are honored.
- Perf convention: instrument startup paths with perf.mark('code/...') markers matching the existing naming scheme (code/willX/code/didX); thresholds like setGlobalLeakWarningThreshold(175) exist and tests will flag emitter leaks.
Languages
| Language | Files | Share of source |
|---|---|---|
| TypeScript | 13609 | 97% |
| JSON | 1422 | docs/config |
| YAML | 572 | docs/config |
| CSS | 495 | docs/config |
| Markdown | 347 | docs/config |
| JavaScript | 155 | 1% |
| HTML | 121 | docs/config |
| Rust | 88 | 1% |
Start reading here
Probable source entrypoint: src/ — inferred from the directory tree and manifest, not the upstream docs.
Source roots
src/ (1675 files)
Repository structure
| Top-level path | Files |
|---|---|
src/ | 1675 |
extensions/ | 1674 |
test/ | 216 |
.github/ | 143 |
cli/ | 89 |
scripts/ | 58 |
.eslint-plugin-local/ | 56 |
resources/ | 37 |
Docs found: AGENTS.mdCONTRIBUTING.mdREADME.md
Package
package.json — code-oss-dev v1.140.0, 80 declared dependencies.
@anthropic-ai/claude-agent-sdk@anthropic-ai/sdk@devcontainers/cli@eslint/compat@github/copilot-sdk@microsoft/1ds-core-js@microsoft/1ds-post-js@microsoft/dev-tunnels-connections@microsoft/dev-tunnels-contracts@microsoft/dev-tunnels-management@microsoft/dev-tunnels-ssh@microsoft/dev-tunnels-ssh-tcp
CI & config entrypoints
README.md— Repository readmeAGENTS.md— Agent instructions.github/workflows/chat-lib-package.yml— GitHub Actions workflow.github/workflows/chat-perf.yml— GitHub Actions workflow.github/workflows/codeql.yml— GitHub Actions workflow.github/workflows/component-fixtures.yml— GitHub Actions workflow.github/workflows/copilot-setup-steps.yml— GitHub Actions workflow.github/workflows/css-order-scan.yml— GitHub Actions workflow.github/workflows/monaco-editor.yml— GitHub Actions workflow.github/workflows/pr-darwin-test.yml— GitHub Actions workflow
Structural health signals
Average score 6.6/10 across 96 analyzed source files; 35 hotspots surfaced.
cli/src/tunnels/agent_host.rs— 2434 lines, score 5.2 (Large file, Long function/block)cli/src/tunnels/agent_host_registry.rs— 1591 lines, score 5.2 (Large file, Long function/block)cli/src/tunnels/control_server.rs— 1589 lines, score 5.2 (Large file, Long function/block)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
f6439326f6892026-09-22 — Update auto tiers descriptions (#337275)8bc9f99ded9e2026-09-22 — test: add WSL import failure diagnostics (#337242)f37673cbfdff2026-09-22 — SessionCustomizationDiscovery: print working directory on error (#337243)1cf23db66a552026-09-22 — agentHost: prevent duplicate Codex skills across sessions (#335475)b87fc44884072026-09-22 — Merge pull request #337254 from mrleemurray/mrleemurray/middle-amaranth-sparrow