chore: update android scripts and add dev runner with IPC restart support

This commit is contained in:
Mohamed Boudra
2025-11-28 11:39:31 +01:00
parent 2c84447ec2
commit 1b019c4688
5 changed files with 81 additions and 6 deletions
+2 -2
View File
@@ -5,8 +5,8 @@
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
"android": "ANDROID_VARIANT=${ANDROID_VARIANT:-devDebug} expo run:android --variant $ANDROID_VARIANT",
"android:release": "ANDROID_VARIANT=${ANDROID_VARIANT:-productionRelease} expo run:android --variant $ANDROID_VARIANT",
"android": "ANDROID_VARIANT=${ANDROID_VARIANT:-devDebug} expo run:android --variant=${ANDROID_VARIANT:-devDebug}",
"android:release": "ANDROID_VARIANT=${ANDROID_VARIANT:-productionRelease} expo run:android --variant=${ANDROID_VARIANT:-productionRelease}",
"ios": "expo run:ios",
"ios:release": "expo run:ios --configuration Release",
"web": "expo start --web",
@@ -6,6 +6,10 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
const REGISTRY_STORAGE_KEY = "@paseo:daemon-registry";
const LEGACY_SETTINGS_KEY = "@paseo:settings";
const FALLBACK_DAEMON_URL = "ws://localhost:6767/ws";
const DEFAULT_DAEMONS: Array<{ label: string; wsUrl: string; restUrl?: string | null }> = [
{ label: "dev", wsUrl: "ws://dev:6767/ws" },
{ label: "macbook", wsUrl: "ws://mohameds-macbook-pro:6767/ws" },
];
const DAEMON_REGISTRY_QUERY_KEY = ["daemon-registry"];
export type DaemonProfile = {
@@ -221,7 +225,9 @@ async function loadDaemonRegistryFromStorage(): Promise<DaemonProfile[]> {
return envDefaults;
}
const fallback = [createProfile("Local Host", FALLBACK_DAEMON_URL)];
const fallback = DEFAULT_DAEMONS.length > 0
? DEFAULT_DAEMONS.map((entry) => createProfile(entry.label, entry.wsUrl))
: [createProfile("Local Host", FALLBACK_DAEMON_URL)];
await AsyncStorage.setItem(REGISTRY_STORAGE_KEY, JSON.stringify(fallback));
return fallback;
} catch (error) {
+1 -1
View File
@@ -4,7 +4,7 @@
"description": "Paseo backend server",
"type": "module",
"scripts": {
"dev": "NODE_ENV=development node --import tsx src/server/index.ts",
"dev": "NODE_ENV=development tsx scripts/dev-runner.ts",
"dev:tsx": "NODE_ENV=development tsx watch --ignore '**/*.timestamp-*' src/server/index.ts",
"build": "tsc -p tsconfig.server.json",
"start": "NODE_ENV=production node dist/server/index.js",
+60
View File
@@ -0,0 +1,60 @@
import { fork, type ChildProcess } from "child_process";
import { fileURLToPath } from "url";
import path from "path";
const serverEntry = fileURLToPath(
new URL("../src/server/index.ts", import.meta.url)
);
let child: ChildProcess | null = null;
let restarting = false;
function spawnServer() {
child = fork(serverEntry, {
stdio: "inherit",
env: process.env,
execArgv: ["--import", "tsx"],
});
child.on("message", (msg: any) => {
if (msg?.type === "paseo:restart") {
restartServer();
}
});
child.on("exit", (code, signal) => {
if (restarting) {
restarting = false;
spawnServer();
return;
}
const exitDescriptor =
signal ?? (typeof code === "number" ? `code ${code}` : "unknown");
console.warn(`[DevRunner] Server exited (${exitDescriptor}). Shutting down.`);
process.exit(typeof code === "number" ? code : 0);
});
}
function restartServer() {
if (!child || restarting) {
return;
}
restarting = true;
console.warn("[DevRunner] Restart requested. Stopping current server...");
child.kill("SIGTERM");
}
function forwardSignal(signal: NodeJS.Signals) {
if (!child) {
process.exit(0);
}
child.kill(signal);
}
process.on("SIGINT", () => forwardSignal("SIGINT"));
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
console.log("[DevRunner] Starting server with tsx (explicit restarts only)");
spawnServer();
+11 -2
View File
@@ -1,6 +1,6 @@
import { v4 as uuidv4 } from "uuid";
import { readFile, mkdir, writeFile } from "fs/promises";
import { exec } from "child_process";
import { exec, spawn } from "child_process";
import { promisify, inspect } from "util";
import { join } from "path";
import invariant from "tiny-invariant";
@@ -75,6 +75,7 @@ const execAsync = promisify(exec);
const ACTIVE_TITLE_GENERATIONS = new Set<string>();
let restartRequested = false;
const KNOWN_AGENT_PROVIDERS: AgentProvider[] = ["claude", "codex"];
const RESTART_EXIT_DELAY_MS = 250;
type ProcessingPhase = "idle" | "transcribing" | "llm";
@@ -886,9 +887,17 @@ export class Session {
payload,
});
if (typeof process.send === "function") {
process.send({
type: "paseo:restart",
...(reason ? { reason } : {}),
});
return;
}
setTimeout(() => {
process.exit(0);
}, 250);
}, RESTART_EXIT_DELAY_MS);
}
private async handleDeleteAgentRequest(agentId: string): Promise<void> {