github-issue-tower-defence-management 1.114.1 → 1.115.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.
- package/CHANGELOG.md +14 -0
- package/README.md +5 -5
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +10 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +3 -2
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js +14 -14
- package/bin/adapter/repositories/FileSystemSessionOutputActivityRepository.js.map +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +36 -2
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/bin/domain/usecases/ResolveInteractiveLiveSessionsUseCase.js +34 -6
- package/bin/domain/usecases/ResolveInteractiveLiveSessionsUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +6 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +120 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +7 -0
- package/src/adapter/repositories/FileSystemInteractiveLiveSessionTranscriptResolver.test.ts +46 -0
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.test.ts +57 -5
- package/src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts +14 -14
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +188 -1
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +59 -0
- package/src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.test.ts +76 -0
- package/src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts +37 -6
- 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/FileSystemSessionOutputActivityRepository.d.ts +8 -5
- package/types/adapter/repositories/FileSystemSessionOutputActivityRepository.d.ts.map +1 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +7 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/ResolveInteractiveLiveSessionsUseCase.d.ts +12 -0
- package/types/domain/usecases/ResolveInteractiveLiveSessionsUseCase.d.ts.map +1 -1
|
@@ -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 { 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;
|
|
@@ -16,6 +17,17 @@ export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
|
|
|
16
17
|
export const DEFAULT_NOTIFICATION_COOLDOWN_SECONDS = 30 * 60;
|
|
17
18
|
export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
18
19
|
|
|
20
|
+
const GITHUB_ISSUE_URL_PATTERN =
|
|
21
|
+
/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/\d+$/;
|
|
22
|
+
|
|
23
|
+
export const parseHubTaskIssueUrlFromSessionName = (
|
|
24
|
+
sessionName: string,
|
|
25
|
+
): string | null => {
|
|
26
|
+
return GITHUB_ISSUE_URL_PATTERN.test(sessionName) ? sessionName : null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
30
|
+
|
|
19
31
|
type NotifyCandidate = {
|
|
20
32
|
sessionName: string;
|
|
21
33
|
message: string;
|
|
@@ -34,6 +46,7 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
34
46
|
private readonly notificationRepository: SilentSessionNotificationRepository,
|
|
35
47
|
private readonly messageComposer: SilentSessionMessageComposer,
|
|
36
48
|
private readonly sleeper: Sleeper,
|
|
49
|
+
private readonly hubTaskStatusResolver: HubTaskStatusResolver | null = null,
|
|
37
50
|
) {}
|
|
38
51
|
|
|
39
52
|
run = async (params: {
|
|
@@ -42,6 +55,7 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
42
55
|
subAgentRunningThresholdSeconds: number;
|
|
43
56
|
cooldownSeconds: number;
|
|
44
57
|
staggerSeconds: number;
|
|
58
|
+
activeHubTaskStatus: string | null;
|
|
45
59
|
now: Date;
|
|
46
60
|
}): Promise<void> => {
|
|
47
61
|
const snapshot =
|
|
@@ -96,6 +110,14 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
96
110
|
);
|
|
97
111
|
continue;
|
|
98
112
|
}
|
|
113
|
+
if (
|
|
114
|
+
!(await this.isHubTaskActive(
|
|
115
|
+
candidate.sessionName,
|
|
116
|
+
params.activeHubTaskStatus,
|
|
117
|
+
))
|
|
118
|
+
) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
99
121
|
if (sentCount > 0) {
|
|
100
122
|
await this.sleeper.sleep(params.staggerSeconds * 1000);
|
|
101
123
|
}
|
|
@@ -112,6 +134,43 @@ export class NotifySilentLiveSessionsUseCase {
|
|
|
112
134
|
}
|
|
113
135
|
};
|
|
114
136
|
|
|
137
|
+
private isHubTaskActive = async (
|
|
138
|
+
sessionName: string,
|
|
139
|
+
activeHubTaskStatus: string | null,
|
|
140
|
+
): Promise<boolean> => {
|
|
141
|
+
if (activeHubTaskStatus === null || this.hubTaskStatusResolver === null) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
const hubTaskIssueUrl = parseHubTaskIssueUrlFromSessionName(sessionName);
|
|
145
|
+
if (hubTaskIssueUrl === null) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const issue =
|
|
150
|
+
await this.hubTaskStatusResolver.getIssueByUrl(hubTaskIssueUrl);
|
|
151
|
+
if (issue === null) {
|
|
152
|
+
console.warn(
|
|
153
|
+
`Hub task ${hubTaskIssueUrl} for session ${sessionName} could not be resolved; sending notification (fail-open).`,
|
|
154
|
+
);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
if (issue.state !== 'OPEN' || issue.status !== activeHubTaskStatus) {
|
|
158
|
+
console.log(
|
|
159
|
+
`Skipping ${sessionName}: hub task ${hubTaskIssueUrl} is no longer active (state "${issue.state}", status "${issue.status ?? 'null'}", active status "${activeHubTaskStatus}").`,
|
|
160
|
+
);
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.warn(
|
|
166
|
+
`Failed to resolve hub task status for session ${sessionName} (${hubTaskIssueUrl}); sending notification (fail-open): ${
|
|
167
|
+
error instanceof Error ? error.message : String(error)
|
|
168
|
+
}`,
|
|
169
|
+
);
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
115
174
|
private collectSnapshots = async (
|
|
116
175
|
interactiveSessions: InteractiveLiveSession[],
|
|
117
176
|
transcriptPathBySessionName: Map<string, string>,
|
|
@@ -219,6 +219,82 @@ describe('ResolveInteractiveLiveSessionsUseCase', () => {
|
|
|
219
219
|
]);
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
+
it('collects the descendant-propagated session id after the own launch id for a non-resume session', () => {
|
|
223
|
+
const snapshot: LiveSessionProcessSnapshot = {
|
|
224
|
+
sessions: [{ sessionName: 'non-resume', panePids: [900] }],
|
|
225
|
+
processes: [
|
|
226
|
+
processInfo({ pid: 900, ppid: 1, commandLine: 'shell' }),
|
|
227
|
+
processInfo({
|
|
228
|
+
pid: 901,
|
|
229
|
+
ppid: 900,
|
|
230
|
+
commandLine: 'claude --model opus',
|
|
231
|
+
sessionId: 'launch-id',
|
|
232
|
+
configDir: '/config/non-resume',
|
|
233
|
+
}),
|
|
234
|
+
processInfo({
|
|
235
|
+
pid: 902,
|
|
236
|
+
ppid: 901,
|
|
237
|
+
commandLine: 'node tool worker',
|
|
238
|
+
sessionId: 'harness-id',
|
|
239
|
+
configDir: '/config/non-resume',
|
|
240
|
+
}),
|
|
241
|
+
processInfo({
|
|
242
|
+
pid: 903,
|
|
243
|
+
ppid: 902,
|
|
244
|
+
commandLine: 'node nested worker',
|
|
245
|
+
sessionId: 'harness-id',
|
|
246
|
+
configDir: '/config/non-resume',
|
|
247
|
+
}),
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const result = useCase.resolve(snapshot);
|
|
252
|
+
|
|
253
|
+
expect(result).toEqual([
|
|
254
|
+
{
|
|
255
|
+
sessionName: 'non-resume',
|
|
256
|
+
sessionId: 'launch-id',
|
|
257
|
+
candidateSessionIds: ['launch-id', 'harness-id'],
|
|
258
|
+
configDir: '/config/non-resume',
|
|
259
|
+
},
|
|
260
|
+
]);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('orders the rotated current id, then the launch id, then the descendant id', () => {
|
|
264
|
+
const snapshot: LiveSessionProcessSnapshot = {
|
|
265
|
+
sessions: [{ sessionName: 'non-resume', panePids: [910] }],
|
|
266
|
+
processes: [
|
|
267
|
+
processInfo({ pid: 910, ppid: 1, commandLine: 'shell' }),
|
|
268
|
+
processInfo({
|
|
269
|
+
pid: 911,
|
|
270
|
+
ppid: 910,
|
|
271
|
+
commandLine: 'claude --model opus',
|
|
272
|
+
sessionId: 'launch-id',
|
|
273
|
+
currentSessionId: 'rotated-id',
|
|
274
|
+
configDir: '/config/non-resume',
|
|
275
|
+
}),
|
|
276
|
+
processInfo({
|
|
277
|
+
pid: 912,
|
|
278
|
+
ppid: 911,
|
|
279
|
+
commandLine: 'node tool worker',
|
|
280
|
+
sessionId: 'harness-id',
|
|
281
|
+
configDir: '/config/non-resume',
|
|
282
|
+
}),
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const result = useCase.resolve(snapshot);
|
|
287
|
+
|
|
288
|
+
expect(result).toEqual([
|
|
289
|
+
{
|
|
290
|
+
sessionName: 'non-resume',
|
|
291
|
+
sessionId: 'launch-id',
|
|
292
|
+
candidateSessionIds: ['rotated-id', 'launch-id', 'harness-id'],
|
|
293
|
+
configDir: '/config/non-resume',
|
|
294
|
+
},
|
|
295
|
+
]);
|
|
296
|
+
});
|
|
297
|
+
|
|
222
298
|
it('returns an empty list when there are no sessions', () => {
|
|
223
299
|
const result = useCase.resolve({ sessions: [], processes: [] });
|
|
224
300
|
|
|
@@ -66,30 +66,61 @@ export class ResolveInteractiveLiveSessionsUseCase {
|
|
|
66
66
|
) {
|
|
67
67
|
continue;
|
|
68
68
|
}
|
|
69
|
+
const candidateSessionIds = this.collectCandidateSessionIds(
|
|
70
|
+
interactiveProcess,
|
|
71
|
+
childrenByPpid,
|
|
72
|
+
);
|
|
69
73
|
sessions.push({
|
|
70
74
|
sessionName: session.sessionName,
|
|
71
75
|
sessionId: interactiveProcess.sessionId,
|
|
72
|
-
candidateSessionIds
|
|
73
|
-
this.collectCandidateSessionIds(interactiveProcess),
|
|
76
|
+
candidateSessionIds,
|
|
74
77
|
configDir: interactiveProcess.configDir,
|
|
75
78
|
});
|
|
76
79
|
}
|
|
77
80
|
return sessions;
|
|
78
81
|
};
|
|
79
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Collects the distinct session ids that may name the actively-written
|
|
85
|
+
* transcript on disk, in priority order. The rotated current session id
|
|
86
|
+
* recorded for the interactive process is first, because for a resumed or
|
|
87
|
+
* compacted session the id rotates and the live transcript is named by the
|
|
88
|
+
* current id. The interactive process's own launch id follows, then the
|
|
89
|
+
* distinct ids propagated to its descendant processes. For a `--resume`
|
|
90
|
+
* session these ids coincide, yielding a single id; for a non-resume session
|
|
91
|
+
* the own (launch) id names no transcript and the live transcript is named by
|
|
92
|
+
* the descendant-propagated id, which is included here so the resolver can
|
|
93
|
+
* find the actively-written file.
|
|
94
|
+
*/
|
|
80
95
|
private collectCandidateSessionIds = (
|
|
81
96
|
interactiveProcess: LiveSessionProcessInfo,
|
|
97
|
+
childrenByPpid: Map<number, LiveSessionProcessInfo[]>,
|
|
82
98
|
): string[] => {
|
|
83
99
|
const candidateSessionIds: string[] = [];
|
|
84
100
|
const seenSessionIds = new Set<string>();
|
|
85
|
-
|
|
86
|
-
interactiveProcess.currentSessionId,
|
|
87
|
-
interactiveProcess.sessionId,
|
|
88
|
-
]) {
|
|
101
|
+
const pushSessionId = (sessionId: string | null): void => {
|
|
89
102
|
if (sessionId !== null && !seenSessionIds.has(sessionId)) {
|
|
90
103
|
seenSessionIds.add(sessionId);
|
|
91
104
|
candidateSessionIds.push(sessionId);
|
|
92
105
|
}
|
|
106
|
+
};
|
|
107
|
+
pushSessionId(interactiveProcess.currentSessionId);
|
|
108
|
+
const visitedPids = new Set<number>();
|
|
109
|
+
const queue: LiveSessionProcessInfo[] = [interactiveProcess];
|
|
110
|
+
let head = 0;
|
|
111
|
+
while (head < queue.length) {
|
|
112
|
+
const process = queue[head];
|
|
113
|
+
head += 1;
|
|
114
|
+
if (visitedPids.has(process.pid)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
visitedPids.add(process.pid);
|
|
118
|
+
pushSessionId(process.sessionId);
|
|
119
|
+
for (const child of childrenByPpid.get(process.pid) ?? []) {
|
|
120
|
+
if (!visitedPids.has(child.pid)) {
|
|
121
|
+
queue.push(child);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
93
124
|
}
|
|
94
125
|
return candidateSessionIds;
|
|
95
126
|
};
|
|
@@ -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;AA0D3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AA0D3D,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,CA+iBP;CACH"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
2
2
|
import { ProcessEnvironReader } from '../../../domain/usecases/adapter-interfaces/ProcessEnvironReader';
|
|
3
|
+
import { HubTaskStatusResolver } from '../../../domain/usecases/NotifySilentLiveSessionsUseCase';
|
|
3
4
|
import { LocalStorageCacheRepository } from '../../repositories/LocalStorageCacheRepository';
|
|
4
5
|
import { SilentSessionMessageTemplates } from '../../repositories/ConfigurableSilentSessionMessageComposer';
|
|
5
6
|
export type NotifySilentTmuxSessionsParams = {
|
|
@@ -16,6 +17,8 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
16
17
|
subAgentRunningThresholdSeconds: number;
|
|
17
18
|
cooldownSeconds: number;
|
|
18
19
|
staggerSeconds: number;
|
|
20
|
+
activeHubTaskStatus: string | null;
|
|
21
|
+
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
19
22
|
messageTemplates: SilentSessionMessageTemplates;
|
|
20
23
|
now: Date;
|
|
21
24
|
};
|
|
@@ -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,EAMtB,MAAM,0DAA0D,CAAC;AAOlE,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAQ7F,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,IAAI,CAAC,2BAA2B,EAAE,WAAW,GAAG,KAAK,CAAC,CAAC;IACxE,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,eAAe,EAAE,MAAM,CAAC;IACxB,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,CA8Dd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;CAM7C,CAAC"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { LiveSessionOutputActivity } from '../../domain/entities/LiveSessionOutputActivity';
|
|
2
2
|
import { SessionOutputActivityRepository } from '../../domain/usecases/adapter-interfaces/SessionOutputActivityRepository';
|
|
3
3
|
/**
|
|
4
|
-
* Reads the last main-session
|
|
4
|
+
* Reads the last main-session activity time for each live session from its
|
|
5
5
|
* already-resolved transcript path. Idle time is computed from the timestamp of
|
|
6
|
-
* the latest
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* the latest entry of any kind (assistant text, owner replies, tool results, or
|
|
7
|
+
* any other entry type) rather than from the transcript file modification time.
|
|
8
|
+
* Because a session that is actively running tool calls keeps appending entries
|
|
9
|
+
* such as `user` and `tool_result` even while it emits no assistant text, every
|
|
10
|
+
* entry with a parseable timestamp counts as activity, so a working session is
|
|
11
|
+
* not mistaken for a silent one.
|
|
9
12
|
*/
|
|
10
13
|
export declare class FileSystemSessionOutputActivityRepository implements SessionOutputActivityRepository {
|
|
11
14
|
listSessionOutputActivities: (transcriptPathBySessionName: Map<string, string>) => Promise<LiveSessionOutputActivity[]>;
|
|
12
|
-
private
|
|
15
|
+
private readLastActivityEpochSeconds;
|
|
13
16
|
}
|
|
14
17
|
//# sourceMappingURL=FileSystemSessionOutputActivityRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSystemSessionOutputActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;AAqB3H
|
|
1
|
+
{"version":3,"file":"FileSystemSessionOutputActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionOutputActivityRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;AAqB3H;;;;;;;;;GASG;AACH,qBAAa,yCAA0C,YAAW,+BAA+B;IAC/F,2BAA2B,GACzB,6BAA6B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/C,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAUrC;IAEF,OAAO,CAAC,4BAA4B,CAoClC;CACH"}
|
|
@@ -6,11 +6,14 @@ 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
13
|
export declare const DEFAULT_NOTIFICATION_COOLDOWN_SECONDS: number;
|
|
13
14
|
export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
15
|
+
export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
|
|
16
|
+
export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
|
|
14
17
|
export declare class NotifySilentLiveSessionsUseCase {
|
|
15
18
|
private readonly liveSessionProcessSnapshotProvider;
|
|
16
19
|
private readonly interactiveLiveSessionTranscriptResolver;
|
|
@@ -20,16 +23,19 @@ export declare class NotifySilentLiveSessionsUseCase {
|
|
|
20
23
|
private readonly notificationRepository;
|
|
21
24
|
private readonly messageComposer;
|
|
22
25
|
private readonly sleeper;
|
|
26
|
+
private readonly hubTaskStatusResolver;
|
|
23
27
|
private readonly resolveInteractiveLiveSessions;
|
|
24
|
-
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper);
|
|
28
|
+
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, sessionOutputActivityRepository: SessionOutputActivityRepository, subAgentActivityRepository: SessionSubAgentActivityRepository, ownerCallStatusProvider: OwnerCallStatusProvider, notificationRepository: SilentSessionNotificationRepository, messageComposer: SilentSessionMessageComposer, sleeper: Sleeper, hubTaskStatusResolver?: HubTaskStatusResolver | null);
|
|
25
29
|
run: (params: {
|
|
26
30
|
mainSilentThresholdSeconds: number;
|
|
27
31
|
subAgentSilentThresholdSeconds: number;
|
|
28
32
|
subAgentRunningThresholdSeconds: number;
|
|
29
33
|
cooldownSeconds: number;
|
|
30
34
|
staggerSeconds: number;
|
|
35
|
+
activeHubTaskStatus: string | null;
|
|
31
36
|
now: Date;
|
|
32
37
|
}) => Promise<void>;
|
|
38
|
+
private isHubTaskActive;
|
|
33
39
|
private collectSnapshots;
|
|
34
40
|
private composeMessage;
|
|
35
41
|
}
|
|
@@ -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,qCAAqC,QAAU,CAAC;AAC7D,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,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CA2Ef;IAEF,OAAO,CAAC,eAAe,CAmCrB;IAEF,OAAO,CAAC,gBAAgB,CA8CtB;IAEF,OAAO,CAAC,cAAc,CAqCpB;CACH"}
|
|
@@ -18,6 +18,18 @@ export declare const OWNER_HANDOVER_COMMAND_MARKER = "Take ownership of";
|
|
|
18
18
|
*/
|
|
19
19
|
export declare class ResolveInteractiveLiveSessionsUseCase {
|
|
20
20
|
resolve: (snapshot: LiveSessionProcessSnapshot) => InteractiveLiveSession[];
|
|
21
|
+
/**
|
|
22
|
+
* Collects the distinct session ids that may name the actively-written
|
|
23
|
+
* transcript on disk, in priority order. The rotated current session id
|
|
24
|
+
* recorded for the interactive process is first, because for a resumed or
|
|
25
|
+
* compacted session the id rotates and the live transcript is named by the
|
|
26
|
+
* current id. The interactive process's own launch id follows, then the
|
|
27
|
+
* distinct ids propagated to its descendant processes. For a `--resume`
|
|
28
|
+
* session these ids coincide, yielding a single id; for a non-resume session
|
|
29
|
+
* the own (launch) id names no transcript and the live transcript is named by
|
|
30
|
+
* the descendant-propagated id, which is included here so the resolver can
|
|
31
|
+
* find the actively-written file.
|
|
32
|
+
*/
|
|
21
33
|
private collectCandidateSessionIds;
|
|
22
34
|
private findInteractiveProcess;
|
|
23
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResolveInteractiveLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAEL,0BAA0B,EAC3B,MAAM,wCAAwC,CAAC;AAOhD,eAAO,MAAM,6BAA6B,sBAAsB,CAAC;AAejE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,qCAAqC;IAChD,OAAO,GACL,UAAU,0BAA0B,KACnC,sBAAsB,EAAE,
|
|
1
|
+
{"version":3,"file":"ResolveInteractiveLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/ResolveInteractiveLiveSessionsUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAEL,0BAA0B,EAC3B,MAAM,wCAAwC,CAAC;AAOhD,eAAO,MAAM,6BAA6B,sBAAsB,CAAC;AAejE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,qCAAqC;IAChD,OAAO,GACL,UAAU,0BAA0B,KACnC,sBAAsB,EAAE,CAoCzB;IAEF;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,0BAA0B,CA+BhC;IAEF,OAAO,CAAC,sBAAsB,CA0B5B;CACH"}
|