76 lines
2.6 KiB
Swift
76 lines
2.6 KiB
Swift
// AIAgentSkillLayout.swift
|
|
// OSGKeyboard · Shared
|
|
//
|
|
// Enabled clipboard skills (ordered) plus which export skills the user
|
|
// confirmed a companion Shortcut for. Missing storage hydrates to every
|
|
// built-in default skill; an explicit empty list is kept
|
|
// so turning every skill off is distinct from a fresh install.
|
|
|
|
import Foundation
|
|
|
|
public struct AIAgentSkillLayout: Codable, Equatable, Sendable {
|
|
public static let defaultEnabledIDs = AIClipboardSkillCatalog.catalog
|
|
.filter(\.isDefault)
|
|
.map(\.id)
|
|
|
|
/// Keyboard chip order. Unknown and duplicate IDs are dropped on sanitize.
|
|
public var enabledIDs: [String]
|
|
/// Export skills whose companion Shortcut the user marked as added.
|
|
public var confirmedShortcutIDs: [String]
|
|
|
|
public static let `default` = AIAgentSkillLayout(
|
|
enabledIDs: defaultEnabledIDs,
|
|
confirmedShortcutIDs: []
|
|
)
|
|
|
|
public init(enabledIDs: [String], confirmedShortcutIDs: [String]) {
|
|
self.enabledIDs = enabledIDs
|
|
self.confirmedShortcutIDs = confirmedShortcutIDs
|
|
}
|
|
|
|
public func isEnabled(_ id: String) -> Bool {
|
|
let canonical = AIClipboardSkillCatalog.canonicalID(for: id)
|
|
return enabledIDs.contains {
|
|
AIClipboardSkillCatalog.canonicalID(for: $0) == canonical
|
|
}
|
|
}
|
|
|
|
public func hasConfirmedShortcut(_ id: String) -> Bool {
|
|
confirmedShortcutIDs.contains(id)
|
|
}
|
|
|
|
/// Drops unknown IDs and duplicates. Shortcut setup is tracked separately
|
|
/// so bundled export skills can remain visible as installed defaults.
|
|
public func sanitized(
|
|
catalog: [AIClipboardSkill] = AIClipboardSkillCatalog.catalog
|
|
) -> AIAgentSkillLayout {
|
|
let known = Dictionary(uniqueKeysWithValues: catalog.map { ($0.id, $0) })
|
|
var seenEnabled = Set<String>()
|
|
let enabled = enabledIDs.compactMap { id -> String? in
|
|
let canonical = AIClipboardSkillCatalog.canonicalID(for: id)
|
|
guard known[canonical] != nil, seenEnabled.insert(canonical).inserted else {
|
|
return nil
|
|
}
|
|
return canonical
|
|
}
|
|
|
|
var seenConfirmed = Set<String>()
|
|
let confirmed = confirmedShortcutIDs.filter { id in
|
|
guard known[id]?.requiresShortcut == true else { return false }
|
|
return seenConfirmed.insert(id).inserted
|
|
}
|
|
|
|
return AIAgentSkillLayout(
|
|
enabledIDs: enabled,
|
|
confirmedShortcutIDs: confirmed
|
|
)
|
|
}
|
|
}
|
|
|
|
public enum AIAgentSkillEnableResult: Equatable, Sendable {
|
|
case enabled
|
|
case alreadyEnabled
|
|
case needsShortcut
|
|
case unknown
|
|
}
|