Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,14 @@ jobs:
echo "SWIFTLY_HOME_DIR=$SWIFTLY_HOME_DIR" >> "$GITHUB_ENV"
echo "SWIFTLY_BIN_DIR=$SWIFTLY_BIN_DIR" >> "$GITHUB_ENV"

swiftly install "$SWIFT_VERSION" --use --assume-yes --verify --post-install-file "$POST_INSTALL_SCRIPT"
for i in 1 2 3 4 5; do
if swiftly install "$SWIFT_VERSION" --use --assume-yes --verify --post-install-file "$POST_INSTALL_SCRIPT"; then
break
fi
if [ "$i" -eq 5 ]; then exit 1; fi
echo "swiftly install failed, retrying in 5s (attempt $i/5)..."
sleep 5
done
if [[ -s "$POST_INSTALL_SCRIPT" ]]; then
sudo apt-get update
sudo bash "$POST_INSTALL_SCRIPT"
Expand Down Expand Up @@ -475,7 +482,14 @@ jobs:
echo "SWIFTLY_HOME_DIR=$SWIFTLY_HOME_DIR" >> "$GITHUB_ENV"
echo "SWIFTLY_BIN_DIR=$SWIFTLY_BIN_DIR" >> "$GITHUB_ENV"

swiftly install "$SWIFT_VERSION" --use --assume-yes --verify --post-install-file "$POST_INSTALL_SCRIPT"
for i in 1 2 3 4 5; do
if swiftly install "$SWIFT_VERSION" --use --assume-yes --verify --post-install-file "$POST_INSTALL_SCRIPT"; then
break
fi
if [ "$i" -eq 5 ]; then exit 1; fi
echo "swiftly install failed, retrying in 5s (attempt $i/5)..."
sleep 5
done
if [[ -s "$POST_INSTALL_SCRIPT" ]]; then
sudo apt-get update
sudo bash "$POST_INSTALL_SCRIPT"
Expand Down
3 changes: 3 additions & 0 deletions Sources/CodexBar/Providers/Claude/ClaudeLoginFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ extension StatusItemController {
if case .success = result.outcome {
let metadata = self.store.metadata(for: .claude)
self.settings.setProviderEnabled(provider: .claude, metadata: metadata, enabled: true)
if self.settings.claudeUsageDataSource == .web {
self.settings.claudeUsageDataSource = .oauth

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep enabling Claude after a successful login

When Claude is disabled—the setup used by both login-flow tests and a normal sign-in onboarding path—replacing the unconditional setProviderEnabled(..., enabled: true) call with this source-only update leaves ProviderConfig.enabled false. Changing claudeUsageDataSource does not alter enablement, so the flow reports success and posts a notification while Claude remains hidden and is not refreshed; the new isProviderEnabledCached assertions consequently fail. Restore provider enablement independently of the selected source.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve a CLI fallback when OAuth reads are disabled

When “Disable Keychain access” or the no-prompt OAuth policy is enabled, claude auth login --claudeai can still succeed because it runs as an external CLI process, but this assignment then forces the provider into strict OAuth mode. ClaudeOAuthFetchStrategy cannot obtain the newly stored Keychain credential in that configuration, and its shouldFallback implementation only permits the working CLI strategy in .auto mode, so the refresh immediately fails despite the successful login. Keep a CLI fallback for this case rather than unconditionally selecting .oauth.

Useful? React with 👍 / 👎.

}
self.postLoginNotification(for: .claude)
return true
}
Expand Down
35 changes: 21 additions & 14 deletions Tests/CodexBarTests/ClaudeLoginFlowPolicyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,30 @@ struct ClaudeLoginFlowTests {
browserDetection: BrowserDetection(cacheTTL: 0),
settings: settings)

await withStatusItemControllerForTesting(store: store, settings: settings, fetcher: fetcher) { controller in
let didLogin = await controller.runClaudeLoginFlow { _, onPhaseChange in
onPhaseChange(.requesting)
await Task.yield()
onPhaseChange(.waitingBrowser)
await Task.yield()
return ClaudeLoginRunner.Result(
outcome: .success,
output: "Successfully logged in",
authLink: nil)
}
let controller = StatusItemController(
store: store,
settings: settings,
account: fetcher.loadAccountInfo(),
updater: DisabledUpdaterController(),
preferencesSelection: PreferencesSelection(),
statusBar: .system)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore status-item teardown in the login-flow test

On macOS test runs, this now constructs a controller against NSStatusBar.system for every source mode without calling releaseStatusItemsForTesting; the removed withStatusItemControllerForTesting helper deferred exactly that cleanup, and StatusItemController.deinit does not remove its status items. These iterations can therefore leave real status items registered and pollute later headless AppKit tests, so retain the helper or add equivalent deferred teardown.

AGENTS.md reference: AGENTS.md:L27-L27

Useful? React with 👍 / 👎.


#expect(didLogin)
#expect(controller.loginPhase == .idle)
let didLogin = await controller.runClaudeLoginFlow { _, onPhaseChange in
onPhaseChange(.requesting)
await Task.yield()
onPhaseChange(.waitingBrowser)
await Task.yield()
return ClaudeLoginRunner.Result(
outcome: .success,
output: "Successfully logged in",
authLink: nil)
}

#expect(settings.claudeUsageDataSource == source)
#expect(didLogin)
#expect(controller.loginPhase == .idle)

let expectedSource: ClaudeUsageDataSource = (source == .web) ? .oauth : source
#expect(settings.claudeUsageDataSource == expectedSource)
#expect(settings.isProviderEnabledCached(provider: .claude, metadataByProvider: registry.metadata))
}
}
Expand Down
Loading