Files
orca/config/electron-builder.config.cjs
T
OrcaWinandOrcaWin 7d6603aa17 [comment audit] Complete repository-wide comment cleanup (#33249)
* [comment audit] Align legacy failure-read counts with cached display

* [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci]

* [comment audit] Condense shared generation, path and preview comments [skip ci]

* [comment audit] Condense host, file and Git contract rationale [skip ci]

* [comment audit] Tighten Git lifecycle and provider contract comments [skip ci]

* [comment audit] Clarify shared host authority and launch isolation [skip ci]

* [comment audit] simplify local access mobile and native chat contracts [skip ci]

* [comment audit] simplify native chat presentation and state contracts [skip ci]

* [comment audit] simplify native runtime and provider contracts [skip ci]

* [comment audit] simplify migration and orchestration contracts [skip ci]

* [comment audit] simplify plugin trust and process capture rationale [skip ci]

* [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci]

* [comment audit] clarify remote recovery and launch wire rationale [skip ci]

* [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci]

* [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci]

* [comment audit] clarify sidebar, skill and SSH invariants [skip ci]

* [comment audit] condense structured chat delivery and timing rationale [skip ci]

* [comment audit] condense terminal replay and telemetry invariants [skip ci]

* [comment audit] clarify launch permission and terminal delivery rationale [skip ci]

* [comment audit] clarify workspace ownership and layout contracts [skip ci]

* [comment audit] wait for fitted and painted SSH terminal links

* [comment audit] clarify layout persistence and session ownership [skip ci]

* [comment audit] clarify host routing and workspace lifecycle contracts [skip ci]

* [comment audit] clarify startup persistence and app lifetime comments [skip ci]

* [comment audit] clarify recovery and activity boundaries [skip ci]

* [comment audit] condense activity and artifact invariants [skip ci]

* [comment audit] condense automation authority contracts [skip ci]

* [comment audit] simplify automation scheduling and history contracts [skip ci]

* [comment audit] clarify browser chrome and annotation lifecycles [skip ci]

* [comment audit] clarify browser routing and retained guest ownership [skip ci]

* [comment audit] clarify browser recovery and document ownership comments [skip ci]

* [comment audit] restore hosted runners required by native IME fixtures

* [comment audit] shorten preview, palette and dashboard invariants [skip ci]

* [comment audit] clarify terminal preview, dashboard and retention comments [skip ci]

* [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci]

* [comment audit] shorten rich-text and combined-diff ownership comments [skip ci]

* [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci]

* [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci]

* [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci]

* [comment audit] clarify rich Markdown source and selection safeguards [skip ci]

* [comment audit] clarify editor loading and emulator stream lifetimes [skip ci]

* [comment audit] trim emulator and feature tour narration [skip ci]

* [comment audit] clarify floating workspace and GitHub cache ownership [skip ci]

* [comment audit] trim provider controls and Linear filter explanations [skip ci]

* [comment audit] clarify pairing and chat resume lifetimes [skip ci]

* [comment audit] clarify chat delivery and transcript lifetimes [skip ci]

* [comment audit] clarify session options and host-owned status [skip ci]

* [comment audit] clarify draft durability and live-status precedence [skip ci]

* [comment audit] Trim chat send and model ownership explanations [skip ci]

* [comment audit] Shorten transcript ownership and send recovery comments [skip ci]

* [comment audit] Simplify native chat composer and transcript hook comments [skip ci]

* [comment audit] Shorten native chat scroll and structured session explanations [skip ci]

* [comment audit] Trim workspace picker and onboarding commentary [skip ci]

* [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci]

* [comment audit] Trim sidebar and session history explanations [skip ci]

* [comment audit] Condense session resume and review checks comments [skip ci]

* [comment audit] Shorten checks state and file explorer refresh comments [skip ci]

* [comment audit] Trim plugin bridge and source-control action rationale [skip ci]

* [comment audit] Trim source-control listing and review rationale [skip ci]

* [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci]

* [comment audit] Condense Settings account and appearance rationale [skip ci]

* [comment audit] Trim pairing and repository Settings explanations [skip ci]

* [comment audit] Condense Settings search SSH and terminal safeguards [skip ci]

* [comment audit] Shorten Settings voice and provider ownership comments [skip ci]

* [comment audit] Condense Settings draft persistence and host-state rationale [skip ci]

* [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci]

* [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci]

* [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci]

* [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci]

* [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci]

* [comment audit] Prune focus-read baseline after comment cleanup

* [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci]

* [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci]

* [comment audit] Clarify viewport geometry and skill update safeguards [skip ci]

* [comment audit] Tighten skill inventory, usage and host status comments [skip ci]

* [comment audit] Clarify usage ownership and resource kill safeguards [skip ci]

* [comment audit] Tighten tab selection, rename and search contracts [skip ci]

* [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci]

* [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci]

* [comment audit] Tighten provider loading and terminal recovery comments [skip ci]

* [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci]

* [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci]

* [comment audit] Tighten PTY startup and replay explanations [skip ci]

* [comment audit] Clarify PTY identity and delivery ownership [skip ci]

* [comment audit] Shorten remote reconnect and input replay rationale [skip ci]

* [comment audit] Condense terminal parking clipboard and file link comments [skip ci]

* [comment audit] Clarify IME ownership and trim trace history [skip ci]

* [comment audit] Shorten pane recovery and parked watcher explanations [skip ci]

* [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci]

* [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci]

* [comment audit] Trim renderer lifecycle and menu rationale [skip ci]

* [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci]

* [comment audit] Clarify renderer hook evidence and source ownership [skip ci]

* [comment audit] Tighten IPC ownership and reconnect explanations [skip ci]

* [comment audit] Trim renderer focus, paste and attention comments [skip ci]

* [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci]

* [comment audit] Trim agent launch, resume and ownership commentary [skip ci]

* [comment audit] Shorten account, browser and editor comments [skip ci]

* [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci]

* [comment audit] Condense launch recovery and editor tokenization comments [skip ci]

* [comment audit] Condense workspace selection and terminal pane rationale [skip ci]

* [comment audit] Condense terminal fitting and rendering recovery comments [skip ci]

* [comment audit] Condense terminal input and host routing explanations [skip ci]

* [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci]

* [comment audit] Condense structured launch and terminal link explanations [skip ci]

* [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci]

* [comment audit] Condense session persistence and workspace activation rationale [skip ci]

* [comment audit] Condense workspace routing and browser ownership rationale [skip ci]

* [comment audit] Condense mirror recovery and layout authority rationale [skip ci]

* [comment audit] Condense runtime transport and file safety rationale [skip ci]

* [comment audit] Condense runtime graph and structured session rationale [skip ci]

* [comment audit] Condense browser creation and remote tab recovery rationale [skip ci]

* [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci]

* [comment audit] Condense frame, startup and provider cache rationale [skip ci]

* [comment audit] Condense host twin and agent lifecycle rationale [skip ci]

* [comment audit] Condense browser authority and editor cleanup rationale [skip ci]

* [comment audit] Condense editor buffer identity and review cache rationale [skip ci]

* [comment audit] Condense provider lifetime and repository ownership rationale [skip ci]

* [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci]

* [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci]

* [comment audit] Condense cleanup ownership and listing admission rationale [skip ci]

* [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci]

* [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci]

* [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci]

* [comment audit] Condense cloud rollout and assignment safety rationale [skip ci]

* [comment audit] Condense relay session and database recovery rationale [skip ci]

* [comment audit] Condense relay placement and protocol compatibility rationale [skip ci]

* [comment audit] Condense build and packaging constraints [skip ci]

* [comment audit] Condense CI gates and validation isolation rationale [skip ci]

* [comment audit] Condense catalog identity and browser validation rationale [skip ci]

* [comment audit] Condense mobile browser and frame-budget rationale [skip ci]

* [comment audit] Shorten mobile route and browser test explanations [skip ci]

* [comment audit] Condense editor and session seam test rationale [skip ci]

* [comment audit] Trim session and terminal closure history [skip ci]

* [comment audit] Shorten terminal browser and census explanations [skip ci]

* [comment audit] Preserve root-only E2E diagnostic baseline

* [comment audit] Condense mobile seam and HTML preview test rationale [skip ci]

* [comment audit] Condense preview instrumentation and render harness rationale [skip ci]

* [comment audit] Condense bundle contracts and native-build constraints [skip ci]

* [comment audit] Shorten native packaging and CI routing rationale [skip ci]

* [comment audit] Condense release tooling and benchmark constraints [skip ci]

* [comment audit] Condense packaging and platform gate rationale [skip ci]

* [comment audit] Shorten mobile route and history rationale [skip ci]

* [comment audit] Condense mobile browser and component rationale [skip ci]

* [comment audit] Shorten drawer and workspace-form rationale [skip ci]

* [comment audit] Trim mobile review and editor-document explanations [skip ci]

* [comment audit] Condense editor lifecycle and Markdown explanations [skip ci]

* [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci]

* [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci]

* [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci]

* [comment audit] Condense bridge stream, native request and audio rationale [skip ci]

* [comment audit] Reduce bridge schema and page-client commentary [skip ci]

* [comment audit] Tighten mobile page bridge contracts [skip ci]

* [comment audit] Clarify mobile cache and session constraints [skip ci]

* [comment audit] Condense mobile route and lifecycle rationale [skip ci]

* [comment audit] Tighten mobile shell hook timing rationale [skip ci]

* [comment audit] Clarify route handoff and notification compatibility [skip ci]

* [comment audit] Clarify push registration and dictation cleanup constraints [skip ci]

* [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci]

* [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci]

* [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci]

* [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci]

* [comment audit] Tighten stream replay and queued session ownership rationale [skip ci]

* [comment audit] Condense mobile composer and reply-schema constraints [skip ci]

* [comment audit] Clarify mobile transcript recovery and session ownership [skip ci]

* [comment audit] Clarify mobile queue and source-control compatibility [skip ci]

* [comment audit] Condense storage and task launch constraints [skip ci]

* [comment audit] Clarify task schemas and terminal document ownership [skip ci]

* [comment audit] Tighten terminal input and viewport rationale [skip ci]

* [comment audit] Shorten terminal and RPC recorder contracts [skip ci]

* [comment audit] Condense recorder engine and connection contracts [skip ci]

* [comment audit] Shorten host credential and relay recovery comments [skip ci]

* [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci]

* [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci]

* [comment audit] Condense catalog and relay entry contracts [skip ci]

* [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci]

* [comment audit] Condense WSL relay and E2E regression rationale [skip ci]

* [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci]

* [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci]

* [comment audit] Shorten layout oracle and regression explanations [skip ci]

* [comment audit] Condense paired recovery and ownership regression contracts [skip ci]

* [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci]

* [comment audit] Condense terminal rendering and IME regression rationale [skip ci]

* [comment audit] Shorten terminal recovery and benchmark contracts [skip ci]

* [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci]

* [comment audit] Condense workflow routing and release rationale [skip ci]

* [comment audit] Condense mobile security and installer contracts [skip ci]

* [comment audit] Shorten native rationale and stylesheet workarounds [skip ci]

* [comment audit] Shorten Windows visibility probe rationale [skip ci]

* [comment audit] Condense embedded release and signing rationale [skip ci]

* [comment audit] Retain current main test behavior in final reconciliation [skip ci]

* [comment audit] Complete final comment review across current source inventory

* [comment audit] Handle consolidated audit reports before final CI

* [comment audit] Preserve credential storage census detail [skip ci]

* [comment audit] Scale broad changed E2E selections with verified timing shards

* [comment audit] Align E2E assertions with browser close and settled session metadata

* [comment audit] Match existing E2Es to current resource and windowing contracts

* [comment audit] Observe the shared server outage notice in reconnect coverage

* [comment audit] Make existing renderer probes measure settled tab and PTY work

* [comment audit] Align palette E2E selector with task search

* [comment audit] Refresh remaining palette search selectors

* [comment audit] Keep selector correction within selected audit specs

* [comment audit] Await emoji fixture settings inside renderer evaluation

* [comment audit] Cancel fixture fit retries between terminal tests

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-25 04:05:46 -07:00

854 lines
35 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { chmodSync, existsSync, readdirSync, readFileSync, writeFileSync } = require('node:fs')
const { execFileSync } = require('node:child_process')
const { join, resolve } = require('node:path')
const {
MACOS_FOLDER_USAGE_DESCRIPTIONS,
applyMacHelperFolderUsageDescriptions
} = require('./scripts/macos-folder-usage-descriptions.cjs')
const electronBuilderNativeRebuild = require('./scripts/electron-builder-native-rebuild.cjs')
const {
assertPackagedDaemonEntryExists,
verifyPackagedDaemonEntryBoots,
verifyPackagedMacTerminalHostBoots
} = require('./scripts/verify-packaged-daemon-entry.cjs')
const {
buildMacTerminalHost,
macTerminalHostSignIgnore,
verifyMacTerminalHost
} = require('./scripts/macos-terminal-host-bundle.cjs')
const {
assertPackagedNativeVariantsInstalled,
assertProcessHostOutputBuilt,
createPackagedRuntimeNodeModuleResources,
prunePackagedRuntimeNodeModules,
verifyPackagedMainRuntimeDeps
} = require('./packaged-runtime-node-modules.cjs')
const {
assertNoWindowsExecutablesInRuntimeNodeModules
} = require('./packaged-windows-only-runtime-files.cjs')
const { verifyLinuxGlibcFloor } = require('./scripts/verify-linux-glibc-floor.cjs')
const {
verifyPackagedWindowsAgentHook
} = require('./scripts/verify-packaged-windows-agent-hook.cjs')
const {
ensureBundledWaylandClipboard,
finalizePackagedWaylandClipboard
} = require('./wayland-clipboard-resources.cjs')
const { writeMacBuildCompatibility } = require('./scripts/mac-build-compatibility.cjs')
const {
MOBILE_WEB_BUNDLE_DIR,
assertMobileWebBundleBuilt
} = require('./scripts/verify-packaged-mobile-web-bundle.cjs')
const { verifyPackagedPluginResources } = require('./scripts/verify-packaged-plugin-resources.cjs')
const {
assertPackagedServeSelectionEntry,
assertPackagedWebClient
} = require('./scripts/verify-packaged-serve-payload.cjs')
const {
assertBundledRipgrepInstalled,
bundledRipgrepExtraResources,
bundledRipgrepMacSignIgnore,
finalizePackagedRipgrep
} = require('./bundled-ripgrep-resources.cjs')
const {
verifyPackagedWindowsNodePty
} = require('./scripts/verify-packaged-node-pty-job-ownership.cjs')
const {
assertOrcadTemplateBuilt,
finalizePackagedOrcadTemplate,
orcadTemplateExtraResource,
orcadTemplateNodeModulesExtraResource,
orcadTemplateMacSignIgnore
} = require('./scripts/packaged-orcad-template.cjs')
const { verifySkillsCliRuntime } = require('./scripts/verify-skills-cli-runtime.cjs')
const { assertNotDarkBuild } = require('./dark-build-switches.cjs')
const { verifyStaticAppImagePackage } = require('./scripts/static-appimage-package-contract.cjs')
const {
appImageNodeRuntimeFpmArgs,
placeAppImageNodeRuntime,
verifyAppImageNodeRuntimeServesPty
} = require('./scripts/appimage-node-runtime.cjs')
const { signWindowsUninstallerViaSignPath } = require('./scripts/windows-uninstaller-signing.cjs')
const { buildMacShipItScheduling } = require('./scripts/macos-shipit-scheduling.cjs')
// Dev channels need release bundle ID/signature/notarization so Squirrel.Mac accepts updates and macOS retains app identity.
const isMacHourly = process.env.ORCA_MAC_HOURLY === '1'
const isMacDaily = process.env.ORCA_MAC_DAILY === '1'
const isMacAdhoc = process.env.ORCA_MAC_ADHOC === '1'
// Keep Windows dev flags separate: mac flags enable hardened runtime/notarization/global signing, which would demand an unavailable Windows cert.
const isWinHourly = process.env.ORCA_WIN_HOURLY === '1'
const isWinDaily = process.env.ORCA_WIN_DAILY === '1'
const isWinAdhoc = process.env.ORCA_WIN_ADHOC === '1'
const isWinDevChannel = isWinHourly || isWinDaily || isWinAdhoc
const isMacRelease = process.env.ORCA_MAC_RELEASE === '1' || isMacHourly || isMacDaily || isMacAdhoc
const isLinuxArm64Release = process.env.ORCA_LINUX_ARM64_RELEASE === '1'
const localBuildVersion =
isMacRelease || isWinDevChannel ? undefined : process.env.ORCA_LOCAL_BUILD_VERSION
const isHourlyChannel = isMacHourly || isWinHourly
const isDailyChannel = isMacDaily || isWinDaily
const isAdhocChannel = isMacAdhoc || isWinAdhoc
const devChannelBuildVersion = isHourlyChannel
? process.env.ORCA_HOURLY_BUILD_VERSION
: isDailyChannel
? process.env.ORCA_DAILY_BUILD_VERSION
: isAdhocChannel
? process.env.ORCA_ADHOC_BUILD_VERSION
: undefined
// Separate dev-channel repos: 24 hourly tags/day would evict stable/RC from the ten-entry release feed; isolate adhoc/daily from hourly subscribers too.
const devChannelRepo = isHourlyChannel
? 'orca-hourly'
: isDailyChannel
? 'orca-daily'
: isAdhocChannel
? 'orca-adhoc'
: null
const appId = 'com.stablyai.orca'
const featureWallResources = {
from: 'resources/onboarding/feature-wall',
to: 'onboarding/feature-wall'
}
// Freshness checks need immutable build identity, not skill bytes or runtime network access.
const skillFreshnessResources = {
from: 'resources/skills',
to: 'skills'
}
// Native agents load plugins by path and cannot read inside app.asar.
const nativeChatVisualsResource = {
from: 'resources/native-chat-visuals',
to: 'native-chat-visuals'
}
// SSH deploy resolves process.resourcesPath/relay; extraResources keeps bundles on real disk.
const relayExtraResource = {
from: 'out/relay',
to: 'relay'
}
// Bootstrap verifies/publishes immutable plugin bytes from ordinary directories.
const bundledPluginResources = {
from: 'resources/plugins/launch',
to: 'plugins/launch'
}
// Packaged main/CLI/SSH/speech paths lack pnpm links; copy runtime closure so bare requires cannot fall through to checkout dependencies.
// Ship only the 166KB emoji dataset used by worktree naming, not all 49MB of emojibase-data.
const emojiShortcodeDatasetResource = {
from: 'node_modules/emojibase-data/en/shortcodes/emojibase.json',
to: 'node_modules/emojibase-data/en/shortcodes/emojibase.json'
}
const commonExtraResources = [
relayExtraResource,
orcadTemplateExtraResource,
orcadTemplateNodeModulesExtraResource,
...bundledRipgrepExtraResources,
bundledPluginResources,
skillFreshnessResources,
nativeChatVisualsResource,
emojiShortcodeDatasetResource
]
// Native speech addons need real disk paths; copy only the artifact target’s variant.
const macSpeechNativeResource = {
from: 'node_modules/sherpa-onnx-darwin-${arch}',
to: 'node_modules/sherpa-onnx-darwin-${arch}'
}
const linuxSpeechNativeResource = {
from: 'node_modules/sherpa-onnx-linux-${arch}',
to: 'node_modules/sherpa-onnx-linux-${arch}'
}
const winSpeechNativeResource = {
from: 'node_modules/sherpa-onnx-win-x64',
to: 'node_modules/sherpa-onnx-win-x64'
}
// electron-builder replaces these defaults when `depends` is configured; retain
// Electron's loader requirements alongside Orca's headless-host dependencies.
const debElectronRuntimeDependencies = [
'libgtk-3-0',
'libnotify4',
'libnss3',
'libxss1',
'libxtst6',
'xdg-utils',
'libatspi2.0-0',
'libuuid1',
'libsecret-1-0'
]
const rpmElectronRuntimeDependencies = [
'gtk3',
'libnotify',
'nss',
'libXScrnSaver',
'(libXtst or libXtst6)',
'xdg-utils',
'at-spi2-core',
'(libuuid or libuuid1)'
]
// Mirror OS document extensions: CJS packager cannot import TS; keep startup/os-opened-documents.ts and NSIS hooks aligned.
const MARKDOWN_FILE_EXTENSIONS = ['md', 'markdown', 'mdx']
const TABULAR_FILE_EXTENSIONS = ['csv', 'tsv']
// Config loads without unused Windows addons; beforePack enforces target natives. Only @vscode/windows-process-tree has os:win32; workspace links prove no binary exists.
const windowsRuntimeResources = existsSync(
join(__dirname, '..', 'node_modules', '@vscode', 'windows-process-tree', 'package.json')
)
? createPackagedRuntimeNodeModuleResources('win32')
: []
// Shared with the terminal host helper so its purpose strings cannot drift from the app's.
const macUsageDescriptions = {
NSAppleEventsUsageDescription:
'Orca allows terminal-launched developer tools to automate local apps when you request it.',
NSBluetoothAlwaysUsageDescription:
'Orca allows terminal-launched developer tools to access Bluetooth devices when you request it.',
NSBluetoothPeripheralUsageDescription:
'Orca allows terminal-launched developer tools to access Bluetooth devices when you request it.',
NSCameraUsageDescription: "Application requests access to the device's camera.",
NSLocationUsageDescription:
'Orca allows terminal-launched developer tools to access location when you request it.',
NSLocalNetworkUsageDescription:
'Orca allows terminal-launched developer tools to discover and connect to local development servers when you request it.',
NSMicrophoneUsageDescription: "Application requests access to the device's microphone.",
NSAudioCaptureUsageDescription:
'Orca allows terminal-launched developer tools to capture desktop audio when you request it.',
NSBonjourServices: ['_http._tcp', '_https._tcp'],
...MACOS_FOLDER_USAGE_DESCRIPTIONS
}
// Developer ID team that signs every release-channel mac build.
const ORCA_MAC_TEAM_ID = '6CX3WHS9HZ'
/** @type {import('electron-builder').Configuration} */
module.exports = {
appId,
productName: 'Orca',
protocols: [{ name: 'Orca', schemes: ['orca'] }],
toolsets: { appimage: '1.0.3' },
...(devChannelBuildVersion
? { extraMetadata: { version: devChannelBuildVersion } }
: localBuildVersion
? { extraMetadata: { version: localBuildVersion } }
: {}),
directories: {
buildResources: 'resources/build'
},
files: [
'!**/.vscode/*',
// Repo inputs already bundled/copied through extraResources would bloat app.asar.
'!src{,/**/*}',
'!out/orcad{,/**/*}',
// Never in app.asar: the template ships via orcadTemplateExtraResource; prebuilds are build inputs.
'!out/orcad-*{,/**/*}',
'!out/.orcad-*{,/**/*}',
// Why: the pinned Node a local orcad build references (~120 MB) and its download cache.
'!out/runtimes{,/**/*}',
'!out/node-runtime-cache{,/**/*}',
'!config{,/**/*}',
// Cloud services deploy separately; their sources are not desktop runtime resources.
'!cloud{,/**/*}',
// Release archives and other build staging are not runtime resources.
'!.build{,/**/*}',
// Worktree-local Vite dependency caches are development inputs.
'!.cache/vite{,.lock}{,/**/*}',
'!docs{,/**/*}',
'!mobile{,/**/*}',
'!native{,/**/*}',
'!skills{,/**/*}',
// Authoring guides/stubs compile into runtime artifacts; source trees only duplicate content.
'!skill-guides{,/**/*}',
'!skill-stubs{,/**/*}',
'!tests{,/**/*}',
// Examples have no runtime consumer and include adversarial hostile-panel; ship only resources/plugins/launch.
'!examples{,/**/*}',
// Exclude gitignored local screenshot evidence defensively so packaging cannot pick up stray captures.
'!pr-evidence{,/**/*}',
// Local build logs and rollback copies are never application resources.
'!notes{,/**/*}',
// Local tooling directories are not runtime inputs and may contain symlink loops.
'!{.claude,.grok,.agents,.codex}{,/**/*}',
'!Casks{,/**/*}',
'!{AGENTS.md,CLAUDE.md,DEVELOPING.md,bundle-size-progress.md,ORCHESTRATION_IMPLEMENTATION_CHECKLIST.md,ORCHESTRATION_STRUCTURED_OUTPUT_DESIGN.md}',
'!out/**/*.test.js',
// Why: main builds with sourcemap:'hidden' so release CI can publish maps
// for decoding minified crash traces. The app never loads them (no
// sourceMappingURL is emitted), and packing them would add ~34MB to app.asar.
'!out/**/*.map',
// Why: Vite's manifest is only used to project the paired web client.
'!out/renderer/.vite{,/**/*}',
// The installed browser serves its allowlisted assets from the unpacked renderer.
'!out/web{,/**/*}',
// Local dev Electron.app caches (~270MB/branch) must not enter packaged builds.
'!out/electron-dev{,/**/*}',
// extraResources already ships relay; duplicating it in asar added 14MB and let script-heuristic quarantine gut the whole archive (#20966/#20972).
'!out/relay{,/**/*}',
'!electron.vite.config.{js,ts,mjs,cjs}',
'!{.oxlintrc.json,.oxfmtrc.json,components.json,opencode.json,orca.yaml,pnpm-workspace.yaml,vite.web.config.ts}',
'!{.eslintcache,eslint.config.mjs,.prettierignore,.prettierrc.yaml,CHANGELOG.md,README.md}',
'!{.env,.env.*,.npmrc,pnpm-lock.yaml}',
'!tsconfig.json',
// Feature media is read from process.resourcesPath via extraResources; exclude duplicate sources.
'!resources/onboarding/feature-wall/**',
'!resources/skills/**',
'!resources/native-chat-visuals/**',
// extraResources already ships plugin bytes; exclude source duplicates.
'!resources/plugins/launch/**',
// Platform extraResources selects speech natives; asar would duplicate it and ship other variants.
'!node_modules/sherpa-onnx*{,/**/*}',
// CLI shim belongs beside resources/bin/orca.exe; unpacking source creates a second .cmd without its executable (#7351).
'!resources/win32{,/**/*}'
],
// Node-mode CLI/daemon/foreign SQLite reader/serve entries cannot read asar; unpack their shared/main dependencies too.
// Keep out/package.json’s CommonJS boundary and remote CLI WebSocket/E2EE deps. Electron-only workers may stay packed.
// Renderer/mobile-web assets need real paths: swept temporary asar extracts are not recreated (#27976).
asarUnpack: [
'out/package.json',
'out/cli/**',
'out/shared/**',
'out/main/agent-hooks/**',
'out/main/antigravity/**',
'out/main/claude/**',
'out/main/codex/**',
'out/main/copilot/**',
'out/main/cursor/**',
'out/main/droid/**',
'out/main/gemini/**',
'out/main/gitlab/project-ref-parser.js',
'out/main/grok/**',
'out/main/hermes/**',
'out/main/asar-transparent-fs.js',
'out/main/macos-tree-clone.js',
'out/main/orca-profiles/profile-index-store.js',
'out/main/persistence/profile-state/**',
'out/main/skills/bundled-skill-install/cli-entry.js',
'out/main/startup/http1-compatibility-marker.js',
'out/main/daemon-entry.js',
'out/main/session-scanner-service-entry.js',
'out/main/wsl-transcript-fs-process-entry.js',
'out/main/foreign-sqlite-reader-entry.js',
'out/main/plugin-host-entry.js',
'out/main/computer-sidecar.js',
'out/main/parcel-watcher-process-entry.js',
'out/main/orcad/orcad-local-serve-selection-entry.js',
'out/main/orcad/orcad-stale-lock-reclaim.js',
'out/main/chunks/**',
'out/renderer/**',
'out/mobile-web/**',
'resources/**',
'node_modules/ws/**',
'node_modules/tweetnacl/**',
'node_modules/zod/**',
'node_modules/yaml/**'
],
artifactBuildCompleted: ({ file, arch }) => {
if (file.endsWith('.AppImage')) {
verifyStaticAppImagePackage(file, arch)
}
},
// electron-builder calls this with the context alone. The second parameter is the bundle root,
// so a test can point the guard at a scratch bundle instead of needing the repo's out/ built.
beforePack: (
context,
mobileWebBundleDir = MOBILE_WEB_BUNDLE_DIR,
ensureWaylandClipboard = ensureBundledWaylandClipboard,
orcadTemplateDir = join(__dirname, '..', orcadTemplateExtraResource.from)
) => {
// The template is the server every SSH host gets, so a dark test template must never ship.
assertNotDarkBuild([join(__dirname, '..', 'out', 'main'), mobileWebBundleDir, orcadTemplateDir])
assertPackagedNativeVariantsInstalled(context.electronPlatformName, context.arch)
assertBundledRipgrepInstalled()
assertProcessHostOutputBuilt()
assertOrcadTemplateBuilt()
assertMobileWebBundleBuilt(mobileWebBundleDir)
if (context.electronPlatformName === 'linux') {
ensureWaylandClipboard(context.arch)
}
},
afterPack: async (context) => {
const resourcesDir =
context.electronPlatformName === 'darwin'
? join(
context.appOutDir,
`${context.packager.appInfo.productFilename}.app`,
'Contents',
'Resources'
)
: join(context.appOutDir, 'resources')
if (!existsSync(resourcesDir)) {
throw new Error(`Missing packaged resources directory: ${resourcesDir}`)
}
// FpmTarget replaces this with deb/rpm while building those artifacts from the shared app tree.
if (context.electronPlatformName === 'linux') {
writeFileSync(join(resourcesDir, 'package-type'), 'AppImage')
}
if (context.electronPlatformName === 'darwin') {
applyMacHelperFolderUsageDescriptions(
join(context.appOutDir, `${context.packager.appInfo.productFilename}.app`),
context.packager.appInfo.productFilename
)
const architecture = macSliceArch(context.arch, 'local-build compatibility')
const schedulingAddon = buildMacShipItScheduling(resourcesDir, architecture)
await signMacStandaloneHelper(schedulingAddon, 'ShipIt scheduling', context.packager)
const version = context.packager.appInfo.version
let commit = process.env.ORCA_BUILD_COMMIT || process.env.GITHUB_SHA || 'unknown'
if (commit === 'unknown') {
try {
commit = execFileSync('git', ['rev-parse', '--short=12', 'HEAD'], {
encoding: 'utf8'
}).trim()
} catch {
// Source archives can still produce a signed build with an explicit version.
}
}
writeMacBuildCompatibility(resourcesDir, { version, commit, architecture })
}
stampPackagedCliVersion(resourcesDir, context.packager.appInfo.version)
prunePackagedRuntimeNodeModules(resourcesDir, context.electronPlatformName, context.arch)
assertNoWindowsExecutablesInRuntimeNodeModules(resourcesDir, context.electronPlatformName)
// Gate native glibc floor after pruning foreign CPU variants; GLIBC_2.34 once broke Ubuntu 20.04 startup (#9902).
let appImageNodeRuntime = null
if (context.electronPlatformName === 'linux') {
const targetArch = { 1: 'x64', 3: 'arm64' }[context.arch]
// Before the floor gate, so the bundled Node is held to the same glibc floor.
appImageNodeRuntime = await placeAppImageNodeRuntime(resourcesDir, targetArch)
// Why the arch is passed: symbol-version checks pass happily on a wrong-architecture binary,
// so a cross-built slice could ship the host's pty.node and only fail at runtime.
finalizePackagedWaylandClipboard(resourcesDir)
verifyLinuxGlibcFloor(context.appOutDir, { targetArch })
}
verifyPackagedMainRuntimeDeps(resourcesDir)
// Smoke only host-runnable slices: daemon JS loads target-arch node-pty. Arch enum ia32=0, x64=1, armv7l=2, arm64=3, universal=4.
const archEnumByNodeArch = { ia32: 0, x64: 1, armv7l: 2, arm64: 3 }
const hostArchEnum = archEnumByNodeArch[process.arch]
const canExecuteTargetArch = context.arch === hostArchEnum || context.arch === 4
if (context.electronPlatformName === 'win32') {
verifyPackagedWindowsNodePty(resourcesDir, context.arch, { canExecuteTargetArch })
verifyPackagedWindowsAgentHook(resourcesDir, context.arch)
}
verifySkillsCliRuntime(join(resourcesDir, 'app.asar.unpacked', 'out'), resourcesDir, {
executeCommands: canExecuteTargetArch
})
if (!canExecuteTargetArch) {
console.log(
`[verify-skills-cli-runtime] skipped command probes on cross-arch slice (target ${context.arch}, host ${process.arch})`
)
}
if (canExecuteTargetArch) {
verifyPackagedDaemonEntryBoots(resourcesDir)
if (appImageNodeRuntime) {
await verifyAppImageNodeRuntimeServesPty(resourcesDir, appImageNodeRuntime)
}
} else {
// Cross-arch smoke cannot run, but missing unpacked entry is always a packaging error.
assertPackagedDaemonEntryExists(resourcesDir)
console.log(
`[verify-packaged-daemon-entry] skipped boot on cross-arch slice (target ${context.arch}, host ${process.arch})`
)
}
// Validate real electron-builder output so broken extraResources mappings fail before shipping.
verifyPackagedPluginResources(resourcesDir)
assertPackagedWebClient(resourcesDir)
assertPackagedServeSelectionEntry(resourcesDir)
finalizePackagedRipgrep(resourcesDir)
await finalizePackagedOrcadTemplate(resourcesDir, {
platform: context.electronPlatformName,
signMacBinary: (path) =>
signMacStandaloneHelper(path, 'orcad template binary', context.packager)
})
chmodUnixCliLaunchers(resourcesDir, context.electronPlatformName)
for (const filename of readdirSync(resourcesDir)) {
if (!filename.startsWith('agent-browser-')) {
continue
}
// Upstream executable bits vary (notably darwin-x64); restore them so packaged execFile works.
chmodSync(join(resourcesDir, filename), 0o755)
}
if (context.electronPlatformName === 'darwin') {
await signMacComputerUseHelper(join(resourcesDir, 'Orca Computer Use.app'), context.packager)
await signMacStandaloneHelper(
join(resourcesDir, '..', 'MacOS', 'orca-notification-status'),
'orca-notification-status',
context.packager
)
await signMacStandaloneHelper(
join(resourcesDir, '..', 'MacOS', 'orca-keyboard-layout'),
'orca-keyboard-layout',
context.packager
)
await packageMacTerminalHost(join(resourcesDir, '..', '..'), context)
}
},
win: {
executableName: 'Orca',
// SignPath signs Windows installers after packaging, so set release publisherName explicitly.
// Unsigned dev channels omit it or updater signature checks reject dev updates and return to stable.
// Sign hook signs nothing: it relays transient NSIS uninstaller files to CI SignPath; unset relay env leaves local/dev builds inert.
signtoolOptions: {
sign: signWindowsUninstallerViaSignPath,
...(isWinDevChannel ? {} : { publisherName: 'SignPath Foundation' })
},
...(isWinDevChannel ? { verifyUpdateCodeSignature: false } : {}),
extraResources: [
...commonExtraResources,
...windowsRuntimeResources,
winSpeechNativeResource,
{
from: 'resources/win32/bin/orca.cmd',
to: 'bin/orca.cmd'
},
{
from: 'native/windows-cli-launcher/.build/orca.exe',
to: 'bin/orca.exe'
},
{
from: 'native/windows-cli-launcher/.build/orca-administrator-restart.exe',
to: 'bin/orca-administrator-restart.exe'
},
// Why resources/bin: SignPath signs every unsigned PE under win-unpacked, and the hook
// installer copies this signed file into ~/.orca/agent-hooks (#20913).
{
from: 'native/windows-agent-hook/.build/orca-agent-hook.exe',
to: 'bin/orca-agent-hook.exe'
},
{
from: 'node_modules/agent-browser/bin/agent-browser-win32-x64.exe',
to: 'agent-browser-win32-x64.exe'
},
{
from: 'native/computer-use-windows/runtime.ps1',
to: 'computer-use-windows/runtime.ps1'
},
featureWallResources
]
},
nsis: {
artifactName: 'orca-windows-setup.${ext}',
shortcutName: '${productName}',
uninstallDisplayName: '${productName}',
createDesktopShortcut: 'always',
// One NSIS include hosts update-guarded daemon cleanup and additive markdown Open With registration.
// Avoid fileAssociations: it would steal default .md ownership; see the include’s header.
include: resolve(__dirname, 'nsis', 'orca-installer-hooks.nsh')
},
mac: {
// Alternate rank preserves Finder’s default; one entry per extension because app-builder globs the value as a string.
fileAssociations: [
...MARKDOWN_FILE_EXTENSIONS.map((ext) => ({
ext,
name: 'Markdown Document',
description: 'Markdown Document',
role: 'Editor',
rank: 'Alternate'
})),
...TABULAR_FILE_EXTENSIONS.map((ext) => ({
ext,
name: `${ext.toUpperCase()} Document`,
description: `${ext.toUpperCase()} Document`,
role: 'Editor',
rank: 'Alternate'
}))
],
icon: 'resources/build/icon.icns',
entitlements: 'resources/build/entitlements.mac.plist',
entitlementsInherit: 'resources/build/entitlements.mac.plist',
...(isMacRelease ? { sign: resolve(__dirname, 'scripts/sign-mac-app.mjs') } : {}),
signIgnore: [
...bundledRipgrepMacSignIgnore,
...orcadTemplateMacSignIgnore,
...macTerminalHostSignIgnore
],
extendInfo: macUsageDescriptions,
// Local macOS builds need no release credentials; hardening/notarization stay on explicit release paths.
hardenedRuntime: isMacRelease,
// Dev notarization preserves TCC identifier/team identity across cdhash changes; unticketed hourly updates otherwise lose folder grants with EPERM and no prompt.
notarize: isMacRelease,
extraResources: [
...commonExtraResources,
...createPackagedRuntimeNodeModuleResources('darwin'),
macSpeechNativeResource,
{
from: 'resources/darwin/bin/orca',
to: 'bin/orca'
},
{
from: 'node_modules/agent-browser/bin/agent-browser-darwin-${arch}',
to: 'agent-browser-darwin-${arch}'
},
{
from: 'native/computer-use-macos/.build/release/Orca Computer Use.app',
to: 'Orca Computer Use.app'
},
featureWallResources
],
// macOS 26 UNUserNotificationCenter aborts helpers launched from Resources; execute from Contents/MacOS (#7929).
extraFiles: [
{
from: 'native/notification-status-macos/.build/release/orca-notification-status',
to: 'MacOS/orca-notification-status'
},
{
from: 'native/keyboard-layout-macos/.build/release/orca-keyboard-layout',
to: 'MacOS/orca-keyboard-layout'
}
],
target: [
{
target: 'dmg',
arch: ['x64', 'arm64']
},
{
target: 'zip',
arch: ['x64', 'arm64']
}
]
},
// Why: release builds should fail if signing is unavailable instead of
// silently downgrading to ad-hoc artifacts that look shippable in CI logs.
forceCodeSigning: isMacRelease,
dmg: {
artifactName: 'orca-macos-${arch}.${ext}'
},
linux: {
// shared-mime-info already maps md/markdown: advertise handler only, leaving mimeapps.list defaults intact.
// Omit mdx because Ubuntu 24.04 maps it to application/x-genesis-32x-rom; claiming it would need a glob override.
mimeTypes: ['text/markdown', 'text/csv', 'text/tab-separated-values'],
// Avoid GNOME Orca’s orca package and /usr/bin/orca names.
executableName: 'orca-ide',
// Use icns to generate hicolor sizes; some Linux docks ignore a lone 1024px PNG.
icon: 'resources/build/icon.icns',
desktop: {
entry: {
// Why: Electron reports WM_CLASS=orca for the visible Linux window;
// GNOME docks need an exact match to group it with orca-ide.desktop.
StartupWMClass: 'orca'
}
},
extraResources: [
...commonExtraResources,
...createPackagedRuntimeNodeModuleResources('linux'),
linuxSpeechNativeResource,
{
from: 'native/wayland-clipboard/.build/${arch}/orca-wayland-clipboard',
to: 'bin/orca-wayland-clipboard'
},
{
from: 'resources/linux/bin/orca-ide',
to: 'bin/orca-ide'
},
{
from: 'node_modules/agent-browser/bin/agent-browser-linux-${arch}',
to: 'agent-browser-linux-${arch}'
},
{
from: 'native/computer-use-linux/runtime.py',
to: 'computer-use-linux/runtime.py'
},
featureWallResources
],
// Keep local artifacts aligned with the release pipeline.
target: ['AppImage', 'deb', 'rpm'],
maintainer: 'stablyai',
category: 'Utility'
},
appImage: {
artifactName: isLinuxArm64Release ? 'orca-linux-arm64.${ext}' : 'orca-linux.${ext}'
},
deb: {
packageName: 'orca-ide',
artifactName: 'orca-ide_${version}_${arch}.${ext}',
// Headless Chromium still needs display service; orca serve starts packaged Xvfb when available (ensure-virtual-display.ts).
depends: [
...debElectronRuntimeDependencies,
'python3',
'python3-gi',
'gir1.2-atspi-2.0',
'at-spi2-core',
'xdotool',
'xclip',
'xvfb'
],
// Install CLI onto PATH for headless hosts where GUI-triggered CliInstaller can never run.
afterInstall: 'resources/linux/packaging/after-install.sh',
afterRemove: 'resources/linux/packaging/after-remove.sh',
// Why: only an AppImage's files can vanish under a running daemon (see appimage-node-runtime.cjs).
fpm: appImageNodeRuntimeFpmArgs
},
rpm: {
packageName: 'orca-ide',
artifactName: 'orca-ide-${version}.${arch}.${ext}',
// Why: see deb depends. RPM distros ship Xvfb as xorg-x11-server-Xvfb (there
// is no `xvfb` package), so the name differs from the deb here.
depends: [
...rpmElectronRuntimeDependencies,
'python3',
'python3-gobject',
'xdotool',
'xclip',
'xorg-x11-server-Xvfb'
],
// Why: same headless CLI-on-PATH registration as deb; rpm runs these via fpm.
afterInstall: 'resources/linux/packaging/after-install.sh',
afterRemove: 'resources/linux/packaging/after-remove.sh',
// Why: only an AppImage's files can vanish under a running daemon (see appimage-node-runtime.cjs).
fpm: appImageNodeRuntimeFpmArgs
},
beforeBuild: electronBuilderNativeRebuild,
// Dual-arch builds need target node-pty rebuilds or Intel Macs get arm64 binaries and posix_spawnp failure.
// beforeBuild performs targeted rebuild then returns false to skip optional cpu-features.
npmRebuild: true,
publish: {
provider: 'github',
owner: 'stablyai',
repo: devChannelRepo ?? 'orca',
// Keep main-repo releases draft until release-cut verifies all assets; early --publish always would expose missing Windows installers.
releaseType: devChannelRepo ? 'prerelease' : 'draft'
}
}
// Stamp the effective channel version where node-mode CLI code can read it.
function stampPackagedCliVersion(resourcesDir, version) {
const packageJsonPath = join(resourcesDir, 'app.asar.unpacked', 'out', 'package.json')
if (!existsSync(packageJsonPath)) {
throw new Error(`Missing unpacked CLI package boundary: ${packageJsonPath}`)
}
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
writeFileSync(packageJsonPath, `${JSON.stringify({ ...packageJson, version }, null, 2)}\n`)
}
function chmodUnixCliLaunchers(resourcesDir, electronPlatformName) {
if (electronPlatformName === 'win32') {
return
}
for (const launcherName of ['orca', 'orca-ide']) {
const launcherPath = join(resourcesDir, 'bin', launcherName)
if (!existsSync(launcherPath)) {
continue
}
// Public shell commands need executable extraResources modes despite source/packager drift.
chmodSync(launcherPath, 0o755)
}
}
async function signMacComputerUseHelper(helperAppPath, packager) {
if (!existsSync(helperAppPath)) {
if (isMacRelease) {
throw new Error(`Missing Orca Computer Use helper app at ${helperAppPath}`)
}
return
}
const codeSigningInfo =
isMacRelease && process.env.CSC_LINK && packager?.codeSigningInfo?.value
? await packager.codeSigningInfo.value
: null
const identity =
process.env.ORCA_COMPUTER_MACOS_SIGN_IDENTITY ??
process.env.CSC_NAME ??
findInstalledMacSigningIdentity(codeSigningInfo?.keychainFile) ??
(isMacRelease ? null : '-')
if (!identity) {
throw new Error('Missing signing identity for Orca Computer Use helper app')
}
// Why: TCC grants attach to this nested app's code identity. Sign it before
// the outer Orca.app is sealed so production builds preserve that identity.
execFileSync('codesign', codesignArgs(identity, helperAppPath), { stdio: 'inherit' })
execFileSync('codesign', ['--verify', '--deep', '--strict', helperAppPath], {
stdio: 'inherit'
})
}
// electron-builder `Arch` enum: x64=1, arm64=3. A universal (4) slice has no single arch.
function macSliceArch(archEnum, purpose) {
const arch = { 1: 'x64', 3: 'arm64' }[archEnum]
if (!arch) {
throw new Error(`Unsupported ${purpose} architecture: ${archEnum}`)
}
return arch
}
// Why after the node_modules prune: the helper copies this slice's node-pty.
async function packageMacTerminalHost(appPath, context) {
const arch = macSliceArch(context.arch, 'macOS terminal host')
await buildMacTerminalHost({
appPath,
arch,
iconPath: resolve(__dirname, '../resources/build/icon.icns'),
entitlementsPath: resolve(__dirname, '../resources/build/entitlements.mac.plist'),
usageDescriptions: macUsageDescriptions,
signCode: (path, { entitlements }) =>
signMacStandaloneHelper(path, 'terminal host', context.packager, entitlements)
})
// Only a local build may skip a slice this host cannot run; a shipped slice must serve a PTY.
await verifyPackagedMacTerminalHostBoots(appPath, {
arch,
required: isMacRelease || process.env.CI === 'true'
})
await verifyMacTerminalHost({
appPath,
arch,
usageDescriptions: macUsageDescriptions,
expectedTeamId: isMacRelease ? ORCA_MAC_TEAM_ID : null
})
}
async function signMacStandaloneHelper(helperPath, helperName, packager, entitlements) {
if (!existsSync(helperPath)) {
if (isMacRelease) {
throw new Error(`Missing ${helperName} helper at ${helperPath}`)
}
return
}
const codeSigningInfo =
isMacRelease && process.env.CSC_LINK && packager?.codeSigningInfo?.value
? await packager.codeSigningInfo.value
: null
const identity =
process.env.CSC_NAME ??
findInstalledMacSigningIdentity(codeSigningInfo?.keychainFile) ??
(isMacRelease ? null : '-')
if (!identity) {
throw new Error(`Missing signing identity for ${helperName} helper`)
}
// Why: nested executables must be signed before the outer app bundle is sealed.
const args = ['--force', '--sign', identity]
if (isMacRelease) {
args.push('--options', 'runtime', '--timestamp')
}
if (entitlements) {
args.push('--entitlements', entitlements)
}
args.push(helperPath)
execFileSync('codesign', args, { stdio: 'inherit' })
execFileSync('codesign', ['--verify', '--strict', helperPath], { stdio: 'inherit' })
}
function codesignArgs(identity, targetPath) {
const args = ['--force', '--deep', '--sign', identity]
if (isMacRelease) {
args.push(
'--options',
'runtime',
'--timestamp',
'--entitlements',
resolve(__dirname, '../resources/build/entitlements.computer-use.mac.plist')
)
}
args.push(targetPath)
return args
}
function findInstalledMacSigningIdentity(keychainFile) {
try {
const output = execFileSync(
'security',
['find-identity', '-v', '-p', 'codesigning', ...(keychainFile ? [keychainFile] : [])],
{
encoding: 'utf8'
}
)
const releaseMatch =
output.match(/"([^"]*Developer ID Application:[^"]+)"/) ??
output.match(/"([^"]*Apple Distribution:[^"]+)"/)
if (releaseMatch?.[1]) {
return releaseMatch[1]
}
if (!isMacRelease) {
return output.match(/"([^"]*Apple Development:[^"]+)"/)?.[1] ?? null
}
} catch {}
return null
}