ship: project dashboard pages + sidebar/chat overhaul + log tooling

Ships accumulated WIP that was sitting uncommitted:
- New (home) dashboard route pages: overview, code, data/tables, hosting,
  infrastructure, services, domains, integrations, agents, analytics, api,
  automations, billing, logs, market, marketing(+seo/social), product, security,
  storage, users, settings(app/auth).
- dashboard-sidebar, project-icon-rail, chat-panel updates; mcp + anatomy route
  changes; package.json/lock dependency bumps.
- Coolify log tooling (scripts/fetch-app-logs.mjs + fetch-app-logs-ssh.mjs) and
  ai-new-thread.md "Fetching Production Logs" section.

Excludes throwaway debug scripts and telemetry audit dumps (the latter contain
live credentials and must not be committed).
This commit is contained in:
2026-06-12 18:09:09 -07:00
parent 0f212c750b
commit eb198e2d4d
37 changed files with 8982 additions and 533 deletions

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env node
/**
* Fetch a Coolify application's runtime (container stdout/stderr) logs via the
* Coolify REST API — no dashboard login needed.
*
* Usage (from the vibn-frontend/ directory):
* node scripts/fetch-app-logs.mjs <appUuid> [lines]
*
* The <appUuid> is the last path segment of the Coolify app URL, e.g.
* https://coolify.vibnai.com/project/.../application/hou4vy5mtyg5mrx3w4nl2lxv
* ^^^^^^^^^^^^^^^^^^^^^^^^ appUuid
*
* Reads COOLIFY_URL + COOLIFY_API_TOKEN from vibn-frontend/.env.local.
* Note: Coolify's /logs endpoint returns the *last N lines* of container output,
* not a date range — pull a generous N and filter by date client-side if needed.
*/
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
function loadEnv(file) {
const out = {};
try {
for (const line of fs.readFileSync(file, "utf8").split("\n")) {
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);
if (!m) continue;
let v = m[2];
if (
(v.startsWith('"') && v.endsWith('"')) ||
(v.startsWith("'") && v.endsWith("'"))
)
v = v.slice(1, -1);
out[m[1]] = v;
}
} catch {}
return out;
}
const env = { ...loadEnv(path.join(__dirname, "../.env.local")), ...process.env };
const COOLIFY_URL = env.COOLIFY_URL || "https://coolify.vibnai.com";
const TOKEN = env.COOLIFY_API_TOKEN;
const uuid = process.argv[2];
const lines = Math.max(1, Math.min(parseInt(process.argv[3] || "1000", 10), 5000));
if (!uuid) {
console.error("Usage: node scripts/fetch-app-logs.mjs <appUuid> [lines]");
process.exit(1);
}
if (!TOKEN) {
console.error("Missing COOLIFY_API_TOKEN in vibn-frontend/.env.local");
process.exit(1);
}
const url = `${COOLIFY_URL}/api/v1/applications/${uuid}/logs?lines=${lines}`;
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
});
if (!res.ok) {
console.error(`Coolify API ${res.status} on ${url}:\n${await res.text()}`);
process.exit(1);
}
const data = await res.json();
process.stdout.write((data?.logs ?? "").toString());
process.stdout.write("\n");