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
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
Copy-Item -LiteralPath 'scripts\install.ps1','scripts\uninstall.ps1','scripts\install-environment.ps1' -Destination 'package\scripts'
Copy-Item -LiteralPath 'README.md','PRIVACY.md','SECURITY.md','LICENSE' -Destination 'package'
Compress-Archive -Path 'package\*' -DestinationPath "CodexWeeklyUsageIndicator-$env:GITHUB_REF_NAME-win-x64.zip"
- name: Publish release
- name: Create draft release for artifact verification
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -40,4 +40,5 @@ jobs:
'dist\WeeklyUsageIndicator.exe' `
'dist\SHA256SUMS.txt' `
--title "Codex + Claude Usage Indicator $env:GITHUB_REF_NAME" `
--draft `
--generate-notes
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This repository contains a small Windows-only WinForms utility. Keep changes foc
- Do not invoke Claude more often than every ten minutes, including explicit UI refreshes, and back off transient command failures.
- Persist at most one credential-free Claude recovery snapshot containing only percentages, reset times, and update time. Use it only for transient cold-start failures, delete it after 24 hours, its Fable reset, or an authentication/schema failure, and never let it suppress the first live request in a new process.
- Stop the app-server child process when the widget pauses or exits.
- Preserve the single-instance mutex and the always-on-top tool-window behavior.
- Preserve the single-instance mutex and the always-on-top tool-window behavior without taking keyboard focus or changing the foreground window. Widget show, hide/re-show, and timer maintenance must leave another window's focused input unchanged; do not restore topmost behavior through an activating WinForms `TopMost` assignment.
- The installer must launch the `--supervise` mode through the per-user interactive, least-privilege scheduled task, never directly from Codex. The supervisor retries nonzero widget exits/start failures only; normal Quit must end supervision. Do not substitute Task Scheduler RestartOnFailure for this loop: it did not retry an exited action in live tests. Disable/stop the task before upgrade or uninstall; filter processes by the current user's exact installed EXE path.
- Check the install directory's final handle path before stopping tasks or processes: packaged shells can redirect AppData even without reporting a package identity. Package `install-environment.ps1` with both lifecycle scripts.

Expand All @@ -45,3 +45,4 @@ Then check that:
8. The context menu works, the widget hides, and its app-server child exits when Codex closes.
9. `install.ps1` and `uninstall.ps1` only modify the current user's dedicated install directory, legacy Startup shortcut, and SID-named scheduled task.
10. The task owns the supervisor and its widget child independently of Codex. Forced termination of the widget child recovers after about one minute; normal Quit ends both processes and does not recover. Reinstall leaves one supervisor and one widget; uninstall removes the task before stopping the app.
11. `AccountUiSmoke` verifies native keyboard focus and foreground-window preservation during widget show, hide/re-show, and repeated maintenance, while checking that the widget remains topmost. Preserve this regression coverage when changing window presentation.
8 changes: 5 additions & 3 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ Codex + Claude Usage Indicator reads Codex rate-limit windows from the locally i

The application:

- does not store usage history;
- does not store a timeline of usage history; optional Codex account management retains each account's latest usage snapshot;
- stores the last window coordinates and the Claude visibility preference in a local `settings.json` file;
- stores one latest successful Claude snapshot in local `claude-usage-cache.json`, containing only usage percentages, reset times, and the update time;
- does not read, print, log, copy, or persist Claude authentication tokens;
- does not collect account identifiers;
- reads Codex account identifiers only after optional account registration, and stores them with labels and login snapshots in a Windows CurrentUser DPAPI encrypted vault;
- does not include telemetry;
- registers a per-user Windows logon/recovery task containing the local executable path and Windows user SID, with no stored password or elevated privileges;
- makes no outbound request for Codex usage;
- makes no direct outbound request for Codex usage; the official local app-server manages service communication;
- makes no direct Claude network request; it invokes `claude.exe` in safe mode without a shell or persistent session, caches successful `/usage` results in memory for ten minutes, and deletes the local recovery snapshot after 24 hours, its Fable reset, or an authentication/schema failure.

Codex Desktop, its local app-server, Claude Code, and Anthropic's API remain governed by their own terms and privacy practices.

Optional Codex account management reads local Codex `auth.json` for explicit registration, switching, and identity checks while refreshing registered-account usage. Replacement happens only on an explicit switch. Additional accounts use official Codex browser login in a restricted temporary home; temporary credentials are removed after import or cancellation. The separate account vault and recovery transaction are DPAPI encrypted and ACL restricted to the Windows user; the login staging directory also permits SYSTEM. They are never sent to this project's developers. DPAPI protects data at rest; it does not protect against other software already running as the same Windows user. The active Codex credential remains owned by the live authentication file: saved snapshots never override its newer tokens during recovery. Uninstall intentionally preserves the separate account vault to avoid losing saved logins.

When reporting a bug, do not attach Codex or Claude logs, credential/configuration files, tokens, or screenshots containing information you do not want to publish.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,19 @@ An unofficial Windows widget that stays on top while Codex Desktop is running an
- Hides while another foreground app is fullscreen, then returns at the saved position.
- Uses a per-user Windows scheduled task at sign-in, so the widget runs independently of Codex. A lightweight supervisor restarts the widget after an abnormal exit, waiting one minute (up to 999 retries per supervisor run).

The widget does not read or store login tokens, account details, or usage history. It stores only the latest successful Claude percentages, reset times, and update time for short-lived recovery. Claude Code itself owns authentication and token refresh. See [PRIVACY.md](PRIVACY.md).
Account management is optional. After you register a Codex account, the widget stores account labels, identities, each account's latest usage snapshot, and Codex login snapshots encrypted with Windows CurrentUser DPAPI. The live authentication file remains authoritative for the active account. Claude credentials are never accessed; Claude Code owns its authentication and token refresh. See [PRIVACY.md](PRIVACY.md).

## Manual Codex accounts

Open **Codex 계정 관리…** from the right-click menu, or double-click the tray icon. Choose **현재 계정 등록** to save the current login with a unique default name. Select an account in the left list to view its status and usage; use **이름 변경** or F2 to edit its name. Enter saves and Escape cancels. Account names appear only in the manager; the compact indicator shows percentages and bars. Renaming only changes local metadata and does not restart the usage helper. If you sign into an unregistered account directly in Codex, the manager offers registration above the existing list.

Choose **+ 다른 계정 추가**, optionally name the account, then select **브라우저에서 로그인**. Complete the official browser login using the additional account. This login uses an isolated private `CODEX_HOME` and does not log the desktop out; **로그인 취소** stops only the login process owned by this tool. The widget maintains its topmost position without activating itself, including when it reappears, so typing in the manager or another app keeps focus.

Select the saved account and click **이 계정으로 전환**. The preparation dialog shows the source and target names and waits while you finish your work and close Codex Desktop and other Codex CLI/engine processes. **전환하고 Codex 열기** becomes available when they have stopped; cancellation keeps the current login. The widget stops its own usage helper, verifies once more that no Codex writers remain, saves the latest current login, and applies the selected login. It attempts to reopen the previously observed packaged desktop; if necessary, launch Codex from the Start menu and confirm the account there. File application and desktop login verification are separate outcomes.

Only explicit selections cause a switch. There is no automatic quota rotation, proxy, inactive-account polling, or quota pooling. Inactive usage figures show the last observation and its time; values past their reset time are marked **갱신 필요**. A pending encrypted transaction blocks polling until **미완료 전환 복구** reconciles it with the actual live authentication; unknown third-party login changes are not overwritten. The management window supports display scaling, and its details scroll when the window is made smaller.

The first version supports local Windows file-based ChatGPT authentication. Unsupported keyring/managed configurations fail closed. The vault is stored separately at `%LOCALAPPDATA%\CodexWeeklyUsageIndicator.Accounts`; uninstall preserves it. Delete inactive accounts from the manager before removing the app if you no longer want their saved credentials. This convenience tool does not establish that any particular multi-account usage pattern is permitted by the service terms.

> [!IMPORTANT]
> This is an unofficial community project. It relies on an experimental local Codex app-server method (`account/rateLimits/read`) and the text output of Claude Code's built-in `/usage` command. Either may change without notice.
Expand Down
2 changes: 2 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ Please open a GitHub issue for ordinary bugs. Do not include credentials, authen
For a security-sensitive report, use GitHub's private vulnerability reporting feature when it is available for this repository.

Release binaries are not code-signed. Verify the accompanying `SHA256SUMS.txt` file or build the application from source before running it.

Optional Codex account switching handles local authentication secrets. Do not attach account-vault files, encrypted recovery transactions, or temporary login folders to an issue. Windows CurrentUser DPAPI and restrictive ACLs protect the vault at rest; same-user malware is outside that boundary. The switcher refuses to replace authentication while Codex engines are running and preserves an encrypted transaction for interrupted writes. It does not revoke or log out saved accounts when deleting local entries.
30 changes: 30 additions & 0 deletions docs/manual-accounts-delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Manual Codex accounts — delivery board

Outcome: manually switch between the owner's paid Codex accounts from the existing Windows usage widget. Keep the 272 × 64 widget; account management uses a separate optional window. No automatic quota switching, proxy routing, inactive-account polling, or Claude credential handling.

Release candidate: **1.5.1**, branch `codex/manual-account-switch`. Locally installed validation build SHA-256: `797F4309994B4C18753CC2E2FB24106A2BEC6020117D340EBD3B98048C05BBC0`, from code revision `1d28dcb6f111dc7a197647cfcbfa812ca9323067`. Installation verified one supervisor and one widget. On 2026-09-09 the user authorized recording the acceptance result and publishing a GitHub release. Public binaries are built by GitHub Actions; release checksums identify those artifacts separately from this local build.

## UX outcome

The user rejected the first manager's rough button layout and requested wireframe-led refinement, including name editing. The replacement uses a left account list and right details with status, usage and account-specific actions. A name editor supports Enter, Escape and inline validation without restarting the helper. Following the user's overlap report, version 1.5.1 removes account names from the compact indicator and keeps them in the manager. Additional login has a separate explanation/name step and cancellation. Switching has a source/target preparation dialog whose confirmation becomes available after Codex writers stop, then rechecks immediately before acceptance. External unregistered current accounts can register above an existing list. Expired usage is marked for refresh. Smaller windows scroll the details.

The earlier blank-name registration and repeating TopMost assignment were corrected in 1.4.1. This revision also fixes WinForms focusing a topmost form when it reappears: native topmost styles and SWP_NOACTIVATE maintain z-order without setting the managed TopMost property. See the upstream [Form.SetVisibleCore behavior](https://github.com/dotnet/winforms/blob/v8.0.0/src/System.Windows.Forms/src/System/Windows/Forms/Form.cs).

## Verification and review

- All 23 regression groups passed and the release build succeeded. The binary scan found no checked personal username or absolute build path; whitespace validation passed.
- Synthetic UI tests click registration, rename current/saved accounts, cancel editing/addition, reject invalid names, check Enter/Escape wiring, follow switch readiness and recheck on confirmation, and register an externally changed current account. Minimum-size scrolling exposes lower actions. Native keyboard focus and foreground remain unchanged across widget show, hide/re-show and repeated maintenance; the widget remains topmost.
- Synthetic WinForms renders at 175% scaling were inspected. Clipped dialog columns/buttons were corrected. No real-account screenshots are committed.
- A fresh source-only reviewer identified two P1 issues: registration after external login, and clipped lower actions at minimum size. Both were fixed and covered by the UI harness. The reviewer accepted the fixes and found no new confirmed P1. A reported old capture discrepancy was absent in the chair's final capture readback.
- Earlier authentication/lifecycle review and tests cover private DPAPI storage, interrupted encrypted transactions, live credential rotation, third-account refusal, corrupt data, private ACLs, reparse rejection, helper generations, owned login cancellation and browser-child survival. These remain synthetic/source checks; the user acceptance below covers the actual account switch and subsequent use.
- On 2026-09-09 the user reported successfully switching from the main account to the secondary account and using Codex without issues, and explicitly approved the experience. This is user-reported acceptance of the installed 1.5.1 flow, not an agent-observed round trip. Secondary-to-main switching has not yet been reported.
- The nonactivating topmost requirement is now explicit in `AGENTS.md`, linked to the existing native-focus regression coverage.
- Installation completed through the existing least-privilege supervisor task with final-path safeguards. The separate temporary install task was removed afterward. Final installed-screen inspection was stopped by the user's physical Escape key before a fresh UI snapshot was obtained.

## Wireframe evidence

Mode: `standalone`. Canonical structural drafts: `wireframes/02_accounts.manager.yaml` and `wireframes/03_accounts.switch.yaml`. The actual WinForms implementation and its synthetic fixture renders are derived review surfaces. Exact reconstructable revisions are the Git blobs committed with these files; retrieve them with `git rev-parse HEAD:wireframes/02_accounts.manager.yaml` and the corresponding switch path.

Wireframe assurance: **exploratory** for the structural YAML, which has not received a separate exact-revision structure review. The installed account-manager flow has user acceptance as recorded above; this does not imply full visual or accessibility certification. The layout prioritizes account identity and available actions, at the cost of extra selection compared with showing every account's full controls at once. Fixed user decisions are manual switching, widget integration, editable names and no Claude/Fable deliberation. Acceptance applies to the revised installed flow, not the rejected first manager.

Carryover owner: user — confirm secondary-to-main switching when next needed. Second-account registration, main-to-secondary switching and subsequent Codex use are confirmed by the user. The implementation agent must not close the running desktop to test switching. Full screen-reader behavior, all monitor/DPI combinations and official service-policy acceptance are not certified.
Loading