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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionOutputDegenerationRecoveryUseCase = exports.DEFAULT_OUTPUT_DEGENERATION_WARNING_MESSAGE = exports.DEFAULT_OUTPUT_DEGENERATION_COOLDOWN_SECONDS = exports.DEFAULT_OUTPUT_DEGENERATION_GRACE_SECONDS = void 0;
|
|
4
|
+
const OutputDegenerationDetector_1 = require("./OutputDegenerationDetector");
|
|
5
|
+
const ResolveInteractiveLiveSessionsUseCase_1 = require("./ResolveInteractiveLiveSessionsUseCase");
|
|
6
|
+
const NotifySilentLiveSessionsUseCase_1 = require("./NotifySilentLiveSessionsUseCase");
|
|
7
|
+
exports.DEFAULT_OUTPUT_DEGENERATION_GRACE_SECONDS = 5;
|
|
8
|
+
exports.DEFAULT_OUTPUT_DEGENERATION_COOLDOWN_SECONDS = 300;
|
|
9
|
+
exports.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).';
|
|
10
|
+
class SessionOutputDegenerationRecoveryUseCase {
|
|
11
|
+
constructor(liveSessionProcessSnapshotProvider, interactiveLiveSessionTranscriptResolver, assistantTurnsRepository, notificationRepository, tmuxSessionRepository, cooldownStateRepository, sleeper, detector = new OutputDegenerationDetector_1.OutputDegenerationDetector()) {
|
|
12
|
+
this.liveSessionProcessSnapshotProvider = liveSessionProcessSnapshotProvider;
|
|
13
|
+
this.interactiveLiveSessionTranscriptResolver = interactiveLiveSessionTranscriptResolver;
|
|
14
|
+
this.assistantTurnsRepository = assistantTurnsRepository;
|
|
15
|
+
this.notificationRepository = notificationRepository;
|
|
16
|
+
this.tmuxSessionRepository = tmuxSessionRepository;
|
|
17
|
+
this.cooldownStateRepository = cooldownStateRepository;
|
|
18
|
+
this.sleeper = sleeper;
|
|
19
|
+
this.detector = detector;
|
|
20
|
+
this.resolveInteractiveLiveSessions = new ResolveInteractiveLiveSessionsUseCase_1.ResolveInteractiveLiveSessionsUseCase();
|
|
21
|
+
this.run = async (params) => {
|
|
22
|
+
const snapshot = await this.liveSessionProcessSnapshotProvider.getSnapshot();
|
|
23
|
+
const allInteractiveSessions = this.resolveInteractiveLiveSessions.resolve(snapshot);
|
|
24
|
+
const interactiveSessions = allInteractiveSessions.filter((session) => (0, NotifySilentLiveSessionsUseCase_1.isGitHubIssueOrPullRequestSessionName)(session.sessionName));
|
|
25
|
+
const transcriptPathBySessionName = this.interactiveLiveSessionTranscriptResolver.resolveTranscriptPaths(interactiveSessions);
|
|
26
|
+
const turnsBySessionName = await this.assistantTurnsRepository.listRecentAssistantTurnsBySessionName(transcriptPathBySessionName, OutputDegenerationDetector_1.OUTPUT_DEGENERATION_CROSS_TURN_WINDOW);
|
|
27
|
+
const lastResetBySessionName = await this.cooldownStateRepository.loadLastResetEpochSecondsBySessionName();
|
|
28
|
+
const nowEpochSeconds = Math.floor(params.now.getTime() / 1000);
|
|
29
|
+
let detectedCount = 0;
|
|
30
|
+
let resetCount = 0;
|
|
31
|
+
let dryRunCount = 0;
|
|
32
|
+
let cooldownSkippedCount = 0;
|
|
33
|
+
for (const session of interactiveSessions) {
|
|
34
|
+
const sessionName = session.sessionName;
|
|
35
|
+
const lastResetEpochSeconds = lastResetBySessionName.get(sessionName);
|
|
36
|
+
if (lastResetEpochSeconds !== undefined &&
|
|
37
|
+
nowEpochSeconds - lastResetEpochSeconds < params.cooldownSeconds) {
|
|
38
|
+
cooldownSkippedCount += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const turns = turnsBySessionName.get(sessionName) ?? [];
|
|
42
|
+
const newestTurn = turns.length > 0 ? turns[0] : null;
|
|
43
|
+
const intraTurn = newestTurn !== null &&
|
|
44
|
+
this.detector.isIntraTurnDegeneration(newestTurn);
|
|
45
|
+
const crossTurn = this.detector.detectCrossTurnDegeneration(turns);
|
|
46
|
+
if (!intraTurn && crossTurn === null) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
detectedCount += 1;
|
|
50
|
+
if (intraTurn && newestTurn !== null) {
|
|
51
|
+
const { token, run, total } = this.detector.maxConsecutiveShortTokenRun(newestTurn);
|
|
52
|
+
console.log(`Output degeneration detected (intra-turn) session=${sessionName} token=${JSON.stringify(token)} run=${run} turnTokens=${total} enabled=${params.enabled}`);
|
|
53
|
+
}
|
|
54
|
+
if (crossTurn !== null) {
|
|
55
|
+
console.log(`Output degeneration detected (cross-turn) session=${sessionName} token=${JSON.stringify(crossTurn.token)} turns=${crossTurn.turnCount}/${Math.min(turns.length, OutputDegenerationDetector_1.OUTPUT_DEGENERATION_CROSS_TURN_WINDOW)} enabled=${params.enabled}`);
|
|
56
|
+
}
|
|
57
|
+
if (params.enabled) {
|
|
58
|
+
try {
|
|
59
|
+
await this.notificationRepository.sendSelfCheckNotification(sessionName, params.warningMessage);
|
|
60
|
+
await this.sleeper.sleep(params.graceSeconds * 1000);
|
|
61
|
+
await this.tmuxSessionRepository.killSession(sessionName);
|
|
62
|
+
resetCount += 1;
|
|
63
|
+
console.log(`Output degeneration reset session=${sessionName} graceSeconds=${params.graceSeconds}`);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error(`Failed to reset degenerated session ${sessionName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
dryRunCount += 1;
|
|
72
|
+
console.log(`Output degeneration dry-run: would warn and reset session=${sessionName}`);
|
|
73
|
+
}
|
|
74
|
+
await this.cooldownStateRepository.recordReset({
|
|
75
|
+
sessionName,
|
|
76
|
+
now: params.now,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
console.log(`Output degeneration recovery: detected ${detectedCount} degenerated session(s) of ${interactiveSessions.length} interactive session(s); reset ${resetCount}, dry-run would-reset ${dryRunCount}, cooldown-skipped ${cooldownSkippedCount}.`);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.SessionOutputDegenerationRecoveryUseCase = SessionOutputDegenerationRecoveryUseCase;
|
|
84
|
+
//# sourceMappingURL=SessionOutputDegenerationRecoveryUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionOutputDegenerationRecoveryUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/SessionOutputDegenerationRecoveryUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionAssistantTurnsRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SessionAssistantTurnsRepository.ts"],"names":[],"mappings":""}
|
package/bin/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionDegenerationCooldownStateRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/SessionDegenerationCooldownStateRepository.ts"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ComposeDashboardUseCase = exports.formatTokenRowLine = exports.formatProjectRowLine = exports.formatProjectHeaderLine = exports.formatMachineStatusLines = exports.formatResetCountdown = exports.roundHalfToEven = exports.PROJECT_ROW_WIDTH_BUDGET = void 0;
|
|
3
|
+
exports.ComposeDashboardUseCase = exports.formatTokenRowLine = exports.formatSevenDayWindowAggregateLine = exports.formatProjectRowLine = exports.formatProjectHeaderLine = exports.formatMachineStatusLines = exports.formatResetCountdown = exports.roundHalfToEven = exports.PROJECT_ROW_WIDTH_BUDGET = void 0;
|
|
4
4
|
exports.PROJECT_ROW_WIDTH_BUDGET = 32;
|
|
5
5
|
const PROJECT_COLUMNS = [
|
|
6
6
|
{ header: 'unr', key: 'unread' },
|
|
@@ -13,6 +13,10 @@ const PROJECT_COLUMNS = [
|
|
|
13
13
|
];
|
|
14
14
|
const PROJECT_COLUMN_WIDTH = 3;
|
|
15
15
|
const SEVERITY_BLANK = ' ';
|
|
16
|
+
const TOKEN_COLOR_DOT_WIDTH = 1;
|
|
17
|
+
const TOKEN_NAME_WIDTH = 4;
|
|
18
|
+
const TOKEN_UTILIZATION_WIDTH = 4;
|
|
19
|
+
const TOKEN_RESET_WIDTH = 7;
|
|
16
20
|
const TOKEN_COLOR_DOT = {
|
|
17
21
|
G: '🟢',
|
|
18
22
|
Y: '🟡',
|
|
@@ -139,7 +143,7 @@ const formatProjectRowLine = (project) => {
|
|
|
139
143
|
return mark + padEnd(project.code, 2, ' ') + cells;
|
|
140
144
|
};
|
|
141
145
|
exports.formatProjectRowLine = formatProjectRowLine;
|
|
142
|
-
const formatUtilization = (percent) => padStart(percent === null ? '?' : `${percent}%`,
|
|
146
|
+
const formatUtilization = (percent) => padStart(percent === null ? '?' : `${percent}%`, TOKEN_UTILIZATION_WIDTH);
|
|
143
147
|
const formatReset = (resetSeconds) => resetSeconds === null ? '?' : (0, exports.formatResetCountdown)(resetSeconds);
|
|
144
148
|
const tokenSortKey = (token) => token.sevenDayResetSeconds === null
|
|
145
149
|
? [1, 0]
|
|
@@ -158,16 +162,42 @@ const sortTokens = (tokens) => tokens
|
|
|
158
162
|
return left.index - right.index;
|
|
159
163
|
})
|
|
160
164
|
.map((entry) => entry.token);
|
|
165
|
+
const joinTokenRowSegments = (segments) => segments.join(' ');
|
|
166
|
+
const SEVEN_DAY_WINDOW_AGGREGATE_LABEL = '7d';
|
|
167
|
+
const formatSevenDayWindowAggregateLine = (aggregate) => {
|
|
168
|
+
if (aggregate === null) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const leftPercent = (0, exports.roundHalfToEven)(100 - aggregate.usedPercent);
|
|
172
|
+
const includedCountSuffix = aggregate.includedTokenCount === aggregate.totalTokenCount
|
|
173
|
+
? ''
|
|
174
|
+
: ` (${aggregate.includedTokenCount})`;
|
|
175
|
+
return (joinTokenRowSegments([
|
|
176
|
+
padEnd(SEVEN_DAY_WINDOW_AGGREGATE_LABEL, TOKEN_COLOR_DOT_WIDTH + TOKEN_NAME_WIDTH, ' '),
|
|
177
|
+
padEnd('', TOKEN_UTILIZATION_WIDTH, ' '),
|
|
178
|
+
padEnd('', TOKEN_RESET_WIDTH, ' '),
|
|
179
|
+
formatUtilization(leftPercent),
|
|
180
|
+
]) + includedCountSuffix);
|
|
181
|
+
};
|
|
182
|
+
exports.formatSevenDayWindowAggregateLine = formatSevenDayWindowAggregateLine;
|
|
161
183
|
const formatTokenRowLine = (token) => {
|
|
162
184
|
const dot = TOKEN_COLOR_DOT[token.color];
|
|
163
|
-
const name = padEnd(token.name,
|
|
185
|
+
const name = padEnd(token.name, TOKEN_NAME_WIDTH, '_');
|
|
164
186
|
const fiveHourUtilization = formatUtilization(token.fiveHourUtilizationPercent);
|
|
165
187
|
const fiveHourReset = formatReset(token.fiveHourResetSeconds);
|
|
166
188
|
const sevenDayUtilization = formatUtilization(token.sevenDayUtilizationPercent);
|
|
167
189
|
const sevenDayReset = formatReset(token.sevenDayResetSeconds);
|
|
168
190
|
const prep = String(token.prep);
|
|
169
191
|
const hum = String(token.hum);
|
|
170
|
-
return
|
|
192
|
+
return joinTokenRowSegments([
|
|
193
|
+
`${dot}${name}`,
|
|
194
|
+
fiveHourUtilization,
|
|
195
|
+
fiveHourReset,
|
|
196
|
+
sevenDayUtilization,
|
|
197
|
+
sevenDayReset,
|
|
198
|
+
prep,
|
|
199
|
+
hum,
|
|
200
|
+
]);
|
|
171
201
|
};
|
|
172
202
|
exports.formatTokenRowLine = formatTokenRowLine;
|
|
173
203
|
const wrapLine = (line) => `<tt>${line.replace(/ /g, ' ')}</tt><br>`;
|
|
@@ -180,7 +210,13 @@ class ComposeDashboardUseCase {
|
|
|
180
210
|
...input.projects.map((project) => (0, exports.formatProjectRowLine)(project)),
|
|
181
211
|
];
|
|
182
212
|
const tokenLines = sortTokens(input.tokens).map((token) => (0, exports.formatTokenRowLine)(token));
|
|
183
|
-
const
|
|
213
|
+
const aggregateLine = (0, exports.formatSevenDayWindowAggregateLine)(input.sevenDayWindowAggregate ?? null);
|
|
214
|
+
const lines = [
|
|
215
|
+
...statsLines,
|
|
216
|
+
...projectLines,
|
|
217
|
+
aggregateLine === null ? '' : aggregateLine,
|
|
218
|
+
...tokenLines,
|
|
219
|
+
];
|
|
184
220
|
return lines.map((line) => wrapLine(line)).join('\n') + '\n';
|
|
185
221
|
};
|
|
186
222
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposeDashboardUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/ComposeDashboardUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ComposeDashboardUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/ComposeDashboardUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GenerateTokenStatusUseCase = exports.judgeTokenColor = void 0;
|
|
3
|
+
exports.GenerateTokenStatusUseCase = exports.computeSevenDayWindowAggregate = exports.judgeTokenColor = void 0;
|
|
4
4
|
const HIGH_UTILIZATION_THRESHOLD = 0.7;
|
|
5
5
|
const ALLOWED_WARNING_STATUS = 'allowed_warning';
|
|
6
6
|
const judgeTokenColor = (decision) => {
|
|
@@ -29,6 +29,21 @@ const judgeTokenColor = (decision) => {
|
|
|
29
29
|
return 'G';
|
|
30
30
|
};
|
|
31
31
|
exports.judgeTokenColor = judgeTokenColor;
|
|
32
|
+
const computeSevenDayWindowAggregate = (tokens) => {
|
|
33
|
+
const utilizations = tokens
|
|
34
|
+
.map((token) => token.sevenDayUtilizationPercent)
|
|
35
|
+
.filter((percent) => percent !== null);
|
|
36
|
+
if (utilizations.length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const total = utilizations.reduce((sum, percent) => sum + percent, 0);
|
|
40
|
+
return {
|
|
41
|
+
usedPercent: total / utilizations.length,
|
|
42
|
+
includedTokenCount: utilizations.length,
|
|
43
|
+
totalTokenCount: tokens.length,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
exports.computeSevenDayWindowAggregate = computeSevenDayWindowAggregate;
|
|
32
47
|
class GenerateTokenStatusUseCase {
|
|
33
48
|
constructor() {
|
|
34
49
|
this.run = (input) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenerateTokenStatusUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"GenerateTokenStatusUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts"],"names":[],"mappings":";;;AA0DA,MAAM,0BAA0B,GAAG,GAAG,CAAC;AACvC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAE1C,MAAM,eAAe,GAAG,CAC7B,QAAuC,EACrB,EAAE;IACpB,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,IAAI,CAAC,CAAC;IAC9D,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,IAAI,CAAC,CAAC;IAC9D,MAAM,iBAAiB,GACrB,mBAAmB,IAAI,GAAG,IAAI,QAAQ,CAAC,gBAAgB,CAAC;IAC1D,MAAM,uBAAuB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;IAC1D,MAAM,0BAA0B,GAC9B,QAAQ,CAAC,sBAAsB,IAAI,QAAQ,CAAC,oBAAoB,CAAC;IACnE,MAAM,aAAa,GACjB,QAAQ,CAAC,OAAO;QAChB,iBAAiB;QACjB,uBAAuB;QACvB,0BAA0B,CAAC;IAC7B,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,QAAQ,CAAC,aAAa,KAAK,sBAAsB,EAAE,CAAC;QACtD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IACE,mBAAmB,IAAI,0BAA0B;QACjD,mBAAmB,IAAI,0BAA0B,EACjD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AA/BW,QAAA,eAAe,mBA+B1B;AAEK,MAAM,8BAA8B,GAAG,CAC5C,MAAqB,EACW,EAAE;IAClC,MAAM,YAAY,GAAG,MAAM;SACxB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,0BAA0B,CAAC;SAChD,MAAM,CAAC,CAAC,OAAO,EAAqB,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IAC5D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;IACtE,OAAO;QACL,WAAW,EAAE,KAAK,GAAG,YAAY,CAAC,MAAM;QACxC,kBAAkB,EAAE,YAAY,CAAC,MAAM;QACvC,eAAe,EAAE,MAAM,CAAC,MAAM;KAC/B,CAAC;AACJ,CAAC,CAAC;AAfW,QAAA,8BAA8B,kCAezC;AAEF,MAAa,0BAA0B;IAAvC;QACE,QAAG,GAAG,CAAC,KAA+B,EAAiB,EAAE;YACvD,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,GAClE,KAAK,CAAC;YACR,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;gBAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;gBACvE,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CACtC,UAAU,CAAC,QAAQ,EACnB,eAAe,CAChB,CAAC;gBACF,OAAO;oBACL,IAAI,EAAE,UAAU,CAAC,IAAI;oBACrB,0BAA0B,EAAE,UAAU,CAAC,0BAA0B;oBACjE,oBAAoB,EAAE,UAAU,CAAC,oBAAoB;oBACrD,0BAA0B,EAAE,UAAU,CAAC,0BAA0B;oBACjE,oBAAoB,EAAE,UAAU,CAAC,oBAAoB;oBACrD,KAAK,EAAE,IAAA,uBAAe,EAAC,QAAQ,CAAC;oBAChC,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;oBACjD,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;iBAChD,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEM,qBAAgB,GAAG,CACzB,QAAuC,EACvC,eAAuB,EAMvB,EAAE;YACF,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;gBACjD,OAAO;oBACL,0BAA0B,EAAE,IAAI;oBAChC,oBAAoB,EAAE,IAAI;oBAC1B,0BAA0B,EAAE,IAAI;oBAChC,oBAAoB,EAAE,IAAI;iBAC3B,CAAC;YACJ,CAAC;YACD,MAAM,aAAa,GACjB,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7D,MAAM,aAAa,GACjB,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7D,MAAM,eAAe,GACnB,aAAa,KAAK,IAAI,IAAI,aAAa,GAAG,eAAe,CAAC;YAC5D,MAAM,eAAe,GACnB,aAAa,KAAK,IAAI,IAAI,aAAa,GAAG,eAAe,CAAC;YAC5D,OAAO;gBACL,0BAA0B,EAAE,eAAe;oBACzC,CAAC,CAAC,CAAC;oBACH,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,mBAAmB,GAAG,GAAG,CAAC;gBAClD,oBAAoB,EAClB,aAAa,KAAK,IAAI;oBACpB,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC;gBAClD,0BAA0B,EAAE,eAAe;oBACzC,CAAC,CAAC,CAAC;oBACH,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,mBAAmB,GAAG,GAAG,CAAC;gBAClD,oBAAoB,EAClB,aAAa,KAAK,IAAI;oBACpB,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC;aACnD,CAAC;QACJ,CAAC,CAAC;QAEM,eAAU,GAAG,CACnB,QAAuC,EACvC,eAAuB,EACQ,EAAE;YACjC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC5B,OAAO;oBACL,mBAAmB,EAAE,IAAI;oBACzB,mBAAmB,EAAE,IAAI;oBACzB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;oBAC3C,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;oBAC3C,OAAO,EAAE,QAAQ,CAAC,OAAO;oBACzB,aAAa,EAAE,QAAQ,CAAC,aAAa;oBACrC,sBAAsB,EAAE,QAAQ,CAAC,sBAAsB;oBACvD,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;oBACnD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,MAAM,eAAe,GACnB,QAAQ,CAAC,aAAa,GAAG,CAAC,IAAI,QAAQ,CAAC,aAAa,GAAG,eAAe,CAAC;YACzE,MAAM,eAAe,GACnB,QAAQ,CAAC,aAAa,GAAG,CAAC,IAAI,QAAQ,CAAC,aAAa,GAAG,eAAe,CAAC;YACzE,OAAO;gBACL,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB;gBACvE,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB;gBACvE,gBAAgB,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB;gBACrE,gBAAgB,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB;gBACrE,OAAO,EAAE,QAAQ,CAAC,OAAO;gBACzB,aAAa,EAAE,QAAQ,CAAC,aAAa;gBACrC,sBAAsB,EACpB,QAAQ,CAAC,sBAAsB;oBAC/B,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBACvD,oBAAoB,EAClB,QAAQ,CAAC,oBAAoB;oBAC7B,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBACvD,OAAO,EAAE,KAAK;aACf,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CAAA;AA1GD,gEA0GC"}
|
package/package.json
CHANGED
|
@@ -233,6 +233,88 @@ describe('buildComposeDashboardInput', () => {
|
|
|
233
233
|
}
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
+
it('reads the seven day window aggregate from token-status.json', () => {
|
|
237
|
+
const dataDir = makeDataDir();
|
|
238
|
+
try {
|
|
239
|
+
fs.writeFileSync(
|
|
240
|
+
path.join(dataDir, 'token-status.json'),
|
|
241
|
+
JSON.stringify({
|
|
242
|
+
tokens: [],
|
|
243
|
+
sevenDayWindowAggregate: {
|
|
244
|
+
usedPercent: 63.5,
|
|
245
|
+
includedTokenCount: 9,
|
|
246
|
+
totalTokenCount: 10,
|
|
247
|
+
},
|
|
248
|
+
capturedAt: 'x',
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
const input = buildComposeDashboardInput({
|
|
252
|
+
dashboardDataDir: dataDir,
|
|
253
|
+
projectNames: [],
|
|
254
|
+
});
|
|
255
|
+
expect(input.sevenDayWindowAggregate).toEqual({
|
|
256
|
+
usedPercent: 63.5,
|
|
257
|
+
includedTokenCount: 9,
|
|
258
|
+
totalTokenCount: 10,
|
|
259
|
+
});
|
|
260
|
+
} finally {
|
|
261
|
+
fs.rmSync(dataDir, { recursive: true, force: true });
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('reads a token-status.json written without the seven day window aggregate', () => {
|
|
266
|
+
const dataDir = makeDataDir();
|
|
267
|
+
try {
|
|
268
|
+
fs.writeFileSync(
|
|
269
|
+
path.join(dataDir, 'token-status.json'),
|
|
270
|
+
JSON.stringify({
|
|
271
|
+
tokens: [
|
|
272
|
+
{
|
|
273
|
+
name: 'alice',
|
|
274
|
+
fiveHourUtilizationPercent: 10,
|
|
275
|
+
fiveHourResetSeconds: 3600,
|
|
276
|
+
sevenDayUtilizationPercent: 12,
|
|
277
|
+
sevenDayResetSeconds: 432000,
|
|
278
|
+
color: 'G',
|
|
279
|
+
prep: 2,
|
|
280
|
+
hum: 1,
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
capturedAt: 'x',
|
|
284
|
+
}),
|
|
285
|
+
);
|
|
286
|
+
const input = buildComposeDashboardInput({
|
|
287
|
+
dashboardDataDir: dataDir,
|
|
288
|
+
projectNames: [],
|
|
289
|
+
});
|
|
290
|
+
expect(input.sevenDayWindowAggregate).toBeNull();
|
|
291
|
+
expect(input.tokens).toHaveLength(1);
|
|
292
|
+
} finally {
|
|
293
|
+
fs.rmSync(dataDir, { recursive: true, force: true });
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('ignores a seven day window aggregate with a missing field', () => {
|
|
298
|
+
const dataDir = makeDataDir();
|
|
299
|
+
try {
|
|
300
|
+
fs.writeFileSync(
|
|
301
|
+
path.join(dataDir, 'token-status.json'),
|
|
302
|
+
JSON.stringify({
|
|
303
|
+
tokens: [],
|
|
304
|
+
sevenDayWindowAggregate: { usedPercent: 63 },
|
|
305
|
+
capturedAt: 'x',
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
const input = buildComposeDashboardInput({
|
|
309
|
+
dashboardDataDir: dataDir,
|
|
310
|
+
projectNames: [],
|
|
311
|
+
});
|
|
312
|
+
expect(input.sevenDayWindowAggregate).toBeNull();
|
|
313
|
+
} finally {
|
|
314
|
+
fs.rmSync(dataDir, { recursive: true, force: true });
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
236
318
|
it('defaults an unknown token color to Y and null windows to null', () => {
|
|
237
319
|
const dataDir = makeDataDir();
|
|
238
320
|
try {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { toDashboardDisplayLabel } from '../../../domain/usecases/dashboard/DashboardProjectCode';
|
|
11
11
|
import { DashboardRow } from '../../../domain/usecases/dashboard/GenerateDashboardRowUseCase';
|
|
12
12
|
import {
|
|
13
|
+
SevenDayWindowAggregate,
|
|
13
14
|
TokenStatus,
|
|
14
15
|
TokenStatusColor,
|
|
15
16
|
} from '../../../domain/usecases/dashboard/GenerateTokenStatusUseCase';
|
|
@@ -163,10 +164,36 @@ const parseTokenStatus = (value: unknown): TokenStatus | null => {
|
|
|
163
164
|
};
|
|
164
165
|
};
|
|
165
166
|
|
|
166
|
-
const
|
|
167
|
+
const parseSevenDayWindowAggregate = (
|
|
168
|
+
value: unknown,
|
|
169
|
+
): SevenDayWindowAggregate | null => {
|
|
170
|
+
if (!isRecord(value)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const usedPercent = asFiniteNumber(value.usedPercent);
|
|
174
|
+
const includedTokenCount = asFiniteNumber(value.includedTokenCount);
|
|
175
|
+
const totalTokenCount = asFiniteNumber(value.totalTokenCount);
|
|
176
|
+
if (
|
|
177
|
+
usedPercent === null ||
|
|
178
|
+
includedTokenCount === null ||
|
|
179
|
+
totalTokenCount === null
|
|
180
|
+
) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return { usedPercent, includedTokenCount, totalTokenCount };
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
type TokenStatusFileContent = {
|
|
187
|
+
tokens: TokenStatus[];
|
|
188
|
+
sevenDayWindowAggregate: SevenDayWindowAggregate | null;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const readTokenStatusFile = (
|
|
192
|
+
dashboardDataDir: string,
|
|
193
|
+
): TokenStatusFileContent => {
|
|
167
194
|
const value = readJsonFile(path.join(dashboardDataDir, 'token-status.json'));
|
|
168
195
|
if (!isRecord(value) || !Array.isArray(value.tokens)) {
|
|
169
|
-
return [];
|
|
196
|
+
return { tokens: [], sevenDayWindowAggregate: null };
|
|
170
197
|
}
|
|
171
198
|
const tokens: TokenStatus[] = [];
|
|
172
199
|
for (const entry of value.tokens) {
|
|
@@ -175,7 +202,12 @@ const readTokenStatuses = (dashboardDataDir: string): TokenStatus[] => {
|
|
|
175
202
|
tokens.push(token);
|
|
176
203
|
}
|
|
177
204
|
}
|
|
178
|
-
return
|
|
205
|
+
return {
|
|
206
|
+
tokens,
|
|
207
|
+
sevenDayWindowAggregate: parseSevenDayWindowAggregate(
|
|
208
|
+
value.sevenDayWindowAggregate,
|
|
209
|
+
),
|
|
210
|
+
};
|
|
179
211
|
};
|
|
180
212
|
|
|
181
213
|
export const buildComposeDashboardInput = (
|
|
@@ -187,10 +219,12 @@ export const buildComposeDashboardInput = (
|
|
|
187
219
|
row: readProjectRow(options.dashboardDataDir, projectName),
|
|
188
220
|
}),
|
|
189
221
|
);
|
|
222
|
+
const tokenStatusFile = readTokenStatusFile(options.dashboardDataDir);
|
|
190
223
|
return {
|
|
191
224
|
projects,
|
|
192
225
|
machineStatus: readMachineStatus(options.dashboardDataDir),
|
|
193
|
-
tokens:
|
|
226
|
+
tokens: tokenStatusFile.tokens,
|
|
227
|
+
sevenDayWindowAggregate: tokenStatusFile.sevenDayWindowAggregate,
|
|
194
228
|
};
|
|
195
229
|
};
|
|
196
230
|
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
notifySilentTmuxSessions,
|
|
17
17
|
DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS,
|
|
18
18
|
} from './notifySilentTmuxSessions';
|
|
19
|
+
import {
|
|
20
|
+
resetDegeneratedTmuxSessions,
|
|
21
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS,
|
|
22
|
+
} from './resetDegeneratedTmuxSessions';
|
|
19
23
|
import { writeRotationOrderFile } from './rotationOrderFileWriter';
|
|
20
24
|
import {
|
|
21
25
|
fetchProjectReadme,
|
|
@@ -145,6 +149,11 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
145
149
|
silentSubAgentIdleMessageFooter?: string;
|
|
146
150
|
silentSubAgentLongRunningMessageHeader?: string;
|
|
147
151
|
silentSubAgentLongRunningMessageFooter?: string;
|
|
152
|
+
outputDegenerationResetEnabled?: boolean;
|
|
153
|
+
outputDegenerationWarningMessage?: string;
|
|
154
|
+
outputDegenerationGraceSeconds?: number;
|
|
155
|
+
outputDegenerationCooldownSeconds?: number;
|
|
156
|
+
outputDegenerationCooldownStateFilePath?: string;
|
|
148
157
|
credentials: {
|
|
149
158
|
manager: {
|
|
150
159
|
github: {
|
|
@@ -740,6 +749,41 @@ export class HandleScheduledEventUseCaseHandler {
|
|
|
740
749
|
}`,
|
|
741
750
|
);
|
|
742
751
|
}
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
const outputDegenerationResetEnabled =
|
|
755
|
+
mergedInput.outputDegenerationResetEnabled ??
|
|
756
|
+
process.env.TDPM_OUTPUT_DEGENERATION_RESET_ENABLED === 'true';
|
|
757
|
+
await resetDegeneratedTmuxSessions({
|
|
758
|
+
enabled: outputDegenerationResetEnabled,
|
|
759
|
+
localCommandRunner: nodeLocalCommandRunner,
|
|
760
|
+
warningMessage:
|
|
761
|
+
mergedInput.outputDegenerationWarningMessage ??
|
|
762
|
+
process.env.TDPM_OUTPUT_DEGENERATION_WARNING_MESSAGE ??
|
|
763
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.warningMessage,
|
|
764
|
+
graceSeconds: readSilentSeconds(
|
|
765
|
+
mergedInput.outputDegenerationGraceSeconds,
|
|
766
|
+
process.env.TDPM_OUTPUT_DEGENERATION_GRACE_SECONDS,
|
|
767
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.graceSeconds,
|
|
768
|
+
),
|
|
769
|
+
cooldownSeconds: readSilentSeconds(
|
|
770
|
+
mergedInput.outputDegenerationCooldownSeconds,
|
|
771
|
+
process.env.TDPM_OUTPUT_DEGENERATION_COOLDOWN_SECONDS,
|
|
772
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.cooldownSeconds,
|
|
773
|
+
),
|
|
774
|
+
cooldownStateFilePath:
|
|
775
|
+
mergedInput.outputDegenerationCooldownStateFilePath ??
|
|
776
|
+
process.env.TDPM_OUTPUT_DEGENERATION_COOLDOWN_STATE_FILE_PATH ??
|
|
777
|
+
null,
|
|
778
|
+
now: inTmuxNow,
|
|
779
|
+
});
|
|
780
|
+
} catch (error) {
|
|
781
|
+
console.error(
|
|
782
|
+
`Failed to reset degenerated tmux sessions: ${
|
|
783
|
+
error instanceof Error ? error.message : String(error)
|
|
784
|
+
}`,
|
|
785
|
+
);
|
|
786
|
+
}
|
|
743
787
|
}
|
|
744
788
|
return result;
|
|
745
789
|
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import {
|
|
5
|
+
resetDegeneratedTmuxSessions,
|
|
6
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS,
|
|
7
|
+
} from './resetDegeneratedTmuxSessions';
|
|
8
|
+
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
9
|
+
|
|
10
|
+
describe('resetDegeneratedTmuxSessions', () => {
|
|
11
|
+
let temporaryDirectory: string;
|
|
12
|
+
let cooldownStateFilePath: string;
|
|
13
|
+
let loggedMessages: string[];
|
|
14
|
+
let consoleLogSpy: jest.SpiedFunction<typeof console.log>;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
temporaryDirectory = fs.mkdtempSync(
|
|
18
|
+
path.join(os.tmpdir(), 'reset-degenerated-'),
|
|
19
|
+
);
|
|
20
|
+
cooldownStateFilePath = path.join(temporaryDirectory, 'cooldown.json');
|
|
21
|
+
loggedMessages = [];
|
|
22
|
+
consoleLogSpy = jest
|
|
23
|
+
.spyOn(console, 'log')
|
|
24
|
+
.mockImplementation((...args: unknown[]): void => {
|
|
25
|
+
loggedMessages.push(args.map((arg) => String(arg)).join(' '));
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
consoleLogSpy.mockRestore();
|
|
31
|
+
fs.rmSync(temporaryDirectory, { recursive: true, force: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('wires the real adapters and runs end to end without acting when no sessions exist', async () => {
|
|
35
|
+
const runCommand: jest.MockedFunction<LocalCommandRunner['runCommand']> =
|
|
36
|
+
jest.fn().mockResolvedValue({ stdout: '', stderr: '', exitCode: 0 });
|
|
37
|
+
const commandRunner: LocalCommandRunner = { runCommand };
|
|
38
|
+
|
|
39
|
+
await resetDegeneratedTmuxSessions({
|
|
40
|
+
enabled: false,
|
|
41
|
+
localCommandRunner: commandRunner,
|
|
42
|
+
warningMessage:
|
|
43
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.warningMessage,
|
|
44
|
+
graceSeconds: DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.graceSeconds,
|
|
45
|
+
cooldownSeconds:
|
|
46
|
+
DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.cooldownSeconds,
|
|
47
|
+
cooldownStateFilePath,
|
|
48
|
+
now: new Date('2026-07-26T00:00:00Z'),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const summaryLogged = loggedMessages.some((message) =>
|
|
52
|
+
message.includes(
|
|
53
|
+
'Output degeneration recovery: detected 0 degenerated session(s) of 0 interactive session(s)',
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
expect(summaryLogged).toBe(true);
|
|
57
|
+
const killInvoked = runCommand.mock.calls.some((callArguments) =>
|
|
58
|
+
callArguments[1].includes('kill-session'),
|
|
59
|
+
);
|
|
60
|
+
expect(killInvoked).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('exposes safe defaults with a five second grace and 300 second cooldown', () => {
|
|
64
|
+
expect(DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.graceSeconds).toBe(5);
|
|
65
|
+
expect(DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS.cooldownSeconds).toBe(
|
|
66
|
+
300,
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
});
|