Conflicts:
- CLAUDE.md: keep both sets of gotchas (drift/merge from main, SSE ping and
swarm_cluster_id from this branch).
- internal/imageref/imageref_test.go: keep both TestIsDigest (main) and
TestIsRegistryHost (this branch).
- internal/master/web/server.go: take main's renderServiceError and make it
render through s.page, so service error pages get the sidebar nav data.
Also renumber this branch's migration 0005_agent_cluster.sql to
0006_agent_cluster.sql, after main's 0005_drift_merge.sql.
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
- Move the .agent @container rule after the base .agent rules. A container
query adds no specificity, so the earlier position always lost and rows
kept six fixed columns, spilling Revoke buttons onto the open drawer.
- Give .drawer min-width:0 so the compose snippet scrolls inside its <pre>
instead of widening the drawer past the viewport at 390px.
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
- icons/gen writes to the current directory so `go generate
./internal/master/web/icons` works (output verified byte-identical)
- share the registry-host check as imageref.IsRegistryHost (with test)
- agents fragment refreshes the "N machines" header count out of band
- ignore the saved machine filter at <=760px where the machine list is hidden
- aria-current on the active machine filter link, aria-pressed on theme toggle
- CLAUDE.md: icons package, SSE ping event, swarm_cluster_id
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
Restyles the master UI after the Ledger design: a sidebar with live counts,
a machine filter, a Live box and a light/dark toggle; the overview groups
services per Swarm cluster and machine with icons, search and the
Icon / Icon + text / Text switch; the agents page gets a revoke popover and
an add-agent panel with a connect step. Jobs, Job and Service pages get the
new shell and tokens only.
- fonts and Simple Icons are served by the master (no CDN)
- the overview reads agents too, to show offline banners and cluster managers
- revoking an agent also publishes the agents event
- the SSE keepalive is a named event (ping) the Live box counts
- the master passes its build version to the UI so agents on another
version are marked old
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
The Ledger UI groups Swarm services under their cluster and lists the
cluster's managers, so the master needs to know which cluster an agent
belongs to. RecordHello now stores hello.SwarmClusterID in the new
agents.swarm_cluster_id column.
Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ