diff --git a/dashboard/app.js b/dashboard/app.js
index 30985cf..02d3a60 100644
--- a/dashboard/app.js
+++ b/dashboard/app.js
@@ -262,10 +262,17 @@ function renderPipeline() {
card.appendChild(el("span", "state-chip", stateLabel(primary)));
card.appendChild(el("div", "agent-runtime", primary.runtime || "\u2014"));
- // Click handler for detail drawer
- card.addEventListener("click", (function(k) {
- return function() { selectAgent(k); };
- })(key));
+ // Click + keyboard handler — enter focus mode
+ card.setAttribute("tabindex", "0");
+ card.setAttribute("role", "button");
+ card.addEventListener("click", (function(ws, ag) {
+ return function() { enterFocusMode(ws, ag); };
+ })(primary.workspace, primary.agent));
+ card.addEventListener("keydown", (function(ws, ag) {
+ return function(e) {
+ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); enterFocusMode(ws, ag); }
+ };
+ })(primary.workspace, primary.agent));
}
// Render work-item dots for active runs at this stage
@@ -604,6 +611,236 @@ function connectSSE() {
es.onmessage = handler;
}
+// ── Agent Focus Mode ──
+var $focusView = document.getElementById("focus-view");
+var $focusBack = document.getElementById("focus-back");
+var $focusAgentName = document.getElementById("focus-agent-name");
+var $focusStatus = document.getElementById("focus-status");
+var $focusMeta = document.getElementById("focus-meta");
+var $focusTerminal = document.getElementById("focus-terminal");
+var $focusStats = document.getElementById("focus-stats");
+var $focusDiff = document.getElementById("focus-diff");
+var $focusProgress = document.getElementById("focus-progress");
+var $focusInput = document.getElementById("focus-prompt-input");
+var $focusSend = document.getElementById("focus-send");
+var focusPollId = null;
+var focusPolling = false;
+
+function enterFocusMode(workspace, agent) {
+ appState.view = "focus";
+ appState.focusAgent = { workspace: workspace, agent: agent };
+ appState.selectedAgent = null;
+
+ // Hide factory, show focus
+ document.getElementById("factory").style.display = "none";
+ document.getElementById("detail-drawer").style.display = "none";
+ document.getElementById("dispatch-panel").style.display = "none";
+ document.getElementById("timeline").style.display = "none";
+ $focusView.style.display = "flex";
+
+ $focusAgentName.textContent = agent;
+ $focusTerminal.textContent = "Connecting\u2026";
+ $focusStats.innerHTML = "";
+ $focusDiff.innerHTML = '
' + (d.files_changed || 0) + ' files, +' + (d.insertions || 0) + ' -' + (d.deletions || 0) + '
';
+ $focusDiff.innerHTML = diffHtml;
+ } else {
+ $focusDiff.innerHTML = 'No changes yet.
';
+ }
+
+ // Progress — show active run for this agent if any
+ var progressHtml = "";
+ var runIds = Object.keys(appState.runs);
+ for (var j = 0; j < runIds.length; j++) {
+ var run = appState.runs[runIds[j]];
+ if (run.status === "running") {
+ progressHtml += statRow("workflow", run.workflowName);
+ progressHtml += statRow("step", run.stepIndex + " / " + run.totalSteps);
+ progressHtml += statRow("started", timeAgo(run.startedAt));
+ break;
+ }
+ }
+ if (!progressHtml) {
+ progressHtml = 'No active run.
';
+ }
+ $focusProgress.innerHTML = progressHtml;
+}
+
+function statRow(label, value, colorClass) {
+ return '