Files
Claude-Code-Monitor/mcp/build/ui/banner.js
T
nntrivi2001 7357070fb9 chore: remove unused desktop app, cloud deployment infra, and monitoring stack
Deletes desktop/ (Electron wrapper), deployments/ (Helm/Kustomize/
Terraform/CI for cloud deploy), and monitoring/ (Prometheus + Grafana
stack) along with DESKTOP.md, DEPLOYMENT.md, docker-compose.full.yml,
their npm scripts, and every dangling reference across README,
ARCHITECTURE, INSTALL, SETUP, docs/, and the repeated per-file
MODULE_GUIDE "Observability" boilerplate comment. The GET /api/metrics
endpoint itself is untouched — it's the dashboard's own route, not
part of the removed monitoring stack.
2026-08-11 12:16:54 +07:00

123 lines
7.3 KiB
JavaScript

/**
* @file banner.ts
* @description Console startup UI for the MCP server's non-stdio transports (HTTP and REPL):
* the ASCII-art wordmark, a boxed server-info panel (version, transport, dashboard URL, port,
* tool count, mutation/destructive policy state), a "ready" line, and a shutdown message. The
* stdio transport never calls any of these, since stdout there is the MCP JSON-RPC channel.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
/* =============================================================================
* MODULE_GUIDE — extended in-file reference (comments only; safe to read, never executed)
* =============================================================================
* **Purpose:** Dashboard module consumed by the React client, MCP tools, or desktop shell depending on deployment mode.
*
* ## Design constraints
* - Local-first: no telemetry leaves the machine unless the user configures webhooks.
* - Fail-safe hooks path on the server must never block Claude Code; UI mirrors that
* philosophy by degrading gracefully (empty states, stale badges, reconnect loops).
* - Destructive flows stay behind explicit confirmation modals and server-side gates.
* - Internationalization: user-visible strings belong in i18n JSON, not literals here.
*
* ## Remote data & SSH
* Remote Data Sources let operators aggregate multiple machines. SSH entries describe
* how to reach a peer dashboard; the global data scope (`dataScope.ts`) narrows every
* scoped GET via `?sources=`. Health checks and import history surface in Settings.
*
* ## Public surface
* - `printBanner` — exported API; see TSDoc on the symbol for behavior.
* - `printServerInfo` — exported API; see TSDoc on the symbol for behavior.
* - `printReady` — exported API; see TSDoc on the symbol for behavior.
* - `printShutdown` — exported API; see TSDoc on the symbol for behavior.
*
* ## Testing pointers
* - Prefer colocated `__tests__` with Vitest + Testing Library for UI.
* - Server contract changes require `npm run test:server` and OpenAPI sync.
* - MCP edits: `npm run mcp:typecheck` and `npm run mcp:build`.
*
* ## Related docs
* - `ARCHITECTURE.md` — hooks → API → SQLite → WebSocket → UI pipeline.
* - `docs/API.md` — REST reference.
* - `.claude/skills/file-headers/` — mandatory `@author` header policy.
* ============================================================================= */
/* -----------------------------------------------------------------------------
* EXPORT CATALOG — quick index of symbols defined below (documentation only).
* -----------------------------------------------------------------------------
* **printBanner**
* Part of this module's public contract. Downstream imports should treat
* the signature and return type as stable unless release notes say otherwise.
* When behavior changes, update the `@file` overview and relevant tests.
*
* **printServerInfo**
* Part of this module's public contract. Downstream imports should treat
* the signature and return type as stable unless release notes say otherwise.
* When behavior changes, update the `@file` overview and relevant tests.
*
* **printReady**
* Part of this module's public contract. Downstream imports should treat
* the signature and return type as stable unless release notes say otherwise.
* When behavior changes, update the `@file` overview and relevant tests.
*
* **printShutdown**
* Part of this module's public contract. Downstream imports should treat
* the signature and return type as stable unless release notes say otherwise.
* When behavior changes, update the `@file` overview and relevant tests.
*
* ----------------------------------------------------------------------------- */
import * as c from "./colors.js";
/** ASCII-art wordmark rendered by {@link printBanner} with a color gradient. */
const BANNER = `
$$\\ $$\\ $$$$$$\\ $$$$$$$\\ $$$$$$$$\\ $$\\
$$$\\ $$$ |$$ __$$\\ $$ __$$\\ \\__$$ __| $$ |
$$$$\\ $$$$ |$$ / \\__|$$ | $$ | $$ | $$$$$$\\ $$$$$$\\ $$ | $$$$$$$\\
$$\\$$\\$$ $$ |$$ | $$$$$$$ | $$ |$$ __$$\\ $$ __$$\\ $$ |$$ _____|
$$ \\$$$ $$ |$$ | $$ ____/ $$ |$$ / $$ |$$ / $$ |$$ |\\$$$$$$\\
$$ |\\$ /$$ |$$ | $$\\ $$ | $$ |$$ | $$ |$$ | $$ |$$ | \\____$$\\
$$ | \\_/ $$ |\\$$$$$$ |$$ | $$ |\\$$$$$$ |\\$$$$$$ |$$ |$$$$$$$ |
\\__| \\__| \\______/ \\__| \\__| \\______/ \\______/ \\__|\\_______/ `;
/** Prints {@link BANNER} one line per gradient color (cyan to magenta).
* Called at HTTP/REPL startup only. */
export function printBanner() {
const gradient = [c.brightCyan, c.cyan, c.brightBlue, c.blue, c.brightMagenta, c.magenta];
const lines = BANNER.split("\n").filter((l) => l.length > 0);
for (let i = 0; i < lines.length; i++) {
const colorFn = gradient[Math.min(i, gradient.length - 1)];
process.stdout.write(colorFn(lines[i]) + "\n");
}
process.stdout.write("\n");
}
/** Prints a boxed config summary beneath the banner, shared by HTTP (`port`
* set) and REPL (`port` omitted). Mutations/Destructive rows mirror the
* `policy/tool-guards.ts` flags, warning-colored when enabled. Ends with a
* reminder that the dashboard must already be running at the printed URL. */
export function printServerInfo(info) {
const divider = c.dim(c.cyan("─".repeat(62)));
const line = (label, value) => ` ${c.dim(c.cyan("│"))} ${c.label(label.padEnd(18))} ${value}`;
process.stdout.write(divider + "\n");
process.stdout.write(` ${c.dim(c.cyan("│"))} ${c.bold(c.brightWhite("Agent Dashboard MCP Server"))}\n`);
process.stdout.write(divider + "\n");
process.stdout.write(line("Version", c.brightCyan(info.version)) + "\n");
process.stdout.write(line("Transport", c.accent(info.transport.toUpperCase())) + "\n");
process.stdout.write(line("Dashboard API", c.green(info.dashboard)) + "\n");
if (info.port !== undefined) {
process.stdout.write(line("HTTP Port", c.brightYellow(String(info.port))) + "\n");
}
process.stdout.write(line("Tools Registered", c.brightWhite(String(info.tools))) + "\n");
process.stdout.write(line("Mutations", info.mutations ? c.warn("ENABLED") : c.success("disabled")) + "\n");
process.stdout.write(line("Destructive", info.destructive ? c.error("ENABLED") : c.success("disabled")) + "\n");
process.stdout.write(divider + "\n");
process.stdout.write(` ${c.dim(c.cyan("│"))} ${c.warn("⚠")} ${c.dim("Dashboard must be running at the URL above.")}\n`);
process.stdout.write(` ${c.dim(c.cyan("│"))} ${c.dim(" Start it first:")} ${c.brightWhite("npm run dev")} ${c.dim("or")} ${c.brightWhite("npm start")}\n`);
process.stdout.write(divider + "\n\n");
}
/** Prints "Server ready" once the HTTP server has bound to its port; not
* used by the REPL transport. */
export function printReady(transport) {
const icon = "✔";
process.stdout.write(` ${c.success(icon)} ${c.bold(c.brightWhite("Server ready"))} ${c.muted(`(${transport})`)}\n\n`);
}
/** Prints "Shutting down...". Called from HTTP/REPL shutdown paths and
* `index.ts`'s SIGINT/SIGTERM handler; never from stdio. */
export function printShutdown() {
process.stdout.write(`\n ${c.warn("⏻")} ${c.bold(c.brightWhite("Shutting down..."))}\n`);
}