chore: import gateway, exchange secrets, env example
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
GATEWAY_PORT=8080
|
||||
|
||||
# Override ambiente per ogni MCP exchange (precedenza: env > secret > default)
|
||||
DERIBIT_TESTNET=true
|
||||
BYBIT_TESTNET=true
|
||||
HYPERLIQUID_TESTNET=true
|
||||
ALPACA_PAPER=true
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
admin off
|
||||
auto_https off
|
||||
}
|
||||
|
||||
:8080 {
|
||||
log {
|
||||
output stdout
|
||||
format console
|
||||
}
|
||||
|
||||
handle_path /mcp-deribit/* {
|
||||
reverse_proxy mcp-deribit:9011
|
||||
}
|
||||
handle_path /mcp-hyperliquid/* {
|
||||
reverse_proxy mcp-hyperliquid:9012
|
||||
}
|
||||
handle_path /mcp-bybit/* {
|
||||
reverse_proxy mcp-bybit:9019
|
||||
}
|
||||
handle_path /mcp-alpaca/* {
|
||||
reverse_proxy mcp-alpaca:9020
|
||||
}
|
||||
handle_path /mcp-macro/* {
|
||||
reverse_proxy mcp-macro:9013
|
||||
}
|
||||
handle_path /mcp-sentiment/* {
|
||||
reverse_proxy mcp-sentiment:9014
|
||||
}
|
||||
|
||||
# Landing page statica
|
||||
handle {
|
||||
root * /srv
|
||||
file_server
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Cerbero — MCP gateway</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Cerbero</h1>
|
||||
<p>Sistema trading autonomo crypto, architettura MCP-only.</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<table id="services">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Stato</th>
|
||||
<th>Servizio</th>
|
||||
<th>Porta int.</th>
|
||||
<th>Descrizione</th>
|
||||
<th>Link</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-path="/mcp-memory">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-memory</td>
|
||||
<td>9015</td>
|
||||
<td>Store L1/L2, system prompt base + dyn</td>
|
||||
<td><a href="/mcp-memory/health">health</a> · <a href="/mcp-memory/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-scheduler">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-scheduler</td>
|
||||
<td>9016</td>
|
||||
<td>Recurring task + core agent runner</td>
|
||||
<td><a href="/mcp-scheduler/health">health</a> · <a href="/mcp-scheduler/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-deribit">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-deribit</td>
|
||||
<td>9011</td>
|
||||
<td>Options testnet order/market</td>
|
||||
<td><a href="/mcp-deribit/health">health</a> · <a href="/mcp-deribit/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-hyperliquid">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-hyperliquid</td>
|
||||
<td>9012</td>
|
||||
<td>Perp DEX testnet</td>
|
||||
<td><a href="/mcp-hyperliquid/health">health</a> · <a href="/mcp-hyperliquid/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-macro">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-macro</td>
|
||||
<td>9013</td>
|
||||
<td>FRED indicators + Finnhub calendar</td>
|
||||
<td><a href="/mcp-macro/health">health</a> · <a href="/mcp-macro/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-sentiment">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-sentiment</td>
|
||||
<td>9014</td>
|
||||
<td>CryptoPanic news feed</td>
|
||||
<td><a href="/mcp-sentiment/health">health</a> · <a href="/mcp-sentiment/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-telegram">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-telegram</td>
|
||||
<td>9017</td>
|
||||
<td>Bot commands + notifiche operatore</td>
|
||||
<td><a href="/mcp-telegram/health">health</a> · <a href="/mcp-telegram/docs">docs</a></td>
|
||||
</tr>
|
||||
<tr data-path="/mcp-portfolio">
|
||||
<td><span class="status" aria-label="unknown"></span></td>
|
||||
<td>mcp-portfolio</td>
|
||||
<td>9018</td>
|
||||
<td>Holdings + yfinance + UI htmx</td>
|
||||
<td><a href="/mcp-portfolio/health">health</a> · <a href="/gui">gui</a> · <a href="/mcp-portfolio/docs">docs</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<section style="margin-top: 2rem;">
|
||||
<h2 style="color: var(--accent); margin-bottom: 0.5rem;">Console operativa</h2>
|
||||
<p><a href="/console" style="font-size: 1.1rem;">/console</a> — run del core agent, eventi stdout/stderr, L1 live, trigger manuale.</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Status aggiornato ogni 5 s. Gateway Caddy su porta configurata via <code>GATEWAY_PORT</code>.</p>
|
||||
</footer>
|
||||
|
||||
<script src="/status.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
const rows = document.querySelectorAll("tr[data-path]");
|
||||
|
||||
async function poll() {
|
||||
for (const row of rows) {
|
||||
const dot = row.querySelector(".status");
|
||||
try {
|
||||
const r = await fetch(`${row.dataset.path}/health`, {
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
});
|
||||
dot.classList.toggle("ok", r.ok);
|
||||
dot.classList.toggle("err", !r.ok);
|
||||
dot.setAttribute("aria-label", r.ok ? "ok" : "error");
|
||||
} catch {
|
||||
dot.classList.remove("ok");
|
||||
dot.classList.add("err");
|
||||
dot.setAttribute("aria-label", "unreachable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poll();
|
||||
setInterval(poll, 5000);
|
||||
@@ -0,0 +1,101 @@
|
||||
:root {
|
||||
--bg: #0f172a;
|
||||
--fg: #e2e8f0;
|
||||
--muted: #94a3b8;
|
||||
--card: #1e293b;
|
||||
--border: #334155;
|
||||
--ok: #22c55e;
|
||||
--err: #ef4444;
|
||||
--unknown: #64748b;
|
||||
--accent: #38bdf8;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
header, main, footer {
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
margin: 0 0 0.25rem;
|
||||
color: var(--accent);
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
header p {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--card);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
th {
|
||||
background: #0f172a;
|
||||
color: var(--muted);
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
tr:last-child td { border-bottom: none; }
|
||||
|
||||
td:nth-child(3) {
|
||||
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--unknown);
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.status.ok { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
|
||||
.status.err { background: var(--err); box-shadow: 0 0 8px var(--err); }
|
||||
|
||||
footer {
|
||||
color: var(--muted);
|
||||
font-size: 0.85rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--border);
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
Reference in New Issue
Block a user