Files
maka/apps/desktop/electron-builder.config.mjs
agent-radar 7be535059e
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 19:05:14 +08:00

309 lines
12 KiB
JavaScript

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, join } from 'node:path';
import {
resolveDesktopBuildVersion,
resolveRuntimeHostSetupPackage,
} from '../../scripts/desktop-nightly.mjs';
import { workspaceReleaseManifest } from '../../scripts/release-cli-file-policy.mjs';
import { resolveProductManifestIdentity } from '../../scripts/product-release-identity.mjs';
function readManifest(relativePath) {
return JSON.parse(readFileSync(new URL(relativePath, import.meta.url), 'utf8'));
}
// Some license files below ship inside third-party packages that apps/desktop
// depends on (electron, @fontsource-variable/geist*). Locate each package by
// resolving its manifest rather than assuming its node_modules location:
// `../../node_modules/<pkg>` only resolves when the installer hoists these
// packages to the workspace root, but they are declared in apps/desktop, not
// the root. electron-builder logs a warning and still exits 0 when a `from`
// path is missing, so a non-hoisting layout would silently drop the notices
// (verify-packaged-app.mjs then fails far from the cause). resolve() finds the
// package wherever the installer placed it — hoisted or nested.
const require = createRequire(import.meta.url);
function resolvePackageFile(packageName, relativePath) {
return join(dirname(require.resolve(`${packageName}/package.json`)), relativePath);
}
async function stageReleaseManifests({ packager }) {
const stage = await packager.info.tempDirManager.createTempDir({
prefix: 'maka-release-manifests',
});
for (const name of ['mcp', 'runtime', 'runtime-host']) {
const directory = join(stage, name);
mkdirSync(directory, { recursive: true });
writeFileSync(
join(directory, 'package.json'),
`${JSON.stringify(workspaceReleaseManifest(readManifest(`../../packages/${name}/package.json`)), null, 2)}\n`,
);
}
packager.config.files.push({ from: stage, to: 'node_modules/@maka' });
}
const rootManifest = readManifest('../../package.json');
const { runtimeHostSetupPackage } = resolveProductManifestIdentity({
rootManifest,
desktopManifest: readManifest('./package.json'),
cliManifest: readManifest('../../packages/cli/package.json'),
});
const baseDesktopBuilderConfig = {
appId: 'com.maka.desktop',
productName: 'Maka',
artifactName: 'Maka-${version}-mac-${arch}.${ext}',
asar: true,
beforePack: stageReleaseManifests,
extraMetadata: { runtimeHostSetupPackage, makaUpdateChannel: 'release' },
directories: {
output: 'release',
},
// `files` names what to include; the production dependency closure of
// `package.json` comes along automatically. Renderer-only packages are kept
// out of that closure by living in `devDependencies` — vite bundles them into
// `dist-renderer`, so a second copy of their sources in `app.asar` is never
// loaded. A hand-written exclude list was tried first and could not hold: it
// has to name every transitive package too, and it silently went stale.
//
// `@xterm/headless` stays a dependency on purpose — `@maka/runtime` imports
// it for the PTY stack, so only the renderer-side xterm packages moved.
files: [
'dist/**/*',
'dist-renderer/**/*',
'package.json',
'!node_modules/@maka/{mcp,runtime,runtime-host}/package.json',
'!**/__tests__/**',
// FakeBackend and the Desktop E2E candidate bootstrap live under
// `test-only/`; they must not reach a packaged app.
'!**/test-only/**',
// `build:main` emits renderer sources as tsc side-files so main's tests can
// import a few helpers. The main process reaches exactly one of them at
// runtime — the cursor overlay engine — while the rest import `react`,
// `@maka/ui` and `@astryxdesign/core`, which the renderer now bundles
// instead of shipping under `node_modules`. Shipping those files would put
// ESM in the archive whose static imports cannot resolve.
'!dist/renderer/**',
'dist/renderer/computer-use-overlay/**',
],
extraResources: [
{
from: 'bundled-tools.json',
to: 'bundled-tools.json',
},
{
// The app icon is read at runtime by the BrowserWindow `icon` option
// and by the permission-overlay card, and `files` above does not carry
// `assets/`. Electron reports the missing file as an empty image rather
// than an error, so without this the packaged app just draws no window
// icon; `assertPackagedResources` requires it on current builds.
from: 'assets',
to: 'assets',
},
{
// Menu bar status item art. Without this the packaged app resolves an
// empty NativeImage and Electron silently shows no icon at all.
from: 'resources/status',
to: 'status',
},
{
from: 'resources/workers/filesystem-worker.js',
to: 'workers/filesystem-worker.js',
},
{
from: '../../native/runtime-host-peer/target/release/maka_runtime_host_peer.node',
to: 'runtime-host-peer/maka_runtime_host_peer.node',
},
{
from: '../../packages/cli/RUNTIME_HOST_PEER_THIRD_PARTY_NOTICES.txt',
to: 'licenses/runtime-host-peer/THIRD_PARTY_NOTICES.txt',
},
...(process.platform === 'win32'
? [
{
from: 'resources/windows-sandbox/maka-windows-sandbox.exe',
to: 'windows-sandbox/maka-windows-sandbox.exe',
},
{
from: 'resources/licenses/cargo/THIRD_PARTY_NOTICES.txt',
to: 'licenses/cargo/THIRD_PARTY_NOTICES.txt',
},
]
: []),
{
from: '../../LICENSE',
to: 'licenses/maka/LICENSE',
},
{
from: '../../NOTICE',
to: 'licenses/maka/NOTICE',
},
{
// Incubator policy requires every release archive to carry a DISCLAIMER
// or DISCLAIMER-WIP. Shipping it beside LICENSE and NOTICE is what makes
// the repository-root file reach the DMG, the ZIP and the Windows
// installer; `assertPackagedResources` then requires it on both paths.
from: '../../DISCLAIMER-WIP',
to: 'licenses/maka/DISCLAIMER-WIP',
},
{
from: resolvePackageFile('electron', 'dist/LICENSE'),
to: 'licenses/electron/LICENSE',
},
{
from: resolvePackageFile('electron', 'dist/LICENSES.chromium.html'),
to: 'licenses/electron/LICENSES.chromium.html',
},
{
from: 'resources/licenses/npm/THIRD_PARTY_NOTICES.txt',
to: 'licenses/npm/THIRD_PARTY_NOTICES.txt',
},
{
from: 'src/renderer/public/THIRD_PARTY_LICENSES.txt',
to: 'licenses/renderer/THIRD_PARTY_LICENSES.txt',
},
{
from: resolvePackageFile('@fontsource-variable/geist', 'LICENSE'),
to: 'licenses/renderer/GEIST_LICENSE.txt',
},
{
from: resolvePackageFile('@fontsource-variable/geist-mono', 'LICENSE'),
to: 'licenses/renderer/GEIST_MONO_LICENSE.txt',
},
{
from: 'resources/licenses/renderer/ANT_DESIGN_ICONS_LICENSE.txt',
to: 'licenses/renderer/ANT_DESIGN_ICONS_LICENSE.txt',
},
{
from: 'resources/licenses/renderer/TDESIGN_ICONS_LICENSE.txt',
to: 'licenses/renderer/TDESIGN_ICONS_LICENSE.txt',
},
{
from: 'resources/licenses/renderer/ALLOGO_LICENSE.txt',
to: 'licenses/renderer/ALLOGO_LICENSE.txt',
},
{
from: 'resources/licenses/renderer/SEMI_ICONS_LICENSE.txt',
to: 'licenses/renderer/SEMI_ICONS_LICENSE.txt',
},
{
from: '../../LICENSE',
to: 'licenses/renderer/MINGCUTE_APACHE_LICENSE.txt',
},
{
// Vendored copy of the installed tarball's LICENSE (CC0-1.0): the
// package hoists to different node_modules depths across majors.
from: 'resources/licenses/renderer/SIMPLE_ICONS_LICENSE.md',
to: 'licenses/renderer/SIMPLE_ICONS_LICENSE.md',
},
],
mac: {
target: [
{ target: 'dmg', arch: ['arm64'] },
{ target: 'zip', arch: ['arm64'] },
],
category: 'public.app-category.productivity',
// The bundle icon is what Finder, Launchpad and the installer show, and
// none of those run our code — so it cannot follow the user's choice and
// has to be the shipped default. `assets/icon.png` is the original mascot
// mark, which is still selectable as the `default` id but is no longer the
// default; pointing the bundle at it would leave every surface outside the
// running app on the old artwork. Kept in step with `DEFAULT_APP_ICON` by
// a test in scripts/verify-packaged-app-icons.test.mjs.
icon: 'assets/app-icons/sky.png',
forceCodeSigning: true,
hardenedRuntime: true,
notarize: true,
entitlements: 'build/entitlements.mac.plist',
entitlementsInherit: 'build/entitlements.mac.inherit.plist',
extendInfo: {
NSAppleEventsUsageDescription:
'Maka may automate other applications when you explicitly run an agent task.',
},
},
dmg: {
title: 'Maka Installer',
// Relative to electron-builder's default buildResources directory (build/).
background: 'background.png',
window: { width: 540, height: 380 },
iconSize: 112,
iconTextSize: 16,
contents: [
{ x: 130, y: 190, type: 'file' },
{ x: 410, y: 190, type: 'link', path: '/Applications' },
],
sign: true,
// Stapling the notarization ticket after electron-builder exits changes the
// DMG bytes. macOS updates use the ZIP, so do not publish a stale DMG hash
// in latest-mac.yml.
writeUpdateInfo: false,
},
win: {
target: [
{ target: 'nsis', arch: ['x64'] },
{ target: 'zip', arch: ['x64'] },
],
artifactName: 'Maka-${version}-win-${arch}.${ext}',
// Same reason as `mac.icon` above: the .exe, the installer and the
// shortcut are drawn by the OS from this file, not by us.
icon: 'assets/app-icons/sky.png',
// No Authenticode certificate yet. Being unsigned is the absence of one:
// electron-builder skips signing when no certificate is configured, and
// `forceCodeSigning` is left off so that skip is not an error. Nothing here
// turns update signature verification off, because nothing has to: without a
// certificate there is no publisher name to put in app-update.yml, and
// electron-updater skips the check when there is none. Adding a certificate
// is then the whole change — the verification follows it.
},
nsis: {
// Everything stays at the one-click per-user defaults; the include only
// adds the Abort-path pre-upgrade backup/rollback (and its test-only
// deterministic failpoint) — see build/installer.nsh for the mechanism
// and its exit-code contract with verify-windows-installer-rollback.mjs.
include: 'build/installer.nsh',
},
publish: [
{
provider: 'github',
owner: 'apache',
repo: 'maka',
},
],
};
export function resolveDesktopBuilderConfig(environment = process.env) {
const nightlyVersion = environment.MAKA_DESKTOP_NIGHTLY_VERSION?.trim();
if (!nightlyVersion) return baseDesktopBuilderConfig;
const version = resolveDesktopBuildVersion(rootManifest.version, environment);
return {
...baseDesktopBuilderConfig,
extraMetadata: {
...baseDesktopBuilderConfig.extraMetadata,
version,
runtimeHostSetupPackage: resolveRuntimeHostSetupPackage(rootManifest.version, environment),
makaUpdateChannel: 'nightly',
},
publish: [{ provider: 'github', owner: 'apache', repo: 'maka', channel: 'dev' }],
};
}
export default resolveDesktopBuilderConfig();