<title>cctop</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#16151a">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="manifest" href="/manifest.webmanifest">
<style>__CCTOP_CSS__
.totals { display: flex; gap: 18px; flex-wrap: wrap; align-items: baseline; }
.totals b { font-family: var(--mono); font-weight: 600; }
.totals .k { color: var(--faint); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; }
.quota {
flex-basis: 100%; display: flex; gap: 4px 14px; flex-wrap: wrap;
align-items: center; font-size: 11px; color: var(--faint);
}
.quota:empty { display: none; }
.quota .qp { display: inline-flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.quota .qwho { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; }
.quota .qw { white-space: nowrap; }
.quota .qw b { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 600; color: var(--dim); }
.quota .ctx { width: 28px; height: 4px; }
.controls { display: flex; gap: 8px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
input[type=search] {
flex: 1 1 200px; min-width: 0; padding: 7px 11px; font: inherit; font-size: 14px;
background: var(--panel); color: var(--ink);
border: 1px solid var(--line); border-radius: 8px;
}
input[type=search]:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
button {
padding: 7px 11px; font: inherit; font-size: 13px; cursor: pointer;
background: var(--panel); color: var(--dim);
border: 1px solid var(--line); border-radius: 8px;
}
button[aria-pressed=true] { color: var(--accent); border-color: var(--accent); }
select {
padding: 7px 9px; font: inherit; font-size: 13px; cursor: pointer;
background: var(--panel); color: var(--dim);
border: 1px solid var(--line); border-radius: 8px;
}
form.launch { display: flex; gap: 8px; align-items: center; margin: 0; }
form.launch[hidden] { display: none; }
form.launch input[type=text] {
width: 180px; padding: 7px 11px; font: inherit; font-size: 14px;
background: var(--panel); color: var(--ink);
border: 1px solid var(--line); border-radius: 8px;
}
form.launch .said { font-size: 12px; }
.attention { border-color: var(--amber); margin-bottom: 16px; }
.attention h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
color: var(--amber); padding: 11px 14px 0; }
.rows { display: block; }
.row {
display: grid; gap: 2px 10px; padding: 11px 14px; border-top: 1px solid var(--line);
grid-template-columns: 8px minmax(0, 1fr) auto;
text-decoration: none; color: inherit; cursor: pointer;
}
.row:first-of-type { border-top: 0; }
.row:hover, .row:focus-visible { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.row.sel { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.row.sel:hover, .row.sel:focus-visible { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.row .dot { margin-top: 7px; }
.row .name { min-width: 0; font-weight: 500; }
.row .name .title { color: var(--dim); font-weight: 400; }
.row .name .pin { color: var(--faint); font-weight: 400; margin-right: 4px; }
.row .name .tick { color: var(--accent); font-weight: 400; margin-right: 4px; }
.row.picked { box-shadow: inset 3px 0 0 var(--accent); }
.row .name .newdot {
display: inline-block; width: 6px; height: 6px; border-radius: 50%;
background: var(--accent); margin-left: 6px; vertical-align: 1px;
}
.row .meta { grid-column: 2; display: flex; gap: 8px; flex-wrap: wrap; font-size: 12px; color: var(--faint); }
.row .meta .snip { flex: 1 1 100%; min-width: 0; }
.row .figures { grid-row: 1 / span 2; grid-column: 3; text-align: right; font-family: var(--mono);
font-variant-numeric: tabular-nums; font-size: 13px; white-space: nowrap; }
.row .figures .sub { font-size: 11px; color: var(--faint); }
.trunc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctx { display: inline-block; width: 46px; height: 5px; border-radius: 3px;
background: var(--line); overflow: hidden; vertical-align: middle; }
.ctx i { display: block; height: 100%; background: var(--dim); }
.wanting { position: relative; border-top: 1px solid var(--line); }
.wanting:first-child { border-top: 0; }
.wanting .row { border-top: 0; padding-right: 38px; }
.wanting .dismiss {
position: absolute; top: 9px; right: 8px; padding: 3px 7px;
font-size: 14px; line-height: 1; border-radius: 6px;
color: var(--faint); background: transparent; border-color: transparent;
}
.wanting .dismiss:hover { color: var(--ink); border-color: var(--line); }
form.say { display: flex; gap: 8px; padding: 0 14px 11px 32px; }
form.say input {
flex: 1 1 auto; min-width: 0; font: inherit; font-size: 13px; padding: 6px 9px;
border-radius: 7px; border: 1px solid var(--line); background: var(--bg); color: var(--ink);
}
form.say input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
form.say button {
font: inherit; font-size: 13px; padding: 0 13px; border-radius: 7px; cursor: pointer;
border: 1px solid var(--accent); background: var(--accent); color: var(--panel);
}
form.say button:disabled { opacity: .5; cursor: default; }
form.say .chip {
font: inherit; font-size: 12px; padding: 0 10px; border-radius: 7px; cursor: pointer;
border: 1px solid var(--line); background: var(--panel); color: var(--dim);
flex: 0 0 auto;
}
.wanting .asked { padding: 0 14px 8px 32px; min-width: 0; }
.wanting .asked code {
display: block; font-size: 12px; padding: 5px 9px; border-radius: 7px;
background: var(--bg); border: 1px solid var(--line); color: var(--ink);
white-space: pre-wrap; overflow-wrap: anywhere;
}
form.say .said { font-size: 12px; align-self: center; color: var(--faint); }
form.say .said.bad { color: var(--red); }
.ctx i.hot { background: var(--amber); }
.ctx i.full { background: var(--red); }
.pickrow { position: relative; }
#rows .pickrow { border-top: 1px solid var(--line); }
#rows .pickrow:first-of-type { border-top: 0; }
.pickrow .row { border-top: 0; padding-left: 30px; }
.pickrow .pick {
position: absolute; left: 9px; top: 14px; margin: 0;
accent-color: var(--accent); opacity: .4; cursor: pointer;
}
.pickrow:hover .pick, .pickrow .pick:checked, .pickrow .pick:focus-visible { opacity: 1; }
.find { position: relative; }
.find h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
color: var(--faint); padding: 11px 14px 0; }
.find .dismiss {
position: absolute; top: 9px; right: 8px; padding: 3px 7px;
font-size: 14px; line-height: 1; border-radius: 6px;
color: var(--faint); background: transparent; border-color: transparent;
}
.find .dismiss:hover { color: var(--ink); border-color: var(--line); }
.empty.bad { color: var(--red); }
.bulk {
display: flex; gap: 6px 10px; align-items: center; flex-wrap: wrap;
margin-top: 12px; font-size: 13px; color: var(--dim);
}
.bulk[hidden] { display: none; }
.bulk .sep { color: var(--faint); }
.bulk form { display: flex; gap: 8px; flex: 1 1 260px; min-width: 0; margin: 0; }
.bulk form[hidden] { display: none; }
.bulk input[type=text] {
flex: 1 1 auto; min-width: 0; font: inherit; font-size: 13px; padding: 6px 9px;
border-radius: 7px; border: 1px solid var(--line); background: var(--panel); color: var(--ink);
}
.bulk input[type=text]:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.bulk button:disabled { opacity: .5; cursor: default; }
.bulk .said { font-size: 12px; }
.bulk .said.bad { color: var(--red); }
@media (max-width: 700px) {
.wrap { padding: 12px 10px 48px; }
.controls { gap: 6px; }
form.launch { flex-basis: 100%; flex-wrap: wrap; }
form.launch input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; }
.row { grid-template-columns: 8px minmax(0, 1fr); }
.row .figures {
grid-row: auto; grid-column: 2; text-align: left; white-space: normal;
display: flex; gap: 4px 14px; flex-wrap: wrap; margin-top: 3px;
}
form.say { flex-wrap: wrap; }
form.say input { flex: 1 1 150px; }
}
footer { margin-top: 20px; font-size: 12px; color: var(--faint);
display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
footer .hint { font-size: 11px; }
.live { display: inline-flex; align-items: center; gap: 6px; }
</style>
<script>__CCTOP_THEME_JS__</script>
<div class="wrap">
<header class="top">
<h1>cctop<span class="v mono">__CCTOP_VERSION__</span></h1>
<div class="spacer"></div>
<div class="totals" id="totals"></div>
<div class="quota" id="quota"></div>
</header>
<div id="banners"></div>
<div class="controls">
<input type="search" id="filter" placeholder="Filter on project, model, branch, title…" autocomplete="off" spellcheck="false"
title="Type to filter the table · Enter to search every transcript">
<button id="gsearch" title="Search every transcript for the filter text">Search transcripts</button>
<button id="running" aria-pressed="false" title="Show only sessions with a live process">Running</button>
<button id="bell" aria-pressed="false" title="Notify when a session starts waiting on you">Notify</button>
<select id="sort" title="Order the table">
<option value="recent">Recent</option>
<option value="cost">Cost</option>
<option value="tokens">Tokens</option>
<option value="context">Context</option>
</select>
<form id="launch" class="launch" hidden>
<select id="launch-agent" title="Which agent to start"></select>
<input id="launch-cwd" type="text" placeholder="directory — default ~" autocomplete="off" spellcheck="false">
<button type="submit" title="Start the agent, in the multiplexer">Start</button>
<span id="launch-said" class="said"></span>
</form>
</div>
<section class="card find" id="find" hidden>
<h2 id="find-heading"></h2>
<button class="dismiss" id="find-close" type="button" title="Back to the session table"
aria-label="Back to the session table">×</button>
<div class="rows" id="find-rows"></div>
</section>
<div id="tableview">
<section class="card attention" id="attention" hidden>
<h2 id="attention-heading"></h2>
<div class="rows" id="attention-rows"></div>
</section>
<section class="card">
<div class="rows" id="rows"></div>
<div class="empty" id="empty">Waiting for the first refresh…</div>
</section>
</div>
<div class="bulk" id="bulk" hidden>
<span id="bulk-count"></span>
<span class="sep">·</span>
<button id="bulk-send" type="button" title="Type one line at every selected session">send…</button>
<span class="sep">·</span>
<button id="bulk-resume" type="button" title="Resume every selected session">resume</button>
<span class="sep">·</span>
<button id="bulk-clear" type="button" title="Empty the selection">clear</button>
<form id="bulk-form" hidden>
<input id="bulk-text" type="text" maxlength="4000" autocomplete="off" spellcheck="false"
placeholder="One line, sent to each selected session">
<button type="submit">Send</button>
</form>
<span class="said" id="bulk-said"></span>
</div>
<footer>
<span class="live"><span class="dot idle" id="link"></span><span id="link-text">connecting…</span></span>
<a id="analytics-link" href="/analytics">analytics</a>
<span class="spacer"></span>
<span id="counts"></span>
<span class="hint" id="keys">j/k select · Enter opens · p pins · / filters · Enter in the filter searches transcripts</span>
<a id="insight-optimize" href="/insight/optimize">optimize</a>
<a id="insight-compare" href="/insight/compare">compare</a>
</footer>
</div>
<script>
__CCTOP_DASHBOARD_JS__</script>