github-issue-tower-defence-management 1.55.0 → 1.56.1

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 (76) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +23 -0
  3. package/bin/adapter/entry-points/cli/index.js +3 -1
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/cli/projectConfig.js +5 -0
  6. package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
  7. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +3 -1
  8. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  9. package/bin/adapter/proxy/RateLimitCache.js +123 -0
  10. package/bin/adapter/proxy/RateLimitCache.js.map +1 -0
  11. package/bin/adapter/proxy/TokenListLoader.js +72 -0
  12. package/bin/adapter/proxy/TokenListLoader.js.map +1 -0
  13. package/bin/adapter/proxy/ensureProxyRunning.js +73 -0
  14. package/bin/adapter/proxy/ensureProxyRunning.js.map +1 -0
  15. package/bin/adapter/proxy/proxyEntry.js +96 -0
  16. package/bin/adapter/proxy/proxyEntry.js.map +1 -0
  17. package/bin/adapter/repositories/NodeLocalCommandRunner.js +10 -4
  18. package/bin/adapter/repositories/NodeLocalCommandRunner.js.map +1 -1
  19. package/bin/adapter/repositories/OauthProxyClaudeRepository.js +3 -0
  20. package/bin/adapter/repositories/OauthProxyClaudeRepository.js.map +1 -1
  21. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +35 -0
  22. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -0
  23. package/bin/domain/entities/ClaudeTokenUsage.js +3 -0
  24. package/bin/domain/entities/ClaudeTokenUsage.js.map +1 -0
  25. package/bin/domain/usecases/StartPreparationUseCase.js +26 -2
  26. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  27. package/bin/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.js +3 -0
  28. package/bin/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.js.map +1 -0
  29. package/package.json +1 -1
  30. package/src/adapter/entry-points/cli/index.ts +5 -0
  31. package/src/adapter/entry-points/cli/projectConfig.ts +13 -0
  32. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +5 -0
  33. package/src/adapter/proxy/RateLimitCache.test.ts +131 -0
  34. package/src/adapter/proxy/RateLimitCache.ts +112 -0
  35. package/src/adapter/proxy/TokenListLoader.test.ts +82 -0
  36. package/src/adapter/proxy/TokenListLoader.ts +35 -0
  37. package/src/adapter/proxy/ensureProxyRunning.test.ts +85 -0
  38. package/src/adapter/proxy/ensureProxyRunning.ts +41 -0
  39. package/src/adapter/proxy/proxyEntry.test.ts +48 -0
  40. package/src/adapter/proxy/proxyEntry.ts +69 -0
  41. package/src/adapter/repositories/NodeLocalCommandRunner.test.ts +3 -1
  42. package/src/adapter/repositories/NodeLocalCommandRunner.ts +18 -4
  43. package/src/adapter/repositories/OauthProxyClaudeRepository.test.ts +29 -0
  44. package/src/adapter/repositories/OauthProxyClaudeRepository.ts +5 -0
  45. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +127 -0
  46. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +36 -0
  47. package/src/domain/entities/ClaudeTokenUsage.ts +5 -0
  48. package/src/domain/usecases/StartPreparationUseCase.test.ts +308 -0
  49. package/src/domain/usecases/StartPreparationUseCase.ts +37 -1
  50. package/src/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.ts +7 -0
  51. package/src/domain/usecases/adapter-interfaces/LocalCommandRunner.ts +5 -0
  52. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  53. package/types/adapter/entry-points/cli/projectConfig.d.ts +1 -0
  54. package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
  55. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  56. package/types/adapter/proxy/RateLimitCache.d.ts +14 -0
  57. package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -0
  58. package/types/adapter/proxy/TokenListLoader.d.ts +2 -0
  59. package/types/adapter/proxy/TokenListLoader.d.ts.map +1 -0
  60. package/types/adapter/proxy/ensureProxyRunning.d.ts +2 -0
  61. package/types/adapter/proxy/ensureProxyRunning.d.ts.map +1 -0
  62. package/types/adapter/proxy/proxyEntry.d.ts +4 -0
  63. package/types/adapter/proxy/proxyEntry.d.ts.map +1 -0
  64. package/types/adapter/repositories/NodeLocalCommandRunner.d.ts +2 -2
  65. package/types/adapter/repositories/NodeLocalCommandRunner.d.ts.map +1 -1
  66. package/types/adapter/repositories/OauthProxyClaudeRepository.d.ts.map +1 -1
  67. package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts +11 -0
  68. package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -0
  69. package/types/domain/entities/ClaudeTokenUsage.d.ts +6 -0
  70. package/types/domain/entities/ClaudeTokenUsage.d.ts.map +1 -0
  71. package/types/domain/usecases/StartPreparationUseCase.d.ts +4 -1
  72. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
  73. package/types/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.d.ts +7 -0
  74. package/types/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.d.ts.map +1 -0
  75. package/types/domain/usecases/adapter-interfaces/LocalCommandRunner.d.ts +4 -1
  76. package/types/domain/usecases/adapter-interfaces/LocalCommandRunner.d.ts.map +1 -1
@@ -6,6 +6,7 @@ import {
6
6
  import { ProjectRepository } from './adapter-interfaces/ProjectRepository';
7
7
  import { LocalCommandRunner } from './adapter-interfaces/LocalCommandRunner';
8
8
  import { ClaudeRepository } from './adapter-interfaces/ClaudeRepository';
9
+ import { ClaudeTokenUsageRepository } from './adapter-interfaces/ClaudeTokenUsageRepository';
9
10
  import { Issue } from '../entities/Issue';
10
11
  import { Project } from '../entities/Project';
11
12
  import { StoryObjectMap } from '../entities/StoryObjectMap';
@@ -92,6 +93,7 @@ describe('StartPreparationUseCase', () => {
92
93
  >;
93
94
  let mockClaudeRepository: Mocked<Pick<ClaudeRepository, 'getUsage'>>;
94
95
  let mockLocalCommandRunner: Mocked<LocalCommandRunner>;
96
+ let mockClaudeTokenUsageRepository: Mocked<ClaudeTokenUsageRepository>;
95
97
  let mockProject: Project;
96
98
  beforeEach(() => {
97
99
  jest.resetAllMocks();
@@ -114,11 +116,17 @@ describe('StartPreparationUseCase', () => {
114
116
  mockLocalCommandRunner = {
115
117
  runCommand: jest.fn(),
116
118
  };
119
+ mockClaudeTokenUsageRepository = {
120
+ ensureObservable: jest.fn().mockResolvedValue(undefined),
121
+ getAvailableTokenUsages: jest.fn().mockResolvedValue([]),
122
+ proxyBaseUrl: jest.fn().mockReturnValue('http://127.0.0.1:8787'),
123
+ };
117
124
  useCase = new StartPreparationUseCase(
118
125
  mockProjectRepository,
119
126
  mockIssueRepository,
120
127
  mockClaudeRepository,
121
128
  mockLocalCommandRunner,
129
+ mockClaudeTokenUsageRepository,
122
130
  );
123
131
  });
124
132
  it('should run aw command for awaiting workspace issues', async () => {
@@ -2516,4 +2524,304 @@ describe('StartPreparationUseCase', () => {
2516
2524
  url: 'https://github.com/user/repo/issues/2',
2517
2525
  });
2518
2526
  });
2527
+
2528
+ it('should pass CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_BASE_URL to runCommand when tokens are available', async () => {
2529
+ const awaitingIssue = createMockIssue({
2530
+ url: 'url1',
2531
+ title: 'Issue 1',
2532
+ labels: ['category:impl'],
2533
+ status: 'Awaiting Workspace',
2534
+ number: 1,
2535
+ itemId: 'item-1',
2536
+ });
2537
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2538
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2539
+ createMockStoryObjectMap([awaitingIssue]),
2540
+ );
2541
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2542
+ stdout: '',
2543
+ stderr: '',
2544
+ exitCode: 0,
2545
+ });
2546
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2547
+ { token: 'token-a', fiveHourUtilization: 0, blocked: false },
2548
+ ]);
2549
+
2550
+ await useCase.run({
2551
+ projectUrl: 'https://github.com/user/repo',
2552
+ defaultAgentName: 'agent1',
2553
+ defaultLlmModelName: 'claude-opus',
2554
+ defaultLlmAgentName: null,
2555
+ configFilePath: '/path/to/config.yml',
2556
+ maximumPreparingIssuesCount: null,
2557
+ utilizationPercentageThreshold: 90,
2558
+ allowedIssueAuthors: null,
2559
+ codexHomeCandidates: null,
2560
+ allowIssueCacheMinutes: 0,
2561
+ });
2562
+
2563
+ expect(
2564
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mock.calls,
2565
+ ).toHaveLength(1);
2566
+ expect(
2567
+ mockClaudeTokenUsageRepository.ensureObservable.mock.calls,
2568
+ ).toHaveLength(1);
2569
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2570
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toEqual({
2571
+ env: {
2572
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-a',
2573
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2574
+ },
2575
+ });
2576
+ });
2577
+
2578
+ it('should rotate Claude OAuth tokens round-robin across multiple awaiting issues', async () => {
2579
+ const awaitingIssues: Issue[] = [
2580
+ createMockIssue({
2581
+ url: 'url1',
2582
+ title: 'Issue 1',
2583
+ labels: ['category:impl'],
2584
+ status: 'Awaiting Workspace',
2585
+ number: 1,
2586
+ itemId: 'item-1',
2587
+ }),
2588
+ createMockIssue({
2589
+ url: 'url2',
2590
+ title: 'Issue 2',
2591
+ labels: ['category:impl'],
2592
+ status: 'Awaiting Workspace',
2593
+ number: 2,
2594
+ itemId: 'item-2',
2595
+ }),
2596
+ createMockIssue({
2597
+ url: 'url3',
2598
+ title: 'Issue 3',
2599
+ labels: ['category:impl'],
2600
+ status: 'Awaiting Workspace',
2601
+ number: 3,
2602
+ itemId: 'item-3',
2603
+ }),
2604
+ ];
2605
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2606
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2607
+ createMockStoryObjectMap(awaitingIssues),
2608
+ );
2609
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2610
+ stdout: '',
2611
+ stderr: '',
2612
+ exitCode: 0,
2613
+ });
2614
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2615
+ { token: 'token-a', fiveHourUtilization: 0, blocked: false },
2616
+ { token: 'token-b', fiveHourUtilization: 0, blocked: false },
2617
+ ]);
2618
+
2619
+ await useCase.run({
2620
+ projectUrl: 'https://github.com/user/repo',
2621
+ defaultAgentName: 'agent1',
2622
+ defaultLlmModelName: 'claude-opus',
2623
+ defaultLlmAgentName: null,
2624
+ configFilePath: '/path/to/config.yml',
2625
+ maximumPreparingIssuesCount: null,
2626
+ utilizationPercentageThreshold: 90,
2627
+ allowedIssueAuthors: null,
2628
+ codexHomeCandidates: null,
2629
+ allowIssueCacheMinutes: 0,
2630
+ });
2631
+
2632
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(3);
2633
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toMatchObject({
2634
+ env: {
2635
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-a',
2636
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2637
+ },
2638
+ });
2639
+ expect(mockLocalCommandRunner.runCommand.mock.calls[1][2]).toMatchObject({
2640
+ env: {
2641
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-b',
2642
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2643
+ },
2644
+ });
2645
+ expect(mockLocalCommandRunner.runCommand.mock.calls[2][2]).toMatchObject({
2646
+ env: {
2647
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-a',
2648
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2649
+ },
2650
+ });
2651
+ });
2652
+
2653
+ it('should not inject env when no tokens are available', async () => {
2654
+ const awaitingIssue = createMockIssue({
2655
+ url: 'url1',
2656
+ title: 'Issue 1',
2657
+ labels: ['category:impl'],
2658
+ status: 'Awaiting Workspace',
2659
+ number: 1,
2660
+ itemId: 'item-1',
2661
+ });
2662
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2663
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2664
+ createMockStoryObjectMap([awaitingIssue]),
2665
+ );
2666
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2667
+ stdout: '',
2668
+ stderr: '',
2669
+ exitCode: 0,
2670
+ });
2671
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue(
2672
+ [],
2673
+ );
2674
+
2675
+ await useCase.run({
2676
+ projectUrl: 'https://github.com/user/repo',
2677
+ defaultAgentName: 'agent1',
2678
+ defaultLlmModelName: 'claude-opus',
2679
+ defaultLlmAgentName: null,
2680
+ configFilePath: '/path/to/config.yml',
2681
+ maximumPreparingIssuesCount: null,
2682
+ utilizationPercentageThreshold: 90,
2683
+ allowedIssueAuthors: null,
2684
+ codexHomeCandidates: null,
2685
+ allowIssueCacheMinutes: 0,
2686
+ });
2687
+
2688
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2689
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toBeUndefined();
2690
+ expect(
2691
+ mockClaudeTokenUsageRepository.ensureObservable.mock.calls,
2692
+ ).toHaveLength(0);
2693
+ });
2694
+
2695
+ it('should pick the least-utilized token first', async () => {
2696
+ const awaitingIssue = createMockIssue({
2697
+ url: 'url1',
2698
+ title: 'Issue 1',
2699
+ labels: ['category:impl'],
2700
+ status: 'Awaiting Workspace',
2701
+ number: 1,
2702
+ itemId: 'item-1',
2703
+ });
2704
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2705
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2706
+ createMockStoryObjectMap([awaitingIssue]),
2707
+ );
2708
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2709
+ stdout: '',
2710
+ stderr: '',
2711
+ exitCode: 0,
2712
+ });
2713
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2714
+ { token: 'token-high', fiveHourUtilization: 80, blocked: false },
2715
+ { token: 'token-low', fiveHourUtilization: 10, blocked: false },
2716
+ ]);
2717
+
2718
+ await useCase.run({
2719
+ projectUrl: 'https://github.com/user/repo',
2720
+ defaultAgentName: 'agent1',
2721
+ defaultLlmModelName: 'claude-opus',
2722
+ defaultLlmAgentName: null,
2723
+ configFilePath: '/path/to/config.yml',
2724
+ maximumPreparingIssuesCount: null,
2725
+ utilizationPercentageThreshold: 90,
2726
+ allowedIssueAuthors: null,
2727
+ codexHomeCandidates: null,
2728
+ allowIssueCacheMinutes: 0,
2729
+ });
2730
+
2731
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2732
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toEqual({
2733
+ env: {
2734
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-low',
2735
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2736
+ },
2737
+ });
2738
+ });
2739
+
2740
+ it('should exclude blocked tokens from rotation', async () => {
2741
+ const awaitingIssue = createMockIssue({
2742
+ url: 'url1',
2743
+ title: 'Issue 1',
2744
+ labels: ['category:impl'],
2745
+ status: 'Awaiting Workspace',
2746
+ number: 1,
2747
+ itemId: 'item-1',
2748
+ });
2749
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2750
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2751
+ createMockStoryObjectMap([awaitingIssue]),
2752
+ );
2753
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2754
+ stdout: '',
2755
+ stderr: '',
2756
+ exitCode: 0,
2757
+ });
2758
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2759
+ { token: 'token-blocked', fiveHourUtilization: 5, blocked: true },
2760
+ { token: 'token-ok', fiveHourUtilization: 50, blocked: false },
2761
+ ]);
2762
+
2763
+ await useCase.run({
2764
+ projectUrl: 'https://github.com/user/repo',
2765
+ defaultAgentName: 'agent1',
2766
+ defaultLlmModelName: 'claude-opus',
2767
+ defaultLlmAgentName: null,
2768
+ configFilePath: '/path/to/config.yml',
2769
+ maximumPreparingIssuesCount: null,
2770
+ utilizationPercentageThreshold: 90,
2771
+ allowedIssueAuthors: null,
2772
+ codexHomeCandidates: null,
2773
+ allowIssueCacheMinutes: 0,
2774
+ });
2775
+
2776
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2777
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toEqual({
2778
+ env: {
2779
+ CLAUDE_CODE_OAUTH_TOKEN: 'token-ok',
2780
+ ANTHROPIC_BASE_URL: 'http://127.0.0.1:8787',
2781
+ },
2782
+ });
2783
+ });
2784
+
2785
+ it('should not inject env when every available token is blocked', async () => {
2786
+ const awaitingIssue = createMockIssue({
2787
+ url: 'url1',
2788
+ title: 'Issue 1',
2789
+ labels: ['category:impl'],
2790
+ status: 'Awaiting Workspace',
2791
+ number: 1,
2792
+ itemId: 'item-1',
2793
+ });
2794
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
2795
+ mockIssueRepository.getStoryObjectMap.mockResolvedValue(
2796
+ createMockStoryObjectMap([awaitingIssue]),
2797
+ );
2798
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
2799
+ stdout: '',
2800
+ stderr: '',
2801
+ exitCode: 0,
2802
+ });
2803
+ mockClaudeTokenUsageRepository.getAvailableTokenUsages.mockResolvedValue([
2804
+ { token: 'token-a', fiveHourUtilization: 5, blocked: true },
2805
+ { token: 'token-b', fiveHourUtilization: 8, blocked: true },
2806
+ ]);
2807
+
2808
+ await useCase.run({
2809
+ projectUrl: 'https://github.com/user/repo',
2810
+ defaultAgentName: 'agent1',
2811
+ defaultLlmModelName: 'claude-opus',
2812
+ defaultLlmAgentName: null,
2813
+ configFilePath: '/path/to/config.yml',
2814
+ maximumPreparingIssuesCount: null,
2815
+ utilizationPercentageThreshold: 90,
2816
+ allowedIssueAuthors: null,
2817
+ codexHomeCandidates: null,
2818
+ allowIssueCacheMinutes: 0,
2819
+ });
2820
+
2821
+ expect(
2822
+ mockClaudeTokenUsageRepository.ensureObservable.mock.calls,
2823
+ ).toHaveLength(0);
2824
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
2825
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][2]).toBeUndefined();
2826
+ });
2519
2827
  });
@@ -2,6 +2,8 @@ import { IssueRepository } from './adapter-interfaces/IssueRepository';
2
2
  import { ProjectRepository } from './adapter-interfaces/ProjectRepository';
3
3
  import { LocalCommandRunner } from './adapter-interfaces/LocalCommandRunner';
4
4
  import { ClaudeRepository } from './adapter-interfaces/ClaudeRepository';
5
+ import { ClaudeTokenUsageRepository } from './adapter-interfaces/ClaudeTokenUsageRepository';
6
+ import { ClaudeTokenUsage } from '../entities/ClaudeTokenUsage';
5
7
  import {
6
8
  AWAITING_WORKSPACE_STATUS_NAME,
7
9
  PREPARATION_STATUS_NAME,
@@ -22,8 +24,15 @@ export class StartPreparationUseCase {
22
24
  >,
23
25
  private readonly claudeRepository: Pick<ClaudeRepository, 'getUsage'>,
24
26
  private readonly localCommandRunner: LocalCommandRunner,
27
+ private readonly claudeTokenUsageRepository: ClaudeTokenUsageRepository,
25
28
  ) {}
26
29
 
30
+ private selectRotationTokens = (tokenUsages: ClaudeTokenUsage[]): string[] =>
31
+ tokenUsages
32
+ .filter((usage) => !usage.blocked)
33
+ .sort((a, b) => a.fiveHourUtilization - b.fiveHourUtilization)
34
+ .map((usage) => usage.token);
35
+
27
36
  run = async (params: {
28
37
  projectUrl: string;
29
38
  defaultAgentName: string;
@@ -84,6 +93,20 @@ export class StartPreparationUseCase {
84
93
  );
85
94
  }
86
95
  }
96
+
97
+ const tokenUsages =
98
+ await this.claudeTokenUsageRepository.getAvailableTokenUsages();
99
+ let rotationTokens: string[] | null = null;
100
+ let proxyBaseUrl: string | null = null;
101
+ if (tokenUsages.length > 0) {
102
+ const ranked = this.selectRotationTokens(tokenUsages);
103
+ if (ranked.length > 0) {
104
+ await this.claudeTokenUsageRepository.ensureObservable();
105
+ rotationTokens = ranked;
106
+ proxyBaseUrl = this.claudeTokenUsageRepository.proxyBaseUrl();
107
+ }
108
+ }
109
+
87
110
  const project = await this.projectRepository.getByUrl(params.projectUrl);
88
111
  const storyObjectMap = await this.issueRepository.getStoryObjectMap(
89
112
  project,
@@ -271,7 +294,20 @@ export class StartPreparationUseCase {
271
294
  ];
272
295
  awArgs.push('--codexHome', codexHome);
273
296
  }
274
- await this.localCommandRunner.runCommand('aw', awArgs);
297
+ let spawnEnv: Record<string, string> | undefined;
298
+ if (rotationTokens !== null && proxyBaseUrl !== null) {
299
+ const selected =
300
+ rotationTokens[startedInThisRunCount % rotationTokens.length];
301
+ spawnEnv = {
302
+ CLAUDE_CODE_OAUTH_TOKEN: selected,
303
+ ANTHROPIC_BASE_URL: proxyBaseUrl,
304
+ };
305
+ }
306
+ await this.localCommandRunner.runCommand(
307
+ 'aw',
308
+ awArgs,
309
+ spawnEnv ? { env: spawnEnv } : undefined,
310
+ );
275
311
  startedInThisRunCount++;
276
312
  updatedCurrentPreparationIssueCount++;
277
313
  }
@@ -0,0 +1,7 @@
1
+ import { ClaudeTokenUsage } from '../../entities/ClaudeTokenUsage';
2
+
3
+ export interface ClaudeTokenUsageRepository {
4
+ ensureObservable(): Promise<void>;
5
+ getAvailableTokenUsages(): Promise<ClaudeTokenUsage[]>;
6
+ proxyBaseUrl(): string;
7
+ }
@@ -1,7 +1,12 @@
1
+ export interface LocalCommandRunnerOptions {
2
+ env?: Record<string, string>;
3
+ }
4
+
1
5
  export interface LocalCommandRunner {
2
6
  runCommand(
3
7
  program: string,
4
8
  args: string[],
9
+ options?: LocalCommandRunnerOptions,
5
10
  ): Promise<{
6
11
  stdout: string;
7
12
  stderr: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAiEzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAkEzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
@@ -12,6 +12,7 @@ export type ConfigFile = {
12
12
  projectName?: string;
13
13
  preparationProcessCheckCommand?: string;
14
14
  codexHomeCandidates?: string[];
15
+ claudeCodeOauthTokenListJsonPath?: string;
15
16
  awLogDirectoryPath?: string;
16
17
  awLogStaleThresholdMinutes?: number;
17
18
  };
@@ -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,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,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC,CAAC;AAoCF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAEvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UA8CvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM,KAAG,UAkDzD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UAuDD,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CAyDvB,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,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;CACrC,CAAC;AAoCF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAEvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UAkDvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM,KAAG,UAsDzD,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UA2DD,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CAyDvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAwB3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,CA2OP;CACH"}
1
+ {"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAyB3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,CA+OP;CACH"}
@@ -0,0 +1,14 @@
1
+ export interface RateLimitSnapshot {
2
+ fiveHourUtilization: number;
3
+ fiveHourReset: number;
4
+ sevenDayUtilization: number;
5
+ sevenDayReset: number;
6
+ blocked: boolean;
7
+ }
8
+ export declare const PROXY_PORT = 8787;
9
+ export declare const cacheDir: () => string;
10
+ export declare const hashToken: (token: string) => string;
11
+ export declare const cachePathForToken: (token: string) => string;
12
+ export declare const writeRateLimit: (token: string, headers: Record<string, string | string[] | undefined>) => void;
13
+ export declare const readRateLimit: (token: string) => RateLimitSnapshot | null;
14
+ //# sourceMappingURL=RateLimitCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RateLimitCache.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/RateLimitCache.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,UAAU,OAAO,CAAC;AAI/B,eAAO,MAAM,QAAQ,QAAO,MAG3B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MACqB,CAAC;AAEhE,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MACC,CAAC;AAEpD,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,KACrD,IAsCF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,iBAAiB,GAAG,IAwCjE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const loadTokens: (jsonPath: string) => string[] | null;
2
+ //# sourceMappingURL=TokenListLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenListLoader.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/TokenListLoader.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,KAAG,MAAM,EAAE,GAAG,IAiBxD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const ensureProxyRunning: (port?: number) => Promise<void>;
2
+ //# sourceMappingURL=ensureProxyRunning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureProxyRunning.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/ensureProxyRunning.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,kBAAkB,GAC7B,OAAM,MAAmB,KACxB,OAAO,CAAC,IAAI,CAUd,CAAC"}
@@ -0,0 +1,4 @@
1
+ declare const extractToken: (authorization: string | string[] | undefined) => string | null;
2
+ declare const startProxy: (port: number) => void;
3
+ export { startProxy, extractToken };
4
+ //# sourceMappingURL=proxyEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxyEntry.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/proxyEntry.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,YAAY,GAChB,eAAe,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAC3C,MAAM,GAAG,IAQX,CAAC;AAEF,QAAA,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,IA0ClC,CAAC;AAMF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
- import { LocalCommandRunner } from '../../domain/usecases/adapter-interfaces/LocalCommandRunner';
1
+ import { LocalCommandRunner, LocalCommandRunnerOptions } from '../../domain/usecases/adapter-interfaces/LocalCommandRunner';
2
2
  export declare class NodeLocalCommandRunner implements LocalCommandRunner {
3
- runCommand(program: string, args: string[]): Promise<{
3
+ runCommand(program: string, args: string[], options?: LocalCommandRunnerOptions): Promise<{
4
4
  stdout: string;
5
5
  stderr: string;
6
6
  exitCode: number;
@@ -1 +1 @@
1
- {"version":3,"file":"NodeLocalCommandRunner.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeLocalCommandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AAMjG,qBAAa,sBAAuB,YAAW,kBAAkB;IACzD,UAAU,CACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CAyBH"}
1
+ {"version":3,"file":"NodeLocalCommandRunner.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeLocalCommandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,6DAA6D,CAAC;AAMrE,qBAAa,sBAAuB,YAAW,kBAAkB;IACzD,UAAU,CACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CAmCH"}
@@ -1 +1 @@
1
- {"version":3,"file":"OauthProxyClaudeRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/OauthProxyClaudeRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAuB5E,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGhC,QAAQ,GAAE,MACoB;IAK1B,QAAQ,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IA6ExC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAO7D"}
1
+ {"version":3,"file":"OauthProxyClaudeRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/OauthProxyClaudeRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAuB5E,qBAAa,0BAA2B,YAAW,gBAAgB;IACjE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGhC,QAAQ,GAAE,MACoB;IAK1B,QAAQ,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAkFxC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAO7D"}
@@ -0,0 +1,11 @@
1
+ import { ClaudeTokenUsage } from '../../domain/entities/ClaudeTokenUsage';
2
+ import { ClaudeTokenUsageRepository } from '../../domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository';
3
+ export declare class ProxyClaudeTokenUsageRepository implements ClaudeTokenUsageRepository {
4
+ private readonly tokenListJsonPath;
5
+ private readonly port;
6
+ constructor(tokenListJsonPath: string | null, port?: number);
7
+ ensureObservable: () => Promise<void>;
8
+ getAvailableTokenUsages: () => Promise<ClaudeTokenUsage[]>;
9
+ proxyBaseUrl: () => string;
10
+ }
11
+ //# sourceMappingURL=ProxyClaudeTokenUsageRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProxyClaudeTokenUsageRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qEAAqE,CAAC;AAKjH,qBAAa,+BAAgC,YAAW,0BAA0B;IAE9E,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,IAAI,GAAE,MAAmB;IAG5C,gBAAgB,QAAa,OAAO,CAAC,IAAI,CAAC,CAExC;IAEF,uBAAuB,QAAa,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAgB7D;IAEF,YAAY,QAAO,MAAM,CAAoC;CAC9D"}
@@ -0,0 +1,6 @@
1
+ export type ClaudeTokenUsage = {
2
+ token: string;
3
+ fiveHourUtilization: number;
4
+ blocked: boolean;
5
+ };
6
+ //# sourceMappingURL=ClaudeTokenUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeTokenUsage.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/ClaudeTokenUsage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC"}
@@ -2,12 +2,15 @@ import { IssueRepository } from './adapter-interfaces/IssueRepository';
2
2
  import { ProjectRepository } from './adapter-interfaces/ProjectRepository';
3
3
  import { LocalCommandRunner } from './adapter-interfaces/LocalCommandRunner';
4
4
  import { ClaudeRepository } from './adapter-interfaces/ClaudeRepository';
5
+ import { ClaudeTokenUsageRepository } from './adapter-interfaces/ClaudeTokenUsageRepository';
5
6
  export declare class StartPreparationUseCase {
6
7
  private readonly projectRepository;
7
8
  private readonly issueRepository;
8
9
  private readonly claudeRepository;
9
10
  private readonly localCommandRunner;
10
- constructor(projectRepository: Pick<ProjectRepository, 'getByUrl'>, issueRepository: Pick<IssueRepository, 'getStoryObjectMap' | 'updateStatus' | 'findRelatedOpenPRs' | 'getOpenPullRequest' | 'closePullRequest' | 'deletePullRequestBranch' | 'createCommentByUrl'>, claudeRepository: Pick<ClaudeRepository, 'getUsage'>, localCommandRunner: LocalCommandRunner);
11
+ private readonly claudeTokenUsageRepository;
12
+ constructor(projectRepository: Pick<ProjectRepository, 'getByUrl'>, issueRepository: Pick<IssueRepository, 'getStoryObjectMap' | 'updateStatus' | 'findRelatedOpenPRs' | 'getOpenPullRequest' | 'closePullRequest' | 'deletePullRequestBranch' | 'createCommentByUrl'>, claudeRepository: Pick<ClaudeRepository, 'getUsage'>, localCommandRunner: LocalCommandRunner, claudeTokenUsageRepository: ClaudeTokenUsageRepository);
13
+ private selectRotationTokens;
11
14
  run: (params: {
12
15
  projectUrl: string;
13
16
  defaultAgentName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAMzE,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAUhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAZlB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,mBAAmB,GACnB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,GACzB,oBAAoB,CACvB,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,cAAc,EAAE,MAAM,CAAC;QACvB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3C,8BAA8B,EAAE,MAAM,CAAC;QACvC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,sBAAsB,EAAE,MAAM,CAAC;KAChC,KAAG,OAAO,CAAC,IAAI,CAAC,CAgPf;CACH"}
1
+ {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAO7F,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAUhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,0BAA0B;gBAb1B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,mBAAmB,GACnB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,GACzB,oBAAoB,CACvB,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB,EACtC,0BAA0B,EAAE,0BAA0B;IAGzE,OAAO,CAAC,oBAAoB,CAIK;IAEjC,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,cAAc,EAAE,MAAM,CAAC;QACvB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3C,8BAA8B,EAAE,MAAM,CAAC;QACvC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACrC,sBAAsB,EAAE,MAAM,CAAC;KAChC,KAAG,OAAO,CAAC,IAAI,CAAC,CA2Qf;CACH"}
@@ -0,0 +1,7 @@
1
+ import { ClaudeTokenUsage } from '../../entities/ClaudeTokenUsage';
2
+ export interface ClaudeTokenUsageRepository {
3
+ ensureObservable(): Promise<void>;
4
+ getAvailableTokenUsages(): Promise<ClaudeTokenUsage[]>;
5
+ proxyBaseUrl(): string;
6
+ }
7
+ //# sourceMappingURL=ClaudeTokenUsageRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeTokenUsageRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,uBAAuB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACvD,YAAY,IAAI,MAAM,CAAC;CACxB"}
@@ -1,5 +1,8 @@
1
+ export interface LocalCommandRunnerOptions {
2
+ env?: Record<string, string>;
3
+ }
1
4
  export interface LocalCommandRunner {
2
- runCommand(program: string, args: string[]): Promise<{
5
+ runCommand(program: string, args: string[], options?: LocalCommandRunnerOptions): Promise<{
3
6
  stdout: string;
4
7
  stderr: string;
5
8
  exitCode: number;
@@ -1 +1 @@
1
- {"version":3,"file":"LocalCommandRunner.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/LocalCommandRunner.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,UAAU,CACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ"}
1
+ {"version":3,"file":"LocalCommandRunner.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/LocalCommandRunner.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ"}