chore: update android scripts and add dev runner with IPC restart support
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start",
|
"start": "expo start",
|
||||||
"reset-project": "node ./scripts/reset-project.js",
|
"reset-project": "node ./scripts/reset-project.js",
|
||||||
"android": "ANDROID_VARIANT=${ANDROID_VARIANT:-devDebug} 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",
|
"android:release": "ANDROID_VARIANT=${ANDROID_VARIANT:-productionRelease} expo run:android --variant=${ANDROID_VARIANT:-productionRelease}",
|
||||||
"ios": "expo run:ios",
|
"ios": "expo run:ios",
|
||||||
"ios:release": "expo run:ios --configuration Release",
|
"ios:release": "expo run:ios --configuration Release",
|
||||||
"web": "expo start --web",
|
"web": "expo start --web",
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|||||||
const REGISTRY_STORAGE_KEY = "@paseo:daemon-registry";
|
const REGISTRY_STORAGE_KEY = "@paseo:daemon-registry";
|
||||||
const LEGACY_SETTINGS_KEY = "@paseo:settings";
|
const LEGACY_SETTINGS_KEY = "@paseo:settings";
|
||||||
const FALLBACK_DAEMON_URL = "ws://localhost:6767/ws";
|
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"];
|
const DAEMON_REGISTRY_QUERY_KEY = ["daemon-registry"];
|
||||||
|
|
||||||
export type DaemonProfile = {
|
export type DaemonProfile = {
|
||||||
@@ -221,7 +225,9 @@ async function loadDaemonRegistryFromStorage(): Promise<DaemonProfile[]> {
|
|||||||
return envDefaults;
|
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));
|
await AsyncStorage.setItem(REGISTRY_STORAGE_KEY, JSON.stringify(fallback));
|
||||||
return fallback;
|
return fallback;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "Paseo backend server",
|
"description": "Paseo backend server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"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",
|
"dev:tsx": "NODE_ENV=development tsx watch --ignore '**/*.timestamp-*' src/server/index.ts",
|
||||||
"build": "tsc -p tsconfig.server.json",
|
"build": "tsc -p tsconfig.server.json",
|
||||||
"start": "NODE_ENV=production node dist/server/index.js",
|
"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 { v4 as uuidv4 } from "uuid";
|
||||||
import { readFile, mkdir, writeFile } from "fs/promises";
|
import { readFile, mkdir, writeFile } from "fs/promises";
|
||||||
import { exec } from "child_process";
|
import { exec, spawn } from "child_process";
|
||||||
import { promisify, inspect } from "util";
|
import { promisify, inspect } from "util";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import invariant from "tiny-invariant";
|
import invariant from "tiny-invariant";
|
||||||
@@ -75,6 +75,7 @@ const execAsync = promisify(exec);
|
|||||||
const ACTIVE_TITLE_GENERATIONS = new Set<string>();
|
const ACTIVE_TITLE_GENERATIONS = new Set<string>();
|
||||||
let restartRequested = false;
|
let restartRequested = false;
|
||||||
const KNOWN_AGENT_PROVIDERS: AgentProvider[] = ["claude", "codex"];
|
const KNOWN_AGENT_PROVIDERS: AgentProvider[] = ["claude", "codex"];
|
||||||
|
const RESTART_EXIT_DELAY_MS = 250;
|
||||||
|
|
||||||
type ProcessingPhase = "idle" | "transcribing" | "llm";
|
type ProcessingPhase = "idle" | "transcribing" | "llm";
|
||||||
|
|
||||||
@@ -886,9 +887,17 @@ export class Session {
|
|||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (typeof process.send === "function") {
|
||||||
|
process.send({
|
||||||
|
type: "paseo:restart",
|
||||||
|
...(reason ? { reason } : {}),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}, 250);
|
}, RESTART_EXIT_DELAY_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleDeleteAgentRequest(agentId: string): Promise<void> {
|
private async handleDeleteAgentRequest(agentId: string): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user