github-issue-tower-defence-management 1.80.1 → 1.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +5 -2
  3. package/bin/adapter/entry-points/cli/index.js +1 -0
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/cli/projectConfig.js +20 -0
  6. package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
  7. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +48 -20
  8. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  9. package/bin/adapter/proxy/RateLimitCache.js +32 -4
  10. package/bin/adapter/proxy/RateLimitCache.js.map +1 -1
  11. package/bin/adapter/proxy/proxyEntry.js +1 -1
  12. package/bin/adapter/proxy/proxyEntry.js.map +1 -1
  13. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +3 -0
  14. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -1
  15. package/bin/domain/usecases/ChangeTargetPullRequestApprover.js +9 -5
  16. package/bin/domain/usecases/ChangeTargetPullRequestApprover.js.map +1 -1
  17. package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -0
  18. package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
  19. package/bin/domain/usecases/IssueRejectionEvaluator.js +1 -1
  20. package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -1
  21. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +1 -1
  22. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
  23. package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +1 -1
  24. package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
  25. package/bin/domain/usecases/StartPreparationUseCase.js +8 -0
  26. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/adapter/entry-points/cli/index.test.ts +18 -0
  29. package/src/adapter/entry-points/cli/index.ts +1 -0
  30. package/src/adapter/entry-points/cli/projectConfig.ts +32 -0
  31. package/src/adapter/entry-points/handlers/rotationOrderFileWriter.test.ts +4 -0
  32. package/src/adapter/proxy/RateLimitCache.test.ts +103 -0
  33. package/src/adapter/proxy/RateLimitCache.ts +44 -2
  34. package/src/adapter/proxy/proxyEntry.test.ts +17 -0
  35. package/src/adapter/proxy/proxyEntry.ts +5 -1
  36. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +14 -0
  37. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +3 -0
  38. package/src/domain/entities/ClaudeTokenUsage.ts +1 -0
  39. package/src/domain/usecases/ChangeTargetPullRequestApprover.test.ts +78 -0
  40. package/src/domain/usecases/ChangeTargetPullRequestApprover.ts +14 -4
  41. package/src/domain/usecases/HandleScheduledEventUseCase.ts +2 -0
  42. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +18 -0
  43. package/src/domain/usecases/IssueRejectionEvaluator.ts +1 -1
  44. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +61 -0
  45. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +2 -0
  46. package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +36 -0
  47. package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +2 -0
  48. package/src/domain/usecases/StartPreparationUseCase.test.ts +190 -0
  49. package/src/domain/usecases/StartPreparationUseCase.ts +14 -0
  50. package/types/adapter/entry-points/cli/projectConfig.d.ts +1 -0
  51. package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
  52. package/types/adapter/proxy/RateLimitCache.d.ts +4 -1
  53. package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -1
  54. package/types/adapter/proxy/proxyEntry.d.ts.map +1 -1
  55. package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -1
  56. package/types/domain/entities/ClaudeTokenUsage.d.ts +1 -0
  57. package/types/domain/entities/ClaudeTokenUsage.d.ts.map +1 -1
  58. package/types/domain/usecases/ChangeTargetPullRequestApprover.d.ts +1 -1
  59. package/types/domain/usecases/ChangeTargetPullRequestApprover.d.ts.map +1 -1
  60. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts +1 -0
  61. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
  62. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +1 -0
  63. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
  64. package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts +1 -0
  65. package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
  66. package/types/domain/usecases/StartPreparationUseCase.d.ts +2 -0
  67. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
@@ -1270,6 +1270,7 @@ describe('StartPreparationUseCase', () => {
1270
1270
  sevenDayUtilization: 0,
1271
1271
  blocked: false,
1272
1272
  rejected: false,
1273
+ blockedUntilEpoch: 0,
1273
1274
  modelWeeklyLimits: {},
1274
1275
  },
1275
1276
  {
@@ -1279,6 +1280,7 @@ describe('StartPreparationUseCase', () => {
1279
1280
  sevenDayUtilization: 0,
1280
1281
  blocked: false,
1281
1282
  rejected: false,
1283
+ blockedUntilEpoch: 0,
1282
1284
  modelWeeklyLimits: {},
1283
1285
  },
1284
1286
  ]);
@@ -1337,6 +1339,7 @@ describe('StartPreparationUseCase', () => {
1337
1339
  sevenDayUtilization: 0,
1338
1340
  blocked: false,
1339
1341
  rejected: false,
1342
+ blockedUntilEpoch: 0,
1340
1343
  modelWeeklyLimits: {},
1341
1344
  },
1342
1345
  {
@@ -1346,6 +1349,7 @@ describe('StartPreparationUseCase', () => {
1346
1349
  sevenDayUtilization: 0,
1347
1350
  blocked: false,
1348
1351
  rejected: false,
1352
+ blockedUntilEpoch: 0,
1349
1353
  modelWeeklyLimits: {},
1350
1354
  },
1351
1355
  ]);
@@ -2373,6 +2377,7 @@ describe('StartPreparationUseCase', () => {
2373
2377
  sevenDayUtilization: 0,
2374
2378
  blocked: false,
2375
2379
  rejected: false,
2380
+ blockedUntilEpoch: 0,
2376
2381
  modelWeeklyLimits: {},
2377
2382
  },
2378
2383
  ]);
@@ -2451,6 +2456,7 @@ describe('StartPreparationUseCase', () => {
2451
2456
  sevenDayUtilization: 0,
2452
2457
  blocked: false,
2453
2458
  rejected: false,
2459
+ blockedUntilEpoch: 0,
2454
2460
  modelWeeklyLimits: {},
2455
2461
  },
2456
2462
  {
@@ -2460,6 +2466,7 @@ describe('StartPreparationUseCase', () => {
2460
2466
  sevenDayUtilization: 0,
2461
2467
  blocked: false,
2462
2468
  rejected: false,
2469
+ blockedUntilEpoch: 0,
2463
2470
  modelWeeklyLimits: {},
2464
2471
  },
2465
2472
  ]);
@@ -2571,6 +2578,7 @@ describe('StartPreparationUseCase', () => {
2571
2578
  sevenDayUtilization: 0.7,
2572
2579
  blocked: false,
2573
2580
  rejected: false,
2581
+ blockedUntilEpoch: 0,
2574
2582
  modelWeeklyLimits: {
2575
2583
  seven_day_opus: {
2576
2584
  rejected: false,
@@ -2585,6 +2593,7 @@ describe('StartPreparationUseCase', () => {
2585
2593
  sevenDayUtilization: 0.2,
2586
2594
  blocked: false,
2587
2595
  rejected: false,
2596
+ blockedUntilEpoch: 0,
2588
2597
  modelWeeklyLimits: {
2589
2598
  seven_day_opus: {
2590
2599
  rejected: false,
@@ -2655,6 +2664,7 @@ describe('StartPreparationUseCase', () => {
2655
2664
  sevenDayUtilization: 0.7,
2656
2665
  blocked: false,
2657
2666
  rejected: false,
2667
+ blockedUntilEpoch: 0,
2658
2668
  modelWeeklyLimits: {
2659
2669
  seven_day_opus: {
2660
2670
  rejected: false,
@@ -2669,6 +2679,7 @@ describe('StartPreparationUseCase', () => {
2669
2679
  sevenDayUtilization: 0.2,
2670
2680
  blocked: false,
2671
2681
  rejected: false,
2682
+ blockedUntilEpoch: 0,
2672
2683
  modelWeeklyLimits: {
2673
2684
  seven_day_opus: {
2674
2685
  rejected: false,
@@ -2728,6 +2739,7 @@ describe('StartPreparationUseCase', () => {
2728
2739
  sevenDayUtilization: 0,
2729
2740
  blocked: true,
2730
2741
  rejected: false,
2742
+ blockedUntilEpoch: 0,
2731
2743
  modelWeeklyLimits: {},
2732
2744
  },
2733
2745
  {
@@ -2737,6 +2749,73 @@ describe('StartPreparationUseCase', () => {
2737
2749
  sevenDayUtilization: 0,
2738
2750
  blocked: false,
2739
2751
  rejected: false,
2752
+ blockedUntilEpoch: 0,
2753
+ modelWeeklyLimits: {},
2754
+ },
2755
+ ]);
2756
+
2757
+ await useCase.run({
2758
+ projectUrl: 'https://github.com/user/repo',
2759
+ defaultAgentName: 'agent1',
2760
+ defaultLlmModelName: 'claude-opus',
2761
+ fallbackLlmModelName: null,
2762
+ defaultLlmAgentName: null,
2763
+ configFilePath: '/path/to/config.yml',
2764
+ maximumPreparingIssuesCount: null,
2765
+ utilizationPercentageThreshold: 90,
2766
+ allowedIssueAuthors: null,
2767
+ codexHomeCandidates: null,
2768
+ allowIssueCacheMinutes: 0,
2769
+ labelsAsLlmAgentName: null,
2770
+ });
2771
+
2772
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2773
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toEqual({
2774
+ env: {
2775
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-ok',
2776
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2777
+ },
2778
+ });
2779
+ });
2780
+
2781
+ it('should exclude a token whose cooldown has not yet lapsed from rotation', async () => {
2782
+ const awaitingIssue = createMockIssue({
2783
+ url: 'url1',
2784
+ title: 'Issue 1',
2785
+ labels: ['category:impl'],
2786
+ status: 'Awaiting Workspace',
2787
+ number: 1,
2788
+ itemId: 'item-1',
2789
+ });
2790
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2791
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2792
+ createMockStoryObjectMap([awaitingIssue]),
2793
+ );
2794
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2795
+ stdout: '',
2796
+ stderr: '',
2797
+ exitCode: 0,
2798
+ });
2799
+ const nowEpochSeconds = Math.floor(Date.now() / 1000);
2800
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2801
+ {
2802
+ name: 'token-cooldown',
2803
+ token: 'token-cooldown',
2804
+ fiveHourUtilization: 0.05,
2805
+ sevenDayUtilization: 0,
2806
+ blocked: false,
2807
+ rejected: false,
2808
+ blockedUntilEpoch: nowEpochSeconds + 90,
2809
+ modelWeeklyLimits: {},
2810
+ },
2811
+ {
2812
+ name: 'token-ok',
2813
+ token: 'token-ok',
2814
+ fiveHourUtilization: 0.5,
2815
+ sevenDayUtilization: 0,
2816
+ blocked: false,
2817
+ rejected: false,
2818
+ blockedUntilEpoch: 0,
2740
2819
  modelWeeklyLimits: {},
2741
2820
  },
2742
2821
  ]);
@@ -2791,6 +2870,7 @@ describe('StartPreparationUseCase', () => {
2791
2870
  sevenDayUtilization: 0,
2792
2871
  blocked: true,
2793
2872
  rejected: false,
2873
+ blockedUntilEpoch: 0,
2794
2874
  modelWeeklyLimits: {},
2795
2875
  },
2796
2876
  {
@@ -2800,6 +2880,7 @@ describe('StartPreparationUseCase', () => {
2800
2880
  sevenDayUtilization: 0,
2801
2881
  blocked: true,
2802
2882
  rejected: false,
2883
+ blockedUntilEpoch: 0,
2803
2884
  modelWeeklyLimits: {},
2804
2885
  },
2805
2886
  ]);
@@ -2860,6 +2941,7 @@ describe('StartPreparationUseCase', () => {
2860
2941
  sevenDayUtilization: 0,
2861
2942
  blocked: false,
2862
2943
  rejected: false,
2944
+ blockedUntilEpoch: 0,
2863
2945
  modelWeeklyLimits: {},
2864
2946
  },
2865
2947
  {
@@ -2869,6 +2951,7 @@ describe('StartPreparationUseCase', () => {
2869
2951
  sevenDayUtilization: 0,
2870
2952
  blocked: false,
2871
2953
  rejected: false,
2954
+ blockedUntilEpoch: 0,
2872
2955
  modelWeeklyLimits: {},
2873
2956
  },
2874
2957
  ]);
@@ -2948,6 +3031,7 @@ describe('StartPreparationUseCase', () => {
2948
3031
  sevenDayUtilization: 0.5,
2949
3032
  blocked: false,
2950
3033
  rejected: false,
3034
+ blockedUntilEpoch: 0,
2951
3035
  modelWeeklyLimits: {
2952
3036
  seven_day_opus: {
2953
3037
  rejected: false,
@@ -2962,6 +3046,7 @@ describe('StartPreparationUseCase', () => {
2962
3046
  sevenDayUtilization: 0.1,
2963
3047
  blocked: false,
2964
3048
  rejected: false,
3049
+ blockedUntilEpoch: 0,
2965
3050
  modelWeeklyLimits: {
2966
3051
  seven_day_opus: {
2967
3052
  rejected: false,
@@ -2976,6 +3061,7 @@ describe('StartPreparationUseCase', () => {
2976
3061
  sevenDayUtilization: 0.7,
2977
3062
  blocked: false,
2978
3063
  rejected: false,
3064
+ blockedUntilEpoch: 0,
2979
3065
  modelWeeklyLimits: {
2980
3066
  seven_day_opus: {
2981
3067
  rejected: false,
@@ -3040,6 +3126,7 @@ describe('StartPreparationUseCase', () => {
3040
3126
  sevenDayUtilization: 0.9,
3041
3127
  blocked: false,
3042
3128
  rejected: false,
3129
+ blockedUntilEpoch: 0,
3043
3130
  modelWeeklyLimits: {},
3044
3131
  },
3045
3132
  ]);
@@ -3094,6 +3181,7 @@ describe('StartPreparationUseCase', () => {
3094
3181
  sevenDayUtilization: 0,
3095
3182
  blocked: false,
3096
3183
  rejected: true,
3184
+ blockedUntilEpoch: 0,
3097
3185
  modelWeeklyLimits: {},
3098
3186
  },
3099
3187
  {
@@ -3103,6 +3191,7 @@ describe('StartPreparationUseCase', () => {
3103
3191
  sevenDayUtilization: 0,
3104
3192
  blocked: false,
3105
3193
  rejected: false,
3194
+ blockedUntilEpoch: 0,
3106
3195
  modelWeeklyLimits: {},
3107
3196
  },
3108
3197
  ]);
@@ -3157,6 +3246,7 @@ describe('StartPreparationUseCase', () => {
3157
3246
  sevenDayUtilization: 0,
3158
3247
  blocked: false,
3159
3248
  rejected: false,
3249
+ blockedUntilEpoch: 0,
3160
3250
  modelWeeklyLimits: {},
3161
3251
  },
3162
3252
  {
@@ -3166,6 +3256,7 @@ describe('StartPreparationUseCase', () => {
3166
3256
  sevenDayUtilization: 0,
3167
3257
  blocked: false,
3168
3258
  rejected: false,
3259
+ blockedUntilEpoch: 0,
3169
3260
  modelWeeklyLimits: {},
3170
3261
  },
3171
3262
  ]);
@@ -3220,6 +3311,7 @@ describe('StartPreparationUseCase', () => {
3220
3311
  sevenDayUtilization: 0,
3221
3312
  blocked: false,
3222
3313
  rejected: true,
3314
+ blockedUntilEpoch: 0,
3223
3315
  modelWeeklyLimits: {},
3224
3316
  },
3225
3317
  {
@@ -3229,6 +3321,7 @@ describe('StartPreparationUseCase', () => {
3229
3321
  sevenDayUtilization: 0,
3230
3322
  blocked: false,
3231
3323
  rejected: false,
3324
+ blockedUntilEpoch: 0,
3232
3325
  modelWeeklyLimits: {},
3233
3326
  },
3234
3327
  ]);
@@ -3283,6 +3376,7 @@ describe('StartPreparationUseCase', () => {
3283
3376
  sevenDayUtilization: 0,
3284
3377
  blocked: false,
3285
3378
  rejected: true,
3379
+ blockedUntilEpoch: 0,
3286
3380
  modelWeeklyLimits: {},
3287
3381
  },
3288
3382
  {
@@ -3292,6 +3386,7 @@ describe('StartPreparationUseCase', () => {
3292
3386
  sevenDayUtilization: 0,
3293
3387
  blocked: false,
3294
3388
  rejected: true,
3389
+ blockedUntilEpoch: 0,
3295
3390
  modelWeeklyLimits: {},
3296
3391
  },
3297
3392
  ]);
@@ -3398,6 +3493,7 @@ describe('StartPreparationUseCase', () => {
3398
3493
  sevenDayUtilization: 0,
3399
3494
  blocked: false,
3400
3495
  rejected: false,
3496
+ blockedUntilEpoch: 0,
3401
3497
  modelWeeklyLimits: {
3402
3498
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
3403
3499
  },
@@ -3409,6 +3505,7 @@ describe('StartPreparationUseCase', () => {
3409
3505
  sevenDayUtilization: 0,
3410
3506
  blocked: false,
3411
3507
  rejected: false,
3508
+ blockedUntilEpoch: 0,
3412
3509
  modelWeeklyLimits: {},
3413
3510
  },
3414
3511
  ]);
@@ -3464,6 +3561,7 @@ describe('StartPreparationUseCase', () => {
3464
3561
  sevenDayUtilization: 0,
3465
3562
  blocked: false,
3466
3563
  rejected: false,
3564
+ blockedUntilEpoch: 0,
3467
3565
  modelWeeklyLimits: {
3468
3566
  seven_day_sonnet: { rejected: false, resetsAt: pastReset },
3469
3567
  },
@@ -3475,6 +3573,7 @@ describe('StartPreparationUseCase', () => {
3475
3573
  sevenDayUtilization: 0,
3476
3574
  blocked: false,
3477
3575
  rejected: false,
3576
+ blockedUntilEpoch: 0,
3478
3577
  modelWeeklyLimits: {},
3479
3578
  },
3480
3579
  ]);
@@ -3530,6 +3629,7 @@ describe('StartPreparationUseCase', () => {
3530
3629
  sevenDayUtilization: 0,
3531
3630
  blocked: false,
3532
3631
  rejected: false,
3632
+ blockedUntilEpoch: 0,
3533
3633
  modelWeeklyLimits: {
3534
3634
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
3535
3635
  },
@@ -3541,6 +3641,7 @@ describe('StartPreparationUseCase', () => {
3541
3641
  sevenDayUtilization: 0,
3542
3642
  blocked: false,
3543
3643
  rejected: false,
3644
+ blockedUntilEpoch: 0,
3544
3645
  modelWeeklyLimits: {},
3545
3646
  },
3546
3647
  ]);
@@ -3596,6 +3697,7 @@ describe('StartPreparationUseCase', () => {
3596
3697
  sevenDayUtilization: 0,
3597
3698
  blocked: false,
3598
3699
  rejected: false,
3700
+ blockedUntilEpoch: 0,
3599
3701
  modelWeeklyLimits: {
3600
3702
  seven_day: { rejected: true, resetsAt: futureReset },
3601
3703
  },
@@ -3607,6 +3709,7 @@ describe('StartPreparationUseCase', () => {
3607
3709
  sevenDayUtilization: 0,
3608
3710
  blocked: false,
3609
3711
  rejected: false,
3712
+ blockedUntilEpoch: 0,
3610
3713
  modelWeeklyLimits: {},
3611
3714
  },
3612
3715
  ]);
@@ -3662,6 +3765,7 @@ describe('StartPreparationUseCase', () => {
3662
3765
  sevenDayUtilization: 0.1,
3663
3766
  blocked: false,
3664
3767
  rejected: false,
3768
+ blockedUntilEpoch: 0,
3665
3769
  modelWeeklyLimits: {
3666
3770
  seven_day_opus: {
3667
3771
  rejected: false,
@@ -3676,6 +3780,7 @@ describe('StartPreparationUseCase', () => {
3676
3780
  sevenDayUtilization: 0.1,
3677
3781
  blocked: false,
3678
3782
  rejected: false,
3783
+ blockedUntilEpoch: 0,
3679
3784
  modelWeeklyLimits: {
3680
3785
  seven_day_opus: {
3681
3786
  rejected: false,
@@ -3736,6 +3841,7 @@ describe('StartPreparationUseCase', () => {
3736
3841
  sevenDayUtilization: 0.1,
3737
3842
  blocked: true,
3738
3843
  rejected: false,
3844
+ blockedUntilEpoch: 0,
3739
3845
  modelWeeklyLimits: {
3740
3846
  seven_day_opus: {
3741
3847
  rejected: false,
@@ -3750,6 +3856,7 @@ describe('StartPreparationUseCase', () => {
3750
3856
  sevenDayUtilization: 0.1,
3751
3857
  blocked: false,
3752
3858
  rejected: false,
3859
+ blockedUntilEpoch: 0,
3753
3860
  modelWeeklyLimits: {
3754
3861
  seven_day_opus: {
3755
3862
  rejected: false,
@@ -3820,6 +3927,7 @@ describe('StartPreparationUseCase', () => {
3820
3927
  sevenDayUtilization: 0.1,
3821
3928
  blocked: false,
3822
3929
  rejected: false,
3930
+ blockedUntilEpoch: 0,
3823
3931
  modelWeeklyLimits: {},
3824
3932
  },
3825
3933
  {
@@ -3829,6 +3937,7 @@ describe('StartPreparationUseCase', () => {
3829
3937
  sevenDayUtilization: 0.1,
3830
3938
  blocked: false,
3831
3939
  rejected: false,
3940
+ blockedUntilEpoch: 0,
3832
3941
  modelWeeklyLimits: {
3833
3942
  seven_day_opus: {
3834
3943
  rejected: false,
@@ -3907,6 +4016,7 @@ describe('StartPreparationUseCase', () => {
3907
4016
  sevenDayUtilization: 0.1,
3908
4017
  blocked: false,
3909
4018
  rejected: false,
4019
+ blockedUntilEpoch: 0,
3910
4020
  modelWeeklyLimits: {
3911
4021
  seven_day: {
3912
4022
  rejected: false,
@@ -3921,6 +4031,7 @@ describe('StartPreparationUseCase', () => {
3921
4031
  sevenDayUtilization: 0.1,
3922
4032
  blocked: false,
3923
4033
  rejected: false,
4034
+ blockedUntilEpoch: 0,
3924
4035
  modelWeeklyLimits: {
3925
4036
  seven_day: {
3926
4037
  rejected: false,
@@ -3935,6 +4046,7 @@ describe('StartPreparationUseCase', () => {
3935
4046
  sevenDayUtilization: 0.1,
3936
4047
  blocked: false,
3937
4048
  rejected: false,
4049
+ blockedUntilEpoch: 0,
3938
4050
  modelWeeklyLimits: {
3939
4051
  seven_day: {
3940
4052
  rejected: false,
@@ -3999,6 +4111,7 @@ describe('StartPreparationUseCase', () => {
3999
4111
  sevenDayUtilization: 0.1,
4000
4112
  blocked: false,
4001
4113
  rejected: false,
4114
+ blockedUntilEpoch: 0,
4002
4115
  modelWeeklyLimits: {
4003
4116
  seven_day: { rejected: false, resetsAt: sharedResetsAt },
4004
4117
  },
@@ -4010,6 +4123,7 @@ describe('StartPreparationUseCase', () => {
4010
4123
  sevenDayUtilization: 0.1,
4011
4124
  blocked: false,
4012
4125
  rejected: false,
4126
+ blockedUntilEpoch: 0,
4013
4127
  modelWeeklyLimits: {
4014
4128
  seven_day: { rejected: false, resetsAt: sharedResetsAt },
4015
4129
  },
@@ -4068,6 +4182,7 @@ describe('StartPreparationUseCase', () => {
4068
4182
  sevenDayUtilization: 0.1,
4069
4183
  blocked: false,
4070
4184
  rejected: false,
4185
+ blockedUntilEpoch: 0,
4071
4186
  modelWeeklyLimits: {
4072
4187
  seven_day_opus: { rejected: false, resetsAt: sharedResetsAt },
4073
4188
  },
@@ -4079,6 +4194,7 @@ describe('StartPreparationUseCase', () => {
4079
4194
  sevenDayUtilization: 0.1,
4080
4195
  blocked: false,
4081
4196
  rejected: false,
4197
+ blockedUntilEpoch: 0,
4082
4198
  modelWeeklyLimits: {
4083
4199
  seven_day_opus: { rejected: false, resetsAt: sharedResetsAt },
4084
4200
  },
@@ -4272,6 +4388,7 @@ describe('StartPreparationUseCase', () => {
4272
4388
  sevenDayUtilization: 0,
4273
4389
  blocked: false,
4274
4390
  rejected: false,
4391
+ blockedUntilEpoch: 0,
4275
4392
  modelWeeklyLimits: {
4276
4393
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
4277
4394
  },
@@ -4337,6 +4454,7 @@ describe('StartPreparationUseCase', () => {
4337
4454
  sevenDayUtilization: 0,
4338
4455
  blocked: false,
4339
4456
  rejected: false,
4457
+ blockedUntilEpoch: 0,
4340
4458
  modelWeeklyLimits: {
4341
4459
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
4342
4460
  },
@@ -4390,6 +4508,7 @@ describe('StartPreparationUseCase', () => {
4390
4508
  sevenDayUtilization: 0,
4391
4509
  blocked: false,
4392
4510
  rejected: false,
4511
+ blockedUntilEpoch: 0,
4393
4512
  modelWeeklyLimits: {
4394
4513
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
4395
4514
  seven_day: { rejected: true, resetsAt: futureReset },
@@ -4449,6 +4568,7 @@ describe('StartPreparationUseCase', () => {
4449
4568
  sevenDayUtilization: 0,
4450
4569
  blocked: false,
4451
4570
  rejected: false,
4571
+ blockedUntilEpoch: 0,
4452
4572
  modelWeeklyLimits: {},
4453
4573
  },
4454
4574
  ]);
@@ -4500,6 +4620,7 @@ describe('StartPreparationUseCase', () => {
4500
4620
  sevenDayUtilization: 0,
4501
4621
  blocked: false,
4502
4622
  rejected: false,
4623
+ blockedUntilEpoch: 0,
4503
4624
  modelWeeklyLimits: {
4504
4625
  seven_day_sonnet: { rejected: true, resetsAt: futureReset },
4505
4626
  },
@@ -4553,6 +4674,7 @@ describe('StartPreparationUseCase', () => {
4553
4674
  sevenDayUtilization: 0,
4554
4675
  blocked: false,
4555
4676
  rejected: false,
4677
+ blockedUntilEpoch: 0,
4556
4678
  modelWeeklyLimits: {},
4557
4679
  },
4558
4680
  ]);
@@ -4612,6 +4734,7 @@ describe('StartPreparationUseCase', () => {
4612
4734
  sevenDayUtilization: 0.9,
4613
4735
  blocked: false,
4614
4736
  rejected: false,
4737
+ blockedUntilEpoch: 0,
4615
4738
  modelWeeklyLimits: {},
4616
4739
  },
4617
4740
  ]);
@@ -4665,6 +4788,7 @@ describe('StartPreparationUseCase', () => {
4665
4788
  sevenDayUtilization: 0.9,
4666
4789
  blocked: false,
4667
4790
  rejected: false,
4791
+ blockedUntilEpoch: 0,
4668
4792
  modelWeeklyLimits: {},
4669
4793
  },
4670
4794
  ]);
@@ -4718,6 +4842,7 @@ describe('StartPreparationUseCase', () => {
4718
4842
  sevenDayUtilization: 0.9,
4719
4843
  blocked: false,
4720
4844
  rejected: false,
4845
+ blockedUntilEpoch: 0,
4721
4846
  modelWeeklyLimits: {},
4722
4847
  },
4723
4848
  {
@@ -4727,6 +4852,7 @@ describe('StartPreparationUseCase', () => {
4727
4852
  sevenDayUtilization: 0.1,
4728
4853
  blocked: false,
4729
4854
  rejected: false,
4855
+ blockedUntilEpoch: 0,
4730
4856
  modelWeeklyLimits: {},
4731
4857
  },
4732
4858
  ]);
@@ -4815,6 +4941,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4815
4941
  sevenDayUtilization: 0.8,
4816
4942
  blocked: false,
4817
4943
  rejected: false,
4944
+ blockedUntilEpoch: 0,
4818
4945
  modelWeeklyLimits: {
4819
4946
  seven_day: {
4820
4947
  rejected: false,
@@ -4829,6 +4956,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4829
4956
  sevenDayUtilization: 0.1,
4830
4957
  blocked: false,
4831
4958
  rejected: false,
4959
+ blockedUntilEpoch: 0,
4832
4960
  modelWeeklyLimits: {
4833
4961
  seven_day: {
4834
4962
  rejected: false,
@@ -4843,6 +4971,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4843
4971
  sevenDayUtilization: 0,
4844
4972
  blocked: true,
4845
4973
  rejected: false,
4974
+ blockedUntilEpoch: 0,
4846
4975
  modelWeeklyLimits: {},
4847
4976
  },
4848
4977
  ];
@@ -4864,6 +4993,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4864
4993
  sevenDayUtilization: 0,
4865
4994
  blocked: false,
4866
4995
  rejected: false,
4996
+ blockedUntilEpoch: 0,
4867
4997
  modelWeeklyLimits: {},
4868
4998
  },
4869
4999
  ];
@@ -4883,6 +5013,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4883
5013
  sevenDayUtilization: 0,
4884
5014
  blocked: false,
4885
5015
  rejected: false,
5016
+ blockedUntilEpoch: 0,
4886
5017
  modelWeeklyLimits: {},
4887
5018
  },
4888
5019
  ];
@@ -4903,6 +5034,7 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4903
5034
  sevenDayUtilization: 0,
4904
5035
  blocked: false,
4905
5036
  rejected: false,
5037
+ blockedUntilEpoch: 0,
4906
5038
  modelWeeklyLimits: {},
4907
5039
  },
4908
5040
  ];
@@ -4914,6 +5046,64 @@ describe('StartPreparationUseCase.buildRotationOrder', () => {
4914
5046
  expect(result[0].rejected).toBe(false);
4915
5047
  expect(result[0].fiveHourUtilization).toBe(0.9);
4916
5048
  });
5049
+
5050
+ it('excludes a token whose blockedUntilEpoch is in the future and marks it cooldownExcluded', () => {
5051
+ const nowEpochSeconds = Math.floor(Date.now() / 1000);
5052
+ const tokenUsages: ClaudeTokenUsage[] = [
5053
+ {
5054
+ name: 'cooling-down',
5055
+ token: 'sk-ant-cooldown',
5056
+ fiveHourUtilization: 0.1,
5057
+ sevenDayUtilization: 0,
5058
+ blocked: false,
5059
+ rejected: false,
5060
+ blockedUntilEpoch: nowEpochSeconds + 90,
5061
+ modelWeeklyLimits: {},
5062
+ },
5063
+ {
5064
+ name: 'available',
5065
+ token: 'sk-ant-available',
5066
+ fiveHourUtilization: 0.2,
5067
+ sevenDayUtilization: 0,
5068
+ blocked: false,
5069
+ rejected: false,
5070
+ blockedUntilEpoch: 0,
5071
+ modelWeeklyLimits: {},
5072
+ },
5073
+ ];
5074
+
5075
+ const result = useCase.buildRotationOrder(tokenUsages, 90, null);
5076
+
5077
+ expect(result[0].name).toBe('available');
5078
+ const cooling = result.find((entry) => entry.name === 'cooling-down');
5079
+ expect(cooling?.cooldownExcluded).toBe(true);
5080
+ expect(cooling?.blocked).toBe(false);
5081
+ expect(cooling?.rejected).toBe(false);
5082
+ expect(cooling?.thresholdExcluded).toBe(false);
5083
+ });
5084
+
5085
+ it('selects a token again once its cooldown has lapsed', () => {
5086
+ const nowEpochSeconds = Math.floor(Date.now() / 1000);
5087
+ const tokenUsages: ClaudeTokenUsage[] = [
5088
+ {
5089
+ name: 'lapsed-cooldown',
5090
+ token: 'sk-ant-lapsed',
5091
+ fiveHourUtilization: 0.1,
5092
+ sevenDayUtilization: 0,
5093
+ blocked: false,
5094
+ rejected: false,
5095
+ blockedUntilEpoch: nowEpochSeconds - 1,
5096
+ modelWeeklyLimits: {},
5097
+ },
5098
+ ];
5099
+
5100
+ const result = useCase.buildRotationOrder(tokenUsages, 90, null);
5101
+
5102
+ expect(result).toHaveLength(1);
5103
+ expect(result[0].name).toBe('lapsed-cooldown');
5104
+ expect(result[0].cooldownExcluded).toBe(false);
5105
+ expect(result[0].thresholdExcluded).toBe(false);
5106
+ });
4917
5107
  });
4918
5108
 
4919
5109
  describe('StartPreparationUseCase.getTokenConcurrentLimit', () => {
@@ -19,6 +19,7 @@ export type RotationOrderEntry = {
19
19
  blocked: boolean;
20
20
  rejected: boolean;
21
21
  thresholdExcluded: boolean;
22
+ cooldownExcluded: boolean;
22
23
  };
23
24
 
24
25
  export class StartPreparationUseCase {
@@ -45,6 +46,11 @@ export class StartPreparationUseCase {
45
46
  return 'seven_day';
46
47
  };
47
48
 
49
+ private isWithinCooldown = (
50
+ usage: ClaudeTokenUsage,
51
+ nowEpochSeconds: number,
52
+ ): boolean => usage.blockedUntilEpoch > nowEpochSeconds;
53
+
48
54
  private isModelWeeklyLimitRejected = (
49
55
  usage: ClaudeTokenUsage,
50
56
  weeklyLimitType: string,
@@ -134,6 +140,7 @@ export class StartPreparationUseCase {
134
140
  const eligibleTokens = tokenUsages
135
141
  .filter((usage) => !usage.blocked)
136
142
  .filter((usage) => !usage.rejected)
143
+ .filter((usage) => !this.isWithinCooldown(usage, nowEpochSeconds))
137
144
  .filter(
138
145
  (usage) => !this.isModelWeeklyLimitRejected(usage, weeklyLimitType),
139
146
  )
@@ -188,6 +195,7 @@ export class StartPreparationUseCase {
188
195
  const selectedTokens = tokenUsages
189
196
  .filter((usage) => !usage.blocked)
190
197
  .filter((usage) => !usage.rejected)
198
+ .filter((usage) => !this.isWithinCooldown(usage, nowEpochSeconds))
191
199
  .filter(
192
200
  (usage) => !this.isModelWeeklyLimitRejected(usage, weeklyLimitType),
193
201
  )
@@ -214,8 +222,13 @@ export class StartPreparationUseCase {
214
222
  thresholdExcluded:
215
223
  !usage.blocked &&
216
224
  !usage.rejected &&
225
+ !this.isWithinCooldown(usage, nowEpochSeconds) &&
217
226
  !this.isModelWeeklyLimitRejected(usage, weeklyLimitType) &&
218
227
  usage.fiveHourUtilization * 100 >= utilizationPercentageThreshold,
228
+ cooldownExcluded:
229
+ !usage.blocked &&
230
+ !usage.rejected &&
231
+ this.isWithinCooldown(usage, nowEpochSeconds),
219
232
  }));
220
233
  const selectedEntries: RotationOrderEntry[] = selectedTokens.map(
221
234
  (usage) => ({
@@ -224,6 +237,7 @@ export class StartPreparationUseCase {
224
237
  blocked: false,
225
238
  rejected: false,
226
239
  thresholdExcluded: false,
240
+ cooldownExcluded: false,
227
241
  }),
228
242
  );
229
243
  return [...selectedEntries, ...excluded];
@@ -17,6 +17,7 @@ export type ConfigFile = {
17
17
  awLogDirectoryPath?: string;
18
18
  awLogStaleThresholdMinutes?: number;
19
19
  labelsAsLlmAgentName?: string[];
20
+ changeTargetPathAliases?: Record<string, string>;
20
21
  };
21
22
  export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
22
23
  export declare const loadConfigFile: (configFilePath: string) => ConfigFile;
@@ -1 +1 @@
1
- {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/projectConfig.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iCAAiC,CAAC,EAAE,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,CAAC;AAoCF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAoBvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UAoDvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,EACd,aAAa,MAAM,KAClB,UAgEF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UAmED,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CA0DvB,CAAC"}
1
+ {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/projectConfig.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iCAAiC,CAAC,EAAE,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD,CAAC;AAsDF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAqBvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UAwDvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,EACd,aAAa,MAAM,KAClB,UAoEF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UAuED,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CA0DvB,CAAC"}