Skip to content

Commit 0c5c6fa

Browse files
authored
Merge branch 'main' into feat/omp-support-model-aliases
2 parents 79e67f0 + 64aae10 commit 0c5c6fa

75 files changed

Lines changed: 9773 additions & 1295 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Block Claude / Anthropic co-author trailers
2+
3+
# Rejects PRs that contain a `Co-authored-by: ... claude ...` or `... anthropic ...`
4+
# trailer in any of their commits. Contributors can still use AI tools to help
5+
# write code, but they must remove the co-author attribution before the PR is
6+
# eligible to merge, per the project's contributor guidelines.
7+
8+
on:
9+
pull_request:
10+
types: [opened, synchronize, reopened]
11+
12+
jobs:
13+
check:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Scan PR commits for disallowed co-author trailers
22+
run: |
23+
BASE_SHA="${{ github.event.pull_request.base.sha }}"
24+
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
25+
FOUND=0
26+
while IFS= read -r c; do
27+
[ -z "$c" ] && continue
28+
SUBJECT=$(git log -1 "$c" --format=%s)
29+
if git log -1 "$c" --format="%B" | grep -qiE 'co-authored-by:.*(claude|anthropic)'; then
30+
echo "::error::Commit $c ($SUBJECT) has a Claude/Anthropic co-author trailer. Please remove it before this PR can merge."
31+
FOUND=1
32+
fi
33+
done < <(git log --format=%H "$BASE_SHA".."$HEAD_SHA")
34+
if [ "$FOUND" != "0" ]; then
35+
echo ""
36+
echo "How to fix:"
37+
echo " 1. Run: git rebase -i $BASE_SHA"
38+
echo " 2. Mark each flagged commit as 'reword'"
39+
echo " 3. Delete the Co-authored-by line from the commit message"
40+
echo " 4. Save, then: git push --force-with-lease"
41+
exit 1
42+
fi
43+
echo "No disallowed co-author trailers found."

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
semgrep:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Install Semgrep
15+
run: pip install semgrep
16+
17+
- name: Run Semgrep bracket-assign guard
18+
run: |
19+
set -e
20+
semgrep --config .semgrep/rules/no-bracket-assign-hot-paths.yml \
21+
--strict --json \
22+
src/providers/ src/parser.ts > semgrep-out.json
23+
FINDINGS=$(jq '.results | length' semgrep-out.json)
24+
if [ "$FINDINGS" -gt 0 ]; then
25+
jq -r '.results[] | "::error file=\(.path),line=\(.start.line)::\(.extra.message)"' semgrep-out.json
26+
exit 1
27+
fi
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Release macOS Menubar
2+
3+
# Triggers on a `mac-v*` tag push (e.g. `git tag mac-v0.8.0 && git push origin mac-v0.8.0`),
4+
# or manually via the Actions tab. Builds a universal arm64+x86_64 bundle, ad-hoc signs it,
5+
# zips via `ditto`, and uploads the zip to the GitHub Release. `npx codeburn menubar` clears
6+
# the download quarantine flag on install so Gatekeeper stays quiet.
7+
on:
8+
push:
9+
tags:
10+
- 'mac-v*'
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: 'Version label for the bundle (e.g. v0.8.0 or dev-preview)'
15+
required: true
16+
default: 'dev-preview'
17+
18+
permissions:
19+
contents: write # Needed to create the release + upload assets.
20+
21+
jobs:
22+
build:
23+
runs-on: macos-latest
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v4
27+
28+
- name: Resolve version label
29+
id: version
30+
run: |
31+
if [[ "${GITHUB_REF}" == refs/tags/mac-v* ]]; then
32+
echo "value=${GITHUB_REF#refs/tags/mac-}" >> "$GITHUB_OUTPUT"
33+
else
34+
echo "value=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT"
35+
fi
36+
37+
- name: Show Swift toolchain
38+
run: swift --version
39+
40+
- name: Build + bundle + zip
41+
run: mac/Scripts/package-app.sh "${{ steps.version.outputs.value }}"
42+
43+
- name: Upload artifact (for manual runs)
44+
if: github.event_name == 'workflow_dispatch'
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: CodeBurnMenubar-${{ steps.version.outputs.value }}
48+
path: mac/.build/dist/CodeBurnMenubar-*.zip
49+
if-no-files-found: error
50+
51+
- name: Create / update GitHub Release
52+
if: startsWith(github.ref, 'refs/tags/mac-v')
53+
uses: softprops/action-gh-release@v2
54+
with:
55+
tag_name: ${{ github.ref_name }}
56+
name: Menubar ${{ steps.version.outputs.value }}
57+
body: |
58+
Install with:
59+
60+
```
61+
npx codeburn menubar
62+
```
63+
64+
That command drops the app into `~/Applications`, clears the download
65+
quarantine, and launches it. If you download the zip from this page directly
66+
and macOS shows "cannot verify developer", right-click the app in Finder and
67+
pick Open to whitelist it once.
68+
files: mac/.build/dist/CodeBurnMenubar-*.zip
69+
fail_on_unmatched_files: true

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Thumbs.db
1515

1616
# Planning artifacts (internal, not shipped)
1717
docs/superpowers/
18+
.claude/
1819

1920
# Config / secrets
2021
.env
@@ -32,3 +33,6 @@ npm-debug.log*
3233

3334
# Build artifacts
3435
*.tsbuildinfo
36+
37+
# Local Discord brand / promo assets not yet ready to publish
38+
assets/discord-*.png
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
rules:
2+
- id: no-bracket-assign-on-literal-object-map
3+
languages: [typescript]
4+
severity: ERROR
5+
message: >
6+
Bracket-assign on a map created with `{}` allows prototype pollution when
7+
the key comes from external data. Initialize the map with
8+
`Object.create(null)` instead.
9+
patterns:
10+
- pattern-either:
11+
- pattern: $MAP[$KEY] = $MAP[$KEY] ?? $INIT
12+
- pattern: $MAP[$KEY] = $MAP[$KEY] || $INIT
13+
- pattern: $MAP[$KEY] ??= $INIT
14+
- pattern: |
15+
if (!$MAP[$KEY]) $MAP[$KEY] = $INIT
16+
- pattern-not-inside: |
17+
const $MAP = Object.create(null)
18+
...
19+
paths:
20+
include:
21+
- '/src/providers/*.ts'
22+
- '/src/parser.ts'

CHANGELOG.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,117 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Added
6+
- **`codeburn report --from/--to`.** Filter sessions to an exact `YYYY-MM-DD` date range (local time). Either flag alone is valid: `--from` alone runs from the given date through end-of-today, `--to` alone runs from the earliest data through the given date. Inverted ranges or malformed dates exit with a clear error. In the TUI, pressing `1`-`5` still switches to the predefined periods. Credit: @lfl1337 (PR #80).
7+
- **`avgCostPerSession` in reports.** JSON `projects[]` entries gain an `avgCostPerSession` field and `export -f csv` adds an `Avg/Session (USD)` column to `projects.csv`. Column order in `projects.csv` is now `Project, Cost, Avg/Session, Share, API Calls, Sessions` -- scripts parsing by column position should read by header instead. Credit: @lfl1337 (PR #80).
8+
9+
### Security
10+
- **Semgrep CI guard against prototype pollution regressions.** New `.github/workflows/ci.yml` runs a bracket-assign guard on `src/providers/` and `src/parser.ts` on every push to main and every PR. Blocks re-introducing `$MAP[$KEY] = $MAP[$KEY] ?? $INIT` patterns on `{}`-initialized maps. `categoryBreakdown` in `parser.ts` switched to `Object.create(null)` for consistency with its sibling breakdown maps. Credit: @lfl1337 (PR #78).
11+
12+
## 0.7.3 - 2026-04-18
13+
14+
### Changed
15+
- **Dropped `better-sqlite3` in favor of Node's built-in `node:sqlite`.** Removes the deprecated `prebuild-install` transitive dependency that npm warned about on every install (issue #75, credit @primeminister). End-user install is now 40 packages down from 167 and shows zero deprecation notices. The experimental-SQLite warning Node 22/23 normally prints on module load is silenced for this specific warning; other warnings pass through unchanged.
16+
- **Minimum Node version raised to 22.** Node 20 reached EOL on 2026-04-30; `node:sqlite` lives in 22+. Users on older Node get a clear upgrade message when a SQLite-backed provider (Cursor, OpenCode) is loaded.
17+
18+
19+
## 0.7.2 - 2026-04-17
20+
21+
### Added
22+
- **Native macOS menubar app.** Swift + SwiftUI app under `mac/` replaces the SwiftBar plugin. Agent tabs, Today/7/30/Month/All period switcher, Trend/Forecast/Pulse/Stats/Plan insights, activity and model breakdowns, optimize findings, CSV/JSON export, instant currency switching, live 60s refresh.
23+
- **`codeburn menubar`.** One-command install: downloads the latest `.app` from GitHub Releases, strips Gatekeeper quarantine, drops it into `~/Applications`, and launches it. `--force` reinstalls in place.
24+
- **`status --format menubar-json`.** Structured payload consumed by the native menubar app. Current-period totals, per-activity and per-model breakdowns, provider costs, optimize findings, and 365-day history.
25+
- **Release workflow.** `.github/workflows/release-menubar.yml` builds a universal `.app` bundle and zip on `mac-v*` tag push.
26+
27+
### Changed
28+
- **`codeburn export -f csv`** now writes a folder of one-table-per-file CSVs (`summary`, `daily`, `activity`, `models`, `projects`, `sessions`, `tools`, `shell-commands`) plus a `README.txt` index. Each file opens cleanly as a single table in any spreadsheet.
29+
- **`codeburn export -f json`** upgraded to schema `codeburn.export.v2` with currency metadata.
30+
31+
### Fixed
32+
- **`codeburn status` terminal Today/Month** now buckets by local date instead of UTC, so spend shows correctly during the window between local midnight and UTC midnight.
33+
- **FX rate validation.** Frankfurter responses are checked to be finite and within `[0.0001, 1_000_000]` before they affect displayed costs.
34+
35+
### Removed
36+
- **SwiftBar plugin.** `src/menubar.ts`, `codeburn install-menubar`, `codeburn uninstall-menubar`, and `status --format menubar` are gone. The native Swift app is the single menubar surface.
37+
38+
### Security
39+
- **`codeburn export -o` guard.** Writes a `.codeburn-export` marker into every folder it creates and refuses to reuse non-marked directories or overwrite existing files, so a typo like `-o ~/.ssh/id_ed25519` cannot delete a sensitive file.
40+
41+
## 0.7.1 - 2026-04-17
42+
43+
### Security
44+
- **External security audit closed.** 1 HIGH, 2 MEDIUM, and 1 LOW finding fixed. Threat model: a compromised third-party AI CLI with write access to `~/.claude/projects/` dropping malicious session JSONL.
45+
- **Prototype pollution blocked.** Breakdown maps in `parser.ts` (model, tool, MCP, bash) now use `Object.create(null)` so attacker-controlled keys like `__proto__` create own properties instead of mutating `Object.prototype`. Credit: @lfl1337 (PR #67).
46+
- **Bounded session-file reads.** New `src/fs-utils.ts` helper caps reads at 128 MB and switches to stream-based parsing above 8 MB. Applied to 13 reachable read sites across parser, Codex, Copilot, Pi, context-budget, and optimize. Credit: @lfl1337 (PR #67).
47+
- **Menubar label sanitizer.** SwiftBar directive-separator (`|`) and ANSI escape injection via crafted model or category names is now prevented by an allowlist (`[A-Za-z0-9 ._/-]`) plus 14-character truncation. Credit: @lfl1337 (PR #67).
48+
49+
### Added
50+
- **`--verbose` flag.** Global CLI option that prints warnings to stderr on skipped (oversize) or failed session-file reads. Silent by default. Credit: @lfl1337 (PR #67).
51+
- **11 new security tests.** `tests/security/prototype-pollution.test.ts`, `tests/security/menubar-injection.test.ts`, `tests/fs-utils.test.ts`. Total suite: 209 tests.
52+
53+
## 0.7.0 - 2026-04-16
54+
55+
### Added
56+
- **`codeburn optimize` command.** Scans your sessions and your `~/.claude/`
57+
setup for 11 common waste patterns and hands back exact copy-paste fixes.
58+
Detection-only, never writes to user files. Supports `--period` (today,
59+
week, 30days, month, all) and `--provider` (all, claude, codex, cursor).
60+
- **Setup health grade (A-F).** Urgency-weighted rollup of all findings, with
61+
impact scored against observed waste so the most expensive issues rank
62+
first. High findings penalise more, medium less, low least.
63+
- **Trend tracking.** Repeat runs classify each finding as new, improving,
64+
or resolved against a 48-hour recent window, so fixed issues disappear
65+
instead of lingering as noise.
66+
- **11 detectors:** files Claude re-reads across sessions, low Read:Edit
67+
ratio, projects missing `.claudeignore`, uncapped `BASH_MAX_OUTPUT_LENGTH`,
68+
unused MCP servers, ghost agents, ghost skills, ghost slash commands,
69+
bloated `CLAUDE.md` files (with `@-import` expansion counted), cache
70+
creation overhead, and junk directory reads.
71+
- **Copy-paste fixes.** Each finding comes with a ready-to-paste remedy: a
72+
`CLAUDE.md` line, a `.claudeignore` template, an environment variable, or
73+
a `mv` command to archive unused items.
74+
- **In-TUI optimize view.** Press `o` in the dashboard when the status bar
75+
shows a finding count, `b` to return. Same engine as the standalone
76+
command, scoped to the current period and provider.
77+
- **Per-project context budget column.** By Project panel now shows the
78+
estimated per-session context overhead for each project (system prompt +
79+
tools + `CLAUDE.md` + skills).
80+
- **34 filesystem-mocking tests.** Tmpdir fixtures with `os.homedir` mocked
81+
via `vi.mock` cover the detector surface end to end. Total suite: 198
82+
tests across 13 files.
83+
84+
### Performance
85+
- **mtime pre-filter + parallel reads + 60s result cache** cut a cold scan
86+
from 12-17s to 6-7s on a 10k-session history.
87+
88+
## 0.6.1 - 2026-04-16
89+
90+
### Added
91+
- **JSON output on `report`, `today`, `month`.** `--format json` writes the
92+
full dashboard (overview, daily, projects, models, activities, tools, MCP
93+
servers, shell commands, top sessions) to stdout. Contributed by @mallek.
94+
- **Project filters.** `--project <name>` and `--exclude <name>` on all
95+
commands (`report`, `today`, `month`, `status`, `export`). Case-insensitive
96+
substring match against project name and path. Both flags are repeatable.
97+
Contributed by @mallek.
98+
- **claude-opus-4-7 model mapping and pricing.** Displays as `Opus 4.7` with
99+
the same Opus pricing as 4.6 and a 6x fast multiplier. Contributed by @mallek.
100+
- **Unit tests for `filterProjectsByName`** covering include/exclude
101+
semantics, case-insensitivity, path matching, and input immutability.
102+
103+
### Fixed
104+
- **Top Sessions panel truncating the calls column.** Row width filled the
105+
full panel width without leaving room for the border and padding, so Ink
106+
truncated the last 4 characters -- landing exactly on the calls column and
107+
producing rows like `$182.58 ...` with no value.
108+
- **SwiftBar custom plugin directory** now honoured when installing the
109+
menubar widget. Reads the configured path from SwiftBar's defaults before
110+
falling back to the standard location. Contributed by @Galeas.
111+
- **`status --format menubar` per-provider today totals** now respect
112+
`--project`/`--exclude`. The main period blocks already did, the provider
113+
breakdown loop was the one spot that bypassed the filter.
114+
3115
## 0.6.0 - 2026-04-16
4116

5117
### Added

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,10 @@ gh pr comment <number> --body "Merged, thanks!"
7575
- NEVER include personal names or usernames in commits
7676
- Small, focused commits. One feature per commit
7777
- Test locally before every commit
78+
79+
### Public-facing language (commits, PRs, release notes, README)
80+
- Commits and release notes are public. Write like you'd publish them.
81+
- NEVER use words like "steal", "stealing", "copy", "rip off", "inspired by" in commit messages
82+
- Describe what the code does, not where ideas came from
83+
- If you must credit prior art, do it in code comments or docs, not commit messages
84+
- No snark, no filler, no self-deprecation. Treat each commit as a product statement

0 commit comments

Comments
 (0)