feat(sync): headless --sync-cli mode so sync only needs the app installed

The Electron app now answers launcher-style sync argv (--sync-cli sync
[host|--snapshot|--merge] ... plus --help/--version) at entry, before any
window or display initialization, backed by a libsql binding of the shared
stats-sync engine. Works over SSH with no display server, so a remote
machine no longer needs the bun launcher. The launcher accepts --sync-cli
as a no-op so both invocation shapes stay equivalent.
This commit is contained in:
2026-07-11 20:23:22 -07:00
parent 04095eebf7
commit ffa183b1a1
16 changed files with 1003 additions and 1 deletions
+9
View File
@@ -30,6 +30,7 @@ import {
} from './main/runtime/first-run-setup-plugin';
import { createWindowsMpvLaunchDeps, launchWindowsMpv } from './main/runtime/windows-mpv-launch';
import { runStatsDaemonControlFromProcess } from './stats-daemon-entry';
import { runSyncCliFromProcess, shouldHandleSyncCliAtEntry } from './main/sync-cli';
import { createFatalErrorReporter, registerFatalErrorHandlers } from './main/fatal-error';
import { buildMpvLoggingArgs } from './shared/mpv-logging-args';
import {
@@ -221,6 +222,14 @@ async function forwardStartupArgvViaAppControlIfAvailable(): Promise<boolean> {
}
async function runEntryProcess(): Promise<void> {
// Headless sync CLI: must run first (its own --help/--version handling) and
// exit before app.whenReady() so it works over SSH with no display server.
if (shouldHandleSyncCliAtEntry(process.argv, process.env)) {
const exitCode = await runSyncCliFromProcess(process.argv, app.getVersion());
app.exit(exitCode);
return;
}
if (shouldHandleHelpOnlyAtEntry(process.argv, process.env)) {
const sanitizedEnv = sanitizeHelpEnv(process.env);
process.env.NODE_NO_WARNINGS = sanitizedEnv.NODE_NO_WARNINGS;