Commit graph

7 commits

Author SHA1 Message Date
AgentSeal
6a08a8f31c fix(menubar): cut idle energy by gating spawns on popover, power, and display state
Every 30s tick spawned 2-3 concurrent Node CLI processes at 100%+ CPU,
and an app-lifetime activity assertion disabled App Nap forever, putting
the menubar's energy use in the video-call class (#647).

- Closed popover now fetches only what the status item renders (menubar
  period plus today); the popover's selected key refreshes on open via
  the existing recovery path, which now also catches up the status
  figure and clears a latched display-sleep flag.
- Spawn cadence stretches to 150s on battery and 300s in Low Power Mode
  while the popover is closed; the 30s timer itself keeps running.
- The app-lifetime beginActivity is gone; each in-flight refresh
  (including manual Refresh Now) holds its own scoped activity, and an
  NSBackgroundActivityScheduler backstop tick every ~3min bounds status
  staleness once App Nap starts coalescing the timer.
- Display sleep skips ticks entirely; wake and popover open clear it.
- The status-payload fallback honors the same spawn interval so the 30s
  cache TTL cannot defeat the backoff.

Child process QoS stays .userInitiated on purpose: lowering it is
documented to slow parses 5-10x and starve the cadence; the win here is
spawn frequency, not priority. Measured on an idle machine: two
concurrent 100%+ CPU spawns per 30s window before, one spawn in 72s
after, with App Nap coalescing the rest.

Fixes #647
2026-07-09 22:47:30 +02:00
iamtoruk
c350dd2a55 feat(menubar): refresh via headless app binary instead of node script
Run CodeBurn's own signed binary in --refresh-once mode under the LaunchAgent
so the spawned CLI inherits CodeBurn's TCC grant. The bare-node shell script
prompted "node would like to access data from other apps" because launchd-
spawned children lose the signed app's TCC attribution. Drops the generated
shell script, scriptEnvironment, and per-period regeneration; the plist is now
static and period is read from UserDefaults at refresh time.
2026-05-30 13:05:48 -07:00
iamtoruk
be7b8278c5 feat(menubar): add CodeburnCLI.scriptEnvironment for shell-script embedding
Exposes the validated argv and augmented PATH so the LaunchAgent runner
script can be generated without re-resolving the binary or PATH.
2026-05-30 00:10:29 -07:00
iamtoruk
e3a0593ed8 Fix menubar PATH discovery for nvm/volta/asdf/npm-global installs
GUI-launched apps inherit a minimal PATH that misses user-managed Node
directories. Scan ~/.volta/bin, ~/.npm-global/bin, ~/.asdf/shims, and
the newest nvm Node version at launch. All candidates pass isSafe()
validation. Closes #331.
2026-05-16 08:54:45 -07:00
iamtoruk
909efcf989 Harden menubar refresh and installer 2026-05-14 18:32:15 -07:00
iamtoruk
556f2bf78c fix(menubar): force status bar redraw and lift subprocess QoS
Two independent causes for the stuck-label / only-refreshes-on-click
behaviour, both fixed here.

1. NSStatusItem button defers the status bar paint for accessory apps
   that are not foreground, so after refreshStatusButton sets the new
   attributed title the menu bar visually froze until the user opened
   the popover (which triggers NSApp.activate and a forced redraw
   cycle). Explicit needsDisplay + display() forces the paint every
   cycle.

2. The codeburn subprocess inherited the accessory app's default QoS,
   which macOS background-throttles. That could stretch a sub-1-second
   parse into tens of seconds on large corpora and overrun the 15s
   refresh cadence. Set .userInitiated so the CLI runs at the same
   priority it does from a user-interactive terminal.
2026-04-21 11:50:28 -07:00
Resham Joshi
495a254338 feat(mac): native Swift menubar app + one-command install
Introduces mac/ with a native SwiftUI menubar app that replaces the
previous SwiftBar plugin entirely. Install via `npx codeburn menubar`,
which downloads the .app from GitHub Releases, strips Gatekeeper
quarantine, and drops it into ~/Applications.

Highlights

- mac/ SwiftUI app: agent tabs, Today/7/30/Month/All period switcher,
  Trend/Forecast/Pulse/Stats/Plan insights, activity + model
  breakdowns, optimize findings, CSV/JSON export, Star-on-GitHub
  banner, live 60s refresh, instant currency switching with offline FX
  cache.
- Security: CodeburnCLI argv-based spawn (no shell interpretation),
  SafeFile symlink guards + O_NOFOLLOW writes, FX rate clamping to
  [0.0001, 1_000_000], keychain filtered to account == "default",
  removed byte-window credential log, in-flight refresh guard, POSIX
  flock on config.json writes, TerminalLauncher validates argv before
  AppleScript interpolation.
- Performance: shared static NumberFormatter (thousands of allocations
  per popover redraw eliminated), concurrent pipe drain with 20 MB cap
  + 60s timeout in DataClient, Observation-tracked reactive UI, 5-min
  payload cache keyed on (period, provider).
- CLI: new `codeburn menubar` subcommand that downloads + installs +
  launches the .app (no clone, no build). New `status --format
  menubar-json` payload builder. `export` rewritten to produce a
  folder of one-table-per-file CSVs with a `.codeburn-export` marker
  so arbitrary -o paths cannot be silently deleted.
- Removed: src/menubar.ts (SwiftBar plugin generator),
  install-menubar / uninstall-menubar subcommands, `status --format
  menubar` directive output, tests/menubar.test.ts,
  tests/security/menubar-injection.test.ts.
- Release: .github/workflows/release-menubar.yml builds universal
  binary, assembles .app, ad-hoc signs, zips, uploads on mac-v* tag
  push. Runs on the free macos-latest runner.

Tests

- 230 TypeScript tests pass
- 10 Swift CapacityEstimator tests pass
- TypeScript typecheck clean
- Swift release build clean
2026-04-17 16:55:56 -07:00