chore: snapshot uncommitted local work before rebasing onto cloud-agent

Safety commit so the 94 uncommitted files in the working tree (in-flight
Account/Mac/Tip work plus the feature-preview recording tooling) survive the
move onto cursor/cloud-agent-1787824905651-vxuwc.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 11:28:07 -07:00
co-authored by Claude Opus 5
parent 39002336c0
commit 5d51c5bf77
101 changed files with 3629 additions and 1354 deletions
@@ -98,7 +98,11 @@ private final class FlowPrerollStore: @unchecked Sendable {
}
/// Rolling bar levels updated from the audio tap; read on the main actor.
private final class FlowLevelStore: @unchecked Sendable {
///
/// Deliberately not `private`: the bar arithmetic runs on the realtime audio
/// thread where a bad range is an uncatchable trap, so it needs direct
/// `@testable` coverage rather than only being reachable through a live engine.
final class FlowLevelStore: @unchecked Sendable {
private let lock = OSAllocatedUnfairLock()
private var levels: [Float]
@@ -115,7 +119,7 @@ private final class FlowLevelStore: @unchecked Sendable {
lock.withLock { levels }
}
private static func calculateLevels(from buffer: AVAudioPCMBuffer, barCount: Int) -> [Float] {
static func calculateLevels(from buffer: AVAudioPCMBuffer, barCount: Int) -> [Float] {
guard let channelData = buffer.floatChannelData else {
return Array(repeating: 0, count: barCount)
}
@@ -127,7 +131,12 @@ private final class FlowLevelStore: @unchecked Sendable {
var result = [Float]()
result.reserveCapacity(barCount)
for barIndex in 0..<barCount {
let start = barIndex * samplesPerBar
// A tap buffer shorter than `barCount` floors `samplesPerBar` to 1,
// so the tail bars would otherwise start past `frameLength` and
// build a reversed `start..<end` range — an uncatchable trap on the
// realtime audio thread. Clamping `start` leaves those bars empty
// (level 0), which is the right reading for samples we do not have.
let start = min(barIndex * samplesPerBar, frameLength)
let end = min(start + samplesPerBar, frameLength)
var sum: Float = 0
for i in start..<end {
@@ -1,126 +0,0 @@
// TipPurchaseManager.swift
// OSGKeyboard · HostSupport
//
// Optional ¥30 consumable tip via StoreKit 2. Voluntary support only —
// no feature gates, no App Group sync, no restore (Apple consumable rules).
import Combine
import Foundation
import StoreKit
#if canImport(OSGKeyboardShared)
import OSGKeyboardShared
#endif
public enum TipPurchaseState: Equatable {
case idle
case loading
case purchasing
case succeeded
case failed(String)
}
@MainActor
public final class TipPurchaseManager: ObservableObject {
public static let shared = TipPurchaseManager()
@Published public private(set) var product: Product?
@Published public private(set) var purchaseState: TipPurchaseState = .idle
@Published public private(set) var supportCount: Int
private var transactionUpdatesTask: Task<Void, Never>?
public init(defaults: UserDefaults = .standard) {
supportCount = defaults.integer(forKey: TipProduct.supportCountDefaultsKey)
transactionUpdatesTask = Task { [weak self] in
await self?.listenForTransactionUpdates()
}
Task { await loadProducts() }
}
deinit {
transactionUpdatesTask?.cancel()
}
/// Loads the tip product from the App Store / StoreKit Test configuration.
public func loadProducts() async {
guard purchaseState != .purchasing else { return }
purchaseState = .loading
do {
let products = try await Product.products(for: TipProduct.allProductIDs)
product = products.first(where: { $0.id == TipProduct.supportID })
purchaseState = product == nil
? .failed(SharedL10n.string("tip.error.productUnavailable"))
: .idle
} catch {
product = nil
purchaseState = .failed(error.localizedDescription)
}
}
/// Starts the StoreKit purchase sheet for the support tip.
public func purchase() async {
guard let product else {
purchaseState = .failed(SharedL10n.string("tip.error.productUnavailable"))
return
}
purchaseState = .purchasing
do {
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try Self.verified(verification)
await handleCompletedTip(transaction)
purchaseState = .succeeded
case .userCancelled:
purchaseState = .idle
case .pending:
purchaseState = .failed(SharedL10n.string("tip.error.pending"))
@unknown default:
purchaseState = .failed(SharedL10n.string("tip.error.unknown"))
}
} catch {
purchaseState = .failed(error.localizedDescription)
}
}
/// Clears transient success / failure state after the UI acknowledges it.
public func acknowledgePurchaseState() {
switch purchaseState {
case .succeeded, .failed:
purchaseState = .idle
default:
break
}
}
private func listenForTransactionUpdates() async {
for await update in Transaction.updates {
guard let transaction = try? Self.verified(update),
transaction.productID == TipProduct.supportID else { continue }
await handleCompletedTip(transaction)
}
}
private func handleCompletedTip(_ transaction: Transaction) async {
await transaction.finish()
recordSupportPurchase()
}
private func recordSupportPurchase() {
supportCount += 1
UserDefaults.standard.set(supportCount, forKey: TipProduct.supportCountDefaultsKey)
}
private static func verified<T>(_ result: VerificationResult<T>) throws -> T {
switch result {
case .verified(let value):
return value
case .unverified:
throw TipPurchaseError.failedVerification
}
}
}
private enum TipPurchaseError: Error {
case failedVerification
}