Files
nntrivi2001 5fe5d51b1b 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
2026-10-06 22:48:09 +07:00

48 lines
1.5 KiB
JavaScript

/**
* @file HTTP surface for AgentHub's own git credentials (git-credentials.js):
* list, save/replace, delete. Like the AI Proxy routes, nothing here ever
* returns a password — `GET` reports `hasToken` — and every write is behind
* the same-origin guard. A lane's fetch/pull/push also saves one, through
* `POST /api/lanes/:id/git/:action` with `credentials.remember`.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
const express = require("express");
const creds = require("../lib/git-credentials");
const { sameOriginGuard } = require("../lib/same-origin");
const router = express.Router();
function fail(res, e) {
const status = e.code === "EBADHOST" || e.code === "EBADCRED" ? 400 : 500;
res.status(status).json({ error: { code: e.code || "EINTERNAL", message: e.message } });
}
router.get("/", (_req, res) => {
res.json({ items: creds.list() });
});
router.post("/", sameOriginGuard, (req, res) => {
try {
const { protocol, host, username, password } = req.body || {};
creds.save({ protocol, host, username, password });
res.json({ items: creds.list() });
} catch (e) {
fail(res, e);
}
});
router.delete("/:protocol/:host", sameOriginGuard, (req, res) => {
try {
if (!creds.remove(req.params.protocol, req.params.host)) {
return res.status(404).json({ error: { code: "ENOTFOUND", message: "no such credential" } });
}
res.json({ items: creds.list() });
} catch (e) {
fail(res, e);
}
});
module.exports = router;