github-issue-tower-defence-management 1.133.0 → 1.135.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +5 -4
  3. package/bin/adapter/entry-points/cli/index.js +11 -1
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/cli/projectConfig.js +21 -0
  6. package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
  7. package/bin/adapter/entry-points/console/dashboardComposeService.js +18 -0
  8. package/bin/adapter/entry-points/console/dashboardComposeService.js.map +1 -1
  9. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +81 -54
  10. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  11. package/bin/adapter/entry-points/handlers/machineStatusWriter.js +6 -0
  12. package/bin/adapter/entry-points/handlers/machineStatusWriter.js.map +1 -1
  13. package/bin/adapter/repositories/ProcHostMetricsRepository.js +4 -0
  14. package/bin/adapter/repositories/ProcHostMetricsRepository.js.map +1 -1
  15. package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -0
  16. package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
  17. package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js +6 -0
  18. package/bin/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.js.map +1 -1
  19. package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js +26 -4
  20. package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/adapter/entry-points/cli/index.test.ts +42 -1
  23. package/src/adapter/entry-points/cli/index.ts +20 -1
  24. package/src/adapter/entry-points/cli/projectConfig.test.ts +75 -0
  25. package/src/adapter/entry-points/cli/projectConfig.ts +31 -0
  26. package/src/adapter/entry-points/console/dashboardComposeService.test.ts +32 -0
  27. package/src/adapter/entry-points/console/dashboardComposeService.ts +20 -0
  28. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.test.ts +66 -0
  29. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +7 -1
  30. package/src/adapter/entry-points/handlers/machineStatusWriter.test.ts +61 -0
  31. package/src/adapter/entry-points/handlers/machineStatusWriter.ts +17 -0
  32. package/src/adapter/repositories/ProcHostMetricsRepository.test.ts +25 -0
  33. package/src/adapter/repositories/ProcHostMetricsRepository.ts +5 -0
  34. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +26 -3
  35. package/src/domain/usecases/HandleScheduledEventUseCase.ts +1 -0
  36. package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.test.ts +157 -1
  37. package/src/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.ts +7 -0
  38. package/src/domain/usecases/dashboard/ComposeDashboardUseCase.test.ts +55 -0
  39. package/src/domain/usecases/dashboard/ComposeDashboardUseCase.ts +34 -5
  40. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  41. package/types/adapter/entry-points/cli/projectConfig.d.ts +5 -0
  42. package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
  43. package/types/adapter/entry-points/console/dashboardComposeService.d.ts.map +1 -1
  44. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts +1 -1
  45. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  46. package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts +7 -0
  47. package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts.map +1 -1
  48. package/types/adapter/repositories/ProcHostMetricsRepository.d.ts +1 -0
  49. package/types/adapter/repositories/ProcHostMetricsRepository.d.ts.map +1 -1
  50. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
  51. package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts +1 -0
  52. package/types/domain/usecases/RevertNotReadyReviewQueueIssueUseCase.d.ts.map +1 -1
  53. package/types/domain/usecases/dashboard/ComposeDashboardUseCase.d.ts +6 -1
  54. package/types/domain/usecases/dashboard/ComposeDashboardUseCase.d.ts.map +1 -1
  55. package/types/index.d.ts +1 -1
@@ -69,7 +69,7 @@ const createMockIssue = (overrides: Partial<Issue> = {}): Issue => ({
69
69
  dependedIssueUrls: [],
70
70
  completionDate50PercentConfidence: null,
71
71
  url: 'https://github.com/user/repo/issues/1',
72
- assignees: [],
72
+ assignees: ['manager-user'],
73
73
  labels: [],
74
74
  org: 'user',
75
75
  repo: 'repo',
@@ -217,6 +217,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
217
217
  });
218
218
 
219
219
  await useCase.run({
220
+ manager: 'manager-user',
220
221
  projectUrl: 'https://github.com/users/user/projects/1',
221
222
  allowedIssueAuthors: ['owner'],
222
223
  });
@@ -237,6 +238,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
237
238
  });
238
239
 
239
240
  await useCase.run({
241
+ manager: 'manager-user',
240
242
  projectUrl: 'https://github.com/users/user/projects/1',
241
243
  allowedIssueAuthors: ['owner'],
242
244
  });
@@ -256,6 +258,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
256
258
  });
257
259
 
258
260
  await useCase.run({
261
+ manager: 'manager-user',
259
262
  projectUrl: 'https://github.com/users/user/projects/1',
260
263
  allowedIssueAuthors: ['owner'],
261
264
  });
@@ -287,6 +290,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
287
290
  });
288
291
 
289
292
  await useCase.run({
293
+ manager: 'manager-user',
290
294
  projectUrl: 'https://github.com/users/user/projects/1',
291
295
  labelsAsLlmAgentName: ['story', 'chore', 'accounting'],
292
296
  allowedIssueAuthors: ['owner'],
@@ -308,6 +312,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
308
312
  });
309
313
 
310
314
  await useCase.run({
315
+ manager: 'manager-user',
311
316
  projectUrl: 'https://github.com/users/user/projects/1',
312
317
  labelsAsLlmAgentName: ['story', 'chore'],
313
318
  allowedIssueAuthors: ['owner'],
@@ -329,6 +334,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
329
334
  });
330
335
 
331
336
  await useCase.run({
337
+ manager: 'manager-user',
332
338
  projectUrl: 'https://github.com/users/user/projects/1',
333
339
  allowedIssueAuthors: ['owner'],
334
340
  });
@@ -356,6 +362,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
356
362
  });
357
363
 
358
364
  await useCase.run({
365
+ manager: 'manager-user',
359
366
  projectUrl: 'https://github.com/users/user/projects/1',
360
367
  labelsAsLlmAgentName: null,
361
368
  allowedIssueAuthors: ['owner'],
@@ -375,6 +382,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
375
382
  linkRelatedOpenPrsToIssue(mockIssueRepository, issue, [createReadyPr()]);
376
383
 
377
384
  await useCase.run({
385
+ manager: 'manager-user',
378
386
  projectUrl: 'https://github.com/users/user/projects/1',
379
387
  allowedIssueAuthors: ['owner'],
380
388
  });
@@ -392,6 +400,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
392
400
  ]);
393
401
 
394
402
  await useCase.run({
403
+ manager: 'manager-user',
395
404
  projectUrl: 'https://github.com/users/user/projects/1',
396
405
  allowedIssueAuthors: ['owner'],
397
406
  });
@@ -424,6 +433,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
424
433
  ]);
425
434
 
426
435
  await useCase.run({
436
+ manager: 'manager-user',
427
437
  projectUrl: 'https://github.com/users/user/projects/1',
428
438
  allowedIssueAuthors: ['owner'],
429
439
  });
@@ -452,6 +462,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
452
462
  ]);
453
463
 
454
464
  await useCase.run({
465
+ manager: 'manager-user',
455
466
  projectUrl: 'https://github.com/users/user/projects/1',
456
467
  allowedIssueAuthors: ['owner'],
457
468
  });
@@ -480,6 +491,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
480
491
  ]);
481
492
 
482
493
  await useCase.run({
494
+ manager: 'manager-user',
483
495
  projectUrl: 'https://github.com/users/user/projects/1',
484
496
  allowedIssueAuthors: ['owner'],
485
497
  });
@@ -509,6 +521,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
509
521
  ]);
510
522
 
511
523
  await useCase.run({
524
+ manager: 'manager-user',
512
525
  projectUrl: 'https://github.com/users/user/projects/1',
513
526
  allowedIssueAuthors: ['owner'],
514
527
  });
@@ -542,6 +555,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
542
555
  ]);
543
556
 
544
557
  await useCase.run({
558
+ manager: 'manager-user',
545
559
  projectUrl: 'https://github.com/users/user/projects/1',
546
560
  allowedIssueAuthors: ['owner'],
547
561
  });
@@ -605,6 +619,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
605
619
  );
606
620
 
607
621
  await useCase.run({
622
+ manager: 'manager-user',
608
623
  projectUrl: 'https://github.com/users/user/projects/1',
609
624
  allowedIssueAuthors: ['owner'],
610
625
  });
@@ -650,6 +665,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
650
665
  );
651
666
 
652
667
  await useCase.run({
668
+ manager: 'manager-user',
653
669
  projectUrl: 'https://github.com/users/user/projects/1',
654
670
  allowedIssueAuthors: ['owner'],
655
671
  });
@@ -682,6 +698,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
682
698
  });
683
699
 
684
700
  await useCase.run({
701
+ manager: 'manager-user',
685
702
  projectUrl: 'https://github.com/users/user/projects/1',
686
703
  allowedIssueAuthors: ['owner'],
687
704
  });
@@ -713,6 +730,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
713
730
 
714
731
  const runCycle = () =>
715
732
  useCase.run({
733
+ manager: 'manager-user',
716
734
  projectUrl: 'https://github.com/users/user/projects/1',
717
735
  allowedIssueAuthors: ['owner'],
718
736
  });
@@ -912,6 +930,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
912
930
  ]);
913
931
 
914
932
  await useCase.run({
933
+ manager: 'manager-user',
915
934
  projectUrl: 'https://github.com/users/user/projects/1',
916
935
  allowedIssueAuthors: ['owner'],
917
936
  changeTargetPathAliases: {
@@ -931,6 +950,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
931
950
  ]);
932
951
 
933
952
  await useCase.run({
953
+ manager: 'manager-user',
934
954
  projectUrl: 'https://github.com/users/user/projects/1',
935
955
  allowedIssueAuthors: ['owner'],
936
956
  changeTargetPathAliases: {
@@ -955,6 +975,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
955
975
  });
956
976
 
957
977
  await useCase.run({
978
+ manager: 'manager-user',
958
979
  projectUrl: 'https://github.com/users/user/projects/1',
959
980
  allowedIssueAuthors: ['owner'],
960
981
  });
@@ -977,6 +998,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
977
998
  });
978
999
 
979
1000
  await useCase.run({
1001
+ manager: 'manager-user',
980
1002
  projectUrl: 'https://github.com/users/user/projects/1',
981
1003
  allowedIssueAuthors: ['owner'],
982
1004
  });
@@ -998,6 +1020,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
998
1020
  });
999
1021
 
1000
1022
  await useCase.run({
1023
+ manager: 'manager-user',
1001
1024
  projectUrl: 'https://github.com/users/user/projects/1',
1002
1025
  allowedIssueAuthors: ['owner'],
1003
1026
  });
@@ -1019,6 +1042,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1019
1042
  mockIssueRepository.getOpenPullRequest.mockResolvedValue(createReadyPr());
1020
1043
 
1021
1044
  await useCase.run({
1045
+ manager: 'manager-user',
1022
1046
  projectUrl: 'https://github.com/users/user/projects/1',
1023
1047
  allowedIssueAuthors: ['owner'],
1024
1048
  });
@@ -1043,6 +1067,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1043
1067
  });
1044
1068
 
1045
1069
  await useCase.run({
1070
+ manager: 'manager-user',
1046
1071
  projectUrl: 'https://github.com/users/user/projects/1',
1047
1072
  allowedIssueAuthors: ['owner'],
1048
1073
  });
@@ -1083,6 +1108,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1083
1108
  });
1084
1109
 
1085
1110
  await useCase.run({
1111
+ manager: 'manager-user',
1086
1112
  projectUrl: 'https://github.com/users/user/projects/1',
1087
1113
  allowedIssueAuthors: ['owner'],
1088
1114
  });
@@ -1118,6 +1144,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1118
1144
  });
1119
1145
 
1120
1146
  await useCase.run({
1147
+ manager: 'manager-user',
1121
1148
  projectUrl: 'https://github.com/users/user/projects/1',
1122
1149
  allowedIssueAuthors: ['owner'],
1123
1150
  });
@@ -1155,6 +1182,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1155
1182
  });
1156
1183
 
1157
1184
  await useCase.run({
1185
+ manager: 'manager-user',
1158
1186
  projectUrl: 'https://github.com/users/user/projects/1',
1159
1187
  allowedIssueAuthors: ['owner'],
1160
1188
  });
@@ -1190,6 +1218,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1190
1218
  });
1191
1219
 
1192
1220
  await useCase.run({
1221
+ manager: 'manager-user',
1193
1222
  projectUrl: 'https://github.com/users/user/projects/1',
1194
1223
  allowedIssueAuthors: ['owner'],
1195
1224
  });
@@ -1222,6 +1251,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1222
1251
  mockIssueRepository.getOpenPullRequest.mockResolvedValue(null);
1223
1252
 
1224
1253
  await useCase.run({
1254
+ manager: 'manager-user',
1225
1255
  projectUrl: 'https://github.com/users/user/projects/1',
1226
1256
  allowedIssueAuthors: ['owner'],
1227
1257
  });
@@ -1260,6 +1290,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1260
1290
  });
1261
1291
 
1262
1292
  await useCase.run({
1293
+ manager: 'manager-user',
1263
1294
  projectUrl: 'https://github.com/users/user/projects/1',
1264
1295
  allowedIssueAuthors: ['owner'],
1265
1296
  });
@@ -1305,6 +1336,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1305
1336
  });
1306
1337
 
1307
1338
  await useCase.run({
1339
+ manager: 'manager-user',
1308
1340
  projectUrl: 'https://github.com/users/user/projects/1',
1309
1341
  allowedIssueAuthors: ['owner'],
1310
1342
  });
@@ -1331,6 +1363,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1331
1363
  });
1332
1364
 
1333
1365
  await useCase.run({
1366
+ manager: 'manager-user',
1334
1367
  projectUrl: 'https://github.com/users/user/projects/1',
1335
1368
  allowedIssueAuthors: ['owner'],
1336
1369
  });
@@ -1356,6 +1389,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1356
1389
  });
1357
1390
 
1358
1391
  await useCase.run({
1392
+ manager: 'manager-user',
1359
1393
  projectUrl: 'https://github.com/users/user/projects/1',
1360
1394
  allowedIssueAuthors: ['owner'],
1361
1395
  });
@@ -1392,6 +1426,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1392
1426
  });
1393
1427
 
1394
1428
  await useCase.run({
1429
+ manager: 'manager-user',
1395
1430
  projectUrl: 'https://github.com/users/user/projects/1',
1396
1431
  allowedIssueAuthors: ['owner'],
1397
1432
  });
@@ -1417,6 +1452,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1417
1452
  });
1418
1453
 
1419
1454
  await useCase.run({
1455
+ manager: 'manager-user',
1420
1456
  projectUrl: 'https://github.com/users/user/projects/1',
1421
1457
  allowedIssueAuthors: ['owner', 'dependabot[bot]'],
1422
1458
  });
@@ -1448,6 +1484,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1448
1484
  });
1449
1485
 
1450
1486
  await useCase.run({
1487
+ manager: 'manager-user',
1451
1488
  projectUrl: 'https://github.com/users/user/projects/1',
1452
1489
  allowedIssueAuthors: null,
1453
1490
  });
@@ -1473,6 +1510,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1473
1510
  });
1474
1511
 
1475
1512
  await useCase.run({
1513
+ manager: 'manager-user',
1476
1514
  projectUrl: 'https://github.com/users/user/projects/1',
1477
1515
  });
1478
1516
 
@@ -1497,6 +1535,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1497
1535
  });
1498
1536
 
1499
1537
  await useCase.run({
1538
+ manager: 'manager-user',
1500
1539
  projectUrl: 'https://github.com/users/user/projects/1',
1501
1540
  allowedIssueAuthors: [],
1502
1541
  });
@@ -1547,6 +1586,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1547
1586
  );
1548
1587
 
1549
1588
  await useCase.run({
1589
+ manager: 'manager-user',
1550
1590
  projectUrl: 'https://github.com/users/user/projects/1',
1551
1591
  allowedIssueAuthors: ['owner'],
1552
1592
  });
@@ -1589,6 +1629,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1589
1629
 
1590
1630
  await expect(
1591
1631
  useCase.run({
1632
+ manager: 'manager-user',
1592
1633
  projectUrl: 'https://github.com/users/user/projects/1',
1593
1634
  allowedIssueAuthors: ['owner'],
1594
1635
  }),
@@ -1632,6 +1673,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1632
1673
  );
1633
1674
 
1634
1675
  await useCase.run({
1676
+ manager: 'manager-user',
1635
1677
  projectUrl: 'https://github.com/users/user/projects/1',
1636
1678
  allowedIssueAuthors: ['owner'],
1637
1679
  });
@@ -1688,6 +1730,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1688
1730
 
1689
1731
  await expect(
1690
1732
  useCase.run({
1733
+ manager: 'manager-user',
1691
1734
  projectUrl: 'https://github.com/users/user/projects/1',
1692
1735
  allowedIssueAuthors: ['owner'],
1693
1736
  }),
@@ -1743,6 +1786,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1743
1786
  );
1744
1787
 
1745
1788
  await useCase.run({
1789
+ manager: 'manager-user',
1746
1790
  projectUrl: 'https://github.com/users/user/projects/1',
1747
1791
  allowedIssueAuthors: ['owner'],
1748
1792
  });
@@ -1796,6 +1840,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1796
1840
  );
1797
1841
 
1798
1842
  await useCase.run({
1843
+ manager: 'manager-user',
1799
1844
  projectUrl: 'https://github.com/users/user/projects/1',
1800
1845
  allowedIssueAuthors: ['owner'],
1801
1846
  });
@@ -1842,6 +1887,7 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1842
1887
  );
1843
1888
 
1844
1889
  await useCase.run({
1890
+ manager: 'manager-user',
1845
1891
  projectUrl: 'https://github.com/users/user/projects/1',
1846
1892
  allowedIssueAuthors: ['owner'],
1847
1893
  });
@@ -1894,10 +1940,120 @@ describe('RevertNotReadyReviewQueueIssueUseCase', () => {
1894
1940
 
1895
1941
  await expect(
1896
1942
  useCase.run({
1943
+ manager: 'manager-user',
1897
1944
  projectUrl: 'https://github.com/users/user/projects/1',
1898
1945
  allowedIssueAuthors: ['owner'],
1899
1946
  }),
1900
1947
  ).rejects.toThrow('Something went wrong');
1901
1948
  });
1902
1949
  });
1950
+
1951
+ describe('manager-assignee gating', () => {
1952
+ it('should not revert a rejected Awaiting Quality Check issue that is not assigned to the manager', async () => {
1953
+ const issue = createMockIssue({
1954
+ status: 'Awaiting Quality Check',
1955
+ assignees: ['other-user'],
1956
+ });
1957
+ mockIssueRepository.getAllIssues.mockResolvedValue({
1958
+ project: mockProject,
1959
+ issues: [issue],
1960
+ cacheUsed: false,
1961
+ });
1962
+
1963
+ await useCase.run({
1964
+ manager: 'manager-user',
1965
+ projectUrl: 'https://github.com/users/user/projects/1',
1966
+ allowedIssueAuthors: ['owner'],
1967
+ });
1968
+
1969
+ expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
1970
+ expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
1971
+ });
1972
+
1973
+ it('should revert a rejected Awaiting Quality Check issue that is assigned to the manager', async () => {
1974
+ const issue = createMockIssue({
1975
+ status: 'Awaiting Quality Check',
1976
+ assignees: ['manager-user'],
1977
+ });
1978
+ mockIssueRepository.getAllIssues.mockResolvedValue({
1979
+ project: mockProject,
1980
+ issues: [issue],
1981
+ cacheUsed: false,
1982
+ });
1983
+
1984
+ await useCase.run({
1985
+ manager: 'manager-user',
1986
+ projectUrl: 'https://github.com/users/user/projects/1',
1987
+ allowedIssueAuthors: ['owner'],
1988
+ });
1989
+
1990
+ expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
1991
+ mockProject,
1992
+ issue,
1993
+ 'awaiting-workspace-id',
1994
+ );
1995
+ expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
1996
+ issue,
1997
+ expect.stringContaining('Auto Status Check: REJECTED'),
1998
+ );
1999
+ });
2000
+
2001
+ it('should not revert a rejected Unread pull request that is not assigned to the manager', async () => {
2002
+ const pullRequest = createMockPullRequest({
2003
+ status: 'Unread',
2004
+ assignees: ['other-user'],
2005
+ });
2006
+ mockIssueRepository.getAllIssues.mockResolvedValue({
2007
+ project: mockProject,
2008
+ issues: [pullRequest],
2009
+ cacheUsed: false,
2010
+ });
2011
+ mockIssueRepository.getOpenPullRequest.mockResolvedValue({
2012
+ ...createReadyPr(),
2013
+ isConflicted: true,
2014
+ });
2015
+
2016
+ await useCase.run({
2017
+ manager: 'manager-user',
2018
+ projectUrl: 'https://github.com/users/user/projects/1',
2019
+ allowedIssueAuthors: ['owner'],
2020
+ });
2021
+
2022
+ expect(mockIssueRepository.updateStatus).not.toHaveBeenCalled();
2023
+ expect(mockIssueRepository.updateStory).not.toHaveBeenCalled();
2024
+ expect(mockIssueCommentRepository.createComment).not.toHaveBeenCalled();
2025
+ });
2026
+
2027
+ it('should revert a rejected Unread pull request that is assigned to the manager', async () => {
2028
+ const pullRequest = createMockPullRequest({
2029
+ status: 'Unread',
2030
+ assignees: ['manager-user'],
2031
+ });
2032
+ mockIssueRepository.getAllIssues.mockResolvedValue({
2033
+ project: mockProject,
2034
+ issues: [pullRequest],
2035
+ cacheUsed: false,
2036
+ });
2037
+ mockIssueRepository.getOpenPullRequest.mockResolvedValue({
2038
+ ...createReadyPr(),
2039
+ isConflicted: true,
2040
+ });
2041
+
2042
+ await useCase.run({
2043
+ manager: 'manager-user',
2044
+ projectUrl: 'https://github.com/users/user/projects/1',
2045
+ allowedIssueAuthors: ['owner'],
2046
+ });
2047
+
2048
+ expect(mockIssueRepository.updateStatus).toHaveBeenCalledWith(
2049
+ mockProject,
2050
+ pullRequest,
2051
+ 'awaiting-workspace-id',
2052
+ );
2053
+ expect(mockIssueCommentRepository.createComment).toHaveBeenCalledWith(
2054
+ pullRequest,
2055
+ expect.stringContaining('Auto Status Check: REJECTED'),
2056
+ );
2057
+ });
2058
+ });
1903
2059
  });
@@ -69,6 +69,7 @@ export class RevertNotReadyReviewQueueIssueUseCase {
69
69
 
70
70
  run = async (params: {
71
71
  projectUrl: string;
72
+ manager: string;
72
73
  labelsAsLlmAgentName?: string[] | null;
73
74
  changeTargetPathAliases?: Record<string, string> | null;
74
75
  allowedIssueAuthors?: string[] | null;
@@ -128,6 +129,9 @@ export class RevertNotReadyReviewQueueIssueUseCase {
128
129
  },
129
130
  );
130
131
  if (rejections.length > 0) {
132
+ if (!issue.assignees.includes(params.manager)) {
133
+ continue;
134
+ }
131
135
  try {
132
136
  await this.issueRepository.updateStatus(
133
137
  project,
@@ -194,6 +198,9 @@ export class RevertNotReadyReviewQueueIssueUseCase {
194
198
  params.labelsAsLlmAgentName ?? [],
195
199
  );
196
200
  if (rejections.length > 0) {
201
+ if (!pullRequest.assignees.includes(params.manager)) {
202
+ continue;
203
+ }
197
204
  try {
198
205
  await this.issueRepository.updateStatus(
199
206
  project,
@@ -120,6 +120,61 @@ describe('formatMachineStatusLines', () => {
120
120
  ).toEqual(['M55% C62% D?% cy13', 'LA 16 23 40']);
121
121
  });
122
122
 
123
+ it('renders each configured partition as title and percent on a disk line', () => {
124
+ expect(
125
+ formatMachineStatusLines({
126
+ memPct: 55,
127
+ cpuPct: 62,
128
+ diskPct: 89,
129
+ disks: [
130
+ { title: 'D', pct: 89 },
131
+ { title: 'S', pct: 41 },
132
+ ],
133
+ load: [16, 23, 40],
134
+ cycleMinutes: 13,
135
+ }),
136
+ ).toEqual(['M55% C62% cy13', 'D89% S41%', 'LA 16 23 40']);
137
+ });
138
+
139
+ it('wraps partitions onto a second disk line when they exceed the width budget', () => {
140
+ const lines = formatMachineStatusLines({
141
+ memPct: 55,
142
+ cpuPct: 62,
143
+ diskPct: 89,
144
+ disks: [
145
+ { title: 'D', pct: 100 },
146
+ { title: 'S', pct: 100 },
147
+ { title: 'A', pct: 100 },
148
+ { title: 'B', pct: 100 },
149
+ { title: 'C', pct: 100 },
150
+ { title: 'E', pct: 100 },
151
+ { title: 'F', pct: 100 },
152
+ ],
153
+ load: [16, 23, 40],
154
+ cycleMinutes: 13,
155
+ });
156
+ expect(lines[0]).toBe('M55% C62% cy13');
157
+ expect(lines[lines.length - 1]).toBe('LA 16 23 40');
158
+ expect(lines.length).toBeGreaterThan(3);
159
+ for (const line of lines) {
160
+ expect(codePointLength(line)).toBeLessThanOrEqual(
161
+ PROJECT_ROW_WIDTH_BUDGET,
162
+ );
163
+ }
164
+ });
165
+
166
+ it('renders the single disk percent when no disks list is present', () => {
167
+ expect(
168
+ formatMachineStatusLines({
169
+ memPct: 55,
170
+ cpuPct: 62,
171
+ diskPct: 89,
172
+ load: [16, 23, 40],
173
+ cycleMinutes: 13,
174
+ }),
175
+ ).toEqual(['M55% C62% D89% cy13', 'LA 16 23 40']);
176
+ });
177
+
123
178
  it('keeps both lines within the 32 character width budget at worst case', () => {
124
179
  const lines = formatMachineStatusLines({
125
180
  memPct: 100,
@@ -8,10 +8,16 @@ export type ComposeDashboardProject = {
8
8
  row: DashboardRow | null;
9
9
  };
10
10
 
11
+ export type ComposeDashboardDisk = {
12
+ title: string;
13
+ pct: number;
14
+ };
15
+
11
16
  export type ComposeDashboardMachineStatus = {
12
17
  memPct: number | null;
13
18
  cpuPct: number | null;
14
19
  diskPct: number | null;
20
+ disks?: ComposeDashboardDisk[] | null;
15
21
  load: [number, number, number] | null;
16
22
  cycleMinutes: number | null;
17
23
  };
@@ -98,9 +104,27 @@ export const formatResetCountdown = (totalSeconds: number): string => {
98
104
  )}`;
99
105
  };
100
106
 
107
+ const packTokensWithinBudget = (tokens: string[]): string[] => {
108
+ const lines: string[] = [];
109
+ let current = '';
110
+ for (const token of tokens) {
111
+ const candidate = current === '' ? token : `${current} ${token}`;
112
+ if (current !== '' && candidate.length > PROJECT_ROW_WIDTH_BUDGET) {
113
+ lines.push(current);
114
+ current = token;
115
+ } else {
116
+ current = candidate;
117
+ }
118
+ }
119
+ if (current !== '') {
120
+ lines.push(current);
121
+ }
122
+ return lines;
123
+ };
124
+
101
125
  export const formatMachineStatusLines = (
102
126
  machineStatus: ComposeDashboardMachineStatus | null,
103
- ): [string, string] => {
127
+ ): string[] => {
104
128
  const memText =
105
129
  machineStatus !== null && machineStatus.memPct !== null
106
130
  ? `${machineStatus.memPct}%`
@@ -121,10 +145,15 @@ export const formatMachineStatusLines = (
121
145
  machineStatus !== null && machineStatus.cycleMinutes !== null
122
146
  ? `cy${machineStatus.cycleMinutes}`
123
147
  : 'cy-';
124
- return [
125
- `M${memText} C${cpuText} D${diskText} ${cycle}`,
126
- `LA ${oneMinute} ${fiveMinute} ${fifteenMinute}`,
127
- ];
148
+ const loadLine = `LA ${oneMinute} ${fiveMinute} ${fifteenMinute}`;
149
+ const disks =
150
+ machineStatus !== null && machineStatus.disks ? machineStatus.disks : null;
151
+ if (disks !== null && disks.length > 0) {
152
+ const diskTokens = disks.map((disk) => `${disk.title}${disk.pct}%`);
153
+ const diskLines = packTokensWithinBudget(diskTokens);
154
+ return [`M${memText} C${cpuText} ${cycle}`, ...diskLines, loadLine];
155
+ }
156
+ return [`M${memText} C${cpuText} D${diskText} ${cycle}`, loadLine];
128
157
  };
129
158
 
130
159
  const capThreeDigits = (value: number): 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;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAqIzB,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;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAgJzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
@@ -21,6 +21,11 @@ export type ConfigFile = {
21
21
  changeTargetPathAliases?: Record<string, string>;
22
22
  consoleAccessToken?: string;
23
23
  consoleProjects?: Record<string, string>;
24
+ disks?: DiskConfig[];
25
+ };
26
+ export type DiskConfig = {
27
+ title: string;
28
+ mountpoint: string;
24
29
  };
25
30
  export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
26
31
  export declare const loadConfigFile: (configFilePath: string) => ConfigFile;
@@ -1 +1 @@
1
- {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/projectConfig.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iCAAiC,CAAC,EAAE,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C,CAAC;AAsDF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AAqBvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UA8DvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,EACd,aAAa,MAAM,KAClB,UAuEF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UA2ED,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CAoDvB,CAAC"}
1
+ {"version":3,"file":"projectConfig.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/projectConfig.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iCAAiC,CAAC,EAAE,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAsDF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CACH,CAAC;AA4CvE,eAAO,MAAM,cAAc,GAAI,gBAAgB,MAAM,KAAG,UA+DvD,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,MAAM,EACd,aAAa,MAAM,KAClB,UAuEF,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,YAAY,UAAU,EACtB,cAAc,UAAU,EACxB,iBAAiB,UAAU,KAC1B,UA4ED,CAAC;AAkBH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,OAAO,CAAC,MAAM,GAAG,IAAI,CAoDvB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboardComposeService.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/dashboardComposeService.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,qBAAqB,EAItB,MAAM,4DAA4D,CAAC;AAQpE,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AA8IF,eAAO,MAAM,0BAA0B,GACrC,SAAS,uBAAuB,KAC/B,qBAYF,CAAC;AAUF,eAAO,MAAM,4BAA4B,GACvC,SAAS,uBAAuB,KAC/B,OAYF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,uBAAuB,KAC/B,MACqE,CAAC"}
1
+ {"version":3,"file":"dashboardComposeService.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/dashboardComposeService.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,qBAAqB,EAItB,MAAM,4DAA4D,CAAC;AAQpE,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAiKF,eAAO,MAAM,0BAA0B,GACrC,SAAS,uBAAuB,KAC/B,qBAYF,CAAC;AAUF,eAAO,MAAM,4BAA4B,GACvC,SAAS,uBAAuB,KAC/B,OAYF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,uBAAuB,KAC/B,MACqE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Issue } from '../../../domain/entities/Issue';
2
2
  import { Project } from '../../../domain/entities/Project';
3
3
  export declare class HandleScheduledEventUseCaseHandler {
4
- handle: (configFilePath: string, _verbose: boolean) => Promise<{
4
+ handle: (configFilePath: string, _verbose: boolean, inTmuxProjectOrderOverride?: string[] | null) => Promise<{
5
5
  project: Project;
6
6
  issues: Issue[];
7
7
  cacheUsed: boolean;