github-issue-tower-defence-management 1.117.8 → 1.117.10
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 +14 -0
- package/README.md +4 -2
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-DID_sTas.js → index-DWiG7btO.js} +24 -24
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +14 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +7 -2
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.js +128 -0
- package/bin/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.js.map +1 -0
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +16 -4
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/bin/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +39 -26
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +28 -2
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +2 -2
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +1 -7
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +55 -26
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +1 -8
- package/src/adapter/entry-points/console/ui-dist/assets/{index-DID_sTas.js → index-DWiG7btO.js} +24 -24
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +11 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +37 -3
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +14 -0
- package/src/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.test.ts +201 -0
- package/src/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.ts +115 -0
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +117 -22
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +22 -2
- package/src/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.ts +10 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +3 -0
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
- package/types/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.d.ts +18 -0
- package/types/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.d.ts.map +1 -0
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +5 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.d.ts +11 -0
- package/types/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.d.ts.map +1 -0
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
8
8
|
DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
9
9
|
DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
10
|
+
DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
|
|
10
11
|
} from './NotifySilentLiveSessionsUseCase';
|
|
11
12
|
import { Issue } from '../entities/Issue';
|
|
12
13
|
import { LiveSessionProcessSnapshotProvider } from './adapter-interfaces/LiveSessionProcessSnapshotProvider';
|
|
@@ -15,6 +16,7 @@ import { SessionOutputActivityRepository } from './adapter-interfaces/SessionOut
|
|
|
15
16
|
import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionSubAgentActivityRepository';
|
|
16
17
|
import { OwnerCallStatusProvider } from './adapter-interfaces/OwnerCallStatusProvider';
|
|
17
18
|
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
19
|
+
import { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
|
|
18
20
|
import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
|
|
19
21
|
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
20
22
|
import { SubAgentActivity } from '../entities/LiveSessionActivitySnapshot';
|
|
@@ -26,6 +28,12 @@ type Mocked<T> = jest.Mocked<T> & jest.MockedObject<T>;
|
|
|
26
28
|
const MAIN_STALLED_SECTION = 'MAIN_STALLED_SECTION';
|
|
27
29
|
const SUBAGENT_SECTION = 'SUBAGENT_SECTION';
|
|
28
30
|
|
|
31
|
+
class EveryNameRecentSet extends Set<string> {
|
|
32
|
+
override has = (): boolean => true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const everyNameRecentSet = (): Set<string> => new EveryNameRecentSet();
|
|
36
|
+
|
|
29
37
|
describe('NotifySilentLiveSessionsUseCase', () => {
|
|
30
38
|
let useCase: NotifySilentLiveSessionsUseCase;
|
|
31
39
|
let mockSnapshotProvider: Mocked<LiveSessionProcessSnapshotProvider>;
|
|
@@ -34,6 +42,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
34
42
|
let mockSubAgentActivityRepository: Mocked<SessionSubAgentActivityRepository>;
|
|
35
43
|
let mockOwnerCallStatusProvider: Mocked<OwnerCallStatusProvider>;
|
|
36
44
|
let mockNotificationRepository: Mocked<SilentSessionNotificationRepository>;
|
|
45
|
+
let mockCandidateStateRepository: Mocked<SilentSessionCandidateStateRepository>;
|
|
37
46
|
let mockMessageComposer: Mocked<SilentSessionMessageComposer>;
|
|
38
47
|
let mockSleeper: Mocked<Sleeper>;
|
|
39
48
|
let mockHubTaskStatusResolver: Mocked<HubTaskStatusResolver>;
|
|
@@ -46,12 +55,16 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
46
55
|
'https_//github_com/HiromiShikata/repo/issues/200';
|
|
47
56
|
|
|
48
57
|
const runParams = (
|
|
49
|
-
overrides?: Partial<{
|
|
58
|
+
overrides?: Partial<{
|
|
59
|
+
activeHubTaskStatus: string | null;
|
|
60
|
+
candidateDebounceRecencyWindowSeconds: number;
|
|
61
|
+
}>,
|
|
50
62
|
): {
|
|
51
63
|
mainSilentThresholdSeconds: number;
|
|
52
64
|
subAgentSilentThresholdSeconds: number;
|
|
53
65
|
subAgentRunningThresholdSeconds: number;
|
|
54
66
|
staggerSeconds: number;
|
|
67
|
+
candidateDebounceRecencyWindowSeconds: number;
|
|
55
68
|
activeHubTaskStatus: string | null;
|
|
56
69
|
now: Date;
|
|
57
70
|
} => ({
|
|
@@ -59,6 +72,8 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
59
72
|
subAgentSilentThresholdSeconds: DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
60
73
|
subAgentRunningThresholdSeconds: DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
61
74
|
staggerSeconds: DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
75
|
+
candidateDebounceRecencyWindowSeconds:
|
|
76
|
+
DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
|
|
62
77
|
activeHubTaskStatus: null,
|
|
63
78
|
now,
|
|
64
79
|
...overrides,
|
|
@@ -132,6 +147,12 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
132
147
|
mockNotificationRepository = {
|
|
133
148
|
sendSelfCheckNotification: jest.fn().mockResolvedValue(undefined),
|
|
134
149
|
};
|
|
150
|
+
mockCandidateStateRepository = {
|
|
151
|
+
loadRecentCandidateSessionNames: jest
|
|
152
|
+
.fn()
|
|
153
|
+
.mockResolvedValue(everyNameRecentSet()),
|
|
154
|
+
saveCandidateSessionNames: jest.fn().mockResolvedValue(undefined),
|
|
155
|
+
};
|
|
135
156
|
mockMessageComposer = {
|
|
136
157
|
composeMainStalledSection: jest
|
|
137
158
|
.fn()
|
|
@@ -151,6 +172,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
151
172
|
mockSubAgentActivityRepository,
|
|
152
173
|
mockOwnerCallStatusProvider,
|
|
153
174
|
mockNotificationRepository,
|
|
175
|
+
mockCandidateStateRepository,
|
|
154
176
|
mockMessageComposer,
|
|
155
177
|
mockSleeper,
|
|
156
178
|
mockHubTaskStatusResolver,
|
|
@@ -464,7 +486,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
464
486
|
).not.toHaveBeenCalled();
|
|
465
487
|
});
|
|
466
488
|
|
|
467
|
-
it('re-notifies a
|
|
489
|
+
it('re-notifies a persistent stall on every cycle once it has been a candidate in the previous cycle', async () => {
|
|
468
490
|
setupLiveInteractiveSession(GITHUB_SESSION);
|
|
469
491
|
mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
|
|
470
492
|
[
|
|
@@ -490,29 +512,102 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
490
512
|
).toHaveBeenNthCalledWith(2, GITHUB_SESSION, MAIN_STALLED_SECTION);
|
|
491
513
|
});
|
|
492
514
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
515
|
+
describe('two-consecutive-cycle debounce', () => {
|
|
516
|
+
const setupSilentGithubSession = (): void => {
|
|
517
|
+
setupLiveInteractiveSession(GITHUB_SESSION);
|
|
518
|
+
mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
|
|
519
|
+
[
|
|
520
|
+
{
|
|
521
|
+
sessionName: GITHUB_SESSION,
|
|
522
|
+
lastOutputEpochSeconds:
|
|
523
|
+
nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
524
|
+
},
|
|
525
|
+
],
|
|
526
|
+
);
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
it('does not notify a session that is a candidate in only one cycle', async () => {
|
|
530
|
+
setupSilentGithubSession();
|
|
531
|
+
mockCandidateStateRepository.loadRecentCandidateSessionNames.mockResolvedValue(
|
|
532
|
+
new Set<string>(),
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
await useCase.run(runParams());
|
|
536
|
+
|
|
537
|
+
expect(
|
|
538
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
539
|
+
).not.toHaveBeenCalled();
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('records the current candidate set so a first-cycle candidate is remembered for the next cycle', async () => {
|
|
543
|
+
setupSilentGithubSession();
|
|
544
|
+
mockCandidateStateRepository.loadRecentCandidateSessionNames.mockResolvedValue(
|
|
545
|
+
new Set<string>(),
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
await useCase.run(runParams());
|
|
549
|
+
|
|
550
|
+
expect(
|
|
551
|
+
mockCandidateStateRepository.saveCandidateSessionNames,
|
|
552
|
+
).toHaveBeenCalledWith({ sessionNames: [GITHUB_SESSION], now });
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it('notifies a session that is a candidate in two consecutive cycles on the second cycle', async () => {
|
|
556
|
+
setupSilentGithubSession();
|
|
557
|
+
const previousCandidates = new Set<string>();
|
|
558
|
+
mockCandidateStateRepository.loadRecentCandidateSessionNames.mockImplementation(
|
|
559
|
+
async () => new Set(previousCandidates),
|
|
560
|
+
);
|
|
561
|
+
mockCandidateStateRepository.saveCandidateSessionNames.mockImplementation(
|
|
562
|
+
async ({ sessionNames }) => {
|
|
563
|
+
previousCandidates.clear();
|
|
564
|
+
for (const sessionName of sessionNames) {
|
|
565
|
+
previousCandidates.add(sessionName);
|
|
566
|
+
}
|
|
501
567
|
},
|
|
502
|
-
|
|
503
|
-
);
|
|
568
|
+
);
|
|
504
569
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
570
|
+
await useCase.run(runParams());
|
|
571
|
+
expect(
|
|
572
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
573
|
+
).not.toHaveBeenCalled();
|
|
508
574
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
575
|
+
await useCase.run(runParams());
|
|
576
|
+
expect(
|
|
577
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
578
|
+
).toHaveBeenCalledTimes(1);
|
|
579
|
+
expect(
|
|
580
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
581
|
+
).toHaveBeenCalledWith(GITHUB_SESSION, MAIN_STALLED_SECTION);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it('suppresses the owner-reply-race candidate that was not a candidate in the previous cycle', async () => {
|
|
585
|
+
setupSilentGithubSession();
|
|
586
|
+
mockCandidateStateRepository.loadRecentCandidateSessionNames.mockResolvedValue(
|
|
587
|
+
new Set<string>(),
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
await useCase.run(runParams());
|
|
591
|
+
|
|
592
|
+
expect(
|
|
593
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
594
|
+
).not.toHaveBeenCalled();
|
|
595
|
+
expect(
|
|
596
|
+
mockMessageComposer.composeMainStalledSection,
|
|
597
|
+
).toHaveBeenCalledWith(DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it('loads the previous candidate set using the configured recency window', async () => {
|
|
601
|
+
setupSilentGithubSession();
|
|
602
|
+
|
|
603
|
+
await useCase.run(
|
|
604
|
+
runParams({ candidateDebounceRecencyWindowSeconds: 900 }),
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
expect(
|
|
608
|
+
mockCandidateStateRepository.loadRecentCandidateSessionNames,
|
|
609
|
+
).toHaveBeenCalledWith({ now, recencyWindowSeconds: 900 });
|
|
610
|
+
});
|
|
516
611
|
});
|
|
517
612
|
|
|
518
613
|
it('sends to multiple sessions sequentially with a stagger delay between sends', async () => {
|
|
@@ -7,6 +7,7 @@ import { SessionOutputActivityRepository } from './adapter-interfaces/SessionOut
|
|
|
7
7
|
import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionSubAgentActivityRepository';
|
|
8
8
|
import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
|
|
9
9
|
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
10
|
+
import { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
|
|
10
11
|
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
11
12
|
import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
12
13
|
import { ResolveInteractiveLiveSessionsUseCase } from './ResolveInteractiveLiveSessionsUseCase';
|
|
@@ -15,6 +16,7 @@ export const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS = 10 * 60;
|
|
|
15
16
|
export const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS = 5 * 60;
|
|
16
17
|
export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
|
|
17
18
|
export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
19
|
+
export const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS = 15 * 60;
|
|
18
20
|
|
|
19
21
|
const GITHUB_ISSUE_OR_PULL_URL_PATTERN =
|
|
20
22
|
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)$/;
|
|
@@ -63,6 +65,7 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
63
65
|
private readonly subAgentActivityRepository: SessionSubAgentActivityRepository,
|
|
64
66
|
private readonly ownerCallStatusProvider: OwnerCallStatusProvider,
|
|
65
67
|
private readonly notificationRepository: SilentSessionNotificationRepository,
|
|
68
|
+
private readonly candidateStateRepository: SilentSessionCandidateStateRepository,
|
|
66
69
|
private readonly messageComposer: SilentSessionMessageComposer,
|
|
67
70
|
private readonly sleeper: Sleeper,
|
|
68
71
|
private readonly hubTaskStatusResolver: HubTaskStatusResolver | null = null,
|
|
@@ -73,6 +76,7 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
73
76
|
subAgentSilentThresholdSeconds: number;
|
|
74
77
|
subAgentRunningThresholdSeconds: number;
|
|
75
78
|
staggerSeconds: number;
|
|
79
|
+
candidateDebounceRecencyWindowSeconds: number;
|
|
76
80
|
activeHubTaskStatus: string | null;
|
|
77
81
|
now: Date;
|
|
78
82
|
}): Promise<void> => {
|
|
@@ -116,12 +120,28 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
116
120
|
: 0,
|
|
117
121
|
);
|
|
118
122
|
|
|
123
|
+
const previousCandidateSessionNames =
|
|
124
|
+
await this.candidateStateRepository.loadRecentCandidateSessionNames({
|
|
125
|
+
now: params.now,
|
|
126
|
+
recencyWindowSeconds: params.candidateDebounceRecencyWindowSeconds,
|
|
127
|
+
});
|
|
128
|
+
await this.candidateStateRepository.saveCandidateSessionNames({
|
|
129
|
+
sessionNames: candidates.map((candidate) => candidate.sessionName),
|
|
130
|
+
now: params.now,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const debouncedCandidates = candidates.filter((candidate) =>
|
|
134
|
+
previousCandidateSessionNames.has(candidate.sessionName),
|
|
135
|
+
);
|
|
136
|
+
const suppressedFirstCycleCount =
|
|
137
|
+
candidates.length - debouncedCandidates.length;
|
|
138
|
+
|
|
119
139
|
console.log(
|
|
120
|
-
`Silent live session notification: ${
|
|
140
|
+
`Silent live session notification: ${debouncedCandidates.length} debounced candidate(s) of ${candidates.length} current candidate(s) across ${interactiveSessions.length} interactive session(s); ${suppressedFirstCycleCount} first-cycle candidate(s) deferred until they persist into the next cycle.`,
|
|
121
141
|
);
|
|
122
142
|
|
|
123
143
|
let sentCount = 0;
|
|
124
|
-
for (const candidate of
|
|
144
|
+
for (const candidate of debouncedCandidates) {
|
|
125
145
|
if (
|
|
126
146
|
!(await this.isHubTaskActive(
|
|
127
147
|
candidate.sessionName,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SilentSessionCandidateStateRepository {
|
|
2
|
+
loadRecentCandidateSessionNames: (params: {
|
|
3
|
+
now: Date;
|
|
4
|
+
recencyWindowSeconds: number;
|
|
5
|
+
}) => Promise<Set<string>>;
|
|
6
|
+
saveCandidateSessionNames: (params: {
|
|
7
|
+
sessionNames: string[];
|
|
8
|
+
now: Date;
|
|
9
|
+
}) => Promise<void>;
|
|
10
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAiD3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAiD3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,CA8iBP;CACH"}
|
|
@@ -14,6 +14,8 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
14
14
|
subAgentSilentThresholdSeconds: number;
|
|
15
15
|
subAgentRunningThresholdSeconds: number;
|
|
16
16
|
staggerSeconds: number;
|
|
17
|
+
candidateDebounceRecencyWindowSeconds: number;
|
|
18
|
+
candidateDebounceStateFilePath: string | null;
|
|
17
19
|
activeHubTaskStatus: string | null;
|
|
18
20
|
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
19
21
|
messageTemplates: SilentSessionMessageTemplates;
|
|
@@ -25,5 +27,6 @@ export declare const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS: {
|
|
|
25
27
|
readonly subAgentSilentThresholdSeconds: number;
|
|
26
28
|
readonly subAgentRunningThresholdSeconds: number;
|
|
27
29
|
readonly staggerSeconds: 25;
|
|
30
|
+
readonly candidateDebounceRecencyWindowSeconds: number;
|
|
28
31
|
};
|
|
29
32
|
//# sourceMappingURL=notifySilentTmuxSessions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifySilentTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAGpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAEL,qBAAqB,
|
|
1
|
+
{"version":3,"file":"notifySilentTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAGpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAEL,qBAAqB,EAMtB,MAAM,0DAA0D,CAAC;AAclE,OAAO,EAEL,6BAA6B,EAC9B,MAAM,6DAA6D,CAAC;AAIrE,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,2BAA2B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,0BAA0B,EAAE,MAAM,CAAC;IACnC,8BAA8B,EAAE,MAAM,CAAC;IACvC,+BAA+B,EAAE,MAAM,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC,EAAE,MAAM,CAAC;IAC9C,8BAA8B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qBAAqB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACpD,gBAAgB,EAAE,6BAA6B,CAAC;IAChD,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAoCF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,8BAA8B,KACrC,OAAO,CAAC,IAAI,CAgEd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;CAO7C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SilentSessionCandidateStateRepository } from '../../domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository';
|
|
2
|
+
export declare const DEFAULT_STATE_RETENTION_WINDOW_SECONDS: number;
|
|
3
|
+
export declare class FileSystemSilentSessionCandidateStateRepository implements SilentSessionCandidateStateRepository {
|
|
4
|
+
private readonly stateFilePath;
|
|
5
|
+
private readonly retentionWindowSeconds;
|
|
6
|
+
constructor(stateFilePath?: string, retentionWindowSeconds?: number);
|
|
7
|
+
loadRecentCandidateSessionNames: (params: {
|
|
8
|
+
now: Date;
|
|
9
|
+
recencyWindowSeconds: number;
|
|
10
|
+
}) => Promise<Set<string>>;
|
|
11
|
+
saveCandidateSessionNames: (params: {
|
|
12
|
+
sessionNames: string[];
|
|
13
|
+
now: Date;
|
|
14
|
+
}) => Promise<void>;
|
|
15
|
+
private readEntries;
|
|
16
|
+
private writeEntries;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=FileSystemSilentSessionCandidateStateRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileSystemSilentSessionCandidateStateRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSilentSessionCandidateStateRepository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qCAAqC,EAAE,MAAM,gFAAgF,CAAC;AAUvI,eAAO,MAAM,sCAAsC,QAAU,CAAC;AAO9D,qBAAa,+CAAgD,YAAW,qCAAqC;IAEzG,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBADtB,aAAa,GAAE,MAA+B,EAC9C,sBAAsB,GAAE,MAA+C;IAG1F,+BAA+B,GAAU,QAAQ;QAC/C,GAAG,EAAE,IAAI,CAAC;QACV,oBAAoB,EAAE,MAAM,CAAC;KAC9B,KAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAYtB;IAEF,yBAAyB,GAAU,QAAQ;QACzC,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAqBf;IAEF,OAAO,CAAC,WAAW,CAoCjB;IAEF,OAAO,CAAC,YAAY,CAMlB;CACH"}
|
|
@@ -5,12 +5,14 @@ import { SessionOutputActivityRepository } from './adapter-interfaces/SessionOut
|
|
|
5
5
|
import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionSubAgentActivityRepository';
|
|
6
6
|
import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
|
|
7
7
|
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
8
|
+
import { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
|
|
8
9
|
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
9
10
|
import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
10
11
|
export declare const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS: number;
|
|
11
12
|
export declare const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS: number;
|
|
12
13
|
export declare const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS: number;
|
|
13
14
|
export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
15
|
+
export declare const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS: number;
|
|
14
16
|
export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
|
|
15
17
|
export declare const isGitHubIssueOrPullRequestSessionName: (sessionName: string) => boolean;
|
|
16
18
|
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
@@ -21,16 +23,18 @@ export declare class NotifySilentLiveSessionsUseCase {
|
|
|
21
23
|
private readonly subAgentActivityRepository;
|
|
22
24
|
private readonly ownerCallStatusProvider;
|
|
23
25
|
private readonly notificationRepository;
|
|
26
|
+
private readonly candidateStateRepository;
|
|
24
27
|
private readonly messageComposer;
|
|
25
28
|
private readonly sleeper;
|
|
26
29
|
private readonly hubTaskStatusResolver;
|
|
27
30
|
private readonly resolveInteractiveLiveSessions;
|
|
28
|
-
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null);
|
|
31
|
+
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, candidateStateRepository: SilentSessionCandidateStateRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null);
|
|
29
32
|
run: (params: {
|
|
30
33
|
mainSilentThresholdSeconds: number;
|
|
31
34
|
subAgentSilentThresholdSeconds: number;
|
|
32
35
|
subAgentRunningThresholdSeconds: number;
|
|
33
36
|
staggerSeconds: number;
|
|
37
|
+
candidateDebounceRecencyWindowSeconds: number;
|
|
34
38
|
activeHubTaskStatus: string | null;
|
|
35
39
|
now: Date;
|
|
36
40
|
}) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yDAAyD,CAAC;AAC7G,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,iCAAiC,EAAE,MAAM,wDAAwD,CAAC;AAC3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,mCAAmC,EAAE,MAAM,0DAA0D,CAAC;AAC/G,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvE,eAAO,MAAM,qCAAqC,QAAU,CAAC;AAC7D,eAAO,MAAM,yCAAyC,QAAS,CAAC;AAChE,eAAO,MAAM,0CAA0C,QAAU,CAAC;AAClE,eAAO,MAAM,oCAAoC,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yDAAyD,CAAC;AAC7G,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,iCAAiC,EAAE,MAAM,wDAAwD,CAAC;AAC3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,mCAAmC,EAAE,MAAM,0DAA0D,CAAC;AAC/G,OAAO,EAAE,qCAAqC,EAAE,MAAM,4DAA4D,CAAC;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvE,eAAO,MAAM,qCAAqC,QAAU,CAAC;AAC7D,eAAO,MAAM,yCAAyC,QAAS,CAAC;AAChE,eAAO,MAAM,0CAA0C,QAAU,CAAC;AAClE,eAAO,MAAM,oCAAoC,KAAK,CAAC;AACvD,eAAO,MAAM,iDAAiD,QAAU,CAAC;AAQzE,eAAO,MAAM,mCAAmC,GAC9C,aAAa,MAAM,KAClB,MAAM,GAAG,IAWX,CAAC;AAKF,eAAO,MAAM,qCAAqC,GAChD,aAAa,MAAM,KAClB,OACkE,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;AAO3E,qBAAa,+BAA+B;IAKxC,OAAO,CAAC,QAAQ,CAAC,kCAAkC;IACnD,OAAO,CAAC,QAAQ,CAAC,wCAAwC;IACzD,OAAO,CAAC,QAAQ,CAAC,+BAA+B;IAChD,OAAO,CAAC,QAAQ,CAAC,0BAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAbxC,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CACD;gBAG3B,kCAAkC,EAAE,kCAAkC,EACtE,wCAAwC,EAAE,wCAAwC,EAClF,+BAA+B,EAAE,+BAA+B,EAChE,0BAA0B,EAAE,iCAAiC,EAC7D,uBAAuB,EAAE,uBAAuB,EAChD,sBAAsB,EAAE,mCAAmC,EAC3D,wBAAwB,EAAE,qCAAqC,EAC/D,eAAe,EAAE,4BAA4B,EAC7C,OAAO,EAAE,OAAO,EAChB,qBAAqB,GAAE,qBAAqB,GAAG,IAAW;IAG7E,GAAG,GAAU,QAAQ;QACnB,0BAA0B,EAAE,MAAM,CAAC;QACnC,8BAA8B,EAAE,MAAM,CAAC;QACvC,+BAA+B,EAAE,MAAM,CAAC;QACxC,cAAc,EAAE,MAAM,CAAC;QACvB,qCAAqC,EAAE,MAAM,CAAC;QAC9C,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAiFf;IAEF,OAAO,CAAC,eAAe,CAmCrB;IAEF,OAAO,CAAC,gBAAgB,CA+CtB;IAEF,OAAO,CAAC,cAAc,CAqCpB;CACH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SilentSessionCandidateStateRepository {
|
|
2
|
+
loadRecentCandidateSessionNames: (params: {
|
|
3
|
+
now: Date;
|
|
4
|
+
recencyWindowSeconds: number;
|
|
5
|
+
}) => Promise<Set<string>>;
|
|
6
|
+
saveCandidateSessionNames: (params: {
|
|
7
|
+
sessionNames: string[];
|
|
8
|
+
now: Date;
|
|
9
|
+
}) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=SilentSessionCandidateStateRepository.d.ts.map
|
package/types/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SilentSessionCandidateStateRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SilentSessionCandidateStateRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qCAAqC;IACpD,+BAA+B,EAAE,CAAC,MAAM,EAAE;QACxC,GAAG,EAAE,IAAI,CAAC;QACV,oBAAoB,EAAE,MAAM,CAAC;KAC9B,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3B,yBAAyB,EAAE,CAAC,MAAM,EAAE;QAClC,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,GAAG,EAAE,IAAI,CAAC;KACX,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB"}
|