Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
38 changes: 38 additions & 0 deletions .worktrees/dashboard-token-tests/.agents/skills/codexbar/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: codexbar
description: "CodexBar read. Provider usage, limits, credits, config health. JSON. No writes."
---

# CodexBar

Read CodexBar. Never mutate config/auth.

## Run

```bash
skill="${CODEX_HOME:-$HOME/.codex}/skills/codexbar"
"$skill/scripts/codexbar" doctor
"$skill/scripts/codexbar" providers
"$skill/scripts/codexbar" usage
"$skill/scripts/codexbar" usage --provider codex
"$skill/scripts/codexbar" usage --all
```

All stdout: JSON. Upstream CodexBar shape kept. Less drift, fewer tokens.

## Rules

- Start `doctor` when install/config unknown.
- `usage` reads enabled providers. Prefer this.
- `usage --provider ID` reads one provider.
- `usage --all` expensive; use only when needed.
- Identities hidden by default. `--include-identities` only when user explicitly needs them.
- Secrets always hidden.
- Helper read-only: fixed allowlist only. No config writes, auth repair, enable/disable, key storage.
- Timeout means upstream stuck. Narrow provider or raise `CODEXBAR_TIMEOUT` (default 120 seconds).

## Binary

Auto-find: `CODEXBAR_BIN`, PATH, app bundle, Homebrew cask. If missing: open CodexBar, Preferences > Advanced > Install CLI; or set `CODEXBAR_BIN`.

Each stdout/stderr stream capped at 1 MiB while fully drained. Timeout kills process group.
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
#!/usr/bin/env python3
"""Read-only, bounded CodexBar CLI bridge."""

from __future__ import annotations

import argparse
import json
import os
import re
import shutil
import signal
import subprocess
import sys
import threading
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Sequence


MAX_CAPTURE_BYTES = 1024 * 1024
DEFAULT_TIMEOUT = 120.0
BIN_ENV = "CODEXBAR_BIN"
TIMEOUT_ENV = "CODEXBAR_TIMEOUT"
SKIP_DISCOVERY_ENV = "CODEXBAR_SKIP_DISCOVERY"

SECRET = "<redacted:secret>"
IDENTITY = "<redacted:identity>"
EMAIL = "<redacted:email>"

EMAIL_RE = re.compile(r"\b[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}\b", re.I)
BEARER_RE = re.compile(r"(?i)\bbearer\s+[A-Z0-9._~+/=\-]+")
JWT_RE = re.compile(r"\beyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\b")
LABELED_SECRET_RE = re.compile(
r"(?i)\b(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token|"
r"session(?:id)?|secret|password|passwd|cookie|set-cookie)(\s*[:=]\s*)([^\s,;]+)"
)
WORD_SECRET_RE = re.compile(
r"(?i)\b(token|secret|password|passwd|cookie)\s+([A-Z0-9._~+/=\-]{6,})\b"
)
SECRET_KEY_RE = re.compile(
r"(?i)(authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token|"
r"session(?:id)?|secret|password|passwd|cookie)"
)
IDENTITY_KEYS = {
"accountemail",
"accountorganization",
"accountid",
"accountname",
"email",
"organization",
"userid",
"username",
}
# ProviderIdentitySnapshot.providerID is UsageProvider, not an account identifier.


@dataclass(frozen=True)
class Binary:
path: str
source: str


@dataclass(frozen=True)
class Result:
returncode: int
stdout: bytes
stderr: bytes
timed_out: bool


def normalized_key(value: str) -> str:
return re.sub(r"[^a-z0-9]", "", value.lower())


def timeout_seconds() -> float:
try:
return max(1.0, float(os.environ.get(TIMEOUT_ENV, DEFAULT_TIMEOUT)))
except ValueError:
return DEFAULT_TIMEOUT


def safe_path(path: str) -> str:
home = str(Path.home())
if path == home:
return "~"
if path.startswith(home + os.sep):
return "~" + path[len(home) :]
return re.sub(r"^/Users/[^/]+", "/Users/<redacted>", path)


def candidates() -> list[tuple[str, Path]]:
found: list[tuple[str, Path]] = []
override = os.environ.get(BIN_ENV)
if override:
found.append(("env", Path(override).expanduser()))

path_hit = shutil.which("codexbar")
if path_hit:
found.append(("path", Path(path_hit)))

if os.environ.get(SKIP_DISCOVERY_ENV) == "1":
return found

home = Path.home()
found.extend(
[
("homebrew", Path("/opt/homebrew/bin/codexbar")),
("homebrew", Path("/usr/local/bin/codexbar")),
("app", Path("/Applications/CodexBar.app/Contents/Helpers/CodexBarCLI")),
("app", home / "Applications/CodexBar.app/Contents/Helpers/CodexBarCLI"),
]
)
for root in (Path("/opt/homebrew/Caskroom/codexbar"), Path("/usr/local/Caskroom/codexbar")):
found.extend(("cask", app / "Contents/Helpers/CodexBarCLI") for app in sorted(root.glob("*/CodexBar.app")))
return found


def resolve_binary() -> Binary | None:
self_path = Path(__file__).resolve()
seen: set[Path] = set()
for source, candidate in candidates():
try:
resolved = candidate.resolve()
if resolved in seen or resolved == self_path:
continue
seen.add(resolved)
if resolved.is_file() and os.access(resolved, os.X_OK):
return Binary(str(resolved), source)
except OSError:
continue
return None


def drain(pipe: Any, target: bytearray) -> None:
try:
while True:
chunk = pipe.read(65536)
if not chunk:
break
room = MAX_CAPTURE_BYTES - len(target)
if room > 0:
target.extend(chunk[:room])
finally:
pipe.close()


def stop_group(process: subprocess.Popen[bytes], sig: signal.Signals) -> None:
try:
os.killpg(process.pid, sig)
except ProcessLookupError:
pass


def run_process(argv: Sequence[str]) -> Result:
process = subprocess.Popen(
list(argv),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
start_new_session=True,
)
assert process.stdout is not None
assert process.stderr is not None
stdout = bytearray()
stderr = bytearray()
readers = [
threading.Thread(target=drain, args=(process.stdout, stdout), daemon=True),
threading.Thread(target=drain, args=(process.stderr, stderr), daemon=True),
]
for reader in readers:
reader.start()

timed_out = False
try:
process.wait(timeout=timeout_seconds())
except subprocess.TimeoutExpired:
timed_out = True
stop_group(process, signal.SIGTERM)
try:
process.wait(timeout=2)
except subprocess.TimeoutExpired:
stop_group(process, signal.SIGKILL)
process.wait()

for reader in readers:
reader.join(timeout=3)
return Result(124 if timed_out else process.returncode, bytes(stdout), bytes(stderr), timed_out)


def decode(value: bytes) -> str:
return value.decode("utf-8", errors="replace")


def sanitize_text(value: str, include_identities: bool) -> str:
value = JWT_RE.sub(SECRET, value)
value = BEARER_RE.sub("Bearer " + SECRET, value)
value = LABELED_SECRET_RE.sub(lambda match: match.group(1) + match.group(2) + SECRET, value)
value = WORD_SECRET_RE.sub(lambda match: match.group(1) + " " + SECRET, value)
if not include_identities:
value = EMAIL_RE.sub(EMAIL, value)
return value


def sanitize(value: Any, include_identities: bool, key: str | None = None) -> Any:
if key and SECRET_KEY_RE.search(key):
return SECRET
if key and normalized_key(key) in IDENTITY_KEYS and not include_identities and value is not None:
return EMAIL if "email" in normalized_key(key) else IDENTITY
if isinstance(value, dict):
return {str(child_key): sanitize(child, include_identities, str(child_key)) for child_key, child in value.items()}
if isinstance(value, list):
return [sanitize(child, include_identities) for child in value]
if isinstance(value, str):
return sanitize_text(value, include_identities)
return value


def print_json(value: Any) -> None:
print(json.dumps(value, indent=2, sort_keys=True))


def print_error(kind: str, message: str, *, binary: Binary | None = None) -> None:
payload: dict[str, Any] = {"error": {"kind": kind, "message": sanitize_text(message, False)}}
if binary:
payload["binary"] = {"path": safe_path(binary.path), "source": binary.source}
print_json(payload)


def emit_stderr(result: Result, include_identities: bool) -> None:
text = sanitize_text(decode(result.stderr), include_identities).strip()
if text:
print(text, file=sys.stderr)


def read_json(binary: Binary, argv: Sequence[str], include_identities: bool) -> int:
result = run_process([binary.path, *argv])
emit_stderr(result, include_identities)
if result.timed_out:
print_error("timeout", f"CodexBar exceeded {timeout_seconds():g}s and was stopped.", binary=binary)
return 124
try:
payload = json.loads(decode(result.stdout))
except json.JSONDecodeError as error:
preview = sanitize_text(decode(result.stdout[:400]), False)
print_error("invalid_json", f"CodexBar JSON failed: {error.msg}. stdout={preview!r}", binary=binary)
return result.returncode or 1
print_json(sanitize(payload, include_identities))
return result.returncode


def doctor(binary: Binary, include_identities: bool) -> int:
version = run_process([binary.path, "--version"])
if version.timed_out:
print_error("timeout", f"CodexBar version exceeded {timeout_seconds():g}s.", binary=binary)
return 124
validation = run_process([binary.path, "config", "validate", "--format", "json", "--json-only"])
emit_stderr(version, include_identities)
emit_stderr(validation, include_identities)
if validation.timed_out:
print_error("timeout", f"CodexBar config validation exceeded {timeout_seconds():g}s.", binary=binary)
return 124
try:
issues = json.loads(decode(validation.stdout))
except json.JSONDecodeError as error:
print_error("invalid_json", f"CodexBar config validation failed: {error.msg}.", binary=binary)
return validation.returncode or 1
print_json(
{
"binary": {"path": safe_path(binary.path), "source": binary.source},
"configIssues": sanitize(issues, include_identities),
"version": sanitize_text((decode(version.stdout) or decode(version.stderr)).strip(), include_identities),
}
)
return version.returncode or validation.returncode


def parser() -> argparse.ArgumentParser:
root = argparse.ArgumentParser(prog="codexbar", description="CodexBar read. JSON out. No writes.")
commands = root.add_subparsers(dest="command", required=True)
for name in ("doctor", "providers"):
command = commands.add_parser(name)
command.add_argument("--include-identities", action="store_true")
usage = commands.add_parser("usage")
scope = usage.add_mutually_exclusive_group()
scope.add_argument("--all", action="store_true")
scope.add_argument("--provider")
usage.add_argument("--include-identities", action="store_true")
return root


def main(argv: Sequence[str] | None = None) -> int:
args = parser().parse_args(argv)
binary = resolve_binary()
if not binary:
print_error("missing", "CodexBar CLI not found. Install CLI in CodexBar Advanced settings or set CODEXBAR_BIN.")
return 1
try:
if args.command == "doctor":
return doctor(binary, args.include_identities)
if args.command == "providers":
return read_json(
binary,
["config", "providers", "--format", "json", "--json-only"],
args.include_identities,
)
usage_args = ["usage", "--format", "json", "--json-only"]
if args.all:
usage_args.extend(["--provider", "all"])
elif args.provider:
usage_args.extend(["--provider", args.provider])
return read_json(binary, usage_args, args.include_identities)
except OSError as error:
print_error("launch", str(error), binary=binary)
return 1


if __name__ == "__main__":
try:
raise SystemExit(main())
except KeyboardInterrupt:
print_error("interrupted", "Interrupted.")
raise SystemExit(130)
Loading
Loading