Commit graph

10 commits

Author SHA1 Message Date
Resham Joshi
43608c2558
desktop and menu bar: six-language localization (#1493)
The desktop app and the macOS menu bar can now run in English, French, Japanese, Korean, Simplified Chinese and Traditional Chinese. A Language setting in the desktop Settings picks the language or follows the system, and the choice is shared so the menu bar switches with it, relaunching to pick up the language with a retry so a switch never leaves it down.

Every user-facing string in the desktop renderer goes through a local lookup table, 1,249 keys per language, no framework and no network. The menu bar gains four .lproj to join English and Simplified Chinese, 626 keys each. A completeness gate fails the build if any language is missing a key, in both the desktop catalogs and the menu bar coverage suite. Fonts fall back per language so Japanese, Korean and both Chinese render their correct glyph forms, and dates and numbers format for the locale with values unchanged. English output is byte-identical.

Strings produced by the CLI engine stay English until the CLI is localized, a separate effort. Validated live in all six languages: no missing text, no clipping, correct fonts, numbers unchanged, and the menu bar switching for every language.
2026-09-19 03:25:46 -07:00
ozymandiashh
9eebfda627 feat(menubar): add Simplified Chinese (zh-Hans) localization
All 533 catalog keys translated into zh-Hans, so the menubar app now follows
the system language with no setting to find and no third-party library. AppKit
picks the table: `CFBundleLocalizations` in both packaging scripts advertises
`en` and `zh-Hans`, which is also what puts the app under System Settings >
Language & Region so a user can override the language for CodeBurn alone.

Wording follows macOS system apps rather than a literal gloss: 立即刷新,
断开连接, 存储并连接, 载入配额, 再试一次. Product nouns stay as users
already know them: provider, model and plan names (Claude, Codex, Gemini,
Opus, Sonnet, Antigravity), Token, Dock, API, OAuth, shell commands and file
paths, currency codes.

Format specifiers are identical to the English entry in count and argument
order. `%%` is a literal percent sign and not an argument, so it may move where
Chinese word order demands it ("%@ · %@ 达到 100%%"); the argument-consuming
specifiers may not, because String(format:) binds them positionally. The next
commit's test enforces exactly that distinction.

Numbers, dates and currency are untouched: they already went through
NumberFormatter / DateFormatter / asCurrency(), and `L(_:_:)` only substitutes
values those produced.
2026-09-12 15:21:49 -07:00
ozymandiashh
d62857ea4e feat(menubar): route every user-facing string through a strings catalog
Groundwork for #1219. The menubar app hardcoded ~530 English strings across
Views/, the presentation structs, the status-item menu and the update alerts,
so there was nothing for a translator to translate.

Every user-facing literal now goes through `L(_:)` / `L(_:_:)`, which look the
string up in `Localizable.strings` in the SwiftPM target resource bundle. The
key *is* the English copy, so English stays the development language and a
missing translation degrades to correct English instead of a dotted
identifier. `en.lproj` is therefore an identity table; it exists so the bundle
advertises `en` and so a translation can be diffed against it.

Why the lookups are explicit rather than relying on SwiftUI's implicit
`LocalizedStringKey`: SwiftPM emits target resources into a sibling bundle
(`CodeBurnMenubar_CodeBurnMenubar.bundle`) that the packaging scripts copy into
`Contents/Resources`. `Bundle.main` has no `.lproj` at all, so `Text("literal")`
would always miss. Naming `Bundle.module` is the one form that resolves the
same way in `swift run`, in `swift test` and in the packaged `.app`.

Enum raw values that double as identity (`Period`, `MenubarScope`,
`InsightMode`, `AccentPreset`, `ProviderFilter`) keep their raw value and gain
a `displayLabel`, so persistence and cache keys are untouched by translation.

Three display-only date formatters that were pinned to `en_US_POSIX` with fixed
patterns now use `setLocalizedDateFormatFromTemplate`, and the calendar
popover's weekday row comes from the locale's own symbols. The `yyyy-MM-dd`
formatter stays POSIX: it parses and builds data keys, not display text.

Not extracted, deliberately: provider, model and plan names; units; currency
codes; shell commands and paths; quota window labels that policy code matches
on by English substring (`QuotaSummary.headlineWindow`); and anything the
`codeburn` CLI produces.

Also copies the SwiftPM resource bundle into the app in build-local.sh, using
the named-bundle + `[[ -d ]]` pattern package-app.sh already uses. Without it
the assembled app finds no strings table (and already trapped on first icon
load, the resource-bundle half of #1262).
2026-09-12 15:21:49 -07:00
Aditya Vikram Singh
bce49926c3 feat: add native Cursor quota connection 2026-08-29 23:48:42 +05:30
iamtoruk
71771a41a4 feat(menubar): System Settings-style sidebar Settings with provider logo rows
Replaces the tab strip with a NavigationSplitView shell: search field,
General/About tile rows, and a data-driven Providers section whose real
logo marks render gray at rest and accent-tinted on hover, with green
connected dots and an N-on counter. Bundles template icon assets.
2026-08-24 08:51:07 -07:00
AgentSeal
d349a01e99 harden(mac): fail-closed minos guard, weak-link errno check, strip em-dashes
Review follow-up on the Sonoma deployment-target fix:
- The release minos guard was fail-open: if vtool returned nothing (missing
  binary, tool change) the check passed vacuously and could green-light a bad
  release. Now it fails closed when no minos is reported.
- The libswift_errno check now excludes weak links, so it only fails on a
  breaking STRONG link. dyld tolerates a missing weakly-linked dylib, so a
  macOS 15.x SDK runner that weak-links errno at the .v14 target no longer
  causes a spurious release failure.
- Removed em-dashes from the changed files per repo style.

Verified: fresh .v14 build is minos 14.0 with no strong errno link; the guard
now fails closed on an unreadable binary and passes on the real one; 71 Swift
tests pass.
2026-07-10 09:20:15 +02:00
wanghao20
a91c1c9f2a fix(mac): target macOS 14 so the menubar app runs on Sonoma
The packaged app set Package.swift to .macOS(.v15), producing a binary with
minos 15.0 that LaunchServices refuses on macOS 14.x with
kLSIncompatibleSystemVersionErr (-10825) — even though Info.plist, the CLI
install guard (MIN_MACOS_MAJOR=14), and the README all advertise macOS 14+.
The .v15 bump was attributed to NSAttributedString(attachment:), which is
actually AppKit since macOS 10.0, so the floor must not exclude Sonoma.

Separately, a stock macOS-15-SDK CI build hard-links libswift_errno.dylib
(macOS 15 only), which dyld cannot resolve on Sonoma even once minos passes.
Building against the macOS 14 SDK avoids that dependency.

- Package.swift: .macOS(.v15) -> .macOS(.v14)
- Scripts/build-local.sh: build on a Sonoma machine (which only has the
  macOS 14 SDK, lacking the SwiftUI @MainActor inference the macOS 15 SDK
  adds to the View protocol) using a standalone swift.org Swift 6.x toolchain,
  patching @MainActor onto views in a scratch copy so repo sources stay clean.
- README: document the Sonoma local-build path.
2026-07-10 09:19:18 +02:00
iamtoruk
ac35746209 fix(menubar): recover from stuck loading state
Commit 5800179 (multi-day calendar) accidentally removed stuck-loading
recovery. Re-add an 8-second watchdog loop in MenuBarContent that calls
recoverFromStuckLoading(). Change inFlightKeys from Set to timestamped
Dict so the watchdog can detect orphaned quiet-refresh entries. Stop
nuking payloadRefreshGeneration in the watchdog (it was killing healthy
in-flight fetches). Bump Package.swift platform to macOS 15 to match
NSAttributedString(attachment:) usage.
2026-05-27 04:06:48 -07:00
Resham Joshi
3482478a49 fix(mac): drop empty Resources/ reference from Package.swift
Caught in a fresh-clone smoke test: SwiftPM refused to build because
.process("../../Resources") pointed at an empty directory that git
does not track. The bundle has no assets to ship yet (icon will land
with signing work), so the reference is gone. Build passes on a clean
checkout and the packaging script produces the universal .app zip as
expected.
2026-04-17 17:01:00 -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