github-issue-tower-defence-management 1.118.0 → 1.119.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 (52) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +5 -3
  3. package/bin/adapter/entry-points/console/ui-dist/assets/{index-BMe1bEF4.css → index-D0RwhyOM.css} +1 -1
  4. package/bin/adapter/entry-points/console/ui-dist/assets/index-syKbd_lW.js +103 -0
  5. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  6. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +14 -2
  7. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  8. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +7 -2
  9. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
  10. package/bin/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.js +128 -0
  11. package/bin/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.js.map +1 -0
  12. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +61 -16
  13. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
  14. package/bin/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.js +3 -0
  15. package/bin/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.js.map +1 -0
  16. package/package.json +1 -1
  17. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +1 -1
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.tsx +8 -2
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleChangedFileList.test.tsx +21 -8
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleChangedFileList.tsx +63 -6
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentList.tsx +4 -0
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +4 -0
  23. package/src/adapter/entry-points/console/ui/src/features/console/lib/markdown.test.ts +37 -0
  24. package/src/adapter/entry-points/console/ui/src/features/console/lib/markdown.ts +69 -5
  25. package/src/adapter/entry-points/console/ui/src/features/console/logic/fileTree.test.ts +95 -0
  26. package/src/adapter/entry-points/console/ui/src/features/console/logic/fileTree.ts +93 -0
  27. package/src/adapter/entry-points/console/ui/src/features/console/logic/references.test.ts +23 -0
  28. package/src/adapter/entry-points/console/ui/src/features/console/logic/references.ts +20 -0
  29. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +6 -2
  30. package/src/adapter/entry-points/console/ui/src/index.css +25 -0
  31. package/src/adapter/entry-points/console/ui-dist/assets/{index-BMe1bEF4.css → index-D0RwhyOM.css} +1 -1
  32. package/src/adapter/entry-points/console/ui-dist/assets/index-syKbd_lW.js +103 -0
  33. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  34. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +11 -0
  35. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +6 -0
  36. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +13 -0
  37. package/src/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.test.ts +251 -0
  38. package/src/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.ts +121 -0
  39. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +218 -9
  40. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +105 -19
  41. package/src/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.ts +20 -0
  42. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  43. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +3 -0
  44. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
  45. package/types/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts +20 -0
  46. package/types/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts.map +1 -0
  47. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +7 -1
  48. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
  49. package/types/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.d.ts +19 -0
  50. package/types/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.d.ts.map +1 -0
  51. package/bin/adapter/entry-points/console/ui-dist/assets/index-DWiG7btO.js +0 -103
  52. package/src/adapter/entry-points/console/ui-dist/assets/index-DWiG7btO.js +0 -103
@@ -8,6 +8,7 @@ import {
8
8
  DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
9
9
  DEFAULT_NOTIFICATION_STAGGER_SECONDS,
10
10
  DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
11
+ DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS,
11
12
  } from './NotifySilentLiveSessionsUseCase';
12
13
  import { Issue } from '../entities/Issue';
13
14
  import { LiveSessionProcessSnapshotProvider } from './adapter-interfaces/LiveSessionProcessSnapshotProvider';
@@ -17,6 +18,7 @@ import { SessionSubAgentActivityRepository } from './adapter-interfaces/SessionS
17
18
  import { OwnerCallStatusProvider } from './adapter-interfaces/OwnerCallStatusProvider';
18
19
  import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
19
20
  import { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
21
+ import { SilentSessionHubTaskStatusCacheRepository } from './adapter-interfaces/SilentSessionHubTaskStatusCacheRepository';
20
22
  import { SilentSessionMessageComposer } from './adapter-interfaces/SilentSessionMessageComposer';
21
23
  import { Sleeper } from './adapter-interfaces/Sleeper';
22
24
  import { SubAgentActivity } from '../entities/LiveSessionActivitySnapshot';
@@ -46,6 +48,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
46
48
  let mockMessageComposer: Mocked<SilentSessionMessageComposer>;
47
49
  let mockSleeper: Mocked<Sleeper>;
48
50
  let mockHubTaskStatusResolver: Mocked<HubTaskStatusResolver>;
51
+ let mockHubTaskStatusCacheRepository: Mocked<SilentSessionHubTaskStatusCacheRepository>;
49
52
  const now = new Date('2026-06-26T00:00:00Z');
50
53
  const nowEpochSeconds = Math.floor(now.getTime() / 1000);
51
54
  const GITHUB_SESSION = 'https_//github_com/HiromiShikata/repo/issues/42';
@@ -58,6 +61,8 @@ describe('NotifySilentLiveSessionsUseCase', () => {
58
61
  overrides?: Partial<{
59
62
  activeHubTaskStatus: string | null;
60
63
  candidateDebounceRecencyWindowSeconds: number;
64
+ hubTaskStatusCacheTtlSeconds: number;
65
+ now: Date;
61
66
  }>,
62
67
  ): {
63
68
  mainSilentThresholdSeconds: number;
@@ -66,6 +71,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
66
71
  staggerSeconds: number;
67
72
  candidateDebounceRecencyWindowSeconds: number;
68
73
  activeHubTaskStatus: string | null;
74
+ hubTaskStatusCacheTtlSeconds: number;
69
75
  now: Date;
70
76
  } => ({
71
77
  mainSilentThresholdSeconds: DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
@@ -75,6 +81,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
75
81
  candidateDebounceRecencyWindowSeconds:
76
82
  DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
77
83
  activeHubTaskStatus: null,
84
+ hubTaskStatusCacheTtlSeconds: DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS,
78
85
  now,
79
86
  ...overrides,
80
87
  });
@@ -165,6 +172,10 @@ describe('NotifySilentLiveSessionsUseCase', () => {
165
172
  mockHubTaskStatusResolver = {
166
173
  getIssueByUrl: jest.fn().mockResolvedValue(null),
167
174
  };
175
+ mockHubTaskStatusCacheRepository = {
176
+ loadHubTaskStatus: jest.fn().mockResolvedValue(null),
177
+ saveHubTaskStatus: jest.fn().mockResolvedValue(undefined),
178
+ };
168
179
  useCase = new NotifySilentLiveSessionsUseCase(
169
180
  mockSnapshotProvider,
170
181
  mockTranscriptResolver,
@@ -176,6 +187,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
176
187
  mockMessageComposer,
177
188
  mockSleeper,
178
189
  mockHubTaskStatusResolver,
190
+ mockHubTaskStatusCacheRepository,
179
191
  );
180
192
  });
181
193
 
@@ -804,14 +816,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
804
816
  warnSpy.mockRestore();
805
817
  });
806
818
 
807
- it('fails open without a warning when the hub task is not a resolvable tracked task', async () => {
819
+ it('fails open with a distinct no-cache warning when the hub task is not a resolvable tracked task and no cached status exists', async () => {
808
820
  setupSilentMainSession(HUB_TASK_SESSION);
809
821
  const warnSpy = jest
810
822
  .spyOn(console, 'warn')
811
823
  .mockImplementation(() => undefined);
812
- const logSpy = jest
813
- .spyOn(console, 'log')
814
- .mockImplementation(() => undefined);
815
824
  mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(null);
816
825
 
817
826
  await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
@@ -819,9 +828,12 @@ describe('NotifySilentLiveSessionsUseCase', () => {
819
828
  expect(
820
829
  mockNotificationRepository.sendSelfCheckNotification,
821
830
  ).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
822
- expect(warnSpy).not.toHaveBeenCalled();
823
- expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('fail-open'));
824
- logSpy.mockRestore();
831
+ expect(warnSpy).toHaveBeenCalledWith(
832
+ expect.stringContaining('no cached status'),
833
+ );
834
+ expect(warnSpy).toHaveBeenCalledWith(
835
+ expect.stringContaining('fail-open'),
836
+ );
825
837
  warnSpy.mockRestore();
826
838
  });
827
839
 
@@ -873,7 +885,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
873
885
  ).not.toHaveBeenCalled();
874
886
  });
875
887
 
876
- it('fails open without throwing or warning for a real tmux session-name form whose repository is unresolvable', async () => {
888
+ it('fails open without throwing for a real tmux session-name form whose repository is unresolvable and has no cached status', async () => {
877
889
  const REAL_TMUX_SESSION =
878
890
  'https_//github_com/example-org/example-repo/issues/2350';
879
891
  const CANONICAL_ISSUE_URL =
@@ -894,7 +906,204 @@ describe('NotifySilentLiveSessionsUseCase', () => {
894
906
  expect(
895
907
  mockNotificationRepository.sendSelfCheckNotification,
896
908
  ).toHaveBeenCalledWith(REAL_TMUX_SESSION, MAIN_STALLED_SECTION);
897
- expect(warnSpy).not.toHaveBeenCalled();
909
+ expect(warnSpy).toHaveBeenCalledWith(
910
+ expect.stringContaining('no cached status'),
911
+ );
912
+ warnSpy.mockRestore();
913
+ });
914
+
915
+ it('suppresses a resolved CLOSED hub task and writes the resolved status to the cache', async () => {
916
+ setupSilentMainSession(HUB_TASK_SESSION);
917
+ mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
918
+ issueFor({
919
+ url: HUB_TASK_SESSION,
920
+ state: 'CLOSED',
921
+ status: ACTIVE_STATUS,
922
+ isClosed: true,
923
+ }),
924
+ );
925
+
926
+ await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
927
+
928
+ expect(
929
+ mockNotificationRepository.sendSelfCheckNotification,
930
+ ).not.toHaveBeenCalled();
931
+ expect(
932
+ mockHubTaskStatusCacheRepository.saveHubTaskStatus,
933
+ ).toHaveBeenCalledWith({
934
+ url: HUB_TASK_SESSION,
935
+ state: 'CLOSED',
936
+ status: ACTIVE_STATUS,
937
+ now,
938
+ });
939
+ });
940
+
941
+ it('suppresses a resolved Done (non-active project status) hub task', async () => {
942
+ setupSilentMainSession(HUB_TASK_SESSION);
943
+ mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
944
+ issueFor({ url: HUB_TASK_SESSION, state: 'OPEN', status: 'Done' }),
945
+ );
946
+
947
+ await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
948
+
949
+ expect(
950
+ mockNotificationRepository.sendSelfCheckNotification,
951
+ ).not.toHaveBeenCalled();
952
+ });
953
+
954
+ it('sends a resolved active hub task and writes its status to the cache', async () => {
955
+ setupSilentMainSession(HUB_TASK_SESSION);
956
+ mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
957
+ issueFor({
958
+ url: HUB_TASK_SESSION,
959
+ state: 'OPEN',
960
+ status: ACTIVE_STATUS,
961
+ }),
962
+ );
963
+
964
+ await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
965
+
966
+ expect(
967
+ mockNotificationRepository.sendSelfCheckNotification,
968
+ ).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
969
+ expect(
970
+ mockHubTaskStatusCacheRepository.saveHubTaskStatus,
971
+ ).toHaveBeenCalledWith({
972
+ url: HUB_TASK_SESSION,
973
+ state: 'OPEN',
974
+ status: ACTIVE_STATUS,
975
+ now,
976
+ });
977
+ });
978
+
979
+ it('decides from a fresh cached entry without consulting the resolver', async () => {
980
+ setupSilentMainSession(HUB_TASK_SESSION);
981
+ mockHubTaskStatusCacheRepository.loadHubTaskStatus.mockResolvedValue({
982
+ url: HUB_TASK_SESSION,
983
+ state: 'OPEN',
984
+ status: ACTIVE_STATUS,
985
+ recordedEpochSeconds: nowEpochSeconds - 60,
986
+ });
987
+
988
+ await useCase.run(
989
+ runParams({
990
+ activeHubTaskStatus: ACTIVE_STATUS,
991
+ hubTaskStatusCacheTtlSeconds: 300,
992
+ }),
993
+ );
994
+
995
+ expect(mockHubTaskStatusResolver.getIssueByUrl).not.toHaveBeenCalled();
996
+ expect(
997
+ mockHubTaskStatusCacheRepository.saveHubTaskStatus,
998
+ ).not.toHaveBeenCalled();
999
+ expect(
1000
+ mockNotificationRepository.sendSelfCheckNotification,
1001
+ ).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
1002
+ });
1003
+
1004
+ it('suppresses from a fresh cached closed entry without consulting the resolver', async () => {
1005
+ setupSilentMainSession(HUB_TASK_SESSION);
1006
+ mockHubTaskStatusCacheRepository.loadHubTaskStatus.mockResolvedValue({
1007
+ url: HUB_TASK_SESSION,
1008
+ state: 'CLOSED',
1009
+ status: ACTIVE_STATUS,
1010
+ recordedEpochSeconds: nowEpochSeconds - 60,
1011
+ });
1012
+
1013
+ await useCase.run(
1014
+ runParams({
1015
+ activeHubTaskStatus: ACTIVE_STATUS,
1016
+ hubTaskStatusCacheTtlSeconds: 300,
1017
+ }),
1018
+ );
1019
+
1020
+ expect(mockHubTaskStatusResolver.getIssueByUrl).not.toHaveBeenCalled();
1021
+ expect(
1022
+ mockNotificationRepository.sendSelfCheckNotification,
1023
+ ).not.toHaveBeenCalled();
1024
+ });
1025
+
1026
+ it('re-resolves when the cached entry is older than the configured time-to-live', async () => {
1027
+ setupSilentMainSession(HUB_TASK_SESSION);
1028
+ mockHubTaskStatusCacheRepository.loadHubTaskStatus.mockResolvedValue({
1029
+ url: HUB_TASK_SESSION,
1030
+ state: 'OPEN',
1031
+ status: ACTIVE_STATUS,
1032
+ recordedEpochSeconds: nowEpochSeconds - 600,
1033
+ });
1034
+ mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(
1035
+ issueFor({
1036
+ url: HUB_TASK_SESSION,
1037
+ state: 'OPEN',
1038
+ status: ACTIVE_STATUS,
1039
+ }),
1040
+ );
1041
+
1042
+ await useCase.run(
1043
+ runParams({
1044
+ activeHubTaskStatus: ACTIVE_STATUS,
1045
+ hubTaskStatusCacheTtlSeconds: 300,
1046
+ }),
1047
+ );
1048
+
1049
+ expect(mockHubTaskStatusResolver.getIssueByUrl).toHaveBeenCalledWith(
1050
+ HUB_TASK_SESSION,
1051
+ );
1052
+ expect(
1053
+ mockNotificationRepository.sendSelfCheckNotification,
1054
+ ).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
1055
+ });
1056
+
1057
+ it('falls back to an expired cached active entry and still sends when live resolution returns null', async () => {
1058
+ setupSilentMainSession(HUB_TASK_SESSION);
1059
+ mockHubTaskStatusCacheRepository.loadHubTaskStatus.mockResolvedValue({
1060
+ url: HUB_TASK_SESSION,
1061
+ state: 'OPEN',
1062
+ status: ACTIVE_STATUS,
1063
+ recordedEpochSeconds: nowEpochSeconds - 600,
1064
+ });
1065
+ mockHubTaskStatusResolver.getIssueByUrl.mockResolvedValue(null);
1066
+
1067
+ await useCase.run(
1068
+ runParams({
1069
+ activeHubTaskStatus: ACTIVE_STATUS,
1070
+ hubTaskStatusCacheTtlSeconds: 300,
1071
+ }),
1072
+ );
1073
+
1074
+ expect(
1075
+ mockNotificationRepository.sendSelfCheckNotification,
1076
+ ).toHaveBeenCalledWith(HUB_TASK_SESSION, MAIN_STALLED_SECTION);
1077
+ });
1078
+
1079
+ it('falls back to an expired cached closed entry and suppresses when live resolution throws', async () => {
1080
+ setupSilentMainSession(HUB_TASK_SESSION);
1081
+ const warnSpy = jest
1082
+ .spyOn(console, 'warn')
1083
+ .mockImplementation(() => undefined);
1084
+ mockHubTaskStatusCacheRepository.loadHubTaskStatus.mockResolvedValue({
1085
+ url: HUB_TASK_SESSION,
1086
+ state: 'CLOSED',
1087
+ status: ACTIVE_STATUS,
1088
+ recordedEpochSeconds: nowEpochSeconds - 600,
1089
+ });
1090
+ mockHubTaskStatusResolver.getIssueByUrl.mockRejectedValue(
1091
+ new Error('GraphQL rate limit'),
1092
+ );
1093
+
1094
+ await useCase.run(
1095
+ runParams({
1096
+ activeHubTaskStatus: ACTIVE_STATUS,
1097
+ hubTaskStatusCacheTtlSeconds: 300,
1098
+ }),
1099
+ );
1100
+
1101
+ expect(
1102
+ mockNotificationRepository.sendSelfCheckNotification,
1103
+ ).not.toHaveBeenCalled();
1104
+ expect(warnSpy).toHaveBeenCalledWith(
1105
+ expect.stringContaining('expired cached status'),
1106
+ );
898
1107
  warnSpy.mockRestore();
899
1108
  });
900
1109
 
@@ -8,6 +8,7 @@ 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 { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
11
+ import { SilentSessionHubTaskStatusCacheRepository } from './adapter-interfaces/SilentSessionHubTaskStatusCacheRepository';
11
12
  import { Sleeper } from './adapter-interfaces/Sleeper';
12
13
  import { IssueRepository } from './adapter-interfaces/IssueRepository';
13
14
  import { ResolveInteractiveLiveSessionsUseCase } from './ResolveInteractiveLiveSessionsUseCase';
@@ -17,6 +18,7 @@ export const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS = 5 * 60;
17
18
  export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
18
19
  export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
19
20
  export const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS = 15 * 60;
21
+ export const DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS = 5 * 60;
20
22
 
21
23
  const GITHUB_ISSUE_OR_PULL_URL_PATTERN =
22
24
  /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)$/;
@@ -69,6 +71,7 @@ export class NotifySilentLiveSessionsUseCase {
69
71
  private readonly messageComposer: SilentSessionMessageComposer,
70
72
  private readonly sleeper: Sleeper,
71
73
  private readonly hubTaskStatusResolver: HubTaskStatusResolver | null = null,
74
+ private readonly hubTaskStatusCacheRepository: SilentSessionHubTaskStatusCacheRepository | null = null,
72
75
  ) {}
73
76
 
74
77
  run = async (params: {
@@ -78,6 +81,7 @@ export class NotifySilentLiveSessionsUseCase {
78
81
  staggerSeconds: number;
79
82
  candidateDebounceRecencyWindowSeconds: number;
80
83
  activeHubTaskStatus: string | null;
84
+ hubTaskStatusCacheTtlSeconds: number;
81
85
  now: Date;
82
86
  }): Promise<void> => {
83
87
  const snapshot =
@@ -146,6 +150,8 @@ export class NotifySilentLiveSessionsUseCase {
146
150
  !(await this.isHubTaskActive(
147
151
  candidate.sessionName,
148
152
  params.activeHubTaskStatus,
153
+ params.hubTaskStatusCacheTtlSeconds,
154
+ params.now,
149
155
  ))
150
156
  ) {
151
157
  continue;
@@ -165,6 +171,8 @@ export class NotifySilentLiveSessionsUseCase {
165
171
  private isHubTaskActive = async (
166
172
  sessionName: string,
167
173
  activeHubTaskStatus: string | null,
174
+ hubTaskStatusCacheTtlSeconds: number,
175
+ now: Date,
168
176
  ): Promise<boolean> => {
169
177
  if (activeHubTaskStatus === null || this.hubTaskStatusResolver === null) {
170
178
  return true;
@@ -173,32 +181,110 @@ export class NotifySilentLiveSessionsUseCase {
173
181
  if (hubTaskIssueUrl === null) {
174
182
  return true;
175
183
  }
176
- try {
177
- const issue =
178
- await this.hubTaskStatusResolver.getIssueByUrl(hubTaskIssueUrl);
179
- if (issue === null) {
180
- console.log(
181
- `Hub task ${hubTaskIssueUrl} for session ${sessionName} is not a resolvable tracked task; sending notification (fail-open).`,
182
- );
183
- return true;
184
- }
185
- if (issue.state !== 'OPEN' || issue.status !== activeHubTaskStatus) {
186
- console.log(
187
- `Skipping ${sessionName}: hub task ${hubTaskIssueUrl} is no longer active (state "${issue.state}", status "${issue.status ?? 'null'}", active status "${activeHubTaskStatus}").`,
184
+
185
+ const cachedEntry =
186
+ this.hubTaskStatusCacheRepository === null
187
+ ? null
188
+ : await this.hubTaskStatusCacheRepository.loadHubTaskStatus({
189
+ url: hubTaskIssueUrl,
190
+ });
191
+ const nowEpochSeconds = Math.floor(now.getTime() / 1000);
192
+ if (cachedEntry !== null) {
193
+ const cacheAgeSeconds =
194
+ nowEpochSeconds - cachedEntry.recordedEpochSeconds;
195
+ if (cacheAgeSeconds <= hubTaskStatusCacheTtlSeconds) {
196
+ const active = this.isResolvedStatusActive(
197
+ cachedEntry.state,
198
+ cachedEntry.status,
199
+ activeHubTaskStatus,
188
200
  );
189
- return false;
201
+ if (!active) {
202
+ console.log(
203
+ `Skipping ${sessionName}: hub task ${hubTaskIssueUrl} is no longer active per cached status (state "${cachedEntry.state}", status "${cachedEntry.status ?? 'null'}", active status "${activeHubTaskStatus}").`,
204
+ );
205
+ }
206
+ return active;
190
207
  }
191
- return true;
192
- } catch (error) {
208
+ }
209
+
210
+ const resolution = await this.tryResolveAndCacheHubTask(
211
+ hubTaskIssueUrl,
212
+ activeHubTaskStatus,
213
+ sessionName,
214
+ now,
215
+ );
216
+ if (resolution.resolved) {
217
+ return resolution.active;
218
+ }
219
+
220
+ if (cachedEntry !== null) {
221
+ const active = this.isResolvedStatusActive(
222
+ cachedEntry.state,
223
+ cachedEntry.status,
224
+ activeHubTaskStatus,
225
+ );
193
226
  console.warn(
194
- `Failed to resolve hub task status for session ${sessionName} (${hubTaskIssueUrl}); sending notification (fail-open): ${
195
- error instanceof Error ? error.message : String(error)
196
- }`,
227
+ `Hub task ${hubTaskIssueUrl} for session ${sessionName} could not be resolved (${resolution.reason}); falling back to expired cached status (state "${cachedEntry.state}", status "${cachedEntry.status ?? 'null'}"), so the notification is ${active ? 'sent' : 'suppressed'}.`,
197
228
  );
198
- return true;
229
+ return active;
199
230
  }
231
+
232
+ console.warn(
233
+ `Hub task ${hubTaskIssueUrl} for session ${sessionName} is not resolvable and has no cached status (${resolution.reason}); sending notification (fail-open).`,
234
+ );
235
+ return true;
200
236
  };
201
237
 
238
+ private tryResolveAndCacheHubTask = async (
239
+ hubTaskIssueUrl: string,
240
+ activeHubTaskStatus: string,
241
+ sessionName: string,
242
+ now: Date,
243
+ ): Promise<
244
+ { resolved: true; active: boolean } | { resolved: false; reason: string }
245
+ > => {
246
+ if (this.hubTaskStatusResolver === null) {
247
+ return { resolved: false, reason: 'resolver is not configured' };
248
+ }
249
+ let issue: Awaited<ReturnType<HubTaskStatusResolver['getIssueByUrl']>>;
250
+ try {
251
+ issue = await this.hubTaskStatusResolver.getIssueByUrl(hubTaskIssueUrl);
252
+ } catch (error) {
253
+ return {
254
+ resolved: false,
255
+ reason: error instanceof Error ? error.message : String(error),
256
+ };
257
+ }
258
+ if (issue === null) {
259
+ return { resolved: false, reason: 'resolver returned no tracked task' };
260
+ }
261
+ if (this.hubTaskStatusCacheRepository !== null) {
262
+ await this.hubTaskStatusCacheRepository.saveHubTaskStatus({
263
+ url: hubTaskIssueUrl,
264
+ state: issue.state,
265
+ status: issue.status,
266
+ now,
267
+ });
268
+ }
269
+ const active = this.isResolvedStatusActive(
270
+ issue.state,
271
+ issue.status,
272
+ activeHubTaskStatus,
273
+ );
274
+ if (!active) {
275
+ console.log(
276
+ `Skipping ${sessionName}: hub task ${hubTaskIssueUrl} is no longer active (state "${issue.state}", status "${issue.status ?? 'null'}", active status "${activeHubTaskStatus}").`,
277
+ );
278
+ }
279
+ return { resolved: true, active };
280
+ };
281
+
282
+ private isResolvedStatusActive = (
283
+ state: 'OPEN' | 'CLOSED' | 'MERGED',
284
+ status: string | null,
285
+ activeHubTaskStatus: string,
286
+ ): boolean => state === 'OPEN' && status === activeHubTaskStatus;
287
+
202
288
  private collectSnapshots = async (
203
289
  interactiveSessions: InteractiveLiveSession[],
204
290
  transcriptPathBySessionName: Map<string, string>,
@@ -0,0 +1,20 @@
1
+ import { Issue } from '../../entities/Issue';
2
+
3
+ export type SilentSessionHubTaskStatusCacheEntry = {
4
+ url: string;
5
+ state: Issue['state'];
6
+ status: string | null;
7
+ recordedEpochSeconds: number;
8
+ };
9
+
10
+ export interface SilentSessionHubTaskStatusCacheRepository {
11
+ loadHubTaskStatus: (params: {
12
+ url: string;
13
+ }) => Promise<SilentSessionHubTaskStatusCacheEntry | null>;
14
+ saveHubTaskStatus: (params: {
15
+ url: string;
16
+ state: Issue['state'];
17
+ status: string | null;
18
+ now: Date;
19
+ }) => Promise<void>;
20
+ }
@@ -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,CAwjBP;CACH"}
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,CAmkBP;CACH"}
@@ -18,6 +18,8 @@ export type NotifySilentTmuxSessionsParams = {
18
18
  candidateDebounceStateFilePath: string | null;
19
19
  activeHubTaskStatus: string | null;
20
20
  hubTaskStatusResolver: HubTaskStatusResolver | null;
21
+ hubTaskStatusCacheStateFilePath: string | null;
22
+ hubTaskStatusCacheTtlSeconds: number;
21
23
  messageTemplates: SilentSessionMessageTemplates;
22
24
  now: Date;
23
25
  };
@@ -28,5 +30,6 @@ export declare const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS: {
28
30
  readonly subAgentRunningThresholdSeconds: number;
29
31
  readonly staggerSeconds: 25;
30
32
  readonly candidateDebounceRecencyWindowSeconds: number;
33
+ readonly hubTaskStatusCacheTtlSeconds: number;
31
34
  };
32
35
  //# 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,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"}
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,EAOtB,MAAM,0DAA0D,CAAC;AAclE,OAAO,EAEL,6BAA6B,EAC9B,MAAM,6DAA6D,CAAC;AAKrE,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,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,4BAA4B,EAAE,MAAM,CAAC;IACrC,gBAAgB,EAAE,6BAA6B,CAAC;IAChD,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAoCF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,8BAA8B,KACrC,OAAO,CAAC,IAAI,CAwEd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;;CAQ7C,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { Issue } from '../../domain/entities/Issue';
2
+ import { SilentSessionHubTaskStatusCacheEntry, SilentSessionHubTaskStatusCacheRepository } from '../../domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository';
3
+ export declare const DEFAULT_HUB_TASK_STATUS_RETENTION_WINDOW_SECONDS: number;
4
+ export declare class FileSystemSilentSessionHubTaskStatusCacheRepository implements SilentSessionHubTaskStatusCacheRepository {
5
+ private readonly stateFilePath;
6
+ private readonly retentionWindowSeconds;
7
+ constructor(stateFilePath?: string, retentionWindowSeconds?: number);
8
+ loadHubTaskStatus: (params: {
9
+ url: string;
10
+ }) => Promise<SilentSessionHubTaskStatusCacheEntry | null>;
11
+ saveHubTaskStatus: (params: {
12
+ url: string;
13
+ state: Issue["state"];
14
+ status: string | null;
15
+ now: Date;
16
+ }) => Promise<void>;
17
+ private readEntries;
18
+ private writeEntries;
19
+ }
20
+ //# sourceMappingURL=FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACpD,OAAO,EACL,oCAAoC,EACpC,yCAAyC,EAC1C,MAAM,oFAAoF,CAAC;AAQ5F,eAAO,MAAM,gDAAgD,QAAU,CAAC;AAOxE,qBAAa,mDAAoD,YAAW,yCAAyC;IAEjH,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBADtB,aAAa,GAAE,MAA+B,EAC9C,sBAAsB,GAAE,MAAyD;IAGpG,iBAAiB,GAAU,QAAQ;QACjC,GAAG,EAAE,MAAM,CAAC;KACb,KAAG,OAAO,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAOtD;IAEF,iBAAiB,GAAU,QAAQ;QACjC,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAoBf;IAEF,OAAO,CAAC,WAAW,CAwCjB;IAEF,OAAO,CAAC,YAAY,CAWlB;CACH"}
@@ -6,6 +6,7 @@ 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 { SilentSessionCandidateStateRepository } from './adapter-interfaces/SilentSessionCandidateStateRepository';
9
+ import { SilentSessionHubTaskStatusCacheRepository } from './adapter-interfaces/SilentSessionHubTaskStatusCacheRepository';
9
10
  import { Sleeper } from './adapter-interfaces/Sleeper';
10
11
  import { IssueRepository } from './adapter-interfaces/IssueRepository';
11
12
  export declare const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS: number;
@@ -13,6 +14,7 @@ export declare const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS: number;
13
14
  export declare const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS: number;
14
15
  export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
15
16
  export declare const DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS: number;
17
+ export declare const DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS: number;
16
18
  export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
17
19
  export declare const isGitHubIssueOrPullRequestSessionName: (sessionName: string) => boolean;
18
20
  export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
@@ -27,8 +29,9 @@ export declare class NotifySilentLiveSessionsUseCase {
27
29
  private readonly messageComposer;
28
30
  private readonly sleeper;
29
31
  private readonly hubTaskStatusResolver;
32
+ private readonly hubTaskStatusCacheRepository;
30
33
  private readonly resolveInteractiveLiveSessions;
31
- constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, candidateStateRepository: SilentSessionCandidateStateRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null);
34
+ constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, candidateStateRepository: SilentSessionCandidateStateRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null, hubTaskStatusCacheRepository?: SilentSessionHubTaskStatusCacheRepository | null);
32
35
  run: (params: {
33
36
  mainSilentThresholdSeconds: number;
34
37
  subAgentSilentThresholdSeconds: number;
@@ -36,9 +39,12 @@ export declare class NotifySilentLiveSessionsUseCase {
36
39
  staggerSeconds: number;
37
40
  candidateDebounceRecencyWindowSeconds: number;
38
41
  activeHubTaskStatus: string | null;
42
+ hubTaskStatusCacheTtlSeconds: number;
39
43
  now: Date;
40
44
  }) => Promise<void>;
41
45
  private isHubTaskActive;
46
+ private tryResolveAndCacheHubTask;
47
+ private isResolvedStatusActive;
42
48
  private collectSnapshots;
43
49
  private composeMessage;
44
50
  }
@@ -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,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,CA0CpB;CACH"}
1
+ {"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Issue } from '../../entities/Issue';
2
+ export type SilentSessionHubTaskStatusCacheEntry = {
3
+ url: string;
4
+ state: Issue['state'];
5
+ status: string | null;
6
+ recordedEpochSeconds: number;
7
+ };
8
+ export interface SilentSessionHubTaskStatusCacheRepository {
9
+ loadHubTaskStatus: (params: {
10
+ url: string;
11
+ }) => Promise<SilentSessionHubTaskStatusCacheEntry | null>;
12
+ saveHubTaskStatus: (params: {
13
+ url: string;
14
+ state: Issue['state'];
15
+ status: string | null;
16
+ now: Date;
17
+ }) => Promise<void>;
18
+ }
19
+ //# sourceMappingURL=SilentSessionHubTaskStatusCacheRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SilentSessionHubTaskStatusCacheRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,MAAM,MAAM,oCAAoC,GAAG;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,yCAAyC;IACxD,iBAAiB,EAAE,CAAC,MAAM,EAAE;QAC1B,GAAG,EAAE,MAAM,CAAC;KACb,KAAK,OAAO,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IAC3D,iBAAiB,EAAE,CAAC,MAAM,EAAE;QAC1B,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,GAAG,EAAE,IAAI,CAAC;KACX,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB"}