Vibeviewer
English | 简体中文
Tags: swift, swiftui, xcode, tuist, macos, menu-bar, release
An open-source macOS menu bar app that surfaces workspace/team usage and spend at a glance, with sign-in, settings, auto-refresh, and sharing capabilities. The project follows a modular Swift Package architecture and a pure SwiftUI MV (not MVVM) approach, emphasizing clear boundaries and replaceability.
Features
- Menu bar summary: Popover shows key metrics and recent activity:
- Billing overview, Free usage (when available), On‑demand (when available)
- Total credits usage with smooth numeric transitions
- Requests compare (Today vs Yesterday) and Usage events
- Top actions: Open Dashboard and Log out
- Sign-in & Settings: Dedicated windows with persisted credentials and preferences.
- Power-aware refresh: Smart refresh strategy reacting to screen power/activity state.
- Modular architecture: One-way dependencies Core ← Model ← API ← Feature; DTO→Domain mapping lives in API only.
- Sharing components: Built-in fonts and assets to generate shareable views.
Notes
- Currently developed and tested against team accounts only. Individual/free accounts are not yet verified — contributions for compatibility are welcome.
- Thanks to the modular layered design, although Cursor is the present data source, other similar apps can be integrated by implementing the corresponding data-layer interfaces — PRs are welcome.
- The app currently has no logo — designers are welcome to contribute one.
Brand and data sources are for demonstration. The UI never sees concrete networking implementations — only service protocols and default implementations are exposed.
Architecture & Structure
Workspace with multiple Swift Packages (one-way dependency: Core ← Model ← API ← Feature):
Vibeviewer/
├─ Vibeviewer.xcworkspace # Open this workspace
├─ Vibeviewer/ # Thin app shell (entry only)
├─ Packages/
│ ├─ VibeviewerCore/ # Core: utilities/extensions/shared services
│ ├─ VibeviewerModel/ # Model: pure domain entities (value types/Sendable)
│ ├─ VibeviewerAPI/ # API: networking/IO + DTO→Domain mapping (protocols exposed)
│ ├─ VibeviewerAppEnvironment/ # Environment injection & cross-feature services
│ ├─ VibeviewerStorage/ # Storage (settings, credentials, etc.)
│ ├─ VibeviewerLoginUI/ # Feature: login UI
│ ├─ VibeviewerMenuUI/ # Feature: menu popover UI (main)
│ ├─ VibeviewerSettingsUI/ # Feature: settings UI
│ └─ VibeviewerShareUI/ # Feature: sharing components & assets
└─ Scripts/ & Makefile # Tuist generation, clean, DMG packaging
Key rules (see also ./.cursor/rules/architecture.mdc):
- Placement & responsibility
- Core/Shared → utilities & extensions
- Model → pure domain data
- API/Service → networking/IO/3rd-party orchestration and DTO→Domain mapping
- Feature/UI → SwiftUI views & interactions consuming service protocols and domain models only
- Dependency direction: Core ← Model ← API ← Feature (no reverse dependencies)
- Replaceability: API exposes service protocols + default impl; UI injects via
@Environment, never references networking libs directly - SwiftUI MV:
- Use
@State/@Observable/@Environment/@Bindingfor state - Side effects in
.task/.onChange(lifecycle-aware cancellation) - Avoid default ViewModel layer (no MVVM by default)
- Use
Requirements
- macOS 14.0+
- Xcode 15.4+ (
SWIFT_VERSION = 5.10) - Tuist
Install Tuist if needed:
brew tap tuist/tuist && brew install tuistGetting Started
- Generate the Xcode workspace:
make generate
# or
Scripts/generate.sh- Open and run:
open Vibeviewer.xcworkspace
# In Xcode: scheme = Vibeviewer, destination = My Mac (macOS), then Run- Build/package via CLI (optional):
make build # Release build (macOS) make dmg # Create DMG package make release # Clean → Generate → Build → Package make release-full # Full automated release (build + tag + GitHub release)
- Release process:
See Scripts/RELEASE_GUIDE.md for detailed release instructions.
Quick release:
./Scripts/release.sh [VERSION] # Automated release workflowRun & Debug
- The menu bar shows the icon and key metrics; click to open the popover.
- Sign-in and Settings windows are provided via environment-injected window managers (see
.environment(...)inVibeviewerApp.swift). - Auto-refresh starts on app launch and reacts to screen power/activity changes.
Testing
Each package ships its own tests. Run from Xcode or via CLI per package:
swift test --package-path Packages/VibeviewerCore swift test --package-path Packages/VibeviewerModel swift test --package-path Packages/VibeviewerAPI swift test --package-path Packages/VibeviewerAppEnvironment swift test --package-path Packages/VibeviewerStorage swift test --package-path Packages/VibeviewerLoginUI swift test --package-path Packages/VibeviewerMenuUI swift test --package-path Packages/VibeviewerSettingsUI swift test --package-path Packages/VibeviewerShareUI
Tip: after adding/removing packages, run
make generatefirst.
Contributing
Issues and PRs are welcome. To keep the codebase consistent and maintainable:
- Branch & commits
- Use branches like
feat/...orfix/.... - Prefer Conventional Commits (e.g.,
feat: add dashboard refresh service).
- Architecture agreements
- Read
./.cursor/rules/architecture.mdcand this README before changes. - Place new code in the proper layer (UI/Service/Model/Core). One primary type per file.
- API layer exposes service protocols + default impl only; DTOs stay internal; UI uses domain models only.
- Self-check
make generateworks and the workspace opensmake buildsucceeds (or Release build in Xcode)swift testpasses for related packages- No reverse dependencies; UI never imports networking implementations
- PR
- Describe motivation, touched modules, and impacts
- Include screenshots/clips for UI changes
- Prefer small, focused PRs
FAQ
-
Q: Missing targets or workspace won’t open?
- A: Run
make generate(orScripts/generate.sh).
- A: Run
-
Q: Tuist command not found?
- A: Install via Homebrew as above.
-
Q: Swift version mismatch during build?
- A: Use Xcode 15.4+ (Swift 5.10). If issues persist, run
Scripts/clear.shthenmake generate.
- A: Use Xcode 15.4+ (Swift 5.10). If issues persist, run
License
This project is open-sourced under the MIT License. See LICENSE for details.
Acknowledgements
Thanks to the community for contributions to modular Swift packages, SwiftUI, and developer tooling — and thanks for helping improve Vibeviewer!
UI inspiration from X user @hi_caicai — see Minto: Vibe Coding Tracker.
