feat: improve background startup and launcher control

Detach --background launches from terminals with quieter runtime output, make wrapper/plugin overlay start explicit, and allow trailing commas in JSONC configs for safer hot-reload edits. Includes pending Anki/docs/backlog updates in this unreleased batch.
This commit is contained in:
2026-02-18 02:22:01 -08:00
parent 4703b995da
commit ebaed49f76
34 changed files with 515 additions and 48 deletions

View File

@@ -21,6 +21,7 @@ export interface AppLifecycleServiceDeps {
onWillQuitCleanup: () => void;
shouldRestoreWindowsOnActivate: () => boolean;
restoreWindowsOnActivate: () => void;
shouldQuitOnWindowAllClosed: () => boolean;
}
interface AppLike {
@@ -42,6 +43,7 @@ export interface AppLifecycleDepsRuntimeOptions {
onWillQuitCleanup: () => void;
shouldRestoreWindowsOnActivate: () => boolean;
restoreWindowsOnActivate: () => void;
shouldQuitOnWindowAllClosed: () => boolean;
}
export function createAppLifecycleDepsRuntime(
@@ -80,6 +82,7 @@ export function createAppLifecycleDepsRuntime(
onWillQuitCleanup: options.onWillQuitCleanup,
shouldRestoreWindowsOnActivate: options.shouldRestoreWindowsOnActivate,
restoreWindowsOnActivate: options.restoreWindowsOnActivate,
shouldQuitOnWindowAllClosed: options.shouldQuitOnWindowAllClosed,
};
}
@@ -119,7 +122,7 @@ export function startAppLifecycle(initialArgs: CliArgs, deps: AppLifecycleServic
});
deps.onWindowAllClosed(() => {
if (!deps.isDarwinPlatform()) {
if (!deps.isDarwinPlatform() && deps.shouldQuitOnWindowAllClosed()) {
deps.quitApp();
}
});

View File

@@ -5,6 +5,7 @@ import { CliCommandServiceDeps, handleCliCommand } from './cli-command';
function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
return {
background: false,
start: false,
stop: false,
toggle: false,

View File

@@ -5,6 +5,7 @@ import { CliArgs } from '../../cli/args';
function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
return {
background: false,
start: false,
stop: false,
toggle: false,
@@ -80,6 +81,7 @@ test('runStartupBootstrapRuntime configures startup state and starts lifecycle',
assert.equal(result.backendOverride, 'x11');
assert.equal(result.autoStartOverlay, true);
assert.equal(result.texthookerOnlyMode, true);
assert.equal(result.backgroundMode, false);
assert.deepEqual(calls, ['setLog:debug:cli', 'forceX11', 'enforceWayland', 'startLifecycle']);
});
@@ -130,6 +132,7 @@ test('runStartupBootstrapRuntime remains lifecycle-stable with Jellyfin CLI flag
assert.equal(result.backendOverride, null);
assert.equal(result.autoStartOverlay, false);
assert.equal(result.texthookerOnlyMode, false);
assert.equal(result.backgroundMode, false);
assert.deepEqual(calls, ['forceX11', 'enforceWayland', 'startLifecycle']);
});
@@ -173,5 +176,26 @@ test('runStartupBootstrapRuntime skips lifecycle when generate-config flow handl
assert.equal(result.mpvSocketPath, '/tmp/default.sock');
assert.equal(result.texthookerPort, 5174);
assert.equal(result.backendOverride, null);
assert.equal(result.backgroundMode, false);
assert.deepEqual(calls, ['setLog:warn:cli', 'forceX11', 'enforceWayland']);
});
test('runStartupBootstrapRuntime enables quiet background mode by default', () => {
const calls: string[] = [];
const args = makeArgs({ background: true });
const result = runStartupBootstrapRuntime({
argv: ['node', 'main.ts', '--background'],
parseArgs: () => args,
setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`),
forceX11Backend: () => calls.push('forceX11'),
enforceUnsupportedWaylandMode: () => calls.push('enforceWayland'),
getDefaultSocketPath: () => '/tmp/default.sock',
defaultTexthookerPort: 5174,
runGenerateConfigFlow: () => false,
startAppLifecycle: () => calls.push('startLifecycle'),
});
assert.equal(result.backgroundMode, true);
assert.deepEqual(calls, ['setLog:warn:cli', 'forceX11', 'enforceWayland', 'startLifecycle']);
});

View File

@@ -9,6 +9,7 @@ export interface StartupBootstrapRuntimeState {
backendOverride: string | null;
autoStartOverlay: boolean;
texthookerOnlyMode: boolean;
backgroundMode: boolean;
}
interface RuntimeAutoUpdateOptionManagerLike {
@@ -47,6 +48,8 @@ export function runStartupBootstrapRuntime(
if (initialArgs.logLevel) {
deps.setLogLevel(initialArgs.logLevel, 'cli');
} else if (initialArgs.background) {
deps.setLogLevel('warn', 'cli');
}
deps.forceX11Backend(initialArgs);
@@ -59,6 +62,7 @@ export function runStartupBootstrapRuntime(
backendOverride: initialArgs.backend ?? null,
autoStartOverlay: initialArgs.autoStartOverlay,
texthookerOnlyMode: initialArgs.texthooker,
backgroundMode: initialArgs.background,
};
if (!deps.runGenerateConfigFlow(initialArgs)) {