1 Commits

Author SHA1 Message Date
Alexander Whitestone
d4bbe157c2 fix: Workshop connection status HUD with timeout and retry
Fixes #5

The Workshop page was stuck on INITIALIZING forever because:
- main.js was never loaded (script tag was commented out)
- No WebSocket connection logic existed
- No status indicator or error handling

Changes:
- Add connection status HUD to world/index.html showing
  connection state (CONNECTING/ONLINE/OFFLINE) and agent count
- Implement WebSocket connection to tower-hermes with 5s timeout
- Auto-retry up to 3 times with 3s delay between attempts
- Show "OFFLINE — backend unreachable" with manual retry button
  when all auto-retries are exhausted
- Enable main.js module script

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 18:54:59 -04:00
2 changed files with 2 additions and 27 deletions

View File

@@ -88,7 +88,6 @@
</div>
<div class="status-line">AGENTS: <span id="agent-count">0</span></div>
<button id="retry-btn">Retry connection</button>
<a id="fallback-link" href="/api/ui" style="display:none; margin-top:6px; color:#8a7f6a; font-size:0.7rem;">Open API dashboard →</a>
</div>
<!-- Reject unknown sub-paths: only /world/ is valid -->
@@ -100,24 +99,6 @@
}
})();
</script>
<!-- Fallback: if main.js fails to load, don't leave user on INITIALIZING forever -->
<script>
(function() {
var INIT_TIMEOUT_MS = 8000;
window.__workshopBooted = false;
setTimeout(function() {
if (window.__workshopBooted) return;
var dot = document.getElementById('status-dot');
var text = document.getElementById('status-text');
var btn = document.getElementById('retry-btn');
var fallback = document.getElementById('fallback-link');
if (dot) { dot.className = 'dot offline'; }
if (text) { text.textContent = 'WORKSHOP UNREACHABLE'; }
if (btn) { btn.style.display = 'block'; }
if (fallback) { fallback.style.display = 'block'; }
}, INIT_TIMEOUT_MS);
})();
</script>
<!-- Three.js scene will mount to #scene -->
<script type="module" src="main.js"></script>
</body>

View File

@@ -23,12 +23,8 @@ const dom = {
text: document.getElementById('status-text'),
agents: document.getElementById('agent-count'),
retryBtn: document.getElementById('retry-btn'),
fallback: document.getElementById('fallback-link'),
};
// Signal to inline fallback script that main.js loaded successfully
window.__workshopBooted = true;
let ws = null;
let autoRetries = 0;
let connectTimer = null;
@@ -36,9 +32,7 @@ let connectTimer = null;
function setStatus(state, message) {
dom.dot.className = 'dot ' + state;
dom.text.textContent = message;
var isOffline = state === Status.OFFLINE;
dom.retryBtn.style.display = isOffline ? 'block' : 'none';
if (dom.fallback) dom.fallback.style.display = isOffline ? 'block' : 'none';
dom.retryBtn.style.display = state === Status.OFFLINE ? 'block' : 'none';
}
function setAgentCount(n) {
@@ -111,7 +105,7 @@ function onFail() {
setStatus(Status.CONNECTING, 'RETRYING (' + autoRetries + '/' + MAX_AUTO_RETRIES + ')\u2026');
setTimeout(connect, RETRY_DELAY_MS);
} else {
setStatus(Status.OFFLINE, 'WORKSHOP OFFLINE');
setStatus(Status.OFFLINE, 'OFFLINE \u2014 backend unreachable');
}
}