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.
Files changed (109) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +8 -2
  3. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +50 -2
  4. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  5. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +5 -2
  6. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
  7. package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js +31 -0
  8. package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js.map +1 -0
  9. package/bin/adapter/repositories/FileHandoverStateRepository.js +99 -0
  10. package/bin/adapter/repositories/FileHandoverStateRepository.js.map +1 -0
  11. package/bin/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.js +125 -0
  12. package/bin/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.js.map +1 -0
  13. package/bin/adapter/repositories/NodeProcessSignalRepository.js +44 -0
  14. package/bin/adapter/repositories/NodeProcessSignalRepository.js.map +1 -0
  15. package/bin/adapter/repositories/NodeTmuxSessionRepository.js +67 -1
  16. package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -1
  17. package/bin/adapter/repositories/ProcClaudeHandoverSessionRepository.js +206 -0
  18. package/bin/adapter/repositories/ProcClaudeHandoverSessionRepository.js.map +1 -0
  19. package/bin/adapter/repositories/RateLimitSnapshotRepository.js +44 -0
  20. package/bin/adapter/repositories/RateLimitSnapshotRepository.js.map +1 -0
  21. package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js +4 -1
  22. package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js.map +1 -1
  23. package/bin/domain/entities/ClaudeHandoverSession.js +3 -0
  24. package/bin/domain/entities/ClaudeHandoverSession.js.map +1 -0
  25. package/bin/domain/entities/TokenExhaustionHandoverState.js +3 -0
  26. package/bin/domain/entities/TokenExhaustionHandoverState.js.map +1 -0
  27. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +48 -1
  28. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
  29. package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js +255 -0
  30. package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js.map +1 -0
  31. package/bin/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.js +3 -0
  32. package/bin/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.js.map +1 -0
  33. package/bin/domain/usecases/adapter-interfaces/ProcessSignalRepository.js +3 -0
  34. package/bin/domain/usecases/adapter-interfaces/ProcessSignalRepository.js.map +1 -0
  35. package/bin/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.js +3 -0
  36. package/bin/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.js.map +1 -0
  37. package/bin/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.js +3 -0
  38. package/bin/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.js.map +1 -0
  39. package/bin/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.js +3 -0
  40. package/bin/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.js.map +1 -0
  41. package/package.json +1 -1
  42. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +37 -0
  43. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +30 -0
  44. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +8 -0
  45. package/src/adapter/entry-points/handlers/tokenExhaustionHandover.ts +79 -0
  46. package/src/adapter/repositories/FileHandoverStateRepository.test.ts +114 -0
  47. package/src/adapter/repositories/FileHandoverStateRepository.ts +76 -0
  48. package/src/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.test.ts +127 -0
  49. package/src/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.ts +108 -0
  50. package/src/adapter/repositories/NodeProcessSignalRepository.test.ts +82 -0
  51. package/src/adapter/repositories/NodeProcessSignalRepository.ts +47 -0
  52. package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +132 -0
  53. package/src/adapter/repositories/NodeTmuxSessionRepository.ts +100 -0
  54. package/src/adapter/repositories/ProcClaudeHandoverSessionRepository.test.ts +194 -0
  55. package/src/adapter/repositories/ProcClaudeHandoverSessionRepository.ts +208 -0
  56. package/src/adapter/repositories/RateLimitSnapshotRepository.ts +50 -0
  57. package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.test.ts +23 -2
  58. package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts +5 -1
  59. package/src/domain/entities/ClaudeHandoverSession.ts +11 -0
  60. package/src/domain/entities/TokenExhaustionHandoverState.ts +8 -0
  61. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +218 -8
  62. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +60 -0
  63. package/src/domain/usecases/TokenExhaustionHandoverUseCase.test.ts +696 -0
  64. package/src/domain/usecases/TokenExhaustionHandoverUseCase.ts +413 -0
  65. package/src/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.ts +5 -0
  66. package/src/domain/usecases/adapter-interfaces/ProcessSignalRepository.ts +5 -0
  67. package/src/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.ts +10 -0
  68. package/src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts +2 -0
  69. package/src/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.ts +6 -0
  70. package/src/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.ts +22 -0
  71. package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +2 -0
  72. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  73. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +1 -0
  74. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
  75. package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts +14 -0
  76. package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts.map +1 -0
  77. package/types/adapter/repositories/FileHandoverStateRepository.d.ts +11 -0
  78. package/types/adapter/repositories/FileHandoverStateRepository.d.ts.map +1 -0
  79. package/types/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.d.ts +16 -0
  80. package/types/adapter/repositories/FileSystemSilentSessionNotifiedStateRepository.d.ts.map +1 -0
  81. package/types/adapter/repositories/NodeProcessSignalRepository.d.ts +8 -0
  82. package/types/adapter/repositories/NodeProcessSignalRepository.d.ts.map +1 -0
  83. package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +7 -1
  84. package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -1
  85. package/types/adapter/repositories/ProcClaudeHandoverSessionRepository.d.ts +13 -0
  86. package/types/adapter/repositories/ProcClaudeHandoverSessionRepository.d.ts.map +1 -0
  87. package/types/adapter/repositories/RateLimitSnapshotRepository.d.ts +9 -0
  88. package/types/adapter/repositories/RateLimitSnapshotRepository.d.ts.map +1 -0
  89. package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts.map +1 -1
  90. package/types/domain/entities/ClaudeHandoverSession.d.ts +10 -0
  91. package/types/domain/entities/ClaudeHandoverSession.d.ts.map +1 -0
  92. package/types/domain/entities/TokenExhaustionHandoverState.d.ts +8 -0
  93. package/types/domain/entities/TokenExhaustionHandoverState.d.ts.map +1 -0
  94. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +3 -1
  95. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
  96. package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts +50 -0
  97. package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts.map +1 -0
  98. package/types/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.d.ts +5 -0
  99. package/types/domain/usecases/adapter-interfaces/ClaudeHandoverSessionRepository.d.ts.map +1 -0
  100. package/types/domain/usecases/adapter-interfaces/ProcessSignalRepository.d.ts +6 -0
  101. package/types/domain/usecases/adapter-interfaces/ProcessSignalRepository.d.ts.map +1 -0
  102. package/types/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.d.ts +11 -0
  103. package/types/domain/usecases/adapter-interfaces/SilentSessionNotifiedStateRepository.d.ts.map +1 -0
  104. package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts +2 -0
  105. package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts.map +1 -1
  106. package/types/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.d.ts +6 -0
  107. package/types/domain/usecases/adapter-interfaces/TokenExhaustionHandoverStateRepository.d.ts.map +1 -0
  108. package/types/domain/usecases/adapter-interfaces/TokenRateLimitSnapshotRepository.d.ts +21 -0
  109. 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,5 @@
1
+ import { ClaudeHandoverSession } from '../../entities/ClaudeHandoverSession';
2
+
3
+ export interface ClaudeHandoverSessionRepository {
4
+ listHandoverSessions: () => ClaudeHandoverSession[];
5
+ }
@@ -0,0 +1,5 @@
1
+ export interface ProcessSignalRepository {
2
+ isProcessAlive: (pid: number) => boolean;
3
+ terminateProcess: (pid: number) => void;
4
+ killProcess: (pid: number) => void;
5
+ }
@@ -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,6 @@
1
+ import { TokenExhaustionHandoverState } from '../../entities/TokenExhaustionHandoverState';
2
+
3
+ export interface TokenExhaustionHandoverStateRepository {
4
+ load: () => TokenExhaustionHandoverState;
5
+ save: (state: TokenExhaustionHandoverState) => void;
6
+ }
@@ -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
+ }
@@ -72,6 +72,8 @@ const createFakeTmuxSessionRepository = (state: {
72
72
  },
73
73
  killSession: async () => undefined,
74
74
  killOwnSession: async () => undefined,
75
+ sendKeys: async () => undefined,
76
+ launchBareNameLeaderSession: async () => undefined,
75
77
  };
76
78
  };
77
79
 
@@ -1 +1 @@
1
- {"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAoCA,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,CAkmBP;CACH"}
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;AAKrE,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,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,CA6Ed,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;;;CAS7C,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
- constructor(localCommandRunner: LocalCommandRunner, procDirectory?: string);
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;AAIxE,qBAAa,yBAA0B,YAAW,qBAAqB;IAEnE,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa;gBADb,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,GAAE,MAAgB;IAGlD,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;CACH"}
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;AAEjG,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,CA4Bd;CACH"}
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