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
@@ -5,12 +5,18 @@ const child_process_1 = require("child_process");
5
5
  const util_1 = require("util");
6
6
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
7
7
  class NodeLocalCommandRunner {
8
- async runCommand(program, args) {
8
+ async runCommand(program, args, options) {
9
+ const execOptions = {
10
+ encoding: 'utf8',
11
+ };
12
+ if (options?.env) {
13
+ execOptions.env = { ...process.env, ...options.env };
14
+ }
9
15
  try {
10
- const { stdout, stderr } = await execFileAsync(program, args);
16
+ const { stdout, stderr } = await execFileAsync(program, args, execOptions);
11
17
  return {
12
- stdout,
13
- stderr,
18
+ stdout: String(stdout),
19
+ stderr: String(stderr),
14
20
  exitCode: 0,
15
21
  };
16
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NodeLocalCommandRunner.js","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeLocalCommandRunner.ts"],"names":[],"mappings":";;;AACA,iDAAyC;AACzC,+BAAiC;AAEjC,MAAM,aAAa,GAAG,IAAA,gBAAS,EAAC,wBAAQ,CAAC,CAAC;AAE1C,MAAa,sBAAsB;IACjC,KAAK,CAAC,UAAU,CACd,OAAe,EACf,IAAc;QAMd,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC9D,OAAO;gBACL,MAAM;gBACN,MAAM;gBACN,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,KAAK;gBACL,OAAO,KAAK,KAAK,QAAQ;gBACzB,QAAQ,IAAI,KAAK;gBACjB,QAAQ,IAAI,KAAK;gBACjB,MAAM,IAAI,KAAK,EACf,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC5B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC5B,QAAQ,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAC1D,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAjCD,wDAiCC"}
1
+ {"version":3,"file":"NodeLocalCommandRunner.js","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeLocalCommandRunner.ts"],"names":[],"mappings":";;;AAIA,iDAAyC;AACzC,+BAAiC;AAEjC,MAAM,aAAa,GAAG,IAAA,gBAAS,EAAC,wBAAQ,CAAC,CAAC;AAE1C,MAAa,sBAAsB;IACjC,KAAK,CAAC,UAAU,CACd,OAAe,EACf,IAAc,EACd,OAAmC;QAMnC,MAAM,WAAW,GAAwC;YACvD,QAAQ,EAAE,MAAM;SACjB,CAAC;QACF,IAAI,OAAO,EAAE,GAAG,EAAE,CAAC;YACjB,WAAW,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QACvD,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAC5C,OAAO,EACP,IAAI,EACJ,WAAW,CACZ,CAAC;YACF,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;gBACtB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;gBACtB,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IACE,KAAK;gBACL,OAAO,KAAK,KAAK,QAAQ;gBACzB,QAAQ,IAAI,KAAK;gBACjB,QAAQ,IAAI,KAAK;gBACjB,MAAM,IAAI,KAAK,EACf,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC5B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;oBAC5B,QAAQ,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;iBAC1D,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AA5CD,wDA4CC"}
@@ -64,9 +64,12 @@ class OauthProxyClaudeRepository {
64
64
  }
65
65
  }
66
66
  const overageStatus = headers['anthropic-ratelimit-unified-overage-status'];
67
+ const overageDisabledReason = headers['anthropic-ratelimit-unified-overage-disabled-reason'];
68
+ const isAdministrativeOverageDisable = overageDisabledReason?.startsWith('org_level_disabled') ?? false;
67
69
  const baseQuotaAvailable = headers['anthropic-ratelimit-unified-5h-status'] === 'allowed' &&
68
70
  headers['anthropic-ratelimit-unified-7d-status'] === 'allowed';
69
71
  if (overageStatus === 'rejected' &&
72
+ !isAdministrativeOverageDisable &&
70
73
  !baseQuotaAvailable &&
71
74
  !usages.some((u) => u.utilizationPercentage >= 100)) {
72
75
  usages.push({
@@ -1 +1 @@
1
- {"version":3,"file":"OauthProxyClaudeRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/OauthProxyClaudeRepository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OauthProxyClaudeRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/OauthProxyClaudeRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProxyClaudeTokenUsageRepository = void 0;
4
+ const ensureProxyRunning_1 = require("../proxy/ensureProxyRunning");
5
+ const RateLimitCache_1 = require("../proxy/RateLimitCache");
6
+ const TokenListLoader_1 = require("../proxy/TokenListLoader");
7
+ class ProxyClaudeTokenUsageRepository {
8
+ constructor(tokenListJsonPath, port = RateLimitCache_1.PROXY_PORT) {
9
+ this.tokenListJsonPath = tokenListJsonPath;
10
+ this.port = port;
11
+ this.ensureObservable = async () => {
12
+ await (0, ensureProxyRunning_1.ensureProxyRunning)(this.port);
13
+ };
14
+ this.getAvailableTokenUsages = async () => {
15
+ if (this.tokenListJsonPath === null) {
16
+ return [];
17
+ }
18
+ const tokens = (0, TokenListLoader_1.loadTokens)(this.tokenListJsonPath);
19
+ if (tokens === null) {
20
+ return [];
21
+ }
22
+ return tokens.map((token) => {
23
+ const snapshot = (0, RateLimitCache_1.readRateLimit)(token);
24
+ return {
25
+ token,
26
+ fiveHourUtilization: snapshot ? snapshot.fiveHourUtilization : 0,
27
+ blocked: snapshot?.blocked ?? false,
28
+ };
29
+ });
30
+ };
31
+ this.proxyBaseUrl = () => `http://127.0.0.1:${this.port}`;
32
+ }
33
+ }
34
+ exports.ProxyClaudeTokenUsageRepository = ProxyClaudeTokenUsageRepository;
35
+ //# sourceMappingURL=ProxyClaudeTokenUsageRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProxyClaudeTokenUsageRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts"],"names":[],"mappings":";;;AAEA,oEAAiE;AACjE,4DAAoE;AACpE,8DAAsD;AAEtD,MAAa,+BAA+B;IAC1C,YACmB,iBAAgC,EAChC,OAAe,2BAAU;QADzB,sBAAiB,GAAjB,iBAAiB,CAAe;QAChC,SAAI,GAAJ,IAAI,CAAqB;QAG5C,qBAAgB,GAAG,KAAK,IAAmB,EAAE;YAC3C,MAAM,IAAA,uCAAkB,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC,CAAC;QAEF,4BAAuB,GAAG,KAAK,IAAiC,EAAE;YAChE,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;gBACpC,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,MAAM,GAAG,IAAA,4BAAU,EAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAClD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC1B,MAAM,QAAQ,GAAG,IAAA,8BAAa,EAAC,KAAK,CAAC,CAAC;gBACtC,OAAO;oBACL,KAAK;oBACL,mBAAmB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;oBAChE,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,KAAK;iBACpC,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,iBAAY,GAAG,GAAW,EAAE,CAAC,oBAAoB,IAAI,CAAC,IAAI,EAAE,CAAC;IAxB1D,CAAC;CAyBL;AA7BD,0EA6BC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ClaudeTokenUsage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeTokenUsage.js","sourceRoot":"","sources":["../../../src/domain/entities/ClaudeTokenUsage.ts"],"names":[],"mappings":""}
@@ -3,11 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StartPreparationUseCase = void 0;
4
4
  const WorkflowStatus_1 = require("../entities/WorkflowStatus");
5
5
  class StartPreparationUseCase {
6
- constructor(projectRepository, issueRepository, claudeRepository, localCommandRunner) {
6
+ constructor(projectRepository, issueRepository, claudeRepository, localCommandRunner, claudeTokenUsageRepository) {
7
7
  this.projectRepository = projectRepository;
8
8
  this.issueRepository = issueRepository;
9
9
  this.claudeRepository = claudeRepository;
10
10
  this.localCommandRunner = localCommandRunner;
11
+ this.claudeTokenUsageRepository = claudeTokenUsageRepository;
12
+ this.selectRotationTokens = (tokenUsages) => tokenUsages
13
+ .filter((usage) => !usage.blocked)
14
+ .sort((a, b) => a.fiveHourUtilization - b.fiveHourUtilization)
15
+ .map((usage) => usage.token);
11
16
  this.run = async (params) => {
12
17
  const claudeUsages = await this.claudeRepository.getUsage();
13
18
  const weeklyWindowHours = 168;
@@ -33,6 +38,17 @@ class StartPreparationUseCase {
33
38
  console.warn(`Weekly Claude usage (${maxWeeklyUtilization}%) exceeds threshold (${params.utilizationPercentageThreshold}%). Reducing maximumPreparingIssuesCount to ${maximumPreparingIssuesCount}.`);
34
39
  }
35
40
  }
41
+ const tokenUsages = await this.claudeTokenUsageRepository.getAvailableTokenUsages();
42
+ let rotationTokens = null;
43
+ let proxyBaseUrl = null;
44
+ if (tokenUsages.length > 0) {
45
+ const ranked = this.selectRotationTokens(tokenUsages);
46
+ if (ranked.length > 0) {
47
+ await this.claudeTokenUsageRepository.ensureObservable();
48
+ rotationTokens = ranked;
49
+ proxyBaseUrl = this.claudeTokenUsageRepository.proxyBaseUrl();
50
+ }
51
+ }
36
52
  const project = await this.projectRepository.getByUrl(params.projectUrl);
37
53
  const storyObjectMap = await this.issueRepository.getStoryObjectMap(project, params.allowIssueCacheMinutes);
38
54
  const allOpenedIssues = Array.from(storyObjectMap.values()).flatMap((storyObject) => storyObject.issues);
@@ -152,7 +168,15 @@ class StartPreparationUseCase {
152
168
  const codexHome = params.codexHomeCandidates[startedInThisRunCount % params.codexHomeCandidates.length];
153
169
  awArgs.push('--codexHome', codexHome);
154
170
  }
155
- await this.localCommandRunner.runCommand('aw', awArgs);
171
+ let spawnEnv;
172
+ if (rotationTokens !== null && proxyBaseUrl !== null) {
173
+ const selected = rotationTokens[startedInThisRunCount % rotationTokens.length];
174
+ spawnEnv = {
175
+ CLAUDE_CODE_OAUTH_TOKEN: selected,
176
+ ANTHROPIC_BASE_URL: proxyBaseUrl,
177
+ };
178
+ }
179
+ await this.localCommandRunner.runCommand('aw', awArgs, spawnEnv ? { env: spawnEnv } : undefined);
156
180
  startedInThisRunCount++;
157
181
  updatedCurrentPreparationIssueCount++;
158
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ClaudeTokenUsageRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeTokenUsageRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/ClaudeTokenUsageRepository.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.55.0",
3
+ "version": "1.56.1",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -16,6 +16,7 @@ import {
16
16
  fetchProjectReadme,
17
17
  } from './projectConfig';
18
18
  import { StartPreparationUseCase } from '../../../domain/usecases/StartPreparationUseCase';
19
+ import { ProxyClaudeTokenUsageRepository } from '../../repositories/ProxyClaudeTokenUsageRepository';
19
20
  import { NotifyFinishedIssuePreparationUseCase } from '../../../domain/usecases/NotifyFinishedIssuePreparationUseCase';
20
21
  import { LocalStorageRepository } from '../../repositories/LocalStorageRepository';
21
22
  import { GraphqlProjectRepository } from '../../repositories/GraphqlProjectRepository';
@@ -269,11 +270,15 @@ program
269
270
  });
270
271
  }
271
272
 
273
+ const claudeTokenUsageRepository = new ProxyClaudeTokenUsageRepository(
274
+ config.claudeCodeOauthTokenListJsonPath ?? null,
275
+ );
272
276
  const useCase = new StartPreparationUseCase(
273
277
  projectRepository,
274
278
  issueRepository,
275
279
  claudeRepository,
276
280
  localCommandRunner,
281
+ claudeTokenUsageRepository,
277
282
  );
278
283
 
279
284
  const rawAllowedIssueAuthors = config.allowedIssueAuthors;
@@ -15,6 +15,7 @@ export type ConfigFile = {
15
15
  projectName?: string;
16
16
  preparationProcessCheckCommand?: string;
17
17
  codexHomeCandidates?: string[];
18
+ claudeCodeOauthTokenListJsonPath?: string;
18
19
  awLogDirectoryPath?: string;
19
20
  awLogStaleThresholdMinutes?: number;
20
21
  };
@@ -89,6 +90,10 @@ export const loadConfigFile = (configFilePath: string): ConfigFile => {
89
90
  'preparationProcessCheckCommand',
90
91
  ),
91
92
  codexHomeCandidates: getStringArrayValue(parsed, 'codexHomeCandidates'),
93
+ claudeCodeOauthTokenListJsonPath: getStringValue(
94
+ parsed,
95
+ 'claudeCodeOauthTokenListJsonPath',
96
+ ),
92
97
  awLogDirectoryPath: getStringValue(parsed, 'awLogDirectoryPath'),
93
98
  awLogStaleThresholdMinutes: getNumberValue(
94
99
  parsed,
@@ -144,6 +149,10 @@ export const parseProjectReadmeConfig = (readme: string): ConfigFile => {
144
149
  'preparationProcessCheckCommand',
145
150
  ),
146
151
  codexHomeCandidates: getStringArrayValue(parsed, 'codexHomeCandidates'),
152
+ claudeCodeOauthTokenListJsonPath: getStringValue(
153
+ parsed,
154
+ 'claudeCodeOauthTokenListJsonPath',
155
+ ),
147
156
  awLogDirectoryPath: getStringValue(parsed, 'awLogDirectoryPath'),
148
157
  awLogStaleThresholdMinutes: getNumberValue(
149
158
  parsed,
@@ -207,6 +216,10 @@ export const mergeConfigs = (
207
216
  readmeOverrides.codexHomeCandidates ??
208
217
  cliOverrides.codexHomeCandidates ??
209
218
  configFile.codexHomeCandidates,
219
+ claudeCodeOauthTokenListJsonPath:
220
+ readmeOverrides.claudeCodeOauthTokenListJsonPath ??
221
+ cliOverrides.claudeCodeOauthTokenListJsonPath ??
222
+ configFile.claudeCodeOauthTokenListJsonPath,
210
223
  awLogDirectoryPath:
211
224
  readmeOverrides.awLogDirectoryPath ??
212
225
  cliOverrides.awLogDirectoryPath ??
@@ -35,6 +35,7 @@ import { UpdateIssueStatusByLabelUseCase } from '../../../domain/usecases/Update
35
35
  import { StartPreparationUseCase } from '../../../domain/usecases/StartPreparationUseCase';
36
36
  import { NodeLocalCommandRunner } from '../../repositories/NodeLocalCommandRunner';
37
37
  import { OauthAPIProxyClaudeRepository } from '../../repositories/OauthAPIProxyClaudeRepository';
38
+ import { ProxyClaudeTokenUsageRepository } from '../../repositories/ProxyClaudeTokenUsageRepository';
38
39
  import { RevertOrphanedPreparationUseCase } from '../../../domain/usecases/RevertOrphanedPreparationUseCase';
39
40
  import { RevertNotReadyAwaitingQualityCheckUseCase } from '../../../domain/usecases/RevertNotReadyAwaitingQualityCheckUseCase';
40
41
  import { GitHubIssueCommentRepository } from '../../repositories/GitHubIssueCommentRepository';
@@ -217,11 +218,15 @@ export class HandleScheduledEventUseCaseHandler {
217
218
  );
218
219
  const nodeLocalCommandRunner = new NodeLocalCommandRunner();
219
220
  const claudeRepository = new OauthAPIProxyClaudeRepository();
221
+ const claudeTokenUsageRepository = new ProxyClaudeTokenUsageRepository(
222
+ null,
223
+ );
220
224
  const startPreparationUseCase = new StartPreparationUseCase(
221
225
  projectRepository,
222
226
  issueRepository,
223
227
  claudeRepository,
224
228
  nodeLocalCommandRunner,
229
+ claudeTokenUsageRepository,
225
230
  );
226
231
  const issueCommentRepository = new GitHubIssueCommentRepository(
227
232
  input.credentials.bot.github.token,
@@ -0,0 +1,131 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import {
5
+ cacheDir,
6
+ cachePathForToken,
7
+ hashToken,
8
+ readRateLimit,
9
+ writeRateLimit,
10
+ } from './RateLimitCache';
11
+
12
+ describe('RateLimitCache', () => {
13
+ let tempDir: string;
14
+ const originalXdg = process.env.XDG_CACHE_HOME;
15
+
16
+ beforeEach(() => {
17
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ratelimit-cache-'));
18
+ process.env.XDG_CACHE_HOME = tempDir;
19
+ });
20
+
21
+ afterEach(() => {
22
+ if (originalXdg === undefined) {
23
+ delete process.env.XDG_CACHE_HOME;
24
+ } else {
25
+ process.env.XDG_CACHE_HOME = originalXdg;
26
+ }
27
+ fs.rmSync(tempDir, { recursive: true, force: true });
28
+ });
29
+
30
+ describe('hashToken', () => {
31
+ it('should be deterministic for the same input', () => {
32
+ expect(hashToken('token-a')).toBe(hashToken('token-a'));
33
+ });
34
+
35
+ it('should differ for different inputs', () => {
36
+ expect(hashToken('token-a')).not.toBe(hashToken('token-b'));
37
+ });
38
+
39
+ it('should return a 64-character hex string for sha256', () => {
40
+ const hash = hashToken('token-a');
41
+ expect(hash).toMatch(/^[0-9a-f]{64}$/);
42
+ });
43
+ });
44
+
45
+ describe('cacheDir', () => {
46
+ it('should honor XDG_CACHE_HOME', () => {
47
+ expect(cacheDir()).toBe(path.join(tempDir, 'tdpm', 'ratelimit'));
48
+ });
49
+
50
+ it('should default to ~/.cache when XDG_CACHE_HOME is unset', () => {
51
+ delete process.env.XDG_CACHE_HOME;
52
+ expect(cacheDir()).toBe(
53
+ path.join(os.homedir(), '.cache', 'tdpm', 'ratelimit'),
54
+ );
55
+ });
56
+ });
57
+
58
+ describe('cachePathForToken', () => {
59
+ it('should place the file under cacheDir with the token hash as filename', () => {
60
+ const token = 'token-x';
61
+ expect(cachePathForToken(token)).toBe(
62
+ path.join(cacheDir(), `${hashToken(token)}.json`),
63
+ );
64
+ });
65
+ });
66
+
67
+ describe('writeRateLimit and readRateLimit', () => {
68
+ it('should round-trip rate limit headers', () => {
69
+ const token = 'roundtrip-token';
70
+ writeRateLimit(token, {
71
+ 'anthropic-ratelimit-unified-status': 'allowed',
72
+ 'anthropic-ratelimit-unified-5h-status': 'allowed',
73
+ 'anthropic-ratelimit-unified-5h-reset': '1700000000',
74
+ 'anthropic-ratelimit-unified-5h-utilization': '42',
75
+ 'anthropic-ratelimit-unified-7d-status': 'allowed',
76
+ 'anthropic-ratelimit-unified-7d-reset': '1700100000',
77
+ 'anthropic-ratelimit-unified-7d-utilization': '17',
78
+ });
79
+ const snapshot = readRateLimit(token);
80
+ expect(snapshot).not.toBeNull();
81
+ if (snapshot === null) return;
82
+ expect(snapshot.fiveHourUtilization).toBe(42);
83
+ expect(snapshot.fiveHourReset).toBe(1700000000);
84
+ expect(snapshot.sevenDayUtilization).toBe(17);
85
+ expect(snapshot.sevenDayReset).toBe(1700100000);
86
+ expect(snapshot.blocked).toBe(false);
87
+ });
88
+
89
+ it('should mark snapshot as blocked when status header is blocked', () => {
90
+ const token = 'blocked-token';
91
+ writeRateLimit(token, {
92
+ 'anthropic-ratelimit-unified-status': 'blocked',
93
+ 'anthropic-ratelimit-unified-5h-status': 'allowed',
94
+ 'anthropic-ratelimit-unified-5h-reset': '1700000000',
95
+ 'anthropic-ratelimit-unified-5h-utilization': '100',
96
+ 'anthropic-ratelimit-unified-7d-status': 'allowed',
97
+ 'anthropic-ratelimit-unified-7d-reset': '1700100000',
98
+ 'anthropic-ratelimit-unified-7d-utilization': '99',
99
+ });
100
+ const snapshot = readRateLimit(token);
101
+ expect(snapshot?.blocked).toBe(true);
102
+ });
103
+
104
+ it('should return null when file does not exist', () => {
105
+ expect(readRateLimit('never-written-token')).toBeNull();
106
+ });
107
+
108
+ it('should return null when file content is malformed JSON', () => {
109
+ const token = 'malformed-token';
110
+ fs.mkdirSync(cacheDir(), { recursive: true });
111
+ fs.writeFileSync(cachePathForToken(token), '{not json');
112
+ expect(readRateLimit(token)).toBeNull();
113
+ });
114
+
115
+ it('should treat array header values as the first element', () => {
116
+ const token = 'array-token';
117
+ writeRateLimit(token, {
118
+ 'anthropic-ratelimit-unified-status': 'allowed',
119
+ 'anthropic-ratelimit-unified-5h-status': 'allowed',
120
+ 'anthropic-ratelimit-unified-5h-reset': ['1700000000', 'ignored'],
121
+ 'anthropic-ratelimit-unified-5h-utilization': ['55', 'ignored'],
122
+ 'anthropic-ratelimit-unified-7d-status': 'allowed',
123
+ 'anthropic-ratelimit-unified-7d-reset': '1700100000',
124
+ 'anthropic-ratelimit-unified-7d-utilization': '10',
125
+ });
126
+ const snapshot = readRateLimit(token);
127
+ expect(snapshot?.fiveHourUtilization).toBe(55);
128
+ expect(snapshot?.fiveHourReset).toBe(1700000000);
129
+ });
130
+ });
131
+ });
@@ -0,0 +1,112 @@
1
+ import * as crypto from 'crypto';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+
6
+ export interface RateLimitSnapshot {
7
+ fiveHourUtilization: number;
8
+ fiveHourReset: number;
9
+ sevenDayUtilization: number;
10
+ sevenDayReset: number;
11
+ blocked: boolean;
12
+ }
13
+
14
+ export const PROXY_PORT = 8787;
15
+
16
+ const HASH_ALGORITHM = 'sha256';
17
+
18
+ export const cacheDir = (): string => {
19
+ const base = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), '.cache');
20
+ return path.join(base, 'tdpm', 'ratelimit');
21
+ };
22
+
23
+ export const hashToken = (token: string): string =>
24
+ crypto.createHash(HASH_ALGORITHM).update(token).digest('hex');
25
+
26
+ export const cachePathForToken = (token: string): string =>
27
+ path.join(cacheDir(), `${hashToken(token)}.json`);
28
+
29
+ export const writeRateLimit = (
30
+ token: string,
31
+ headers: Record<string, string | string[] | undefined>,
32
+ ): void => {
33
+ const dir = cacheDir();
34
+ if (!fs.existsSync(dir)) {
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ }
37
+ const pick = (key: string): string | undefined => {
38
+ const value = headers[key];
39
+ if (Array.isArray(value)) return value[0];
40
+ return value;
41
+ };
42
+ const payload = {
43
+ ts: Date.now() / 1000,
44
+ headers: {
45
+ 'anthropic-ratelimit-unified-status': pick(
46
+ 'anthropic-ratelimit-unified-status',
47
+ ),
48
+ 'anthropic-ratelimit-unified-5h-status': pick(
49
+ 'anthropic-ratelimit-unified-5h-status',
50
+ ),
51
+ 'anthropic-ratelimit-unified-5h-reset': pick(
52
+ 'anthropic-ratelimit-unified-5h-reset',
53
+ ),
54
+ 'anthropic-ratelimit-unified-5h-utilization': pick(
55
+ 'anthropic-ratelimit-unified-5h-utilization',
56
+ ),
57
+ 'anthropic-ratelimit-unified-7d-status': pick(
58
+ 'anthropic-ratelimit-unified-7d-status',
59
+ ),
60
+ 'anthropic-ratelimit-unified-7d-reset': pick(
61
+ 'anthropic-ratelimit-unified-7d-reset',
62
+ ),
63
+ 'anthropic-ratelimit-unified-7d-utilization': pick(
64
+ 'anthropic-ratelimit-unified-7d-utilization',
65
+ ),
66
+ },
67
+ };
68
+ const filePath = path.join(dir, `${hashToken(token)}.json`);
69
+ fs.writeFileSync(filePath, JSON.stringify(payload));
70
+ };
71
+
72
+ export const readRateLimit = (token: string): RateLimitSnapshot | null => {
73
+ const filePath = cachePathForToken(token);
74
+ if (!fs.existsSync(filePath)) return null;
75
+ try {
76
+ const raw = fs.readFileSync(filePath, 'utf8');
77
+ const parsed: unknown = JSON.parse(raw);
78
+ const isRecord = (value: unknown): value is Record<string, unknown> =>
79
+ value !== null && typeof value === 'object' && !Array.isArray(value);
80
+ if (!isRecord(parsed)) return null;
81
+ const headersUnknown = parsed.headers;
82
+ const headers: Record<string, string> = {};
83
+ if (isRecord(headersUnknown)) {
84
+ for (const [key, value] of Object.entries(headersUnknown)) {
85
+ if (typeof value === 'string') {
86
+ headers[key] = value;
87
+ }
88
+ }
89
+ }
90
+ const num = (key: string): number => {
91
+ const value = headers[key];
92
+ if (typeof value !== 'string') return 0;
93
+ const parsedValue = Number(value);
94
+ return Number.isFinite(parsedValue) ? parsedValue : 0;
95
+ };
96
+ const status = headers['anthropic-ratelimit-unified-status'];
97
+ const fiveHourStatus = headers['anthropic-ratelimit-unified-5h-status'];
98
+ const sevenDayStatus = headers['anthropic-ratelimit-unified-7d-status'];
99
+ return {
100
+ fiveHourUtilization: num('anthropic-ratelimit-unified-5h-utilization'),
101
+ fiveHourReset: num('anthropic-ratelimit-unified-5h-reset'),
102
+ sevenDayUtilization: num('anthropic-ratelimit-unified-7d-utilization'),
103
+ sevenDayReset: num('anthropic-ratelimit-unified-7d-reset'),
104
+ blocked:
105
+ status === 'blocked' ||
106
+ fiveHourStatus === 'blocked' ||
107
+ sevenDayStatus === 'blocked',
108
+ };
109
+ } catch {
110
+ return null;
111
+ }
112
+ };
@@ -0,0 +1,82 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { loadTokens } from './TokenListLoader';
5
+
6
+ describe('TokenListLoader', () => {
7
+ let tempDir: string;
8
+
9
+ beforeEach(() => {
10
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'token-list-loader-'));
11
+ });
12
+
13
+ afterEach(() => {
14
+ fs.rmSync(tempDir, { recursive: true, force: true });
15
+ });
16
+
17
+ it('should return tokens in the order they appear in the JSON file', () => {
18
+ const filePath = path.join(tempDir, 'tokens.json');
19
+ fs.writeFileSync(
20
+ filePath,
21
+ JSON.stringify([
22
+ { name: 'first', token: 'token-1' },
23
+ { name: 'second', token: 'token-2' },
24
+ ]),
25
+ );
26
+ expect(loadTokens(filePath)).toEqual(['token-1', 'token-2']);
27
+ });
28
+
29
+ it('should return null when the file does not exist', () => {
30
+ expect(loadTokens(path.join(tempDir, 'missing.json'))).toBeNull();
31
+ });
32
+
33
+ it('should return null when the JSON root is not an array', () => {
34
+ const filePath = path.join(tempDir, 'object.json');
35
+ fs.writeFileSync(filePath, JSON.stringify({ token: 'token-1' }));
36
+ expect(loadTokens(filePath)).toBeNull();
37
+ });
38
+
39
+ it('should return null when JSON parsing fails', () => {
40
+ const filePath = path.join(tempDir, 'malformed.json');
41
+ fs.writeFileSync(filePath, '{not json');
42
+ expect(loadTokens(filePath)).toBeNull();
43
+ });
44
+
45
+ it('should skip entries that do not contain a string token', () => {
46
+ const filePath = path.join(tempDir, 'mixed.json');
47
+ fs.writeFileSync(
48
+ filePath,
49
+ JSON.stringify([
50
+ { name: 'no-token' },
51
+ { name: 'first', token: 'token-1' },
52
+ { name: 'numeric', token: 123 },
53
+ { name: 'second', token: 'token-2' },
54
+ ]),
55
+ );
56
+ expect(loadTokens(filePath)).toEqual(['token-1', 'token-2']);
57
+ });
58
+
59
+ it('should return null when every entry is invalid', () => {
60
+ const filePath = path.join(tempDir, 'no-valid-entries.json');
61
+ fs.writeFileSync(
62
+ filePath,
63
+ JSON.stringify([{ name: 'no-token' }, { token: 42 }]),
64
+ );
65
+ expect(loadTokens(filePath)).toBeNull();
66
+ });
67
+
68
+ it('should expand a leading tilde to the home directory', () => {
69
+ const home = os.homedir();
70
+ const fileName = `tdpm-loader-${process.pid}-${Date.now()}.json`;
71
+ const targetPath = path.join(home, fileName);
72
+ fs.writeFileSync(
73
+ targetPath,
74
+ JSON.stringify([{ name: 'first', token: 'home-token' }]),
75
+ );
76
+ try {
77
+ expect(loadTokens(`~/${fileName}`)).toEqual(['home-token']);
78
+ } finally {
79
+ fs.unlinkSync(targetPath);
80
+ }
81
+ });
82
+ });