github-issue-tower-defence-management 1.114.2 → 1.115.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +3 -4
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +10 -17
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +3 -4
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js +1 -26
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js.map +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +34 -9
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +6 -21
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +110 -62
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +8 -12
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.test.ts +2 -98
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts +1 -45
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +221 -11
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +55 -18
- package/src/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.ts +0 -5
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +3 -4
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
- package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts +1 -6
- package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts.map +1 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +7 -3
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.d.ts +0 -2
- package/types/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.d.ts.map +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NotifySilentLiveSessionsUseCase,
|
|
3
|
+
HubTaskStatusResolver,
|
|
4
|
+
parseHubTaskIssueUrlFromSessionName,
|
|
3
5
|
DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
4
6
|
DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
5
7
|
DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
6
|
-
DEFAULT_NOTIFICATION_COOLDOWN_SECONDS,
|
|
7
8
|
DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
8
9
|
} from './NotifySilentLiveSessionsUseCase';
|
|
10
|
+
import { Issue } from '../entities/Issue';
|
|
9
11
|
import { LiveSessionProcessSnapshotProvider } from './adapter-interfaces/LiveSessionProcessSnapshotProvider';
|
|
10
12
|
import { InteractiveLiveSessionTranscriptResolver } from './adapter-interfaces/InteractiveLiveSessionTranscriptResolver';
|
|
11
13
|
import { SessionOutputActivityRepository } from './adapter-interfaces/SessionOutputActivityRepository';
|
|
@@ -33,23 +35,27 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
33
35
|
let mockNotificationRepository: Mocked<SilentSessionNotificationRepository>;
|
|
34
36
|
let mockMessageComposer: Mocked<SilentSessionMessageComposer>;
|
|
35
37
|
let mockSleeper: Mocked<Sleeper>;
|
|
38
|
+
let mockHubTaskStatusResolver: Mocked<HubTaskStatusResolver>;
|
|
36
39
|
const now = new Date('2026-06-26T00:00:00Z');
|
|
37
40
|
const nowEpochSeconds = Math.floor(now.getTime() / 1000);
|
|
38
41
|
|
|
39
|
-
const runParams = (
|
|
42
|
+
const runParams = (
|
|
43
|
+
overrides?: Partial<{ activeHubTaskStatus: string | null }>,
|
|
44
|
+
): {
|
|
40
45
|
mainSilentThresholdSeconds: number;
|
|
41
46
|
subAgentSilentThresholdSeconds: number;
|
|
42
47
|
subAgentRunningThresholdSeconds: number;
|
|
43
|
-
cooldownSeconds: number;
|
|
44
48
|
staggerSeconds: number;
|
|
49
|
+
activeHubTaskStatus: string | null;
|
|
45
50
|
now: Date;
|
|
46
51
|
} => ({
|
|
47
52
|
mainSilentThresholdSeconds: DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
48
53
|
subAgentSilentThresholdSeconds: DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
49
54
|
subAgentRunningThresholdSeconds: DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
50
|
-
cooldownSeconds: DEFAULT_NOTIFICATION_COOLDOWN_SECONDS,
|
|
51
55
|
staggerSeconds: DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
56
|
+
activeHubTaskStatus: null,
|
|
52
57
|
now,
|
|
58
|
+
...overrides,
|
|
53
59
|
});
|
|
54
60
|
|
|
55
61
|
const emptySnapshot: LiveSessionProcessSnapshot = {
|
|
@@ -118,8 +124,6 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
118
124
|
.mockResolvedValue(new Set<string>()),
|
|
119
125
|
};
|
|
120
126
|
mockNotificationRepository = {
|
|
121
|
-
getLastNotifiedEpochSeconds: jest.fn().mockResolvedValue(null),
|
|
122
|
-
setLastNotifiedEpochSeconds: jest.fn().mockResolvedValue(undefined),
|
|
123
127
|
sendSelfCheckNotification: jest.fn().mockResolvedValue(undefined),
|
|
124
128
|
};
|
|
125
129
|
mockMessageComposer = {
|
|
@@ -131,6 +135,9 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
131
135
|
mockSleeper = {
|
|
132
136
|
sleep: jest.fn().mockResolvedValue(undefined),
|
|
133
137
|
};
|
|
138
|
+
mockHubTaskStatusResolver = {
|
|
139
|
+
getIssueByUrl: jest.fn().mockResolvedValue(null),
|
|
140
|
+
};
|
|
134
141
|
useCase = new NotifySilentLiveSessionsUseCase(
|
|
135
142
|
mockSnapshotProvider,
|
|
136
143
|
mockTranscriptResolver,
|
|
@@ -140,9 +147,51 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
140
147
|
mockNotificationRepository,
|
|
141
148
|
mockMessageComposer,
|
|
142
149
|
mockSleeper,
|
|
150
|
+
mockHubTaskStatusResolver,
|
|
143
151
|
);
|
|
144
152
|
});
|
|
145
153
|
|
|
154
|
+
const issueFor = (overrides: Partial<Issue>): Issue => ({
|
|
155
|
+
nameWithOwner: 'HiromiShikata/repo',
|
|
156
|
+
number: 42,
|
|
157
|
+
title: 'Hub task',
|
|
158
|
+
state: 'OPEN',
|
|
159
|
+
status: 'In tmux',
|
|
160
|
+
story: null,
|
|
161
|
+
nextActionDate: null,
|
|
162
|
+
nextActionHour: null,
|
|
163
|
+
estimationMinutes: null,
|
|
164
|
+
dependedIssueUrls: [],
|
|
165
|
+
completionDate50PercentConfidence: null,
|
|
166
|
+
url: 'https://github.com/HiromiShikata/repo/issues/42',
|
|
167
|
+
assignees: [],
|
|
168
|
+
labels: [],
|
|
169
|
+
org: 'HiromiShikata',
|
|
170
|
+
repo: 'repo',
|
|
171
|
+
body: '',
|
|
172
|
+
itemId: 'item-id',
|
|
173
|
+
isPr: false,
|
|
174
|
+
isInProgress: false,
|
|
175
|
+
isClosed: false,
|
|
176
|
+
createdAt: now,
|
|
177
|
+
author: 'HiromiShikata',
|
|
178
|
+
closingIssueReferenceUrls: [],
|
|
179
|
+
...overrides,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const setupSilentMainSession = (sessionName: string): void => {
|
|
183
|
+
setupLiveInteractiveSession(sessionName);
|
|
184
|
+
mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
|
|
185
|
+
[
|
|
186
|
+
{
|
|
187
|
+
sessionName,
|
|
188
|
+
lastOutputEpochSeconds:
|
|
189
|
+
nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
146
195
|
const setupLiveInteractiveSession = (sessionName: string): void => {
|
|
147
196
|
mockSnapshotProvider.getSnapshot.mockResolvedValue(
|
|
148
197
|
snapshotWithSessions([sessionName]),
|
|
@@ -156,7 +205,6 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
156
205
|
expect(DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS).toBe(600);
|
|
157
206
|
expect(DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS).toBe(300);
|
|
158
207
|
expect(DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS).toBe(900);
|
|
159
|
-
expect(DEFAULT_NOTIFICATION_COOLDOWN_SECONDS).toBe(30 * 60);
|
|
160
208
|
expect(DEFAULT_NOTIFICATION_STAGGER_SECONDS).toBe(25);
|
|
161
209
|
});
|
|
162
210
|
|
|
@@ -325,7 +373,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
325
373
|
).not.toHaveBeenCalled();
|
|
326
374
|
});
|
|
327
375
|
|
|
328
|
-
it('
|
|
376
|
+
it('re-notifies a session on every consecutive cycle while it remains a valid silent target', async () => {
|
|
329
377
|
setupLiveInteractiveSession('workbench');
|
|
330
378
|
mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
|
|
331
379
|
[
|
|
@@ -336,15 +384,44 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
336
384
|
},
|
|
337
385
|
],
|
|
338
386
|
);
|
|
339
|
-
|
|
340
|
-
|
|
387
|
+
|
|
388
|
+
await useCase.run(runParams());
|
|
389
|
+
await useCase.run(runParams());
|
|
390
|
+
|
|
391
|
+
expect(
|
|
392
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
393
|
+
).toHaveBeenCalledTimes(2);
|
|
394
|
+
expect(
|
|
395
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
396
|
+
).toHaveBeenNthCalledWith(1, 'workbench', MAIN_STALLED_SECTION);
|
|
397
|
+
expect(
|
|
398
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
399
|
+
).toHaveBeenNthCalledWith(2, 'workbench', MAIN_STALLED_SECTION);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('notifies on every repeated cycle at the same instant without reading any cooldown state', async () => {
|
|
403
|
+
setupLiveInteractiveSession('workbench');
|
|
404
|
+
mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
|
|
405
|
+
[
|
|
406
|
+
{
|
|
407
|
+
sessionName: 'workbench',
|
|
408
|
+
lastOutputEpochSeconds:
|
|
409
|
+
nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
410
|
+
},
|
|
411
|
+
],
|
|
341
412
|
);
|
|
342
413
|
|
|
414
|
+
await useCase.run(runParams());
|
|
415
|
+
await useCase.run(runParams());
|
|
343
416
|
await useCase.run(runParams());
|
|
344
417
|
|
|
345
418
|
expect(
|
|
346
419
|
mockNotificationRepository.sendSelfCheckNotification,
|
|
347
|
-
).
|
|
420
|
+
).toHaveBeenCalledTimes(3);
|
|
421
|
+
expect(Object.keys(mockNotificationRepository)).toEqual([
|
|
422
|
+
'sendSelfCheckNotification',
|
|
423
|
+
]);
|
|
424
|
+
expect(runParams()).not.toHaveProperty('cooldownSeconds');
|
|
348
425
|
});
|
|
349
426
|
|
|
350
427
|
it('sends to multiple sessions sequentially with a stagger delay between sends', async () => {
|
|
@@ -406,6 +483,139 @@ describe('NotifySilentLiveSessionsUseCase', () => {
|
|
|
406
483
|
await expect(useCase.run(runParams())).rejects.toThrow('send-keys failed');
|
|
407
484
|
});
|
|
408
485
|
|
|
486
|
+
describe('hub-task active-status pre-send gate', () => {
|
|
487
|
+
const HUB_TASK_SESSION = 'https://github.com/HiromiShikata/repo/issues/42';
|
|
488
|
+
const ACTIVE_STATUS = 'In tmux';
|
|
489
|
+
|
|
490
|
+
it('sends when the hub task is open and in the active status', async () => {
|
|
491
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
492
|
+
mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
|
|
493
|
+
issueFor({
|
|
494
|
+
url: HUB_TASK_SESSION,
|
|
495
|
+
state: 'OPEN',
|
|
496
|
+
status: ACTIVE_STATUS,
|
|
497
|
+
}),
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
501
|
+
|
|
502
|
+
expect(mockHubTaskStatusResolver.getIssueByUrl).toHaveBeenCalledWith(
|
|
503
|
+
HUB_TASK_SESSION,
|
|
504
|
+
);
|
|
505
|
+
expect(
|
|
506
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
507
|
+
).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('skips when the hub task status differs from the active status', async () => {
|
|
511
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
512
|
+
mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
|
|
513
|
+
issueFor({ url: HUB_TASK_SESSION, state: 'OPEN', status: 'Todo' }),
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
517
|
+
|
|
518
|
+
expect(
|
|
519
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
520
|
+
).not.toHaveBeenCalled();
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it('skips when the hub task issue is closed', async () => {
|
|
524
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
525
|
+
mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
|
|
526
|
+
issueFor({
|
|
527
|
+
url: HUB_TASK_SESSION,
|
|
528
|
+
state: 'CLOSED',
|
|
529
|
+
status: ACTIVE_STATUS,
|
|
530
|
+
isClosed: true,
|
|
531
|
+
}),
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
535
|
+
|
|
536
|
+
expect(
|
|
537
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
538
|
+
).not.toHaveBeenCalled();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
it('leaves a non-URL session name unchecked and sends as before', async () => {
|
|
542
|
+
setupSilentMainSession('workbench');
|
|
543
|
+
|
|
544
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
545
|
+
|
|
546
|
+
expect(mockHubTaskStatusResolver.getIssueByUrl).not.toHaveBeenCalled();
|
|
547
|
+
expect(
|
|
548
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
549
|
+
).toHaveBeenCalledWith('workbench', MAIN_STALLED_SECTION);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('does not call the resolver at all when the active status is unconfigured', async () => {
|
|
553
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
554
|
+
|
|
555
|
+
await useCase.run(runParams({ activeHubTaskStatus: null }));
|
|
556
|
+
|
|
557
|
+
expect(mockHubTaskStatusResolver.getIssueByUrl).not.toHaveBeenCalled();
|
|
558
|
+
expect(
|
|
559
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
560
|
+
).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('fails open and logs a warning when status resolution throws', async () => {
|
|
564
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
565
|
+
const warnSpy = jest
|
|
566
|
+
.spyOn(console, 'warn')
|
|
567
|
+
.mockImplementation(() => undefined);
|
|
568
|
+
mockHubTaskStatusResolver.getIssueByUrl.mockRejectedValue(
|
|
569
|
+
new Error('GitHub API timeout'),
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
573
|
+
|
|
574
|
+
expect(
|
|
575
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
576
|
+
).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
|
|
577
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
578
|
+
expect.stringContaining('fail-open'),
|
|
579
|
+
);
|
|
580
|
+
warnSpy.mockRestore();
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
it('fails open and logs a warning when the hub task cannot be resolved', async () => {
|
|
584
|
+
setupSilentMainSession(HUB_TASK_SESSION);
|
|
585
|
+
const warnSpy = jest
|
|
586
|
+
.spyOn(console, 'warn')
|
|
587
|
+
.mockImplementation(() => undefined);
|
|
588
|
+
mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(null);
|
|
589
|
+
|
|
590
|
+
await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
|
|
591
|
+
|
|
592
|
+
expect(
|
|
593
|
+
mockNotificationRepository.sendSelfCheckNotification,
|
|
594
|
+
).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
|
|
595
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
596
|
+
expect.stringContaining('fail-open'),
|
|
597
|
+
);
|
|
598
|
+
warnSpy.mockRestore();
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('parses a github.com issue URL session name and rejects other names', () => {
|
|
602
|
+
expect(parseHubTaskIssueUrlFromSessionName(HUB_TASK_SESSION)).toBe(
|
|
603
|
+
HUB_TASK_SESSION,
|
|
604
|
+
);
|
|
605
|
+
expect(parseHubTaskIssueUrlFromSessionName('workbench')).toBeNull();
|
|
606
|
+
expect(
|
|
607
|
+
parseHubTaskIssueUrlFromSessionName(
|
|
608
|
+
'https://github.com/HiromiShikata/repo/pull/42',
|
|
609
|
+
),
|
|
610
|
+
).toBeNull();
|
|
611
|
+
expect(
|
|
612
|
+
parseHubTaskIssueUrlFromSessionName(
|
|
613
|
+
'https://example.com/HiromiShikata/repo/issues/42',
|
|
614
|
+
),
|
|
615
|
+
).toBeNull();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
|
|
409
619
|
it('uses the session entity helper for type completeness', () => {
|
|
410
620
|
expect(sessionFor('workbench')).toEqual({
|
|
411
621
|
sessionName: 'workbench',
|
|
@@ -8,14 +8,25 @@ import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionS
|
|
|
8
8
|
import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
|
|
9
9
|
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
10
10
|
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
11
|
+
import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
11
12
|
import { ResolveInteractiveLiveSessionsUseCase } from './ResolveInteractiveLiveSessionsUseCase';
|
|
12
13
|
|
|
13
14
|
export const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS = 10 * 60;
|
|
14
15
|
export const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS = 5 * 60;
|
|
15
16
|
export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
|
|
16
|
-
export const DEFAULT_NOTIFICATION_COOLDOWN_SECONDS = 30 * 60;
|
|
17
17
|
export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
18
18
|
|
|
19
|
+
const GITHUB_ISSUE_URL_PATTERN =
|
|
20
|
+
/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/\d+$/;
|
|
21
|
+
|
|
22
|
+
export const parseHubTaskIssueUrlFromSessionName = (
|
|
23
|
+
sessionName: string,
|
|
24
|
+
): string | null => {
|
|
25
|
+
return GITHUB_ISSUE_URL_PATTERN.test(sessionName) ? sessionName : null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
29
|
+
|
|
19
30
|
type NotifyCandidate = {
|
|
20
31
|
sessionName: string;
|
|
21
32
|
message: string;
|
|
@@ -34,14 +45,15 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
34
45
|
private readonly notificationRepository: SilentSessionNotificationRepository,
|
|
35
46
|
private readonly messageComposer: SilentSessionMessageComposer,
|
|
36
47
|
private readonly sleeper: Sleeper,
|
|
48
|
+
private readonly hubTaskStatusResolver: HubTaskStatusResolver | null = null,
|
|
37
49
|
) {}
|
|
38
50
|
|
|
39
51
|
run = async (params: {
|
|
40
52
|
mainSilentThresholdSeconds: number;
|
|
41
53
|
subAgentSilentThresholdSeconds: number;
|
|
42
54
|
subAgentRunningThresholdSeconds: number;
|
|
43
|
-
cooldownSeconds: number;
|
|
44
55
|
staggerSeconds: number;
|
|
56
|
+
activeHubTaskStatus: string | null;
|
|
45
57
|
now: Date;
|
|
46
58
|
}): Promise<void> => {
|
|
47
59
|
const snapshot =
|
|
@@ -78,22 +90,14 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
78
90
|
`Silent live session notification: ${candidates.length} candidate(s) of ${interactiveSessions.length} interactive session(s).`,
|
|
79
91
|
);
|
|
80
92
|
|
|
81
|
-
const nowEpochSeconds = Math.floor(params.now.getTime() / 1000);
|
|
82
93
|
let sentCount = 0;
|
|
83
94
|
for (const candidate of candidates) {
|
|
84
|
-
const lastNotifiedEpochSeconds =
|
|
85
|
-
await this.notificationRepository.getLastNotifiedEpochSeconds(
|
|
86
|
-
candidate.sessionName,
|
|
87
|
-
);
|
|
88
95
|
if (
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
!(await this.isHubTaskActive(
|
|
97
|
+
candidate.sessionName,
|
|
98
|
+
params.activeHubTaskStatus,
|
|
99
|
+
))
|
|
91
100
|
) {
|
|
92
|
-
console.log(
|
|
93
|
-
`Skipping ${candidate.sessionName}: notified ${
|
|
94
|
-
nowEpochSeconds - lastNotifiedEpochSeconds
|
|
95
|
-
} seconds ago, within cooldown ${params.cooldownSeconds} seconds.`,
|
|
96
|
-
);
|
|
97
101
|
continue;
|
|
98
102
|
}
|
|
99
103
|
if (sentCount > 0) {
|
|
@@ -103,15 +107,48 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
103
107
|
candidate.sessionName,
|
|
104
108
|
candidate.message,
|
|
105
109
|
);
|
|
106
|
-
await this.notificationRepository.setLastNotifiedEpochSeconds(
|
|
107
|
-
candidate.sessionName,
|
|
108
|
-
nowEpochSeconds,
|
|
109
|
-
);
|
|
110
110
|
sentCount += 1;
|
|
111
111
|
console.log(`Notified ${candidate.sessionName}.`);
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
+
private isHubTaskActive = async (
|
|
116
|
+
sessionName: string,
|
|
117
|
+
activeHubTaskStatus: string | null,
|
|
118
|
+
): Promise<boolean> => {
|
|
119
|
+
if (activeHubTaskStatus === null || this.hubTaskStatusResolver === null) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const hubTaskIssueUrl = parseHubTaskIssueUrlFromSessionName(sessionName);
|
|
123
|
+
if (hubTaskIssueUrl === null) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const issue =
|
|
128
|
+
await this.hubTaskStatusResolver.getIssueByUrl(hubTaskIssueUrl);
|
|
129
|
+
if (issue === null) {
|
|
130
|
+
console.warn(
|
|
131
|
+
`Hub task ${hubTaskIssueUrl} for session ${sessionName} could not be resolved; sending notification (fail-open).`,
|
|
132
|
+
);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
if (issue.state !== 'OPEN' || issue.status !== activeHubTaskStatus) {
|
|
136
|
+
console.log(
|
|
137
|
+
`Skipping ${sessionName}: hub task ${hubTaskIssueUrl} is no longer active (state "${issue.state}", status "${issue.status ?? 'null'}", active status "${activeHubTaskStatus}").`,
|
|
138
|
+
);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn(
|
|
144
|
+
`Failed to resolve hub task status for session ${sessionName} (${hubTaskIssueUrl}); sending notification (fail-open): ${
|
|
145
|
+
error instanceof Error ? error.message : String(error)
|
|
146
|
+
}`,
|
|
147
|
+
);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
115
152
|
private collectSnapshots = async (
|
|
116
153
|
interactiveSessions: InteractiveLiveSession[],
|
|
117
154
|
transcriptPathBySessionName: Map<string, string>,
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
export interface SilentSessionNotificationRepository {
|
|
2
|
-
getLastNotifiedEpochSeconds: (sessionName: string) => Promise<number | null>;
|
|
3
|
-
setLastNotifiedEpochSeconds: (
|
|
4
|
-
sessionName: string,
|
|
5
|
-
epochSeconds: number,
|
|
6
|
-
) => Promise<void>;
|
|
7
2
|
sendSelfCheckNotification: (
|
|
8
3
|
sessionName: string,
|
|
9
4
|
message: string,
|
|
@@ -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;
|
|
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,CAmiBP;CACH"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
2
2
|
import { ProcessEnvironReader } from '../../../domain/usecases/adapter-interfaces/ProcessEnvironReader';
|
|
3
|
-
import {
|
|
3
|
+
import { HubTaskStatusResolver } from '../../../domain/usecases/NotifySilentLiveSessionsUseCase';
|
|
4
4
|
import { SilentSessionMessageTemplates } from '../../repositories/ConfigurableSilentSessionMessageComposer';
|
|
5
5
|
export type NotifySilentTmuxSessionsParams = {
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
localCommandRunner: LocalCommandRunner;
|
|
8
8
|
processEnvironReader?: ProcessEnvironReader;
|
|
9
|
-
cacheRepository: Pick<LocalStorageCacheRepository, 'getLatest' | 'set'>;
|
|
10
9
|
ownerCallMarker: string | null;
|
|
11
10
|
subAgentOutputRootDirectory: string | null;
|
|
12
11
|
subAgentProcessMatchPattern: string | null;
|
|
@@ -14,8 +13,9 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
14
13
|
mainSilentThresholdSeconds: number;
|
|
15
14
|
subAgentSilentThresholdSeconds: number;
|
|
16
15
|
subAgentRunningThresholdSeconds: number;
|
|
17
|
-
cooldownSeconds: number;
|
|
18
16
|
staggerSeconds: number;
|
|
17
|
+
activeHubTaskStatus: string | null;
|
|
18
|
+
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
19
19
|
messageTemplates: SilentSessionMessageTemplates;
|
|
20
20
|
now: Date;
|
|
21
21
|
};
|
|
@@ -24,7 +24,6 @@ export declare const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS: {
|
|
|
24
24
|
readonly mainSilentThresholdSeconds: number;
|
|
25
25
|
readonly subAgentSilentThresholdSeconds: number;
|
|
26
26
|
readonly subAgentRunningThresholdSeconds: number;
|
|
27
|
-
readonly cooldownSeconds: number;
|
|
28
27
|
readonly staggerSeconds: 25;
|
|
29
28
|
};
|
|
30
29
|
//# 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;
|
|
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,EAKtB,MAAM,0DAA0D,CAAC;AAclE,OAAO,EAEL,6BAA6B,EAC9B,MAAM,6DAA6D,CAAC;AAGrE,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,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,CAwDd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;CAK7C,CAAC"}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { SilentSessionNotificationRepository } from '../../domain/usecases/adapter-interfaces/SilentSessionNotificationRepository';
|
|
2
2
|
import { LocalCommandRunner } from '../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
3
|
-
import { LocalStorageCacheRepository } from './LocalStorageCacheRepository';
|
|
4
3
|
export declare class TmuxSilentSessionNotificationRepository implements SilentSessionNotificationRepository {
|
|
5
4
|
private readonly localCommandRunner;
|
|
6
|
-
|
|
7
|
-
constructor(localCommandRunner: LocalCommandRunner, cacheRepository: Pick<LocalStorageCacheRepository, 'getLatest' | 'set'>);
|
|
8
|
-
getLastNotifiedEpochSeconds: (sessionName: string) => Promise<number | null>;
|
|
9
|
-
setLastNotifiedEpochSeconds: (sessionName: string, epochSeconds: number) => Promise<void>;
|
|
5
|
+
constructor(localCommandRunner: LocalCommandRunner);
|
|
10
6
|
sendSelfCheckNotification: (sessionName: string, message: string) => Promise<void>;
|
|
11
|
-
private toCacheKey;
|
|
12
7
|
}
|
|
13
8
|
//# sourceMappingURL=TmuxSilentSessionNotificationRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TmuxSilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;AACnI,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"TmuxSilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;AACnI,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AAEjG,qBAAa,uCAAwC,YAAW,mCAAmC;IACrF,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,kBAAkB;IAEnE,yBAAyB,GACvB,aAAa,MAAM,EACnB,SAAS,MAAM,KACd,OAAO,CAAC,IAAI,CAAC,CA4Bd;CACH"}
|
|
@@ -6,11 +6,13 @@ import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionS
|
|
|
6
6
|
import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
|
|
7
7
|
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
8
8
|
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
9
|
+
import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
9
10
|
export declare const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS: number;
|
|
10
11
|
export declare const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS: number;
|
|
11
12
|
export declare const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS: number;
|
|
12
|
-
export declare const DEFAULT_NOTIFICATION_COOLDOWN_SECONDS: number;
|
|
13
13
|
export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
14
|
+
export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
|
|
15
|
+
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
14
16
|
export declare class NotifySilentLiveSessionsUseCase {
|
|
15
17
|
private readonly liveSessionProcessSnapshotProvider;
|
|
16
18
|
private readonly interactiveLiveSessionTranscriptResolver;
|
|
@@ -20,16 +22,18 @@ export declare class NotifySilentLiveSessionsUseCase {
|
|
|
20
22
|
private readonly notificationRepository;
|
|
21
23
|
private readonly messageComposer;
|
|
22
24
|
private readonly sleeper;
|
|
25
|
+
private readonly hubTaskStatusResolver;
|
|
23
26
|
private readonly resolveInteractiveLiveSessions;
|
|
24
|
-
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper);
|
|
27
|
+
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null);
|
|
25
28
|
run: (params: {
|
|
26
29
|
mainSilentThresholdSeconds: number;
|
|
27
30
|
subAgentSilentThresholdSeconds: number;
|
|
28
31
|
subAgentRunningThresholdSeconds: number;
|
|
29
|
-
cooldownSeconds: number;
|
|
30
32
|
staggerSeconds: number;
|
|
33
|
+
activeHubTaskStatus: string | null;
|
|
31
34
|
now: Date;
|
|
32
35
|
}) => Promise<void>;
|
|
36
|
+
private isHubTaskActive;
|
|
33
37
|
private collectSnapshots;
|
|
34
38
|
private composeMessage;
|
|
35
39
|
}
|
|
@@ -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;
|
|
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;AAKvD,eAAO,MAAM,mCAAmC,GAC9C,aAAa,MAAM,KAClB,MAAM,GAAG,IAEX,CAAC;AAEF,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,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAZxC,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,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,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAuDf;IAEF,OAAO,CAAC,eAAe,CAmCrB;IAEF,OAAO,CAAC,gBAAgB,CA8CtB;IAEF,OAAO,CAAC,cAAc,CAqCpB;CACH"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export interface SilentSessionNotificationRepository {
|
|
2
|
-
getLastNotifiedEpochSeconds: (sessionName: string) => Promise<number | null>;
|
|
3
|
-
setLastNotifiedEpochSeconds: (sessionName: string, epochSeconds: number) => Promise<void>;
|
|
4
2
|
sendSelfCheckNotification: (sessionName: string, message: string) => Promise<void>;
|
|
5
3
|
}
|
|
6
4
|
//# sourceMappingURL=SilentSessionNotificationRepository.d.ts.map
|
package/types/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mCAAmC;IAClD,
|
|
1
|
+
{"version":3,"file":"SilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mCAAmC;IAClD,yBAAyB,EAAE,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB"}
|