one default port, and it is 9000
Every PORT fallback in the tree now says 9000. There were three answers to one question, each defensible where it was written and none of them visible from the others: server.tsx and 19 sidecars 5000 a default from before there was an installer user-instance.ts 9010 what scripts/setup-old/setup.sh really wrote .env.example 9000 what we told people to write 5000 goes first because macOS binds it — AirPlay Receiver has owned it since Monterey, so a dev server there fails to bind or gets shadowed by something that answers. All 22 sites moved together, which is the point. Changing the app alone would have turned a consistent-but-wrong default into a split one: the app on 9000 while nineteen sidecars still dialled 5000. 9010 was the interesting one. It was the only value that ever matched a real machine, because it is what the old installer wrote — and it was in the single file whose disagreement would have broken chat alone, with nothing else looking wrong. Its own comment records the same bug being fixed once already, within the file, by a change that left it disagreeing with everything outside it. Note what these defaults actually are: the sidecars bind nothing. user-instance.ts has no listener at all — it builds ws:// and http:// URLs that both address the app's single listener. So every one of these numbers is a guess at where the app is, for a value that .env always supplies. Worth removing rather than aligning, which is a separate change. Not typechecked (empty node_modules, frozen installs). Every edited file parses under `bun build --no-bundle`; the pm2 profile loads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,7 @@ function defineProfile({ file, include, excluded }) {
|
||||
|
||||
// `cwd` is pinned because Bun auto-loads .env from the working directory (and the pty sidecar does
|
||||
// `import 'dotenv/config'`). Without it, starting pm2 from anywhere but the repo root silently falls
|
||||
// back to PORT=5000 with no POSTGRES_URL.
|
||||
// back to the default PORT with no POSTGRES_URL.
|
||||
//
|
||||
// It also decides where the install is. src/servers/data-path.ts derives OFFICER_ROOT as the PARENT of
|
||||
// the working directory, and data/, capabilities/ and dockers/ hang off that — so a wrong cwd does not
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import './servers/api/chat/opencode/sidecar-server'; // subscribe to the opencod
|
||||
import type { SidecarRegistration } from './servers/sidecar/registration-protocol';
|
||||
import { toShellUsername } from './servers/data-path';
|
||||
|
||||
const { PORT = '5000' } = process.env;
|
||||
const { PORT = '9000' } = process.env;
|
||||
|
||||
// Build static file routes from public/
|
||||
const publicRoutes: Record<string, (req: Request) => Response> = {};
|
||||
|
||||
@@ -23,7 +23,7 @@ import { logger } from './logger';
|
||||
/** A name has to survive being typed into a prompt and into a shell, so keep it boring. */
|
||||
const NAME_RE = /^[a-z0-9][a-z0-9-]{0,30}[a-z0-9]$|^[a-z0-9]$/;
|
||||
|
||||
const API_ORIGIN = `http://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_ORIGIN = `http://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
export function registerAgentPanelRoutes(router: Hono<any>): void {
|
||||
// GET /chat/agent-panels?dashboardId=… — the address book for one dashboard.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { sign } from '@@/jwt';
|
||||
|
||||
const { PORT = '5000', PUBLIC_URL } = process.env;
|
||||
const { PORT = '9000', PUBLIC_URL } = process.env;
|
||||
|
||||
const PUBLIC_HOST = (() => {
|
||||
try {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { DATA_PATH } from '../../data-path';
|
||||
// machine-facing interface. Same split officer-email already uses.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { loadState, flushAndSave, acquireLock, releaseLock, getState } from './s
|
||||
import { startAnthropicProxy, getProxySecret, ensureProxySecret } from './proxy';
|
||||
import { createSidecarConnector } from '../connect';
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// ── Startup ──
|
||||
|
||||
|
||||
@@ -61,9 +61,16 @@ async function resolveOwner() {
|
||||
const dbUser = await resolveOwner();
|
||||
const email = dbUser.email;
|
||||
|
||||
// Same officer instance for both, so the fallback port has to agree. It used to default to 5000 for the
|
||||
// WebSocket and 9010 for the REST base, which would have split them apart if PORT were ever unset.
|
||||
const OFFICER_PORT = process.env.PORT ?? '9010';
|
||||
// Both URLs address the SAME officer instance — this file binds nothing, and the app serves HTTP and
|
||||
// WebSocket on one listener. So the fallback port has to agree, and twice it did not: 5000 for the
|
||||
// WebSocket against 9010 for the REST base here, and then 9010 here against 5000 in the app and every
|
||||
// other sidecar. The second one was the worse half, because chat is the only thing that would have
|
||||
// broken and nothing else would have looked wrong.
|
||||
//
|
||||
// 9000 everywhere now, matching server.tsx and .env.example. 9010 was the old installer's default
|
||||
// (scripts/setup-old/setup.sh), which is why it was the only one of the three that ever matched a real
|
||||
// machine.
|
||||
const OFFICER_PORT = process.env.PORT ?? '9000';
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${OFFICER_PORT}`;
|
||||
const OFFICER_API_URL = process.env.OFFICER_API_URL ?? `http://127.0.0.1:${OFFICER_PORT}`;
|
||||
const MCP_SERVER_SCRIPT = resolve(import.meta.dir, '../../mcp-tool-server.ts');
|
||||
|
||||
@@ -5,7 +5,7 @@ type AnyCommand = SidecarCommand;
|
||||
type AnyEvent = SidecarEvent;
|
||||
|
||||
type SidecarConnectorConfig = {
|
||||
apiUrl: string; // ws://127.0.0.1:5000/api/sidecar/register
|
||||
apiUrl: string; // ws://127.0.0.1:9000/api/sidecar/register
|
||||
name: string;
|
||||
capabilities: string[];
|
||||
onCommand: (cmd: AnyCommand, reply: (msg: AnyEvent) => void) => void;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { broadcastEmailNew } from './routes';
|
||||
import { startEmailServer } from './http';
|
||||
import { createSidecarConnector } from '../connect';
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// The sidecar used to reach BACK into the platform's queue over this socket to get a sync run —
|
||||
// enqueueViaWs / listJobsViaWs and a pending-response map. Syncs run in this process now
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
// sidecar from being a general-purpose SSRF hop into whatever else is on that host.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// Everything under /api/v1 the UI legitimately needs.
|
||||
//
|
||||
|
||||
@@ -54,7 +54,7 @@ import { MIN_VERSION_LABEL } from './version';
|
||||
// — the mistake the Soulseek panels made with 37 raw upstream calls. Every quirk is absorbed here.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -51,7 +51,7 @@ import { getConfig } from './upstream';
|
||||
// update/*, installation/*, mail config, settings writes, ownership transfer — is deliberately unreachable.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -43,7 +43,7 @@ import { getConfig, probe } from './upstream';
|
||||
// general proxy, and why HLS forces it to keep Jellyfin's own paths.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { callMemos, getMemosConfig, invalidateMemosConfig, normalizeBase, probe
|
||||
// SSRF hop into whatever else is on that host.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// Everything under /api/v1 the UI legitimately needs. Auth routes are excluded on purpose: signin and
|
||||
// signout would mint or destroy sessions on the instance, and this sidecar authenticates with a stored
|
||||
|
||||
@@ -114,7 +114,7 @@ const asKeys = (v: unknown): string[] | null =>
|
||||
// `v` = per-album version stamp; unchanged `v` ⇒ nothing changed ⇒ the phone can skip re-downloading.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// ── Audio-streaming HTTP server ──
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import type { Notification, NotifyType } from './types';
|
||||
// the visible string is composed here rather than sent by the producer.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
const VALID_TYPES: NotifyType[] = ['job', 'mail', 'agent', 'download', 'test'];
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { runOpenCodeTurnOnServe, killServeTurn, listRunningServeTurns, stopAllSe
|
||||
// CRUD only, with turns spawned as `opencode run --dir <cwd>` subprocesses — that path was deleted on
|
||||
// 2026-08-10 once the serve had streaming, mid-turn injection and interrupt working end to end.
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
const OPENCODE_BIN = process.env.OPENCODE_BIN || join(homedir(), '.opencode', 'bin', 'opencode');
|
||||
const SERVE_CWD = join(DATA_PATH, 'opencode_server');
|
||||
const HEALTH_TIMEOUT_MS = 20_000;
|
||||
|
||||
@@ -46,7 +46,7 @@ import { getConfig } from './upstream';
|
||||
// ETag included. The administrative half of Immich's API is unreachable — see routes.ts for the list.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -19,7 +19,7 @@ import { startServer } from './server.mjs';
|
||||
|
||||
import 'dotenv/config';
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
const REGISTER_URL = `${API_URL}/api/sidecar/register`;
|
||||
const RECONNECT_DELAYS = [200, 500, 1000, 2000, 4000, 8000, 15000];
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import { handleOfficerRoute } from './officer';
|
||||
// (src/servers/sidecar/vault/index.ts) once the client needs real-time updates. SignalR carries its
|
||||
// credential as an `?access_token=` query param on the socket, so the key injection differs from HTTP.
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -45,7 +45,7 @@ import { getTransmissionConfig } from './upstream';
|
||||
// platform, and which daemon to talk to is per-owner data.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { getVaultBase, getVaultWsBase, stripHopByHop, redactPath } from './upstr
|
||||
// The server listens on a random loopback port, reported to the API on connect so it can route here.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as vncManager from './vnc-manager';
|
||||
import { createSidecarConnector } from '../connect';
|
||||
import { getOwnerHomeDir } from '@@/data-path';
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
// ── Command handlers ──
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ import { invalidateAll } from './resolve';
|
||||
// WALLET_LOCKED from signing paths only; every read above keeps working.
|
||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||
|
||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||
function getFreePort(): number {
|
||||
|
||||
Reference in New Issue
Block a user