npm-cli-gh-issue-preparator 1.15.1 → 1.16.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.
- package/CHANGELOG.md +7 -0
- package/bin/adapter/entry-points/cli/index.js +13 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +155 -0
- package/src/adapter/entry-points/cli/index.ts +22 -0
- package/src/domain/usecases/StartPreparationUseCase.test.ts +91 -0
- package/src/domain/usecases/StartPreparationUseCase.ts +7 -1
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts +1 -0
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.16.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.15.1...v1.16.0) (2026-02-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **core:** add utilizationPercentageThreshold CLI option to startDaemon ([746aaba](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/746aaba045108e2e8d10846562958ebe5923e2dd))
|
|
7
|
+
|
|
1
8
|
## [1.15.1](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.15.0...v1.15.1) (2026-02-24)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -31,6 +31,7 @@ program
|
|
|
31
31
|
.requiredOption('--configFilePath <path>', 'Path to config file for tower defence management')
|
|
32
32
|
.option('--logFilePath <path>', 'Path to log file')
|
|
33
33
|
.option('--maximumPreparingIssuesCount <count>', 'Maximum number of issues in preparation status (default: 6)')
|
|
34
|
+
.option('--utilizationPercentageThreshold <percentage>', 'Claude usage percentage threshold for skipping preparation (default: 90)')
|
|
34
35
|
.action(async (options) => {
|
|
35
36
|
const token = process.env.GH_TOKEN;
|
|
36
37
|
if (!token) {
|
|
@@ -58,6 +59,17 @@ program
|
|
|
58
59
|
}
|
|
59
60
|
maximumPreparingIssuesCount = parsedCount;
|
|
60
61
|
}
|
|
62
|
+
let utilizationPercentageThreshold = 90;
|
|
63
|
+
if (options.utilizationPercentageThreshold !== undefined) {
|
|
64
|
+
const parsedThreshold = Number(options.utilizationPercentageThreshold);
|
|
65
|
+
if (!Number.isFinite(parsedThreshold) ||
|
|
66
|
+
parsedThreshold < 0 ||
|
|
67
|
+
parsedThreshold > 100) {
|
|
68
|
+
console.error('Invalid value for --utilizationPercentageThreshold. It must be a number between 0 and 100.');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
utilizationPercentageThreshold = parsedThreshold;
|
|
72
|
+
}
|
|
61
73
|
await useCase.run({
|
|
62
74
|
projectUrl: options.projectUrl,
|
|
63
75
|
awaitingWorkspaceStatus: options.awaitingWorkspaceStatus,
|
|
@@ -65,6 +77,7 @@ program
|
|
|
65
77
|
defaultAgentName: options.defaultAgentName,
|
|
66
78
|
logFilePath: options.logFilePath,
|
|
67
79
|
maximumPreparingIssuesCount,
|
|
80
|
+
utilizationPercentageThreshold,
|
|
68
81
|
});
|
|
69
82
|
});
|
|
70
83
|
program
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";;;;;;;AACA,oDAA4B;AAC5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,yCAAoC;AACpC,8FAA2F;AAC3F,0HAAuH;AACvH,gGAA6F;AAC7F,sFAAmF;AACnF,oGAAiG;AACjG,kGAA+F;AAC/F,sFAAmF;AACnF,0FAAuF;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ class StartPreparationUseCase {
|
|
|
10
10
|
this.run = async (params) => {
|
|
11
11
|
try {
|
|
12
12
|
const claudeUsages = await this.claudeRepository.getUsage();
|
|
13
|
-
if (claudeUsages.some((usage) => usage.utilizationPercentage >
|
|
13
|
+
if (claudeUsages.some((usage) => usage.utilizationPercentage > params.utilizationPercentageThreshold)) {
|
|
14
14
|
console.warn('Claude usage limit exceeded. Skipping starting preparation.');
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":";;;AAOA,MAAa,uBAAuB;IAClC,YACmB,iBAAsD,EACtD,eAGhB,EACgB,gBAAoD,EACpD,kBAAsC;QANtC,sBAAiB,GAAjB,iBAAiB,CAAqC;QACtD,oBAAe,GAAf,eAAe,CAG/B;QACgB,qBAAgB,GAAhB,gBAAgB,CAAoC;QACpD,uBAAkB,GAAlB,kBAAkB,CAAoB;QAGzD,QAAG,GAAG,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -78,6 +78,7 @@ describe('CLI', () => {
|
|
|
78
78
|
defaultAgentName: 'agent1',
|
|
79
79
|
logFilePath: undefined,
|
|
80
80
|
maximumPreparingIssuesCount: null,
|
|
81
|
+
utilizationPercentageThreshold: 90,
|
|
81
82
|
});
|
|
82
83
|
});
|
|
83
84
|
|
|
@@ -118,6 +119,7 @@ describe('CLI', () => {
|
|
|
118
119
|
defaultAgentName: 'agent1',
|
|
119
120
|
logFilePath: '/path/to/log.txt',
|
|
120
121
|
maximumPreparingIssuesCount: null,
|
|
122
|
+
utilizationPercentageThreshold: 90,
|
|
121
123
|
});
|
|
122
124
|
});
|
|
123
125
|
|
|
@@ -158,6 +160,7 @@ describe('CLI', () => {
|
|
|
158
160
|
defaultAgentName: 'agent1',
|
|
159
161
|
logFilePath: undefined,
|
|
160
162
|
maximumPreparingIssuesCount: 10,
|
|
163
|
+
utilizationPercentageThreshold: 90,
|
|
161
164
|
});
|
|
162
165
|
});
|
|
163
166
|
|
|
@@ -309,6 +312,158 @@ describe('CLI', () => {
|
|
|
309
312
|
processExitSpy.mockRestore();
|
|
310
313
|
});
|
|
311
314
|
|
|
315
|
+
it('should pass custom utilizationPercentageThreshold to StartPreparationUseCase when provided', async () => {
|
|
316
|
+
const mockRun = jest.fn().mockResolvedValue(undefined);
|
|
317
|
+
const MockedStartPreparationUseCase = jest.mocked(StartPreparationUseCase);
|
|
318
|
+
|
|
319
|
+
MockedStartPreparationUseCase.mockImplementation(function (
|
|
320
|
+
this: StartPreparationUseCase,
|
|
321
|
+
) {
|
|
322
|
+
this.run = mockRun;
|
|
323
|
+
return this;
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
await program.parseAsync([
|
|
327
|
+
'node',
|
|
328
|
+
'test',
|
|
329
|
+
'startDaemon',
|
|
330
|
+
'--projectUrl',
|
|
331
|
+
'https://github.com/test/project',
|
|
332
|
+
'--awaitingWorkspaceStatus',
|
|
333
|
+
'Awaiting',
|
|
334
|
+
'--preparationStatus',
|
|
335
|
+
'Preparing',
|
|
336
|
+
'--defaultAgentName',
|
|
337
|
+
'agent1',
|
|
338
|
+
'--configFilePath',
|
|
339
|
+
'/path/to/config.yml',
|
|
340
|
+
'--utilizationPercentageThreshold',
|
|
341
|
+
'75',
|
|
342
|
+
]);
|
|
343
|
+
|
|
344
|
+
expect(mockRun).toHaveBeenCalledTimes(1);
|
|
345
|
+
expect(mockRun).toHaveBeenCalledWith({
|
|
346
|
+
projectUrl: 'https://github.com/test/project',
|
|
347
|
+
awaitingWorkspaceStatus: 'Awaiting',
|
|
348
|
+
preparationStatus: 'Preparing',
|
|
349
|
+
defaultAgentName: 'agent1',
|
|
350
|
+
logFilePath: undefined,
|
|
351
|
+
maximumPreparingIssuesCount: null,
|
|
352
|
+
utilizationPercentageThreshold: 75,
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should exit with error for non-numeric utilizationPercentageThreshold', async () => {
|
|
357
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
358
|
+
const processExitSpy = jest
|
|
359
|
+
.spyOn(process, 'exit')
|
|
360
|
+
.mockImplementation(() => {
|
|
361
|
+
throw new Error('process.exit called');
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await expect(
|
|
365
|
+
program.parseAsync([
|
|
366
|
+
'node',
|
|
367
|
+
'test',
|
|
368
|
+
'startDaemon',
|
|
369
|
+
'--projectUrl',
|
|
370
|
+
'https://github.com/test/project',
|
|
371
|
+
'--awaitingWorkspaceStatus',
|
|
372
|
+
'Awaiting',
|
|
373
|
+
'--preparationStatus',
|
|
374
|
+
'Preparing',
|
|
375
|
+
'--defaultAgentName',
|
|
376
|
+
'agent1',
|
|
377
|
+
'--configFilePath',
|
|
378
|
+
'/path/to/config.yml',
|
|
379
|
+
'--utilizationPercentageThreshold',
|
|
380
|
+
'abc',
|
|
381
|
+
]),
|
|
382
|
+
).rejects.toThrow('process.exit called');
|
|
383
|
+
|
|
384
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
385
|
+
'Invalid value for --utilizationPercentageThreshold. It must be a number between 0 and 100.',
|
|
386
|
+
);
|
|
387
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
388
|
+
|
|
389
|
+
consoleErrorSpy.mockRestore();
|
|
390
|
+
processExitSpy.mockRestore();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should exit with error for negative utilizationPercentageThreshold', async () => {
|
|
394
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
395
|
+
const processExitSpy = jest
|
|
396
|
+
.spyOn(process, 'exit')
|
|
397
|
+
.mockImplementation(() => {
|
|
398
|
+
throw new Error('process.exit called');
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
await expect(
|
|
402
|
+
program.parseAsync([
|
|
403
|
+
'node',
|
|
404
|
+
'test',
|
|
405
|
+
'startDaemon',
|
|
406
|
+
'--projectUrl',
|
|
407
|
+
'https://github.com/test/project',
|
|
408
|
+
'--awaitingWorkspaceStatus',
|
|
409
|
+
'Awaiting',
|
|
410
|
+
'--preparationStatus',
|
|
411
|
+
'Preparing',
|
|
412
|
+
'--defaultAgentName',
|
|
413
|
+
'agent1',
|
|
414
|
+
'--configFilePath',
|
|
415
|
+
'/path/to/config.yml',
|
|
416
|
+
'--utilizationPercentageThreshold',
|
|
417
|
+
'-5',
|
|
418
|
+
]),
|
|
419
|
+
).rejects.toThrow('process.exit called');
|
|
420
|
+
|
|
421
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
422
|
+
'Invalid value for --utilizationPercentageThreshold. It must be a number between 0 and 100.',
|
|
423
|
+
);
|
|
424
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
425
|
+
|
|
426
|
+
consoleErrorSpy.mockRestore();
|
|
427
|
+
processExitSpy.mockRestore();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('should exit with error for utilizationPercentageThreshold over 100', async () => {
|
|
431
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
432
|
+
const processExitSpy = jest
|
|
433
|
+
.spyOn(process, 'exit')
|
|
434
|
+
.mockImplementation(() => {
|
|
435
|
+
throw new Error('process.exit called');
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
await expect(
|
|
439
|
+
program.parseAsync([
|
|
440
|
+
'node',
|
|
441
|
+
'test',
|
|
442
|
+
'startDaemon',
|
|
443
|
+
'--projectUrl',
|
|
444
|
+
'https://github.com/test/project',
|
|
445
|
+
'--awaitingWorkspaceStatus',
|
|
446
|
+
'Awaiting',
|
|
447
|
+
'--preparationStatus',
|
|
448
|
+
'Preparing',
|
|
449
|
+
'--defaultAgentName',
|
|
450
|
+
'agent1',
|
|
451
|
+
'--configFilePath',
|
|
452
|
+
'/path/to/config.yml',
|
|
453
|
+
'--utilizationPercentageThreshold',
|
|
454
|
+
'101',
|
|
455
|
+
]),
|
|
456
|
+
).rejects.toThrow('process.exit called');
|
|
457
|
+
|
|
458
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
459
|
+
'Invalid value for --utilizationPercentageThreshold. It must be a number between 0 and 100.',
|
|
460
|
+
);
|
|
461
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
462
|
+
|
|
463
|
+
consoleErrorSpy.mockRestore();
|
|
464
|
+
processExitSpy.mockRestore();
|
|
465
|
+
});
|
|
466
|
+
|
|
312
467
|
it('should pass correct parameters to NotifyFinishedIssuePreparationUseCase', async () => {
|
|
313
468
|
const mockRun = jest.fn().mockResolvedValue(undefined);
|
|
314
469
|
const MockedNotifyFinishedUseCase = jest.mocked(
|
|
@@ -19,6 +19,7 @@ type StartDaemonOptions = {
|
|
|
19
19
|
defaultAgentName: string;
|
|
20
20
|
logFilePath?: string;
|
|
21
21
|
maximumPreparingIssuesCount?: string;
|
|
22
|
+
utilizationPercentageThreshold?: string;
|
|
22
23
|
configFilePath: string;
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -59,6 +60,10 @@ program
|
|
|
59
60
|
'--maximumPreparingIssuesCount <count>',
|
|
60
61
|
'Maximum number of issues in preparation status (default: 6)',
|
|
61
62
|
)
|
|
63
|
+
.option(
|
|
64
|
+
'--utilizationPercentageThreshold <percentage>',
|
|
65
|
+
'Claude usage percentage threshold for skipping preparation (default: 90)',
|
|
66
|
+
)
|
|
62
67
|
.action(async (options: StartDaemonOptions) => {
|
|
63
68
|
const token = process.env.GH_TOKEN;
|
|
64
69
|
if (!token) {
|
|
@@ -109,6 +114,22 @@ program
|
|
|
109
114
|
maximumPreparingIssuesCount = parsedCount;
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
let utilizationPercentageThreshold = 90;
|
|
118
|
+
if (options.utilizationPercentageThreshold !== undefined) {
|
|
119
|
+
const parsedThreshold = Number(options.utilizationPercentageThreshold);
|
|
120
|
+
if (
|
|
121
|
+
!Number.isFinite(parsedThreshold) ||
|
|
122
|
+
parsedThreshold < 0 ||
|
|
123
|
+
parsedThreshold > 100
|
|
124
|
+
) {
|
|
125
|
+
console.error(
|
|
126
|
+
'Invalid value for --utilizationPercentageThreshold. It must be a number between 0 and 100.',
|
|
127
|
+
);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
utilizationPercentageThreshold = parsedThreshold;
|
|
131
|
+
}
|
|
132
|
+
|
|
112
133
|
await useCase.run({
|
|
113
134
|
projectUrl: options.projectUrl,
|
|
114
135
|
awaitingWorkspaceStatus: options.awaitingWorkspaceStatus,
|
|
@@ -116,6 +137,7 @@ program
|
|
|
116
137
|
defaultAgentName: options.defaultAgentName,
|
|
117
138
|
logFilePath: options.logFilePath,
|
|
118
139
|
maximumPreparingIssuesCount,
|
|
140
|
+
utilizationPercentageThreshold,
|
|
119
141
|
});
|
|
120
142
|
});
|
|
121
143
|
|
|
@@ -130,6 +130,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
130
130
|
preparationStatus: 'Preparation',
|
|
131
131
|
defaultAgentName: 'agent1',
|
|
132
132
|
maximumPreparingIssuesCount: null,
|
|
133
|
+
utilizationPercentageThreshold: 90,
|
|
133
134
|
});
|
|
134
135
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
135
136
|
expect(mockIssueRepository.update.mock.calls[0][0]).toMatchObject({
|
|
@@ -173,6 +174,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
173
174
|
preparationStatus: 'Preparation',
|
|
174
175
|
defaultAgentName: 'agent1',
|
|
175
176
|
maximumPreparingIssuesCount: null,
|
|
177
|
+
utilizationPercentageThreshold: 90,
|
|
176
178
|
});
|
|
177
179
|
// Both awaiting issues should be updated (forward iteration: url1 first, then url2)
|
|
178
180
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(2);
|
|
@@ -225,6 +227,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
225
227
|
preparationStatus: 'Preparation',
|
|
226
228
|
defaultAgentName: 'agent1',
|
|
227
229
|
maximumPreparingIssuesCount: null,
|
|
230
|
+
utilizationPercentageThreshold: 90,
|
|
228
231
|
});
|
|
229
232
|
// Loop doesn't run because we're already at max (6 >= 6)
|
|
230
233
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(0);
|
|
@@ -256,6 +259,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
256
259
|
defaultAgentName: 'agent1',
|
|
257
260
|
logFilePath: '/path/to/log.txt',
|
|
258
261
|
maximumPreparingIssuesCount: null,
|
|
262
|
+
utilizationPercentageThreshold: 90,
|
|
259
263
|
});
|
|
260
264
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
|
|
261
265
|
expect(mockLocalCommandRunner.runCommand.mock.calls[0][0]).toBe(
|
|
@@ -287,6 +291,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
287
291
|
preparationStatus: 'Preparation',
|
|
288
292
|
defaultAgentName: 'agent1',
|
|
289
293
|
maximumPreparingIssuesCount: null,
|
|
294
|
+
utilizationPercentageThreshold: 90,
|
|
290
295
|
});
|
|
291
296
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
|
|
292
297
|
expect(mockLocalCommandRunner.runCommand.mock.calls[0][0]).toBe(
|
|
@@ -319,6 +324,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
319
324
|
preparationStatus: 'Preparation',
|
|
320
325
|
defaultAgentName: 'agent1',
|
|
321
326
|
maximumPreparingIssuesCount: null,
|
|
327
|
+
utilizationPercentageThreshold: 90,
|
|
322
328
|
});
|
|
323
329
|
// No issues are in 'Awaiting Workspace' status, so no updates should happen
|
|
324
330
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(0);
|
|
@@ -349,6 +355,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
349
355
|
preparationStatus: 'Preparation',
|
|
350
356
|
defaultAgentName: 'agent1',
|
|
351
357
|
maximumPreparingIssuesCount: 3,
|
|
358
|
+
utilizationPercentageThreshold: 90,
|
|
352
359
|
});
|
|
353
360
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(3);
|
|
354
361
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(3);
|
|
@@ -378,6 +385,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
378
385
|
preparationStatus: 'Preparation',
|
|
379
386
|
defaultAgentName: 'agent1',
|
|
380
387
|
maximumPreparingIssuesCount: null,
|
|
388
|
+
utilizationPercentageThreshold: 90,
|
|
381
389
|
});
|
|
382
390
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(6);
|
|
383
391
|
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(6);
|
|
@@ -443,6 +451,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
443
451
|
preparationStatus: 'Preparation',
|
|
444
452
|
defaultAgentName: 'agent1',
|
|
445
453
|
maximumPreparingIssuesCount: null,
|
|
454
|
+
utilizationPercentageThreshold: 90,
|
|
446
455
|
});
|
|
447
456
|
|
|
448
457
|
// The blocked issue should be skipped (continue statement), but the blocker issue itself should be processed
|
|
@@ -494,6 +503,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
494
503
|
preparationStatus: 'Preparation',
|
|
495
504
|
defaultAgentName: 'agent1',
|
|
496
505
|
maximumPreparingIssuesCount: null,
|
|
506
|
+
utilizationPercentageThreshold: 90,
|
|
497
507
|
});
|
|
498
508
|
|
|
499
509
|
// The blocker issue should be processed since it's the blocker itself
|
|
@@ -562,6 +572,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
562
572
|
preparationStatus: 'Preparation',
|
|
563
573
|
defaultAgentName: 'agent1',
|
|
564
574
|
maximumPreparingIssuesCount: null,
|
|
575
|
+
utilizationPercentageThreshold: 90,
|
|
565
576
|
});
|
|
566
577
|
|
|
567
578
|
// The awaiting issue should be processed since there are no blockers (undefined returned empty array [])
|
|
@@ -597,6 +608,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
597
608
|
preparationStatus: 'Preparation',
|
|
598
609
|
defaultAgentName: 'agent1',
|
|
599
610
|
maximumPreparingIssuesCount: null,
|
|
611
|
+
utilizationPercentageThreshold: 90,
|
|
600
612
|
});
|
|
601
613
|
|
|
602
614
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(0);
|
|
@@ -635,6 +647,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
635
647
|
preparationStatus: 'Preparation',
|
|
636
648
|
defaultAgentName: 'agent1',
|
|
637
649
|
maximumPreparingIssuesCount: null,
|
|
650
|
+
utilizationPercentageThreshold: 90,
|
|
638
651
|
});
|
|
639
652
|
|
|
640
653
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -653,6 +666,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
653
666
|
preparationStatus: 'Preparation',
|
|
654
667
|
defaultAgentName: 'agent1',
|
|
655
668
|
maximumPreparingIssuesCount: null,
|
|
669
|
+
utilizationPercentageThreshold: 90,
|
|
656
670
|
});
|
|
657
671
|
|
|
658
672
|
expect(mockProjectRepository.getByUrl).not.toHaveBeenCalled();
|
|
@@ -690,6 +704,77 @@ describe('StartPreparationUseCase', () => {
|
|
|
690
704
|
preparationStatus: 'Preparation',
|
|
691
705
|
defaultAgentName: 'agent1',
|
|
692
706
|
maximumPreparingIssuesCount: null,
|
|
707
|
+
utilizationPercentageThreshold: 90,
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
711
|
+
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
it('should skip preparation when Claude usage exceeds custom threshold', async () => {
|
|
715
|
+
mockClaudeRepository.getUsage.mockResolvedValue([
|
|
716
|
+
{ hour: 5, utilizationPercentage: 75, resetsAt: new Date() },
|
|
717
|
+
]);
|
|
718
|
+
|
|
719
|
+
const awaitingIssues: Issue[] = [
|
|
720
|
+
createMockIssue({
|
|
721
|
+
url: 'url1',
|
|
722
|
+
title: 'Issue 1',
|
|
723
|
+
labels: [],
|
|
724
|
+
status: 'Awaiting Workspace',
|
|
725
|
+
}),
|
|
726
|
+
];
|
|
727
|
+
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
728
|
+
mockIssueRepository.getStoryObjectMap.mockResolvedValue(
|
|
729
|
+
createMockStoryObjectMap(awaitingIssues),
|
|
730
|
+
);
|
|
731
|
+
mockIssueRepository.getAllOpened.mockResolvedValueOnce(awaitingIssues);
|
|
732
|
+
|
|
733
|
+
await useCase.run({
|
|
734
|
+
projectUrl: 'https://github.com/user/repo',
|
|
735
|
+
awaitingWorkspaceStatus: 'Awaiting Workspace',
|
|
736
|
+
preparationStatus: 'Preparation',
|
|
737
|
+
defaultAgentName: 'agent1',
|
|
738
|
+
maximumPreparingIssuesCount: null,
|
|
739
|
+
utilizationPercentageThreshold: 70,
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
expect(mockIssueRepository.update.mock.calls).toHaveLength(0);
|
|
743
|
+
expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(0);
|
|
744
|
+
expect(mockProjectRepository.getByUrl).not.toHaveBeenCalled();
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
it('should proceed with preparation when Claude usage is under custom threshold', async () => {
|
|
748
|
+
mockClaudeRepository.getUsage.mockResolvedValue([
|
|
749
|
+
{ hour: 5, utilizationPercentage: 75, resetsAt: new Date() },
|
|
750
|
+
]);
|
|
751
|
+
|
|
752
|
+
const awaitingIssues: Issue[] = [
|
|
753
|
+
createMockIssue({
|
|
754
|
+
url: 'url1',
|
|
755
|
+
title: 'Issue 1',
|
|
756
|
+
labels: ['category:impl'],
|
|
757
|
+
status: 'Awaiting Workspace',
|
|
758
|
+
}),
|
|
759
|
+
];
|
|
760
|
+
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
761
|
+
mockIssueRepository.getStoryObjectMap.mockResolvedValue(
|
|
762
|
+
createMockStoryObjectMap(awaitingIssues),
|
|
763
|
+
);
|
|
764
|
+
mockIssueRepository.getAllOpened.mockResolvedValueOnce(awaitingIssues);
|
|
765
|
+
mockLocalCommandRunner.runCommand.mockResolvedValue({
|
|
766
|
+
stdout: '',
|
|
767
|
+
stderr: '',
|
|
768
|
+
exitCode: 0,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
await useCase.run({
|
|
772
|
+
projectUrl: 'https://github.com/user/repo',
|
|
773
|
+
awaitingWorkspaceStatus: 'Awaiting Workspace',
|
|
774
|
+
preparationStatus: 'Preparation',
|
|
775
|
+
defaultAgentName: 'agent1',
|
|
776
|
+
maximumPreparingIssuesCount: null,
|
|
777
|
+
utilizationPercentageThreshold: 80,
|
|
693
778
|
});
|
|
694
779
|
|
|
695
780
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -732,6 +817,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
732
817
|
preparationStatus: 'Preparation',
|
|
733
818
|
defaultAgentName: 'agent1',
|
|
734
819
|
maximumPreparingIssuesCount: null,
|
|
820
|
+
utilizationPercentageThreshold: 90,
|
|
735
821
|
});
|
|
736
822
|
|
|
737
823
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -785,6 +871,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
785
871
|
preparationStatus: 'Preparation',
|
|
786
872
|
defaultAgentName: 'agent1',
|
|
787
873
|
maximumPreparingIssuesCount: null,
|
|
874
|
+
utilizationPercentageThreshold: 90,
|
|
788
875
|
});
|
|
789
876
|
|
|
790
877
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -841,6 +928,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
841
928
|
preparationStatus: 'Preparation',
|
|
842
929
|
defaultAgentName: 'agent1',
|
|
843
930
|
maximumPreparingIssuesCount: null,
|
|
931
|
+
utilizationPercentageThreshold: 90,
|
|
844
932
|
});
|
|
845
933
|
|
|
846
934
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -886,6 +974,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
886
974
|
preparationStatus: 'Preparation',
|
|
887
975
|
defaultAgentName: 'agent1',
|
|
888
976
|
maximumPreparingIssuesCount: null,
|
|
977
|
+
utilizationPercentageThreshold: 90,
|
|
889
978
|
});
|
|
890
979
|
|
|
891
980
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -931,6 +1020,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
931
1020
|
preparationStatus: 'Preparation',
|
|
932
1021
|
defaultAgentName: 'agent1',
|
|
933
1022
|
maximumPreparingIssuesCount: null,
|
|
1023
|
+
utilizationPercentageThreshold: 90,
|
|
934
1024
|
});
|
|
935
1025
|
|
|
936
1026
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -976,6 +1066,7 @@ describe('StartPreparationUseCase', () => {
|
|
|
976
1066
|
preparationStatus: 'Preparation',
|
|
977
1067
|
defaultAgentName: 'agent1',
|
|
978
1068
|
maximumPreparingIssuesCount: null,
|
|
1069
|
+
utilizationPercentageThreshold: 90,
|
|
979
1070
|
});
|
|
980
1071
|
|
|
981
1072
|
expect(mockIssueRepository.update.mock.calls).toHaveLength(1);
|
|
@@ -23,10 +23,16 @@ export class StartPreparationUseCase {
|
|
|
23
23
|
defaultAgentName: string;
|
|
24
24
|
logFilePath?: string;
|
|
25
25
|
maximumPreparingIssuesCount: number | null;
|
|
26
|
+
utilizationPercentageThreshold: number;
|
|
26
27
|
}): Promise<void> => {
|
|
27
28
|
try {
|
|
28
29
|
const claudeUsages = await this.claudeRepository.getUsage();
|
|
29
|
-
if (
|
|
30
|
+
if (
|
|
31
|
+
claudeUsages.some(
|
|
32
|
+
(usage) =>
|
|
33
|
+
usage.utilizationPercentage > params.utilizationPercentageThreshold,
|
|
34
|
+
)
|
|
35
|
+
) {
|
|
30
36
|
console.warn(
|
|
31
37
|
'Claude usage limit exceeded. Skipping starting preparation.',
|
|
32
38
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAwL9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -16,6 +16,7 @@ export declare class StartPreparationUseCase {
|
|
|
16
16
|
defaultAgentName: string;
|
|
17
17
|
logFilePath?: string;
|
|
18
18
|
maximumPreparingIssuesCount: number | null;
|
|
19
|
+
utilizationPercentageThreshold: number;
|
|
19
20
|
}) => Promise<void>;
|
|
20
21
|
createWorkflowBockerIsues: (storyObjectMap: StoryObjectMap) => {
|
|
21
22
|
orgRepo: 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;AAE7E,OAAO,EAAe,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAIhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBANlB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACf,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAChD,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
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;AAE7E,OAAO,EAAe,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAEzE,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAIhC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBANlB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACf,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAChD,EACgB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EACpD,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3C,8BAA8B,EAAE,MAAM,CAAC;KACxC,KAAG,OAAO,CAAC,IAAI,CAAC,CA8Ff;IACF,yBAAyB,GACvB,gBAAgB,cAAc,KAC7B;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,EAAE,CAyBD;CACH"}
|