github-issue-tower-defence-management 1.118.0 → 1.118.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 +7 -0
- package/README.md +5 -3
- 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/FileSystemSilentSessionHubTaskStatusCacheRepository.js +128 -0
- package/bin/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.js.map +1 -0
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +61 -16
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/bin/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +11 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +6 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +13 -0
- package/src/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.test.ts +251 -0
- package/src/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.ts +121 -0
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +218 -9
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +105 -19
- package/src/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.ts +20 -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/FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts +20 -0
- package/types/adapter/repositories/FileSystemSilentSessionHubTaskStatusCacheRepository.d.ts.map +1 -0
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +7 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.d.ts +19 -0
- package/types/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.d.ts.map +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifySilentLiveSessionsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"NotifySilentLiveSessionsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"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"}
|
package/bin/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SilentSessionHubTaskStatusCacheRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -120,6 +120,8 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
120
120
|
candidateDebounceRecencyWindowSeconds?: number;
|
|
121
121
|
candidateDebounceStateFilePath?: string;
|
|
122
122
|
activeHubTaskStatus?: string;
|
|
123
|
+
hubTaskStatusCacheStateFilePath?: string;
|
|
124
|
+
hubTaskStatusCacheTtlSeconds?: number;
|
|
123
125
|
silentMainStalledMessage?: string;
|
|
124
126
|
silentSubAgentIdleMessageHeader?: string;
|
|
125
127
|
silentSubAgentIdleMessageFooter?: string;
|
|
@@ -626,6 +628,15 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
626
628
|
process.env.TDPM_ACTIVE_HUB_TASK_STATUS ??
|
|
627
629
|
null,
|
|
628
630
|
hubTaskStatusResolver: issueRepository,
|
|
631
|
+
hubTaskStatusCacheStateFilePath:
|
|
632
|
+
mergedInput.hubTaskStatusCacheStateFilePath ??
|
|
633
|
+
process.env.TDPM_SILENT_HUB_TASK_STATUS_CACHE_STATE_FILE_PATH ??
|
|
634
|
+
null,
|
|
635
|
+
hubTaskStatusCacheTtlSeconds: readSilentSeconds(
|
|
636
|
+
mergedInput.hubTaskStatusCacheTtlSeconds,
|
|
637
|
+
process.env.TDPM_SILENT_HUB_TASK_STATUS_CACHE_TTL_SECONDS,
|
|
638
|
+
DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS.hubTaskStatusCacheTtlSeconds,
|
|
639
|
+
),
|
|
629
640
|
messageTemplates: {
|
|
630
641
|
mainStalledMessage:
|
|
631
642
|
mergedInput.silentMainStalledMessage ??
|
|
@@ -39,6 +39,7 @@ const createMockRunner = (): Mocked<LocalCommandRunner> => ({
|
|
|
39
39
|
describe('notifySilentTmuxSessions', () => {
|
|
40
40
|
let configDir: string;
|
|
41
41
|
let candidateStateFilePath: string;
|
|
42
|
+
let hubTaskStatusCacheStateFilePath: string;
|
|
42
43
|
|
|
43
44
|
beforeEach(() => {
|
|
44
45
|
jest.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
@@ -47,6 +48,10 @@ describe('notifySilentTmuxSessions', () => {
|
|
|
47
48
|
configDir,
|
|
48
49
|
'silent-session-candidates.json',
|
|
49
50
|
);
|
|
51
|
+
hubTaskStatusCacheStateFilePath = path.join(
|
|
52
|
+
configDir,
|
|
53
|
+
'silent-session-hub-task-status.json',
|
|
54
|
+
);
|
|
50
55
|
});
|
|
51
56
|
|
|
52
57
|
afterEach(() => {
|
|
@@ -136,6 +141,7 @@ describe('notifySilentTmuxSessions', () => {
|
|
|
136
141
|
candidateDebounceStateFilePath: candidateStateFilePath,
|
|
137
142
|
activeHubTaskStatus: null,
|
|
138
143
|
hubTaskStatusResolver: null,
|
|
144
|
+
hubTaskStatusCacheStateFilePath: hubTaskStatusCacheStateFilePath,
|
|
139
145
|
messageTemplates: EMPTY_TEMPLATES,
|
|
140
146
|
now: NOW,
|
|
141
147
|
...DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
11
11
|
DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
12
12
|
DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
|
|
13
|
+
DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS,
|
|
13
14
|
} from '../../../domain/usecases/NotifySilentLiveSessionsUseCase';
|
|
14
15
|
import { DefaultSilentSessionMessageComposer } from '../../../domain/usecases/DefaultSilentSessionMessageComposer';
|
|
15
16
|
import { LocalProcessLiveSessionProcessSnapshotProvider } from '../../repositories/LocalProcessLiveSessionProcessSnapshotProvider';
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
} from '../../repositories/ConfigurableSilentSessionMessageComposer';
|
|
31
32
|
import { RealSleeper } from '../../repositories/RealSleeper';
|
|
32
33
|
import { FileSystemSilentSessionCandidateStateRepository } from '../../repositories/FileSystemSilentSessionCandidateStateRepository';
|
|
34
|
+
import { FileSystemSilentSessionHubTaskStatusCacheRepository } from '../../repositories/FileSystemSilentSessionHubTaskStatusCacheRepository';
|
|
33
35
|
|
|
34
36
|
export type NotifySilentTmuxSessionsParams = {
|
|
35
37
|
enabled: boolean;
|
|
@@ -47,6 +49,8 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
47
49
|
candidateDebounceStateFilePath: string | null;
|
|
48
50
|
activeHubTaskStatus: string | null;
|
|
49
51
|
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
52
|
+
hubTaskStatusCacheStateFilePath: string | null;
|
|
53
|
+
hubTaskStatusCacheTtlSeconds: number;
|
|
50
54
|
messageTemplates: SilentSessionMessageTemplates;
|
|
51
55
|
now: Date;
|
|
52
56
|
};
|
|
@@ -104,6 +108,8 @@ export const notifySilentTmuxSessions = async (
|
|
|
104
108
|
candidateDebounceStateFilePath,
|
|
105
109
|
activeHubTaskStatus,
|
|
106
110
|
hubTaskStatusResolver,
|
|
111
|
+
hubTaskStatusCacheStateFilePath,
|
|
112
|
+
hubTaskStatusCacheTtlSeconds,
|
|
107
113
|
messageTemplates,
|
|
108
114
|
now,
|
|
109
115
|
} = params;
|
|
@@ -141,6 +147,11 @@ export const notifySilentTmuxSessions = async (
|
|
|
141
147
|
messageComposer,
|
|
142
148
|
new RealSleeper(),
|
|
143
149
|
hubTaskStatusResolver,
|
|
150
|
+
hubTaskStatusCacheStateFilePath !== null
|
|
151
|
+
? new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
152
|
+
hubTaskStatusCacheStateFilePath,
|
|
153
|
+
)
|
|
154
|
+
: new FileSystemSilentSessionHubTaskStatusCacheRepository(),
|
|
144
155
|
);
|
|
145
156
|
await useCase.run({
|
|
146
157
|
mainSilentThresholdSeconds,
|
|
@@ -149,6 +160,7 @@ export const notifySilentTmuxSessions = async (
|
|
|
149
160
|
staggerSeconds,
|
|
150
161
|
candidateDebounceRecencyWindowSeconds,
|
|
151
162
|
activeHubTaskStatus,
|
|
163
|
+
hubTaskStatusCacheTtlSeconds,
|
|
152
164
|
now,
|
|
153
165
|
});
|
|
154
166
|
};
|
|
@@ -160,4 +172,5 @@ export const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS = {
|
|
|
160
172
|
staggerSeconds: DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
161
173
|
candidateDebounceRecencyWindowSeconds:
|
|
162
174
|
DEFAULT_CANDIDATE_DEBOUNCE_RECENCY_WINDOW_SECONDS,
|
|
175
|
+
hubTaskStatusCacheTtlSeconds: DEFAULT_HUB_TASK_STATUS_CACHE_TTL_SECONDS,
|
|
163
176
|
} as const;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_HUB_TASK_STATUS_RETENTION_WINDOW_SECONDS,
|
|
6
|
+
FileSystemSilentSessionHubTaskStatusCacheRepository,
|
|
7
|
+
} from './FileSystemSilentSessionHubTaskStatusCacheRepository';
|
|
8
|
+
|
|
9
|
+
describe('FileSystemSilentSessionHubTaskStatusCacheRepository', () => {
|
|
10
|
+
let rootDirectory: string;
|
|
11
|
+
let stateFilePath: string;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
rootDirectory = fs.mkdtempSync(
|
|
15
|
+
path.join(os.tmpdir(), 'silent-session-hub-task-status-'),
|
|
16
|
+
);
|
|
17
|
+
stateFilePath = path.join(
|
|
18
|
+
rootDirectory,
|
|
19
|
+
'silent-session-hub-task-status.json',
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
fs.rmSync(rootDirectory, { force: true, recursive: true });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const issueAlpha = 'https://github.com/HiromiShikata/repo/issues/100';
|
|
28
|
+
const issueBravo = 'https://github.com/HiromiShikata/repo/issues/200';
|
|
29
|
+
|
|
30
|
+
it('round-trips a saved status so the next cycle reads it back', async () => {
|
|
31
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
32
|
+
stateFilePath,
|
|
33
|
+
);
|
|
34
|
+
const now = new Date('2026-06-26T00:00:00Z');
|
|
35
|
+
|
|
36
|
+
await repository.saveHubTaskStatus({
|
|
37
|
+
url: issueAlpha,
|
|
38
|
+
state: 'OPEN',
|
|
39
|
+
status: 'In tmux',
|
|
40
|
+
now,
|
|
41
|
+
});
|
|
42
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
43
|
+
|
|
44
|
+
expect(loaded).toEqual({
|
|
45
|
+
url: issueAlpha,
|
|
46
|
+
state: 'OPEN',
|
|
47
|
+
status: 'In tmux',
|
|
48
|
+
recordedEpochSeconds: Math.floor(now.getTime() / 1000),
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('preserves a null project status across a round-trip', async () => {
|
|
53
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
54
|
+
stateFilePath,
|
|
55
|
+
);
|
|
56
|
+
const now = new Date('2026-06-26T00:00:00Z');
|
|
57
|
+
|
|
58
|
+
await repository.saveHubTaskStatus({
|
|
59
|
+
url: issueAlpha,
|
|
60
|
+
state: 'CLOSED',
|
|
61
|
+
status: null,
|
|
62
|
+
now,
|
|
63
|
+
});
|
|
64
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
65
|
+
|
|
66
|
+
expect(loaded).toEqual({
|
|
67
|
+
url: issueAlpha,
|
|
68
|
+
state: 'CLOSED',
|
|
69
|
+
status: null,
|
|
70
|
+
recordedEpochSeconds: Math.floor(now.getTime() / 1000),
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('returns null when no status has been recorded for the url', async () => {
|
|
75
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
76
|
+
stateFilePath,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
80
|
+
|
|
81
|
+
expect(loaded).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('returns null when no state file exists yet', async () => {
|
|
85
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
86
|
+
path.join(rootDirectory, 'missing.json'),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
90
|
+
|
|
91
|
+
expect(loaded).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('returns the most recently recorded status when a url is saved again', async () => {
|
|
95
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
96
|
+
stateFilePath,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
await repository.saveHubTaskStatus({
|
|
100
|
+
url: issueAlpha,
|
|
101
|
+
state: 'OPEN',
|
|
102
|
+
status: 'In tmux',
|
|
103
|
+
now: new Date('2026-06-26T00:00:00Z'),
|
|
104
|
+
});
|
|
105
|
+
await repository.saveHubTaskStatus({
|
|
106
|
+
url: issueAlpha,
|
|
107
|
+
state: 'CLOSED',
|
|
108
|
+
status: 'Done',
|
|
109
|
+
now: new Date('2026-06-26T00:01:00Z'),
|
|
110
|
+
});
|
|
111
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
112
|
+
|
|
113
|
+
expect(loaded?.state).toBe('CLOSED');
|
|
114
|
+
expect(loaded?.status).toBe('Done');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('preserves another url recorded by a concurrent run when saving a different url', async () => {
|
|
118
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
119
|
+
stateFilePath,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
await repository.saveHubTaskStatus({
|
|
123
|
+
url: issueAlpha,
|
|
124
|
+
state: 'OPEN',
|
|
125
|
+
status: 'In tmux',
|
|
126
|
+
now: new Date('2026-06-26T00:00:00Z'),
|
|
127
|
+
});
|
|
128
|
+
await repository.saveHubTaskStatus({
|
|
129
|
+
url: issueBravo,
|
|
130
|
+
state: 'CLOSED',
|
|
131
|
+
status: 'Done',
|
|
132
|
+
now: new Date('2026-06-26T00:00:30Z'),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(
|
|
136
|
+
(await repository.loadHubTaskStatus({ url: issueAlpha }))?.state,
|
|
137
|
+
).toBe('OPEN');
|
|
138
|
+
expect(
|
|
139
|
+
(await repository.loadHubTaskStatus({ url: issueBravo }))?.state,
|
|
140
|
+
).toBe('CLOSED');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('drops a stored entry that has aged beyond the retention window on the next save', async () => {
|
|
144
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
145
|
+
stateFilePath,
|
|
146
|
+
60 * 60,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
await repository.saveHubTaskStatus({
|
|
150
|
+
url: issueAlpha,
|
|
151
|
+
state: 'OPEN',
|
|
152
|
+
status: 'In tmux',
|
|
153
|
+
now: new Date('2026-06-26T00:00:00Z'),
|
|
154
|
+
});
|
|
155
|
+
await repository.saveHubTaskStatus({
|
|
156
|
+
url: issueBravo,
|
|
157
|
+
state: 'OPEN',
|
|
158
|
+
status: 'In tmux',
|
|
159
|
+
now: new Date('2026-06-26T01:30:00Z'),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const persisted: unknown = JSON.parse(
|
|
163
|
+
fs.readFileSync(stateFilePath, 'utf8'),
|
|
164
|
+
);
|
|
165
|
+
expect(persisted).toEqual({
|
|
166
|
+
hubTaskStatuses: [
|
|
167
|
+
{
|
|
168
|
+
url: issueBravo,
|
|
169
|
+
state: 'OPEN',
|
|
170
|
+
status: 'In tmux',
|
|
171
|
+
recordedEpochSeconds: Math.floor(
|
|
172
|
+
new Date('2026-06-26T01:30:00Z').getTime() / 1000,
|
|
173
|
+
),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('treats a corrupt state file as no recorded status', async () => {
|
|
180
|
+
fs.writeFileSync(stateFilePath, 'not valid json');
|
|
181
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
182
|
+
stateFilePath,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
186
|
+
|
|
187
|
+
expect(loaded).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('ignores a malformed stored entry that lacks a valid state', async () => {
|
|
191
|
+
fs.writeFileSync(
|
|
192
|
+
stateFilePath,
|
|
193
|
+
JSON.stringify({
|
|
194
|
+
hubTaskStatuses: [
|
|
195
|
+
{
|
|
196
|
+
url: issueAlpha,
|
|
197
|
+
state: 'UNKNOWN',
|
|
198
|
+
status: 'In tmux',
|
|
199
|
+
recordedEpochSeconds: 1,
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
204
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
205
|
+
stateFilePath,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const loaded = await repository.loadHubTaskStatus({ url: issueAlpha });
|
|
209
|
+
|
|
210
|
+
expect(loaded).toBeNull();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('creates the parent directory when the configured path does not exist yet', async () => {
|
|
214
|
+
const nestedPath = path.join(rootDirectory, 'nested', 'dir', 'state.json');
|
|
215
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
216
|
+
nestedPath,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
await repository.saveHubTaskStatus({
|
|
220
|
+
url: issueAlpha,
|
|
221
|
+
state: 'OPEN',
|
|
222
|
+
status: 'In tmux',
|
|
223
|
+
now: new Date('2026-06-26T00:00:00Z'),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
expect(fs.existsSync(nestedPath)).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('writes atomically by renaming a temp file into place leaving no temp file behind', async () => {
|
|
230
|
+
const repository = new FileSystemSilentSessionHubTaskStatusCacheRepository(
|
|
231
|
+
stateFilePath,
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
await repository.saveHubTaskStatus({
|
|
235
|
+
url: issueAlpha,
|
|
236
|
+
state: 'OPEN',
|
|
237
|
+
status: 'In tmux',
|
|
238
|
+
now: new Date('2026-06-26T00:00:00Z'),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const leftoverTempFiles = fs
|
|
242
|
+
.readdirSync(rootDirectory)
|
|
243
|
+
.filter((name) => name.includes('.tmp'));
|
|
244
|
+
expect(leftoverTempFiles).toEqual([]);
|
|
245
|
+
expect(fs.existsSync(stateFilePath)).toBe(true);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('exposes the default retention window as a named constant', () => {
|
|
249
|
+
expect(DEFAULT_HUB_TASK_STATUS_RETENTION_WINDOW_SECONDS).toBe(60 * 60);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { Issue } from '../../domain/entities/Issue';
|
|
5
|
+
import {
|
|
6
|
+
SilentSessionHubTaskStatusCacheEntry,
|
|
7
|
+
SilentSessionHubTaskStatusCacheRepository,
|
|
8
|
+
} from '../../domain/usecases/adapter-interfaces/SilentSessionHubTaskStatusCacheRepository';
|
|
9
|
+
|
|
10
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
11
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
12
|
+
|
|
13
|
+
const isIssueState = (value: unknown): value is Issue['state'] =>
|
|
14
|
+
value === 'OPEN' || value === 'CLOSED' || value === 'MERGED';
|
|
15
|
+
|
|
16
|
+
export const DEFAULT_HUB_TASK_STATUS_RETENTION_WINDOW_SECONDS = 60 * 60;
|
|
17
|
+
|
|
18
|
+
const defaultStateFilePath = (): string => {
|
|
19
|
+
const base = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), '.cache');
|
|
20
|
+
return path.join(base, 'tdpm', 'silent-session-hub-task-status.json');
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export class FileSystemSilentSessionHubTaskStatusCacheRepository implements SilentSessionHubTaskStatusCacheRepository {
|
|
24
|
+
constructor(
|
|
25
|
+
private readonly stateFilePath: string = defaultStateFilePath(),
|
|
26
|
+
private readonly retentionWindowSeconds: number = DEFAULT_HUB_TASK_STATUS_RETENTION_WINDOW_SECONDS,
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
loadHubTaskStatus = async (params: {
|
|
30
|
+
url: string;
|
|
31
|
+
}): Promise<SilentSessionHubTaskStatusCacheEntry | null> => {
|
|
32
|
+
for (const entry of this.readEntries()) {
|
|
33
|
+
if (entry.url === params.url) {
|
|
34
|
+
return entry;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
saveHubTaskStatus = async (params: {
|
|
41
|
+
url: string;
|
|
42
|
+
state: Issue['state'];
|
|
43
|
+
status: string | null;
|
|
44
|
+
now: Date;
|
|
45
|
+
}): Promise<void> => {
|
|
46
|
+
const recordedEpochSeconds = Math.floor(params.now.getTime() / 1000);
|
|
47
|
+
const oldestRetainedEpochSeconds =
|
|
48
|
+
recordedEpochSeconds - this.retentionWindowSeconds;
|
|
49
|
+
const mergedByUrl = new Map<string, SilentSessionHubTaskStatusCacheEntry>();
|
|
50
|
+
for (const entry of this.readEntries()) {
|
|
51
|
+
if (
|
|
52
|
+
entry.recordedEpochSeconds >= oldestRetainedEpochSeconds &&
|
|
53
|
+
entry.url !== params.url
|
|
54
|
+
) {
|
|
55
|
+
mergedByUrl.set(entry.url, entry);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
mergedByUrl.set(params.url, {
|
|
59
|
+
url: params.url,
|
|
60
|
+
state: params.state,
|
|
61
|
+
status: params.status,
|
|
62
|
+
recordedEpochSeconds,
|
|
63
|
+
});
|
|
64
|
+
this.writeEntries(Array.from(mergedByUrl.values()));
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
private readEntries = (): SilentSessionHubTaskStatusCacheEntry[] => {
|
|
68
|
+
let raw: string;
|
|
69
|
+
try {
|
|
70
|
+
raw = fs.readFileSync(this.stateFilePath, 'utf8');
|
|
71
|
+
} catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
let parsed: unknown;
|
|
75
|
+
try {
|
|
76
|
+
parsed = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
if (!isRecord(parsed)) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const storedEntries = parsed.hubTaskStatuses;
|
|
84
|
+
if (!Array.isArray(storedEntries)) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const entries: SilentSessionHubTaskStatusCacheEntry[] = [];
|
|
88
|
+
for (const storedEntry of storedEntries) {
|
|
89
|
+
if (!isRecord(storedEntry)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const url = storedEntry.url;
|
|
93
|
+
const state = storedEntry.state;
|
|
94
|
+
const status = storedEntry.status;
|
|
95
|
+
const recordedEpochSeconds = storedEntry.recordedEpochSeconds;
|
|
96
|
+
if (
|
|
97
|
+
typeof url === 'string' &&
|
|
98
|
+
isIssueState(state) &&
|
|
99
|
+
(typeof status === 'string' || status === null) &&
|
|
100
|
+
typeof recordedEpochSeconds === 'number' &&
|
|
101
|
+
Number.isFinite(recordedEpochSeconds)
|
|
102
|
+
) {
|
|
103
|
+
entries.push({ url, state, status, recordedEpochSeconds });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return entries;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
private writeEntries = (
|
|
110
|
+
entries: SilentSessionHubTaskStatusCacheEntry[],
|
|
111
|
+
): void => {
|
|
112
|
+
const directory = path.dirname(this.stateFilePath);
|
|
113
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
114
|
+
const temporaryPath = `${this.stateFilePath}.${process.pid}.tmp`;
|
|
115
|
+
fs.writeFileSync(
|
|
116
|
+
temporaryPath,
|
|
117
|
+
JSON.stringify({ hubTaskStatuses: entries }),
|
|
118
|
+
);
|
|
119
|
+
fs.renameSync(temporaryPath, this.stateFilePath);
|
|
120
|
+
};
|
|
121
|
+
}
|