feat: v2.5.5 — AI Router renamed AI Proxy, reload onto new builds, update no longer spins

AI Proxy (was AI Router):
- server/lib/ai-proxies.js, proxy-apply.js, routes/ai-proxies.js mounted at
  /api/ai-proxies and the old /api/ai-routers; `router` still accepted on the
  start routes; profiles move to <CLAUDE_HOME>/agenthub-proxies/
- dashboard_runs.router renamed in place to proxy: an older build on the same
  DB fails on that column, so dev and prod sharing one DB update together
- a proxy's baseUrl stored as its root (a typed /v1 made /v1/v1/messages);
  Test probes Claude /v1/messages and Codex /v1/responses
- Settings → AI Proxy (/settings/ai-router redirects), ProxyPicker

Updates:
- every tab reloads onto the new UI build when its WebSocket reconnects to a
  server of another version (lib/newBuildReload.ts, once per version)
- Update now stops waiting on a plugin chain that failed or pulled nothing
  (the old server never goes down), and reloads as soon as a new version answers

Also:
- a pane whose command exits at once says so (EPANEEXITED) instead of
  "Command failed: tmux set-option … mouse on"
- the pane drag preview draws where the pane actually lands
This commit is contained in:
2026-10-06 22:48:09 +07:00
parent dd9b23106c
commit 5fe5d51b1b
82 changed files with 1792 additions and 1412 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ const schemas = {
},
resume: { type: "boolean", description: "Offers Resume last session" },
bypass: { type: "boolean", description: "Offers the per-run Bypass permissions switch" },
routerCapable: { type: "boolean", description: "Can use an AI Router profile" },
proxyCapable: { type: "boolean", description: "Can use an AI Proxy profile" },
install: {
type: "object",
nullable: true,
+1 -1
View File
@@ -585,7 +585,7 @@ const paths = {
},
403: {
description:
"ESECRET — `.claude/settings.local.json` (the AI Router key) is refused at every rev, at any depth, and under any path that resolves to it (a symlinked `.claude`).",
"ESECRET — `.claude/settings.local.json` (where an older build kept the AI Proxy key) is refused at every rev, at any depth, and under any path that resolves to it (a symlinked `.claude`).",
},
404: { description: "Lane not found." },
},
+3 -23
View File
@@ -329,17 +329,6 @@ const schemas = {
description:
"True when the real environment, or the checkout's own `.env`, set this variable at startup: either wins over the settings file, so a saved value is overridden again at the next start.",
},
routers: {
type: "object",
properties: {
missing: {
type: "array",
items: { type: "string" },
description:
"`<lane id> (<title>): <profile>` for every lane naming an AI Router profile the new home's store (`<CLAUDE_HOME>/agenthub-routers/`) does not have — such a lane starts on its base configuration.",
},
},
},
},
},
@@ -1233,7 +1222,7 @@ const paths = {
tags: ["Settings"],
summary: "Get the active Codex home directory",
description:
"Returns the Codex home directory (CODEX_HOME, else `<homedir>/.codex`) the dashboard reads Codex config and rollout journals from, writes AI Router layers into, and hands every codex lane pane through tmux `-e`.",
"Returns the Codex home directory (CODEX_HOME, else `<homedir>/.codex`) the dashboard reads Codex config and rollout journals from, writes AI Proxy layers into at each spawn, and hands every codex lane pane through tmux `-e`.",
operationId: "getCodexHome",
responses: {
200: {
@@ -1258,7 +1247,7 @@ const paths = {
tags: ["Settings"],
summary: "Update the Codex home directory",
description:
"Same validation and persistence as PUT /api/settings/claude-home (403 EBADORIGIN from another site, settings file, EBADHOME for a path that is or contains the OS home, INVALID_PATH otherwise). On success it re-writes the AI Router layer (`<name>.config.toml`) of every codex lane on a router into the new home, reported as `routers`, because `codex -p <name>` loads it from there. A codex pane already running keeps its old home until restarted.",
"Same validation and persistence as PUT /api/settings/claude-home (403 EBADORIGIN from another site, settings file, EBADHOME for a path that is or contains the OS home, INVALID_PATH otherwise). Nothing is re-written here: a session's AI Proxy layer (`<name>.config.toml`) is written into the current home at its spawn. A codex pane already running keeps its old home until restarted.",
operationId: "updateCodexHome",
requestBody: {
required: true,
@@ -1280,26 +1269,17 @@ const paths = {
"application/json": {
schema: {
type: "object",
required: ["ok", "codex_home", "env_owned", "routers"],
required: ["ok", "codex_home", "env_owned"],
properties: {
ok: { type: "boolean", enum: [true] },
codex_home: { type: "string" },
env_owned: { type: "boolean" },
routers: {
type: "object",
required: ["updated", "failed"],
properties: {
updated: { type: "integer" },
failed: { type: "array", items: { type: "string" } },
},
},
},
},
example: {
ok: true,
codex_home: "/Users/son/.codex-work",
env_owned: false,
routers: { updated: 1, failed: [] },
},
},
},