diff --git a/CHANGELOG.md b/CHANGELOG.md index 07bec8c..83b633b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ All notable changes to InferenceMeter are documented here. The project follows [ Codex compatibility release following the upstream removal of its five-hour usage window. +### Added + +- Add a native macOS About panel with Monomyth Development, project, and license details. + ### Fixed - Prefer Codex's live CLI rate-limit snapshot and ignore expired legacy windows left in rollout files after an upstream quota change. diff --git a/InferenceMeter/UI/DetailPopover.swift b/InferenceMeter/UI/DetailPopover.swift index f91468a..05bf477 100644 --- a/InferenceMeter/UI/DetailPopover.swift +++ b/InferenceMeter/UI/DetailPopover.swift @@ -46,6 +46,50 @@ func relativeUpdatedString(from updatedAt: Date, now: Date) -> String { } } +struct AboutPanelDetails: Equatable { + let organizationName: String + let websiteURL: URL + let repositoryURL: URL + let licenseURL: URL + + static let inferenceMeter = AboutPanelDetails( + organizationName: "Monomyth Development", + websiteURL: URL(string: "https://monomyth.dev")!, + repositoryURL: URL(string: "https://github.com/MonomythDevelopment/inference-meter")!, + licenseURL: URL(string: "https://github.com/MonomythDevelopment/inference-meter/blob/main/LICENSE")! + ) +} + +func makeAboutPanelCredits(details: AboutPanelDetails) -> NSAttributedString { + let credits = NSMutableAttributedString( + string: "Built by \(details.organizationName)\n" + ) + credits.append(aboutPanelLink(title: "monomyth.dev", url: details.websiteURL)) + credits.append(NSAttributedString(string: "\n")) + credits.append(aboutPanelLink(title: "Source code on GitHub", url: details.repositoryURL)) + credits.append(NSAttributedString(string: "\n")) + credits.append(aboutPanelLink(title: "Released under the MIT License", url: details.licenseURL)) + return credits +} + +@MainActor +func presentInferenceMeterAboutPanel() { + let details = AboutPanelDetails.inferenceMeter + NSApplication.shared.orderFrontStandardAboutPanel( + options: [ + .credits: makeAboutPanelCredits(details: details) + ] + ) + NSApplication.shared.activate(ignoringOtherApps: true) +} + +private func aboutPanelLink(title: String, url: URL) -> NSAttributedString { + NSAttributedString( + string: title, + attributes: [.link: url] + ) +} + struct DetailPopover: View { @Environment(AppState.self) private var appState @AppStorage("compactLabel") private var isCompactLabel = false @@ -117,6 +161,10 @@ struct DetailPopover: View { launchAtLoginMessage + Divider() + + Button("About Inference Meter", action: presentInferenceMeterAboutPanel) + Button("Quit Inference Meter", role: .destructive, action: handleQuit) .keyboardShortcut("q") } diff --git a/InferenceMeterTests/AboutPanelTests.swift b/InferenceMeterTests/AboutPanelTests.swift new file mode 100644 index 0000000..274f805 --- /dev/null +++ b/InferenceMeterTests/AboutPanelTests.swift @@ -0,0 +1,41 @@ +import Foundation +import Testing +@testable import InferenceMeter + +@Test("About panel identifies Monomyth Development and public project details") +func aboutPanelIdentifiesMonomythDevelopmentAndProjectDetails() { + let details = AboutPanelDetails.inferenceMeter + + #expect(details.organizationName == "Monomyth Development") + #expect(details.websiteURL.absoluteString == "https://monomyth.dev") + #expect(details.repositoryURL.absoluteString == "https://github.com/MonomythDevelopment/inference-meter") + #expect(details.licenseURL.absoluteString.hasSuffix("/blob/main/LICENSE")) +} + +@Test("About panel credits expose working website, repository, and license links") +func aboutPanelCreditsExposeExpectedLinks() { + let details = AboutPanelDetails.inferenceMeter + let credits = makeAboutPanelCredits(details: details) + + #expect( + credits.string == """ + Built by Monomyth Development + monomyth.dev + Source code on GitHub + Released under the MIT License + """ + ) + #expect(link(in: credits, for: "monomyth.dev") == details.websiteURL) + #expect(link(in: credits, for: "Source code on GitHub") == details.repositoryURL) + #expect(link(in: credits, for: "Released under the MIT License") == details.licenseURL) +} + +private func link(in attributedString: NSAttributedString, for text: String) -> URL? { + let range = (attributedString.string as NSString).range(of: text) + + guard range.location != NSNotFound else { + return nil + } + + return attributedString.attribute(.link, at: range.location, effectiveRange: nil) as? URL +} diff --git a/project.yml b/project.yml index f1fdaca..5bf196c 100644 --- a/project.yml +++ b/project.yml @@ -29,6 +29,7 @@ targets: PRODUCT_BUNDLE_IDENTIFIER: dev.monomyth.InferenceMeter GENERATE_INFOPLIST_FILE: YES INFOPLIST_KEY_LSUIElement: YES + INFOPLIST_KEY_NSHumanReadableCopyright: "Copyright © 2026 Monomyth Development" ENABLE_APP_SANDBOX: NO ENABLE_HARDENED_RUNTIME: NO