Self-contained desktop dev script with worktree isolation
dev:desktop now launches its own Metro on a random port + Electron, no dependency on a shared :8081. In worktrees, Electron gets a unique userData path and dock badge so multiple instances run side-by-side.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "npm --prefix ../.. run build:daemon && npm run build:main && electron-builder --config electron-builder.yml",
|
||||
"build:main": "tsc -p tsconfig.json",
|
||||
"dev": "npm run build:main && wait-on tcp:8081 && electron .",
|
||||
"dev": "./scripts/dev.sh",
|
||||
"test": "vitest run",
|
||||
"typecheck": "tsc --noEmit -p tsconfig.json"
|
||||
},
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DESKTOP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
APP_DIR="$(cd "$DESKTOP_DIR/../app" && pwd)"
|
||||
ROOT_DIR="$(cd "$DESKTOP_DIR/../.." && pwd)"
|
||||
|
||||
# Build the Electron main process
|
||||
npm run build:main
|
||||
|
||||
# Get a random available port for Metro
|
||||
EXPO_PORT=$("$ROOT_DIR/node_modules/.bin/get-port")
|
||||
export EXPO_PORT
|
||||
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
echo " Paseo Desktop Dev"
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
echo " Metro: http://localhost:${EXPO_PORT}"
|
||||
echo "══════════════════════════════════════════════════════"
|
||||
|
||||
# Launch Metro + Electron together, kill both on exit
|
||||
"$ROOT_DIR/node_modules/.bin/concurrently" \
|
||||
--kill-others \
|
||||
--names "metro,electron" \
|
||||
--prefix-colors "magenta,cyan" \
|
||||
"cd '$APP_DIR' && npx expo start --port $EXPO_PORT" \
|
||||
"$ROOT_DIR/node_modules/.bin/wait-on tcp:$EXPO_PORT && EXPO_DEV_URL=http://localhost:$EXPO_PORT electron '$DESKTOP_DIR'"
|
||||
@@ -8,6 +8,7 @@ inheritLoginShellEnv();
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { existsSync } from "node:fs";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { app, BrowserWindow, ipcMain, nativeImage, net, protocol } from "electron";
|
||||
import { registerDaemonManager } from "./daemon/daemon-manager.js";
|
||||
import {
|
||||
@@ -38,6 +39,37 @@ const APP_SCHEME = "paseo";
|
||||
const OPEN_PROJECT_EVENT = "paseo:event:open-project";
|
||||
app.setName("Paseo");
|
||||
|
||||
// In dev mode, detect git worktrees and isolate each instance so multiple
|
||||
// Electron windows can run side-by-side (separate userData = separate lock).
|
||||
let devWorktreeName: string | null = null;
|
||||
if (!app.isPackaged) {
|
||||
try {
|
||||
const topLevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 3000,
|
||||
}).trim();
|
||||
devWorktreeName = path.basename(topLevel);
|
||||
// Main checkout (e.g. "paseo") gets default userData — only worktrees diverge.
|
||||
const commonDir = path.resolve(
|
||||
topLevel,
|
||||
execFileSync("git", ["rev-parse", "--git-common-dir"], {
|
||||
cwd: topLevel,
|
||||
encoding: "utf-8",
|
||||
timeout: 3000,
|
||||
}).trim(),
|
||||
);
|
||||
const isWorktree = path.resolve(topLevel, ".git") !== commonDir;
|
||||
if (isWorktree) {
|
||||
app.setPath("userData", path.join(app.getPath("appData"), `Paseo-${devWorktreeName}`));
|
||||
log.info("[worktree] isolated userData for worktree:", devWorktreeName);
|
||||
} else {
|
||||
devWorktreeName = null;
|
||||
}
|
||||
} catch {
|
||||
devWorktreeName = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow users to pass Chromium flags via PASEO_ELECTRON_FLAGS for debugging
|
||||
// rendering issues (e.g. "--disable-gpu --ozone-platform=x11").
|
||||
// Must run before app.whenReady().
|
||||
@@ -127,7 +159,9 @@ async function createMainWindow(): Promise<void> {
|
||||
const iconPath = getWindowIconPath();
|
||||
const systemTheme = resolveSystemWindowTheme();
|
||||
|
||||
const title = devWorktreeName ? `Paseo (${devWorktreeName})` : "Paseo";
|
||||
const mainWindow = new BrowserWindow({
|
||||
title,
|
||||
width: 1200,
|
||||
height: 800,
|
||||
show: false,
|
||||
@@ -144,6 +178,10 @@ async function createMainWindow(): Promise<void> {
|
||||
},
|
||||
});
|
||||
|
||||
if (devWorktreeName) {
|
||||
app.dock?.setBadge(devWorktreeName);
|
||||
}
|
||||
|
||||
setupWindowResizeEvents(mainWindow);
|
||||
setupDefaultContextMenu(mainWindow);
|
||||
setupDragDropPrevention(mainWindow);
|
||||
|
||||
Reference in New Issue
Block a user