mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 15:39:41 +02:00
Merge pull request #346 from JackStuart/codex/show-codex-usage-limits
feat(web): show Codex plan usage in header
This commit is contained in:
+18
-10
@@ -2597,8 +2597,8 @@ class CodemanApp {
|
||||
}
|
||||
}
|
||||
|
||||
// Claude plan usage limits (5-hour + weekly) — account-global, so the latest
|
||||
// sample from any session drives the shared header chip.
|
||||
// Claude + Codex plan usage limits — account-global, so the latest sample
|
||||
// drives the shared header chip.
|
||||
_onSessionStatusTelemetry(data) {
|
||||
this.updatePlanUsageChip(data);
|
||||
// Persist last-known so the chip shows immediately on the next page load /
|
||||
@@ -2625,9 +2625,6 @@ class CodemanApp {
|
||||
const chip = document.getElementById('planUsageChip');
|
||||
if (!chip || !data) return;
|
||||
const pct = (w) => (w && typeof w.usedPercentage === 'number' ? Math.round(w.usedPercentage) : null);
|
||||
const five = pct(data.fiveHour);
|
||||
const seven = pct(data.sevenDay);
|
||||
if (five === null && seven === null) return;
|
||||
// Per-window color by how much is used up: green < 60%, yellow 60–84%, red ≥ 85%.
|
||||
const colorClass = (p) => (p >= 85 ? 'pu-red' : p >= 60 ? 'pu-yellow' : 'pu-green');
|
||||
// innerHTML here is XSS-safe ONLY because every interpolated value is a
|
||||
@@ -2641,12 +2638,23 @@ class CodemanApp {
|
||||
if (!Number.isFinite(n)) return '';
|
||||
return `<span class="pu-win"><span class="pu-label">${label}</span><span class="pu-val ${colorClass(n)}">${n}%</span></span>`;
|
||||
};
|
||||
chip.innerHTML = [seg('5h', five), seg('7d', seven)].filter(Boolean).join('<span class="pu-sep">·</span>');
|
||||
const row = (provider, usage) => {
|
||||
const windows = [seg('5h', pct(usage?.fiveHour)), seg('7d', pct(usage?.sevenDay))].filter(Boolean);
|
||||
if (!windows.length) return '';
|
||||
return `<span class="pu-row"><span class="pu-provider">${provider}</span><span class="pu-windows">${windows.join('<span class="pu-sep">·</span>')}</span></span>`;
|
||||
};
|
||||
const rows = [row('Claude', data), row('Codex', data.codex)].filter(Boolean);
|
||||
chip.innerHTML = rows.length ? rows.join('') : '—';
|
||||
const resetStr = (w) => (w && w.resetAt ? new Date(w.resetAt).toLocaleString() : '—');
|
||||
chip.title =
|
||||
`Claude plan usage\n` +
|
||||
`5-hour limit: ${five ?? '—'}% used (resets ${resetStr(data.fiveHour)})\n` +
|
||||
`Weekly limit: ${seven ?? '—'}% used (resets ${resetStr(data.sevenDay)})`;
|
||||
const details = (provider, usage) => {
|
||||
const lines = [];
|
||||
const five = pct(usage?.fiveHour);
|
||||
const seven = pct(usage?.sevenDay);
|
||||
if (five !== null) lines.push(`5-hour limit: ${five}% used (resets ${resetStr(usage.fiveHour)})`);
|
||||
if (seven !== null) lines.push(`Weekly limit: ${seven}% used (resets ${resetStr(usage.sevenDay)})`);
|
||||
return lines.length ? `${provider} plan usage\n${lines.join('\n')}` : '';
|
||||
};
|
||||
chip.title = [details('Claude', data), details('Codex', data.codex)].filter(Boolean).join('\n\n') || 'Plan usage limits';
|
||||
}
|
||||
|
||||
// Scheduled runs
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
<button class="btn-icon-header btn-file-viewer" onclick="app.toggleFileBrowserButton()" title="File Viewer" aria-label="Open file viewer" aria-expanded="false"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></button>
|
||||
<button class="btn-icon-header btn-multimonitor btn-multimonitor--hidden" onclick="app.launchMultiMonitor()" title="Open Codeman across all displays" aria-label="Open Codeman across all displays"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="13" height="9" rx="1.5"/><rect x="11" y="9" width="11" height="8" rx="1.5"/></svg></button>
|
||||
<button class="btn-icon-header btn-ultracode-agents btn-ultracode-agents--hidden" onclick="app.toggleUltracodeAgentsPanel()" title="Ultracode / Workflow agents" aria-label="Open ultracode workflow agents"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><path d="M8.2 7.2 15.6 11M8.2 16.8 15.6 13"/></svg></button>
|
||||
<div class="header-plan-usage header-plan-usage--hidden" id="planUsageChip" title="Claude plan usage limits">—</div>
|
||||
<div class="header-plan-usage header-plan-usage--hidden" id="planUsageChip" title="Claude and Codex plan usage limits">—</div>
|
||||
<button class="btn-icon-header btn-notifications" onclick="app.toggleNotifications()" title="Notifications" aria-label="Toggle notifications" style="display:none;">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
|
||||
<span class="notification-badge" id="notifBadge" style="display:none;">0</span>
|
||||
|
||||
@@ -12372,17 +12372,20 @@ kbd {
|
||||
}
|
||||
|
||||
/* Plan-usage chip (App Settings → Display → "Plan Usage Limits"). Shows the
|
||||
live 5-hour + weekly plan limits parsed from the Claude statusline. Ships
|
||||
live Claude and Codex plan limits in provider rows. Ships
|
||||
hidden via the marker class below because display is PER-DEVICE and the
|
||||
server cannot read localStorage; settings-ui.js reveals it on load (desktop
|
||||
default ON, handhelds OFF) and on a live toggle. */
|
||||
.header-plan-usage {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
height: 22px;
|
||||
padding: 0 0.5rem;
|
||||
border-radius: 11px;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
min-height: 22px;
|
||||
padding: 3px 0.5rem;
|
||||
border-radius: 8px;
|
||||
font-size: 0.7rem;
|
||||
line-height: 1.1;
|
||||
font-weight: 500;
|
||||
font-family: 'SF Mono', Monaco, monospace;
|
||||
color: var(--text-dim);
|
||||
@@ -12391,6 +12394,23 @@ kbd {
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
.header-plan-usage .pu-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
.header-plan-usage .pu-provider {
|
||||
width: 46px;
|
||||
flex: 0 0 46px;
|
||||
font-size: 0.58rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-dim);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.header-plan-usage .pu-windows {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
/* Readable two-window layout: dim uppercase label + bold, color-coded value. */
|
||||
.header-plan-usage .pu-win {
|
||||
display: inline-flex;
|
||||
|
||||
Reference in New Issue
Block a user