github-issue-tower-defence-management 1.139.0 → 1.140.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +8 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +50 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +5 -2
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js +31 -0
- package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js.map +1 -0
- package/bin/adapter/repositories/FileHandoverStateRepository.js +99 -0
- package/bin/adapter/repositories/FileHandoverStateRepository.js.map +1 -0
- package/bin/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.js +125 -0
- package/bin/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.js.map +1 -0
- package/bin/adapter/repositories/NodeProcessSignalRepository.js +44 -0
- package/bin/adapter/repositories/NodeProcessSignalRepository.js.map +1 -0
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js +67 -1
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -1
- package/bin/adapter/repositories/ProcClaudeHandoverSessionRepository.js +206 -0
- package/bin/adapter/repositories/ProcClaudeHandoverSessionRepository.js.map +1 -0
- package/bin/adapter/repositories/RateLimitSnapshotRepository.js +44 -0
- package/bin/adapter/repositories/RateLimitSnapshotRepository.js.map +1 -0
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js +4 -1
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js.map +1 -1
- package/bin/domain/entities/ClaudeHandoverSession.js +3 -0
- package/bin/domain/entities/ClaudeHandoverSession.js.map +1 -0
- package/bin/domain/entities/TokenExhaustionHandoverState.js +3 -0
- package/bin/domain/entities/TokenExhaustionHandoverState.js.map +1 -0
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +48 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js +255 -0
- package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/ProcessSignalRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/ProcessSignalRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +37 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +30 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +8 -0
- package/src/adapter/entry-points/handlers/tokenExhaustionHandover.ts +79 -0
- package/src/adapter/repositories/FileHandoverStateRepository.test.ts +114 -0
- package/src/adapter/repositories/FileHandoverStateRepository.ts +76 -0
- package/src/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.test.ts +127 -0
- package/src/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.ts +108 -0
- package/src/adapter/repositories/NodeProcessSignalRepository.test.ts +82 -0
- package/src/adapter/repositories/NodeProcessSignalRepository.ts +47 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +132 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.ts +100 -0
- package/src/adapter/repositories/ProcClaudeHandoverSessionRepository.test.ts +194 -0
- package/src/adapter/repositories/ProcClaudeHandoverSessionRepository.ts +208 -0
- package/src/adapter/repositories/RateLimitSnapshotRepository.ts +50 -0
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.test.ts +23 -2
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts +5 -1
- package/src/domain/entities/ClaudeHandoverSession.ts +11 -0
- package/src/domain/entities/TokenExhaustionHandoverState.ts +8 -0
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +218 -8
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +60 -0
- package/src/domain/usecases/TokenExhaustionHandoverUseCase.test.ts +696 -0
- package/src/domain/usecases/TokenExhaustionHandoverUseCase.ts +413 -0
- package/src/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.ts +5 -0
- package/src/domain/usecases/adapter-interfaces/ProcessSignalRepository.ts +5 -0
- package/src/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.ts +10 -0
- package/src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts +2 -0
- package/src/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.ts +6 -0
- package/src/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.ts +22 -0
- package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +2 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +1 -0
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts +14 -0
- package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts.map +1 -0
- package/types/adapter/repositories/FileHandoverStateRepository.d.ts +11 -0
- package/types/adapter/repositories/FileHandoverStateRepository.d.ts.map +1 -0
- package/types/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.d.ts +16 -0
- package/types/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.d.ts.map +1 -0
- package/types/adapter/repositories/NodeProcessSignalRepository.d.ts +8 -0
- package/types/adapter/repositories/NodeProcessSignalRepository.d.ts.map +1 -0
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +7 -1
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -1
- package/types/adapter/repositories/ProcClaudeHandoverSessionRepository.d.ts +13 -0
- package/types/adapter/repositories/ProcClaudeHandoverSessionRepository.d.ts.map +1 -0
- package/types/adapter/repositories/RateLimitSnapshotRepository.d.ts +9 -0
- package/types/adapter/repositories/RateLimitSnapshotRepository.d.ts.map +1 -0
- package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts.map +1 -1
- package/types/domain/entities/ClaudeHandoverSession.d.ts +10 -0
- package/types/domain/entities/ClaudeHandoverSession.d.ts.map +1 -0
- package/types/domain/entities/TokenExhaustionHandoverState.d.ts +8 -0
- package/types/domain/entities/TokenExhaustionHandoverState.d.ts.map +1 -0
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +3 -1
- package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
- package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts +50 -0
- package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.d.ts +5 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/ProcessSignalRepository.d.ts +6 -0
- package/types/domain/usecases/adapter-interfaces/ProcessSignalRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.d.ts +11 -0
- package/types/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts +2 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.d.ts +6 -0
- package/types/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.d.ts +21 -0
- package/types/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.d.ts.map +1 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { ClaudeHandoverSession } from '../entities/ClaudeHandoverSession';
|
|
2
|
+
import {
|
|
3
|
+
TokenExhaustionHandoverState,
|
|
4
|
+
TokenExhaustionHandoverStateEntry,
|
|
5
|
+
} from '../entities/TokenExhaustionHandoverState';
|
|
6
|
+
import { ClaudeHandoverSessionRepository } from './adapter-interfaces/ClaudeHandoverSessionRepository';
|
|
7
|
+
import { ProcessSignalRepository } from './adapter-interfaces/ProcessSignalRepository';
|
|
8
|
+
import { TmuxSessionRepository } from './adapter-interfaces/TmuxSessionRepository';
|
|
9
|
+
import {
|
|
10
|
+
TokenModelWeeklyLimit,
|
|
11
|
+
TokenRateLimitSnapshot,
|
|
12
|
+
TokenRateLimitSnapshotRepository,
|
|
13
|
+
} from './adapter-interfaces/TokenRateLimitSnapshotRepository';
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_TOKEN_EXHAUSTION_HANDOVER_MESSAGE =
|
|
16
|
+
'TOKEN NEAR EXHAUSTION. Within 2 minutes, write a CHECKPOINT to your assigned task issue: the in-flight subagents and what each is doing, their durable refs (branch and pull request URLs), the working directory and branch, the single concrete next action to resume, and the reason (token near exhaustion). Do this WITHOUT waiting for long-running or CI-watching subagents. Then self-kill your own tmux session with `tmux kill-session`.';
|
|
17
|
+
|
|
18
|
+
export const DEFAULT_TOKEN_EXHAUSTION_HANDOVER_MESSAGE_BARE_NAME_LEADER =
|
|
19
|
+
'TOKEN NEAR EXHAUSTION. You are a resident leader with no assigned task issue. Within 2 minutes, write a CHECKPOINT for every in-flight subagent (what each is doing and its durable refs = branch and pull request URLs, plus the single concrete next action to resume and the working directory and branch) into the GitHub issue that each subagent is working on, WITHOUT waiting for long-running or CI-watching subagents. Then stop and stay idle; do NOT self-kill. This session will be terminated and relaunched on a token that still has quota so its work is preserved.';
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_TOKEN_EXHAUSTION_GRACE_PERIOD_SECONDS = 180;
|
|
22
|
+
export const TOKEN_EXHAUSTION_SNAPSHOT_STALE_THRESHOLD_SECONDS = 900;
|
|
23
|
+
export const TOKEN_EXHAUSTION_SNAPSHOT_HARD_STALE_THRESHOLD_SECONDS = 3600;
|
|
24
|
+
export const TOKEN_EXHAUSTION_FIVE_HOUR_FREE_THRESHOLD = 0.1;
|
|
25
|
+
export const TOKEN_EXHAUSTION_SEVEN_DAY_FREE_THRESHOLD = 0.05;
|
|
26
|
+
export const TOKEN_EXHAUSTION_FIVE_HOUR_WARNING_FREE_THRESHOLD = 0.25;
|
|
27
|
+
export const TOKEN_EXHAUSTION_SEVEN_DAY_WARNING_FREE_THRESHOLD = 0.15;
|
|
28
|
+
|
|
29
|
+
type SnapshotVerdict = {
|
|
30
|
+
stale: boolean;
|
|
31
|
+
exhausted: boolean;
|
|
32
|
+
reason: string;
|
|
33
|
+
fiveHourFree: number;
|
|
34
|
+
sevenDayFree: number;
|
|
35
|
+
blocked: boolean;
|
|
36
|
+
weeklyCapped: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type TokenExhaustionHandoverInput = {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
issueUrlLeaderMessage: string;
|
|
42
|
+
bareNameLeaderMessage: string;
|
|
43
|
+
gracePeriodSeconds: number;
|
|
44
|
+
state: TokenExhaustionHandoverState;
|
|
45
|
+
now: Date;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type TokenExhaustionHandoverResult = {
|
|
49
|
+
newlyHandoverSentSessionNames: string[];
|
|
50
|
+
killedSessionNames: string[];
|
|
51
|
+
terminatedPids: number[];
|
|
52
|
+
relaunchedLeaderNames: string[];
|
|
53
|
+
leftAliveSessionNames: string[];
|
|
54
|
+
state: TokenExhaustionHandoverState;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export class TokenExhaustionHandoverUseCase {
|
|
58
|
+
constructor(
|
|
59
|
+
private readonly handoverSessionRepository: Pick<
|
|
60
|
+
ClaudeHandoverSessionRepository,
|
|
61
|
+
'listHandoverSessions'
|
|
62
|
+
>,
|
|
63
|
+
private readonly snapshotRepository: Pick<
|
|
64
|
+
TokenRateLimitSnapshotRepository,
|
|
65
|
+
'listSnapshots'
|
|
66
|
+
>,
|
|
67
|
+
private readonly tmuxSessionRepository: Pick<
|
|
68
|
+
TmuxSessionRepository,
|
|
69
|
+
| 'sendKeys'
|
|
70
|
+
| 'killSession'
|
|
71
|
+
| 'listLiveSessionNames'
|
|
72
|
+
| 'launchBareNameLeaderSession'
|
|
73
|
+
>,
|
|
74
|
+
private readonly processSignalRepository: ProcessSignalRepository,
|
|
75
|
+
) {}
|
|
76
|
+
|
|
77
|
+
run = async (
|
|
78
|
+
input: TokenExhaustionHandoverInput,
|
|
79
|
+
): Promise<TokenExhaustionHandoverResult> => {
|
|
80
|
+
const nowEpochSeconds = Math.floor(input.now.getTime() / 1000);
|
|
81
|
+
const sessions = this.handoverSessionRepository.listHandoverSessions();
|
|
82
|
+
const snapshots = this.snapshotRepository.listSnapshots();
|
|
83
|
+
const snapshotByToken = new Map(
|
|
84
|
+
snapshots.map((snapshot) => [snapshot.token, snapshot]),
|
|
85
|
+
);
|
|
86
|
+
const liveSessionNames = new Set(
|
|
87
|
+
await this.tmuxSessionRepository.listLiveSessionNames(),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const nextEntries: Record<string, TokenExhaustionHandoverStateEntry> = {
|
|
91
|
+
...input.state.entries,
|
|
92
|
+
};
|
|
93
|
+
const newlyHandoverSentSessionNames: string[] = [];
|
|
94
|
+
const killedSessionNames: string[] = [];
|
|
95
|
+
const terminatedPids: number[] = [];
|
|
96
|
+
const relaunchedLeaderNames: string[] = [];
|
|
97
|
+
const leftAliveSessionNames: string[] = [];
|
|
98
|
+
|
|
99
|
+
for (const session of sessions) {
|
|
100
|
+
try {
|
|
101
|
+
const snapshot = snapshotByToken.get(session.token);
|
|
102
|
+
if (snapshot === undefined) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const hasTmux = session.kind !== 'implSubagent';
|
|
106
|
+
const verdict = this.evaluateSnapshot(
|
|
107
|
+
snapshot,
|
|
108
|
+
nowEpochSeconds,
|
|
109
|
+
hasTmux,
|
|
110
|
+
);
|
|
111
|
+
const stateKey = this.stateKeyFor(session);
|
|
112
|
+
|
|
113
|
+
if (verdict.stale) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!verdict.exhausted) {
|
|
117
|
+
delete nextEntries[stateKey];
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (
|
|
121
|
+
!this.isFresherTokenAvailable(
|
|
122
|
+
session.token,
|
|
123
|
+
snapshots,
|
|
124
|
+
nowEpochSeconds,
|
|
125
|
+
)
|
|
126
|
+
) {
|
|
127
|
+
console.log(
|
|
128
|
+
`Token exhaustion handover: leaving ${this.displayName(session)} alive (token pool globally exhausted, no fresher token available)`,
|
|
129
|
+
);
|
|
130
|
+
leftAliveSessionNames.push(this.displayName(session));
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const entry = nextEntries[stateKey];
|
|
135
|
+
if (entry === undefined) {
|
|
136
|
+
if (input.enabled) {
|
|
137
|
+
await this.sendHandover(session, input);
|
|
138
|
+
}
|
|
139
|
+
console.log(
|
|
140
|
+
`Token exhaustion handover: signaled ${this.displayName(session)} kind=${session.kind} reason=${verdict.reason} enabled=${input.enabled}`,
|
|
141
|
+
);
|
|
142
|
+
nextEntries[stateKey] = {
|
|
143
|
+
signaledAtEpoch: nowEpochSeconds,
|
|
144
|
+
pid: session.pid,
|
|
145
|
+
};
|
|
146
|
+
newlyHandoverSentSessionNames.push(this.displayName(session));
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
nowEpochSeconds - entry.signaledAtEpoch <
|
|
152
|
+
input.gracePeriodSeconds
|
|
153
|
+
) {
|
|
154
|
+
console.log(
|
|
155
|
+
`Token exhaustion handover: waiting for grace period for ${this.displayName(session)} remainingSeconds=${input.gracePeriodSeconds - (nowEpochSeconds - entry.signaledAtEpoch)}`,
|
|
156
|
+
);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const alive = hasTmux
|
|
161
|
+
? session.sessionName !== null &&
|
|
162
|
+
liveSessionNames.has(session.sessionName)
|
|
163
|
+
: this.processSignalRepository.isProcessAlive(entry.pid);
|
|
164
|
+
if (!alive) {
|
|
165
|
+
if (input.enabled && this.needsRelaunch(session)) {
|
|
166
|
+
await this.relaunchBareNameLeader(session, relaunchedLeaderNames);
|
|
167
|
+
}
|
|
168
|
+
delete nextEntries[stateKey];
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!input.enabled) {
|
|
173
|
+
console.log(
|
|
174
|
+
`Token exhaustion handover: would force-kill ${this.displayName(session)} kind=${session.kind} (dry-run, enabled=false)`,
|
|
175
|
+
);
|
|
176
|
+
delete nextEntries[stateKey];
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await this.forceKill(session, entry);
|
|
181
|
+
if (this.needsRelaunch(session)) {
|
|
182
|
+
await this.relaunchBareNameLeader(session, relaunchedLeaderNames);
|
|
183
|
+
}
|
|
184
|
+
console.log(
|
|
185
|
+
`Token exhaustion handover: force-killed ${this.displayName(session)} kind=${session.kind}`,
|
|
186
|
+
);
|
|
187
|
+
if (hasTmux) {
|
|
188
|
+
killedSessionNames.push(this.displayName(session));
|
|
189
|
+
} else {
|
|
190
|
+
terminatedPids.push(entry.pid);
|
|
191
|
+
}
|
|
192
|
+
delete nextEntries[stateKey];
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error(
|
|
195
|
+
`Token exhaustion handover: error processing ${this.displayName(session)}: ${
|
|
196
|
+
error instanceof Error ? error.message : String(error)
|
|
197
|
+
}`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(
|
|
203
|
+
`Token exhaustion handover: cycle summary evaluated=${sessions.length} enabled=${input.enabled} signaled=${newlyHandoverSentSessionNames.length} killed=${killedSessionNames.length} terminatedPids=${terminatedPids.length} relaunched=${relaunchedLeaderNames.length} leftAlive=${leftAliveSessionNames.length}`,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
newlyHandoverSentSessionNames,
|
|
208
|
+
killedSessionNames,
|
|
209
|
+
terminatedPids,
|
|
210
|
+
relaunchedLeaderNames,
|
|
211
|
+
leftAliveSessionNames,
|
|
212
|
+
state: { entries: nextEntries },
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
private needsRelaunch = (session: ClaudeHandoverSession): boolean =>
|
|
217
|
+
session.kind === 'bareNameLeader' && session.name !== null;
|
|
218
|
+
|
|
219
|
+
private relaunchBareNameLeader = async (
|
|
220
|
+
session: ClaudeHandoverSession,
|
|
221
|
+
relaunchedLeaderNames: string[],
|
|
222
|
+
): Promise<void> => {
|
|
223
|
+
if (session.name === null) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
await this.tmuxSessionRepository.launchBareNameLeaderSession(session.name);
|
|
227
|
+
relaunchedLeaderNames.push(session.name);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
private sendHandover = async (
|
|
231
|
+
session: ClaudeHandoverSession,
|
|
232
|
+
input: TokenExhaustionHandoverInput,
|
|
233
|
+
): Promise<void> => {
|
|
234
|
+
if (session.kind === 'implSubagent') {
|
|
235
|
+
this.processSignalRepository.terminateProcess(session.pid);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (session.sessionName === null) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const message =
|
|
242
|
+
session.kind === 'issueUrlLeader'
|
|
243
|
+
? input.issueUrlLeaderMessage
|
|
244
|
+
: input.bareNameLeaderMessage;
|
|
245
|
+
await this.tmuxSessionRepository.sendKeys(session.sessionName, message);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
private forceKill = async (
|
|
249
|
+
session: ClaudeHandoverSession,
|
|
250
|
+
entry: TokenExhaustionHandoverStateEntry,
|
|
251
|
+
): Promise<void> => {
|
|
252
|
+
if (session.kind === 'implSubagent') {
|
|
253
|
+
this.processSignalRepository.killProcess(entry.pid);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (session.sessionName !== null) {
|
|
257
|
+
try {
|
|
258
|
+
await this.tmuxSessionRepository.killSession(session.sessionName);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error(
|
|
261
|
+
`Token exhaustion handover: killSession failed for ${session.sessionName}: ${
|
|
262
|
+
error instanceof Error ? error.message : String(error)
|
|
263
|
+
}`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
this.processSignalRepository.killProcess(entry.pid);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
private stateKeyFor = (session: ClaudeHandoverSession): string =>
|
|
271
|
+
session.kind === 'implSubagent'
|
|
272
|
+
? `pid:${session.pid}`
|
|
273
|
+
: (session.sessionName ?? `pid:${session.pid}`);
|
|
274
|
+
|
|
275
|
+
private displayName = (session: ClaudeHandoverSession): string =>
|
|
276
|
+
session.sessionName ?? `pid:${session.pid}`;
|
|
277
|
+
|
|
278
|
+
private isFresherTokenAvailable = (
|
|
279
|
+
currentToken: string,
|
|
280
|
+
snapshots: TokenRateLimitSnapshot[],
|
|
281
|
+
nowEpochSeconds: number,
|
|
282
|
+
): boolean => {
|
|
283
|
+
for (const snapshot of snapshots) {
|
|
284
|
+
if (snapshot.token === currentToken) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
const verdict = this.evaluateSnapshot(snapshot, nowEpochSeconds, true);
|
|
288
|
+
if (!verdict.stale && !verdict.exhausted) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
private evaluateSnapshot = (
|
|
296
|
+
snapshot: TokenRateLimitSnapshot,
|
|
297
|
+
nowEpochSeconds: number,
|
|
298
|
+
hasTmux: boolean,
|
|
299
|
+
): SnapshotVerdict => {
|
|
300
|
+
const age = nowEpochSeconds - snapshot.lastUpdatedEpoch;
|
|
301
|
+
const fiveHourFree = this.freeRatio(
|
|
302
|
+
snapshot.fiveHourUtilization,
|
|
303
|
+
snapshot.fiveHourReset,
|
|
304
|
+
nowEpochSeconds,
|
|
305
|
+
);
|
|
306
|
+
const sevenDayFree = this.freeRatio(
|
|
307
|
+
snapshot.sevenDayUtilization,
|
|
308
|
+
snapshot.sevenDayReset,
|
|
309
|
+
nowEpochSeconds,
|
|
310
|
+
);
|
|
311
|
+
const blocked =
|
|
312
|
+
snapshot.blocked ||
|
|
313
|
+
snapshot.rejected ||
|
|
314
|
+
snapshot.blockedUntilEpoch > nowEpochSeconds;
|
|
315
|
+
const weeklyCapped = this.isWeeklyCapped(
|
|
316
|
+
snapshot.modelWeeklyLimits,
|
|
317
|
+
nowEpochSeconds,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (age > TOKEN_EXHAUSTION_SNAPSHOT_HARD_STALE_THRESHOLD_SECONDS) {
|
|
321
|
+
return {
|
|
322
|
+
stale: true,
|
|
323
|
+
exhausted: false,
|
|
324
|
+
reason: 'hard_stale',
|
|
325
|
+
fiveHourFree,
|
|
326
|
+
sevenDayFree,
|
|
327
|
+
blocked,
|
|
328
|
+
weeklyCapped,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const inWarningBand =
|
|
333
|
+
fiveHourFree < TOKEN_EXHAUSTION_FIVE_HOUR_WARNING_FREE_THRESHOLD ||
|
|
334
|
+
sevenDayFree < TOKEN_EXHAUSTION_SEVEN_DAY_WARNING_FREE_THRESHOLD ||
|
|
335
|
+
blocked ||
|
|
336
|
+
weeklyCapped;
|
|
337
|
+
if (
|
|
338
|
+
age > TOKEN_EXHAUSTION_SNAPSHOT_STALE_THRESHOLD_SECONDS &&
|
|
339
|
+
!inWarningBand
|
|
340
|
+
) {
|
|
341
|
+
return {
|
|
342
|
+
stale: true,
|
|
343
|
+
exhausted: false,
|
|
344
|
+
reason: 'stale_healthy',
|
|
345
|
+
fiveHourFree,
|
|
346
|
+
sevenDayFree,
|
|
347
|
+
blocked,
|
|
348
|
+
weeklyCapped,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const exhausted =
|
|
353
|
+
fiveHourFree < TOKEN_EXHAUSTION_FIVE_HOUR_FREE_THRESHOLD ||
|
|
354
|
+
(hasTmux && sevenDayFree < TOKEN_EXHAUSTION_SEVEN_DAY_FREE_THRESHOLD) ||
|
|
355
|
+
blocked ||
|
|
356
|
+
weeklyCapped;
|
|
357
|
+
const reason = weeklyCapped
|
|
358
|
+
? 'weekly_hard_cap_rejected'
|
|
359
|
+
: fiveHourFree < TOKEN_EXHAUSTION_FIVE_HOUR_FREE_THRESHOLD
|
|
360
|
+
? 'five_hour_free_below_threshold'
|
|
361
|
+
: hasTmux && sevenDayFree < TOKEN_EXHAUSTION_SEVEN_DAY_FREE_THRESHOLD
|
|
362
|
+
? 'seven_day_free_below_threshold'
|
|
363
|
+
: blocked
|
|
364
|
+
? 'blocked_or_rejected'
|
|
365
|
+
: 'healthy';
|
|
366
|
+
return {
|
|
367
|
+
stale: false,
|
|
368
|
+
exhausted,
|
|
369
|
+
reason,
|
|
370
|
+
fiveHourFree,
|
|
371
|
+
sevenDayFree,
|
|
372
|
+
blocked,
|
|
373
|
+
weeklyCapped,
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
private freeRatio = (
|
|
378
|
+
utilization: number,
|
|
379
|
+
resetEpoch: number,
|
|
380
|
+
nowEpochSeconds: number,
|
|
381
|
+
): number => {
|
|
382
|
+
if (resetEpoch > 0 && nowEpochSeconds > resetEpoch) {
|
|
383
|
+
return 1;
|
|
384
|
+
}
|
|
385
|
+
return 1 - this.clamp01(utilization);
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
private clamp01 = (value: number): number => {
|
|
389
|
+
if (value < 0) {
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
if (value > 1) {
|
|
393
|
+
return 1;
|
|
394
|
+
}
|
|
395
|
+
return value;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
private isWeeklyCapped = (
|
|
399
|
+
modelWeeklyLimits: TokenModelWeeklyLimit[],
|
|
400
|
+
nowEpochSeconds: number,
|
|
401
|
+
): boolean => {
|
|
402
|
+
for (const limit of modelWeeklyLimits) {
|
|
403
|
+
if (!limit.rejected) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (limit.resetsAt > 0 && nowEpochSeconds > limit.resetsAt) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
return false;
|
|
412
|
+
};
|
|
413
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SilentSessionNotifiedStateRepository {
|
|
2
|
+
loadRecentNotifiedSessionNames: (params: {
|
|
3
|
+
now: Date;
|
|
4
|
+
recencyWindowSeconds: number;
|
|
5
|
+
}) => Promise<Set<string>>;
|
|
6
|
+
saveNotifiedSessionNames: (params: {
|
|
7
|
+
sessionNames: string[];
|
|
8
|
+
now: Date;
|
|
9
|
+
}) => Promise<void>;
|
|
10
|
+
}
|
|
@@ -11,4 +11,6 @@ export interface TmuxSessionRepository {
|
|
|
11
11
|
) => Promise<void>;
|
|
12
12
|
killSession: (sessionName: string) => Promise<void>;
|
|
13
13
|
killOwnSession: () => Promise<void>;
|
|
14
|
+
sendKeys: (sessionName: string, literalText: string) => Promise<void>;
|
|
15
|
+
launchBareNameLeaderSession: (name: string) => Promise<void>;
|
|
14
16
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type TokenModelWeeklyLimit = {
|
|
2
|
+
rejected: boolean;
|
|
3
|
+
resetsAt: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type TokenRateLimitSnapshot = {
|
|
7
|
+
token: string;
|
|
8
|
+
name: string;
|
|
9
|
+
fiveHourUtilization: number;
|
|
10
|
+
fiveHourReset: number;
|
|
11
|
+
sevenDayUtilization: number;
|
|
12
|
+
sevenDayReset: number;
|
|
13
|
+
blocked: boolean;
|
|
14
|
+
rejected: boolean;
|
|
15
|
+
blockedUntilEpoch: number;
|
|
16
|
+
modelWeeklyLimits: TokenModelWeeklyLimit[];
|
|
17
|
+
lastUpdatedEpoch: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export interface TokenRateLimitSnapshotRepository {
|
|
21
|
+
listSnapshots: () => TokenRateLimitSnapshot[];
|
|
22
|
+
}
|
|
@@ -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":"AAqCA,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,CAsoBP;CACH"}
|
|
@@ -18,6 +18,7 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
18
18
|
staggerSeconds: number;
|
|
19
19
|
candidateDebounceRecencyWindowSeconds: number;
|
|
20
20
|
candidateDebounceStateFilePath: string | null;
|
|
21
|
+
notifiedStateFilePath: string | null;
|
|
21
22
|
activeHubTaskStatus: string | null;
|
|
22
23
|
hubTaskStatusResolver: HubTaskStatusResolver | null;
|
|
23
24
|
hubTaskStatusCacheStateFilePath: string | null;
|
|
@@ -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,EAQtB,MAAM,0DAA0D,CAAC;AAgBlE,OAAO,EAEL,6BAA6B,EAC9B,MAAM,6DAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"notifySilentTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAGpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AACxG,OAAO,EAEL,qBAAqB,EAQtB,MAAM,0DAA0D,CAAC;AAgBlE,OAAO,EAEL,6BAA6B,EAC9B,MAAM,6DAA6D,CAAC;AAMrE,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,4BAA4B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,0BAA0B,EAAE,MAAM,CAAC;IACnC,+BAA+B,EAAE,MAAM,CAAC;IACxC,8BAA8B,EAAE,MAAM,CAAC;IACvC,+BAA+B,EAAE,MAAM,CAAC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC,EAAE,MAAM,CAAC;IAC9C,8BAA8B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qBAAqB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACpD,+BAA+B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,4BAA4B,EAAE,MAAM,CAAC;IACrC,gBAAgB,EAAE,6BAA6B,CAAC;IAChD,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAuCF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,8BAA8B,KACrC,OAAO,CAAC,IAAI,CAmFd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;;;CAS7C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
2
|
+
export type TokenExhaustionHandoverParams = {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
tokenListJsonPath: string | null;
|
|
5
|
+
handoverMessage?: string | null;
|
|
6
|
+
bareNameLeaderHandoverMessage?: string | null;
|
|
7
|
+
tokenRateLimitSnapshotBaseDir?: string | null;
|
|
8
|
+
gracePeriodSeconds?: number | null;
|
|
9
|
+
stateFilePath?: string | null;
|
|
10
|
+
localCommandRunner: LocalCommandRunner;
|
|
11
|
+
now: Date;
|
|
12
|
+
};
|
|
13
|
+
export declare const handleTokenExhaustionHandover: (params: TokenExhaustionHandoverParams) => Promise<void>;
|
|
14
|
+
//# sourceMappingURL=tokenExhaustionHandover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenExhaustionHandover.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenExhaustionHandover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAgBpG,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,QAAQ,6BAA6B,KACpC,OAAO,CAAC,IAAI,CAgDd,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TokenExhaustionHandoverState } from '../../domain/entities/TokenExhaustionHandoverState';
|
|
2
|
+
import { TokenExhaustionHandoverStateRepository } from '../../domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository';
|
|
3
|
+
export declare const defaultHandoverStateFilePath: () => string;
|
|
4
|
+
export declare class FileHandoverStateRepository implements TokenExhaustionHandoverStateRepository {
|
|
5
|
+
private readonly filePath;
|
|
6
|
+
constructor(filePath?: string);
|
|
7
|
+
load: () => TokenExhaustionHandoverState;
|
|
8
|
+
save: (state: TokenExhaustionHandoverState) => void;
|
|
9
|
+
private parseEntries;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=FileHandoverStateRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileHandoverStateRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileHandoverStateRepository.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,4BAA4B,EAE7B,MAAM,oDAAoD,CAAC;AAC5D,OAAO,EAAE,sCAAsC,EAAE,MAAM,iFAAiF,CAAC;AAEzI,eAAO,MAAM,4BAA4B,QAAO,MAO/C,CAAC;AAKF,qBAAa,2BAA4B,YAAW,sCAAsC;IAEtF,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,GAAE,MAAuC;IAGpE,IAAI,QAAO,4BAA4B,CAcrC;IAEF,IAAI,GAAI,OAAO,4BAA4B,KAAG,IAAI,CAQhD;IAEF,OAAO,CAAC,YAAY,CAsBlB;CACH"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SilentSessionNotifiedStateRepository } from '../../domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository';
|
|
2
|
+
export declare class FileSystemSilentSessionNotifiedStateRepository implements SilentSessionNotifiedStateRepository {
|
|
3
|
+
private readonly stateFilePath;
|
|
4
|
+
constructor(stateFilePath?: string);
|
|
5
|
+
loadRecentNotifiedSessionNames: (params: {
|
|
6
|
+
now: Date;
|
|
7
|
+
recencyWindowSeconds: number;
|
|
8
|
+
}) => Promise<Set<string>>;
|
|
9
|
+
saveNotifiedSessionNames: (params: {
|
|
10
|
+
sessionNames: string[];
|
|
11
|
+
now: Date;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
private readNotifiedEntries;
|
|
14
|
+
private writeState;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=FileSystemSilentSessionNotifiedStateRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileSystemSilentSessionNotifiedStateRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oCAAoC,EAAE,MAAM,+EAA+E,CAAC;AAuBrI,qBAAa,8CAA+C,YAAW,oCAAoC;IAEvG,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,GAAE,MAA+B;IAGjE,8BAA8B,GAAU,QAAQ;QAC9C,GAAG,EAAE,IAAI,CAAC;QACV,oBAAoB,EAAE,MAAM,CAAC;KAC9B,KAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAWtB;IAEF,wBAAwB,GAAU,QAAQ;QACxC,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,GAAG,EAAE,IAAI,CAAC;KACX,KAAG,OAAO,CAAC,IAAI,CAAC,CAUf;IAEF,OAAO,CAAC,mBAAmB,CAoCzB;IAEF,OAAO,CAAC,UAAU,CAMhB;CACH"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ProcessSignalRepository } from '../../domain/usecases/adapter-interfaces/ProcessSignalRepository';
|
|
2
|
+
export declare class NodeProcessSignalRepository implements ProcessSignalRepository {
|
|
3
|
+
isProcessAlive: (pid: number) => boolean;
|
|
4
|
+
terminateProcess: (pid: number) => void;
|
|
5
|
+
killProcess: (pid: number) => void;
|
|
6
|
+
private signal;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=NodeProcessSignalRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeProcessSignalRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeProcessSignalRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AAc3G,qBAAa,2BAA4B,YAAW,uBAAuB;IACzE,cAAc,GAAI,KAAK,MAAM,KAAG,OAAO,CAOrC;IAEF,gBAAgB,GAAI,KAAK,MAAM,KAAG,IAAI,CAEpC;IAEF,WAAW,GAAI,KAAK,MAAM,KAAG,IAAI,CAE/B;IAEF,OAAO,CAAC,MAAM,CAaZ;CACH"}
|
|
@@ -4,7 +4,8 @@ import { LiveTmuxSession } from '../../domain/entities/LiveTmuxSession';
|
|
|
4
4
|
export declare class NodeTmuxSessionRepository implements TmuxSessionRepository {
|
|
5
5
|
private readonly localCommandRunner;
|
|
6
6
|
private readonly procDirectory;
|
|
7
|
-
|
|
7
|
+
private readonly submitDelayMilliseconds;
|
|
8
|
+
constructor(localCommandRunner: LocalCommandRunner, procDirectory?: string, submitDelayMilliseconds?: number);
|
|
8
9
|
listLiveSessionNames: () => Promise<string[]>;
|
|
9
10
|
listLiveSessionsWithActivity: () => Promise<LiveTmuxSession[]>;
|
|
10
11
|
listInteractiveProcessCommandLines: () => Promise<string[]>;
|
|
@@ -12,5 +13,10 @@ export declare class NodeTmuxSessionRepository implements TmuxSessionRepository
|
|
|
12
13
|
killSession: (sessionName: string) => Promise<void>;
|
|
13
14
|
killOwnSession: () => Promise<void>;
|
|
14
15
|
private stopScopeUnit;
|
|
16
|
+
sendKeys: (sessionName: string, literalText: string) => Promise<void>;
|
|
17
|
+
launchBareNameLeaderSession: (name: string) => Promise<void>;
|
|
18
|
+
private sendEnter;
|
|
19
|
+
private messageStillInComposer;
|
|
20
|
+
private delaySubmit;
|
|
15
21
|
}
|
|
16
22
|
//# sourceMappingURL=NodeTmuxSessionRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeTmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeTmuxSessionRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeTmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeTmuxSessionRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAWxE,qBAAa,yBAA0B,YAAW,qBAAqB;IAEnE,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,uBAAuB;gBAFvB,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,GAAE,MAAgB,EAC/B,uBAAuB,GAAE,MAA0C;IAGtF,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAYhD;IAEF,4BAA4B,QAAa,OAAO,CAAC,eAAe,EAAE,CAAC,CAkBjE;IAEF,kCAAkC,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAY9D;IAEF,qBAAqB,GACnB,aAAa,MAAM,EACnB,iBAAiB,MAAM,EACvB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAcd;IAEF,WAAW,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CActD;IAEF,cAAc,QAAa,OAAO,CAAC,IAAI,CAAC,CAatC;IAEF,OAAO,CAAC,aAAa,CAsBnB;IAEF,QAAQ,GACN,aAAa,MAAM,EACnB,aAAa,MAAM,KAClB,OAAO,CAAC,IAAI,CAAC,CAqBd;IAEF,2BAA2B,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAc/D;IAEF,OAAO,CAAC,SAAS,CAcf;IAEF,OAAO,CAAC,sBAAsB,CAuB5B;IAEF,OAAO,CAAC,WAAW,CAOjB;CACH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ClaudeHandoverSession } from '../../domain/entities/ClaudeHandoverSession';
|
|
2
|
+
import { ClaudeHandoverSessionRepository } from '../../domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository';
|
|
3
|
+
export declare class ProcClaudeHandoverSessionRepository implements ClaudeHandoverSessionRepository {
|
|
4
|
+
private readonly procDirectory;
|
|
5
|
+
constructor(procDirectory?: string);
|
|
6
|
+
listHandoverSessions: () => ClaudeHandoverSession[];
|
|
7
|
+
private listProcessIdDirectories;
|
|
8
|
+
private readHandoverSession;
|
|
9
|
+
private readComm;
|
|
10
|
+
private readCommandArguments;
|
|
11
|
+
private readEnviron;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ProcClaudeHandoverSessionRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcClaudeHandoverSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/ProcClaudeHandoverSessionRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,qBAAqB,EAEtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,+BAA+B,EAAE,MAAM,0EAA0E,CAAC;AAoG3H,qBAAa,mCAAoC,YAAW,+BAA+B;IAEvF,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,GAAE,MAA+B;IAGjE,oBAAoB,QAAO,qBAAqB,EAAE,CAShD;IAEF,OAAO,CAAC,wBAAwB,CAQ9B;IAEF,OAAO,CAAC,mBAAmB,CAiBzB;IAEF,OAAO,CAAC,QAAQ,CAOd;IAEF,OAAO,CAAC,oBAAoB,CAe1B;IAEF,OAAO,CAAC,WAAW,CA6BjB;CACH"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TokenRateLimitSnapshot, TokenRateLimitSnapshotRepository } from '../../domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository';
|
|
2
|
+
export declare class RateLimitSnapshotRepository implements TokenRateLimitSnapshotRepository {
|
|
3
|
+
private readonly tokenListJsonPath;
|
|
4
|
+
private readonly baseDir;
|
|
5
|
+
constructor(tokenListJsonPath: string, baseDir?: string);
|
|
6
|
+
listSnapshots: () => TokenRateLimitSnapshot[];
|
|
7
|
+
private toModelWeeklyLimits;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=RateLimitSnapshotRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimitSnapshotRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/RateLimitSnapshotRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EACtB,gCAAgC,EACjC,MAAM,2EAA2E,CAAC;AAInF,qBAAa,2BAA4B,YAAW,gCAAgC;IAEhF,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,MAAmB;IAG/C,aAAa,QAAO,sBAAsB,EAAE,CA0B1C;IAEF,OAAO,CAAC,mBAAmB,CAMrB;CACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TmuxSilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;AACnI,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"TmuxSilentSessionNotificationRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,8EAA8E,CAAC;AACnI,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AAKjG,qBAAa,uCAAwC,YAAW,mCAAmC;IACrF,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,kBAAkB;IAEnE,yBAAyB,GACvB,aAAa,MAAM,EACnB,SAAS,MAAM,KACd,OAAO,CAAC,IAAI,CAAC,CA6Bd;CACH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ClaudeHandoverSessionKind = 'issueUrlLeader' | 'bareNameLeader' | 'implSubagent';
|
|
2
|
+
export type ClaudeHandoverSession = {
|
|
3
|
+
kind: ClaudeHandoverSessionKind;
|
|
4
|
+
pid: number;
|
|
5
|
+
token: string;
|
|
6
|
+
sessionName: string | null;
|
|
7
|
+
name: string | null;
|
|
8
|
+
issueUrl: string | null;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=ClaudeHandoverSession.d.ts.map
|