mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 16:03:20 +00:00
* fix(runtime): preserve terminals during headless desktop activation * rm design doc * Fix desktop activation launch ordering and blocked-window status resolut - Check desktopWindowStatus before spawning the Orca app so a blocked runtime no longer launches a doomed second instance. - Reuse resolveDesktopWindowStatus for remote runtime status so it honors the same authoritativeWindowId fallback as local status. - Re-check the authoritative window at spawn time instead of trusting a possibly-stale snapshot, since it can be destroyed mid-await. - Harden the e2e activation spec against silent spawn failures. --------- Co-authored-by: bbingz <zzb@gxsmjx.com>
69 lines
3.0 KiB
TypeScript
69 lines
3.0 KiB
TypeScript
import type { App } from 'electron'
|
|
import { writeStartupDiagnosticLine, type StartupDiagnosticSink } from './startup-diagnostics'
|
|
|
|
export const SINGLE_INSTANCE_LOCK_FAILURE_MESSAGE =
|
|
'[single-instance] Another Orca instance is already running for this userData profile; exiting this launch after requesting the existing window. If no Orca process is running, this may be an Electron/macOS single-instance lock failure.'
|
|
export const SINGLE_INSTANCE_LOCK_BYPASS_ENV = 'ORCA_BYPASS_SINGLE_INSTANCE_LOCK'
|
|
export const SINGLE_INSTANCE_LOCK_E2E_ENFORCE_ENV = 'ORCA_E2E_ENFORCE_SINGLE_INSTANCE_LOCK'
|
|
export const SINGLE_INSTANCE_LOCK_BYPASS_MESSAGE =
|
|
'[single-instance] ORCA_BYPASS_SINGLE_INSTANCE_LOCK=1 is set; bypassing the packaged macOS single-instance lock for diagnostics. Do not use this with another Orca instance running for the same profile.'
|
|
|
|
/**
|
|
* Why: Orca writes two canonical discovery files into `<userData>/`:
|
|
* `orca-runtime.json` (RPC endpoint + authToken for the bundled CLI) and
|
|
* `agent-hooks/endpoint.env` (hook port + token for cursor-agent/claude/codex
|
|
* scripts). Without a single-instance lock, every AppImage/.app double-click
|
|
* boots a fresh Electron main that clobbers both files. When the most recent
|
|
* instance quits, metadata points at a dead pid and `orca status` reports
|
|
* `stale_bootstrap` even though the original process is still running.
|
|
*
|
|
* This helper centralises the lock gate so it is testable in isolation and
|
|
* so `src/main/index.ts` has one clean call site rather than two spread-out
|
|
* Electron calls.
|
|
*
|
|
* Electron derives the lock identity from the current `userData` path, so
|
|
* callers MUST invoke this AFTER `configureDevUserDataPath(is.dev)` — that
|
|
* way dev (`orca-dev` userData) and packaged (`orca` userData) runs lock in
|
|
* separate namespaces instead of serialising against each other.
|
|
*/
|
|
export function acquireSingleInstanceLock(app: App, onSecondInstance: () => void): boolean {
|
|
if (!app.requestSingleInstanceLock()) {
|
|
return false
|
|
}
|
|
app.on('second-instance', onSecondInstance)
|
|
return true
|
|
}
|
|
|
|
export function shouldBypassSingleInstanceLock(options: {
|
|
env?: NodeJS.ProcessEnv
|
|
isDev: boolean
|
|
isServeMode: boolean
|
|
platform?: NodeJS.Platform
|
|
}): boolean {
|
|
const env = options.env ?? process.env
|
|
const platform = options.platform ?? process.platform
|
|
return (
|
|
platform === 'darwin' &&
|
|
!options.isDev &&
|
|
!options.isServeMode &&
|
|
env[SINGLE_INSTANCE_LOCK_BYPASS_ENV] === '1'
|
|
)
|
|
}
|
|
|
|
export function shouldSkipSingleInstanceLock(options: {
|
|
env?: NodeJS.ProcessEnv
|
|
isDev: boolean
|
|
isServeMode: boolean
|
|
}): boolean {
|
|
const env = options.env ?? process.env
|
|
return options.isDev && !options.isServeMode && env[SINGLE_INSTANCE_LOCK_E2E_ENFORCE_ENV] !== '1'
|
|
}
|
|
|
|
export function logSingleInstanceLockFailure(write?: StartupDiagnosticSink): void {
|
|
writeStartupDiagnosticLine(SINGLE_INSTANCE_LOCK_FAILURE_MESSAGE, write)
|
|
}
|
|
|
|
export function logSingleInstanceLockBypass(write?: StartupDiagnosticSink): void {
|
|
writeStartupDiagnosticLine(SINGLE_INSTANCE_LOCK_BYPASS_MESSAGE, write)
|
|
}
|