<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Dobby</title>
  <link rel="icon" href="/assets/dobby.png" type="image/png">
  <script>
    (function() {
      var theme = 'dark';
      try {
        var stored = localStorage.getItem('dobby.dashboard.theme');
        if (stored === 'light' || stored === 'dark') {
          theme = stored;
        }
      } catch (err) {}
      document.documentElement.dataset.theme = theme;
    }());
  </script>
  <link rel="stylesheet" href="/static/dashboard.css?v=32">
</head>
<body>
<div id="mobile-overlay" onclick="closeSidebarOnMobile()"></div>

<!-- ================================================================
     SIDEBAR
================================================================ -->
<aside id="sidebar">

  <div class="sidebar-topbar">
    <div class="sidebar-logo" onclick="deselectTask()">
      <img src="/assets/dobby.gif" alt="Dobby" />
      <span class="sidebar-logo-text sidebar-text">Dobby</span>
    </div>
    <div class="sidebar-links sidebar-text">
      <a class="sidebar-link" href="{{GITHUB_URL}}" target="_blank" rel="noopener" aria-label="GitHub" title="GitHub" id="sidebar-github-link" style="display:none">
        <span id="sidebar-github-icon" aria-hidden="true"></span>
      </a>
      <a class="sidebar-link" href="/dashboard" aria-label="Dashboard" title="Dashboard">
        <span id="sidebar-home-icon" aria-hidden="true"></span>
      </a>
    </div>
  </div>

  <div class="sidebar-scroll-area">
    <div class="queue-bar-wrap">
      <div class="queue-bar-label">Queue</div>
      <div class="queue-bar" id="queue-bar"></div>
      <div class="queue-bar-counts" id="queue-bar-counts"></div>
    </div>

    <div class="sidebar-spokes sidebar-text" id="sidebar-spokes" style="display:none"></div>

    <div class="sidebar-toolbar sidebar-text" id="sidebar-toolbar">
      <div class="sidebar-search-wrap">
        <span class="sidebar-search-icon" id="sidebar-search-icon" aria-hidden="true"></span>
        <input
          id="task-search"
          class="sidebar-search"
          type="text"
          placeholder="Search..."
          oninput="updateSearch(this.value)"
        />
      </div>
      <div class="sidebar-filter-row">
        <label class="sidebar-filter-label" for="status-filter-select">Status</label>
        <select id="status-filter-select" class="sidebar-select" onchange="setStatusFilter(this.value)">
          <option value="all">All sessions</option>
          <option value="running">Running</option>
          <option value="pending">Pending</option>
          <option value="completed">Completed</option>
          <option value="failed">Failed</option>
        </select>
      </div>
      <div class="sidebar-toolbar-summary" id="toolbar-summary"></div>
    </div>

    <div class="task-sections" id="task-sections"></div>
  </div>

  <div class="sidebar-footer">
    <div class="sidebar-footer-row">
      <div class="sidebar-footer-text" id="sidebar-footer-text"></div>
      <div class="sidebar-toggle" id="sidebar-toggle" onclick="toggleSidebar()" title="Toggle sidebar">
        <span id="toggle-icon" aria-hidden="true"></span>
      </div>
    </div>
  </div>

  <div id="sidebar-resize-handle" aria-hidden="true"></div>

</aside>

<!-- ================================================================
     MAIN
================================================================ -->
<div id="main">

  <div id="main-header">
    <button class="header-btn sidebar-open-btn" id="sidebar-open-btn" onclick="toggleSidebar()" title="Open queue" aria-label="Open queue">
      <span id="sidebar-open-icon" aria-hidden="true"></span>
    </button>
    <div class="main-header-title-group">
      <div class="main-header-eyebrow">Dobby Dashboard</div>
      <div class="main-header-title">Live queue control for long-running agent work</div>
    </div>
    <div class="main-header-meta">
      <span class="status-pill info" id="refresh-status">Loading queue</span>
      <span class="status-pill info" id="filter-status">All projects</span>
      <button class="header-btn hidden" id="clear-filter-btn" onclick="clearProjectFilter()">Clear filter</button>
      <button class="header-btn" onclick="showDocs('changelog')" title="Changelog & Wishlist">Docs</button>
      <button class="header-btn icon-btn" id="guide-btn" onclick="toggleGuideModal()" aria-label="Usage guide" title="Usage guide">
        <span class="icon-btn-glyph" aria-hidden="true">&#x1F4D6;</span>
      </button>
      <button class="header-btn icon-btn" id="theme-toggle-btn" onclick="toggleTheme()" aria-label="Toggle theme" title="Toggle theme">
        <span class="icon-btn-glyph" aria-hidden="true"></span>
      </button>
      <button class="header-btn icon-btn" id="refresh-btn" onclick="manualRefresh()" aria-label="Refresh dashboard" title="Refresh dashboard">
        <span class="icon-btn-glyph" id="refresh-btn-glyph" aria-hidden="true"></span>
      </button>
    </div>
  </div>

  <div id="status-banner"></div>

  <!-- OVERVIEW (no task selected) -->
  <div id="overview" class="visible">


    <div class="usage-section" id="usage-section" style="display:none">
      <button class="usage-toggle" id="usage-toggle" onclick="toggleUsageSection()" aria-expanded="true">
        <div class="usage-toggle-copy">
          <div class="usage-toggle-title">Usage</div>
          <div class="usage-toggle-summary" id="usage-summary"></div>
        </div>
        <span class="usage-toggle-chevron" id="usage-chevron">&#x25BE;</span>
      </button>
      <div class="usage-body" id="usage-body"></div>
    </div>

    <div class="live-jobs-section">
      <div class="overview-section-title">Live Jobs</div>
      <div class="live-jobs-grid" id="live-jobs"></div>
    </div>

    <!-- Scheduled Items -->
    <div class="scheduled-section" id="scheduled-section" style="display:none">
      <div class="overview-section-title">Scheduled</div>
      <div class="scheduled-list" id="scheduled-list"></div>
    </div>

    <!-- Agent Network -->
    <div class="network-section" id="network-section" style="display:none">
      <div class="overview-section-title">Agent Network</div>
      <div class="network-graph" id="network-graph"></div>
    </div>

    <div class="overview-section-title">Operations</div>
    <div class="operations-grid" id="operations-grid"></div>

    <!-- Active Batches -->
    <div class="batches-section" id="batches-section" style="display:none">
      <div class="overview-section-title">Active Batches</div>
      <div id="batches-list"></div>
    </div>

    <div class="timeline-section" id="timeline-section" style="display:none">
      <div class="overview-section-title">Timeline</div>
      <div class="timeline-row-layout">
        <div class="timeline-chart" id="timeline-chart"></div>
        <div class="util-chart-wrap" id="util-chart-wrap" style="display:none">
          <div class="util-chart-header">
            <div class="util-chart-title">Usage Over Time</div>
            <div class="util-chart-toggles" id="util-chart-toggles"></div>
          </div>
          <div class="util-chart-svg-wrap" id="util-chart-svg-wrap"></div>
          <div class="util-chart-legend" id="util-chart-legend"></div>
        </div>
      </div>
    </div>

    <!-- Command Center -->
    <div class="overview-section-title">Project Control</div>
    <div class="project-cards" id="project-cards">
      <div class="no-activity">Loading projects...</div>
    </div>

    <!-- Recent Activity -->
    <div class="activity-section">
      <div class="overview-section-title">Recent Activity</div>
      <div id="activity-feed"></div>
    </div>

    <!-- Cost Breakdown -->
    <div class="overview-section-title">Cost Breakdown</div>
    <div class="stat-cards" id="cost-summary-cards">
      <div class="stat-card">
        <div class="stat-card-label">Cost Today</div>
        <div class="stat-card-value green" id="cb-cost-today">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Cost This Week</div>
        <div class="stat-card-value blue" id="cb-cost-week">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Cost All Time</div>
        <div class="stat-card-value" id="cb-cost-total">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Tokens Today</div>
        <div class="stat-card-value amber" id="cb-tokens-today">--</div>
      </div>
    </div>
    <div class="cost-by-project" id="cost-by-project"></div>
    <div class="cost-subscription-note" id="cost-subscription-note" style="display:none"></div>

    <!-- Stats -->
    <div class="overview-section-title">Stats</div>
    <div class="stat-cards" id="stat-cards">
      <div class="stat-card">
        <div class="stat-card-label">Completed Today</div>
        <div class="stat-card-value green" id="ov-completed-today">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Total Cost Today</div>
        <div class="stat-card-value" id="ov-cost-today">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Total Cost (All)</div>
        <div class="stat-card-value" id="ov-cost">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Total Tokens</div>
        <div class="stat-card-value blue" id="ov-tokens">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Avg Duration</div>
        <div class="stat-card-value" id="ov-avg-duration">--</div>
      </div>
      <div class="stat-card">
        <div class="stat-card-label">Tasks Today</div>
        <div class="stat-card-value amber" id="ov-tasks-today">--</div>
      </div>
    </div>

  </div>

  <!-- TASK DETAIL VIEW -->
  <div id="detail">

    <div class="detail-topbar">
      <span class="detail-back" onclick="deselectTask()" title="Back to overview">&#x2190;</span>
      <span class="detail-id" id="detail-id"></span>
      <span class="detail-project" id="detail-project"></span>
      <span id="detail-badge"></span>
      <span class="detail-elapsed" id="detail-elapsed"></span>
      <span class="detail-spacer"></span>
      <span id="detail-actions"></span>
    </div>

    <!-- LIVE ACTIVITY PANEL (for running tasks) -->
    <div id="live-activity-panel">
      <div class="live-activity-inner">
        <div class="la-section" style="flex:1;min-width:180px;">
          <div class="la-section-title">Current Action</div>
          <div class="la-current-action" id="la-current-action">—</div>
        </div>
        <div class="la-section" style="flex:1;min-width:180px;">
          <div class="la-section-title">Files Touched</div>
          <div class="la-files-list" id="la-files-list"></div>
        </div>
        <div class="la-section" style="min-width:200px;">
          <div class="la-section-title">Tool Usage</div>
          <div class="la-tool-bars" id="la-tool-bars"></div>
        </div>
      </div>
    </div>

    <div class="detail-tabs">
      <div class="detail-tab active" data-tab="logs" onclick="switchTab(this)">Logs</div>
      <div class="detail-tab" data-tab="details" onclick="switchTab(this)">Details</div>
      <div class="detail-tab" data-tab="timeline" onclick="switchTab(this)">Timeline</div>
    </div>

    <!-- LOGS TAB -->
    <div class="tab-panel active" id="tab-logs">
      <div class="log-toolbar">
        <div class="log-view-toggle" id="log-view-toggle">
          <button class="log-view-btn active" data-mode="flow" onclick="setLogViewMode('flow')">Flow</button>
          <button class="log-view-btn" data-mode="raw" onclick="setLogViewMode('raw')">Raw</button>
        </div>
        <button class="fv-expand-all-btn" id="fv-expand-all-btn" onclick="fvToggleAll()" style="display:none">Expand all</button>
        <input type="text" class="log-search" id="log-search" placeholder="Filter logs..." oninput="filterLogs()" />
        <span class="log-match-count" id="log-match-count"></span>
      </div>
      <div class="log-viewer" id="log-viewer">
        <div class="log-empty" id="log-empty">Select a running task to view logs</div>
        <div id="log-sentinel"></div>
      </div>
      <div class="scroll-bottom-btn" id="scroll-bottom-btn" onclick="scrollToBottom()">Scroll to bottom</div>
    </div>

    <!-- DETAILS TAB -->
    <div class="tab-panel" id="tab-details">
      <div class="details-panel" id="details-content"></div>
    </div>

    <!-- TIMELINE TAB -->
    <div class="tab-panel" id="tab-timeline">
      <div class="timeline-panel" id="timeline-content"></div>
    </div>

  </div>

  <!-- DOCS VIEW (changelog / wishlist) -->
  <div id="docs-view" style="display:none">
    <div class="docs-tabs">
      <button class="docs-tab active" data-doc="changelog" onclick="switchDoc(this)">Changelog</button>
      <button class="docs-tab" data-doc="wishlist" onclick="switchDoc(this)">Wishlist</button>
      <button class="docs-tab" data-doc="memory" onclick="switchDoc(this)">Memory</button>
      <button class="docs-tab" onclick="showOverview()" style="margin-left:auto">Back to Dashboard</button>
    </div>
    <div class="docs-content" id="docs-content"></div>
  </div>

</div>
<!-- Usage Guide Modal -->
<div class="guide-overlay" id="guide-overlay" onclick="toggleGuideModal()"></div>
<div class="guide-modal" id="guide-modal">
  <div class="guide-modal-header">
    <div class="guide-modal-title">&#x1F4D6; Dobby Usage Guide</div>
    <button class="guide-dismiss" onclick="toggleGuideModal()">&times;</button>
  </div>
  <div class="guide-modal-body">

    <div class="guide-section">
      <div class="guide-section-title">What is Dobby?</div>
      <p class="guide-text">Dobby is a meta-agent orchestrator that dispatches coding tasks to AI agents (Claude Code, Codex) across multiple machines. Submit work from Slack, CLI, or Claude Code — agents execute on your Mac, cloud servers, or GPU clusters while you track progress here.</p>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F4AC; Submit via Slack</div>
      <div class="guide-example">
        <div class="guide-example-label">Submit a task (mention the project name):</div>
        <code>@Dobby fix the login bug in spare</code>
        <code>@Dobby add docs to dobby with high priority</code>
        <code>@Dobby run eval on spare-tillicum using codex</code>
      </div>
      <div class="guide-example">
        <div class="guide-example-label">Batch tasks (bullet list):</div>
        <code>@Dobby<br>- fix tests in spare<br>- add docs to dobby<br>- run eval on adpo</code>
      </div>
      <div class="guide-example">
        <div class="guide-example-label">Check status:</div>
        <code>status</code> — bullet-point overview (last 4h)<br>
        <code>status 12h</code> — custom time range<br>
        <code>summary</code> — detailed AI summary (last 12h)<br>
        <code>summary spare 24h</code> — per-project with time range<br>
        <code>running</code> — currently executing tasks<br>
        <code>projects</code> — list all projects with their spoke servers
      </div>
      <div class="guide-example">
        <div class="guide-example-label">Free-form chat (no project = Claude conversation):</div>
        <code>@Dobby what's the best way to structure a training loop?</code>
      </div>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F527; Submit via MCP (Claude Code)</div>
      <div class="guide-example">
        <div class="guide-example-label">In any Claude Code session with Dobby MCP configured:</div>
        <code>dobby_add_task(project="spare", description="fix the training loop", target="mac-local")</code>
        <code>dobby_status()</code>
        <code>dobby_projects()</code>
      </div>
      <div class="guide-example">
        <div class="guide-example-label">MCP config (~/.claude/.mcp.json):</div>
        <code>{"mcpServers": {"dobby": {"command": "uv", "args": ["run", "--project", "/path/to/dobby", "dobby-mcp"], "env": {"DOBBY_URL": "https://your-hub-url"}}}}</code>
      </div>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F4BB; Submit via CLI</div>
      <div class="guide-example">
        <code>dobby add -p spare "fix the training loop"</code>
        <code>dobby status</code>
        <code>dobby logs t-20260322-abcd</code>
      </div>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F310; Submit via API</div>
      <div class="guide-example">
        <code>curl -X POST https://your-hub/tasks -H 'Content-Type: application/json' \<br>&nbsp;&nbsp;-d '{"project":"spare", "description":"fix the bug", "target":"mac-local"}'</code>
      </div>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F5A5; Connect a Spoke Agent</div>
      <div class="guide-example">
        <div class="guide-example-label">On any machine with Claude Code installed:</div>
        <code>pip install dobby &amp;&amp; dobby agent --hub https://your-hub --id my-machine</code>
      </div>
      <p class="guide-text">The spoke registers with the hub, polls for tasks targeted at it, executes them locally, and streams logs back to this dashboard.</p>
    </div>

    <div class="guide-section">
      <div class="guide-section-title">&#x1F4CA; Dashboard Features</div>
      <p class="guide-text">
        <strong>Agent Network</strong> — see connected spokes with status dots<br>
        <strong>Heatmap</strong> — GitHub-style activity chart per project<br>
        <strong>Flow View</strong> — VibeLens-style agent execution timeline (click any task → Logs → Flow)<br>
        <strong>Live Jobs</strong> — currently running tasks with real-time updates<br>
        <strong>Usage</strong> — Claude rate limit utilization bars
      </p>
    </div>

  </div>
</div>

<script src="/static/dashboard.js?v=32"></script>
<script>
  // Show GitHub link only when configured
  (function() {
    var link = document.getElementById('sidebar-github-link');
    if (link && link.href && link.href !== window.location.origin + '/' && link.href !== '') {
      link.style.display = '';
    }
  })();
</script>
</html>
