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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ test-results.xml
vscode.lsif
vscode.db
/.profile-oss
/.vousoir-web-data
/.vousoir-dev-run
/cli/target
/cli/openssl
product.overrides.json
Expand Down
66 changes: 65 additions & 1 deletion build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,33 @@
.PARAMETER Archive
Also produce a .zip alongside the output folder.

.PARAMETER Installer
Also build an Inno Setup installer from the packaged folder. Adds a couple of
minutes on top of packaging. The installer is what registers the "Open with
Vousoir" Explorer context menu, file associations and the PATH entry; the plain
folder output registers nothing.

To get just the context menu against an existing folder build - no installer -
use scripts\vousoir-shell-integration.ps1 instead.

.PARAMETER InstallerTarget
user (default) installs to %LOCALAPPDATA%\Programs and needs no elevation.
system installs to Program Files and prompts for admin.

.EXAMPLE
.\build.ps1
.EXAMPLE
.\build.ps1 -NoMinify -Archive
.EXAMPLE
.\build.ps1 -Installer
#>
[CmdletBinding()]
param(
[ValidateSet('x64', 'arm64')][string]$Arch = 'x64',
[switch]$NoMinify,
[switch]$Archive
[switch]$Archive,
[switch]$Installer,
[ValidateSet('user', 'system')][string]$InstallerTarget = 'user'
)

$ErrorActionPreference = 'Stop'
Expand All @@ -59,6 +76,15 @@ if (-not (Test-Path (Join-Path $repoRoot 'node_modules'))) {
Fail "node_modules is missing - dependencies are not installed." "Run .\setup.ps1 first."
}

# Fail before the 45-minute packaging run, not after it.
$iscc = Join-Path $repoRoot 'node_modules\innosetup\bin\ISCC.exe'
if ($Installer -and -not (Test-Path $iscc)) {
Fail "-Installer needs the Inno Setup compiler, but $iscc is missing." @"
The 'innosetup' package should have come from npm ci. Reinstall it:
npm ci
"@
}

# Same space-free Node path the setup script establishes. Packaging shells out
# to native tooling, so the node-gyp-build spaces bug can bite here too.
$nodeExe = (Get-Command node).Source
Expand Down Expand Up @@ -114,6 +140,33 @@ if (-not (Test-Path $exe)) {
$sizeGb = [math]::Round((Get-ChildItem $outDir -Recurse -File -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum).Sum / 1GB, 2)

# --- Optional installer ----------------------------------------------------
$setupExe = $null
if ($Installer) {
# code.iss pulls tools\* out of the packaged folder without skipifsourcedoesntexist, and the
# packaging task above does not put them there - the inno-updater task does. Skipping this
# makes the Inno compile fail on a missing source file.
Write-Host ""
Write-Host "==> Staging updater tools: gulp vscode-win32-$Arch-inno-updater" -ForegroundColor Cyan
& $nodeExe $npmCli run gulp "vscode-win32-$Arch-inno-updater"
if ($LASTEXITCODE -ne 0) { Fail "Task 'vscode-win32-$Arch-inno-updater' failed." "" }
Write-Ok "tools staged"

Write-Host ""
Write-Host "==> Building installer: gulp vscode-win32-$Arch-$InstallerTarget-setup" -ForegroundColor Cyan
Write-Warn "A few minutes. Inno Setup recompresses the whole payload."

& $nodeExe $npmCli run gulp "vscode-win32-$Arch-$InstallerTarget-setup"
if ($LASTEXITCODE -ne 0) { Fail "Task 'vscode-win32-$Arch-$InstallerTarget-setup' failed." "" }

# gulpfile.vscode.win32.ts writes into .build\win32-<arch>\<target>-setup.
$setupDir = Join-Path $repoRoot ".build\win32-$Arch\$InstallerTarget-setup"
$setupExe = Get-ChildItem $setupDir -Filter *.exe -ErrorAction SilentlyContinue |
Sort-Object Length -Descending | Select-Object -First 1
if (-not $setupExe) { Fail "The setup task reported success but no .exe is in $setupDir." "" }
Write-Ok "installer built"
}

# --- Optional archive ------------------------------------------------------
$zipPath = $null
if ($Archive) {
Expand All @@ -133,6 +186,17 @@ Write-Host ""
Write-Host " Output $outDir ($sizeGb GB)" -ForegroundColor White
if ($zipPath) { Write-Host " Archive $zipPath" -ForegroundColor White }
Write-Host " Run $exe" -ForegroundColor White
if ($setupExe) {
Write-Host " Setup $($setupExe.FullName) ($([math]::Round($setupExe.Length / 1MB)) MB, $InstallerTarget install)" -ForegroundColor White
Write-Host ""
Write-Host " 'Open with Vousoir' for files and folders is checked by default in the" -ForegroundColor DarkGray
Write-Host " installer. On Windows 11 it appears under 'Show more options'." -ForegroundColor DarkGray
} else {
Write-Host ""
Write-Host " This folder registers nothing with Windows. For the Explorer context menu:" -ForegroundColor DarkGray
Write-Host " .\scripts\vousoir-shell-integration.ps1 (no installer, no elevation)" -ForegroundColor DarkGray
Write-Host " .\build.ps1 -Installer (full installer)" -ForegroundColor DarkGray
}
Write-Host ""
Write-Host " Note: this build is UNSIGNED. Signed installers are out of scope" -ForegroundColor DarkGray
Write-Host " for v1 (work order section 10). Windows SmartScreen will warn on" -ForegroundColor DarkGray
Expand Down
11 changes: 1 addition & 10 deletions build/buildfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@ export const workbenchDesktop = [
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
createModuleDescription('vs/platform/localTranscription/node/localTranscriptionMain'),
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
createModuleDescription('vs/platform/agentHost/node/agentHostMain'),
createModuleDescription('vs/platform/agentHost/node/diffWorkerMain'),
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
createModuleDescription('vs/workbench/workbench.desktop.main'),
createModuleDescription('vs/sessions/sessions.desktop.main')
createModuleDescription('vs/workbench/workbench.desktop.main')
];

export const workbenchWeb = createModuleDescription('vs/workbench/workbench.web.main.internal');

export const sessionsWeb = createModuleDescription('vs/sessions/sessions.web.main.internal');

export const keyboardMaps = [
createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'),
createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin'),
Expand All @@ -48,7 +43,6 @@ export const code = [
createModuleDescription('vs/code/node/cliProcessMain'),
createModuleDescription('vs/code/electron-utility/sharedProcess/sharedProcessMain'),
createModuleDescription('vs/code/electron-browser/workbench/workbench'),
createModuleDescription('vs/sessions/electron-browser/sessions'),
];

export const codeWeb = createModuleDescription('vs/code/browser/workbench/workbench');
Expand All @@ -59,8 +53,6 @@ export const codeServer = [
createModuleDescription('vs/workbench/api/node/extensionHostProcess'),
createModuleDescription('vs/platform/files/node/watcher/watcherMain'),
createModuleDescription('vs/platform/terminal/node/ptyHostMain'),
createModuleDescription('vs/platform/agentHost/node/agentHostMain'),
createModuleDescription('vs/platform/agentHost/node/diffWorkerMain'),
];

export const entrypoint = createModuleDescription;
Expand All @@ -76,7 +68,6 @@ const buildfile = {
workerBackgroundTokenization,
workbenchDesktop,
workbenchWeb,
sessionsWeb,
keyboardMaps,
code,
codeWeb,
Expand Down
25 changes: 9 additions & 16 deletions build/gulpfile.vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,10 @@ const vscodeResourceIncludes = [

// Workbench
'out-build/vs/code/electron-browser/workbench/workbench.html',
'out-build/vs/sessions/electron-browser/sessions.html',

// Electron Preload
'out-build/vs/base/parts/sandbox/electron-browser/preload.js',
'out-build/vs/base/parts/sandbox/electron-browser/preload-aux.js',
'out-build/vs/platform/browserView/electron-browser/preload-browserView.js',

// Node Scripts
'out-build/vs/base/node/{terminateProcess.sh,cpuUsage.sh,ps.sh}',
Expand All @@ -96,13 +94,6 @@ const vscodeResourceIncludes = [
// Welcome
'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}',

// Sessions
'out-build/vs/sessions/contrib/chat/browser/media/*.svg',
'out-build/vs/sessions/contrib/welcome/browser/media/*.svg',
'out-build/vs/sessions/contrib/welcome/browser/media/themePreviews/*.svg',
'out-build/vs/sessions/prompts/*.prompt.md',
'out-build/vs/sessions/skills/**/SKILL.md',

// Extensions
'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}',
'out-build/vs/workbench/services/extensionManagement/common/media/*.{svg,png}',
Expand Down Expand Up @@ -267,11 +258,7 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
'vs/workbench/workbench.desktop.main.css',
'vs/workbench/api/node/extensionHostProcess.js',
'vs/code/electron-browser/workbench/workbench.html',
'vs/code/electron-browser/workbench/workbench.js',
'vs/sessions/sessions.desktop.main.js',
'vs/sessions/sessions.desktop.main.css',
'vs/sessions/electron-browser/sessions.html',
'vs/sessions/electron-browser/sessions.js'
'vs/code/electron-browser/workbench/workbench.js'
]);

const src = gulp.src(out + '/**', { base: '.' })
Expand Down Expand Up @@ -529,7 +516,13 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
result = es.merge(result, gulp.src('.build/policies/win32/**', { base: '.build/policies/win32' })
.pipe(rename(f => f.dirname = `policies/${f.dirname}`)));

if (quality === 'stable' || quality === 'insider') {
// The MSIX sparse package exists only to host the Windows 11 modern context menu, which
// needs Microsoft's signed explorer-command DLL and the CLSID that identifies it.
// Upstream gated this on quality alone because its stable/insider builds always carry
// `win32ContextMenu`; Vousoir is quality "stable" without it, so gate on the CLSID
// itself. Without this the line below dereferences undefined and packaging dies.
const win32ContextMenu = (product as { win32ContextMenu?: Record<string, { clsid: string }> }).win32ContextMenu;
if ((quality === 'stable' || quality === 'insider') && win32ContextMenu?.[arch]) {
result = es.merge(result, gulp.src('.build/win32/appx/**', { base: '.build/win32' }));
const rawVersion = version.replace(/-\w+$/, '').split('.');
const appxVersion = `${rawVersion[0]}.0.${rawVersion[1]}.${rawVersion[2]}`;
Expand All @@ -541,7 +534,7 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
.pipe(replace('@@ApplicationIdShort@@', product.win32RegValueName))
.pipe(replace('@@ApplicationExe@@', product.nameShort + '.exe'))
.pipe(replace('@@FileExplorerContextMenuID@@', quality === 'stable' ? 'OpenWithCode' : 'OpenWithCodeInsiders'))
.pipe(replace('@@FileExplorerContextMenuCLSID@@', (product as { win32ContextMenu?: Record<string, { clsid: string }> }).win32ContextMenu![arch].clsid))
.pipe(replace('@@FileExplorerContextMenuCLSID@@', win32ContextMenu[arch].clsid))
.pipe(replace('@@FileExplorerContextMenuDLL@@', `${quality === 'stable' ? 'code' : 'code_insider'}_explorer_command_${arch}.dll`))
.pipe(rename(f => f.dirname = `appx/manifest`)));
}
Expand Down
1 change: 0 additions & 1 deletion build/gulpfile.vscode.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ const vscodeWebEntryPoints = [
buildfile.workerBackgroundTokenization,
buildfile.keyboardMaps,
buildfile.workbenchWeb,
buildfile.sessionsWeb,
].flat();

/**
Expand Down
13 changes: 8 additions & 5 deletions build/gulpfile.vscode.win32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,17 @@ function buildWin32Setup(arch: string, target: string): task.CallbackTask {
Quality: quality
};

if (quality === 'stable' || quality === 'insider') {
// Defining AppxPackageName switches code.iss onto the Windows 11 modern context menu: it
// then expects `appx\*.appx` in the packaged output and stops writing the legacy verbs.
// That package only exists when product.json declares a `win32ContextMenu` CLSID (see
// gulpfile.vscode.ts). Gating on quality alone, as upstream does, would make Inno fail on
// missing appx sources and leave a Vousoir install with no context menu at all.
const ctxMenu = (product as { win32ContextMenu?: Record<string, { clsid: string }> }).win32ContextMenu;
if ((quality === 'stable' || quality === 'insider') && ctxMenu && ctxMenu[arch]) {
definitions['AppxPackage'] = `${quality === 'stable' ? 'code' : 'code_insider'}_${arch}.appx`;
definitions['AppxPackageDll'] = `${quality === 'stable' ? 'code' : 'code_insider'}_explorer_command_${arch}.dll`;
definitions['AppxPackageName'] = `${product.win32AppUserModelId}`;
const ctxMenu = (product as { win32ContextMenu?: Record<string, { clsid: string }> }).win32ContextMenu;
if (ctxMenu && ctxMenu[arch]) {
definitions['FileExplorerContextMenuCLSID'] = ctxMenu[arch].clsid;
}
definitions['FileExplorerContextMenuCLSID'] = ctxMenu[arch].clsid;
}

fs.writeFileSync(productJsonPath, JSON.stringify(productJson, undefined, '\t'));
Expand Down
1 change: 0 additions & 1 deletion build/lib/mangle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ const skippedExportMangledFiles = [
buildfile.workerBackgroundTokenization,
buildfile.workbenchDesktop,
buildfile.workbenchWeb,
buildfile.sessionsWeb,
buildfile.code,
buildfile.codeWeb
].flat().map(x => x.name),
Expand Down
24 changes: 2 additions & 22 deletions build/next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,17 @@ const desktopWorkerEntryPoints = [
// Desktop workbench and code entry points
const desktopEntryPoints = [
'vs/workbench/workbench.desktop.main',
'vs/sessions/sessions.desktop.main',
'vs/workbench/contrib/debug/node/telemetryApp',
'vs/platform/files/node/watcher/watcherMain',
'vs/platform/localTranscription/node/localTranscriptionMain',
'vs/platform/terminal/node/ptyHostMain',
'vs/platform/agentHost/node/agentHostMain',
'vs/platform/agentHost/node/diffWorkerMain',
'vs/workbench/api/node/extensionHostProcess',
];

const codeEntryPoints = [
'vs/code/node/cliProcessMain',
'vs/code/electron-utility/sharedProcess/sharedProcessMain',
'vs/code/electron-browser/workbench/workbench',
'vs/sessions/electron-browser/sessions',
];

// Web entry points (used in server-web and vscode-web)
Expand All @@ -121,9 +117,7 @@ const webEntryPoints = [
];

// Additional web-only entry points (CDN build only, not in server-web)
const webOnlyEntryPoints = [
'vs/sessions/sessions.web.main.internal',
];
const webOnlyEntryPoints: string[] = [];

const keyboardMapEntryPoints = [
'vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux',
Expand All @@ -136,8 +130,6 @@ const serverEntryPoints = [
'vs/workbench/api/node/extensionHostProcess',
'vs/platform/files/node/watcher/watcherMain',
'vs/platform/terminal/node/ptyHostMain',
'vs/platform/agentHost/node/agentHostMain',
'vs/platform/agentHost/node/diffWorkerMain',
];

// Bootstrap files per target
Expand Down Expand Up @@ -214,8 +206,6 @@ function getCssBundleEntryPointsForTarget(target: BuildTarget): Set<string> {
return new Set([
'vs/workbench/workbench.desktop.main',
'vs/code/electron-browser/workbench/workbench',
'vs/sessions/sessions.desktop.main',
'vs/sessions/electron-browser/sessions',
]);
case 'server':
return new Set(); // Server has no UI
Expand All @@ -227,7 +217,6 @@ function getCssBundleEntryPointsForTarget(target: BuildTarget): Set<string> {
case 'web':
return new Set([
'vs/workbench/workbench.web.main.internal',
'vs/sessions/sessions.web.main.internal',
]);
default:
throw new Error(`Unknown target: ${target}`);
Expand All @@ -246,9 +235,7 @@ const commonResourcePatterns = [

// SVGs referenced from CSS (needed for transpile/dev builds where CSS is copied as-is)
'vs/workbench/browser/media/code-icon.svg',
'vs/workbench/browser/parts/editor/media/letterpress*.svg',
'vs/sessions/contrib/chat/browser/media/*.svg',
'vs/sessions/contrib/welcome/browser/media/themePreviews/*.svg'
'vs/workbench/browser/parts/editor/media/letterpress*.svg'
];

// Resources for desktop target
Expand All @@ -258,8 +245,6 @@ const desktopResourcePatterns = [
// HTML
'vs/code/electron-browser/workbench/workbench.html',
'vs/code/electron-browser/workbench/workbench-dev.html',
'vs/sessions/electron-browser/sessions.html',
'vs/sessions/electron-browser/sessions-dev.html',
'vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html',
'vs/workbench/contrib/webview/browser/pre/*.html',

Expand Down Expand Up @@ -292,10 +277,6 @@ const desktopResourcePatterns = [
'vs/workbench/services/extensionManagement/common/media/*.png',
'vs/workbench/browser/parts/editor/media/*.png',
'vs/workbench/contrib/debug/browser/media/*.png',

// Sessions - built-in prompts and skills
'vs/sessions/prompts/*.prompt.md',
'vs/sessions/skills/**/SKILL.md',
];

// Resources for server target (minimal - no UI)
Expand Down Expand Up @@ -490,7 +471,6 @@ async function copyFile(srcPath: string, destPath: string): Promise<void> {
const desktopStandaloneFiles = [
'vs/base/parts/sandbox/electron-browser/preload.ts',
'vs/base/parts/sandbox/electron-browser/preload-aux.ts',
'vs/platform/browserView/electron-browser/preload-browserView.ts',
];

async function compileStandaloneFiles(outDir: string, doMinify: boolean, target: BuildTarget): Promise<void> {
Expand Down
Loading
Loading