chore: update android scripts and add dev runner with IPC restart support
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user