github-issue-tower-defence-management 1.146.5 → 1.146.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +2 -0
- package/.github/workflows/commit-lint.yml +20 -0
- package/.github/workflows/umino-project.yml +0 -1
- package/CHANGELOG.md +7 -0
- package/bin/adapter/entry-points/cli/index.js +2 -2
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js +4 -3
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/OauthTokenSelectHandler.js +4 -3
- package/bin/adapter/entry-points/handlers/OauthTokenSelectHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +3 -2
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.js +1 -1
- package/bin/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.js.map +1 -1
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js +73 -2
- package/bin/adapter/repositories/TmuxSilentSessionNotificationRepository.js.map +1 -1
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js +3 -1
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js.map +1 -1
- package/bin/domain/usecases/OauthTokenSelectUseCase.js +13 -4
- package/bin/domain/usecases/OauthTokenSelectUseCase.js.map +1 -1
- package/package.json +1 -1
- package/renovate.json +5 -0
- package/src/adapter/entry-points/cli/index.ts +2 -2
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.test.ts +7 -4
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts +4 -1
- package/src/adapter/entry-points/handlers/OauthTokenSelectHandler.test.ts +6 -2
- package/src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts +8 -2
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +1 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +14 -2
- package/src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.ts +4 -1
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.test.ts +157 -15
- package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.ts +115 -1
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.test.ts +77 -5
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts +10 -1
- package/src/domain/usecases/OauthTokenSelectUseCase.test.ts +39 -8
- package/src/domain/usecases/OauthTokenSelectUseCase.ts +25 -5
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts +3 -1
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/OauthTokenSelectHandler.d.ts +3 -2
- package/types/adapter/entry-points/handlers/OauthTokenSelectHandler.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/resetDegeneratedTmuxSessions.d.ts.map +1 -1
- package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts +14 -1
- package/types/adapter/repositories/TmuxSilentSessionNotificationRepository.d.ts.map +1 -1
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts.map +1 -1
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts +4 -1
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts.map +1 -1
|
@@ -47,6 +47,7 @@ describe('LiveSessionOauthTokenSelectUseCase', () => {
|
|
|
47
47
|
[candidate('busy', snapshot({})), candidate('idle', snapshot({}))],
|
|
48
48
|
[session('busy', 'session-a')],
|
|
49
49
|
NOW,
|
|
50
|
+
() => 0.5,
|
|
50
51
|
);
|
|
51
52
|
|
|
52
53
|
expect(result.selected?.name).toBe('idle');
|
|
@@ -63,12 +64,13 @@ describe('LiveSessionOauthTokenSelectUseCase', () => {
|
|
|
63
64
|
],
|
|
64
65
|
[session('far', 'session-a'), session('soon', 'session-b')],
|
|
65
66
|
NOW,
|
|
67
|
+
() => 0.5,
|
|
66
68
|
);
|
|
67
69
|
|
|
68
70
|
expect(result.selected?.name).toBe('soon');
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
it('
|
|
73
|
+
it('falls back to fewer live sessions when occupancy exactly cancels the urgency gap', () => {
|
|
72
74
|
const result = useCase.run(
|
|
73
75
|
[
|
|
74
76
|
candidate('soonButBusy', snapshot({ sevenDayReset: NOW + 2 * DAY })),
|
|
@@ -79,6 +81,7 @@ describe('LiveSessionOauthTokenSelectUseCase', () => {
|
|
|
79
81
|
session('soonButBusy', 'session-b'),
|
|
80
82
|
],
|
|
81
83
|
NOW,
|
|
84
|
+
throwingRandom,
|
|
82
85
|
);
|
|
83
86
|
|
|
84
87
|
expect(result.selected?.name).toBe('farButIdle');
|
|
@@ -114,6 +117,7 @@ describe('LiveSessionOauthTokenSelectUseCase', () => {
|
|
|
114
117
|
session('twoSessions', 'session-c'),
|
|
115
118
|
],
|
|
116
119
|
NOW,
|
|
120
|
+
() => 0.5,
|
|
117
121
|
);
|
|
118
122
|
|
|
119
123
|
expect(result.selected?.name).toBe('oneSession');
|
|
@@ -136,6 +140,7 @@ describe('LiveSessionOauthTokenSelectUseCase', () => {
|
|
|
136
140
|
session('fresh', 'session-fresh'),
|
|
137
141
|
],
|
|
138
142
|
NOW,
|
|
143
|
+
() => 0.99,
|
|
139
144
|
);
|
|
140
145
|
|
|
141
146
|
expect(result.selected?.name).toBe('fresh');
|
|
@@ -231,15 +236,18 @@ const withSelectionWeight = (
|
|
|
231
236
|
describe('LiveSessionOauthTokenSelectUseCase selectionWeight', () => {
|
|
232
237
|
const useCase = new LiveSessionOauthTokenSelectUseCase();
|
|
233
238
|
|
|
234
|
-
it('keeps the deterministic
|
|
239
|
+
it('keeps the deterministic selection and never consults random when the urgency weights are identical', () => {
|
|
235
240
|
const result = useCase.run(
|
|
236
|
-
[
|
|
237
|
-
|
|
241
|
+
[
|
|
242
|
+
candidate('firstOfEqualPair', snapshot({})),
|
|
243
|
+
candidate('secondOfEqualPair', snapshot({})),
|
|
244
|
+
],
|
|
245
|
+
[],
|
|
238
246
|
NOW,
|
|
239
247
|
throwingRandom,
|
|
240
248
|
);
|
|
241
249
|
|
|
242
|
-
expect(result.selected?.name).toBe('
|
|
250
|
+
expect(result.selected?.name).toBe('firstOfEqualPair');
|
|
243
251
|
});
|
|
244
252
|
|
|
245
253
|
it('selects a sole eligible low-weight token without consulting random (no starvation)', () => {
|
|
@@ -283,3 +291,67 @@ describe('LiveSessionOauthTokenSelectUseCase selectionWeight', () => {
|
|
|
283
291
|
expect(Math.abs(light / count - 1 / 3)).toBeLessThan(0.02);
|
|
284
292
|
});
|
|
285
293
|
});
|
|
294
|
+
|
|
295
|
+
describe('LiveSessionOauthTokenSelectUseCase seven day urgency weighting', () => {
|
|
296
|
+
const useCase = new LiveSessionOauthTokenSelectUseCase();
|
|
297
|
+
|
|
298
|
+
it('prefers the token whose seven day window resets soonest with capacity left over an idle token with a distant reset', () => {
|
|
299
|
+
const soonResetting = candidate(
|
|
300
|
+
'soon-resetting',
|
|
301
|
+
snapshot({
|
|
302
|
+
sevenDayUtilization: 0.5,
|
|
303
|
+
sevenDayReset: NOW + 8 * HOUR,
|
|
304
|
+
}),
|
|
305
|
+
);
|
|
306
|
+
const distantReset = candidate(
|
|
307
|
+
'distant-reset',
|
|
308
|
+
snapshot({
|
|
309
|
+
sevenDayUtilization: 0,
|
|
310
|
+
sevenDayReset: NOW + 160 * HOUR,
|
|
311
|
+
}),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const result = useCase.run(
|
|
315
|
+
[soonResetting, distantReset],
|
|
316
|
+
[
|
|
317
|
+
session('soon-resetting', 'session-a'),
|
|
318
|
+
session('soon-resetting', 'session-b'),
|
|
319
|
+
session('soon-resetting', 'session-c'),
|
|
320
|
+
],
|
|
321
|
+
NOW,
|
|
322
|
+
() => 0.5,
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
expect(result.selected?.name).toBe('soon-resetting');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('leaves the token with a distant reset selectable when the random draw falls in its share', () => {
|
|
329
|
+
const soonResetting = candidate(
|
|
330
|
+
'soon-resetting',
|
|
331
|
+
snapshot({
|
|
332
|
+
sevenDayUtilization: 0.5,
|
|
333
|
+
sevenDayReset: NOW + 8 * HOUR,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
const distantReset = candidate(
|
|
337
|
+
'distant-reset',
|
|
338
|
+
snapshot({
|
|
339
|
+
sevenDayUtilization: 0,
|
|
340
|
+
sevenDayReset: NOW + 160 * HOUR,
|
|
341
|
+
}),
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const result = useCase.run(
|
|
345
|
+
[soonResetting, distantReset],
|
|
346
|
+
[
|
|
347
|
+
session('soon-resetting', 'session-a'),
|
|
348
|
+
session('soon-resetting', 'session-b'),
|
|
349
|
+
session('soon-resetting', 'session-c'),
|
|
350
|
+
],
|
|
351
|
+
NOW,
|
|
352
|
+
() => 0.9,
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
expect(result.selected?.name).toBe('distant-reset');
|
|
356
|
+
});
|
|
357
|
+
});
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
OauthTokenSelectUseCase,
|
|
5
5
|
SelectionRandom,
|
|
6
6
|
selectWeightedCandidate,
|
|
7
|
+
selectionWeightOf,
|
|
8
|
+
sevenDayUrgencyFactor,
|
|
7
9
|
} from './OauthTokenSelectUseCase';
|
|
8
10
|
|
|
9
11
|
export type LiveSessionOauthTokenCandidateMetrics = {
|
|
@@ -72,7 +74,14 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
72
74
|
|
|
73
75
|
const selected = selectWeightedCandidate(
|
|
74
76
|
eligible,
|
|
75
|
-
(entry) =>
|
|
77
|
+
(entry) =>
|
|
78
|
+
(selectionWeightOf(entry.candidate) *
|
|
79
|
+
sevenDayUrgencyFactor(
|
|
80
|
+
entry.metric.sevenDayFreeRatio,
|
|
81
|
+
entry.metric.sevenDayEndEpoch,
|
|
82
|
+
nowEpochSeconds,
|
|
83
|
+
)) /
|
|
84
|
+
(1 + entry.metric.liveSessionCount),
|
|
76
85
|
deterministicBest,
|
|
77
86
|
random,
|
|
78
87
|
);
|
|
@@ -2,6 +2,8 @@ import {
|
|
|
2
2
|
OauthTokenCandidate,
|
|
3
3
|
OauthTokenSelectUseCase,
|
|
4
4
|
OauthTokenWindowSnapshot,
|
|
5
|
+
SEVEN_DAY_WINDOW_HOURS,
|
|
6
|
+
sevenDayUrgencyFactor,
|
|
5
7
|
} from './OauthTokenSelectUseCase';
|
|
6
8
|
|
|
7
9
|
const NOW = 1_000_000;
|
|
@@ -53,6 +55,7 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
53
55
|
),
|
|
54
56
|
],
|
|
55
57
|
NOW,
|
|
58
|
+
() => 0.5,
|
|
56
59
|
);
|
|
57
60
|
|
|
58
61
|
expect(result.selected?.name).toBe('soon');
|
|
@@ -176,6 +179,7 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
176
179
|
),
|
|
177
180
|
],
|
|
178
181
|
NOW,
|
|
182
|
+
() => 0.5,
|
|
179
183
|
);
|
|
180
184
|
|
|
181
185
|
expect(result.selected?.name).toBe('activeSoon');
|
|
@@ -291,15 +295,15 @@ const withSelectionWeight = (
|
|
|
291
295
|
describe('OauthTokenSelectUseCase selectionWeight', () => {
|
|
292
296
|
const useCase = new OauthTokenSelectUseCase();
|
|
293
297
|
|
|
294
|
-
it('keeps the deterministic
|
|
298
|
+
it('keeps the deterministic selection and never consults random when the urgency weights are identical', () => {
|
|
295
299
|
const result = useCase.run(
|
|
296
300
|
[
|
|
297
301
|
candidate(
|
|
298
|
-
'
|
|
299
|
-
snapshot({ sevenDayUtilization: 0.1, sevenDayReset: NOW +
|
|
302
|
+
'firstOfEqualPair',
|
|
303
|
+
snapshot({ sevenDayUtilization: 0.1, sevenDayReset: NOW + 2 * DAY }),
|
|
300
304
|
),
|
|
301
305
|
candidate(
|
|
302
|
-
'
|
|
306
|
+
'secondOfEqualPair',
|
|
303
307
|
snapshot({ sevenDayUtilization: 0.1, sevenDayReset: NOW + 2 * DAY }),
|
|
304
308
|
),
|
|
305
309
|
],
|
|
@@ -307,23 +311,26 @@ describe('OauthTokenSelectUseCase selectionWeight', () => {
|
|
|
307
311
|
throwingRandom,
|
|
308
312
|
);
|
|
309
313
|
|
|
310
|
-
expect(result.selected?.name).toBe('
|
|
314
|
+
expect(result.selected?.name).toBe('firstOfEqualPair');
|
|
311
315
|
});
|
|
312
316
|
|
|
313
317
|
it('treats an absent selectionWeight the same as weight 1 (uniform, deterministic)', () => {
|
|
314
318
|
const result = useCase.run(
|
|
315
319
|
[
|
|
316
320
|
withSelectionWeight(
|
|
317
|
-
candidate(
|
|
321
|
+
candidate(
|
|
322
|
+
'explicitWeightOne',
|
|
323
|
+
snapshot({ sevenDayReset: NOW + 2 * DAY }),
|
|
324
|
+
),
|
|
318
325
|
1,
|
|
319
326
|
),
|
|
320
|
-
candidate('
|
|
327
|
+
candidate('absentWeight', snapshot({ sevenDayReset: NOW + 2 * DAY })),
|
|
321
328
|
],
|
|
322
329
|
NOW,
|
|
323
330
|
throwingRandom,
|
|
324
331
|
);
|
|
325
332
|
|
|
326
|
-
expect(result.selected?.name).toBe('
|
|
333
|
+
expect(result.selected?.name).toBe('explicitWeightOne');
|
|
327
334
|
});
|
|
328
335
|
|
|
329
336
|
it('selects a sole eligible low-weight token without consulting random (no starvation)', () => {
|
|
@@ -431,3 +438,27 @@ describe('OauthTokenSelectUseCase selectionWeight', () => {
|
|
|
431
438
|
expect(result.selected?.name).toBe('soon');
|
|
432
439
|
});
|
|
433
440
|
});
|
|
441
|
+
|
|
442
|
+
describe('sevenDayUrgencyFactor', () => {
|
|
443
|
+
const now = 1_000_000;
|
|
444
|
+
|
|
445
|
+
it('grows as the seven day window gets closer to its reset', () => {
|
|
446
|
+
const nearReset = sevenDayUrgencyFactor(0.5, now + 8 * 3600, now);
|
|
447
|
+
const farReset = sevenDayUrgencyFactor(0.5, now + 160 * 3600, now);
|
|
448
|
+
|
|
449
|
+
expect(nearReset).toBeGreaterThan(farReset);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('scales with the free ratio of the seven day window', () => {
|
|
453
|
+
const halfFree = sevenDayUrgencyFactor(0.5, now + 24 * 3600, now);
|
|
454
|
+
const fullyFree = sevenDayUrgencyFactor(1, now + 24 * 3600, now);
|
|
455
|
+
|
|
456
|
+
expect(fullyFree).toBeCloseTo(halfFree * 2);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('clips the remaining hours at one hour so an imminent reset does not produce an unbounded factor', () => {
|
|
460
|
+
const almostReset = sevenDayUrgencyFactor(1, now + 60, now);
|
|
461
|
+
|
|
462
|
+
expect(almostReset).toBe(SEVEN_DAY_WINDOW_HOURS);
|
|
463
|
+
});
|
|
464
|
+
});
|
|
@@ -44,18 +44,32 @@ const SEVEN_DAYS_IN_SECONDS = 7 * SECONDS_PER_DAY;
|
|
|
44
44
|
export const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
|
|
45
45
|
export const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
|
|
46
46
|
|
|
47
|
+
export const SEVEN_DAY_WINDOW_HOURS = 168;
|
|
48
|
+
export const MIN_HOURS_TO_RESET = 1;
|
|
49
|
+
const SECONDS_PER_HOUR = 3600;
|
|
50
|
+
|
|
51
|
+
export const sevenDayUrgencyFactor = (
|
|
52
|
+
sevenDayFreeRatio: number,
|
|
53
|
+
sevenDayEndEpoch: number,
|
|
54
|
+
nowEpochSeconds: number,
|
|
55
|
+
): number => {
|
|
56
|
+
const hoursToReset = Math.max(
|
|
57
|
+
(sevenDayEndEpoch - nowEpochSeconds) / SECONDS_PER_HOUR,
|
|
58
|
+
MIN_HOURS_TO_RESET,
|
|
59
|
+
);
|
|
60
|
+
return sevenDayFreeRatio * (SEVEN_DAY_WINDOW_HOURS / hoursToReset);
|
|
61
|
+
};
|
|
62
|
+
|
|
47
63
|
export const selectWeightedCandidate = <Entry>(
|
|
48
64
|
eligible: Entry[],
|
|
49
|
-
|
|
65
|
+
weightOf: (entry: Entry) => number,
|
|
50
66
|
deterministicBest: Entry,
|
|
51
67
|
random: SelectionRandom,
|
|
52
68
|
): Entry => {
|
|
53
69
|
if (eligible.length <= 1) {
|
|
54
70
|
return deterministicBest;
|
|
55
71
|
}
|
|
56
|
-
const weights = eligible.map((entry) =>
|
|
57
|
-
selectionWeightOf(candidateOf(entry)),
|
|
58
|
-
);
|
|
72
|
+
const weights = eligible.map((entry) => Math.max(weightOf(entry), 0));
|
|
59
73
|
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
60
74
|
const uniform = weights.every((weight) => weight === weights[0]);
|
|
61
75
|
if (uniform || totalWeight <= 0) {
|
|
@@ -97,7 +111,13 @@ export class OauthTokenSelectUseCase {
|
|
|
97
111
|
|
|
98
112
|
const selected = selectWeightedCandidate(
|
|
99
113
|
eligible,
|
|
100
|
-
(entry) =>
|
|
114
|
+
(entry) =>
|
|
115
|
+
selectionWeightOf(entry.candidate) *
|
|
116
|
+
sevenDayUrgencyFactor(
|
|
117
|
+
entry.metric.sevenDayFreeRatio,
|
|
118
|
+
entry.metric.sevenDayEndEpoch,
|
|
119
|
+
nowEpochSeconds,
|
|
120
|
+
),
|
|
101
121
|
deterministicBest,
|
|
102
122
|
random,
|
|
103
123
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClaudeLiveSessionRepository } from '../../../domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
2
|
import { LiveSessionOauthTokenSelectUseCase } from '../../../domain/usecases/LiveSessionOauthTokenSelectUseCase';
|
|
3
|
+
import { SelectionRandom } from '../../../domain/usecases/OauthTokenSelectUseCase';
|
|
3
4
|
export type LiveSessionOauthTokenSelectHandlerInput = {
|
|
4
5
|
tokenListJsonPath: string | null;
|
|
5
6
|
cacheDirectory: string | null;
|
|
@@ -13,7 +14,8 @@ export type LiveSessionOauthTokenSelectHandlerOutput = {
|
|
|
13
14
|
export declare class LiveSessionOauthTokenSelectHandler {
|
|
14
15
|
private readonly useCase;
|
|
15
16
|
private readonly liveSessionRepository;
|
|
16
|
-
|
|
17
|
+
private readonly random;
|
|
18
|
+
constructor(useCase?: LiveSessionOauthTokenSelectUseCase, liveSessionRepository?: ClaudeLiveSessionRepository, random?: SelectionRandom);
|
|
17
19
|
handle: (input: LiveSessionOauthTokenSelectHandlerInput) => LiveSessionOauthTokenSelectHandlerOutput;
|
|
18
20
|
private formatDiagnostics;
|
|
19
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionOauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAEL,kCAAkC,EACnC,MAAM,6DAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAEL,kCAAkC,EACnC,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAKL,eAAe,EAChB,MAAM,kDAAkD,CAAC;AAS1D,MAAM,MAAM,uCAAuC,GAAG;IACpD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,wCAAwC,GAAG;IACrD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,OAAO,GAAE,kCAA6E,EACtF,qBAAqB,GAAE,2BAAmE,EAC1F,MAAM,GAAE,eAA6B;IAGxD,MAAM,GACJ,OAAO,uCAAuC,KAC7C,wCAAwC,CAmEzC;IAEF,OAAO,CAAC,iBAAiB,CAyBvB;CACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OauthTokenSelectUseCase } from '../../../domain/usecases/OauthTokenSelectUseCase';
|
|
1
|
+
import { OauthTokenSelectUseCase, SelectionRandom } from '../../../domain/usecases/OauthTokenSelectUseCase';
|
|
2
2
|
export type OauthTokenSelectHandlerInput = {
|
|
3
3
|
tokenListJsonPath: string | null;
|
|
4
4
|
cacheDirectory: string | null;
|
|
@@ -13,7 +13,8 @@ export declare const resolveTokenListJsonPath: (explicitPath: string | null) =>
|
|
|
13
13
|
export declare const resolveCacheDirectory: (explicitDirectory: string | null) => string;
|
|
14
14
|
export declare class OauthTokenSelectHandler {
|
|
15
15
|
private readonly useCase;
|
|
16
|
-
|
|
16
|
+
private readonly random;
|
|
17
|
+
constructor(useCase?: OauthTokenSelectUseCase, random?: SelectionRandom);
|
|
17
18
|
handle: (input: OauthTokenSelectHandlerInput) => OauthTokenSelectHandlerOutput;
|
|
18
19
|
private formatDiagnostics;
|
|
19
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,uBAAuB,
|
|
1
|
+
{"version":3,"file":"OauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,uBAAuB,EACvB,eAAe,EAChB,MAAM,kDAAkD,CAAC;AAQ1D,MAAM,MAAM,4BAA4B,GAAG;IACzC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAKF,eAAO,MAAM,wBAAwB,GACnC,cAAc,MAAM,GAAG,IAAI,KAC1B,MAAM,GAAG,IASX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,mBAAmB,MAAM,GAAG,IAAI,KAC/B,MASF,CAAC;AAEF,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,GAAE,uBAAuD,EAChE,MAAM,GAAE,eAA6B;IAGxD,MAAM,GACJ,OAAO,4BAA4B,KAClC,6BAA6B,CAgE9B;IAEF,OAAO,CAAC,iBAAiB,CAuBvB;CACH"}
|
|
@@ -23,6 +23,7 @@ export type NotifySilentTmuxSessionsParams = {
|
|
|
23
23
|
hubTaskStatusCacheStateFilePath: string | null;
|
|
24
24
|
hubTaskStatusCacheTtlSeconds: number;
|
|
25
25
|
messageTemplates: SilentSessionMessageTemplates;
|
|
26
|
+
submitPushOutWaitMilliseconds?: number;
|
|
26
27
|
now: Date;
|
|
27
28
|
};
|
|
28
29
|
export declare const notifySilentTmuxSessions: (params: NotifySilentTmuxSessionsParams) => Promise<void>;
|
|
@@ -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;
|
|
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;AAoBlE,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,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAuCF,eAAO,MAAM,wBAAwB,GACnC,QAAQ,8BAA8B,KACrC,OAAO,CAAC,IAAI,CAoFd,CAAC;AAEF,eAAO,MAAM,0CAA0C;;;;;;;;CAS7C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resetDegeneratedTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AAgBxG,MAAM,MAAM,kCAAkC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,QAAQ,kCAAkC,KACzC,OAAO,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"resetDegeneratedTmuxSessions.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kEAAkE,CAAC;AAgBxG,MAAM,MAAM,kCAAkC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,QAAQ,kCAAkC,KACzC,OAAO,CAAC,IAAI,CAqCd,CAAC;AAEF,eAAO,MAAM,8CAA8C;;;;CAIjD,CAAC"}
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { SilentSessionNotificationRepository } from '../../domain/usecases/adapter-interfaces/SilentSessionNotificationRepository';
|
|
2
2
|
import { LocalCommandRunner } from '../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
3
|
+
import { Sleeper } from '../../domain/usecases/adapter-interfaces/Sleeper';
|
|
4
|
+
export declare const DEFAULT_SUBMIT_PUSH_OUT_ATTEMPT_LIMIT = 3;
|
|
5
|
+
export declare const DEFAULT_SUBMIT_PUSH_OUT_WAIT_MILLISECONDS = 2500;
|
|
6
|
+
type InputBoxState = 'holdsMessage' | 'clearedMessage' | 'unreadable';
|
|
7
|
+
export declare const extractTmuxInputBoxContent: (paneText: string) => string | null;
|
|
8
|
+
export declare const resolveInputBoxStateFromPane: (paneText: string, singleLineMessage: string) => InputBoxState;
|
|
3
9
|
export declare class TmuxSilentSessionNotificationRepository implements SilentSessionNotificationRepository {
|
|
4
10
|
private readonly localCommandRunner;
|
|
5
|
-
|
|
11
|
+
private readonly sleeper;
|
|
12
|
+
private readonly submitPushOutAttemptLimit;
|
|
13
|
+
private readonly submitPushOutWaitMilliseconds;
|
|
14
|
+
constructor(localCommandRunner: LocalCommandRunner, sleeper: Sleeper, submitPushOutAttemptLimit?: number, submitPushOutWaitMilliseconds?: number);
|
|
6
15
|
sendSelfCheckNotification: (sessionName: string, message: string) => Promise<void>;
|
|
16
|
+
private submitInputBox;
|
|
17
|
+
private pushOutUnsubmittedMessage;
|
|
18
|
+
private readInputBoxState;
|
|
7
19
|
}
|
|
20
|
+
export {};
|
|
8
21
|
//# sourceMappingURL=TmuxSilentSessionNotificationRepository.d.ts.map
|
|
@@ -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;AACjG,OAAO,EAAE,OAAO,EAAE,MAAM,kDAAkD,CAAC;AAK3E,eAAO,MAAM,qCAAqC,IAAI,CAAC;AACvD,eAAO,MAAM,yCAAyC,OAAO,CAAC;AAM9D,KAAK,aAAa,GAAG,cAAc,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAItE,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,IAgBtE,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,UAAU,MAAM,EAChB,mBAAmB,MAAM,KACxB,aAeF,CAAC;AAEF,qBAAa,uCAAwC,YAAW,mCAAmC;IAE/F,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,6BAA6B;gBAH7B,kBAAkB,EAAE,kBAAkB,EACtC,OAAO,EAAE,OAAO,EAChB,yBAAyB,GAAE,MAA8C,EACzE,6BAA6B,GAAE,MAAkD;IAGpG,yBAAyB,GACvB,aAAa,MAAM,EACnB,SAAS,MAAM,KACd,OAAO,CAAC,IAAI,CAAC,CAmBd;IAEF,OAAO,CAAC,cAAc,CAcpB;IAEF,OAAO,CAAC,yBAAyB,CA4B/B;IAEF,OAAO,CAAC,iBAAiB,CAsBvB;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionOauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACrF,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACrF,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,EAIhB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,qCAAqC,EAAE,CAAC;CAClD,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBAAtB,sBAAsB,GAAE,uBAAuD;IAGlG,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,cAAc,iBAAiB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,iCAAiC,CAsDlC;IAEF,OAAO,CAAC,SAAS,CAUf;IAEF,OAAO,CAAC,uBAAuB,CAe7B;CACH"}
|
|
@@ -30,7 +30,10 @@ export type OauthTokenSelectResult = {
|
|
|
30
30
|
};
|
|
31
31
|
export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.25;
|
|
32
32
|
export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.03;
|
|
33
|
-
export declare const
|
|
33
|
+
export declare const SEVEN_DAY_WINDOW_HOURS = 168;
|
|
34
|
+
export declare const MIN_HOURS_TO_RESET = 1;
|
|
35
|
+
export declare const sevenDayUrgencyFactor: (sevenDayFreeRatio: number, sevenDayEndEpoch: number, nowEpochSeconds: number) => number;
|
|
36
|
+
export declare const selectWeightedCandidate: <Entry>(eligible: Entry[], weightOf: (entry: Entry) => number, deterministicBest: Entry, random: SelectionRandom) => Entry;
|
|
34
37
|
export declare class OauthTokenSelectUseCase {
|
|
35
38
|
run: (candidates: OauthTokenCandidate[], nowEpochSeconds: number, random?: SelectionRandom) => OauthTokenSelectResult;
|
|
36
39
|
private evaluate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,
|
|
1
|
+
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAGpC,eAAO,MAAM,qBAAqB,GAChC,mBAAmB,MAAM,EACzB,kBAAkB,MAAM,EACxB,iBAAiB,MAAM,KACtB,MAMF,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,UAAU,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,EAClC,mBAAmB,KAAK,EACxB,QAAQ,eAAe,KACtB,KAkBF,CAAC;AAEF,qBAAa,uBAAuB;IAClC,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,sBAAsB,CAiCvB;IAEF,OAAO,CAAC,QAAQ,CAiCd;IAEF,OAAO,CAAC,eAAe,CAuBrB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,gBAAgB,CActB;IAEF,OAAO,CAAC,aAAa,CAGwC;IAE7D,OAAO,CAAC,wBAAwB,CAG9B;IAEF,OAAO,CAAC,SAAS,CAAsD;CACxE"}
|