Skip to content

Commit 973ec70

Browse files
steipetePeter Steinberger
andauthored
refactor: derive remaining provider registries and correct authoring docs (#2686)
* refactor: derive config validation capabilities * refactor: derive provider log categories * refactor: derive menu metric capabilities * build: derive provider manifest order * fix: preserve provider bootstrap order * test: derive credential gatekeeper coverage * docs: document provider registration truth --------- Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
1 parent 0535e09 commit 973ec70

119 files changed

Lines changed: 415 additions & 420 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Scripts/regenerate-provider-manifests.sh

Lines changed: 26 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ IMPLEMENTATION_DIR="${ROOT_DIR}/Sources/CodexBar/Providers"
99
DESCRIPTOR_OUTPUT="${DESCRIPTOR_DIR}/ProviderManifest.swift"
1010
IMPLEMENTATION_OUTPUT="${IMPLEMENTATION_DIR}/Shared/ProviderImplementationManifest.swift"
1111
INSTANCE_ID_OUTPUT="${DESCRIPTOR_DIR}/ProviderInstanceIDAliases.generated.swift"
12+
PROVIDER_IDS_OUTPUT="${ROOT_DIR}/docs/provider-ids.md"
1213
MODE="${1:-write}"
1314

1415
case "$MODE" in
@@ -24,105 +25,17 @@ case "$MODE" in
2425
;;
2526
esac
2627

27-
# Canonical first-party bootstrap order. This single declaration generates both manifests and the
28-
# ProviderInstanceID aliases; provider types are discovered from their provider-owned declarations.
29-
PROVIDERS=(
30-
codex
31-
openai
32-
azureopenai
33-
claude
34-
clinepass
35-
cursor
36-
opencode
37-
opencodego
38-
alibaba
39-
alibabatokenplan
40-
qwencloud
41-
factory
42-
gemini
43-
antigravity
44-
copilot
45-
devin
46-
zai
47-
minimax
48-
manus
49-
kimi
50-
kilo
51-
kiro
52-
vertexai
53-
augment
54-
jetbrains
55-
moonshot
56-
amp
57-
t3chat
58-
ollama
59-
synthetic
60-
openrouter
61-
elevenlabs
62-
warp
63-
windsurf
64-
zed
65-
perplexity
66-
mimo
67-
doubao
68-
sakana
69-
abacus
70-
mistral
71-
deepseek
72-
deepinfra
73-
codebuff
74-
crof
75-
venice
76-
commandcode
77-
qoder
78-
stepfun
79-
bedrock
80-
grok
81-
groq
82-
llmproxy
83-
litellm
84-
deepgram
85-
poe
86-
chutes
87-
neuralwatt
88-
clawrouter
89-
longcat
90-
sub2api
91-
wayfinder
92-
zenmux
93-
aiand
94-
zoommate
95-
xai
96-
notion
97-
)
98-
99-
ENUM_PROVIDERS=()
28+
# UsageProvider is the canonical first-party bootstrap order. Provider types are discovered from
29+
# their provider-owned declarations; this parsed order generates both manifests and the aliases.
30+
PROVIDERS=()
10031
while IFS= read -r provider; do
101-
ENUM_PROVIDERS+=("$provider")
32+
PROVIDERS+=("$provider")
10233
done < <(sed -nE '/public enum UsageProvider:/,/^}/s/^[[:space:]]*case ([a-z0-9]+)$/\1/p' "$PROVIDERS_FILE")
10334

104-
contains_provider() {
105-
local needle="$1"
106-
shift
107-
local candidate
108-
for candidate in "$@"; do
109-
[[ "$candidate" == "$needle" ]] && return 0
110-
done
111-
return 1
112-
}
113-
114-
for provider in "${ENUM_PROVIDERS[@]}"; do
115-
if ! contains_provider "$provider" "${PROVIDERS[@]}"; then
116-
echo "error: UsageProvider '${provider}' is missing from the canonical PROVIDERS order in ${BASH_SOURCE[0]#${ROOT_DIR}/}" >&2
117-
exit 1
118-
fi
119-
done
120-
for provider in "${PROVIDERS[@]}"; do
121-
if ! contains_provider "$provider" "${ENUM_PROVIDERS[@]}"; then
122-
echo "error: canonical provider '${provider}' has no UsageProvider case in ${PROVIDERS_FILE#${ROOT_DIR}/}" >&2
123-
exit 1
124-
fi
125-
done
35+
if [[ "${#PROVIDERS[@]}" -eq 0 ]]; then
36+
echo "error: no UsageProvider cases found in ${PROVIDERS_FILE#${ROOT_DIR}/}" >&2
37+
exit 1
38+
fi
12639

12740
DESCRIPTOR_TYPES=()
12841
IMPLEMENTATION_TYPES=()
@@ -215,6 +128,22 @@ SWIFT
215128
SWIFT
216129
}
217130

131+
render_provider_ids() {
132+
cat <<'MARKDOWN'
133+
<!-- Generated by Scripts/regenerate-provider-manifests.sh. Do not edit by hand. -->
134+
135+
# Provider IDs
136+
137+
MARKDOWN
138+
local separator=""
139+
local provider
140+
for provider in "${PROVIDERS[@]}"; do
141+
printf '%s`%s`' "$separator" "$provider"
142+
separator=", "
143+
done
144+
printf '.\n'
145+
}
146+
218147
check_or_write() {
219148
local output="$1"
220149
local renderer="$2"
@@ -242,6 +171,7 @@ check_or_write() {
242171
check_or_write "$DESCRIPTOR_OUTPUT" render_descriptors
243172
check_or_write "$IMPLEMENTATION_OUTPUT" render_implementations
244173
check_or_write "$INSTANCE_ID_OUTPUT" render_instance_ids
174+
check_or_write "$PROVIDER_IDS_OUTPUT" render_provider_ids
245175
if [[ "$CHECK_ONLY" -eq 1 ]]; then
246176
echo "Provider manifests are current (${#PROVIDERS[@]} providers)"
247177
fi

Sources/CodexBar/CopilotTokenStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum CopilotTokenStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainCopilotTokenStore: CopilotTokenStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.copilotTokenStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.copilot, scope: "token-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "copilot-api-token"

Sources/CodexBar/CursorLoginRunner.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ final class CursorLoginRunner {
123123
private let accountChooser: AccountChooser?
124124
private let timeout: TimeInterval
125125
private let pollInterval: TimeInterval
126-
private let logger = CodexBarLog.logger(LogCategories.cursorLogin)
126+
private let logger = CodexBarLog.logger(LogCategories.provider(.cursor, scope: "login"))
127127

128128
static let authURL = URL(string: "https://authenticator.cursor.sh/")!
129129

Sources/CodexBar/KimiTokenStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum KimiTokenStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainKimiTokenStore: KimiTokenStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.kimiTokenStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.kimi, scope: "token-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "kimi-auth-token"

Sources/CodexBar/MiniMaxAPITokenStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum MiniMaxAPITokenStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainMiniMaxAPITokenStore: MiniMaxAPITokenStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.minimaxAPITokenStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.minimax, scope: "api-token-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "minimax-api-token"

Sources/CodexBar/MiniMaxCookieStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum MiniMaxCookieStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainMiniMaxCookieStore: MiniMaxCookieStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.minimaxCookieStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.minimax, scope: "cookie-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "minimax-cookie"

Sources/CodexBar/SettingsStore+MenuPreferences.swift

Lines changed: 31 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -201,112 +201,36 @@ extension SettingsStore {
201201
}
202202

203203
func menuBarMetricPreference(for provider: UsageProvider) -> MenuBarMetricPreference {
204-
if Self.isBalanceOnlyProvider(provider), provider != .mistral {
205-
return .automatic
206-
}
207-
if provider == .mistral {
208-
let raw = self.menuBarMetricPreferencesRaw[provider.rawValue] ?? ""
209-
let preference = MenuBarMetricPreference(rawValue: raw) ?? .automatic
210-
switch preference {
211-
case .automatic, .monthlyPlan:
212-
return preference
213-
case .primary, .secondary, .primaryAndSecondary, .tertiary, .extraUsage, .average:
214-
return .automatic
215-
}
216-
}
217-
if provider == .openrouter {
218-
let raw = self.menuBarMetricPreferencesRaw[provider.rawValue] ?? ""
219-
let preference = MenuBarMetricPreference(rawValue: raw) ?? .automatic
220-
switch preference {
221-
case .automatic, .primary:
222-
return preference
223-
case .secondary, .primaryAndSecondary, .average, .tertiary, .extraUsage, .monthlyPlan:
224-
return .automatic
225-
}
226-
}
227204
let raw = self.menuBarMetricPreferencesRaw[provider.rawValue] ?? ""
228205
let preference = MenuBarMetricPreference(rawValue: raw) ?? .automatic
229-
if preference == .average, !self.menuBarMetricSupportsAverage(for: provider) {
230-
return .automatic
231-
}
232-
if preference == .primaryAndSecondary, !self.menuBarMetricSupportsPrimaryAndSecondary(for: provider) {
233-
return .automatic
234-
}
235-
if preference == .tertiary, !self.menuBarMetricSupportsTertiary(for: provider) {
236-
return .automatic
237-
}
238-
if preference == .extraUsage, !self.menuBarMetricSupportsExtraUsage(for: provider) {
239-
return .automatic
240-
}
241-
if preference == .monthlyPlan {
242-
return .automatic
243-
}
244-
return preference
206+
return self.menuBarMetricSupports(preference, for: provider) ? preference : .automatic
245207
}
246208

247209
func setMenuBarMetricPreference(_ preference: MenuBarMetricPreference, for provider: UsageProvider) {
248-
if Self.isBalanceOnlyProvider(provider), provider != .mistral {
249-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
250-
return
251-
}
252-
if provider == .mistral {
253-
switch preference {
254-
case .automatic, .monthlyPlan:
255-
self.menuBarMetricPreferencesRaw[provider.rawValue] = preference.rawValue
256-
case .primary, .secondary, .primaryAndSecondary, .tertiary, .extraUsage, .average:
257-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
258-
}
259-
return
260-
}
261-
if provider == .openrouter {
262-
switch preference {
263-
case .automatic, .primary:
264-
self.menuBarMetricPreferencesRaw[provider.rawValue] = preference.rawValue
265-
case .secondary, .primaryAndSecondary, .average, .tertiary, .extraUsage, .monthlyPlan:
266-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
267-
}
268-
return
269-
}
270-
if preference == .primaryAndSecondary, !self.menuBarMetricSupportsPrimaryAndSecondary(for: provider) {
271-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
272-
return
273-
}
274-
if preference == .tertiary, !self.menuBarMetricSupportsTertiary(for: provider) {
275-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
276-
return
277-
}
278-
if preference == .extraUsage, !self.menuBarMetricSupportsExtraUsage(for: provider) {
279-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
280-
return
281-
}
282-
if preference == .monthlyPlan {
283-
self.menuBarMetricPreferencesRaw[provider.rawValue] = MenuBarMetricPreference.automatic.rawValue
284-
return
285-
}
286-
self.menuBarMetricPreferencesRaw[provider.rawValue] = preference.rawValue
210+
let resolved = self.menuBarMetricSupports(preference, for: provider) ? preference : .automatic
211+
self.menuBarMetricPreferencesRaw[provider.rawValue] = resolved.rawValue
287212
}
288213

289214
func menuBarMetricSupportsAverage(for provider: UsageProvider) -> Bool {
290-
provider == .gemini
215+
self.menuBarMetricCapabilities(for: provider).supports(.average)
291216
}
292217

293218
func menuBarMetricSupportsPrimaryAndSecondary(for provider: UsageProvider) -> Bool {
294-
provider == .codex || provider == .claude
219+
self.menuBarMetricCapabilities(for: provider).supports(.primaryAndSecondary)
295220
}
296221

297222
func menuBarMetricSupportsTertiary(for provider: UsageProvider) -> Bool {
298-
provider == .cursor || provider == .perplexity
223+
self.menuBarMetricCapabilities(for: provider).supports(.tertiary)
299224
}
300225

301226
func menuBarMetricSupportsTertiary(for provider: UsageProvider, snapshot: UsageSnapshot?) -> Bool {
302-
if provider == .cursor {
303-
return snapshot?.tertiary != nil
304-
}
305-
return self.menuBarMetricSupportsTertiary(for: provider)
227+
let capabilities = self.menuBarMetricCapabilities(for: provider)
228+
guard capabilities.supports(.tertiary) else { return false }
229+
return !capabilities.tertiaryRequiresWindow || snapshot?.tertiary != nil
306230
}
307231

308232
func menuBarMetricSupportsExtraUsage(for provider: UsageProvider) -> Bool {
309-
provider == .cursor || provider == .claude
233+
self.menuBarMetricCapabilities(for: provider).supports(.extraUsage)
310234
}
311235

312236
func menuBarMetricSupportsExtraUsage(for provider: UsageProvider, snapshot: UsageSnapshot?) -> Bool {
@@ -340,7 +264,26 @@ extension SettingsStore {
340264
self.resetTimesShowAbsolute ? .absolute : .countdown
341265
}
342266

343-
static func isBalanceOnlyProvider(_ provider: UsageProvider) -> Bool {
344-
ProviderDescriptorRegistry.descriptor(for: provider).metadata.balanceOnly
267+
private func menuBarMetricCapabilities(for provider: UsageProvider) -> ProviderMenuBarMetricCapabilities {
268+
ProviderDescriptorRegistry.descriptor(for: provider).menuBarMetrics
269+
}
270+
271+
private func menuBarMetricSupports(_ preference: MenuBarMetricPreference, for provider: UsageProvider) -> Bool {
272+
self.menuBarMetricCapabilities(for: provider).supports(preference.providerMetric)
273+
}
274+
}
275+
276+
extension MenuBarMetricPreference {
277+
fileprivate var providerMetric: ProviderMenuBarMetric {
278+
switch self {
279+
case .automatic: .automatic
280+
case .primary: .primary
281+
case .secondary: .secondary
282+
case .primaryAndSecondary: .primaryAndSecondary
283+
case .tertiary: .tertiary
284+
case .extraUsage: .extraUsage
285+
case .average: .average
286+
case .monthlyPlan: .monthlyPlan
287+
}
345288
}
346289
}

Sources/CodexBar/SyntheticTokenStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum SyntheticTokenStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainSyntheticTokenStore: SyntheticTokenStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.syntheticTokenStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.synthetic, scope: "token-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "synthetic-api-key"

Sources/CodexBar/UsageStore.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,9 @@ final class UsageStore {
313313
@ObservationIgnored let pluginApprovalStore = ProviderPluginApprovalStore()
314314
@ObservationIgnored let sessionQuotaNotifier: any SessionQuotaNotifying
315315
@ObservationIgnored let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)
316-
@ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)
316+
@ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.provider(.openai, scope: "web"))
317317
@ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)
318-
@ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)
318+
@ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.provider(.augment))
319319
@ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)
320320
@ObservationIgnored let adaptiveRefreshLogger = CodexBarLog.logger(LogCategories.adaptiveRefresh)
321321
@ObservationIgnored var openAIWebDebugLines: [String] = []

Sources/CodexBar/ZaiTokenStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ enum ZaiTokenStoreError: LocalizedError {
2222
}
2323

2424
struct KeychainZaiTokenStore: ZaiTokenStoring {
25-
private static let log = CodexBarLog.logger(LogCategories.zaiTokenStore)
25+
private static let log = CodexBarLog.logger(LogCategories.provider(.zai, scope: "token-store"))
2626

2727
private let service = "com.steipete.CodexBar"
2828
private let account = "zai-api-token"

0 commit comments

Comments
 (0)