- Replace single 'Connect to Claude / ChatGPT' button with a modal picker offering Claude.ai web, Claude Desktop, Codex CLI, and ChatGPT/GPT Actions. - Add /oauth/connect-claude-ai backend route that redirects to Anthropic's official https://claude.ai/api/mcp/auth_callback OAuth callback. - Update MCP callback result page with browser-specific instructions for Claude.ai web, Claude Desktop, ChatGPT/GPT Actions, and Codex CLI. - Deploy new app and hermes images to K8s.
369 lines
16 KiB
HTML
369 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SquareMCP — AI Social Gateway</title>
|
|
<link rel="stylesheet" href="styles.css">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<!-- Password Reset Request View -->
|
|
<div id="reset-request-view" class="view hidden">
|
|
<div class="auth-card">
|
|
<div class="logo">
|
|
<div class="logo-mark">S</div>
|
|
<h1>Reset Password</h1>
|
|
<p>Enter your email to receive a reset link</p>
|
|
</div>
|
|
<form id="reset-request-form" class="auth-form">
|
|
<input type="email" name="email" placeholder="Email" aria-label="Email address" required>
|
|
<button type="submit" class="btn btn-primary">Send Reset Link</button>
|
|
<p class="error-msg" id="reset-request-error"></p>
|
|
<p class="success-msg" id="reset-request-success"></p>
|
|
<a href="#" id="back-to-login" style="color:#888;font-size:13px;text-align:center;display:block;margin-top:12px;">Back to login</a>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Password Reset Confirm View -->
|
|
<div id="reset-confirm-view" class="view hidden">
|
|
<div class="auth-card">
|
|
<div class="logo">
|
|
<div class="logo-mark">S</div>
|
|
<h1>New Password</h1>
|
|
<p>Enter your new password below</p>
|
|
</div>
|
|
<form id="reset-confirm-form" class="auth-form">
|
|
<input type="password" name="password" placeholder="New password (min 8 chars)" aria-label="New password" required minlength="8">
|
|
<button type="submit" class="btn btn-primary">Update Password</button>
|
|
<p class="error-msg" id="reset-confirm-error"></p>
|
|
<p class="success-msg" id="reset-confirm-success"></p>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Login View -->
|
|
<div id="login-view" class="view">
|
|
<div class="auth-card">
|
|
<div class="logo">
|
|
<div class="logo-mark">S</div>
|
|
<h1>SquareMCP</h1>
|
|
<p>AI Social Media Gateway</p>
|
|
</div>
|
|
<div class="tabs">
|
|
<button class="tab-btn active" data-tab="login">Sign In</button>
|
|
<button class="tab-btn" data-tab="signup">Create Account</button>
|
|
</div>
|
|
<form id="login-form" class="auth-form">
|
|
<input type="email" name="email" placeholder="Email" aria-label="Email address" required>
|
|
<input type="password" name="password" placeholder="Password" aria-label="Password" required minlength="8">
|
|
<button type="submit" class="btn btn-primary">Sign In</button>
|
|
<p class="error-msg" id="login-error"></p>
|
|
</form>
|
|
<form id="signup-form" class="auth-form hidden">
|
|
<input type="email" name="email" placeholder="Email" aria-label="Email address" required>
|
|
<input type="password" name="password" placeholder="Password (min 8 chars)" aria-label="Password" required minlength="8">
|
|
<button type="submit" class="btn btn-primary">Create Account</button>
|
|
<p class="error-msg" id="signup-error"></p>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dashboard View -->
|
|
<div id="dashboard-view" class="view hidden">
|
|
<header class="app-header">
|
|
<div class="header-left">
|
|
<div class="logo-mark small">S</div>
|
|
<span class="app-title">SquareMCP</span>
|
|
</div>
|
|
<div class="header-right">
|
|
<nav class="header-nav">
|
|
<button class="nav-link active" data-view="platforms">Platforms</button>
|
|
<button class="nav-link" data-view="analytics">Analytics</button>
|
|
<button class="nav-link" data-view="invoices">Invoices</button>
|
|
<button class="nav-link" data-view="webhooks">Webhooks</button>
|
|
<button class="nav-link hidden" data-view="admin" id="admin-nav">Admin</button>
|
|
</nav>
|
|
<span id="user-email" class="user-email"></span>
|
|
<button id="logout-btn" class="btn btn-ghost">Logout</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="dashboard">
|
|
<section class="welcome">
|
|
<h2>Connect your accounts</h2>
|
|
<p>Connect once. Then ask Claude or ChatGPT to post, search your notes, or send email — without touching any of these apps.</p>
|
|
<button id="connect-mcp-btn" class="btn btn-primary" style="margin-top:16px;" aria-label="Connect Claude.ai, ChatGPT, Claude Desktop, or Codex CLI" title="Connect Claude.ai, ChatGPT, Claude Desktop, or Codex CLI">Connect AI Client</button>
|
|
</section>
|
|
|
|
<section class="usage-bar" id="usage-bar">
|
|
<div class="usage-info">
|
|
<span class="plan-badge" id="plan-badge">Free</span>
|
|
<span class="usage-text" id="usage-text">0 / 100 calls this month</span>
|
|
</div>
|
|
<div class="usage-bar-track"><div class="usage-bar-fill" id="usage-bar-fill" style="width:0%"></div></div>
|
|
</section>
|
|
|
|
<section class="platform-grid">
|
|
<div class="onboarding-banner" id="onboarding-banner">
|
|
<strong>Start here</strong> — connect one of these four to get started with Claude and ChatGPT.
|
|
</div>
|
|
|
|
<!-- v1 platforms: Obsidian, Email, Facebook, Instagram -->
|
|
<div class="platform-card v1-platform" data-platform="obsidian">
|
|
<div class="platform-icon" style="background:#7c3aed;">📓</div>
|
|
<div class="platform-info">
|
|
<h3>Obsidian</h3>
|
|
<p class="platform-desc">Search and edit your notes vault</p>
|
|
<span class="status-badge disconnected" id="status-obsidian">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="obsidian" aria-label="Connect Obsidian" title="Connect Obsidian">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card v1-platform" data-platform="email">
|
|
<div class="platform-icon" style="background:#ea4335;">✉️</div>
|
|
<div class="platform-info">
|
|
<h3>Email</h3>
|
|
<p class="platform-desc">Gmail, Yahoo, and IMAP accounts</p>
|
|
<span class="status-badge disconnected" id="status-email">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="email" aria-label="Connect Email" title="Connect Email">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card v1-platform" data-platform="facebook">
|
|
<div class="platform-icon" style="background:#1877f2;">f</div>
|
|
<div class="platform-info">
|
|
<h3>Facebook</h3>
|
|
<p class="platform-desc">Post to pages and manage content</p>
|
|
<span class="status-badge disconnected" id="status-facebook">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="facebook" aria-label="Connect Facebook" title="Connect Facebook">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card v1-platform" data-platform="instagram">
|
|
<div class="platform-icon" style="background:linear-gradient(45deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888);">📷</div>
|
|
<div class="platform-info">
|
|
<h3>Instagram</h3>
|
|
<p class="platform-desc">Publish reels and images</p>
|
|
<span class="status-badge disconnected" id="status-instagram">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="instagram" aria-label="Connect Instagram" title="Connect Instagram">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-divider">
|
|
<span>More platforms</span>
|
|
</div>
|
|
|
|
<!-- Other platforms -->
|
|
<div class="platform-card" data-platform="linkedin">
|
|
<div class="platform-icon" style="background:#0a66c2;">in</div>
|
|
<div class="platform-info">
|
|
<h3>LinkedIn</h3>
|
|
<p class="platform-desc">Share posts, images, and videos</p>
|
|
<span class="status-badge disconnected" id="status-linkedin">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="linkedin" aria-label="Connect LinkedIn" title="Connect LinkedIn">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="twitter">
|
|
<div class="platform-icon" style="background:#000;">𝕏</div>
|
|
<div class="platform-info">
|
|
<h3>Twitter / X</h3>
|
|
<p class="platform-desc">Tweet with media support</p>
|
|
<span class="status-badge disconnected" id="status-twitter">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="twitter" aria-label="Connect Twitter / X" title="Connect Twitter / X">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="whatsapp">
|
|
<div class="platform-icon" style="background:#25d366;">💬</div>
|
|
<div class="platform-info">
|
|
<h3>WhatsApp</h3>
|
|
<p class="platform-desc">Business messaging</p>
|
|
<span class="status-badge disconnected" id="status-whatsapp">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="whatsapp" aria-label="Connect WhatsApp" title="Connect WhatsApp">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="telegram">
|
|
<div class="platform-icon" style="background:#0088cc;">✈️</div>
|
|
<div class="platform-info">
|
|
<h3>Telegram</h3>
|
|
<p class="platform-desc">Send messages via bot</p>
|
|
<span class="status-badge disconnected" id="status-telegram">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="telegram" aria-label="Connect Telegram" title="Connect Telegram">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="discord">
|
|
<div class="platform-icon" style="background:#5865f2;">🎮</div>
|
|
<div class="platform-info">
|
|
<h3>Discord</h3>
|
|
<p class="platform-desc">Send messages to channels</p>
|
|
<span class="status-badge disconnected" id="status-discord">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="discord" aria-label="Connect Discord" title="Connect Discord">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="slack">
|
|
<div class="platform-icon" style="background:#4a154b;">💬</div>
|
|
<div class="platform-info">
|
|
<h3>Slack</h3>
|
|
<p class="platform-desc">Send messages to channels</p>
|
|
<span class="status-badge disconnected" id="status-slack">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="slack" aria-label="Connect Slack" title="Connect Slack">Connect</button>
|
|
</div>
|
|
|
|
<div class="platform-card" data-platform="tiktok">
|
|
<div class="platform-icon" style="background:#000;">🎵</div>
|
|
<div class="platform-info">
|
|
<h3>TikTok</h3>
|
|
<p class="platform-desc">Publish videos and view analytics</p>
|
|
<span class="status-badge disconnected" id="status-tiktok">Not connected</span>
|
|
</div>
|
|
<button class="btn btn-connect" data-platform="tiktok" aria-label="Connect TikTok" title="Connect TikTok">Connect</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="analytics-section hidden" id="analytics-section">
|
|
<h3 class="section-title">Analytics</h3>
|
|
<p class="section-subtitle">Tool calls this month, by platform and day</p>
|
|
<div class="charts-grid">
|
|
<div class="chart-card">
|
|
<h4>By platform</h4>
|
|
<div class="chart-container"><canvas id="platform-chart"></canvas></div>
|
|
</div>
|
|
<div class="chart-card">
|
|
<h4>Daily activity</h4>
|
|
<div class="chart-container"><canvas id="daily-chart"></canvas></div>
|
|
</div>
|
|
</div>
|
|
<div id="analytics-empty" class="analytics-empty hidden">
|
|
<p>No activity yet this month. Make your first tool call to see data here.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="invoices-section hidden" id="invoices-section">
|
|
<h3>Invoices</h3>
|
|
<div id="invoices-list" class="invoices-list"></div>
|
|
</section>
|
|
|
|
<section class="admin-section hidden" id="admin-section">
|
|
<h3>Admin Panel</h3>
|
|
<div id="admin-customers" class="admin-customers"></div>
|
|
</section>
|
|
|
|
<section class="webhooks-section hidden" id="webhooks-section">
|
|
<h3 class="section-title">Webhook</h3>
|
|
<p class="section-subtitle">Receive real-time events when messages arrive on your connected platforms.</p>
|
|
<div class="webhook-card" id="webhook-card">
|
|
<div id="webhook-status-row" class="webhook-status-row">
|
|
<span id="webhook-url-display" class="webhook-url-display">No webhook configured</span>
|
|
<button id="webhook-delete-btn" class="btn btn-ghost hidden" aria-label="Remove webhook URL" title="Remove webhook URL">Remove</button>
|
|
</div>
|
|
<form id="webhook-form" class="webhook-form">
|
|
<input type="url" id="webhook-url-input" placeholder="https://your-server.com/webhook" aria-label="Webhook URL" required>
|
|
<button type="submit" class="btn btn-primary">Save & generate secret</button>
|
|
</form>
|
|
<div id="webhook-secret-box" class="webhook-secret-box hidden">
|
|
<p class="webhook-secret-label">Signing secret — copy now, not shown again:</p>
|
|
<div class="webhook-secret-value" id="webhook-secret-value"></div>
|
|
<button class="btn btn-ghost" onclick="copyWebhookSecret()">Copy secret</button>
|
|
</div>
|
|
<div class="webhook-instructions">
|
|
<p>Verify each request by computing <code>sha256=HMAC-SHA256(secret, rawBody)</code> and comparing to the <code>X-SquareMCP-Signature</code> header.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Connection Modal -->
|
|
<div id="connect-modal" class="modal hidden">
|
|
<div class="modal-backdrop"></div>
|
|
<div class="modal-content">
|
|
<button class="modal-close" aria-label="Close" title="Close">×</button>
|
|
<div id="modal-body"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
|
<script src="app.js"></script>
|
|
<script src="https://hermes.squaremcp.com/chat-widget.js"></script>
|
|
<style>
|
|
.onboarding-banner {
|
|
grid-column: 1 / -1;
|
|
background: linear-gradient(135deg, #ede9fe 0%, #e0f2fe 100%);
|
|
border: 1px solid #c4b5fd;
|
|
border-radius: 10px;
|
|
padding: 14px 18px;
|
|
font-size: 0.9rem;
|
|
color: #4c1d95;
|
|
margin-bottom: 4px;
|
|
}
|
|
.platform-card.v1-platform {
|
|
border: 1.5px solid #c4b5fd;
|
|
}
|
|
.platform-divider {
|
|
grid-column: 1 / -1;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin: 8px 0 4px;
|
|
color: #94a3b8;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.05em;
|
|
text-transform: uppercase;
|
|
}
|
|
.platform-divider::before,
|
|
.platform-divider::after {
|
|
content: '';
|
|
flex: 1;
|
|
height: 1px;
|
|
background: #e2e8f0;
|
|
}
|
|
.status-badge.connected {
|
|
background: #dcfce7;
|
|
color: #166534;
|
|
border-color: #bbf7d0;
|
|
}
|
|
.status-badge.connected::before {
|
|
content: '✓ ';
|
|
}
|
|
</style>
|
|
<script>
|
|
/* After app.js loads, patch platform card connected states to show account name */
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const origSetStatus = window.setPlatformStatus;
|
|
/* Override connect button handler to update badge with account name when connected */
|
|
document.querySelectorAll('.platform-card').forEach(function(card) {
|
|
const platform = card.dataset.platform;
|
|
const badge = card.querySelector('.status-badge');
|
|
const btn = card.querySelector('.btn-connect');
|
|
if (!badge || !btn) return;
|
|
/* app.js manages status via API; we observe class changes to update text */
|
|
const observer = new MutationObserver(function() {
|
|
if (badge.classList.contains('connected') && badge.textContent.trim() === 'Connected') {
|
|
/* badge was set to generic "Connected" — good enough for now */
|
|
}
|
|
});
|
|
observer.observe(badge, { attributes: true, childList: true, subtree: true });
|
|
});
|
|
/* Hide onboarding banner once any v1 platform is connected */
|
|
function checkOnboardingBanner() {
|
|
const banner = document.getElementById('onboarding-banner');
|
|
if (!banner) return;
|
|
const anyV1Connected = Array.from(document.querySelectorAll('.platform-card.v1-platform .status-badge'))
|
|
.some(function(b) { return b.classList.contains('connected'); });
|
|
if (anyV1Connected) banner.style.display = 'none';
|
|
}
|
|
document.querySelector('.platform-grid').addEventListener('DOMSubtreeModified', checkOnboardingBanner);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|