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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ app: check-toolchain release-facts ## Build the release app bundle
run-app: check-toolchain ## Build and open the local app bundle
./scripts/build-and-run-vifty.sh

install: check-toolchain ## Build and install to /Applications
install: check-toolchain app ## Build and install to /Applications
CONFIGURATION="$(CONFIGURATION)" ./scripts/install-vifty.sh

install-public-release: ## Verify and install the exact current published release archive
Expand Down Expand Up @@ -271,7 +271,7 @@ test-full: check-toolchain ## Run the full XCTest suite, including slow evidence
swift test $(SWIFT_BUILD_ARGS) $(SWIFT_TEST_WARNING_ARGS)

verify: check-toolchain ## Run fast local trust gates without installing
/bin/bash -n scripts/*.sh scripts/lib/*.sh examples/viftyctl/*.sh
@for script in scripts/*.sh scripts/lib/*.sh examples/viftyctl/*.sh; do /bin/bash -n "$$script" || exit $$?; done
$(MAKE) release-facts
scripts/check-community-standards.sh
scripts/validate-release-metadata.sh --mode "$(RELEASE_METADATA_MODE)"
Expand Down
25 changes: 2 additions & 23 deletions Sources/Vifty/AgentWorkflowSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,18 @@ extension ViftyAgentRuleWorkloadCommandMode {
extension AgentWorkflowSupport {
static let safeWorkloadCommandTemplates: [WorkloadCommandTemplate] = ViftyCtlWorkloadTemplate.auditedTemplates

static func agentRule(
bundleURL: URL = Bundle.main.bundleURL,
fileManager: FileManager = .default
) -> String {
ViftyAgentRule.rule(bundleURL: bundleURL, fileManager: fileManager)
}

@discardableResult
@MainActor
static func copyAgentRule(
bundleURL: URL = Bundle.main.bundleURL,
pasteboard: NSPasteboard = .general
) -> String {
let rule = agentRule(bundleURL: bundleURL)
let rule = ViftyAgentRule.rule(bundleURL: bundleURL)
pasteboard.clearContents()
pasteboard.setString(rule, forType: .string)
return rule
}

static func workloadCommand(
_ template: WorkloadCommandTemplate,
mode: WorkloadCommandMode,
bundleURL: URL = Bundle.main.bundleURL,
fileManager: FileManager = .default
) -> String {
ViftyAgentRule.workloadCommand(
template,
mode: mode,
bundleURL: bundleURL,
fileManager: fileManager
)
}

@discardableResult
@MainActor
static func copyWorkloadCommand(
Expand All @@ -67,7 +46,7 @@ extension AgentWorkflowSupport {
bundleURL: URL = Bundle.main.bundleURL,
pasteboard: NSPasteboard = .general
) -> String {
let command = workloadCommand(template, mode: mode, bundleURL: bundleURL)
let command = ViftyAgentRule.workloadCommand(template, mode: mode, bundleURL: bundleURL)
pasteboard.clearContents()
pasteboard.setString(command, forType: .string)
return command
Expand Down
16 changes: 0 additions & 16 deletions Sources/Vifty/AppModel+Control.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@ import ViftyCore

@MainActor
extension AppModel {
func applyModeSelection() {
if selectedMode == .auto {
restoreAuto()
} else {
markFanControlDraftPending()
}
}

func performModeSelectionAction() {
Task { await performModeSelectionActionNow() }
}
Expand Down Expand Up @@ -47,10 +39,6 @@ extension AppModel {
)
}

func applyPendingFanControl() {
Task { _ = await applyCurrentModeSelection() }
}

@discardableResult
func applyCurrentModeSelection() async -> FanControlApplyResult {
if selectedMode == .auto {
Expand Down Expand Up @@ -350,10 +338,6 @@ extension AppModel {
fanControlSessionController.fanMode(for: draft)
}

func applyCurveOverrides() {
markFanControlDraftPending()
}

func restoreAutoIfManualSessionExpired() async -> FanControlSessionOperation? {
guard fanControlSessionController.shouldRestoreExpiredManualSession(
selectedMode: selectedMode,
Expand Down
23 changes: 5 additions & 18 deletions Sources/Vifty/CodexUsage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,6 @@ struct CodexUsageReader {
return latest?.snapshot
}

private func latestUsageEvent(in url: URL) -> (timestamp: String, snapshot: CodexUsageSnapshot)? {
for line in candidateLines(fromTailOf: url) {
guard let event = parseEvent(line, sourceURL: url) else { continue }
return event
}
return nil
}

private func usageFiles() -> [URL] {
let sessionsURL = codexHome.appendingPathComponent("sessions", isDirectory: true)
guard let enumerator = fileManager.enumerator(
Expand All @@ -231,31 +223,26 @@ struct CodexUsageReader {
.map(\.url)
}

private func candidateLines(fromTailOf url: URL) -> [String] {
guard let handle = try? FileHandle(forReadingFrom: url) else { return [] }
private func latestUsageEvent(in url: URL) -> (timestamp: String, snapshot: CodexUsageSnapshot)? {
guard let handle = try? FileHandle(forReadingFrom: url) else { return nil }
defer { try? handle.close() }

let size = (try? handle.seekToEnd()) ?? 0
let offset = size > Self.tailBytes ? size - Self.tailBytes : 0
do {
try handle.seek(toOffset: offset)
} catch {
return []
return nil
}
let data = (try? handle.readToEnd()) ?? Data()
return candidateLines(in: data)
}

private func candidateLines(in data: Data) -> [String] {
var matches: [String] = []
for line in String(decoding: data, as: UTF8.self)
.split(separator: "\n", omittingEmptySubsequences: true)
.reversed()
{
guard line.contains("token_count"), line.contains("rate_limits") else { continue }
matches.append(String(line))
if let event = parseEvent(String(line), sourceURL: url) { return event }
}
return matches
return nil
}

private func parseEvent(_ line: String, sourceURL: URL) -> (timestamp: String, snapshot: CodexUsageSnapshot)? {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Vifty/DaemonInstallService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ struct DaemonLifecycleScriptLoader: Sendable {
// This digest is compiled into the signed app executable. The resource is
// read once into an immutable Data snapshot and only that snapshot runs.
// Update it intentionally whenever vifty-helper-lifecycle.sh changes.
let expectedSHA256 = "d0ba8e8ed28cd3b85d1df53db5defa30334ee933a00f1d76b09736b0c21a78bd"
let expectedSHA256 = "3777a71c14046f0ef9d27a575d604300683914bdb03e0a79e9fb0c6cf6f6e18f"
let maximumSize = 256 * 1_024
let descriptor = Darwin.open(url.path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW)
guard descriptor >= 0 else {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Vifty/DaemonInstaller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ final class DaemonInstaller: ObservableObject {
return .failed
}
case .enabled:
// Keep SMAppService and launchd aligned when macOS reports a
// stale enabled record after a prior bootout or app replacement.
try? backend.register()
return await runSafeLifecycle()
case .unknown:
statusText = "Helper registration state is unknown; restore Auto or reboot before repair"
Expand Down
8 changes: 0 additions & 8 deletions Sources/Vifty/FanControlSessionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,6 @@ struct FanControlSessionController {
)
}

func previousSessionDeadline(for operation: FanControlSessionOperation) -> Date? {
guard let attempt = manualApplyAttempt,
attempt.operation == operation else {
return nil
}
return attempt.previousSessionExpiresAt
}

func fanMode(for draft: FanControlDraft) -> FanMode {
switch draft.mode {
case .auto:
Expand Down
12 changes: 0 additions & 12 deletions Sources/Vifty/HelperDiagnosticsSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,6 @@ enum HelperDiagnosticsSupport {
return command
}

@discardableResult
@MainActor
static func copyDiagnoseCommand(
bundleURL: URL = Bundle.main.bundleURL,
pasteboard: NSPasteboard = .general
) -> String {
let command = diagnoseCommand(bundleURL: bundleURL)
pasteboard.clearContents()
pasteboard.setString(command, forType: .string)
return command
}

private static func developmentToolURL(
beside executableURL: URL?,
fileManager: FileManager
Expand Down
5 changes: 4 additions & 1 deletion Sources/Vifty/HelperServiceManagementBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,10 @@ enum HelperServiceManagementBridge {
case .register:
switch backend.state {
case .enabled:
break
// macOS can retain the enabled SMAppService record after the
// launchd job was booted out. Re-submit the native service so
// the next XPC lookup can launch it again.
try backend.register()
case .notRegistered:
try backend.register()
case .requiresApproval:
Expand Down
6 changes: 1 addition & 5 deletions Sources/Vifty/MenuBarTelemetryPrimeScheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Foundation

@MainActor
final class MenuBarTelemetryPrimeScheduler {
private var currentOperation: (@MainActor () async -> Void)?
private var task: Task<Void, Never>?

var isPriming: Bool {
Expand All @@ -12,15 +11,12 @@ final class MenuBarTelemetryPrimeScheduler {
@discardableResult
func schedule(_ operation: @escaping @MainActor () async -> Void) -> Bool {
guard task == nil else { return false }
currentOperation = operation
task = Task { @MainActor [weak self] in
guard let self else { return }
let operation = self.currentOperation
defer {
self.currentOperation = nil
self.task = nil
}
await operation?()
await operation()
}
return true
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Vifty/SettingsGeneralView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct SettingsGeneralView: View {
Text("Temperature Curve").tag(ModeSelection.curve)
}

Text(StartupModePresentation.resolve(model.startupMode).detail)
Text(StartupModePresentation.detail(for: model.startupMode))
.viftyFont(.caption)
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
Expand Down
17 changes: 4 additions & 13 deletions Sources/Vifty/StartupModePresentation.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
struct StartupModePresentation: Equatable {
let detail: String
let requiresExplicitApply: Bool

static func resolve(_ mode: ModeSelection) -> StartupModePresentation {
enum StartupModePresentation {
static func detail(for mode: ModeSelection) -> String {
switch mode {
case .auto:
return StartupModePresentation(
detail: "Starts in macOS Auto control.",
requiresExplicitApply: false
)
"Starts in macOS Auto control."
case .fixed, .curve:
return StartupModePresentation(
detail: "Preselects this mode as a draft; it does not change fan control at launch. Review the targets and choose Apply.",
requiresExplicitApply: true
)
"Preselects this mode as a draft; it does not change fan control at launch. Review the targets and choose Apply."
}
}
}
4 changes: 4 additions & 0 deletions Sources/ViftyCore/SMCClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ public final class SMCClient: @unchecked Sendable {

var input = infoInput
input.keyInfo = infoOutput.keyInfo
// AppleSMC expects the write envelope to declare the exact payload
// size. Leaving the discovered size implicit can accept F0Md while
// silently ignoring the following F{n}Tg write on protected Macs.
input.keyInfo.dataSize = UInt32(bytes.count)
input.data8 = 6
for (index, byte) in bytes.enumerated() {
input.bytes[index] = byte
Expand Down
8 changes: 0 additions & 8 deletions Sources/ViftyCore/SecureStorageDirectory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -965,14 +965,6 @@ public final class SecureStorageDirectory: @unchecked Sendable {
lhs.st_dev == rhs.st_dev && lhs.st_ino == rhs.st_ino
}

private static func sameOptionalIdentity(_ lhs: stat?, _ rhs: stat?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): true
case (.some(let lhs), .some(let rhs)): sameIdentity(lhs, rhs)
default: false
}
}

private static func sameOptionalVersion(_ lhs: stat?, _ rhs: stat?) -> Bool {
switch (lhs, rhs) {
case (nil, nil): true
Expand Down
Loading