5fe5d51b1b
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
48 lines
1.5 KiB
JavaScript
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;
|