Skip to content

Commit 4c5d050

Browse files
committed
chore: release v0.1.1
1 parent 134838e commit 4c5d050

23 files changed

Lines changed: 246 additions & 41 deletions

‎CHANGELOG.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [v0.1.1] - 2026-05-21
9+
10+
### Added
11+
12+
- Added provider-list default model selection so Codex and Claude Code channels can switch their active model directly from the provider row.
13+
14+
### Changed
15+
16+
- Bundled Alibaba PuHuiTi in the desktop app resources and applied it consistently to the app shell, theme tokens, rolling numbers, and usage trend charts.
17+
- Tightened compact input vertical alignment for the refreshed provider controls.
18+
19+
### Fixed
20+
21+
- Disposed tracked usage log writers in infrastructure tests before temp-directory cleanup so Windows CI no longer leaves daily usage log files locked.
22+
823
## [v0.1.0] - 2026-05-21
924

1025
### Added

‎CodexSwitch.Tests/UiV2InfrastructureTests.cs‎

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public sealed class UiV2InfrastructureTests : IDisposable
1919
Path.GetTempPath(),
2020
"CodexSwitchTests",
2121
Guid.NewGuid().ToString("N"));
22+
private readonly List<UsageLogWriter> _usageLogWriters = [];
2223

2324
[Fact]
2425
public void EnsureValidDefaults_SelectsFirstProvider_WhenActiveProviderIsMissing()
@@ -364,7 +365,7 @@ public async Task ProxyHostService_StartAsync_StaysStopped_WhenProxyIsDisabled()
364365
await using var service = new ProxyHostService(
365366
new UsageMeter(calculator),
366367
calculator,
367-
new UsageLogWriter(paths),
368+
CreateUsageLogWriter(paths),
368369
new CodexConfigWriter(paths),
369370
new ClaudeCodeConfigWriter(paths),
370371
new ProviderAuthService(configStore, config, httpClient),
@@ -415,7 +416,7 @@ public async Task ProxyHostService_StopAsync_RestoresBakFiles()
415416
await using var service = new ProxyHostService(
416417
new UsageMeter(calculator),
417418
calculator,
418-
new UsageLogWriter(paths),
419+
CreateUsageLogWriter(paths),
419420
new CodexConfigWriter(paths),
420421
new ClaudeCodeConfigWriter(paths),
421422
new ProviderAuthService(configStore, config, authHttpClient),
@@ -467,7 +468,7 @@ public async Task ProxyHostService_StartAsync_ReusesLocalHealthConnection()
467468
await using var service = new ProxyHostService(
468469
new UsageMeter(calculator),
469470
calculator,
470-
new UsageLogWriter(paths),
471+
CreateUsageLogWriter(paths),
471472
new CodexConfigWriter(paths),
472473
new ClaudeCodeConfigWriter(paths),
473474
new ProviderAuthService(configStore, config, authHttpClient),
@@ -715,7 +716,7 @@ public async Task ProxyHostService_Messages_ProxiesAnthropicDirectRequest()
715716
await using var service = new ProxyHostService(
716717
meter,
717718
calculator,
718-
new UsageLogWriter(paths),
719+
CreateUsageLogWriter(paths),
719720
new CodexConfigWriter(paths),
720721
new ClaudeCodeConfigWriter(paths),
721722
new ProviderAuthService(configStore, config, authHttpClient),
@@ -816,7 +817,7 @@ public async Task ProxyHostService_Messages_ProxiesAnthropicStreamingResponse()
816817
await using var service = new ProxyHostService(
817818
meter,
818819
calculator,
819-
new UsageLogWriter(paths),
820+
CreateUsageLogWriter(paths),
820821
new CodexConfigWriter(paths),
821822
new ClaudeCodeConfigWriter(paths),
822823
new ProviderAuthService(configStore, config, authHttpClient),
@@ -914,7 +915,7 @@ public async Task ProxyHostService_Messages_ConvertsOpenAiChatProviderRequest()
914915
await using var service = new ProxyHostService(
915916
meter,
916917
calculator,
917-
new UsageLogWriter(paths),
918+
CreateUsageLogWriter(paths),
918919
new CodexConfigWriter(paths),
919920
new ClaudeCodeConfigWriter(paths),
920921
new ProviderAuthService(configStore, config, authHttpClient),
@@ -983,7 +984,7 @@ public async Task ProxyHostService_RestartAsync_PublishesStartingWithoutTransien
983984
await using var service = new ProxyHostService(
984985
new UsageMeter(calculator),
985986
calculator,
986-
new UsageLogWriter(paths),
987+
CreateUsageLogWriter(paths),
987988
new CodexConfigWriter(paths),
988989
new ClaudeCodeConfigWriter(paths),
989990
new ProviderAuthService(configStore, config, httpClient),
@@ -1048,7 +1049,7 @@ public async Task ProxyHostService_ReloadConfig_RoutesResponsesToUpdatedActivePr
10481049
await using var service = new ProxyHostService(
10491050
new UsageMeter(calculator),
10501051
calculator,
1051-
new UsageLogWriter(paths),
1052+
CreateUsageLogWriter(paths),
10521053
new CodexConfigWriter(paths),
10531054
new ClaudeCodeConfigWriter(paths),
10541055
new ProviderAuthService(configStore, config, authHttpClient),
@@ -1117,7 +1118,7 @@ public async Task ProxyHostService_ResponsesWebSocket_ProxiesRewrittenPayloadAnd
11171118
await using var service = new ProxyHostService(
11181119
meter,
11191120
calculator,
1120-
new UsageLogWriter(paths),
1121+
CreateUsageLogWriter(paths),
11211122
new CodexConfigWriter(paths),
11221123
new ClaudeCodeConfigWriter(paths),
11231124
new ProviderAuthService(configStore, config, authHttpClient),
@@ -1198,7 +1199,7 @@ public async Task ProxyHostService_ResponsesWebSocket_ReturnsErrorForUnsupported
11981199
await using var service = new ProxyHostService(
11991200
meter,
12001201
calculator,
1201-
new UsageLogWriter(paths),
1202+
CreateUsageLogWriter(paths),
12021203
new CodexConfigWriter(paths),
12031204
new ClaudeCodeConfigWriter(paths),
12041205
new ProviderAuthService(configStore, config, authHttpClient),
@@ -1284,7 +1285,7 @@ public async Task ProxyHostService_ResponsesWebSocket_RetriesOAuthUpstreamConnec
12841285
await using var service = new ProxyHostService(
12851286
meter,
12861287
calculator,
1287-
new UsageLogWriter(paths),
1288+
CreateUsageLogWriter(paths),
12881289
new CodexConfigWriter(paths),
12891290
new ClaudeCodeConfigWriter(paths),
12901291
new ProviderAuthService(new ConfigurationStore(paths), config, authHttpClient),
@@ -1387,7 +1388,7 @@ public void UsageLogItem_FromRecord_ShowsOutputTps()
13871388
public void UsageLogReader_AggregatesRequestsCostAndTokens()
13881389
{
13891390
var paths = CreatePaths("usage");
1390-
var writer = new UsageLogWriter(paths);
1391+
var writer = CreateUsageLogWriter(paths);
13911392
writer.Append(new UsageLogRecord
13921393
{
13931394
Timestamp = new DateTimeOffset(2026, 5, 12, 8, 15, 0, TimeSpan.Zero),
@@ -1450,7 +1451,7 @@ public void UsageLogReader_AggregatesRequestsCostAndTokens()
14501451
public void UsageLogReader_OutputTpsDurationUsesOutputRequestsOnly()
14511452
{
14521453
var paths = CreatePaths("usage-output-tps");
1453-
var writer = new UsageLogWriter(paths);
1454+
var writer = CreateUsageLogWriter(paths);
14541455
var timestamp = new DateTimeOffset(2026, 5, 12, 8, 15, 0, TimeSpan.Zero);
14551456
writer.Append(new UsageLogRecord
14561457
{
@@ -1655,7 +1656,7 @@ public void ProtocolAdapterCommon_ReportOutputActivity_UsesParsedDeltaContent()
16551656
public void UsageLogReader_UsesSelectedRangeAndDailyBuckets()
16561657
{
16571658
var paths = CreatePaths("usage-range");
1658-
var writer = new UsageLogWriter(paths);
1659+
var writer = CreateUsageLogWriter(paths);
16591660
var now = new DateTimeOffset(2026, 5, 13, 12, 0, 0, TimeSpan.Zero);
16601661
writer.Append(new UsageLogRecord
16611662
{
@@ -1707,7 +1708,7 @@ public void UsageLogWriter_WritesDailyPartitionedFiles()
17071708
{
17081709
var paths = CreatePaths("usage-partitioned-write");
17091710
var timestamp = new DateTimeOffset(2026, 5, 12, 12, 0, 0, TimeSpan.Zero);
1710-
var writer = new UsageLogWriter(paths);
1711+
var writer = CreateUsageLogWriter(paths);
17111712

17121713
writer.Append(new UsageLogRecord
17131714
{
@@ -1738,7 +1739,7 @@ public async Task UsageLogWriter_BufferedAppend_FlushesOnDispose()
17381739
{
17391740
var paths = CreatePaths("usage-buffered-write");
17401741
var timestamp = new DateTimeOffset(2026, 5, 12, 12, 0, 0, TimeSpan.Zero);
1741-
var writer = new UsageLogWriter(paths);
1742+
var writer = CreateUsageLogWriter(paths);
17421743

17431744
writer.AppendBuffered(new UsageLogRecord
17441745
{
@@ -1786,7 +1787,7 @@ public void UsageLogReader_ReadsPartitionedAndLegacyLogs()
17861787
legacyRecord,
17871788
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }) + Environment.NewLine);
17881789

1789-
var writer = new UsageLogWriter(paths);
1790+
var writer = CreateUsageLogWriter(paths);
17901791
writer.Append(new UsageLogRecord
17911792
{
17921793
Timestamp = now.AddHours(-1),
@@ -1812,7 +1813,7 @@ public void UsageLogReader_ReadsPartitionedAndLegacyLogs()
18121813
public void UsageLogReader_PaginatesRecentRowsWhileKeepingFullTotals()
18131814
{
18141815
var paths = CreatePaths("usage-recent-limit");
1815-
var writer = new UsageLogWriter(paths);
1816+
var writer = CreateUsageLogWriter(paths);
18161817
var now = new DateTimeOffset(2026, 5, 13, 12, 0, 0, TimeSpan.Zero);
18171818

18181819
for (var i = 0; i < 100; i++)
@@ -1856,7 +1857,7 @@ public void UsageLogReader_PaginatesRecentRowsWhileKeepingFullTotals()
18561857
public void UsageLogReader_FiltersBeforeRecentRowLimit()
18571858
{
18581859
var paths = CreatePaths("usage-filter-limit");
1859-
var writer = new UsageLogWriter(paths);
1860+
var writer = CreateUsageLogWriter(paths);
18601861
var now = new DateTimeOffset(2026, 5, 13, 12, 0, 0, TimeSpan.Zero);
18611862

18621863
for (var i = 0; i < 80; i++)
@@ -1914,7 +1915,7 @@ public void UsageLogReader_FiltersBeforeRecentRowLimit()
19141915
public void UsageLogReader_FiltersByClientAppBeforeTotals()
19151916
{
19161917
var paths = CreatePaths("usage-client-app-filter");
1917-
var writer = new UsageLogWriter(paths);
1918+
var writer = CreateUsageLogWriter(paths);
19181919
var now = new DateTimeOffset(2026, 5, 13, 12, 0, 0, TimeSpan.Zero);
19191920

19201921
writer.Append(new UsageLogRecord
@@ -2240,7 +2241,7 @@ public async Task ProviderRequestContext_CodexOAuthHeadersResolveChatGptAccountI
22402241
ActiveProviderId = provider.Id,
22412242
Providers = { provider }
22422243
};
2243-
var writer = new UsageLogWriter(paths);
2244+
var writer = CreateUsageLogWriter(paths);
22442245
try
22452246
{
22462247
var authService = new ProviderAuthService(new ConfigurationStore(paths), config, new HttpClient());
@@ -2420,6 +2421,9 @@ public async Task ProviderUsageQueryService_UsesSelectedOAuthAccountPlaceholders
24202421

24212422
public void Dispose()
24222423
{
2424+
foreach (var writer in _usageLogWriters)
2425+
writer.DisposeAsync().AsTask().GetAwaiter().GetResult();
2426+
24232427
if (Directory.Exists(_tempDirectory))
24242428
Directory.Delete(_tempDirectory, recursive: true);
24252429
}
@@ -2431,6 +2435,13 @@ private AppPaths CreatePaths(string scenario)
24312435
Path.Combine(_tempDirectory, scenario, "codex"));
24322436
}
24332437

2438+
private UsageLogWriter CreateUsageLogWriter(AppPaths paths)
2439+
{
2440+
var writer = new UsageLogWriter(paths);
2441+
_usageLogWriters.Add(writer);
2442+
return writer;
2443+
}
2444+
24342445
private static string WriteCodexSession(AppPaths paths, string relativePath, string modelProvider)
24352446
{
24362447
var path = Path.Combine(paths.CodexDirectory, relativePath.Replace('/', Path.DirectorySeparatorChar));
@@ -2529,7 +2540,7 @@ private static HttpResponseMessage CreateOpenAiResponsesSuccess()
25292540
};
25302541
}
25312542

2532-
private static ProxyHostService CreateProxyHostService(
2543+
private ProxyHostService CreateProxyHostService(
25332544
AppPaths paths,
25342545
AppConfig config,
25352546
UsageMeter meter,
@@ -2540,7 +2551,7 @@ private static ProxyHostService CreateProxyHostService(
25402551
return new ProxyHostService(
25412552
meter,
25422553
calculator,
2543-
new UsageLogWriter(paths),
2554+
CreateUsageLogWriter(paths),
25442555
new CodexConfigWriter(paths),
25452556
new ClaudeCodeConfigWriter(paths),
25462557
new ProviderAuthService(configStore, config, upstreamHttpClient),
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Alibaba PuHuiTi 3.0
2+
3+
Official site: https://www.alibabafonts.com/#/font
4+
Downloaded from: https://fonts.alibabadesign.com/AlibabaPuHuiTi-3.zip
5+
Retrieved: 2026-05-21
6+
7+
Bundled weights:
8+
- AlibabaPuHuiTi-3-55-Regular.ttf
9+
- AlibabaPuHuiTi-3-65-Medium.ttf
10+
- AlibabaPuHuiTi-3-75-SemiBold.ttf
11+
- AlibabaPuHuiTi-3-85-Bold.ttf
12+
13+
The download endpoint requires a Referer header from the official site.

‎CodexSwitch/Assets/i18n/en-US.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"providers.apiKey": "API Key",
148148
"providers.notLoggedIn": "Not logged in",
149149
"providers.currentAccount": "Current account: {0}",
150+
"providers.defaultModel": "Default model",
150151
"providers.edit": "Edit provider",
151152
"providers.delete": "Delete provider",
152153
"providers.disabled": "Disabled",
@@ -364,6 +365,7 @@
364365
"status.providerAdded": "Provider added.",
365366
"status.providerSaved": "Provider saved.",
366367
"status.providerRemoved": "Provider removed.",
368+
"status.providerDefaultModelSaved": "Default model updated.",
367369
"status.providerDisabled": "This channel is disabled and will not join request routing.",
368370
"status.oauthIncomplete": "Codex OAuth configuration is incomplete.",
369371
"status.oauthOpeningBrowser": "Opening browser to complete Codex OAuth login...",

‎CodexSwitch/Assets/i18n/ja-JP.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"providers.apiKey": "API Key",
148148
"providers.notLoggedIn": "未ログイン",
149149
"providers.currentAccount": "現在のアカウント: {0}",
150+
"providers.defaultModel": "デフォルトモデル",
150151
"providers.edit": "プロバイダーを編集",
151152
"providers.delete": "プロバイダーを削除",
152153
"providers.disabled": "無効",
@@ -323,6 +324,7 @@
323324
"status.providerAdded": "プロバイダーを追加しました。",
324325
"status.providerSaved": "プロバイダーを保存しました。",
325326
"status.providerRemoved": "プロバイダーを削除しました。",
327+
"status.providerDefaultModelSaved": "デフォルトモデルを更新しました。",
326328
"status.providerDisabled": "このチャネルは無効のため、リクエストルーティングには参加しません。",
327329
"status.oauthIncomplete": "Codex OAuth 設定が不完全です。",
328330
"status.oauthOpeningBrowser": "ブラウザーを開いて Codex OAuth ログインを完了します...",

‎CodexSwitch/Assets/i18n/zh-CN.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"providers.apiKey": "API Key",
148148
"providers.notLoggedIn": "未登录",
149149
"providers.currentAccount": "当前账户:{0}",
150+
"providers.defaultModel": "默认模型",
150151
"providers.edit": "编辑提供商",
151152
"providers.delete": "删除提供商",
152153
"providers.disabled": "已禁用",
@@ -323,6 +324,7 @@
323324
"status.providerAdded": "提供商已添加。",
324325
"status.providerSaved": "提供商已保存。",
325326
"status.providerRemoved": "供应商已删除。",
327+
"status.providerDefaultModelSaved": "默认模型已更新。",
326328
"status.providerDisabled": "该渠道已禁用,不会加入请求分配名单。",
327329
"status.oauthIncomplete": "Codex OAuth 配置不完整。",
328330
"status.oauthOpeningBrowser": "正在打开浏览器完成 Codex OAuth 登录...",

0 commit comments

Comments
 (0)