4a665da79e
- /ws-pty carries the dashboard token like /ws (the terminal never attached with DASHBOARD_TOKEN set), and so does everything that cannot send the header: images, downloads, exports, drops (withToken/tokenHeader). A refused upgrade answers 401/403 and is logged and counted by reason. - The browser asks for a missing or wrong token (401 EUNAUTHORIZED) and takes ?token= from the link agenthub start prints, dropping it from the URL. - The CLI sends the token (DASHBOARD_TOKEN, else the one the running server publishes 0600 in <data dir>/runtime/dashboard-token); MCP and statusline read the same file. - DASHBOARD_HOST takes a list, and 127.0.0.1 is always listened on too, so a LAN-only bind keeps hooks and the CLI working. - agenthub start --host/--allowed-hosts/--token are saved in <data dir>/network.json for every later start; a wide bind gets a token; every reachable URL is printed. - tmux < 3.7 is an amber, once-per-version notice that says only the pane scrollbar is missing, with a ~/.local build instead of sudo make install. - INSTALL: PATH belongs in ~/.profile for sudo -iu/ssh; WSL mirrored notes.
51 lines
2.0 KiB
JavaScript
51 lines
2.0 KiB
JavaScript
/**
|
|
* @file Where the running dashboard answers, for a process that is NOT the
|
|
* dashboard: the `agenthub` CLI, the MCP server (`mcp/server.js`) and the
|
|
* statusline (`statusline/statusline.js`). An explicit CLAUDE_DASHBOARD_PORT /
|
|
* DASHBOARD_PORT wins (the hook handler's contract), then the live-server
|
|
* discovery file `~/.claude/.agenthub.json` (`server-info.js`, PID-checked),
|
|
* then the default port. `dashboardToken()` is the token such a process sends
|
|
* when the dashboard requires one: `DASHBOARD_TOKEN`, else the one the running
|
|
* server published (`<data dir>/runtime/dashboard-token`, 0600 — see
|
|
* `security.publishDashboardToken`), so a shell that never exported it still
|
|
* reaches a token-gated dashboard. Never throws.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const path = require("node:path");
|
|
|
|
/** Base URL of the live dashboard, e.g. `http://127.0.0.1:4820`. */
|
|
function dashboardUrl() {
|
|
const envPort = process.env.CLAUDE_DASHBOARD_PORT || process.env.DASHBOARD_PORT;
|
|
if (envPort) return `http://127.0.0.1:${envPort}`;
|
|
try {
|
|
const { resolveDashboardPort } = require(path.join(__dirname, "server-info.js"));
|
|
const port = resolveDashboardPort();
|
|
if (port) return `http://127.0.0.1:${port}`;
|
|
} catch {
|
|
/* discovery unavailable — fall through to the default */
|
|
}
|
|
return "http://127.0.0.1:4820";
|
|
}
|
|
|
|
/** The dashboard token to send, or null when none is configured or readable. */
|
|
function dashboardToken() {
|
|
const env = process.env.DASHBOARD_TOKEN;
|
|
if (typeof env === "string" && env) return env;
|
|
try {
|
|
const { tokenFilePath } = require(path.join(__dirname, "security.js"));
|
|
const t = require("node:fs").readFileSync(tokenFilePath(), "utf8").trim();
|
|
return t || null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/** The headers carrying `dashboardToken()` (both spellings the server takes); {} with none. */
|
|
function tokenHeaders() {
|
|
const t = dashboardToken();
|
|
return t ? { "x-dashboard-token": t } : {};
|
|
}
|
|
|
|
module.exports = { dashboardUrl, dashboardToken, tokenHeaders };
|