蜂鸟Pro v2.0.1 - 基础框架版本 (待完善)
## 当前状态 - 插件界面已完成重命名 (cursorpro → hummingbird) - 双账号池 UI 已实现 (Auto/Pro 卡片) - 后端已切换到 MySQL 数据库 - 添加了 Cursor 官方用量 API 文档 ## 已知问题 (待修复) 1. 激活时检查账号导致无账号时激活失败 2. 未启用无感换号时不应获取账号 3. 账号用量模块不显示 (seamless 未启用时应隐藏) 4. 积分显示为 0 (后端未正确返回) 5. Auto/Pro 双密钥逻辑混乱,状态不同步 6. 账号添加后无自动分析功能 ## 下一版本计划 - 重构数据模型,优化账号状态管理 - 实现 Cursor API 自动分析账号 - 修复激活流程,不依赖账号 - 启用无感时才分配账号 - 完善账号用量实时显示 ## 文件说明 - docs/系统设计文档.md - 完整架构设计 - cursor 官方用量接口.md - Cursor API 文档 - 参考计费/ - Vibeviewer 开源项目参考 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
17
参考计费/Packages/VibeviewerCore/Package.swift
Normal file
17
参考计费/Packages/VibeviewerCore/Package.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
// swift-tools-version:5.10
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "VibeviewerCore",
|
||||
platforms: [
|
||||
.macOS(.v14)
|
||||
],
|
||||
products: [
|
||||
.library(name: "VibeviewerCore", targets: ["VibeviewerCore"]),
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(name: "VibeviewerCore", dependencies: []),
|
||||
.testTarget(name: "VibeviewerCoreTests", dependencies: ["VibeviewerCore"])
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Data+E.swift
|
||||
// HttpClient
|
||||
//
|
||||
// Created by Groot chen on 2024/9/6.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Data {
|
||||
func toPrettyPrintedJSONString() -> String? {
|
||||
if let json = try? JSONSerialization.jsonObject(with: self),
|
||||
let data = try? JSONSerialization.data(
|
||||
withJSONObject: json,
|
||||
options: [.prettyPrinted, .withoutEscapingSlashes]
|
||||
)
|
||||
{
|
||||
return String(data: data, encoding: .utf8)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import Foundation
|
||||
|
||||
public extension Date {
|
||||
/// 毫秒时间戳(字符串)
|
||||
public var millisecondsSince1970String: String {
|
||||
String(Int(self.timeIntervalSince1970 * 1000))
|
||||
}
|
||||
|
||||
/// 由毫秒时间戳字符串构造 Date
|
||||
public static func fromMillisecondsString(_ msString: String) -> Date? {
|
||||
guard let ms = Double(msString) else { return nil }
|
||||
return Date(timeIntervalSince1970: ms / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Calendar {
|
||||
/// 给定日期所在天的起止 [start, end]
|
||||
public func dayRange(for date: Date) -> (start: Date, end: Date) {
|
||||
let startOfDay = self.startOfDay(for: date)
|
||||
let nextDay = self.date(byAdding: .day, value: 1, to: startOfDay) ?? date
|
||||
let endOfDay = Date(timeInterval: -0.001, since: nextDay)
|
||||
return (startOfDay, endOfDay)
|
||||
}
|
||||
|
||||
/// 昨天 00:00 到当前时刻的区间 [yesterdayStart, now]
|
||||
public func yesterdayToNowRange(from now: Date = Date()) -> (start: Date, end: Date) {
|
||||
let startOfToday = self.startOfDay(for: now)
|
||||
let startOfYesterday = self.date(byAdding: .day, value: -1, to: startOfToday) ?? now
|
||||
return (startOfYesterday, now)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import Foundation
|
||||
|
||||
public enum DateUtils {
|
||||
public enum TimeFormat {
|
||||
case hm // HH:mm
|
||||
case hms // HH:mm:ss
|
||||
|
||||
fileprivate var dateFormat: String {
|
||||
switch self {
|
||||
case .hm: return "HH:mm"
|
||||
case .hms: return "HH:mm:ss"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 给定日期所在天的起止 [start, end]
|
||||
public static func dayRange(for date: Date, calendar: Calendar = .current) -> (start: Date, end: Date) {
|
||||
let startOfDay = calendar.startOfDay(for: date)
|
||||
let nextDay = calendar.date(byAdding: .day, value: 1, to: startOfDay) ?? date
|
||||
let endOfDay = Date(timeInterval: -0.001, since: nextDay)
|
||||
return (startOfDay, endOfDay)
|
||||
}
|
||||
|
||||
/// 昨天 00:00 到当前时刻的区间 [yesterdayStart, now]
|
||||
public static func yesterdayToNowRange(from now: Date = Date(), calendar: Calendar = .current) -> (start: Date, end: Date) {
|
||||
let startOfToday = calendar.startOfDay(for: now)
|
||||
let startOfYesterday = calendar.date(byAdding: .day, value: -1, to: startOfToday) ?? now
|
||||
return (startOfYesterday, now)
|
||||
}
|
||||
|
||||
/// 7 天前的 00:00 到明天 00:00 的区间 [sevenDaysAgoStart, tomorrowStart]
|
||||
public static func sevenDaysAgoToNowRange(from now: Date = Date(), calendar: Calendar = .current) -> (start: Date, end: Date) {
|
||||
let startOfToday = calendar.startOfDay(for: now)
|
||||
let startOfSevenDaysAgo = calendar.date(byAdding: .day, value: -7, to: startOfToday) ?? now
|
||||
let startOfTomorrow = calendar.date(byAdding: .day, value: 1, to: startOfToday) ?? now
|
||||
return (startOfSevenDaysAgo, startOfTomorrow)
|
||||
}
|
||||
|
||||
/// 指定天数前的 00:00 到明天 00:00 的区间 [nDaysAgoStart, tomorrowStart]
|
||||
public static func daysAgoToNowRange(days: Int, from now: Date = Date(), calendar: Calendar = .current) -> (start: Date, end: Date) {
|
||||
let startOfToday = calendar.startOfDay(for: now)
|
||||
let startOfNDaysAgo = calendar.date(byAdding: .day, value: -days, to: startOfToday) ?? now
|
||||
let startOfTomorrow = calendar.date(byAdding: .day, value: 1, to: startOfToday) ?? now
|
||||
return (startOfNDaysAgo, startOfTomorrow)
|
||||
}
|
||||
|
||||
/// 将 Date 转为毫秒字符串
|
||||
public static func millisecondsString(from date: Date) -> String {
|
||||
String(Int(date.timeIntervalSince1970 * 1000))
|
||||
}
|
||||
|
||||
/// 由毫秒字符串转 Date
|
||||
public static func date(fromMillisecondsString msString: String) -> Date? {
|
||||
guard let ms = Double(msString) else { return nil }
|
||||
return Date(timeIntervalSince1970: ms / 1000.0)
|
||||
}
|
||||
|
||||
/// 将 Date 按指定格式转为时间字符串(默认 HH:mm:ss)
|
||||
public static func timeString(from date: Date,
|
||||
format: TimeFormat = .hms,
|
||||
timeZone: TimeZone = .current,
|
||||
locale: Locale = Locale(identifier: "en_US_POSIX")) -> String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.locale = locale
|
||||
formatter.timeZone = timeZone
|
||||
formatter.dateFormat = format.dateFormat
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
/// 由毫秒级时间戳转为时间字符串
|
||||
public static func timeString(fromMilliseconds ms: Int64,
|
||||
format: TimeFormat = .hms,
|
||||
timeZone: TimeZone = .current,
|
||||
locale: Locale = .current) -> String {
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(ms) / 1000.0)
|
||||
return timeString(from: date, format: format, timeZone: timeZone, locale: locale)
|
||||
}
|
||||
|
||||
/// 由秒级时间戳转为时间字符串
|
||||
public static func timeString(fromSeconds s: Int64,
|
||||
format: TimeFormat = .hms,
|
||||
timeZone: TimeZone = .current,
|
||||
locale: Locale = .current) -> String {
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(s))
|
||||
return timeString(from: date, format: format, timeZone: timeZone, locale: locale)
|
||||
}
|
||||
|
||||
/// 由毫秒级时间戳(字符串)转为时间字符串;非法输入返回空字符串
|
||||
public static func timeString(fromMillisecondsString msString: String,
|
||||
format: TimeFormat = .hms,
|
||||
timeZone: TimeZone = .current,
|
||||
locale: Locale = .current) -> String {
|
||||
guard let ms = Int64(msString) else { return "" }
|
||||
return timeString(fromMilliseconds: ms, format: format, timeZone: timeZone, locale: locale)
|
||||
}
|
||||
|
||||
/// 将 Date 转为 YYYY-MM-DD 格式的日期字符串
|
||||
public static func dateString(from date: Date, calendar: Calendar = .current) -> String {
|
||||
let formatter = DateFormatter()
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
return formatter.string(from: date)
|
||||
}
|
||||
|
||||
/// 计算从指定天数前到今天的时间范围(用于 API 日期参数)
|
||||
/// 使用 UTC 时区确保日期一致性
|
||||
/// 返回从 n 天前到今天(包括今天)的日期范围
|
||||
public static func daysAgoToTodayRange(days: Int, from now: Date = Date(), calendar: Calendar = .current) -> (start: String, end: String) {
|
||||
// 使用 UTC 时区来计算日期,确保与 dateString 方法一致
|
||||
var utcCalendar = Calendar(identifier: .gregorian)
|
||||
utcCalendar.timeZone = TimeZone(secondsFromGMT: 0)!
|
||||
|
||||
let startOfToday = utcCalendar.startOfDay(for: now)
|
||||
// 从 (days-1) 天前开始,这样包括今天一共是 days 天
|
||||
let startOfNDaysAgo = utcCalendar.date(byAdding: .day, value: -(days - 1), to: startOfToday) ?? now
|
||||
return (dateString(from: startOfNDaysAgo, calendar: utcCalendar), dateString(from: startOfToday, calendar: utcCalendar))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
public extension Int {
|
||||
var dollarStringFromCents: String {
|
||||
"$" + String(format: "%.2f", Double(self) / 100.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import Foundation
|
||||
import ServiceManagement
|
||||
|
||||
public protocol LaunchAtLoginService {
|
||||
var isEnabled: Bool { get }
|
||||
func setEnabled(_ enabled: Bool) -> Bool
|
||||
}
|
||||
|
||||
public final class DefaultLaunchAtLoginService: LaunchAtLoginService {
|
||||
public init() {}
|
||||
|
||||
public var isEnabled: Bool {
|
||||
SMAppService.mainApp.status == .enabled
|
||||
}
|
||||
|
||||
public func setEnabled(_ enabled: Bool) -> Bool {
|
||||
do {
|
||||
if enabled {
|
||||
if SMAppService.mainApp.status == .enabled {
|
||||
return true
|
||||
}
|
||||
try SMAppService.mainApp.register()
|
||||
return true
|
||||
} else {
|
||||
if SMAppService.mainApp.status != .enabled {
|
||||
return true
|
||||
}
|
||||
try SMAppService.mainApp.unregister()
|
||||
return true
|
||||
}
|
||||
} catch {
|
||||
print("Failed to \(enabled ? "enable" : "disable") launch at login: \(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@testable import VibeviewerCore
|
||||
import XCTest
|
||||
|
||||
final class VibeviewerCoreTests: XCTestCase {
|
||||
func testExample() {
|
||||
XCTAssertTrue(true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user