shell-mirror
Version:
Access your Mac shell from any device securely. Perfect for mobile coding with Claude Code CLI, Gemini CLI, and any shell tool.
235 lines (202 loc) • 10.9 kB
HTML
<html>
<head>
<title>Shell Mirror - Connection Debug</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.status { padding: 10px; margin: 10px 0; border-radius: 5px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.info { background: #d1ecf1; color: #0c5460; }
.warning { background: #fff3cd; color: #856404; }
pre { background: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; }
.btn { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #0056b3; }
</style>
</head>
<body>
<h1>Shell Mirror - Connection Diagnostic</h1>
<div id="local-agent-info" class="status info">
<h3>Local Mac Agent Info</h3>
<p><strong>Agent ID:</strong> local-MacBookPro-1752594896069</p>
<p><strong>Owner Email:</strong> bac9i4mo@gmail.com</p>
<p><strong>Status:</strong> Registered and running</p>
</div>
<div id="web-auth-status" class="status info">
<h3>Web Authentication Status</h3>
<p id="web-auth-text">Checking...</p>
</div>
<div id="connection-diagnosis" class="status info">
<h3>Connection Diagnosis</h3>
<p id="diagnosis-text">Analyzing...</p>
</div>
<div id="solution" class="status warning" style="display: none;">
<h3>Solution</h3>
<p id="solution-text"></p>
</div>
<button class="btn" onclick="checkConnection()">Check Connection</button>
<button class="btn" onclick="loginWithGoogle()">Login with Google</button>
<div id="debug-info" style="margin-top: 20px;">
<h3>Debug Information</h3>
<pre id="debug-output"></pre>
</div>
<script>
function log(message) {
const output = document.getElementById('debug-output');
output.textContent += new Date().toISOString() + ': ' + message + '\n';
}
async function checkConnection() {
log('Starting connection check...');
// Check web authentication
try {
const authResponse = await fetch('/php-backend/api/auth-status.php', {
credentials: 'include'
});
const authData = await authResponse.json();
log('Web auth check: ' + JSON.stringify(authData));
const webAuthStatus = document.getElementById('web-auth-status');
const webAuthText = document.getElementById('web-auth-text');
if (authData.success && authData.data && authData.data.authenticated) {
webAuthStatus.className = 'status success';
webAuthText.innerHTML = `
<strong>✅ Authenticated</strong><br>
User: ${authData.data.user.name}<br>
Email: ${authData.data.user.email}
`;
// Check if emails match
const localEmail = 'bac9i4mo@gmail.com';
const webEmail = authData.data.user.email;
if (localEmail === webEmail) {
await checkAgents();
} else {
showEmailMismatchError(localEmail, webEmail);
}
} else {
webAuthStatus.className = 'status error';
webAuthText.innerHTML = '<strong>❌ Not authenticated</strong><br>Please login with Google first.';
showAuthenticationError();
}
} catch (error) {
log('Auth check failed: ' + error.message);
webAuthStatus.className = 'status error';
webAuthText.innerHTML = '<strong>❌ Error checking authentication</strong><br>' + error.message;
}
}
async function checkAgents() {
log('Checking for Mac agents...');
try {
const agentsResponse = await fetch('/php-backend/api/agents-list.php', {
credentials: 'include'
});
const agentsData = await agentsResponse.json();
log('Agents check: ' + JSON.stringify(agentsData));
const diagnosisDiv = document.getElementById('connection-diagnosis');
const diagnosisText = document.getElementById('diagnosis-text');
if (agentsData.success && agentsData.data && agentsData.data.agents) {
const agents = agentsData.data.agents;
const onlineAgents = agents.filter(agent => agent.onlineStatus === 'online');
if (onlineAgents.length > 0) {
diagnosisDiv.className = 'status success';
diagnosisText.innerHTML = `
<strong>✅ Connection successful!</strong><br>
Found ${onlineAgents.length} online Mac agent(s):<br>
${onlineAgents.map(agent => `• ${agent.machineName || agent.agentId} (${agent.ownerEmail})`).join('<br>')}
`;
hideSolution();
} else if (agents.length > 0) {
diagnosisDiv.className = 'status warning';
diagnosisText.innerHTML = `
<strong>⚠️ Mac agent found but offline</strong><br>
Found ${agents.length} agent(s) but none are online.<br>
Make sure your Mac is running: <code>shell-mirror</code>
`;
showOfflineAgentSolution();
} else {
diagnosisDiv.className = 'status error';
diagnosisText.innerHTML = '<strong>❌ No Mac agents found</strong><br>No agents registered for your account.';
showNoAgentsSolution();
}
} else {
diagnosisDiv.className = 'status error';
diagnosisText.innerHTML = '<strong>❌ Failed to check agents</strong><br>' + (agentsData.message || 'Unknown error');
}
} catch (error) {
log('Agents check failed: ' + error.message);
diagnosisDiv.className = 'status error';
diagnosisText.innerHTML = '<strong>❌ Error checking agents</strong><br>' + error.message;
}
}
function showEmailMismatchError(localEmail, webEmail) {
const diagnosisDiv = document.getElementById('connection-diagnosis');
const diagnosisText = document.getElementById('diagnosis-text');
diagnosisDiv.className = 'status error';
diagnosisText.innerHTML = `
<strong>❌ Email mismatch</strong><br>
Local Mac agent: ${localEmail}<br>
Web user: ${webEmail}<br>
These must match for connection to work.
`;
showSolution(`
<strong>Email Mismatch Issue:</strong><br>
Your local Mac agent is registered with <code>${localEmail}</code> but you're logged into the web with <code>${webEmail}</code>.<br><br>
<strong>Solution:</strong> Logout and login with the correct Google account (<code>${localEmail}</code>)
`);
}
function showAuthenticationError() {
const diagnosisDiv = document.getElementById('connection-diagnosis');
const diagnosisText = document.getElementById('diagnosis-text');
diagnosisDiv.className = 'status error';
diagnosisText.innerHTML = '<strong>❌ Authentication required</strong><br>You must login with Google first.';
showSolution(`
<strong>Authentication Required:</strong><br>
Click the "Login with Google" button above and authenticate with <code>bac9i4mo@gmail.com</code>
`);
}
function showOfflineAgentSolution() {
showSolution(`
<strong>Mac Agent Offline:</strong><br>
Your Mac agent is registered but not currently running.<br><br>
<strong>Solution:</strong> On your Mac, run: <code>shell-mirror</code>
`);
}
function showNoAgentsSolution() {
showSolution(`
<strong>No Mac Agents:</strong><br>
No Mac agents are registered for your account.<br><br>
<strong>Solution:</strong> On your Mac, run:<br><br>
<div style="background: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px 14px; display: inline-flex; align-items: center; gap: 12px; max-width: 100%;">
<code style="font-family: 'Monaco', 'Menlo', 'Courier New', monospace; font-size: 0.9rem; color: #1a1a1a;">npm install -g shell-mirror && shell-mirror</code>
<button onclick="copyToClipboard('npm install -g shell-mirror && shell-mirror', this)" style="background: #667eea; color: white; border: none; border-radius: 6px; padding: 6px 12px; font-size: 0.85rem; cursor: pointer; transition: all 0.2s ease; white-space: nowrap;">Copy</button>
</div>
`);
}
function showSolution(text) {
document.getElementById('solution').style.display = 'block';
document.getElementById('solution-text').innerHTML = text;
}
function hideSolution() {
document.getElementById('solution').style.display = 'none';
}
function copyToClipboard(text, button) {
navigator.clipboard.writeText(text).then(() => {
const originalText = button.textContent;
button.textContent = 'Copied!';
setTimeout(() => {
button.textContent = originalText;
}, 2000);
}).catch(err => {
console.error('Failed to copy:', err);
button.textContent = 'Failed';
setTimeout(() => {
button.textContent = 'Copy';
}, 2000);
});
}
function loginWithGoogle() {
window.location.href = '/php-backend/api/auth-login.php';
}
// Auto-check on page load
document.addEventListener('DOMContentLoaded', checkConnection);
</script>
</body>
</html>