github-issue-tower-defence-management 1.146.7 → 1.146.9
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 +5 -4
- package/bin/adapter/entry-points/cli/fleetConfig.js +101 -0
- package/bin/adapter/entry-points/cli/fleetConfig.js.map +1 -0
- package/bin/adapter/entry-points/cli/index.js +21 -4
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js +4 -5
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js.map +1 -1
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js +24 -9
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/fleetConfig.test.ts +177 -0
- package/src/adapter/entry-points/cli/fleetConfig.ts +109 -0
- package/src/adapter/entry-points/cli/index.test.ts +82 -0
- package/src/adapter/entry-points/cli/index.ts +31 -3
- package/src/adapter/entry-points/handlers/GetStoryObjectMapUseCaseHandler.test.ts +8 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.test.ts +8 -0
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.test.ts +25 -10
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts +5 -5
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +12 -0
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.test.ts +325 -156
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts +50 -22
- package/types/adapter/entry-points/cli/fleetConfig.d.ts +6 -0
- package/types/adapter/entry-points/cli/fleetConfig.d.ts.map +1 -0
- package/types/adapter/entry-points/cli/index.d.ts +2 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts +3 -4
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts.map +1 -1
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts +10 -2
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts.map +1 -1
|
@@ -2,18 +2,47 @@ import { ClaudeLiveSession } from './adapter-interfaces/ClaudeLiveSessionReposit
|
|
|
2
2
|
import {
|
|
3
3
|
OauthTokenCandidate,
|
|
4
4
|
OauthTokenSelectUseCase,
|
|
5
|
-
SelectionRandom,
|
|
6
|
-
selectWeightedCandidate,
|
|
7
5
|
selectionWeightOf,
|
|
8
|
-
sevenDayUrgencyFactor,
|
|
9
6
|
} from './OauthTokenSelectUseCase';
|
|
10
7
|
|
|
8
|
+
export type LiveSessionOauthTokenSelectionSettings = {
|
|
9
|
+
maxConcurrentSessionCount: number;
|
|
10
|
+
fullSpeedFiveHourFreeRatio: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_LIVE_SESSION_OAUTH_TOKEN_SELECTION_SETTINGS: LiveSessionOauthTokenSelectionSettings =
|
|
14
|
+
{
|
|
15
|
+
maxConcurrentSessionCount: 10,
|
|
16
|
+
fullSpeedFiveHourFreeRatio: 0.5,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const liveSessionConcurrentLimitOf = (
|
|
20
|
+
fiveHourFreeRatio: number,
|
|
21
|
+
selectionWeight: number,
|
|
22
|
+
settings: LiveSessionOauthTokenSelectionSettings,
|
|
23
|
+
): number => {
|
|
24
|
+
const fiveHourThrottleFactor = Math.min(
|
|
25
|
+
fiveHourFreeRatio / settings.fullSpeedFiveHourFreeRatio,
|
|
26
|
+
1,
|
|
27
|
+
);
|
|
28
|
+
return Math.max(
|
|
29
|
+
Math.floor(
|
|
30
|
+
settings.maxConcurrentSessionCount *
|
|
31
|
+
selectionWeight *
|
|
32
|
+
fiveHourThrottleFactor,
|
|
33
|
+
),
|
|
34
|
+
1,
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
11
38
|
export type LiveSessionOauthTokenCandidateMetrics = {
|
|
12
39
|
name: string;
|
|
13
40
|
fiveHourFreeRatio: number;
|
|
14
41
|
sevenDayFreeRatio: number;
|
|
15
42
|
sevenDayEndEpoch: number;
|
|
16
43
|
liveSessionCount: number;
|
|
44
|
+
concurrentSessionLimit: number;
|
|
45
|
+
hasConcurrencyHeadroom: boolean;
|
|
17
46
|
eligible: boolean;
|
|
18
47
|
exclusionReason: string | null;
|
|
19
48
|
};
|
|
@@ -32,7 +61,7 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
32
61
|
candidates: OauthTokenCandidate[],
|
|
33
62
|
liveSessions: ClaudeLiveSession[],
|
|
34
63
|
nowEpochSeconds: number,
|
|
35
|
-
|
|
64
|
+
settings: LiveSessionOauthTokenSelectionSettings,
|
|
36
65
|
): LiveSessionOauthTokenSelectResult => {
|
|
37
66
|
const rateLimitResult = this.rateLimitSelectUseCase.run(
|
|
38
67
|
candidates,
|
|
@@ -45,6 +74,11 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
45
74
|
const rateLimitMetric = rateLimitResult.metrics[index];
|
|
46
75
|
const liveSessionCount =
|
|
47
76
|
liveSessionCountByToken.get(candidate.token) ?? 0;
|
|
77
|
+
const concurrentSessionLimit = liveSessionConcurrentLimitOf(
|
|
78
|
+
rateLimitMetric.fiveHourFreeRatio,
|
|
79
|
+
selectionWeightOf(candidate),
|
|
80
|
+
settings,
|
|
81
|
+
);
|
|
48
82
|
return {
|
|
49
83
|
candidate,
|
|
50
84
|
metric: {
|
|
@@ -53,6 +87,8 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
53
87
|
sevenDayFreeRatio: rateLimitMetric.sevenDayFreeRatio,
|
|
54
88
|
sevenDayEndEpoch: rateLimitMetric.sevenDayEndEpoch,
|
|
55
89
|
liveSessionCount,
|
|
90
|
+
concurrentSessionLimit,
|
|
91
|
+
hasConcurrencyHeadroom: liveSessionCount < concurrentSessionLimit,
|
|
56
92
|
eligible: rateLimitMetric.eligible,
|
|
57
93
|
exclusionReason: rateLimitMetric.exclusionReason,
|
|
58
94
|
},
|
|
@@ -66,26 +102,12 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
66
102
|
return { selected: null, metrics };
|
|
67
103
|
}
|
|
68
104
|
|
|
69
|
-
const
|
|
105
|
+
const selected = eligible.reduce((bestEntry, currentEntry) =>
|
|
70
106
|
this.preferred(currentEntry.metric, bestEntry.metric)
|
|
71
107
|
? currentEntry
|
|
72
108
|
: bestEntry,
|
|
73
109
|
);
|
|
74
110
|
|
|
75
|
-
const selected = selectWeightedCandidate(
|
|
76
|
-
eligible,
|
|
77
|
-
(entry) =>
|
|
78
|
-
(selectionWeightOf(entry.candidate) *
|
|
79
|
-
sevenDayUrgencyFactor(
|
|
80
|
-
entry.metric.sevenDayFreeRatio,
|
|
81
|
-
entry.metric.sevenDayEndEpoch,
|
|
82
|
-
nowEpochSeconds,
|
|
83
|
-
)) /
|
|
84
|
-
(1 + entry.metric.liveSessionCount),
|
|
85
|
-
deterministicBest,
|
|
86
|
-
random,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
111
|
return { selected: selected.candidate, metrics };
|
|
90
112
|
};
|
|
91
113
|
|
|
@@ -93,12 +115,18 @@ export class LiveSessionOauthTokenSelectUseCase {
|
|
|
93
115
|
candidateMetric: LiveSessionOauthTokenCandidateMetrics,
|
|
94
116
|
incumbentMetric: LiveSessionOauthTokenCandidateMetrics,
|
|
95
117
|
): boolean => {
|
|
96
|
-
if (
|
|
118
|
+
if (
|
|
119
|
+
candidateMetric.hasConcurrencyHeadroom !==
|
|
120
|
+
incumbentMetric.hasConcurrencyHeadroom
|
|
121
|
+
) {
|
|
122
|
+
return candidateMetric.hasConcurrencyHeadroom;
|
|
123
|
+
}
|
|
124
|
+
if (candidateMetric.sevenDayEndEpoch !== incumbentMetric.sevenDayEndEpoch) {
|
|
97
125
|
return (
|
|
98
|
-
candidateMetric.
|
|
126
|
+
candidateMetric.sevenDayEndEpoch < incumbentMetric.sevenDayEndEpoch
|
|
99
127
|
);
|
|
100
128
|
}
|
|
101
|
-
return candidateMetric.
|
|
129
|
+
return candidateMetric.liveSessionCount < incumbentMetric.liveSessionCount;
|
|
102
130
|
};
|
|
103
131
|
|
|
104
132
|
private liveSessionCountByToken = (
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LiveSessionOauthTokenSelectionSettings } from '../../../domain/usecases/LiveSessionOauthTokenSelectUseCase';
|
|
2
|
+
export declare const FLEET_CONFIG_FILE_PATH_ENVIRONMENT_VARIABLE = "TDPM_FLEET_CONFIG";
|
|
3
|
+
export declare const LIVE_SESSION_OAUTH_TOKEN_SELECTION_SECTION_KEY = "liveSessionOauthTokenSelection";
|
|
4
|
+
export declare const resolveFleetConfigFilePath: (cliValue: string | null) => string | null;
|
|
5
|
+
export declare const loadLiveSessionOauthTokenSelectionSettings: (fleetConfigFilePath: string | null) => LiveSessionOauthTokenSelectionSettings;
|
|
6
|
+
//# sourceMappingURL=fleetConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleetConfig.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/fleetConfig.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,sCAAsC,EACvC,MAAM,6DAA6D,CAAC;AAErE,eAAO,MAAM,2CAA2C,sBAAsB,CAAC;AAE/E,eAAO,MAAM,8CAA8C,mCACzB,CAAC;AAEnC,eAAO,MAAM,0BAA0B,GACrC,UAAU,MAAM,GAAG,IAAI,KACtB,MAAM,GAAG,IAUX,CAAC;AAwDF,eAAO,MAAM,0CAA0C,GACrD,qBAAqB,MAAM,GAAG,IAAI,KACjC,sCA0BF,CAAC"}
|
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
export { ConfigFile, loadConfigFile, parseProjectReadmeConfig, mergeConfigs, fetchProjectReadme, } from './projectConfig';
|
|
4
4
|
export declare const program: Command;
|
|
5
|
+
export declare const reportFatalErrorAndExit: (error: unknown) => void;
|
|
6
|
+
export declare const runCliProgram: (argv: string[], handleFatalError: (error: unknown) => void) => Promise<void>;
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAoKzB,eAAO,MAAM,OAAO,SAAgB,CAAC;AAq8BrC,eAAO,MAAM,uBAAuB,GAAI,OAAO,OAAO,KAAG,IAGxD,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EAAE,EACd,kBAAkB,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KACzC,OAAO,CAAC,IAAI,CAMd,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ClaudeLiveSessionRepository } from '../../../domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
-
import { LiveSessionOauthTokenSelectUseCase } from '../../../domain/usecases/LiveSessionOauthTokenSelectUseCase';
|
|
3
|
-
import { SelectionRandom } from '../../../domain/usecases/OauthTokenSelectUseCase';
|
|
2
|
+
import { LiveSessionOauthTokenSelectUseCase, LiveSessionOauthTokenSelectionSettings } from '../../../domain/usecases/LiveSessionOauthTokenSelectUseCase';
|
|
4
3
|
export type LiveSessionOauthTokenSelectHandlerInput = {
|
|
5
4
|
tokenListJsonPath: string | null;
|
|
6
5
|
cacheDirectory: string | null;
|
|
7
6
|
nowEpochSeconds: number;
|
|
7
|
+
selectionSettings: LiveSessionOauthTokenSelectionSettings;
|
|
8
8
|
};
|
|
9
9
|
export type LiveSessionOauthTokenSelectHandlerOutput = {
|
|
10
10
|
selectedToken: string | null;
|
|
@@ -14,8 +14,7 @@ export type LiveSessionOauthTokenSelectHandlerOutput = {
|
|
|
14
14
|
export declare class LiveSessionOauthTokenSelectHandler {
|
|
15
15
|
private readonly useCase;
|
|
16
16
|
private readonly liveSessionRepository;
|
|
17
|
-
|
|
18
|
-
constructor(useCase?: LiveSessionOauthTokenSelectUseCase, liveSessionRepository?: ClaudeLiveSessionRepository, random?: SelectionRandom);
|
|
17
|
+
constructor(useCase?: LiveSessionOauthTokenSelectUseCase, liveSessionRepository?: ClaudeLiveSessionRepository);
|
|
19
18
|
handle: (input: LiveSessionOauthTokenSelectHandlerInput) => LiveSessionOauthTokenSelectHandlerOutput;
|
|
20
19
|
private formatDiagnostics;
|
|
21
20
|
}
|
|
@@ -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,
|
|
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,EAClC,sCAAsC,EACvC,MAAM,6DAA6D,CAAC;AAerE,MAAM,MAAM,uCAAuC,GAAG;IACpD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,sCAAsC,CAAC;CAC3D,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;gBADrB,OAAO,GAAE,kCAA6E,EACtF,qBAAqB,GAAE,2BAAmE;IAG7G,MAAM,GACJ,OAAO,uCAAuC,KAC7C,wCAAwC,CAmEzC;IAEF,OAAO,CAAC,iBAAiB,CAyBvB;CACH"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { ClaudeLiveSession } from './adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
-
import { OauthTokenCandidate, OauthTokenSelectUseCase
|
|
2
|
+
import { OauthTokenCandidate, OauthTokenSelectUseCase } from './OauthTokenSelectUseCase';
|
|
3
|
+
export type LiveSessionOauthTokenSelectionSettings = {
|
|
4
|
+
maxConcurrentSessionCount: number;
|
|
5
|
+
fullSpeedFiveHourFreeRatio: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const DEFAULT_LIVE_SESSION_OAUTH_TOKEN_SELECTION_SETTINGS: LiveSessionOauthTokenSelectionSettings;
|
|
8
|
+
export declare const liveSessionConcurrentLimitOf: (fiveHourFreeRatio: number, selectionWeight: number, settings: LiveSessionOauthTokenSelectionSettings) => number;
|
|
3
9
|
export type LiveSessionOauthTokenCandidateMetrics = {
|
|
4
10
|
name: string;
|
|
5
11
|
fiveHourFreeRatio: number;
|
|
6
12
|
sevenDayFreeRatio: number;
|
|
7
13
|
sevenDayEndEpoch: number;
|
|
8
14
|
liveSessionCount: number;
|
|
15
|
+
concurrentSessionLimit: number;
|
|
16
|
+
hasConcurrencyHeadroom: boolean;
|
|
9
17
|
eligible: boolean;
|
|
10
18
|
exclusionReason: string | null;
|
|
11
19
|
};
|
|
@@ -16,7 +24,7 @@ export type LiveSessionOauthTokenSelectResult = {
|
|
|
16
24
|
export declare class LiveSessionOauthTokenSelectUseCase {
|
|
17
25
|
private readonly rateLimitSelectUseCase;
|
|
18
26
|
constructor(rateLimitSelectUseCase?: OauthTokenSelectUseCase);
|
|
19
|
-
run: (candidates: OauthTokenCandidate[], liveSessions: ClaudeLiveSession[], nowEpochSeconds: number,
|
|
27
|
+
run: (candidates: OauthTokenCandidate[], liveSessions: ClaudeLiveSession[], nowEpochSeconds: number, settings: LiveSessionOauthTokenSelectionSettings) => LiveSessionOauthTokenSelectResult;
|
|
20
28
|
private preferred;
|
|
21
29
|
private liveSessionCountByToken;
|
|
22
30
|
}
|
|
@@ -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,
|
|
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,EAExB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,sCAAsC,GAAG;IACnD,yBAAyB,EAAE,MAAM,CAAC;IAClC,0BAA0B,EAAE,MAAM,CAAC;CACpC,CAAC;AAEF,eAAO,MAAM,mDAAmD,EAAE,sCAI/D,CAAC;AAEJ,eAAO,MAAM,4BAA4B,GACvC,mBAAmB,MAAM,EACzB,iBAAiB,MAAM,EACvB,UAAU,sCAAsC,KAC/C,MAaF,CAAC;AAEF,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,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,OAAO,CAAC;IAChC,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,UAAU,sCAAsC,KAC/C,iCAAiC,CA+ClC;IAEF,OAAO,CAAC,SAAS,CAgBf;IAEF,OAAO,CAAC,uBAAuB,CAe7B;CACH"}
|