Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Codexbar.app/
# Release artifacts
*.ipa
*.dSYM*
*.xcarchive/
*.xcresult/
*.zip
*.delta
*.dmg
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

Tiny macOS 14+ menu bar app that keeps **AI coding-provider limits visible** and shows when each window resets. Codex, OpenAI, Claude, Cursor, Gemini, Copilot, Grok, GroqCloud, ElevenLabs, Deepgram, z.ai, MiniMax, Kiro, Zed, Vertex AI, Augment, OpenRouter, LiteLLM, LLM Proxy, Codebuff, Command Code, AWS Bedrock, and many newer coding providers. One status item per provider, or Merge Icons mode with a provider switcher. No Dock icon, minimal UI, dynamic bar icons.

<img src="codexbar.png" alt="CodexBar menu popover with provider tiles, usage bars, and reset countdowns" width="520" />
<img src="docs/codexbar.png" alt="CodexBar menu popover with provider tiles, usage bars, and reset countdowns" width="520" />

## Why

Expand Down
37 changes: 37 additions & 0 deletions Scripts/check_repository_size.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MAX_BYTES=$((2 * 1024 * 1024))
failures=0
tracked_files=0

cd "$ROOT_DIR"

while IFS= read -r -d '' path; do
tracked_files=$((tracked_files + 1))

case "$path" in
*.app | *.app/* | *.dSYM | *.dSYM/* | *.xcarchive/* | *.xcresult/* | *.ipa | *.zip | *.delta | *.dmg | \
*.pkg | *.tar.gz | *.tgz)
printf 'ERROR: generated artifact is tracked: %s\n' "$path" >&2
failures=$((failures + 1))
;;
esac

[[ -f "$path" && ! -L "$path" ]] || continue

size=$(wc -c < "$path")
if ((size > MAX_BYTES)); then
printf 'ERROR: tracked file exceeds %d bytes: %s (%d bytes)\n' "$MAX_BYTES" "$path" "$size" >&2
failures=$((failures + 1))
fi
done < <(git ls-files -z)

if ((failures > 0)); then
printf 'Repository size check failed with %d violation(s).\n' "$failures" >&2
printf 'Publish build/release artifacts outside Git and optimize required source assets.\n' >&2
exit 1
fi

printf 'repository size OK: %d tracked files, maximum %d bytes each\n' "$tracked_files" "$MAX_BYTES"
6 changes: 6 additions & 0 deletions Scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ check_ci_path_gate() {
"${ROOT_DIR}/Scripts/test_ci_path_gate.sh"
}

check_repository_size() {
"${ROOT_DIR}/Scripts/check_repository_size.sh"
"${ROOT_DIR}/Scripts/test_repository_size.sh"
}

check_shell_scripts() {
local count=0
local script
Expand Down Expand Up @@ -83,6 +88,7 @@ run_portable_checks() {
check_sparkle_signing_paths
check_swift_test_sharding
check_ci_path_gate
check_repository_size
check_shell_scripts
check_documentation_links
check_llms_index
Expand Down
59 changes: 59 additions & 0 deletions Scripts/test_repository_size.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/codexbar-repository-size.XXXXXX")
trap 'rm -rf "$TEMP_DIR"' EXIT

mkdir -p "$TEMP_DIR/Scripts"
cp "$ROOT_DIR/Scripts/check_repository_size.sh" "$TEMP_DIR/Scripts/"
git -C "$TEMP_DIR" init --quiet
printf 'small source file\n' > "$TEMP_DIR/source.txt"
git -C "$TEMP_DIR" add source.txt Scripts/check_repository_size.sh

"$TEMP_DIR/Scripts/check_repository_size.sh" >/dev/null

dd if=/dev/zero of="$TEMP_DIR/untracked.bin" bs=1024 count=2049 2>/dev/null
"$TEMP_DIR/Scripts/check_repository_size.sh" >/dev/null

dd if=/dev/zero of="$TEMP_DIR/boundary.bin" bs=1024 count=2048 2>/dev/null
git -C "$TEMP_DIR" add boundary.bin
"$TEMP_DIR/Scripts/check_repository_size.sh" >/dev/null
printf 'x' >> "$TEMP_DIR/boundary.bin"
if "$TEMP_DIR/Scripts/check_repository_size.sh" >"$TEMP_DIR/large.log" 2>&1; then
printf 'ERROR: oversized tracked file was accepted.\n' >&2
exit 1
fi
grep -Fq 'tracked file exceeds 2097152 bytes: boundary.bin (2097153 bytes)' "$TEMP_DIR/large.log"

git -C "$TEMP_DIR" rm --cached --force --quiet boundary.bin
artifacts=(
"CodexBar 2.app/Contents/MacOS/CodexBar"
"CodexBar.dSYM/Contents/Info.plist"
"CodexBar.xcarchive/Products/Applications/CodexBar.app/Contents/Info.plist"
"CodexBar.xcresult/Data/data"
"CodexBar.ipa"
"CodexBar.zip"
"CodexBar.delta"
"CodexBar.dmg"
"CodexBar.pkg"
"CodexBar.tar.gz"
"CodexBar.tgz"
)
for artifact in "${artifacts[@]}"; do
mkdir -p "$TEMP_DIR/$(dirname "$artifact")"
printf 'release artifact\n' > "$TEMP_DIR/$artifact"
git -C "$TEMP_DIR" add -f "$artifact"
done
ln -s source.txt "$TEMP_DIR/CodexBar-latest.dmg"
git -C "$TEMP_DIR" add -f CodexBar-latest.dmg

if "$TEMP_DIR/Scripts/check_repository_size.sh" >"$TEMP_DIR/artifact.log" 2>&1; then
printf 'ERROR: tracked release artifacts were accepted.\n' >&2
exit 1
fi
for artifact in "${artifacts[@]}" CodexBar-latest.dmg; do
grep -Fq "generated artifact is tracked: $artifact" "$TEMP_DIR/artifact.log"
done

printf 'Repository size tests passed.\n'
Binary file removed codexbar.png
Binary file not shown.
68 changes: 68 additions & 0 deletions docs/repository-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
summary: "Repository size findings, prevention checks, and the maintainer-only history cleanup runbook."
read_when:
- Adding large assets or release artifacts
- Investigating clone size
- Planning a Git history rewrite
---

# Repository size

The checked-out source tree is not the main cause of CodexBar's clone size. At commit `61ff9320`, tracked files total
22,292,801 bytes, while the packed Git object database is 103.91 MiB. `CHANGELOG.md` is 150,271 bytes in the current
tree and all of its historical blobs occupy about 0.55 MB compressed.

Most of the packed history comes from files that are no longer present on `main`:

| Historical path group | Approximate compressed bytes |
| --- | ---: |
| `screenshots/` | 39,023,716 |
| `Quotio/` | 23,141,837 |
| `CodexBar 2.app/` | 7,088,125 |
| `CodexBar-0.2.2.zip` | 2,296,323 |

The largest single blob is the retired `Quotio/Resources/Proxy/cli-proxy-api-plus` executable: 49,202,546 bytes
before compression and about 15.8 MB in the pack. Deleting these files in later commits stopped further growth but
did not remove their blobs from existing history.

## Prevention

`Scripts/check_repository_size.sh` runs under `make check`. It rejects:

- tracked files larger than 2 MiB;
- app bundles, dSYMs, Xcode results, IPAs, archives, deltas, disk images, and installer packages.

Publish release artifacts through GitHub Releases. Optimize required source images before committing them. If a
source asset genuinely must exceed the limit, discuss and review the limit change explicitly rather than bypassing
the check.

For a smaller local checkout when full history is unnecessary, use one of:

```bash
git clone --filter=blob:none https://github.com/steipete/CodexBar.git
git clone --depth=1 https://github.com/steipete/CodexBar.git
```

## One-time history cleanup

A normal pull request cannot reduce the size of already reachable Git objects. Maintainers can recover most of the
avoidable clone weight only with a coordinated history rewrite. Candidate paths that are absent from current
`main` are:

```text
screenshots/
Quotio/Resources/Proxy/cli-proxy-api-plus
CodexBar 2.app/
CodexBar_Dev.app/
CodexBar-0.2.2.zip
CodexBar6-2.delta
CodexBar6-4.delta
```

Use `git filter-repo` on a fresh mirror, validate all branches and tags, and force-push only during an announced
maintenance window. This changes commit and tag IDs and requires contributors to re-clone or carefully rebase, so
the rewrite must not be performed from a normal contributor branch.

An isolated mirror rehearsal using exactly the candidate paths above reduced the packed object database from
103.90 MiB to 41.99 MiB (59.6%) and passed `git fsck --full --no-dangling`. Treat this as a reproducible baseline,
not authorization to rewrite the canonical repository.