github-issue-tower-defence-management 1.140.2 → 1.142.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 +20 -0
- package/README.md +13 -6
- package/bin/adapter/entry-points/console/dashboardComposeService.js +23 -4
- package/bin/adapter/entry-points/console/dashboardComposeService.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +43 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.js +32 -0
- package/bin/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.js.map +1 -0
- package/bin/adapter/entry-points/handlers/tokenStatusWriter.js +1 -0
- package/bin/adapter/entry-points/handlers/tokenStatusWriter.js.map +1 -1
- package/bin/adapter/repositories/FileSystemSessionAssistantTurnsRepository.js +135 -0
- package/bin/adapter/repositories/FileSystemSessionAssistantTurnsRepository.js.map +1 -0
- package/bin/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.js +120 -0
- package/bin/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.js.map +1 -0
- package/bin/adapter/repositories/FileSystemSubAgentLivenessResolver.js +3 -3
- package/bin/adapter/repositories/FileSystemSubAgentLivenessResolver.js.map +1 -1
- package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js +23 -9
- package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js.map +1 -1
- package/bin/domain/entities/OutputDegeneration.js +3 -0
- package/bin/domain/entities/OutputDegeneration.js.map +1 -0
- package/bin/domain/usecases/OutputDegenerationDetector.js +150 -0
- package/bin/domain/usecases/OutputDegenerationDetector.js.map +1 -0
- package/bin/domain/usecases/SessionOutputDegenerationRecoveryUseCase.js +84 -0
- package/bin/domain/usecases/SessionOutputDegenerationRecoveryUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.js.map +1 -0
- package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js +41 -5
- package/bin/domain/usecases/dashboard/ComposeDashboardUseCase.js.map +1 -1
- package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js +16 -1
- package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/console/dashboardComposeService.test.ts +82 -0
- package/src/adapter/entry-points/console/dashboardComposeService.ts +38 -4
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +44 -0
- package/src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.test.ts +69 -0
- package/src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.ts +71 -0
- package/src/adapter/entry-points/handlers/tokenStatusWriter.test.ts +6 -0
- package/src/adapter/entry-points/handlers/tokenStatusWriter.ts +4 -0
- package/src/adapter/repositories/FileSystemSessionAssistantTurnsRepository.test.ts +138 -0
- package/src/adapter/repositories/FileSystemSessionAssistantTurnsRepository.ts +113 -0
- package/src/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.test.ts +85 -0
- package/src/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.ts +105 -0
- package/src/adapter/repositories/FileSystemSubAgentLivenessResolver.test.ts +94 -0
- package/src/adapter/repositories/FileSystemSubAgentLivenessResolver.ts +3 -3
- package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.test.ts +368 -1
- package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts +28 -10
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +31 -0
- package/src/domain/entities/OutputDegeneration.ts +10 -0
- package/src/domain/usecases/OutputDegenerationDetector.test.ts +167 -0
- package/src/domain/usecases/OutputDegenerationDetector.ts +169 -0
- package/src/domain/usecases/SessionOutputDegenerationRecoveryUseCase.test.ts +224 -0
- package/src/domain/usecases/SessionOutputDegenerationRecoveryUseCase.ts +142 -0
- package/src/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.ts +6 -0
- package/src/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.ts +4 -0
- package/src/domain/usecases/dashboard/ComposeDashboardUseCase.test.ts +164 -0
- package/src/domain/usecases/dashboard/ComposeDashboardUseCase.ts +63 -5
- package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.test.ts +73 -0
- package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts +23 -0
- package/types/adapter/entry-points/console/dashboardComposeService.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.d.ts +19 -0
- package/types/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts +2 -1
- package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts.map +1 -1
- package/types/adapter/repositories/FileSystemSessionAssistantTurnsRepository.d.ts +10 -0
- package/types/adapter/repositories/FileSystemSessionAssistantTurnsRepository.d.ts.map +1 -0
- package/types/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.d.ts +15 -0
- package/types/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.d.ts.map +1 -0
- package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts +2 -1
- package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts.map +1 -1
- package/types/domain/entities/OutputDegeneration.d.ts +10 -0
- package/types/domain/entities/OutputDegeneration.d.ts.map +1 -0
- package/types/domain/usecases/OutputDegenerationDetector.d.ts +32 -0
- package/types/domain/usecases/OutputDegenerationDetector.d.ts.map +1 -0
- package/types/domain/usecases/SessionOutputDegenerationRecoveryUseCase.d.ts +31 -0
- package/types/domain/usecases/SessionOutputDegenerationRecoveryUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.d.ts +4 -0
- package/types/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.d.ts +8 -0
- package/types/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.d.ts.map +1 -0
- package/types/domain/usecases/dashboard/ComposeDashboardUseCase.d.ts +3 -1
- package/types/domain/usecases/dashboard/ComposeDashboardUseCase.d.ts.map +1 -1
- package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts +6 -0
- package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts.map +1 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
formatProjectHeaderLine,
|
|
7
7
|
formatProjectRowLine,
|
|
8
8
|
formatResetCountdown,
|
|
9
|
+
formatSevenDayWindowAggregateLine,
|
|
9
10
|
formatTokenRowLine,
|
|
10
11
|
roundHalfToEven,
|
|
11
12
|
} from './ComposeDashboardUseCase';
|
|
@@ -485,3 +486,166 @@ describe('ComposeDashboardUseCase', () => {
|
|
|
485
486
|
}
|
|
486
487
|
});
|
|
487
488
|
});
|
|
489
|
+
|
|
490
|
+
describe('formatSevenDayWindowAggregateLine', () => {
|
|
491
|
+
const columnEnd = (line: string, field: string): number =>
|
|
492
|
+
codePointLength(line.slice(0, line.indexOf(field) + field.length));
|
|
493
|
+
|
|
494
|
+
it('renders only the remaining percentage, without a count when every token is included', () => {
|
|
495
|
+
expect(
|
|
496
|
+
formatSevenDayWindowAggregateLine({
|
|
497
|
+
usedPercent: 63,
|
|
498
|
+
includedTokenCount: 10,
|
|
499
|
+
totalTokenCount: 10,
|
|
500
|
+
}),
|
|
501
|
+
).toBe('7d 37%');
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('aligns the remaining percentage under the seven day column of the token rows', () => {
|
|
505
|
+
const tokenRow = formatTokenRowLine(
|
|
506
|
+
tokenStatus({
|
|
507
|
+
name: 'dev4',
|
|
508
|
+
color: 'K',
|
|
509
|
+
fiveHourUtilizationPercent: 0,
|
|
510
|
+
fiveHourResetSeconds: 60,
|
|
511
|
+
sevenDayUtilizationPercent: 100,
|
|
512
|
+
sevenDayResetSeconds: 96060,
|
|
513
|
+
}),
|
|
514
|
+
);
|
|
515
|
+
const aggregateLine = formatSevenDayWindowAggregateLine({
|
|
516
|
+
usedPercent: 63.36,
|
|
517
|
+
includedTokenCount: 11,
|
|
518
|
+
totalTokenCount: 11,
|
|
519
|
+
});
|
|
520
|
+
expect(tokenRow).toBe('⚪dev4 0% 0d00h01 100% 1d02h41 0 0');
|
|
521
|
+
expect(aggregateLine).toBe('7d 37%');
|
|
522
|
+
expect(columnEnd(aggregateLine ?? '', '37%')).toBe(
|
|
523
|
+
columnEnd(tokenRow, '100%'),
|
|
524
|
+
);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('keeps the alignment when the remaining percentage needs fewer digits', () => {
|
|
528
|
+
const wide = formatSevenDayWindowAggregateLine({
|
|
529
|
+
usedPercent: 0,
|
|
530
|
+
includedTokenCount: 1,
|
|
531
|
+
totalTokenCount: 1,
|
|
532
|
+
});
|
|
533
|
+
const narrow = formatSevenDayWindowAggregateLine({
|
|
534
|
+
usedPercent: 95,
|
|
535
|
+
includedTokenCount: 1,
|
|
536
|
+
totalTokenCount: 1,
|
|
537
|
+
});
|
|
538
|
+
expect(wide).toBe('7d 100%');
|
|
539
|
+
expect(narrow).toBe('7d 5%');
|
|
540
|
+
expect(codePointLength(wide ?? '')).toBe(codePointLength(narrow ?? ''));
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it('appends the included token count when some tokens have no value', () => {
|
|
544
|
+
expect(
|
|
545
|
+
formatSevenDayWindowAggregateLine({
|
|
546
|
+
usedPercent: 63,
|
|
547
|
+
includedTokenCount: 9,
|
|
548
|
+
totalTokenCount: 10,
|
|
549
|
+
}),
|
|
550
|
+
).toBe('7d 37% (9)');
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it('rounds the remaining percentage with half-to-even before rendering', () => {
|
|
554
|
+
expect(
|
|
555
|
+
formatSevenDayWindowAggregateLine({
|
|
556
|
+
usedPercent: 62.5,
|
|
557
|
+
includedTokenCount: 2,
|
|
558
|
+
totalTokenCount: 2,
|
|
559
|
+
}),
|
|
560
|
+
).toBe('7d 38%');
|
|
561
|
+
expect(
|
|
562
|
+
formatSevenDayWindowAggregateLine({
|
|
563
|
+
usedPercent: 63.5,
|
|
564
|
+
includedTokenCount: 2,
|
|
565
|
+
totalTokenCount: 2,
|
|
566
|
+
}),
|
|
567
|
+
).toBe('7d 36%');
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it('renders nothing when the aggregate is absent', () => {
|
|
571
|
+
expect(formatSevenDayWindowAggregateLine(null)).toBeNull();
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('fits the width budget at the widest rendering', () => {
|
|
575
|
+
const line = formatSevenDayWindowAggregateLine({
|
|
576
|
+
usedPercent: 0,
|
|
577
|
+
includedTokenCount: 999,
|
|
578
|
+
totalTokenCount: 1000,
|
|
579
|
+
});
|
|
580
|
+
expect(line).toBe('7d 100% (999)');
|
|
581
|
+
expect(codePointLength(line ?? '')).toBeLessThanOrEqual(
|
|
582
|
+
PROJECT_ROW_WIDTH_BUDGET,
|
|
583
|
+
);
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
describe('ComposeDashboardUseCase seven day window aggregate line', () => {
|
|
588
|
+
const aggregateInput = (
|
|
589
|
+
sevenDayWindowAggregate: ComposeDashboardInput['sevenDayWindowAggregate'],
|
|
590
|
+
): ComposeDashboardInput => ({
|
|
591
|
+
machineStatus: null,
|
|
592
|
+
projects: [{ code: 'um', row: projectRow({ unread: 1 }) }],
|
|
593
|
+
tokens: [
|
|
594
|
+
tokenStatus({ name: 'alice', sevenDayUtilizationPercent: 60 }),
|
|
595
|
+
tokenStatus({ name: 'bob', sevenDayUtilizationPercent: 66 }),
|
|
596
|
+
],
|
|
597
|
+
sevenDayWindowAggregate,
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
const unwrappedLines = (output: string): string[] =>
|
|
601
|
+
output
|
|
602
|
+
.split('\n')
|
|
603
|
+
.filter((line) => line.length > 0)
|
|
604
|
+
.map((line) =>
|
|
605
|
+
line
|
|
606
|
+
.replace(/^<tt>/, '')
|
|
607
|
+
.replace(/<\/tt><br>$/, '')
|
|
608
|
+
.replace(/ /g, ' '),
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
it('places the aggregate line immediately above the token rows', () => {
|
|
612
|
+
const lines = unwrappedLines(
|
|
613
|
+
new ComposeDashboardUseCase().run(
|
|
614
|
+
aggregateInput({
|
|
615
|
+
usedPercent: 63,
|
|
616
|
+
includedTokenCount: 2,
|
|
617
|
+
totalTokenCount: 2,
|
|
618
|
+
}),
|
|
619
|
+
),
|
|
620
|
+
);
|
|
621
|
+
const aggregateIndex = lines.indexOf('7d 37%');
|
|
622
|
+
expect(aggregateIndex).toBeGreaterThan(-1);
|
|
623
|
+
expect(lines[aggregateIndex - 1]).toBe(
|
|
624
|
+
formatProjectRowLine({
|
|
625
|
+
code: 'um',
|
|
626
|
+
row: projectRow({ unread: 1 }),
|
|
627
|
+
}),
|
|
628
|
+
);
|
|
629
|
+
expect(lines[aggregateIndex + 1]).toContain('alice');
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it('keeps the blank separator line when the aggregate is absent', () => {
|
|
633
|
+
const lines = unwrappedLines(
|
|
634
|
+
new ComposeDashboardUseCase().run(aggregateInput(null)),
|
|
635
|
+
);
|
|
636
|
+
expect(lines.some((line) => line.startsWith('7d '))).toBe(false);
|
|
637
|
+
expect(lines).toContain('');
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it('keeps the blank separator line when the aggregate field is missing entirely', () => {
|
|
641
|
+
const lines = unwrappedLines(
|
|
642
|
+
new ComposeDashboardUseCase().run({
|
|
643
|
+
machineStatus: null,
|
|
644
|
+
projects: [],
|
|
645
|
+
tokens: [tokenStatus({ name: 'alice' })],
|
|
646
|
+
}),
|
|
647
|
+
);
|
|
648
|
+
expect(lines.some((line) => line.startsWith('7d '))).toBe(false);
|
|
649
|
+
expect(lines).toContain('');
|
|
650
|
+
});
|
|
651
|
+
});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { DashboardRow } from './GenerateDashboardRowUseCase';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SevenDayWindowAggregate,
|
|
4
|
+
TokenStatus,
|
|
5
|
+
TokenStatusColor,
|
|
6
|
+
} from './GenerateTokenStatusUseCase';
|
|
3
7
|
|
|
4
8
|
export const PROJECT_ROW_WIDTH_BUDGET = 32;
|
|
5
9
|
|
|
@@ -26,6 +30,7 @@ export type ComposeDashboardInput = {
|
|
|
26
30
|
projects: ComposeDashboardProject[];
|
|
27
31
|
machineStatus: ComposeDashboardMachineStatus | null;
|
|
28
32
|
tokens: TokenStatus[];
|
|
33
|
+
sevenDayWindowAggregate?: SevenDayWindowAggregate | null;
|
|
29
34
|
};
|
|
30
35
|
|
|
31
36
|
type ProjectColumn = {
|
|
@@ -47,6 +52,14 @@ const PROJECT_COLUMN_WIDTH = 3;
|
|
|
47
52
|
|
|
48
53
|
const SEVERITY_BLANK = ' ';
|
|
49
54
|
|
|
55
|
+
const TOKEN_COLOR_DOT_WIDTH = 1;
|
|
56
|
+
|
|
57
|
+
const TOKEN_NAME_WIDTH = 4;
|
|
58
|
+
|
|
59
|
+
const TOKEN_UTILIZATION_WIDTH = 4;
|
|
60
|
+
|
|
61
|
+
const TOKEN_RESET_WIDTH = 7;
|
|
62
|
+
|
|
50
63
|
const TOKEN_COLOR_DOT: Record<TokenStatusColor, string> = {
|
|
51
64
|
G: '🟢',
|
|
52
65
|
Y: '🟡',
|
|
@@ -196,7 +209,7 @@ export const formatProjectRowLine = (
|
|
|
196
209
|
};
|
|
197
210
|
|
|
198
211
|
const formatUtilization = (percent: number | null): string =>
|
|
199
|
-
padStart(percent === null ? '?' : `${percent}%`,
|
|
212
|
+
padStart(percent === null ? '?' : `${percent}%`, TOKEN_UTILIZATION_WIDTH);
|
|
200
213
|
|
|
201
214
|
const formatReset = (resetSeconds: number | null): string =>
|
|
202
215
|
resetSeconds === null ? '?' : formatResetCountdown(resetSeconds);
|
|
@@ -222,9 +235,38 @@ const sortTokens = (tokens: TokenStatus[]): TokenStatus[] =>
|
|
|
222
235
|
})
|
|
223
236
|
.map((entry) => entry.token);
|
|
224
237
|
|
|
238
|
+
const joinTokenRowSegments = (segments: string[]): string => segments.join(' ');
|
|
239
|
+
|
|
240
|
+
const SEVEN_DAY_WINDOW_AGGREGATE_LABEL = '7d';
|
|
241
|
+
|
|
242
|
+
export const formatSevenDayWindowAggregateLine = (
|
|
243
|
+
aggregate: SevenDayWindowAggregate | null,
|
|
244
|
+
): string | null => {
|
|
245
|
+
if (aggregate === null) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const leftPercent = roundHalfToEven(100 - aggregate.usedPercent);
|
|
249
|
+
const includedCountSuffix =
|
|
250
|
+
aggregate.includedTokenCount === aggregate.totalTokenCount
|
|
251
|
+
? ''
|
|
252
|
+
: ` (${aggregate.includedTokenCount})`;
|
|
253
|
+
return (
|
|
254
|
+
joinTokenRowSegments([
|
|
255
|
+
padEnd(
|
|
256
|
+
SEVEN_DAY_WINDOW_AGGREGATE_LABEL,
|
|
257
|
+
TOKEN_COLOR_DOT_WIDTH + TOKEN_NAME_WIDTH,
|
|
258
|
+
' ',
|
|
259
|
+
),
|
|
260
|
+
padEnd('', TOKEN_UTILIZATION_WIDTH, ' '),
|
|
261
|
+
padEnd('', TOKEN_RESET_WIDTH, ' '),
|
|
262
|
+
formatUtilization(leftPercent),
|
|
263
|
+
]) + includedCountSuffix
|
|
264
|
+
);
|
|
265
|
+
};
|
|
266
|
+
|
|
225
267
|
export const formatTokenRowLine = (token: TokenStatus): string => {
|
|
226
268
|
const dot = TOKEN_COLOR_DOT[token.color];
|
|
227
|
-
const name = padEnd(token.name,
|
|
269
|
+
const name = padEnd(token.name, TOKEN_NAME_WIDTH, '_');
|
|
228
270
|
const fiveHourUtilization = formatUtilization(
|
|
229
271
|
token.fiveHourUtilizationPercent,
|
|
230
272
|
);
|
|
@@ -235,7 +277,15 @@ export const formatTokenRowLine = (token: TokenStatus): string => {
|
|
|
235
277
|
const sevenDayReset = formatReset(token.sevenDayResetSeconds);
|
|
236
278
|
const prep = String(token.prep);
|
|
237
279
|
const hum = String(token.hum);
|
|
238
|
-
return
|
|
280
|
+
return joinTokenRowSegments([
|
|
281
|
+
`${dot}${name}`,
|
|
282
|
+
fiveHourUtilization,
|
|
283
|
+
fiveHourReset,
|
|
284
|
+
sevenDayUtilization,
|
|
285
|
+
sevenDayReset,
|
|
286
|
+
prep,
|
|
287
|
+
hum,
|
|
288
|
+
]);
|
|
239
289
|
};
|
|
240
290
|
|
|
241
291
|
const wrapLine = (line: string): string =>
|
|
@@ -251,7 +301,15 @@ export class ComposeDashboardUseCase {
|
|
|
251
301
|
const tokenLines = sortTokens(input.tokens).map((token) =>
|
|
252
302
|
formatTokenRowLine(token),
|
|
253
303
|
);
|
|
254
|
-
const
|
|
304
|
+
const aggregateLine = formatSevenDayWindowAggregateLine(
|
|
305
|
+
input.sevenDayWindowAggregate ?? null,
|
|
306
|
+
);
|
|
307
|
+
const lines = [
|
|
308
|
+
...statsLines,
|
|
309
|
+
...projectLines,
|
|
310
|
+
aggregateLine === null ? '' : aggregateLine,
|
|
311
|
+
...tokenLines,
|
|
312
|
+
];
|
|
255
313
|
return lines.map((line) => wrapLine(line)).join('\n') + '\n';
|
|
256
314
|
};
|
|
257
315
|
}
|
|
@@ -2,6 +2,8 @@ import {
|
|
|
2
2
|
GenerateTokenStatusUseCase,
|
|
3
3
|
TokenRateLimitDecision,
|
|
4
4
|
TokenRateLimitSnapshot,
|
|
5
|
+
TokenStatus,
|
|
6
|
+
computeSevenDayWindowAggregate,
|
|
5
7
|
judgeTokenColor,
|
|
6
8
|
} from './GenerateTokenStatusUseCase';
|
|
7
9
|
|
|
@@ -207,3 +209,74 @@ describe('GenerateTokenStatusUseCase', () => {
|
|
|
207
209
|
expect(result[0].color).toBe('G');
|
|
208
210
|
});
|
|
209
211
|
});
|
|
212
|
+
|
|
213
|
+
describe('computeSevenDayWindowAggregate', () => {
|
|
214
|
+
const tokenStatus = (
|
|
215
|
+
sevenDayUtilizationPercent: number | null,
|
|
216
|
+
name: string,
|
|
217
|
+
): TokenStatus => ({
|
|
218
|
+
name,
|
|
219
|
+
fiveHourUtilizationPercent: null,
|
|
220
|
+
fiveHourResetSeconds: null,
|
|
221
|
+
sevenDayUtilizationPercent,
|
|
222
|
+
sevenDayResetSeconds: null,
|
|
223
|
+
color: 'G',
|
|
224
|
+
prep: 0,
|
|
225
|
+
hum: 0,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('averages the seven day utilization of every token when all values are present', () => {
|
|
229
|
+
expect(
|
|
230
|
+
computeSevenDayWindowAggregate([
|
|
231
|
+
tokenStatus(60, 'alice'),
|
|
232
|
+
tokenStatus(64, 'bob'),
|
|
233
|
+
tokenStatus(65, 'carol'),
|
|
234
|
+
]),
|
|
235
|
+
).toEqual({
|
|
236
|
+
usedPercent: 63,
|
|
237
|
+
includedTokenCount: 3,
|
|
238
|
+
totalTokenCount: 3,
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('excludes tokens without a value from both numerator and denominator', () => {
|
|
243
|
+
expect(
|
|
244
|
+
computeSevenDayWindowAggregate([
|
|
245
|
+
tokenStatus(80, 'alice'),
|
|
246
|
+
tokenStatus(null, 'bob'),
|
|
247
|
+
tokenStatus(40, 'carol'),
|
|
248
|
+
tokenStatus(null, 'dave'),
|
|
249
|
+
]),
|
|
250
|
+
).toEqual({
|
|
251
|
+
usedPercent: 60,
|
|
252
|
+
includedTokenCount: 2,
|
|
253
|
+
totalTokenCount: 4,
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('keeps the fractional mean so the presentation layer decides the rounding', () => {
|
|
258
|
+
expect(
|
|
259
|
+
computeSevenDayWindowAggregate([
|
|
260
|
+
tokenStatus(63, 'alice'),
|
|
261
|
+
tokenStatus(64, 'bob'),
|
|
262
|
+
]),
|
|
263
|
+
).toEqual({
|
|
264
|
+
usedPercent: 63.5,
|
|
265
|
+
includedTokenCount: 2,
|
|
266
|
+
totalTokenCount: 2,
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('returns null when no token has a seven day utilization value', () => {
|
|
271
|
+
expect(
|
|
272
|
+
computeSevenDayWindowAggregate([
|
|
273
|
+
tokenStatus(null, 'alice'),
|
|
274
|
+
tokenStatus(null, 'bob'),
|
|
275
|
+
]),
|
|
276
|
+
).toBeNull();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('returns null when there is no token at all', () => {
|
|
280
|
+
expect(computeSevenDayWindowAggregate([])).toBeNull();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -37,6 +37,12 @@ export type TokenStatus = {
|
|
|
37
37
|
hum: number;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
export type SevenDayWindowAggregate = {
|
|
41
|
+
usedPercent: number;
|
|
42
|
+
includedTokenCount: number;
|
|
43
|
+
totalTokenCount: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
40
46
|
export type TokenStatusInput = {
|
|
41
47
|
name: string;
|
|
42
48
|
token: string;
|
|
@@ -86,6 +92,23 @@ export const judgeTokenColor = (
|
|
|
86
92
|
return 'G';
|
|
87
93
|
};
|
|
88
94
|
|
|
95
|
+
export const computeSevenDayWindowAggregate = (
|
|
96
|
+
tokens: TokenStatus[],
|
|
97
|
+
): SevenDayWindowAggregate | null => {
|
|
98
|
+
const utilizations = tokens
|
|
99
|
+
.map((token) => token.sevenDayUtilizationPercent)
|
|
100
|
+
.filter((percent): percent is number => percent !== null);
|
|
101
|
+
if (utilizations.length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const total = utilizations.reduce((sum, percent) => sum + percent, 0);
|
|
105
|
+
return {
|
|
106
|
+
usedPercent: total / utilizations.length,
|
|
107
|
+
includedTokenCount: utilizations.length,
|
|
108
|
+
totalTokenCount: tokens.length,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
|
|
89
112
|
export class GenerateTokenStatusUseCase {
|
|
90
113
|
run = (input: GenerateTokenStatusInput): TokenStatus[] => {
|
|
91
114
|
const { tokens, prepCountByToken, humCountByToken, nowEpochSeconds } =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboardComposeService.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/dashboardComposeService.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,qBAAqB,EAItB,MAAM,4DAA4D,CAAC;
|
|
1
|
+
{"version":3,"file":"dashboardComposeService.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/dashboardComposeService.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,qBAAqB,EAItB,MAAM,4DAA4D,CAAC;AASpE,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAgMF,eAAO,MAAM,0BAA0B,GACrC,SAAS,uBAAuB,KAC/B,qBAcF,CAAC;AAUF,eAAO,MAAM,4BAA4B,GACvC,SAAS,uBAAuB,KAC/B,OAYF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,uBAAuB,KAC/B,MACqE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAyCA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAkD3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,EACjB,6BAA4B,MAAM,EAAE,GAAG,IAAW,KACjD,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,CA8qBP;CACH"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
2
|
+
import { ProcessEnvironReader } from '../../../domain/usecases/adapter-interfaces/ProcessEnvironReader';
|
|
3
|
+
export type ResetDegeneratedTmuxSessionsParams = {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
localCommandRunner: LocalCommandRunner;
|
|
6
|
+
processEnvironReader?: ProcessEnvironReader;
|
|
7
|
+
warningMessage: string;
|
|
8
|
+
graceSeconds: number;
|
|
9
|
+
cooldownSeconds: number;
|
|
10
|
+
cooldownStateFilePath: string | null;
|
|
11
|
+
now: Date;
|
|
12
|
+
};
|
|
13
|
+
export declare const resetDegeneratedTmuxSessions: (params: ResetDegeneratedTmuxSessionsParams) => Promise<void>;
|
|
14
|
+
export declare const DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS: {
|
|
15
|
+
readonly warningMessage: "OUTPUT DEGENERATION DETECTED: your session is about to be reset. Immediately write a checkpoint to your assigned task issue (single concrete next action to resume, working directory and branch, in-flight sub-agent branch/PR URLs).";
|
|
16
|
+
readonly graceSeconds: 5;
|
|
17
|
+
readonly cooldownSeconds: 300;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=resetDegeneratedTmuxSessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resetDegeneratedTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AAgBxG,MAAM,MAAM,kCAAkC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,QAAQ,kCAAkC,KACzC,OAAO,CAAC,IAAI,CAkCd,CAAC;AAEF,eAAO,MAAM,8CAA8C;;;;CAIjD,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Issue } from '../../../domain/entities/Issue';
|
|
2
|
-
import { TokenRateLimitSnapshot, TokenStatus } from '../../../domain/usecases/dashboard/GenerateTokenStatusUseCase';
|
|
2
|
+
import { SevenDayWindowAggregate, TokenRateLimitSnapshot, TokenStatus } from '../../../domain/usecases/dashboard/GenerateTokenStatusUseCase';
|
|
3
3
|
import { ClaudeInteractiveSessionRepository } from '../../../domain/usecases/adapter-interfaces/ClaudeInteractiveSessionRepository';
|
|
4
4
|
import { TakeOwnershipSpawnRepository } from '../../../domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository';
|
|
5
5
|
import { RateLimitSnapshot } from '../../proxy/RateLimitCache';
|
|
@@ -15,6 +15,7 @@ export type TokenStatusWriterParams = {
|
|
|
15
15
|
};
|
|
16
16
|
export type TokenStatusFile = {
|
|
17
17
|
tokens: TokenStatus[];
|
|
18
|
+
sevenDayWindowAggregate: SevenDayWindowAggregate | null;
|
|
18
19
|
capturedAt: string;
|
|
19
20
|
};
|
|
20
21
|
export declare const toTokenRateLimitSnapshot: (snapshot: RateLimitSnapshot | null) => TokenRateLimitSnapshot | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenStatusWriter.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenStatusWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAEL,sBAAsB,EACtB,WAAW,
|
|
1
|
+
{"version":3,"file":"tokenStatusWriter.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenStatusWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAEL,uBAAuB,EACvB,sBAAsB,EACtB,WAAW,EAGZ,MAAM,+DAA+D,CAAC;AAGvE,OAAO,EAAE,kCAAkC,EAAE,MAAM,gFAAgF,CAAC;AACpI,OAAO,EAAE,4BAA4B,EAAE,MAAM,0EAA0E,CAAC;AACxH,OAAO,EAAE,iBAAiB,EAAiB,MAAM,4BAA4B,CAAC;AAU9E,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,iBAAiB,GAAG,IAAI,CAAC;IAC3D,4BAA4B,CAAC,EAAE,kCAAkC,CAAC;IAClE,eAAe,CAAC,EAAE,4BAA4B,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,uBAAuB,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AA0EF,eAAO,MAAM,wBAAwB,GACnC,UAAU,iBAAiB,GAAG,IAAI,KACjC,sBAAsB,GAAG,IA0B3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,uBAAuB,KAAG,IAgHlE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SessionAssistantTurnsRepository } from '../../domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository';
|
|
2
|
+
export declare const DEFAULT_TRANSCRIPT_TAIL_BYTES = 3000000;
|
|
3
|
+
export declare class FileSystemSessionAssistantTurnsRepository implements SessionAssistantTurnsRepository {
|
|
4
|
+
private readonly tailBytes;
|
|
5
|
+
constructor(tailBytes?: number);
|
|
6
|
+
listRecentAssistantTurnsBySessionName: (transcriptPathBySessionName: Map<string, string>, maxTurnsPerSession: number) => Promise<Map<string, string[]>>;
|
|
7
|
+
private readRecentAssistantTurns;
|
|
8
|
+
private readTailLines;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=FileSystemSessionAssistantTurnsRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileSystemSessionAssistantTurnsRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionAssistantTurnsRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;AAE3H,eAAO,MAAM,6BAA6B,UAAY,CAAC;AA0BvD,qBAAa,yCAA0C,YAAW,+BAA+B;IAE7F,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,GAAE,MAAsC;IAGpE,qCAAqC,GACnC,6BAA6B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChD,oBAAoB,MAAM,KACzB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAY/B;IAEF,OAAO,CAAC,wBAAwB,CAkC9B;IAEF,OAAO,CAAC,aAAa,CAwBnB;CACH"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SessionDegenerationCooldownStateRepository } from '../../domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository';
|
|
2
|
+
export declare const DEFAULT_RESET_RETENTION_WINDOW_SECONDS: number;
|
|
3
|
+
export declare class FileSystemSessionDegenerationCooldownStateRepository implements SessionDegenerationCooldownStateRepository {
|
|
4
|
+
private readonly stateFilePath;
|
|
5
|
+
private readonly retentionWindowSeconds;
|
|
6
|
+
constructor(stateFilePath?: string, retentionWindowSeconds?: number);
|
|
7
|
+
loadLastResetEpochSecondsBySessionName: () => Promise<Map<string, number>>;
|
|
8
|
+
recordReset: (params: {
|
|
9
|
+
sessionName: string;
|
|
10
|
+
now: Date;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
private readResetEntries;
|
|
13
|
+
private writeState;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=FileSystemSessionDegenerationCooldownStateRepository.d.ts.map
|
package/types/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileSystemSessionDegenerationCooldownStateRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSessionDegenerationCooldownStateRepository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,0CAA0C,EAAE,MAAM,qFAAqF,CAAC;AAUjJ,eAAO,MAAM,sCAAsC,QAAU,CAAC;AAO9D,qBAAa,oDAAqD,YAAW,0CAA0C;IAEnH,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBADtB,aAAa,GAAE,MAA+B,EAC9C,sBAAsB,GAAE,MAA+C;IAG1F,sCAAsC,QAAa,OAAO,CACxD,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CACpB,CAMC;IAEF,WAAW,GAAU,QAAQ;QAC3B,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAkBf;IAEF,OAAO,CAAC,gBAAgB,CAoCtB;IAEF,OAAO,CAAC,UAAU,CAMhB;CACH"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OwnerCallStatusProvider } from '../../domain/usecases/adapter-interfaces/OwnerCallStatusProvider';
|
|
2
|
+
export declare const ownerCallMarkerFamilyResolve: (marker: string) => string[];
|
|
2
3
|
export declare class TranscriptOwnerCallStatusProvider implements OwnerCallStatusProvider {
|
|
3
|
-
private readonly
|
|
4
|
+
private readonly ownerCallMarkerFamily;
|
|
4
5
|
constructor(ownerCallMarker: string | null);
|
|
5
6
|
listUnansweredOwnerCallEpochSecondsBySessionName: (transcriptPathBySessionName: Map<string, string>) => Promise<Map<string, number>>;
|
|
6
7
|
private findUnansweredOwnerCallEpochMs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranscriptOwnerCallStatusProvider.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;
|
|
1
|
+
{"version":3,"file":"TranscriptOwnerCallStatusProvider.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AA6F3G,eAAO,MAAM,4BAA4B,GAAI,QAAQ,MAAM,KAAG,MAAM,EAMtD,CAAC;AAEf,qBAAa,iCAAkC,YAAW,uBAAuB;IAC/E,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAW;gBAErC,eAAe,EAAE,MAAM,GAAG,IAAI;IAO1C,gDAAgD,GAC9C,6BAA6B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAqB7B;IAEF,OAAO,CAAC,8BAA8B,CAsDpC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OutputDegeneration.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/OutputDegeneration.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CrossTurnDegeneration } from '../entities/OutputDegeneration';
|
|
2
|
+
export declare const OUTPUT_DEGENERATION_REPEAT_THRESHOLD = 5;
|
|
3
|
+
export declare const OUTPUT_DEGENERATION_DOMINATION_FRACTION = 0.8;
|
|
4
|
+
export declare const OUTPUT_DEGENERATION_MAX_TOKEN_LENGTH = 32;
|
|
5
|
+
export declare const OUTPUT_DEGENERATION_ABSOLUTE_RUN_THRESHOLD = 15;
|
|
6
|
+
export declare const OUTPUT_DEGENERATION_REP4_THRESHOLD = 0.3;
|
|
7
|
+
export declare const OUTPUT_DEGENERATION_REP4_MIN_TOKENS = 40;
|
|
8
|
+
export declare const OUTPUT_DEGENERATION_CROSS_TURN_WINDOW = 10;
|
|
9
|
+
export declare const OUTPUT_DEGENERATION_CROSS_TURN_MIN_TURNS = 4;
|
|
10
|
+
export type ShortTokenRun = {
|
|
11
|
+
token: string | null;
|
|
12
|
+
run: number;
|
|
13
|
+
total: number;
|
|
14
|
+
};
|
|
15
|
+
export declare class OutputDegenerationDetector {
|
|
16
|
+
private readonly repeatThreshold;
|
|
17
|
+
private readonly dominationFraction;
|
|
18
|
+
private readonly maxTokenLength;
|
|
19
|
+
private readonly absoluteRunThreshold;
|
|
20
|
+
private readonly rep4Threshold;
|
|
21
|
+
private readonly rep4MinTokens;
|
|
22
|
+
private readonly crossTurnWindow;
|
|
23
|
+
private readonly crossTurnMinTurns;
|
|
24
|
+
constructor(repeatThreshold?: number, dominationFraction?: number, maxTokenLength?: number, absoluteRunThreshold?: number, rep4Threshold?: number, rep4MinTokens?: number, crossTurnWindow?: number, crossTurnMinTurns?: number);
|
|
25
|
+
maxConsecutiveShortTokenRun: (text: string) => ShortTokenRun;
|
|
26
|
+
isIntraTurnDegeneration: (text: string) => boolean;
|
|
27
|
+
detectCrossTurnDegeneration: (texts: string[]) => CrossTurnDegeneration | null;
|
|
28
|
+
private stripRepetitionExemptSpans;
|
|
29
|
+
private duplicateNgramFraction;
|
|
30
|
+
private trailingSpuriousToken;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=OutputDegenerationDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OutputDegenerationDetector.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OutputDegenerationDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,eAAO,MAAM,oCAAoC,IAAI,CAAC;AACtD,eAAO,MAAM,uCAAuC,MAAM,CAAC;AAC3D,eAAO,MAAM,oCAAoC,KAAK,CAAC;AACvD,eAAO,MAAM,0CAA0C,KAAK,CAAC;AAC7D,eAAO,MAAM,kCAAkC,MAAM,CAAC;AACtD,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,qCAAqC,KAAK,CAAC;AACxD,eAAO,MAAM,wCAAwC,IAAI,CAAC;AAE1D,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,qBAAa,0BAA0B;IAEnC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;gBAPjB,eAAe,GAAE,MAA6C,EAC9D,kBAAkB,GAAE,MAAgD,EACpE,cAAc,GAAE,MAA6C,EAC7D,oBAAoB,GAAE,MAAmD,EACzE,aAAa,GAAE,MAA2C,EAC1D,aAAa,GAAE,MAA4C,EAC3D,eAAe,GAAE,MAA8C,EAC/D,iBAAiB,GAAE,MAAiD;IAGvF,2BAA2B,GAAI,MAAM,MAAM,KAAG,aAAa,CAyBzD;IAEF,uBAAuB,GAAI,MAAM,MAAM,KAAG,OAAO,CAoB/C;IAEF,2BAA2B,GACzB,OAAO,MAAM,EAAE,KACd,qBAAqB,GAAG,IAAI,CAqB7B;IAEF,OAAO,CAAC,0BAA0B,CAqBhC;IAEF,OAAO,CAAC,sBAAsB,CAiB5B;IAEF,OAAO,CAAC,qBAAqB,CAc3B;CACH"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LiveSessionProcessSnapshotProvider } from './adapter-interfaces/LiveSessionProcessSnapshotProvider';
|
|
2
|
+
import { InteractiveLiveSessionTranscriptResolver } from './adapter-interfaces/InteractiveLiveSessionTranscriptResolver';
|
|
3
|
+
import { SessionAssistantTurnsRepository } from './adapter-interfaces/SessionAssistantTurnsRepository';
|
|
4
|
+
import { SessionDegenerationCooldownStateRepository } from './adapter-interfaces/SessionDegenerationCooldownStateRepository';
|
|
5
|
+
import { SilentSessionNotificationRepository } from './adapter-interfaces/SilentSessionNotificationRepository';
|
|
6
|
+
import { TmuxSessionRepository } from './adapter-interfaces/TmuxSessionRepository';
|
|
7
|
+
import { Sleeper } from './adapter-interfaces/Sleeper';
|
|
8
|
+
import { OutputDegenerationDetector } from './OutputDegenerationDetector';
|
|
9
|
+
export declare const DEFAULT_OUTPUT_DEGENERATION_GRACE_SECONDS = 5;
|
|
10
|
+
export declare const DEFAULT_OUTPUT_DEGENERATION_COOLDOWN_SECONDS = 300;
|
|
11
|
+
export declare const DEFAULT_OUTPUT_DEGENERATION_WARNING_MESSAGE = "OUTPUT DEGENERATION DETECTED: your session is about to be reset. Immediately write a checkpoint to your assigned task issue (single concrete next action to resume, working directory and branch, in-flight sub-agent branch/PR URLs).";
|
|
12
|
+
export declare class SessionOutputDegenerationRecoveryUseCase {
|
|
13
|
+
private readonly liveSessionProcessSnapshotProvider;
|
|
14
|
+
private readonly interactiveLiveSessionTranscriptResolver;
|
|
15
|
+
private readonly assistantTurnsRepository;
|
|
16
|
+
private readonly notificationRepository;
|
|
17
|
+
private readonly tmuxSessionRepository;
|
|
18
|
+
private readonly cooldownStateRepository;
|
|
19
|
+
private readonly sleeper;
|
|
20
|
+
private readonly detector;
|
|
21
|
+
private readonly resolveInteractiveLiveSessions;
|
|
22
|
+
constructor(liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver, assistantTurnsRepository: SessionAssistantTurnsRepository, notificationRepository: SilentSessionNotificationRepository, tmuxSessionRepository: Pick<TmuxSessionRepository, 'killSession'>, cooldownStateRepository: SessionDegenerationCooldownStateRepository, sleeper: Sleeper, detector?: OutputDegenerationDetector);
|
|
23
|
+
run: (params: {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
warningMessage: string;
|
|
26
|
+
graceSeconds: number;
|
|
27
|
+
cooldownSeconds: number;
|
|
28
|
+
now: Date;
|
|
29
|
+
}) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=SessionOutputDegenerationRecoveryUseCase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionOutputDegenerationRecoveryUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/SessionOutputDegenerationRecoveryUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,yDAAyD,CAAC;AAC7G,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAC;AACzH,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,0CAA0C,EAAE,MAAM,iEAAiE,CAAC;AAC7H,OAAO,EAAE,mCAAmC,EAAE,MAAM,0DAA0D,CAAC;AAC/G,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EACL,0BAA0B,EAE3B,MAAM,8BAA8B,CAAC;AAItC,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAC3D,eAAO,MAAM,4CAA4C,MAAM,CAAC;AAChE,eAAO,MAAM,2CAA2C,2OACkL,CAAC;AAE3O,qBAAa,wCAAwC;IAKjD,OAAO,CAAC,QAAQ,CAAC,kCAAkC;IACnD,OAAO,CAAC,QAAQ,CAAC,wCAAwC;IACzD,OAAO,CAAC,QAAQ,CAAC,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAItC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAd3B,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CACD;gBAG3B,kCAAkC,EAAE,kCAAkC,EACtE,wCAAwC,EAAE,wCAAwC,EAClF,wBAAwB,EAAE,+BAA+B,EACzD,sBAAsB,EAAE,mCAAmC,EAC3D,qBAAqB,EAAE,IAAI,CAC1C,qBAAqB,EACrB,aAAa,CACd,EACgB,uBAAuB,EAAE,0CAA0C,EACnE,OAAO,EAAE,OAAO,EAChB,QAAQ,GAAE,0BAA6D;IAG1F,GAAG,GAAU,QAAQ;QACnB,OAAO,EAAE,OAAO,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAiGf;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionAssistantTurnsRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,+BAA+B;IAC9C,qCAAqC,EAAE,CACrC,2BAA2B,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChD,kBAAkB,EAAE,MAAM,KACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CACrC"}
|
package/types/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface SessionDegenerationCooldownStateRepository {
|
|
2
|
+
loadLastResetEpochSecondsBySessionName: () => Promise<Map<string, number>>;
|
|
3
|
+
recordReset: (params: {
|
|
4
|
+
sessionName: string;
|
|
5
|
+
now: Date;
|
|
6
|
+
}) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=SessionDegenerationCooldownStateRepository.d.ts.map
|
package/types/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionDegenerationCooldownStateRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0CAA0C;IACzD,sCAAsC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3E,WAAW,EAAE,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E"}
|