chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:26:02 +08:00
commit a0a48b5e45
437 changed files with 100767 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
# CodeBurn GNOME Extension
Monitor AI coding assistant token usage and costs from your GNOME desktop panel.
## Requirements
- GNOME Shell 45 or later
- CodeBurn CLI installed (`npm i -g codeburn`)
- `glib-compile-schemas` (usually part of `glib2-devel` or `libglib2.0-dev`)
## Install
```bash
cd gnome
chmod +x install.sh
./install.sh
```
Then restart GNOME Shell:
- **Wayland:** Log out and back in
- **X11:** Press `Alt+F2`, type `r`, press Enter
Enable the extension:
```bash
gnome-extensions enable codeburn@codeburn.dev
```
## Configure
Open preferences:
```bash
gnome-extensions prefs codeburn@codeburn.dev
```
Or use the GNOME Extensions app.
### Settings
| Setting | Default | Description |
|---------|---------|-------------|
| Refresh Interval | 30s | How often to poll CodeBurn CLI |
| Default Period | Today | Period shown on open |
| Compact Mode | Off | Hide cost label, show icon only |
| Budget Threshold | $0 | Daily budget alert (0 = disabled) |
| Budget Alerts | Off | Show warning when budget exceeded |
| CLI Path | (auto) | Custom path to `codeburn` binary |
## Uninstall
```bash
gnome-extensions disable codeburn@codeburn.dev
rm -r ~/.local/share/gnome-shell/extensions/codeburn@codeburn.dev
```
## Development
Test changes without installing:
```bash
# Compile schemas locally
glib-compile-schemas schemas/
# Symlink for development
ln -sf "$(pwd)" ~/.local/share/gnome-shell/extensions/codeburn@codeburn.dev
# Watch logs
journalctl -f -o cat /usr/bin/gnome-shell
```
+161
View File
@@ -0,0 +1,161 @@
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
const TIMEOUT_SECONDS = 15;
const SAFE_ARG_RE = /^[A-Za-z0-9 ._/\-]+$/;
function buildAdditionalPaths() {
const home = GLib.get_home_dir();
return [
'/usr/local/bin',
`${home}/.local/bin`,
`${home}/.npm-global/bin`,
`${home}/.volta/bin`,
`${home}/.bun/bin`,
`${home}/.cargo/bin`,
`${home}/.asdf/shims`,
`${home}/.local/share/fnm/aliases/default/bin`,
`${home}/.local/share/pnpm`,
];
}
export class DataClient {
_cache = new Map();
_inFlight = null;
_codeburnPath;
_augmentedPath;
constructor(codeburnPath) {
this._codeburnPath = codeburnPath || '';
this._augmentedPath = this._buildAugmentedPath();
}
setCodeburnPath(path) {
this._codeburnPath = path || '';
}
cancelInFlight() {
if (this._inFlight) {
this._inFlight.cancellable.cancel();
this._inFlight = null;
}
}
getCached(period, provider) {
const key = `${period}:${provider}`;
return this._cache.get(key) ?? null;
}
async fetch(period, provider) {
this.cancelInFlight();
const cancellable = new Gio.Cancellable();
this._inFlight = { cancellable };
try {
const payload = await this._spawn(period, provider, cancellable);
const key = `${period}:${provider}`;
this._cache.set(key, payload);
return payload;
} finally {
if (this._inFlight?.cancellable === cancellable)
this._inFlight = null;
}
}
_buildArgv(period, provider) {
let base;
if (this._codeburnPath && SAFE_ARG_RE.test(this._codeburnPath)) {
base = this._codeburnPath.split(' ').filter(s => s.length > 0);
} else {
base = ['codeburn'];
}
const args = [
...base,
'status',
'--format', 'menubar-json',
'--period', period,
'--no-optimize',
];
if (provider && provider !== 'all')
args.push('--provider', provider);
return args;
}
_buildAugmentedPath() {
const currentPath = GLib.getenv('PATH') || '/usr/bin:/bin';
const parts = currentPath.split(':');
for (const extra of buildAdditionalPaths()) {
if (!parts.includes(extra))
parts.push(extra);
}
return parts.join(':');
}
_spawn(period, provider, cancellable) {
return new Promise((resolve, reject) => {
const argv = this._buildArgv(period, provider);
let settled = false;
const settle = (fn, value) => {
if (settled) return;
settled = true;
fn(value);
};
let proc;
try {
const launcher = Gio.SubprocessLauncher.new(
Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE
);
launcher.setenv('PATH', this._augmentedPath, true);
proc = launcher.spawnv(argv);
} catch (e) {
settle(reject, new Error(`CLI not found: ${e.message}`));
return;
}
let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, TIMEOUT_SECONDS, () => {
timeoutId = 0;
proc.force_exit();
settle(reject, new Error('CLI timeout'));
return GLib.SOURCE_REMOVE;
});
proc.communicate_utf8_async(null, cancellable, (_proc, res) => {
if (timeoutId) {
GLib.Source.remove(timeoutId);
timeoutId = 0;
}
try {
const [, stdout, stderr] = _proc.communicate_utf8_finish(res);
if (!_proc.get_successful()) {
const msg = stderr?.trim() || 'CLI exited with error';
settle(reject, new Error(msg));
return;
}
if (!stdout || stdout.trim().length === 0) {
settle(reject, new Error('CLI returned empty output'));
return;
}
const payload = JSON.parse(stdout);
settle(resolve, payload);
} catch (e) {
settle(reject, e);
}
});
});
}
destroy() {
this.cancelInFlight();
this._cache.clear();
}
}
+17
View File
@@ -0,0 +1,17 @@
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { CodeBurnIndicator } from './indicator.js';
export default class CodeBurnExtension extends Extension {
_indicator = null;
enable() {
this._indicator = new CodeBurnIndicator(this);
Main.panel.addToStatusArea('codeburn-indicator', this._indicator);
}
disable() {
this._indicator?.destroy();
this._indicator = null;
}
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="currentColor" d="M8 1C6.5 3.5 4 5 4 8c0 2.2 1.8 4 4 4s4-1.8 4-4c0-3-2.5-4.5-4-7zm0 9.5c-1 0-1.5-.7-1.5-1.5 0-1.2 1-2 1.5-3 .5 1 1.5 1.8 1.5 3 0 .8-.5 1.5-1.5 1.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

+1020
View File
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -euo pipefail
UUID="codeburn@codeburn.dev"
INSTALL_DIR="${HOME}/.local/share/gnome-shell/extensions/${UUID}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "Installing CodeBurn GNOME extension..."
# Compile GSettings schema
echo "Compiling schemas..."
glib-compile-schemas "${SCRIPT_DIR}/schemas/"
# Create install directory
mkdir -p "${INSTALL_DIR}"
# Copy extension files
cp "${SCRIPT_DIR}/metadata.json" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/extension.js" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/indicator.js" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/dataClient.js" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/prefs.js" "${INSTALL_DIR}/"
cp "${SCRIPT_DIR}/stylesheet.css" "${INSTALL_DIR}/"
# Copy schemas
mkdir -p "${INSTALL_DIR}/schemas"
cp "${SCRIPT_DIR}/schemas/"* "${INSTALL_DIR}/schemas/"
# Copy icons
mkdir -p "${INSTALL_DIR}/icons"
cp "${SCRIPT_DIR}/icons/"* "${INSTALL_DIR}/icons/"
echo "Extension installed to ${INSTALL_DIR}"
echo ""
echo "Next steps:"
echo " 1. Restart GNOME Shell (log out and back in on Wayland)"
echo " 2. Enable: gnome-extensions enable ${UUID}"
echo " 3. Configure: gnome-extensions prefs ${UUID}"
+8
View File
@@ -0,0 +1,8 @@
{
"name": "CodeBurn Monitor",
"description": "Monitor AI coding assistant token usage and costs",
"uuid": "codeburn@codeburn.dev",
"shell-version": ["45", "46", "47", "48", "49", "50"],
"url": "https://github.com/getagentseal/codeburn",
"settings-schema": "org.gnome.shell.extensions.codeburn"
}
+171
View File
@@ -0,0 +1,171 @@
import Adw from 'gi://Adw';
import Gtk from 'gi://Gtk';
import Gio from 'gi://Gio';
import { ExtensionPreferences } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
const PROVIDERS = [
{ id: 'claude', label: 'Claude' },
{ id: 'codex', label: 'Codex' },
{ id: 'copilot', label: 'Copilot' },
{ id: 'cursor', label: 'Cursor' },
{ id: 'devin', label: 'Devin' },
{ id: 'droid', label: 'Droid' },
{ id: 'gemini', label: 'Gemini' },
{ id: 'goose', label: 'Goose' },
{ id: 'kilo-code', label: 'Kilo Code' },
{ id: 'kiro', label: 'Kiro' },
{ id: 'kimi', label: 'Kimi' },
{ id: 'openclaw', label: 'OpenClaw' },
{ id: 'opencode', label: 'OpenCode' },
{ id: 'pi', label: 'Pi' },
{ id: 'qwen', label: 'Qwen' },
{ id: 'roo-code', label: 'Roo Code' },
{ id: 'antigravity', label: 'Antigravity' },
];
const PERIODS = [
{ id: 'today', label: 'Today' },
{ id: 'week', label: '7 Days' },
{ id: '30days', label: '30 Days' },
{ id: 'month', label: 'Month' },
{ id: 'all', label: '6 Months' },
];
export default class CodeBurnPreferences extends ExtensionPreferences {
fillPreferencesWindow(window) {
const settings = this.getSettings();
const displayPage = new Adw.PreferencesPage({
title: 'Display',
icon_name: 'preferences-desktop-display-symbolic',
});
window.add(displayPage);
const displayGroup = new Adw.PreferencesGroup({
title: 'Display',
description: 'Configure how CodeBurn appears in the panel',
});
displayPage.add(displayGroup);
const refreshRow = new Adw.SpinRow({
title: 'Refresh Interval',
subtitle: 'Seconds between data refreshes',
adjustment: new Gtk.Adjustment({
lower: 5,
upper: 300,
step_increment: 5,
page_increment: 30,
value: settings.get_uint('refresh-interval'),
}),
});
settings.bind('refresh-interval', refreshRow, 'value', Gio.SettingsBindFlags.DEFAULT);
displayGroup.add(refreshRow);
const compactRow = new Adw.SwitchRow({
title: 'Compact Mode',
subtitle: 'Show only the icon, hide the cost label',
});
settings.bind('compact-mode', compactRow, 'active', Gio.SettingsBindFlags.DEFAULT);
displayGroup.add(compactRow);
const darkModeRow = new Adw.SwitchRow({
title: 'Force Dark Mode',
subtitle: 'Always use dark theme for the popup',
});
settings.bind('force-dark-mode', darkModeRow, 'active', Gio.SettingsBindFlags.DEFAULT);
displayGroup.add(darkModeRow);
const exactCostsRow = new Adw.SwitchRow({
title: 'Show Exact Costs',
subtitle: 'Show full values like $2,655.23 instead of $2.7k',
});
settings.bind('show-exact-costs', exactCostsRow, 'active', Gio.SettingsBindFlags.DEFAULT);
displayGroup.add(exactCostsRow);
const periodModel = new Gtk.StringList();
for (const p of PERIODS)
periodModel.append(p.label);
const periodRow = new Adw.ComboRow({
title: 'Default Period',
subtitle: 'Time period shown when extension opens',
model: periodModel,
});
const currentPeriod = settings.get_string('default-period');
const periodIndex = PERIODS.findIndex(p => p.id === currentPeriod);
periodRow.set_selected(periodIndex >= 0 ? periodIndex : 0);
periodRow.connect('notify::selected', () => {
const idx = periodRow.get_selected();
if (idx >= 0 && idx < PERIODS.length)
settings.set_string('default-period', PERIODS[idx].id);
});
displayGroup.add(periodRow);
const alertsGroup = new Adw.PreferencesGroup({
title: 'Budget Alerts',
description: 'Get warned when spending exceeds a threshold',
});
displayPage.add(alertsGroup);
const budgetEnabledRow = new Adw.SwitchRow({
title: 'Enable Budget Alerts',
subtitle: 'Show a warning when daily spending exceeds the threshold',
});
settings.bind('budget-alert-enabled', budgetEnabledRow, 'active', Gio.SettingsBindFlags.DEFAULT);
alertsGroup.add(budgetEnabledRow);
const budgetRow = new Adw.SpinRow({
title: 'Daily Budget (USD)',
subtitle: 'Set to 0 to disable',
adjustment: new Gtk.Adjustment({
lower: 0,
upper: 1000,
step_increment: 1,
page_increment: 10,
value: settings.get_double('budget-threshold'),
}),
digits: 2,
});
settings.bind('budget-threshold', budgetRow, 'value', Gio.SettingsBindFlags.DEFAULT);
alertsGroup.add(budgetRow);
const providersGroup = new Adw.PreferencesGroup({
title: 'Providers',
description: 'Toggle providers on/off for cost accounting',
});
displayPage.add(providersGroup);
const disabledProviders = settings.get_strv('disabled-providers');
for (const provider of PROVIDERS) {
const row = new Adw.SwitchRow({
title: provider.label,
active: !disabledProviders.includes(provider.id),
});
row.connect('notify::active', () => {
const current = settings.get_strv('disabled-providers');
if (row.get_active()) {
settings.set_strv('disabled-providers', current.filter(p => p !== provider.id));
} else {
if (!current.includes(provider.id))
settings.set_strv('disabled-providers', [...current, provider.id]);
}
});
providersGroup.add(row);
}
const advancedGroup = new Adw.PreferencesGroup({
title: 'Advanced',
});
displayPage.add(advancedGroup);
const pathRow = new Adw.EntryRow({
title: 'CodeBurn CLI Path',
text: settings.get_string('codeburn-path'),
});
pathRow.connect('changed', () => {
settings.set_string('codeburn-path', pathRow.get_text());
});
advancedGroup.add(pathRow);
}
}
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="codeburn">
<schema id="org.gnome.shell.extensions.codeburn"
path="/org/gnome/shell/extensions/codeburn/">
<key name="refresh-interval" type="u">
<default>30</default>
<summary>Refresh interval</summary>
<description>Seconds between automatic data refreshes</description>
<range min="5" max="300"/>
</key>
<key name="default-period" type="s">
<default>'today'</default>
<summary>Default time period</summary>
<description>Period shown when extension opens (today, week, 30days, month, all)</description>
</key>
<key name="budget-threshold" type="d">
<default>0.0</default>
<summary>Budget threshold</summary>
<description>Daily budget threshold in USD. Set to 0 to disable.</description>
</key>
<key name="budget-alert-enabled" type="b">
<default>false</default>
<summary>Enable budget alerts</summary>
<description>Show warning when spending exceeds budget threshold</description>
</key>
<key name="compact-mode" type="b">
<default>false</default>
<summary>Compact mode</summary>
<description>Show only icon in panel, hide cost label</description>
</key>
<key name="force-dark-mode" type="b">
<default>false</default>
<summary>Force dark mode</summary>
<description>Always use dark theme for the popup, regardless of system theme</description>
</key>
<key name="show-exact-costs" type="b">
<default>false</default>
<summary>Show exact costs</summary>
<description>Show full decimal values instead of compact notation (e.g. $2,655.23 instead of $2.7k)</description>
</key>
<key name="codeburn-path" type="s">
<default>''</default>
<summary>CodeBurn CLI path</summary>
<description>Custom path to the codeburn executable. Leave empty to use PATH.</description>
</key>
<key name="provider-filter" type="s">
<default>'all'</default>
<summary>Default provider filter</summary>
<description>Default provider to filter by (all shows everything)</description>
</key>
<key name="disabled-providers" type="as">
<default>[]</default>
<summary>Disabled providers</summary>
<description>Providers excluded from cost accounting and display</description>
</key>
</schema>
</schemalist>
+610
View File
@@ -0,0 +1,610 @@
/* ---- panel button ---- */
.codeburn-panel {
spacing: 4px;
}
.codeburn-flame {
font-size: 14px;
}
.codeburn-label {
font-weight: 500;
padding-left: 2px;
padding-right: 2px;
}
/* ---- popup host ---- */
.codeburn-menu {
padding: 0;
}
.codeburn-host {
padding: 0;
margin: 0;
background: transparent;
border: none;
}
.codeburn-host:hover,
.codeburn-host:focus,
.codeburn-host:active,
.codeburn-host:selected {
background: transparent;
}
.codeburn-root {
width: 340px;
height: 540px;
padding: 0;
spacing: 0;
}
.codeburn-scroll {
padding: 0;
}
/* ---- brand header ---- */
.codeburn-brand-header {
padding: 14px 16px 10px 16px;
spacing: 2px;
}
.codeburn-brand-row {
spacing: 0;
}
.codeburn-brand-primary {
font-weight: 700;
font-size: 18px;
}
.codeburn-brand-accent {
font-weight: 700;
font-size: 18px;
color: #ff8c42;
}
.codeburn-brand-subhead {
font-size: 10.5px;
opacity: 0.55;
}
/* ---- tab rows ---- */
.codeburn-tab-row {
padding: 4px 10px 8px 10px;
spacing: 4px;
}
.codeburn-period-row {
padding-top: 0;
padding-bottom: 10px;
}
.codeburn-tab,
.codeburn-period {
padding: 5px 6px;
border-radius: 6px;
font-size: 11px;
font-weight: 500;
background: transparent;
border: none;
opacity: 0.7;
transition-duration: 80ms;
}
.codeburn-tab:hover,
.codeburn-period:hover {
background: rgba(255, 140, 66, 0.08);
opacity: 1;
}
.codeburn-tab-active,
.codeburn-period-active {
background: rgba(255, 140, 66, 0.18);
color: #ff8c42;
opacity: 1;
font-weight: 600;
}
.codeburn-agent-scroll {
padding: 0;
}
.codeburn-agent-badge {
padding: 3px 10px;
border-radius: 10px;
background: rgba(255, 140, 66, 0.12);
color: #ff8c42;
font-size: 10.5px;
font-weight: 500;
}
/* ---- hero ---- */
.codeburn-hero {
padding: 4px 16px 10px 16px;
spacing: 2px;
}
.codeburn-hero-top {
spacing: 6px;
}
.codeburn-hero-dot {
width: 6px;
height: 6px;
border-radius: 3px;
background-color: #ff8c42;
margin-top: 7px;
}
.codeburn-hero-label {
font-size: 11px;
opacity: 0.65;
font-weight: 500;
}
.codeburn-hero-amount {
font-size: 28px;
font-weight: 700;
color: #ffd700;
}
.codeburn-hero-meta {
font-size: 11px;
opacity: 0.6;
}
/* ---- activity section ---- */
.codeburn-section-title {
font-weight: 600;
font-size: 11px;
opacity: 0.6;
padding-bottom: 2px;
}
/* ---- table headers ---- */
.codeburn-table-header {
spacing: 6px;
padding: 2px 0 4px 0;
}
.codeburn-th {
font-size: 10px;
font-weight: 600;
opacity: 0.45;
}
.codeburn-th-cost {
min-width: 64px;
}
.codeburn-th-turns {
min-width: 40px;
}
.codeburn-th-calls {
min-width: 50px;
}
.codeburn-activity-rows {
spacing: 0;
}
.codeburn-activity-row {
spacing: 3px;
padding: 6px 0;
}
.codeburn-activity-top {
spacing: 6px;
}
.codeburn-activity-name {
font-size: 11.5px;
font-weight: 500;
min-width: 120px;
}
.codeburn-activity-cost {
font-size: 11.5px;
font-family: monospace;
font-weight: 600;
color: #ffd700;
min-width: 64px;
}
.codeburn-activity-turns {
font-size: 10.5px;
font-family: monospace;
opacity: 0.6;
min-width: 40px;
}
.codeburn-activity-oneshot {
font-size: 10.5px;
font-family: monospace;
color: #4ec972;
min-width: 40px;
}
.codeburn-bar-track {
height: 4px;
border-radius: 2px;
background-color: rgba(255, 255, 255, 0.08);
width: 240px;
}
.codeburn-bar-fill {
height: 4px;
border-radius: 2px;
background-color: #ff8c42;
}
.codeburn-empty {
font-style: italic;
opacity: 0.55;
padding: 6px 0;
}
/* ---- loading skeleton ---- */
.codeburn-loading {
padding: 10px 16px;
spacing: 10px;
}
.codeburn-skeleton-bar {
background-color: rgba(255, 140, 66, 0.15);
border-radius: 4px;
}
.codeburn-light .codeburn-skeleton-bar {
background-color: rgba(200, 80, 30, 0.12);
}
/* ---- findings CTA ---- */
.codeburn-findings {
margin: 2px 16px 10px 16px;
padding: 9px 11px;
border-radius: 8px;
background: rgba(255, 140, 66, 0.12);
border: none;
transition-duration: 120ms;
}
.codeburn-findings:hover {
background: rgba(255, 140, 66, 0.2);
}
.codeburn-findings-inner {
spacing: 8px;
}
.codeburn-findings-count {
font-size: 11.5px;
font-weight: 600;
color: #ff8c42;
}
.codeburn-findings-savings {
font-size: 11.5px;
font-weight: 500;
color: #ff8c42;
opacity: 0.8;
}
/* ---- footer ---- */
.codeburn-footer {
padding: 10px 12px;
spacing: 6px;
}
.codeburn-footer-btn {
padding: 6px 10px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.05);
border: none;
font-size: 11px;
font-weight: 500;
transition-duration: 80ms;
}
.codeburn-footer-btn:hover {
background: rgba(255, 255, 255, 0.1);
}
.codeburn-currency-box {
spacing: 2px;
}
.codeburn-currency-btn {
font-family: monospace;
min-width: 62px;
}
.codeburn-currency-picker {
background: rgba(30, 30, 30, 0.95);
border-radius: 8px;
padding: 4px;
height: 180px;
}
.codeburn-currency-list {
spacing: 1px;
}
.codeburn-currency-item {
padding: 4px 10px;
border-radius: 4px;
font-size: 11px;
font-family: monospace;
background: transparent;
border: none;
}
.codeburn-currency-item:hover {
background: rgba(255, 140, 66, 0.12);
}
.codeburn-currency-item-active {
background: rgba(255, 140, 66, 0.2);
color: #ff8c42;
font-weight: 600;
}
.codeburn-footer-cta {
background: #c9521d;
color: #ffffff;
}
.codeburn-footer-cta:hover {
background: #ff8c42;
}
.codeburn-updated {
font-size: 10px;
opacity: 0.45;
padding: 0 16px 10px 16px;
}
/* ---- insight pills row ---- */
.codeburn-insight-row {
padding: 4px 10px 8px 10px;
spacing: 4px;
}
.codeburn-insight-pill {
padding: 4px 4px;
border-radius: 6px;
font-size: 10.5px;
font-weight: 500;
background: transparent;
border: none;
opacity: 0.65;
transition-duration: 80ms;
}
.codeburn-insight-pill:hover {
background: rgba(255, 140, 66, 0.08);
opacity: 1;
}
.codeburn-insight-pill-active {
background: rgba(255, 140, 66, 0.18);
color: #ff8c42;
opacity: 1;
font-weight: 600;
}
/* ---- token histogram chart ---- */
.codeburn-chart {
padding: 0 16px 10px 16px;
spacing: 4px;
}
.codeburn-chart-header {
spacing: 6px;
}
.codeburn-chart-label {
font-weight: 600;
font-size: 11px;
opacity: 0.6;
}
.codeburn-chart-total {
font-family: monospace;
font-size: 11px;
opacity: 0.7;
color: #ff8c42;
}
.codeburn-chart-bars {
spacing: 2px;
height: 52px;
}
.codeburn-chart-col {
height: 52px;
}
.codeburn-chart-spacer {
background: transparent;
}
.codeburn-chart-bar {
background-color: #ff8c42;
border-radius: 2px 2px 0 0;
}
.codeburn-chart-bar-hover {
background-color: #ffa94d;
}
.codeburn-chart-total-hover {
font-weight: 600;
}
.codeburn-divider {
height: 1px;
background-color: rgba(255, 255, 255, 0.08);
margin: 4px 16px;
}
/* ---- trend, pulse, stats, kv rows ---- */
.codeburn-content {
padding: 6px 16px 10px 16px;
spacing: 6px;
}
.codeburn-trend-row,
.codeburn-kv-row {
padding: 4px 0;
spacing: 8px;
}
.codeburn-trend-date,
.codeburn-kv-label {
font-size: 11.5px;
font-weight: 500;
}
.codeburn-trend-cost,
.codeburn-kv-value {
font-family: monospace;
font-size: 11.5px;
font-weight: 600;
color: #ffd700;
}
.codeburn-trend-calls {
font-size: 10.5px;
opacity: 0.6;
min-width: 62px;
}
/* ---- pulse tiles ---- */
.codeburn-pulse-row {
spacing: 6px;
padding: 4px 0;
}
.codeburn-pulse-tile {
padding: 10px 8px;
border-radius: 8px;
background: rgba(255, 140, 66, 0.08);
spacing: 2px;
}
.codeburn-pulse-value {
font-size: 16px;
font-weight: 700;
color: #ff8c42;
font-family: monospace;
}
.codeburn-pulse-label {
font-size: 10px;
opacity: 0.6;
}
/* ---- models rows ---- */
.codeburn-models-rows {
spacing: 0;
padding-top: 4px;
}
.codeburn-model-row {
spacing: 8px;
padding: 6px 0;
}
.codeburn-model-name {
font-size: 11.5px;
min-width: 120px;
}
.codeburn-model-cost {
font-family: monospace;
font-size: 11.5px;
color: #ffd700;
min-width: 64px;
}
.codeburn-model-calls {
font-family: monospace;
font-size: 10.5px;
opacity: 0.6;
min-width: 50px;
}
/* ---- settings gear button ---- */
.codeburn-prefs-btn {
padding: 6px 8px;
font-size: 14px;
}
/* ---- budget warning ---- */
.codeburn-budget-warning {
color: #e5a50a;
font-weight: bold;
font-size: 11.5px;
padding: 6px 16px;
}
/* ---- dark theme ---- */
.codeburn-dark {
background-color: rgba(30, 30, 30, 0.98);
color: #e0e0e0;
border-radius: 12px;
}
.codeburn-dark .codeburn-brand-primary {
color: #ffffff;
}
.codeburn-dark .codeburn-brand-subhead {
color: rgba(255, 255, 255, 0.55);
}
.codeburn-dark .codeburn-hero-label,
.codeburn-dark .codeburn-hero-meta {
color: rgba(255, 255, 255, 0.65);
}
.codeburn-dark .codeburn-section-title,
.codeburn-dark .codeburn-th,
.codeburn-dark .codeburn-chart-label {
color: rgba(255, 255, 255, 0.5);
}
.codeburn-dark .codeburn-activity-name,
.codeburn-dark .codeburn-model-name,
.codeburn-dark .codeburn-trend-date,
.codeburn-dark .codeburn-kv-label {
color: #e0e0e0;
}
.codeburn-dark .codeburn-activity-turns,
.codeburn-dark .codeburn-model-calls,
.codeburn-dark .codeburn-trend-calls {
color: rgba(255, 255, 255, 0.5);
}
.codeburn-dark .codeburn-footer-btn {
background: rgba(255, 255, 255, 0.08);
color: #e0e0e0;
}
.codeburn-dark .codeburn-footer-btn:hover {
background: rgba(255, 255, 255, 0.14);
}
.codeburn-dark .codeburn-currency-picker {
background: rgba(20, 20, 20, 0.98);
}
.codeburn-dark .codeburn-currency-item {
color: #e0e0e0;
}
.codeburn-dark .codeburn-tab,
.codeburn-dark .codeburn-period,
.codeburn-dark .codeburn-insight-pill {
color: rgba(255, 255, 255, 0.7);
}
.codeburn-dark .codeburn-updated {
color: rgba(255, 255, 255, 0.45);
}
/* ---- light theme ---- */
.codeburn-light {
background-color: rgba(255, 255, 255, 0.98);
color: #1a1a1a;
border-radius: 12px;
}
.codeburn-light .codeburn-brand-primary {
color: #1a1a1a;
}
.codeburn-light .codeburn-brand-subhead {
color: rgba(0, 0, 0, 0.5);
}
.codeburn-light .codeburn-hero-label,
.codeburn-light .codeburn-hero-meta {
color: rgba(0, 0, 0, 0.6);
}
.codeburn-light .codeburn-hero-amount {
color: #c9521d;
}
.codeburn-light .codeburn-section-title,
.codeburn-light .codeburn-th,
.codeburn-light .codeburn-chart-label {
color: rgba(0, 0, 0, 0.45);
}
.codeburn-light .codeburn-activity-name,
.codeburn-light .codeburn-model-name,
.codeburn-light .codeburn-trend-date,
.codeburn-light .codeburn-kv-label {
color: #1a1a1a;
}
.codeburn-light .codeburn-activity-cost,
.codeburn-light .codeburn-model-cost,
.codeburn-light .codeburn-trend-cost,
.codeburn-light .codeburn-kv-value {
color: #c9521d;
}
.codeburn-light .codeburn-activity-turns,
.codeburn-light .codeburn-model-calls,
.codeburn-light .codeburn-trend-calls {
color: rgba(0, 0, 0, 0.5);
}
.codeburn-light .codeburn-activity-oneshot {
color: #1b7a35;
}
.codeburn-light .codeburn-bar-track {
background-color: rgba(0, 0, 0, 0.08);
}
.codeburn-light .codeburn-bar-fill {
background-color: #c9521d;
}
.codeburn-light .codeburn-chart-bar {
background-color: #c9521d;
}
.codeburn-light .codeburn-footer-btn {
background: rgba(0, 0, 0, 0.06);
color: #1a1a1a;
}
.codeburn-light .codeburn-footer-btn:hover {
background: rgba(0, 0, 0, 0.1);
}
.codeburn-light .codeburn-currency-picker {
background: rgba(245, 245, 245, 0.98);
}
.codeburn-light .codeburn-currency-item {
color: #1a1a1a;
}
.codeburn-light .codeburn-tab,
.codeburn-light .codeburn-period,
.codeburn-light .codeburn-insight-pill {
color: rgba(0, 0, 0, 0.65);
}
.codeburn-light .codeburn-pulse-tile {
background: rgba(255, 140, 66, 0.1);
}
.codeburn-light .codeburn-updated {
color: rgba(0, 0, 0, 0.4);
}
.codeburn-light .codeburn-divider {
background-color: rgba(0, 0, 0, 0.1);
}