blame.html
html
sha256:7281683f5c41e5d88b6d8811fbdafebd3e01a0c9dcd90975cfcb444ba71e8e81
docs: add local source-of-truth for musehub#225, #226, #227…
Sonnet 5
1 day ago
| 1 | {% extends "musehub/base.html" %} |
| 2 | |
| 3 | {% block title %}{{ owner }}/{{ repo_slug }} — blame/{{ short_ref }}/{{ short_path }}{% endblock %} |
| 4 | |
| 5 | {% block breadcrumb %} |
| 6 | <a href="/{{ owner }}">{{ owner }}</a> / |
| 7 | <a href="/{{ owner }}/{{ repo_slug }}">{{ repo_slug }}</a> / |
| 8 | blame / |
| 9 | <a href="/{{ owner }}/{{ repo_slug }}/tree/{{ ref }}">{{ short_ref }}</a> / |
| 10 | {{ short_path }} |
| 11 | {% endblock %} |
| 12 | |
| 13 | {% block repo_nav %}{% include "musehub/partials/repo_nav.html" %}{% endblock %} |
| 14 | {% block body_class %}app-shell{% endblock %} |
| 15 | |
| 16 | {% block content %} |
| 17 | |
| 18 | {# ── Page header ──────────────────────────────────────────────────────────── #} |
| 19 | <div class="blm-page-header"> |
| 20 | <div class="blm-header-left"> |
| 21 | <div class="blm-path-icon"> |
| 22 | {{ icon("clock-circle", 18) }} |
| 23 | </div> |
| 24 | <div class="blm-path-info"> |
| 25 | <h1 class="blm-filename"> |
| 26 | <code>{{ short_path }}</code> |
| 27 | <span class="blm-type-badge blm-type-{{ blame_type }}"> |
| 28 | {%- if blame_type == "symbol" -%}symbol-level |
| 29 | {%- else -%}file-level |
| 30 | {%- endif -%} |
| 31 | </span> |
| 32 | </h1> |
| 33 | <p class="blm-breadcrumb"> |
| 34 | at <code>{{ short_ref }}</code> |
| 35 | <span>·</span> |
| 36 | <a class="blm-breadcrumb-link" href="{{ base_url }}/blob/{{ ref }}/{{ path }}">View file ↗</a> |
| 37 | {% if blame_type in ("symbol", "file") %} |
| 38 | <span>·</span> |
| 39 | <a class="blm-breadcrumb-link" href="{{ base_url }}/intel">Intel ↗</a> |
| 40 | {% endif %} |
| 41 | </p> |
| 42 | </div> |
| 43 | </div> |
| 44 | <div style="flex-shrink:0;margin-top:6px"> |
| 45 | <a href="{{ base_url }}/commits" class="btn btn-secondary btn-sm">History</a> |
| 46 | </div> |
| 47 | </div> |
| 48 | |
| 49 | {# ── Stats strip ──────────────────────────────────────────────────────────── #} |
| 50 | <div class="blm-stats"> |
| 51 | <div class="blm-stat"> |
| 52 | <span class="blm-stat-val">{{ total_entries | fmtnum }}</span> |
| 53 | <span> |
| 54 | {%- if blame_type == "symbol" -%}symbols |
| 55 | {%- else -%}files |
| 56 | {%- endif -%} |
| 57 | </span> |
| 58 | </div> |
| 59 | <div class="blm-stat"> |
| 60 | <span class="blm-stat-val">{{ commits_in_view | length }}</span> |
| 61 | <span>commits</span> |
| 62 | </div> |
| 63 | {% if blame_type in ("symbol", "file") %} |
| 64 | <div class="blm-stat blm-stat--hotspot {% if intel_hotspot_count > 0 %}blm-stat--active{% endif %}"> |
| 65 | <span class="blm-stat-val">{{ intel_hotspot_count }}</span> |
| 66 | <span>{{ icon("flame", 11) }} hotspots</span> |
| 67 | </div> |
| 68 | <div class="blm-stat blm-stat--dead {% if intel_dead_count > 0 %}blm-stat--active{% endif %}"> |
| 69 | <span class="blm-stat-val">{{ intel_dead_count }}</span> |
| 70 | <span>🧊 dead</span> |
| 71 | </div> |
| 72 | <div class="blm-stat blm-stat--blast {% if intel_blast_count > 0 %}blm-stat--active{% endif %}"> |
| 73 | <span class="blm-stat-val">{{ intel_blast_count }}</span> |
| 74 | <span>💥 blast risk</span> |
| 75 | </div> |
| 76 | {% endif %} |
| 77 | </div> |
| 78 | |
| 79 | {# ── Empty state ──────────────────────────────────────────────────────────── #} |
| 80 | {% if not blame_entries %} |
| 81 | <div class="blm-empty"> |
| 82 | {{ icon("clock-circle", 32, "icon--light-stroke") }} |
| 83 | <p>No blame data found for <code>{{ path }}</code></p> |
| 84 | {% if blame_type == "symbol" %} |
| 85 | <p class="blm-empty-hint">This file has not been indexed yet. Push a commit to trigger indexing.</p> |
| 86 | {% else %} |
| 87 | <p class="blm-empty-hint">Check that the path exists at ref <code>{{ short_ref }}</code>.</p> |
| 88 | {% endif %} |
| 89 | </div> |
| 90 | |
| 91 | {% else %} |
| 92 | |
| 93 | {# ── Blame layout ─────────────────────────────────────────────────────────── #} |
| 94 | <div class="blm-layout"> |
| 95 | |
| 96 | {# ── Left: commit legend (sticky) ──────────────────────────────────────── #} |
| 97 | <aside class="blm-legend"> |
| 98 | <div class="blm-legend-hdr"> |
| 99 | <span>Commits</span> |
| 100 | <span class="blm-legend-prov-key"> |
| 101 | <span title="AI agent">{{ icon("agent-sm", 10) }}</span> agent |
| 102 | · |
| 103 | <span title="Human">{{ icon("user-sm", 10) }}</span> human |
| 104 | </span> |
| 105 | </div> |
| 106 | {% for c in commits_in_view %} |
| 107 | <a class="blm-commit-card" href="{{ base_url }}/commits/{{ c.commit_id }}"> |
| 108 | <span class="blm-commit-dot" style="background:{{ commit_color[c.commit_id] }}"></span> |
| 109 | <div class="blm-commit-body"> |
| 110 | <div class="blm-commit-top"> |
| 111 | <code class="blm-commit-sha">{{ c.short_id }}</code> |
| 112 | {% if c.is_agent %} |
| 113 | <span class="blm-commit-prov blm-commit-prov--agent" title="{{ c.model_id or c.agent_id }}"> |
| 114 | {{ icon("agent-sm", 9) }} |
| 115 | </span> |
| 116 | {% else %} |
| 117 | <span class="blm-commit-prov blm-commit-prov--human" title="{{ c.author }}"> |
| 118 | {{ icon("user-sm", 9) }} |
| 119 | </span> |
| 120 | {% endif %} |
| 121 | <span class="blm-commit-count">{{ c.note_count }} sym{{ 's' if c.note_count != 1 else '' }}</span> |
| 122 | </div> |
| 123 | <div class="blm-commit-msg">{{ c.message | truncate(44, True, "…") }}</div> |
| 124 | <div class="blm-commit-meta"> |
| 125 | {{ c.author }} |
| 126 | {% if c.is_agent and c.model_id %} |
| 127 | <span class="blm-commit-model">{{ c.model_id | replace("claude-", "") }}</span> |
| 128 | {% endif %} |
| 129 | · {{ c.timestamp | fmtdate }} |
| 130 | </div> |
| 131 | </div> |
| 132 | </a> |
| 133 | {% endfor %} |
| 134 | </aside> |
| 135 | |
| 136 | {# ── Right: blame content ─────────────────────────────────────────────── #} |
| 137 | <div class="blm-content"> |
| 138 | |
| 139 | {# ════════════════════════════════════════════════════════════════════ #} |
| 140 | {# SYMBOL BLAME ──────────────────────────────────────────────────────── #} |
| 141 | {# ════════════════════════════════════════════════════════════════════ #} |
| 142 | {% if blame_type == "symbol" %} |
| 143 | <div class="blm-symbol-list"> |
| 144 | {% for entry in blame_entries %} |
| 145 | {% set c = commit_map.get(entry.commit_id, {}) %} |
| 146 | <details class="blm-card" style="--card-color: {{ commit_color.get(entry.commit_id, '#444') }}"> |
| 147 | <summary class="blm-card-summary"> |
| 148 | |
| 149 | <div class="blm-card-main"> |
| 150 | {# Top row: symbol name + op + signals #} |
| 151 | <div class="blm-card-top"> |
| 152 | {{ icon("chevron-down", 10, "blm-expand-chevron") }} |
| 153 | <a class="blm-symbol-name blm-symbol-link" |
| 154 | href="{{ base_url }}/symbols?q={{ entry.symbol_name | urlencode }}" |
| 155 | title="{{ entry.symbol_address }}">{{ entry.symbol_name | e }}</a> |
| 156 | |
| 157 | <span class="blm-op blm-op--{{ entry.op }}">{{ entry.op }}</span> |
| 158 | |
| 159 | {% if entry.is_hotspot %} |
| 160 | <span class="blm-signal blm-signal--hotspot">{{ icon("flame", 10) }} hotspot</span> |
| 161 | {% endif %} |
| 162 | {% if entry.is_dead %} |
| 163 | <span class="blm-signal blm-signal--dead">🧊 dead</span> |
| 164 | {% endif %} |
| 165 | {% if entry.is_blast_risk %} |
| 166 | <span class="blm-signal blm-signal--blast" title="co-changes with {{ entry.blast_co_symbols[:2] | join(', ') }}">💥 blast</span> |
| 167 | {% endif %} |
| 168 | </div> |
| 169 | |
| 170 | {# Bottom row: heat + author + commit sha #} |
| 171 | <div class="blm-card-bottom"> |
| 172 | <div class="blm-heat" title="{{ entry.change_count }} change{{ 's' if entry.change_count != 1 else '' }}"> |
| 173 | <span class="blm-heat-bar"> |
| 174 | <span class="blm-heat-fill" style="width:{{ [entry.change_count / heat_max * 100, 2] | max | round | int }}%"></span> |
| 175 | </span> |
| 176 | <span class="blm-heat-count">{{ entry.change_count }}×</span> |
| 177 | </div> |
| 178 | |
| 179 | <div class="blm-card-author"> |
| 180 | {% if c.is_agent %} |
| 181 | <span class="blm-author-icon blm-author-icon--agent" title="{{ c.model_id or c.agent_id or 'AI agent' }}"> |
| 182 | {{ icon("agent-sm", 9) }} |
| 183 | </span> |
| 184 | {% else %} |
| 185 | <span class="blm-author-icon blm-author-icon--human" title="{{ entry.author }}"> |
| 186 | {{ icon("user-sm", 9) }} |
| 187 | </span> |
| 188 | {% endif %} |
| 189 | <span>{{ entry.author | e }}</span> |
| 190 | <span class="blm-card-dot">·</span> |
| 191 | <span class="blm-card-time">{{ entry.timestamp | fmtdate }}</span> |
| 192 | </div> |
| 193 | |
| 194 | <a class="blm-card-commit" href="{{ base_url }}/commits/{{ entry.commit_id }}"> |
| 195 | {{ entry.commit_id[:8] }} |
| 196 | </a> |
| 197 | </div> |
| 198 | </div> |
| 199 | |
| 200 | </summary> |
| 201 | |
| 202 | {# Expanded: full symbol history #} |
| 203 | <div class="blm-history-panel"> |
| 204 | {% set history = symbol_history_map.get(entry.symbol_address, []) %} |
| 205 | {% if history %} |
| 206 | <table class="blm-history-table"> |
| 207 | <thead> |
| 208 | <tr> |
| 209 | <th>#</th> |
| 210 | <th>Commit</th> |
| 211 | <th>Op</th> |
| 212 | <th>Message</th> |
| 213 | <th>Author</th> |
| 214 | <th>When</th> |
| 215 | </tr> |
| 216 | </thead> |
| 217 | <tbody> |
| 218 | {% for h in history %} |
| 219 | {% set hc = commit_map.get(h.commit_id, {}) %} |
| 220 | <tr> |
| 221 | <td class="blm-hist-num">{{ loop.index }}</td> |
| 222 | <td class="blm-hist-sha"> |
| 223 | <a href="{{ base_url }}/commits/{{ h.commit_id }}">{{ h.commit_id | short_id }}</a> |
| 224 | </td> |
| 225 | <td> |
| 226 | <span class="blm-op blm-op--{{ h.op }}">{{ h.op }}</span> |
| 227 | </td> |
| 228 | <td class="blm-hist-msg">{{ (hc.message or "") | truncate(60, True, "…") | e }}</td> |
| 229 | <td class="blm-hist-author"> |
| 230 | {% if hc.is_agent %} |
| 231 | <span class="blm-author-icon blm-author-icon--agent" title="{{ hc.model_id or 'AI agent' }}"> |
| 232 | {{ icon("agent-sm", 9) }} |
| 233 | </span> |
| 234 | {% else %} |
| 235 | <span class="blm-author-icon blm-author-icon--human"> |
| 236 | {{ icon("user-sm", 9) }} |
| 237 | </span> |
| 238 | {% endif %} |
| 239 | {{ hc.author or (h.commit_id | short_id) | e }} |
| 240 | </td> |
| 241 | <td class="blm-hist-age">{{ (h.committed_at or "")[:10] }}</td> |
| 242 | </tr> |
| 243 | {% endfor %} |
| 244 | </tbody> |
| 245 | </table> |
| 246 | {% else %} |
| 247 | <p class="blm-history-empty">No detailed history available for this symbol.</p> |
| 248 | {% endif %} |
| 249 | <div class="blm-history-footer"> |
| 250 | <a href="{{ base_url }}/symbols?q={{ entry.symbol_name | urlencode }}">View symbol detail ↗</a> |
| 251 | </div> |
| 252 | </div> |
| 253 | |
| 254 | </details> |
| 255 | {% endfor %} |
| 256 | </div> |
| 257 | |
| 258 | {# ════════════════════════════════════════════════════════════════════ #} |
| 259 | {# FILE BLAME ────────────────────────────────────────────────────────── #} |
| 260 | {# ════════════════════════════════════════════════════════════════════ #} |
| 261 | {% elif blame_type == "file" %} |
| 262 | {% set entry = blame_entries[0] %} |
| 263 | <div class="blm-file-view"> |
| 264 | |
| 265 | {# Commit info bar #} |
| 266 | <div class="blm-file-commit-bar"> |
| 267 | <span class="blm-commit-dot" style="background: {{ commit_color.get(entry.commit_id, '#444') }}"></span> |
| 268 | <a class="blm-file-commit-sha" href="{{ base_url }}/commits/{{ entry.commit_id }}"> |
| 269 | {{ entry.commit_id[:8] }} |
| 270 | </a> |
| 271 | <span class="blm-file-commit-msg">{{ entry.commit_message | truncate(72, True, "…") | e }}</span> |
| 272 | <span class="blm-file-commit-sep">·</span> |
| 273 | <span class="blm-file-commit-author">{{ entry.author | e }}</span> |
| 274 | <span class="blm-file-commit-sep">·</span> |
| 275 | <span class="blm-file-commit-time">{{ entry.timestamp | fmtdate }}</span> |
| 276 | </div> |
| 277 | |
| 278 | {# Code lines with blame gutter #} |
| 279 | {% if file_lines %} |
| 280 | <div style="overflow-x:auto"> |
| 281 | <table class="blm-code-table"> |
| 282 | <tbody> |
| 283 | {% for line in file_lines %} |
| 284 | <tr class="blm-code-row" id="L{{ loop.index }}"> |
| 285 | <td class="blm-gutter" style="border-left:3px solid {{ commit_color.get(entry.commit_id, '#444') }}"> |
| 286 | <a class="blm-lnlink" href="#L{{ loop.index }}">{{ loop.index }}</a> |
| 287 | </td> |
| 288 | <td class="blm-code-cell">{{ line | e }}</td> |
| 289 | </tr> |
| 290 | {% endfor %} |
| 291 | </tbody> |
| 292 | </table> |
| 293 | </div> |
| 294 | {% if file_truncated %} |
| 295 | <div class="blm-code-truncated"> |
| 296 | File truncated at 200 KB — <a href="{{ base_url }}/blob/{{ ref }}/{{ path }}">view full file ↗</a> |
| 297 | </div> |
| 298 | {% endif %} |
| 299 | {% else %} |
| 300 | <div class="blm-file-empty"> |
| 301 | File content not available. <a href="{{ base_url }}/blob/{{ ref }}/{{ path }}">View in blob viewer ↗</a> |
| 302 | </div> |
| 303 | {% endif %} |
| 304 | |
| 305 | </div> |
| 306 | {% endif %} |
| 307 | |
| 308 | </div>{# .blm-content #} |
| 309 | </div>{# .blm-layout #} |
| 310 | |
| 311 | {% endif %}{# blame_entries #} |
| 312 | |
| 313 | {% endblock %} |
| 314 | |
| 315 | {% block page_json %}{"page":"blame","baseUrl":{{ base_url | tojson }},"blameType":{{ blame_type | tojson }},"heatMax":{{ heat_max | tojson }}}{% endblock %} |
File History
1 commit
sha256:7281683f5c41e5d88b6d8811fbdafebd3e01a0c9dcd90975cfcb444ba71e8e81
docs: add local source-of-truth for musehub#225, #226, #227…
Sonnet 5
1 day ago