Expand onboarding and adaptive keyboard intelligence

Add resilient usage analytics, OOBE gateway flows, clipboard semantic ranking, purchase recovery, style learning, and managed current-information search.
This commit is contained in:
Rocky
2026-08-22 16:33:18 +08:00
parent ac374631ae
commit e5a83843db
162 changed files with 23574 additions and 1013 deletions
@@ -13,11 +13,14 @@ public final class AIAgentSkillLayoutStore: ObservableObject {
@Published public private(set) var layout: AIAgentSkillLayout
@Published public private(set) var userCatalog: AIUserSkillCatalog
@Published public private(set) var officialCatalog: OfficialSkillCatalog
private let persistLayout: (AIAgentSkillLayout) -> Void
private let persistUserCatalog: (AIUserSkillCatalog) -> Void
private let loadLayout: () -> AIAgentSkillLayout
private let loadUserCatalog: () -> AIUserSkillCatalog
private let loadOfficialCatalog: () -> OfficialSkillCatalog
private let loadUILanguage: () -> AppUILanguage
public init(defaults: UserDefaults? = nil) {
if let defaults {
@@ -25,29 +28,41 @@ public final class AIAgentSkillLayoutStore: ObservableObject {
self.persistUserCatalog = { AppGroupStore(defaults: defaults).setAgentUserSkillCatalog($0) }
self.loadLayout = { AppGroupStore(defaults: defaults).agentSkillLayout }
self.persistLayout = { AppGroupStore(defaults: defaults).setAgentSkillLayout($0) }
self.loadOfficialCatalog = { AppGroupStore(defaults: defaults).officialSkillCatalog }
self.loadUILanguage = { AppGroupStore(defaults: defaults).uiLanguage }
} else {
self.loadUserCatalog = { AppGroupStore().agentUserSkillCatalog }
self.persistUserCatalog = { AppGroupStore().setAgentUserSkillCatalog($0) }
self.loadLayout = { AppGroupStore().agentSkillLayout }
self.persistLayout = { AppGroupStore().setAgentSkillLayout($0) }
self.loadOfficialCatalog = { AppGroupStore().officialSkillCatalog }
self.loadUILanguage = { AppGroupStore().uiLanguage }
}
self.userCatalog = self.loadUserCatalog()
self.officialCatalog = self.loadOfficialCatalog()
self.layout = self.loadLayout()
}
public func reload() {
userCatalog = loadUserCatalog()
officialCatalog = loadOfficialCatalog()
layout = loadLayout()
}
public var mergedCatalog: [AIClipboardSkill] {
AIClipboardSkillCatalog.all(userCatalog: userCatalog)
AIClipboardSkillCatalog.all(
officialCatalog: officialCatalog,
userCatalog: userCatalog,
uiLanguage: loadUILanguage()
)
}
public var enabledSkills: [AIClipboardSkill] {
AIClipboardSkillCatalog.visible(
enabledIDs: layout.enabledIDs,
userCatalog: userCatalog
officialCatalog: officialCatalog,
userCatalog: userCatalog,
uiLanguage: loadUILanguage()
)
}
@@ -62,14 +77,13 @@ public final class AIAgentSkillLayoutStore: ObservableObject {
@discardableResult
public func enable(_ id: String) -> AIAgentSkillEnableResult {
let current = layout.sanitized(catalog: mergedCatalog)
guard let skill = AIClipboardSkillCatalog.skill(id: id, userCatalog: userCatalog) else {
guard let skill = mergedCatalog.first(where: { $0.id == id }) else {
return .unknown
}
if current.isEnabled(id) { return .alreadyEnabled }
if skill.requiresShortcut, !current.hasConfirmedShortcut(id) {
return .needsShortcut
}
if current.isFull { return .full }
commitLayout(
AIAgentSkillLayout(
enabledIDs: current.enabledIDs + [id],
@@ -94,7 +108,7 @@ public final class AIAgentSkillLayoutStore: ObservableObject {
/// Marks the companion Shortcut as added, then tries to occupy a slot.
@discardableResult
public func confirmShortcutAndEnable(_ id: String) -> AIAgentSkillEnableResult {
guard let skill = AIClipboardSkillCatalog.skill(id: id, userCatalog: userCatalog),
guard let skill = mergedCatalog.first(where: { $0.id == id }),
skill.requiresShortcut else {
return .unknown
}