github-issue-tower-defence-management 1.117.4 → 1.117.6
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/console/ui-dist/assets/{index-DGVKvwux.css → index-BMe1bEF4.css} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-BXcfEKkX.js → index-Dx_VHaDe.js} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +2 -7
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +4 -5
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/repositories/TranscriptSessionSubAgentActivityRepository.js +8 -6
- package/bin/adapter/repositories/TranscriptSessionSubAgentActivityRepository.js.map +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +1 -2
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.tsx +10 -10
- package/src/adapter/entry-points/console/ui/src/index.css +1 -0
- package/src/adapter/entry-points/console/ui-dist/assets/{index-DGVKvwux.css → index-BMe1bEF4.css} +1 -1
- package/src/adapter/entry-points/console/ui-dist/assets/{index-BXcfEKkX.js → index-Dx_VHaDe.js} +1 -1
- package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +0 -6
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +0 -7
- package/src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.test.ts +173 -98
- package/src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.ts +7 -7
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +0 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +0 -2
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
- package/types/adapter/repositories/TranscriptSessionSubAgentActivityRepository.d.ts +1 -2
- package/types/adapter/repositories/TranscriptSessionSubAgentActivityRepository.d.ts.map +1 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +0 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
9
9
|
DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
10
10
|
DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
11
|
-
DEFAULT_SUBAGENT_SILENT_CEILING_SECONDS,
|
|
12
11
|
DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
13
12
|
} from '../../../domain/usecases/NotifySilentLiveSessionsUseCase';
|
|
14
13
|
import { DefaultSilentSessionMessageComposer } from '../../../domain/usecases/DefaultSilentSessionMessageComposer';
|
|
@@ -41,7 +40,6 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
41
40
|
mainSilentThresholdSeconds: number;
|
|
42
41
|
subAgentSilentThresholdSeconds: number;
|
|
43
42
|
subAgentRunningThresholdSeconds: number;
|
|
44
|
-
subAgentSilentCeilingSeconds: number;
|
|
45
43
|
staggerSeconds: number;
|
|
46
44
|
activeHubTaskStatus: string | null;
|
|
47
45
|
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
@@ -62,7 +60,6 @@ const createSubAgentActivityRepository = (
|
|
|
62
60
|
subAgentTranscriptRootDirectory: string | null,
|
|
63
61
|
subAgentProcessMatchPattern: string | null,
|
|
64
62
|
subAgentOutputRootDirectory: string | null,
|
|
65
|
-
subAgentSilentCeilingSeconds: number,
|
|
66
63
|
localCommandRunner: LocalCommandRunner,
|
|
67
64
|
now: Date,
|
|
68
65
|
): SessionSubAgentActivityRepository => {
|
|
@@ -72,7 +69,6 @@ const createSubAgentActivityRepository = (
|
|
|
72
69
|
subAgentTranscriptRootDirectory,
|
|
73
70
|
),
|
|
74
71
|
now,
|
|
75
|
-
subAgentSilentCeilingSeconds,
|
|
76
72
|
);
|
|
77
73
|
}
|
|
78
74
|
return new ProcessListSessionSubAgentActivityRepository(
|
|
@@ -99,7 +95,6 @@ export const notifySilentTmuxSessions = async (
|
|
|
99
95
|
mainSilentThresholdSeconds,
|
|
100
96
|
subAgentSilentThresholdSeconds,
|
|
101
97
|
subAgentRunningThresholdSeconds,
|
|
102
|
-
subAgentSilentCeilingSeconds,
|
|
103
98
|
staggerSeconds,
|
|
104
99
|
activeHubTaskStatus,
|
|
105
100
|
hubTaskStatusResolver,
|
|
@@ -127,7 +122,6 @@ export const notifySilentTmuxSessions = async (
|
|
|
127
122
|
subAgentTranscriptRootDirectory,
|
|
128
123
|
subAgentProcessMatchPattern,
|
|
129
124
|
subAgentOutputRootDirectory,
|
|
130
|
-
subAgentSilentCeilingSeconds,
|
|
131
125
|
localCommandRunner,
|
|
132
126
|
now,
|
|
133
127
|
),
|
|
@@ -151,6 +145,5 @@ export const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS = {
|
|
|
151
145
|
mainSilentThresholdSeconds: DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
|
|
152
146
|
subAgentSilentThresholdSeconds: DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
|
|
153
147
|
subAgentRunningThresholdSeconds: DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
|
|
154
|
-
subAgentSilentCeilingSeconds: DEFAULT_SUBAGENT_SILENT_CEILING_SECONDS,
|
|
155
148
|
staggerSeconds: DEFAULT_NOTIFICATION_STAGGER_SECONDS,
|
|
156
149
|
} as const;
|
|
@@ -9,7 +9,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
9
9
|
let rootDirectory: string;
|
|
10
10
|
const now = new Date('2026-06-27T12:00:00.000Z');
|
|
11
11
|
const nowEpochSeconds = Math.floor(now.getTime() / 1000);
|
|
12
|
-
const noOpCeilingSeconds = 365 * 24 * 60 * 60;
|
|
13
12
|
|
|
14
13
|
beforeEach(() => {
|
|
15
14
|
rootDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'subagent-tx-'));
|
|
@@ -76,7 +75,11 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
76
75
|
{
|
|
77
76
|
type: 'assistant',
|
|
78
77
|
timestamp: startTimestamp,
|
|
79
|
-
message: {
|
|
78
|
+
message: {
|
|
79
|
+
role: 'assistant',
|
|
80
|
+
stop_reason: 'tool_use',
|
|
81
|
+
content: [{ type: 'tool_use', name: 'Bash', input: {} }],
|
|
82
|
+
},
|
|
80
83
|
},
|
|
81
84
|
];
|
|
82
85
|
|
|
@@ -149,6 +152,73 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
149
152
|
},
|
|
150
153
|
];
|
|
151
154
|
|
|
155
|
+
const toolResultTerminalEntries = (startTimestamp: string): object[] => [
|
|
156
|
+
{ type: 'user', timestamp: startTimestamp, message: { role: 'user' } },
|
|
157
|
+
{
|
|
158
|
+
type: 'assistant',
|
|
159
|
+
timestamp: startTimestamp,
|
|
160
|
+
message: {
|
|
161
|
+
role: 'assistant',
|
|
162
|
+
stop_reason: 'tool_use',
|
|
163
|
+
content: [{ type: 'tool_use', name: 'Bash', input: {} }],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 'user',
|
|
168
|
+
timestamp: startTimestamp,
|
|
169
|
+
message: {
|
|
170
|
+
role: 'user',
|
|
171
|
+
content: [{ type: 'tool_result', content: 'command output' }],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
const structuredOutputTerminalEntries = (
|
|
177
|
+
startTimestamp: string,
|
|
178
|
+
): object[] => [
|
|
179
|
+
{ type: 'user', timestamp: startTimestamp, message: { role: 'user' } },
|
|
180
|
+
{
|
|
181
|
+
type: 'assistant',
|
|
182
|
+
timestamp: startTimestamp,
|
|
183
|
+
message: {
|
|
184
|
+
role: 'assistant',
|
|
185
|
+
stop_reason: 'tool_use',
|
|
186
|
+
content: [{ type: 'tool_use', name: 'StructuredOutput', input: {} }],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'user',
|
|
191
|
+
timestamp: startTimestamp,
|
|
192
|
+
message: {
|
|
193
|
+
role: 'user',
|
|
194
|
+
content: [
|
|
195
|
+
{
|
|
196
|
+
type: 'tool_result',
|
|
197
|
+
content: 'Structured output provided successfully',
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
const emptyUserTerminalEntries = (startTimestamp: string): object[] => [
|
|
205
|
+
{ type: 'user', timestamp: startTimestamp, message: { role: 'user' } },
|
|
206
|
+
{
|
|
207
|
+
type: 'assistant',
|
|
208
|
+
timestamp: startTimestamp,
|
|
209
|
+
message: {
|
|
210
|
+
role: 'assistant',
|
|
211
|
+
stop_reason: 'tool_use',
|
|
212
|
+
content: [{ type: 'tool_use', name: 'Bash', input: {} }],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
type: 'user',
|
|
217
|
+
timestamp: startTimestamp,
|
|
218
|
+
message: { role: 'user', content: [] },
|
|
219
|
+
},
|
|
220
|
+
];
|
|
221
|
+
|
|
152
222
|
const pendingToolUseEntries = (startTimestamp: string): object[] => [
|
|
153
223
|
{ type: 'user', timestamp: startTimestamp, message: { role: 'user' } },
|
|
154
224
|
{
|
|
@@ -182,7 +252,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
182
252
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
183
253
|
createResolver(),
|
|
184
254
|
now,
|
|
185
|
-
noOpCeilingSeconds,
|
|
186
255
|
);
|
|
187
256
|
|
|
188
257
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -206,7 +275,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
206
275
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
207
276
|
createResolver(),
|
|
208
277
|
now,
|
|
209
|
-
noOpCeilingSeconds,
|
|
210
278
|
);
|
|
211
279
|
|
|
212
280
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -228,7 +296,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
228
296
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
229
297
|
createResolver(),
|
|
230
298
|
now,
|
|
231
|
-
noOpCeilingSeconds,
|
|
232
299
|
);
|
|
233
300
|
|
|
234
301
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -250,7 +317,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
250
317
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
251
318
|
createResolver(),
|
|
252
319
|
now,
|
|
253
|
-
noOpCeilingSeconds,
|
|
254
320
|
);
|
|
255
321
|
|
|
256
322
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -272,7 +338,69 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
272
338
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
273
339
|
createResolver(),
|
|
274
340
|
now,
|
|
275
|
-
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
344
|
+
[sessionName],
|
|
345
|
+
transcriptMapFor([sessionName]),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
expect(result.size).toBe(0);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('excludes a dead sub-agent whose transcript ends with an unconsumed tool result and no following assistant turn', async () => {
|
|
352
|
+
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
353
|
+
writeAgentTranscript(
|
|
354
|
+
sessionName,
|
|
355
|
+
'toolresultend',
|
|
356
|
+
toolResultTerminalEntries('2026-06-27T11:00:00.000Z'),
|
|
357
|
+
nowEpochSeconds - 600,
|
|
358
|
+
);
|
|
359
|
+
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
360
|
+
createResolver(),
|
|
361
|
+
now,
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
365
|
+
[sessionName],
|
|
366
|
+
transcriptMapFor([sessionName]),
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
expect(result.size).toBe(0);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('excludes a finished sub-agent whose transcript ends with the final StructuredOutput tool result', async () => {
|
|
373
|
+
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
374
|
+
writeAgentTranscript(
|
|
375
|
+
sessionName,
|
|
376
|
+
'structuredend',
|
|
377
|
+
structuredOutputTerminalEntries('2026-06-27T11:00:00.000Z'),
|
|
378
|
+
nowEpochSeconds - 600,
|
|
379
|
+
);
|
|
380
|
+
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
381
|
+
createResolver(),
|
|
382
|
+
now,
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
386
|
+
[sessionName],
|
|
387
|
+
transcriptMapFor([sessionName]),
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(result.size).toBe(0);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('excludes a dead sub-agent whose transcript ends with a user entry that has no content blocks', async () => {
|
|
394
|
+
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
395
|
+
writeAgentTranscript(
|
|
396
|
+
sessionName,
|
|
397
|
+
'emptyuserend',
|
|
398
|
+
emptyUserTerminalEntries('2026-06-27T11:00:00.000Z'),
|
|
399
|
+
nowEpochSeconds - 600,
|
|
400
|
+
);
|
|
401
|
+
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
402
|
+
createResolver(),
|
|
403
|
+
now,
|
|
276
404
|
);
|
|
277
405
|
|
|
278
406
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -294,7 +422,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
294
422
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
295
423
|
createResolver(),
|
|
296
424
|
now,
|
|
297
|
-
noOpCeilingSeconds,
|
|
298
425
|
);
|
|
299
426
|
|
|
300
427
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -307,6 +434,34 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
307
434
|
]);
|
|
308
435
|
});
|
|
309
436
|
|
|
437
|
+
it('flags a long-silent genuine stall whose last entry is a pending tool call regardless of how old it is', async () => {
|
|
438
|
+
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
439
|
+
const fourDaysSeconds = 4 * 24 * 60 * 60;
|
|
440
|
+
writeAgentTranscript(
|
|
441
|
+
sessionName,
|
|
442
|
+
'longstall',
|
|
443
|
+
pendingToolUseEntries('2026-06-23T12:00:00.000Z'),
|
|
444
|
+
nowEpochSeconds - fourDaysSeconds,
|
|
445
|
+
);
|
|
446
|
+
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
447
|
+
createResolver(),
|
|
448
|
+
now,
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
452
|
+
[sessionName],
|
|
453
|
+
transcriptMapFor([sessionName]),
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
expect(result.get(sessionName)).toEqual([
|
|
457
|
+
{
|
|
458
|
+
label: 'agent-longstall',
|
|
459
|
+
silentSeconds: fourDaysSeconds,
|
|
460
|
+
runningSeconds: fourDaysSeconds,
|
|
461
|
+
},
|
|
462
|
+
]);
|
|
463
|
+
});
|
|
464
|
+
|
|
310
465
|
it('follows a symlinked transcript when computing silent seconds', async () => {
|
|
311
466
|
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
312
467
|
const targetDir = fs.mkdtempSync(
|
|
@@ -326,7 +481,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
326
481
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
327
482
|
createResolver(),
|
|
328
483
|
now,
|
|
329
|
-
noOpCeilingSeconds,
|
|
330
484
|
);
|
|
331
485
|
|
|
332
486
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -344,7 +498,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
344
498
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
345
499
|
{ resolveSubAgentsDirectory: () => null },
|
|
346
500
|
now,
|
|
347
|
-
noOpCeilingSeconds,
|
|
348
501
|
);
|
|
349
502
|
|
|
350
503
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -359,7 +512,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
359
512
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
360
513
|
createResolver(),
|
|
361
514
|
now,
|
|
362
|
-
noOpCeilingSeconds,
|
|
363
515
|
);
|
|
364
516
|
|
|
365
517
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -387,7 +539,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
387
539
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
388
540
|
createResolver(),
|
|
389
541
|
now,
|
|
390
|
-
noOpCeilingSeconds,
|
|
391
542
|
);
|
|
392
543
|
|
|
393
544
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -409,7 +560,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
409
560
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
410
561
|
createResolver(),
|
|
411
562
|
now,
|
|
412
|
-
noOpCeilingSeconds,
|
|
413
563
|
);
|
|
414
564
|
|
|
415
565
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -455,7 +605,6 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
455
605
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
456
606
|
new FileSystemSubAgentTranscriptDirectoryResolver(projectsRoot),
|
|
457
607
|
now,
|
|
458
|
-
noOpCeilingSeconds,
|
|
459
608
|
);
|
|
460
609
|
|
|
461
610
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -472,102 +621,24 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
472
621
|
]);
|
|
473
622
|
});
|
|
474
623
|
|
|
475
|
-
it('
|
|
624
|
+
it('flags a marker-less stall and excludes a finished transcript in the same session regardless of their age', async () => {
|
|
476
625
|
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
477
626
|
const twoDaysSeconds = 2 * 24 * 60 * 60;
|
|
478
627
|
writeAgentTranscript(
|
|
479
628
|
sessionName,
|
|
480
|
-
'
|
|
481
|
-
|
|
629
|
+
'finishedold',
|
|
630
|
+
finishedEntries('2026-06-25T12:00:00.000Z'),
|
|
482
631
|
nowEpochSeconds - twoDaysSeconds,
|
|
483
632
|
);
|
|
484
|
-
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
485
|
-
createResolver(),
|
|
486
|
-
now,
|
|
487
|
-
60 * 60,
|
|
488
|
-
);
|
|
489
|
-
|
|
490
|
-
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
491
|
-
[sessionName],
|
|
492
|
-
transcriptMapFor([sessionName]),
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
expect(result.size).toBe(0);
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
it('keeps a recently-silent sub-agent whose transcript is within the ceiling', async () => {
|
|
499
|
-
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
500
|
-
writeAgentTranscript(
|
|
501
|
-
sessionName,
|
|
502
|
-
'aliveone',
|
|
503
|
-
runningEntries('2026-06-27T11:45:00.000Z'),
|
|
504
|
-
nowEpochSeconds - 360,
|
|
505
|
-
);
|
|
506
|
-
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
507
|
-
createResolver(),
|
|
508
|
-
now,
|
|
509
|
-
60 * 60,
|
|
510
|
-
);
|
|
511
|
-
|
|
512
|
-
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
513
|
-
[sessionName],
|
|
514
|
-
transcriptMapFor([sessionName]),
|
|
515
|
-
);
|
|
516
|
-
|
|
517
|
-
expect(result.get(sessionName)).toEqual([
|
|
518
|
-
{ label: 'agent-aliveone', silentSeconds: 360, runningSeconds: 900 },
|
|
519
|
-
]);
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
it('keeps a sub-agent silent exactly at the ceiling and excludes one past it', async () => {
|
|
523
|
-
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
524
|
-
writeAgentTranscript(
|
|
525
|
-
sessionName,
|
|
526
|
-
'atceiling',
|
|
527
|
-
runningEntries('2026-06-27T11:00:00.000Z'),
|
|
528
|
-
nowEpochSeconds - 3600,
|
|
529
|
-
);
|
|
530
633
|
writeAgentTranscript(
|
|
531
634
|
sessionName,
|
|
532
|
-
'
|
|
533
|
-
|
|
534
|
-
nowEpochSeconds - 3601,
|
|
535
|
-
);
|
|
536
|
-
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
537
|
-
createResolver(),
|
|
538
|
-
now,
|
|
539
|
-
3600,
|
|
540
|
-
);
|
|
541
|
-
|
|
542
|
-
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
543
|
-
[sessionName],
|
|
544
|
-
transcriptMapFor([sessionName]),
|
|
545
|
-
);
|
|
546
|
-
|
|
547
|
-
expect(result.get(sessionName)).toEqual([
|
|
548
|
-
{ label: 'agent-atceiling', silentSeconds: 3600, runningSeconds: 3600 },
|
|
549
|
-
]);
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
it('flags only the recently-silent sub-agent when a session holds both a dead and an alive transcript', async () => {
|
|
553
|
-
const sessionName = 'https_//github_com/owner/repo/issues/9';
|
|
554
|
-
const twoDaysSeconds = 2 * 24 * 60 * 60;
|
|
555
|
-
writeAgentTranscript(
|
|
556
|
-
sessionName,
|
|
557
|
-
'deadtwo',
|
|
558
|
-
runningEntries('2026-06-25T11:00:00.000Z'),
|
|
635
|
+
'stalledold',
|
|
636
|
+
pendingToolUseEntries('2026-06-25T12:00:00.000Z'),
|
|
559
637
|
nowEpochSeconds - twoDaysSeconds,
|
|
560
638
|
);
|
|
561
|
-
writeAgentTranscript(
|
|
562
|
-
sessionName,
|
|
563
|
-
'alivetwo',
|
|
564
|
-
runningEntries('2026-06-27T11:45:00.000Z'),
|
|
565
|
-
nowEpochSeconds - 400,
|
|
566
|
-
);
|
|
567
639
|
const repository = new TranscriptSessionSubAgentActivityRepository(
|
|
568
640
|
createResolver(),
|
|
569
641
|
now,
|
|
570
|
-
60 * 60,
|
|
571
642
|
);
|
|
572
643
|
|
|
573
644
|
const result = await repository.listSubAgentActivitiesBySessionName(
|
|
@@ -576,7 +647,11 @@ describe('TranscriptSessionSubAgentActivityRepository', () => {
|
|
|
576
647
|
);
|
|
577
648
|
|
|
578
649
|
expect(result.get(sessionName)).toEqual([
|
|
579
|
-
{
|
|
650
|
+
{
|
|
651
|
+
label: 'agent-stalledold',
|
|
652
|
+
silentSeconds: twoDaysSeconds,
|
|
653
|
+
runningSeconds: twoDaysSeconds,
|
|
654
|
+
},
|
|
580
655
|
]);
|
|
581
656
|
});
|
|
582
657
|
});
|
|
@@ -54,9 +54,13 @@ const entryIndicatesCompletion = (entry: Record<string, unknown>): boolean => {
|
|
|
54
54
|
return lastBlock !== undefined && readString(lastBlock, 'type') === 'text';
|
|
55
55
|
}
|
|
56
56
|
if (type === 'user') {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
const blocks = readContentBlocks(message);
|
|
58
|
+
if (blocks.length === 0) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
62
|
+
const lastBlockType = readString(lastBlock, 'type');
|
|
63
|
+
return lastBlockType === 'text' || lastBlockType === 'tool_result';
|
|
60
64
|
}
|
|
61
65
|
return false;
|
|
62
66
|
};
|
|
@@ -95,7 +99,6 @@ export class TranscriptSessionSubAgentActivityRepository implements SessionSubAg
|
|
|
95
99
|
constructor(
|
|
96
100
|
private readonly directoryResolver: SubAgentTranscriptDirectoryResolver,
|
|
97
101
|
private readonly now: Date,
|
|
98
|
-
private readonly silentCeilingSeconds: number,
|
|
99
102
|
) {}
|
|
100
103
|
|
|
101
104
|
listSubAgentActivitiesBySessionName = async (
|
|
@@ -167,9 +170,6 @@ export class TranscriptSessionSubAgentActivityRepository implements SessionSubAg
|
|
|
167
170
|
const silentSeconds = clampToZero(
|
|
168
171
|
nowEpochSeconds - Math.floor(stats.mtimeMs / 1000),
|
|
169
172
|
);
|
|
170
|
-
if (silentSeconds > this.silentCeilingSeconds) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
173
|
const runningSeconds =
|
|
174
174
|
transcript.firstEntryEpochSeconds === null
|
|
175
175
|
? 0
|
|
@@ -14,7 +14,6 @@ import { ResolveInteractiveLiveSessionsUseCase } from './ResolveInteractiveLiveS
|
|
|
14
14
|
export const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS = 10 * 60;
|
|
15
15
|
export const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS = 5 * 60;
|
|
16
16
|
export const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS = 15 * 60;
|
|
17
|
-
export const DEFAULT_SUBAGENT_SILENT_CEILING_SECONDS = 60 * 60;
|
|
18
17
|
export const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
19
18
|
|
|
20
19
|
const GITHUB_ISSUE_OR_PULL_URL_PATTERN =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAiD3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAiD3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,KAAK,EAAE,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,IAAI,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC,CAmiBP;CACH"}
|
|
@@ -13,7 +13,6 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
13
13
|
mainSilentThresholdSeconds: number;
|
|
14
14
|
subAgentSilentThresholdSeconds: number;
|
|
15
15
|
subAgentRunningThresholdSeconds: number;
|
|
16
|
-
subAgentSilentCeilingSeconds: number;
|
|
17
16
|
staggerSeconds: number;
|
|
18
17
|
activeHubTaskStatus: string | null;
|
|
19
18
|
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
@@ -25,7 +24,6 @@ export declare const DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS: {
|
|
|
25
24
|
readonly mainSilentThresholdSeconds: number;
|
|
26
25
|
readonly subAgentSilentThresholdSeconds: number;
|
|
27
26
|
readonly subAgentRunningThresholdSeconds: number;
|
|
28
|
-
readonly subAgentSilentCeilingSeconds: number;
|
|
29
27
|
readonly staggerSeconds: 25;
|
|
30
28
|
};
|
|
31
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;AACxG,OAAO,EAEL,qBAAqB,
|
|
1
|
+
{"version":3,"file":"notifySilentTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAGpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAEL,qBAAqB,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"}
|
|
@@ -4,8 +4,7 @@ import { SubAgentTranscriptDirectoryResolver } from '../../domain/usecases/adapt
|
|
|
4
4
|
export declare class TranscriptSessionSubAgentActivityRepository implements SessionSubAgentActivityRepository {
|
|
5
5
|
private readonly directoryResolver;
|
|
6
6
|
private readonly now;
|
|
7
|
-
|
|
8
|
-
constructor(directoryResolver: SubAgentTranscriptDirectoryResolver, now: Date, silentCeilingSeconds: number);
|
|
7
|
+
constructor(directoryResolver: SubAgentTranscriptDirectoryResolver, now: Date);
|
|
9
8
|
listSubAgentActivitiesBySessionName: (sessionNames: string[], transcriptPathBySessionName: Map<string, string>) => Promise<Map<string, SubAgentActivity[]>>;
|
|
10
9
|
private collectActivities;
|
|
11
10
|
private toActivity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranscriptSessionSubAgentActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AACrF,OAAO,EAAE,iCAAiC,EAAE,MAAM,4EAA4E,CAAC;AAC/H,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;
|
|
1
|
+
{"version":3,"file":"TranscriptSessionSubAgentActivityRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TranscriptSessionSubAgentActivityRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AACrF,OAAO,EAAE,iCAAiC,EAAE,MAAM,4EAA4E,CAAC;AAC/H,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;AA6FnI,qBAAa,2CAA4C,YAAW,iCAAiC;IAEjG,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,iBAAiB,EAAE,mCAAmC,EACtD,GAAG,EAAE,IAAI;IAG5B,mCAAmC,GACjC,cAAc,MAAM,EAAE,EACtB,6BAA6B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAmBzC;IAEF,OAAO,CAAC,iBAAiB,CAuBvB;IAEF,OAAO,CAAC,UAAU,CA6BhB;CACH"}
|
|
@@ -10,7 +10,6 @@ import { IssueRepository } from './adapter-interfaces/IssueRepository';
|
|
|
10
10
|
export declare const DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS: number;
|
|
11
11
|
export declare const DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS: number;
|
|
12
12
|
export declare const DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS: number;
|
|
13
|
-
export declare const DEFAULT_SUBAGENT_SILENT_CEILING_SECONDS: number;
|
|
14
13
|
export declare const DEFAULT_NOTIFICATION_STAGGER_SECONDS = 25;
|
|
15
14
|
export declare const parseHubTaskIssueUrlFromSessionName: (sessionName: string) => string | null;
|
|
16
15
|
export declare const isGitHubIssueOrPullRequestSessionName: (sessionName: string) => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifySilentLiveSessionsUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifySilentLiveSessionsUseCase.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yDAAyD,CAAC;AAC7G,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,iCAAiC,EAAE,MAAM,wDAAwD,CAAC;AAC3G,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,mCAAmC,EAAE,MAAM,0DAA0D,CAAC;AAC/G,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvE,eAAO,MAAM,qCAAqC,QAAU,CAAC;AAC7D,eAAO,MAAM,yCAAyC,QAAS,CAAC;AAChE,eAAO,MAAM,0CAA0C,QAAU,CAAC;AAClE,eAAO,MAAM,
|
|
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;AAQvD,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,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,CAiEf;IAEF,OAAO,CAAC,eAAe,CAmCrB;IAEF,OAAO,CAAC,gBAAgB,CA+CtB;IAEF,OAAO,CAAC,cAAc,CAqCpB;CACH"}
|