Repository navigation
feat: ship packaged macOS menu bar companion #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
8607b64
feat(status): expose structured proxy health metadata
jaycho46 dd98501
feat(macos): add native menu bar companion
jaycho46 8d48052
docs(macos): document the menu bar companion
jaycho46 32642c0
feat(release): package macOS companion assets
jaycho46 03c4e8a
docs(macos): explain packaged release assets
jaycho46 fbc9c84
fix(release): scope Trusted Publishing OIDC to publish job
jaycho46 1454a92
fix(macos): bound ocx CLI runs with timeout and concurrent pipe drain
jaycho46 dcf4fea
fix(macos): treat stale launchd services as repairable failures
jaycho46 cddea2c
docs(macos): document Gatekeeper first-launch approval path
jaycho46 6156f05
docs(cli): clarify nullable healthy version and uptime fields
jaycho46 4cd2876
docs(macos): align build script name to build:macos-app
jaycho46 3560e56
fix(release): use lowercase macos in packaged asset filenames
jaycho46 3946f0f
fix(macos): wait on process exit for CLI command timeouts
jaycho46 6b24897
fix(macos): require healthy proxy before reporting running phase
jaycho46 560b6f0
docs(cli): clarify Korean nullable healthy metadata wording
jaycho46 0ebbb6a
fix(macos): wait for pipe drain before reading CLI output buffers
jaycho46 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| node_modules/ | ||
| dist/ | ||
| .build/ | ||
| .env | ||
| *.log | ||
| .DS_Store | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <key>CFBundleDevelopmentRegion</key> | ||
| <string>en</string> | ||
| <key>CFBundleDisplayName</key> | ||
| <string>OpenCodex</string> | ||
| <key>CFBundleExecutable</key> | ||
| <string>OpenCodexMenuBar</string> | ||
| <key>CFBundleIdentifier</key> | ||
| <string>com.opencodex.menubar</string> | ||
| <key>CFBundleIconFile</key> | ||
| <string>OpenCodex.icns</string> | ||
| <key>CFBundleInfoDictionaryVersion</key> | ||
| <string>6.0</string> | ||
| <key>CFBundleName</key> | ||
| <string>OpenCodex</string> | ||
| <key>CFBundlePackageType</key> | ||
| <string>APPL</string> | ||
| <key>CFBundleShortVersionString</key> | ||
| <string>0.1.0</string> | ||
| <key>CFBundleVersion</key> | ||
| <string>1</string> | ||
| <key>LSMinimumSystemVersion</key> | ||
| <string>12.0</string> | ||
| <key>LSUIElement</key> | ||
| <true/> | ||
| <key>NSHighResolutionCapable</key> | ||
| <true/> | ||
| </dict> | ||
| </plist> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // swift-tools-version: 5.9 | ||
| import PackageDescription | ||
|
|
||
| let package = Package( | ||
| name: "OpenCodexMenuBar", | ||
| platforms: [ | ||
| .macOS(.v12), | ||
| ], | ||
| products: [ | ||
| .executable(name: "OpenCodexMenuBar", targets: ["OpenCodexMenuBar"]), | ||
| ], | ||
| targets: [ | ||
| .target( | ||
| name: "OpenCodexMenuBarCore", | ||
| path: "Sources/OpenCodexMenuBarCore" | ||
| ), | ||
| .executableTarget( | ||
| name: "OpenCodexMenuBar", | ||
| dependencies: ["OpenCodexMenuBarCore"], | ||
| path: "Sources/OpenCodexMenuBar" | ||
| ), | ||
| .testTarget( | ||
| name: "OpenCodexMenuBarCoreTests", | ||
| dependencies: ["OpenCodexMenuBarCore"], | ||
| path: "Tests/OpenCodexMenuBarCoreTests" | ||
| ), | ||
| ], | ||
| swiftLanguageVersions: [.v5] | ||
| ) |
43 changes: 43 additions & 0 deletions
43
apps/macos-menu-bar/Sources/OpenCodexMenuBar/MenuText.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import Foundation | ||
|
|
||
| enum Text { | ||
| static let isKorean = Locale.current.languageCode == "ko" | ||
|
|
||
| static let appName = "OpenCodex" | ||
| static var checking: String { isKorean ? "상태 확인 중…" : "Checking status…" } | ||
| static var running: String { isKorean ? "프록시 실행 중" : "Proxy running" } | ||
| static var stopped: String { isKorean ? "프록시 중지됨" : "Proxy stopped" } | ||
| static var degraded: String { isKorean ? "프록시 상태 확인 필요" : "Proxy needs attention" } | ||
| static var cliMissing: String { isKorean ? "ocx CLI를 찾을 수 없음" : "ocx CLI not found" } | ||
| static var failed: String { isKorean ? "상태를 확인할 수 없음" : "Status unavailable" } | ||
| static var openDashboard: String { isKorean ? "대시보드 열기" : "Open Dashboard" } | ||
| static var start: String { isKorean ? "프록시 시작" : "Start Proxy" } | ||
| static var restart: String { isKorean ? "프록시 재시작…" : "Restart Proxy…" } | ||
| static var stop: String { isKorean ? "프록시 종료…" : "Stop Proxy…" } | ||
| static var refresh: String { isKorean ? "상태 새로고침" : "Refresh Status" } | ||
| static var chooseCLI: String { isKorean ? "ocx CLI 선택…" : "Choose ocx CLI…" } | ||
| static var resetCLI: String { isKorean ? "CLI 자동 탐색 사용" : "Use Auto-detected CLI" } | ||
| static var quit: String { isKorean ? "메뉴바 앱 종료" : "Quit Menu Bar App" } | ||
| static var noService: String { isKorean ? "launchd 서비스 없음" : "No launchd service" } | ||
| static var serviceStale: String { isKorean ? "서비스 손상 — 재설치 필요" : "Service stale — repair required" } | ||
| static var repairService: String { isKorean ? "서비스 복구" : "Repair Service" } | ||
| static var serviceRunning: String { isKorean ? "launchd 서비스 사용 중" : "Launchd service enabled" } | ||
| static var serviceStopped: String { isKorean ? "launchd 서비스 중지됨" : "Launchd service stopped" } | ||
| static var runtime: String { isKorean ? "Bun 런타임" : "Bun runtime" } | ||
| static let cli = "ocx CLI" | ||
| static var starting: String { isKorean ? "프록시 시작 중…" : "Starting proxy…" } | ||
| static var restarting: String { isKorean ? "프록시 재시작 중…" : "Restarting proxy…" } | ||
| static var stopping: String { isKorean ? "프록시 종료 중…" : "Stopping proxy…" } | ||
| static var actionFailed: String { isKorean ? "프록시 제어 실패" : "Proxy Control Failed" } | ||
| static var invalidCLI: String { isKorean ? "실행 가능한 ocx 파일을 선택해 주세요." : "Choose an executable ocx file." } | ||
| static var restartTitle: String { isKorean ? "프록시를 재시작할까요?" : "Restart the proxy?" } | ||
| static var stopTitle: String { isKorean ? "프록시를 종료할까요?" : "Stop the proxy?" } | ||
| static var interruptionWarning: String { | ||
| isKorean | ||
| ? "진행 중인 요청이 중단될 수 있습니다. 종료하면 Codex 설정은 네이티브 상태로 복원됩니다." | ||
| : "Active requests may be interrupted. Stopping also restores native Codex configuration." | ||
| } | ||
| static var cancel: String { isKorean ? "취소" : "Cancel" } | ||
| static var confirmRestart: String { isKorean ? "재시작" : "Restart" } | ||
| static var confirmStop: String { isKorean ? "종료" : "Stop" } | ||
| } |
34 changes: 34 additions & 0 deletions
34
apps/macos-menu-bar/Sources/OpenCodexMenuBar/StatusBarIcon.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import AppKit | ||
|
|
||
| enum StatusBarIcon { | ||
| private static let size = NSSize(width: 22, height: 22) | ||
| private static let cropRatio: CGFloat = 0.09375 | ||
| private static let verticalOffset: CGFloat = -1 | ||
|
|
||
| static func make(accessibilityDescription: String) -> NSImage? { | ||
| guard let imageURL = Bundle.main.url(forResource: "OpenCodexMenuBar", withExtension: "png"), | ||
| let sourceImage = NSImage(contentsOf: imageURL) else { | ||
| return fallback(accessibilityDescription: accessibilityDescription) | ||
| } | ||
|
|
||
| let sourceRect = NSRect(origin: .zero, size: sourceImage.size).insetBy( | ||
| dx: sourceImage.size.width * cropRatio, | ||
| dy: sourceImage.size.height * cropRatio | ||
| ) | ||
| let image = NSImage(size: size, flipped: false) { destinationRect in | ||
| let alignedRect = destinationRect.offsetBy(dx: 0, dy: verticalOffset) | ||
| sourceImage.draw(in: alignedRect, from: sourceRect, operation: .sourceOver, fraction: 1) | ||
| return true | ||
| } | ||
| image.isTemplate = true | ||
| return image | ||
| } | ||
|
|
||
| private static func fallback(accessibilityDescription: String) -> NSImage? { | ||
| let configuration = NSImage.SymbolConfiguration(pointSize: 15, weight: .medium) | ||
| let image = NSImage(systemSymbolName: "network", accessibilityDescription: accessibilityDescription)? | ||
| .withSymbolConfiguration(configuration) | ||
| image?.isTemplate = true | ||
| return image | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.