github-issue-tower-defence-management 1.104.4 → 1.106.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +8 -7
- package/bin/adapter/entry-points/cli/index.js +21 -13
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/console/{consoleServer.js → webServer.js} +11 -11
- package/bin/adapter/entry-points/console/webServer.js.map +1 -0
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +54 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/dashboardRowWriter.js +34 -0
- package/bin/adapter/entry-points/handlers/dashboardRowWriter.js.map +1 -0
- package/bin/adapter/entry-points/handlers/machineStatusWriter.js +60 -0
- package/bin/adapter/entry-points/handlers/machineStatusWriter.js.map +1 -0
- package/bin/adapter/entry-points/handlers/staleTmuxSessionCleaner.js +18 -0
- package/bin/adapter/entry-points/handlers/staleTmuxSessionCleaner.js.map +1 -0
- package/bin/adapter/entry-points/handlers/tokenStatusWriter.js +98 -0
- package/bin/adapter/entry-points/handlers/tokenStatusWriter.js.map +1 -0
- package/bin/adapter/proxy/RateLimitCache.js +3 -0
- package/bin/adapter/proxy/RateLimitCache.js.map +1 -1
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js +22 -0
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -1
- package/bin/adapter/repositories/ProcHostMetricsRepository.js +136 -0
- package/bin/adapter/repositories/ProcHostMetricsRepository.js.map +1 -0
- package/bin/adapter/repositories/ProcTakeOwnershipSpawnRepository.js +131 -0
- package/bin/adapter/repositories/ProcTakeOwnershipSpawnRepository.js.map +1 -0
- package/bin/domain/entities/LiveTmuxSession.js +3 -0
- package/bin/domain/entities/LiveTmuxSession.js.map +1 -0
- package/bin/domain/usecases/StaleTmuxSessionKillUseCase.js +58 -0
- package/bin/domain/usecases/StaleTmuxSessionKillUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.js.map +1 -0
- package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js +38 -0
- package/bin/domain/usecases/dashboard/GenerateDashboardRowUseCase.js.map +1 -0
- package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js +115 -0
- package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +74 -21
- package/src/adapter/entry-points/cli/index.ts +146 -136
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +2 -2
- package/src/adapter/entry-points/console/{consoleServer.test.ts → webServer.test.ts} +32 -32
- package/src/adapter/entry-points/console/{consoleServer.ts → webServer.ts} +15 -17
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +69 -0
- package/src/adapter/entry-points/handlers/dashboardRowWriter.test.ts +111 -0
- package/src/adapter/entry-points/handlers/dashboardRowWriter.ts +51 -0
- package/src/adapter/entry-points/handlers/machineStatusWriter.test.ts +100 -0
- package/src/adapter/entry-points/handlers/machineStatusWriter.ts +79 -0
- package/src/adapter/entry-points/handlers/staleTmuxSessionCleaner.test.ts +170 -0
- package/src/adapter/entry-points/handlers/staleTmuxSessionCleaner.ts +40 -0
- package/src/adapter/entry-points/handlers/tokenStatusWriter.test.ts +176 -0
- package/src/adapter/entry-points/handlers/tokenStatusWriter.ts +139 -0
- package/src/adapter/proxy/RateLimitCache.test.ts +32 -0
- package/src/adapter/proxy/RateLimitCache.ts +6 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +81 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.ts +35 -0
- package/src/adapter/repositories/ProcHostMetricsRepository.test.ts +135 -0
- package/src/adapter/repositories/ProcHostMetricsRepository.ts +136 -0
- package/src/adapter/repositories/ProcTakeOwnershipSpawnRepository.test.ts +130 -0
- package/src/adapter/repositories/ProcTakeOwnershipSpawnRepository.ts +118 -0
- package/src/domain/entities/LiveTmuxSession.ts +4 -0
- package/src/domain/usecases/StaleTmuxSessionKillUseCase.test.ts +286 -0
- package/src/domain/usecases/StaleTmuxSessionKillUseCase.ts +102 -0
- package/src/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.ts +8 -0
- package/src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts +4 -0
- package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.test.ts +159 -0
- package/src/domain/usecases/dashboard/GenerateDashboardRowUseCase.ts +72 -0
- package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.test.ts +209 -0
- package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts +195 -0
- package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +6 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/console/{consoleServer.d.ts → webServer.d.ts} +7 -7
- package/types/adapter/entry-points/console/webServer.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/dashboardRowWriter.d.ts +15 -0
- package/types/adapter/entry-points/handlers/dashboardRowWriter.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts +16 -0
- package/types/adapter/entry-points/handlers/machineStatusWriter.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/staleTmuxSessionCleaner.d.ts +12 -0
- package/types/adapter/entry-points/handlers/staleTmuxSessionCleaner.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts +21 -0
- package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts.map +1 -0
- package/types/adapter/proxy/RateLimitCache.d.ts +2 -0
- package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -1
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +3 -0
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -1
- package/types/adapter/repositories/ProcHostMetricsRepository.d.ts +23 -0
- package/types/adapter/repositories/ProcHostMetricsRepository.d.ts.map +1 -0
- package/types/adapter/repositories/ProcTakeOwnershipSpawnRepository.d.ts +11 -0
- package/types/adapter/repositories/ProcTakeOwnershipSpawnRepository.d.ts.map +1 -0
- package/types/domain/entities/LiveTmuxSession.d.ts +5 -0
- package/types/domain/entities/LiveTmuxSession.d.ts.map +1 -0
- package/types/domain/usecases/StaleTmuxSessionKillUseCase.d.ts +19 -0
- package/types/domain/usecases/StaleTmuxSessionKillUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.d.ts +8 -0
- package/types/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts +3 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts.map +1 -1
- package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts +19 -0
- package/types/domain/usecases/dashboard/GenerateDashboardRowUseCase.d.ts.map +1 -0
- package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts +53 -0
- package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts.map +1 -0
- package/bin/adapter/entry-points/console/consoleServer.js.map +0 -1
- package/types/adapter/entry-points/console/consoleServer.d.ts.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaleTmuxSessionKillUseCase = exports.DEFAULT_IDLE_THRESHOLD_SECONDS = exports.DEFAULT_EXCLUDED_STATUS = void 0;
|
|
4
|
+
const WorkflowStatus_1 = require("../entities/WorkflowStatus");
|
|
5
|
+
const InTmuxByHumanSessionReconcileUseCase_1 = require("./intmux/InTmuxByHumanSessionReconcileUseCase");
|
|
6
|
+
exports.DEFAULT_EXCLUDED_STATUS = WorkflowStatus_1.IN_TMUX_STATUS_NAME;
|
|
7
|
+
exports.DEFAULT_IDLE_THRESHOLD_SECONDS = 24 * 60 * 60;
|
|
8
|
+
class StaleTmuxSessionKillUseCase {
|
|
9
|
+
constructor(issueRepository, tmuxSessionRepository) {
|
|
10
|
+
this.issueRepository = issueRepository;
|
|
11
|
+
this.tmuxSessionRepository = tmuxSessionRepository;
|
|
12
|
+
this.run = async (params) => {
|
|
13
|
+
const liveSessions = await this.tmuxSessionRepository.listLiveSessionsWithActivity();
|
|
14
|
+
const openIssues = await this.issueRepository.getAllOpened(params.project, params.allowCacheMinutes);
|
|
15
|
+
const issueBySessionName = new Map();
|
|
16
|
+
for (const issue of openIssues) {
|
|
17
|
+
issueBySessionName.set((0, InTmuxByHumanSessionReconcileUseCase_1.toTmuxSessionName)(issue.url), issue);
|
|
18
|
+
}
|
|
19
|
+
const nowEpochSeconds = Math.floor(params.now.getTime() / 1000);
|
|
20
|
+
const killCandidates = [];
|
|
21
|
+
for (const session of liveSessions) {
|
|
22
|
+
const reason = this.evaluateKillReason(session, issueBySessionName.get(session.sessionName) ?? null, nowEpochSeconds, params.excludedStatus, params.idleThresholdSeconds);
|
|
23
|
+
if (reason !== null) {
|
|
24
|
+
killCandidates.push({ sessionName: session.sessionName, reason });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
console.log(`Stale tmux session cleanup: ${killCandidates.length} kill candidate(s) of ${liveSessions.length} live session(s).`);
|
|
28
|
+
for (const candidate of killCandidates) {
|
|
29
|
+
console.log(`Kill candidate: ${candidate.sessionName} (${candidate.reason})`);
|
|
30
|
+
}
|
|
31
|
+
for (const candidate of killCandidates) {
|
|
32
|
+
await this.tmuxSessionRepository.killSession(candidate.sessionName);
|
|
33
|
+
console.log(`Killed tmux session: ${candidate.sessionName} (${candidate.reason})`);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
this.evaluateKillReason = (session, issue, nowEpochSeconds, excludedStatus, idleThresholdSeconds) => {
|
|
37
|
+
if (issue !== null) {
|
|
38
|
+
if (issue.status !== excludedStatus) {
|
|
39
|
+
return `mapped to open issue ${issue.url} with status "${issue.status ?? 'null'}" which is not the excluded status "${excludedStatus}"`;
|
|
40
|
+
}
|
|
41
|
+
if (issue.nextActionDate !== null) {
|
|
42
|
+
return `mapped to open issue ${issue.url} which has a next action date set`;
|
|
43
|
+
}
|
|
44
|
+
if (issue.nextActionHour !== null) {
|
|
45
|
+
return `mapped to open issue ${issue.url} which has a next action hour set`;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const idleSeconds = nowEpochSeconds - session.activityEpochSeconds;
|
|
50
|
+
if (idleSeconds >= idleThresholdSeconds) {
|
|
51
|
+
return `maps to no open issue and has been idle for ${idleSeconds} seconds (threshold ${idleThresholdSeconds} seconds)`;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.StaleTmuxSessionKillUseCase = StaleTmuxSessionKillUseCase;
|
|
58
|
+
//# sourceMappingURL=StaleTmuxSessionKillUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StaleTmuxSessionKillUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StaleTmuxSessionKillUseCase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TakeOwnershipSpawnRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/TakeOwnershipSpawnRepository.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GenerateDashboardRowUseCase = void 0;
|
|
4
|
+
const WorkflowStatus_1 = require("../../entities/WorkflowStatus");
|
|
5
|
+
const WORKFLOW_BLOCKER_STORY_MARKER = 'workflow blocker';
|
|
6
|
+
class GenerateDashboardRowUseCase {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.run = (input) => {
|
|
9
|
+
const { issues, assigneeLogin } = input;
|
|
10
|
+
const mine = (issue) => issue.isClosed === false && issue.assignees.includes(assigneeLogin);
|
|
11
|
+
const actionable = (issue) => mine(issue) &&
|
|
12
|
+
issue.dependedIssueUrls.length === 0 &&
|
|
13
|
+
issue.nextActionDate === null &&
|
|
14
|
+
issue.nextActionHour === null;
|
|
15
|
+
const countActionableWithStatus = (statusName) => issues.filter((issue) => issue.status === statusName && actionable(issue))
|
|
16
|
+
.length;
|
|
17
|
+
const countMineWithStatus = (statusName) => issues.filter((issue) => mine(issue) && issue.status === statusName)
|
|
18
|
+
.length;
|
|
19
|
+
return {
|
|
20
|
+
unread: countActionableWithStatus(WorkflowStatus_1.DEFAULT_STATUS_NAME),
|
|
21
|
+
todo: countActionableWithStatus(WorkflowStatus_1.TODO_STATUS_NAME),
|
|
22
|
+
qc: countActionableWithStatus(WorkflowStatus_1.AWAITING_QUALITY_CHECK_STATUS_NAME),
|
|
23
|
+
fail: countMineWithStatus(WorkflowStatus_1.FAILED_PREPARATION_STATUS_NAME),
|
|
24
|
+
pr: countMineWithStatus(WorkflowStatus_1.PREPARATION_STATUS_NAME),
|
|
25
|
+
ws: countActionableWithStatus(WorkflowStatus_1.AWAITING_WORKSPACE_STATUS_NAME),
|
|
26
|
+
dep: issues.filter((issue) => mine(issue) &&
|
|
27
|
+
issue.status === WorkflowStatus_1.AWAITING_WORKSPACE_STATUS_NAME &&
|
|
28
|
+
issue.dependedIssueUrls.length > 0).length,
|
|
29
|
+
blocker: issues.filter((issue) => mine(issue) &&
|
|
30
|
+
(issue.story ?? '')
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.includes(WORKFLOW_BLOCKER_STORY_MARKER)).length,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.GenerateDashboardRowUseCase = GenerateDashboardRowUseCase;
|
|
38
|
+
//# sourceMappingURL=GenerateDashboardRowUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerateDashboardRowUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/GenerateDashboardRowUseCase.ts"],"names":[],"mappings":";;;AACA,kEAOuC;AAkBvC,MAAM,6BAA6B,GAAG,kBAAkB,CAAC;AAEzD,MAAa,2BAA2B;IAAxC;QACE,QAAG,GAAG,CAAC,KAAgC,EAAgB,EAAE;YACvD,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;YAExC,MAAM,IAAI,GAAG,CAAC,KAAY,EAAW,EAAE,CACrC,KAAK,CAAC,QAAQ,KAAK,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YAEtE,MAAM,UAAU,GAAG,CAAC,KAAY,EAAW,EAAE,CAC3C,IAAI,CAAC,KAAK,CAAC;gBACX,KAAK,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC;gBACpC,KAAK,CAAC,cAAc,KAAK,IAAI;gBAC7B,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC;YAEhC,MAAM,yBAAyB,GAAG,CAAC,UAAkB,EAAU,EAAE,CAC/D,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,UAAU,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;iBACvE,MAAM,CAAC;YAEZ,MAAM,mBAAmB,GAAG,CAAC,UAAkB,EAAU,EAAE,CACzD,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC;iBACjE,MAAM,CAAC;YAEZ,OAAO;gBACL,MAAM,EAAE,yBAAyB,CAAC,oCAAmB,CAAC;gBACtD,IAAI,EAAE,yBAAyB,CAAC,iCAAgB,CAAC;gBACjD,EAAE,EAAE,yBAAyB,CAAC,mDAAkC,CAAC;gBACjE,IAAI,EAAE,mBAAmB,CAAC,+CAA8B,CAAC;gBACzD,EAAE,EAAE,mBAAmB,CAAC,wCAAuB,CAAC;gBAChD,EAAE,EAAE,yBAAyB,CAAC,+CAA8B,CAAC;gBAC7D,GAAG,EAAE,MAAM,CAAC,MAAM,CAChB,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,CAAC,KAAK,CAAC;oBACX,KAAK,CAAC,MAAM,KAAK,+CAA8B;oBAC/C,KAAK,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CACrC,CAAC,MAAM;gBACR,OAAO,EAAE,MAAM,CAAC,MAAM,CACpB,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,CAAC,KAAK,CAAC;oBACX,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;yBAChB,WAAW,EAAE;yBACb,QAAQ,CAAC,6BAA6B,CAAC,CAC7C,CAAC,MAAM;aACT,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CAAA;AA3CD,kEA2CC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GenerateTokenStatusUseCase = exports.judgeTokenColor = void 0;
|
|
4
|
+
const HIGH_UTILIZATION_THRESHOLD = 0.7;
|
|
5
|
+
const ALLOWED_WARNING_STATUS = 'allowed_warning';
|
|
6
|
+
const judgeTokenColor = (decision) => {
|
|
7
|
+
if (decision === null || decision.partial) {
|
|
8
|
+
return 'Y';
|
|
9
|
+
}
|
|
10
|
+
const fiveHourUtilization = decision.fiveHourUtilization ?? 0;
|
|
11
|
+
const sevenDayUtilization = decision.sevenDayUtilization ?? 0;
|
|
12
|
+
const fiveHourExhausted = fiveHourUtilization >= 1.0 || decision.fiveHourRejected;
|
|
13
|
+
const generalSevenDayRejected = decision.sevenDayRejected;
|
|
14
|
+
const bothModelsSevenDayRejected = decision.sevenDaySonnetRejected && decision.sevenDayOpusRejected;
|
|
15
|
+
const noModelUsable = decision.blocked ||
|
|
16
|
+
fiveHourExhausted ||
|
|
17
|
+
generalSevenDayRejected ||
|
|
18
|
+
bothModelsSevenDayRejected;
|
|
19
|
+
if (noModelUsable) {
|
|
20
|
+
return 'K';
|
|
21
|
+
}
|
|
22
|
+
if (decision.unifiedStatus === ALLOWED_WARNING_STATUS) {
|
|
23
|
+
return 'Y';
|
|
24
|
+
}
|
|
25
|
+
if (fiveHourUtilization >= HIGH_UTILIZATION_THRESHOLD ||
|
|
26
|
+
sevenDayUtilization >= HIGH_UTILIZATION_THRESHOLD) {
|
|
27
|
+
return 'Y';
|
|
28
|
+
}
|
|
29
|
+
return 'G';
|
|
30
|
+
};
|
|
31
|
+
exports.judgeTokenColor = judgeTokenColor;
|
|
32
|
+
class GenerateTokenStatusUseCase {
|
|
33
|
+
constructor() {
|
|
34
|
+
this.run = (input) => {
|
|
35
|
+
const { tokens, prepCountByToken, humCountByToken, nowEpochSeconds } = input;
|
|
36
|
+
return tokens.map((tokenInput) => {
|
|
37
|
+
const decision = this.toDecision(tokenInput.snapshot, nowEpochSeconds);
|
|
38
|
+
const normalized = this.normalizeWindows(tokenInput.snapshot, nowEpochSeconds);
|
|
39
|
+
return {
|
|
40
|
+
name: tokenInput.name,
|
|
41
|
+
fiveHourUtilizationPercent: normalized.fiveHourUtilizationPercent,
|
|
42
|
+
fiveHourResetSeconds: normalized.fiveHourResetSeconds,
|
|
43
|
+
sevenDayUtilizationPercent: normalized.sevenDayUtilizationPercent,
|
|
44
|
+
sevenDayResetSeconds: normalized.sevenDayResetSeconds,
|
|
45
|
+
color: (0, exports.judgeTokenColor)(decision),
|
|
46
|
+
prep: prepCountByToken.get(tokenInput.token) ?? 0,
|
|
47
|
+
hum: humCountByToken.get(tokenInput.token) ?? 0,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
this.normalizeWindows = (snapshot, nowEpochSeconds) => {
|
|
52
|
+
if (snapshot === null || !snapshot.hasWindowData) {
|
|
53
|
+
return {
|
|
54
|
+
fiveHourUtilizationPercent: null,
|
|
55
|
+
fiveHourResetSeconds: null,
|
|
56
|
+
sevenDayUtilizationPercent: null,
|
|
57
|
+
sevenDayResetSeconds: null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const fiveHourReset = snapshot.fiveHourReset > 0 ? snapshot.fiveHourReset : null;
|
|
61
|
+
const sevenDayReset = snapshot.sevenDayReset > 0 ? snapshot.sevenDayReset : null;
|
|
62
|
+
const fiveHourExpired = fiveHourReset !== null && fiveHourReset < nowEpochSeconds;
|
|
63
|
+
const sevenDayExpired = sevenDayReset !== null && sevenDayReset < nowEpochSeconds;
|
|
64
|
+
return {
|
|
65
|
+
fiveHourUtilizationPercent: fiveHourExpired
|
|
66
|
+
? 0
|
|
67
|
+
: Math.trunc(snapshot.fiveHourUtilization * 100),
|
|
68
|
+
fiveHourResetSeconds: fiveHourReset === null
|
|
69
|
+
? null
|
|
70
|
+
: Math.max(0, fiveHourReset - nowEpochSeconds),
|
|
71
|
+
sevenDayUtilizationPercent: sevenDayExpired
|
|
72
|
+
? 0
|
|
73
|
+
: Math.trunc(snapshot.sevenDayUtilization * 100),
|
|
74
|
+
sevenDayResetSeconds: sevenDayReset === null
|
|
75
|
+
? null
|
|
76
|
+
: Math.max(0, sevenDayReset - nowEpochSeconds),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
this.toDecision = (snapshot, nowEpochSeconds) => {
|
|
80
|
+
if (snapshot === null) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (!snapshot.hasWindowData) {
|
|
84
|
+
return {
|
|
85
|
+
fiveHourUtilization: null,
|
|
86
|
+
sevenDayUtilization: null,
|
|
87
|
+
fiveHourRejected: snapshot.fiveHourRejected,
|
|
88
|
+
sevenDayRejected: snapshot.sevenDayRejected,
|
|
89
|
+
blocked: snapshot.blocked,
|
|
90
|
+
unifiedStatus: snapshot.unifiedStatus,
|
|
91
|
+
sevenDaySonnetRejected: snapshot.sevenDaySonnetRejected,
|
|
92
|
+
sevenDayOpusRejected: snapshot.sevenDayOpusRejected,
|
|
93
|
+
partial: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const fiveHourExpired = snapshot.fiveHourReset > 0 && snapshot.fiveHourReset < nowEpochSeconds;
|
|
97
|
+
const sevenDayExpired = snapshot.sevenDayReset > 0 && snapshot.sevenDayReset < nowEpochSeconds;
|
|
98
|
+
return {
|
|
99
|
+
fiveHourUtilization: fiveHourExpired ? 0 : snapshot.fiveHourUtilization,
|
|
100
|
+
sevenDayUtilization: sevenDayExpired ? 0 : snapshot.sevenDayUtilization,
|
|
101
|
+
fiveHourRejected: fiveHourExpired ? false : snapshot.fiveHourRejected,
|
|
102
|
+
sevenDayRejected: sevenDayExpired ? false : snapshot.sevenDayRejected,
|
|
103
|
+
blocked: snapshot.blocked,
|
|
104
|
+
unifiedStatus: snapshot.unifiedStatus,
|
|
105
|
+
sevenDaySonnetRejected: snapshot.sevenDaySonnetRejected ||
|
|
106
|
+
(sevenDayExpired ? false : snapshot.sevenDayRejected),
|
|
107
|
+
sevenDayOpusRejected: snapshot.sevenDayOpusRejected ||
|
|
108
|
+
(sevenDayExpired ? false : snapshot.sevenDayRejected),
|
|
109
|
+
partial: false,
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.GenerateTokenStatusUseCase = GenerateTokenStatusUseCase;
|
|
115
|
+
//# sourceMappingURL=GenerateTokenStatusUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerateTokenStatusUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -73,23 +73,22 @@ jest.mock('../handlers/HandleScheduledEventUseCaseHandler', () => ({
|
|
|
73
73
|
handle: jest.fn().mockResolvedValue(null),
|
|
74
74
|
})),
|
|
75
75
|
}));
|
|
76
|
-
import type {
|
|
76
|
+
import type { StartWebServerOptions } from '../console/webServer';
|
|
77
77
|
|
|
78
|
-
const
|
|
79
|
-
.fn<Promise<unknown>, [
|
|
78
|
+
const mockStartWebServer = jest
|
|
79
|
+
.fn<Promise<unknown>, [StartWebServerOptions]>()
|
|
80
80
|
.mockResolvedValue({
|
|
81
81
|
close: jest.fn(),
|
|
82
82
|
address: jest.fn().mockReturnValue({ port: 9981 }),
|
|
83
83
|
});
|
|
84
|
-
jest.mock('../console/
|
|
84
|
+
jest.mock('../console/webServer', () => {
|
|
85
85
|
const actual: Record<string, unknown> = jest.requireActual(
|
|
86
|
-
'../console/
|
|
86
|
+
'../console/webServer',
|
|
87
87
|
);
|
|
88
88
|
return {
|
|
89
89
|
...actual,
|
|
90
|
-
|
|
91
|
-
options
|
|
92
|
-
): Promise<unknown> => mockStartConsoleServer(options),
|
|
90
|
+
startWebServer: (options: StartWebServerOptions): Promise<unknown> =>
|
|
91
|
+
mockStartWebServer(options),
|
|
93
92
|
};
|
|
94
93
|
});
|
|
95
94
|
|
|
@@ -1677,10 +1676,10 @@ mysteryKey: 'value'
|
|
|
1677
1676
|
});
|
|
1678
1677
|
});
|
|
1679
1678
|
|
|
1680
|
-
describe('
|
|
1679
|
+
describe('serveWeb', () => {
|
|
1681
1680
|
it('should appear in the CLI help output', () => {
|
|
1682
1681
|
const helpText = program.helpInformation();
|
|
1683
|
-
expect(helpText).toContain('
|
|
1682
|
+
expect(helpText).toContain('serveWeb');
|
|
1684
1683
|
});
|
|
1685
1684
|
|
|
1686
1685
|
it('should start the server on the default port 9981 when --port is omitted', async () => {
|
|
@@ -1690,13 +1689,13 @@ mysteryKey: 'value'
|
|
|
1690
1689
|
await program.parseAsync([
|
|
1691
1690
|
'node',
|
|
1692
1691
|
'test',
|
|
1693
|
-
'
|
|
1692
|
+
'serveWeb',
|
|
1694
1693
|
'--configFilePath',
|
|
1695
1694
|
configFilePath,
|
|
1696
1695
|
]);
|
|
1697
1696
|
|
|
1698
|
-
expect(
|
|
1699
|
-
const callArg =
|
|
1697
|
+
expect(mockStartWebServer).toHaveBeenCalledTimes(1);
|
|
1698
|
+
const callArg = mockStartWebServer.mock.calls[0][0];
|
|
1700
1699
|
expect(callArg.port).toBe(9981);
|
|
1701
1700
|
expect(callArg.accessToken).toBe('config-token');
|
|
1702
1701
|
expect(callArg.consoleDataOutputDir).toBeNull();
|
|
@@ -1717,7 +1716,7 @@ mysteryKey: 'value'
|
|
|
1717
1716
|
await program.parseAsync([
|
|
1718
1717
|
'node',
|
|
1719
1718
|
'test',
|
|
1720
|
-
'
|
|
1719
|
+
'serveWeb',
|
|
1721
1720
|
'--configFilePath',
|
|
1722
1721
|
configFilePath,
|
|
1723
1722
|
'--port',
|
|
@@ -1726,7 +1725,7 @@ mysteryKey: 'value'
|
|
|
1726
1725
|
'/tmp/console-data',
|
|
1727
1726
|
]);
|
|
1728
1727
|
|
|
1729
|
-
const callArg =
|
|
1728
|
+
const callArg = mockStartWebServer.mock.calls[0][0];
|
|
1730
1729
|
expect(callArg.port).toBe(12345);
|
|
1731
1730
|
expect(callArg.consoleDataOutputDir).toBe('/tmp/console-data');
|
|
1732
1731
|
|
|
@@ -1746,7 +1745,7 @@ mysteryKey: 'value'
|
|
|
1746
1745
|
program.parseAsync([
|
|
1747
1746
|
'node',
|
|
1748
1747
|
'test',
|
|
1749
|
-
'
|
|
1748
|
+
'serveWeb',
|
|
1750
1749
|
'--configFilePath',
|
|
1751
1750
|
configFilePath,
|
|
1752
1751
|
]),
|
|
@@ -1774,7 +1773,7 @@ mysteryKey: 'value'
|
|
|
1774
1773
|
program.parseAsync([
|
|
1775
1774
|
'node',
|
|
1776
1775
|
'test',
|
|
1777
|
-
'
|
|
1776
|
+
'serveWeb',
|
|
1778
1777
|
'--configFilePath',
|
|
1779
1778
|
configFilePath,
|
|
1780
1779
|
'--port',
|
|
@@ -1795,12 +1794,12 @@ mysteryKey: 'value'
|
|
|
1795
1794
|
await program.parseAsync([
|
|
1796
1795
|
'node',
|
|
1797
1796
|
'test',
|
|
1798
|
-
'
|
|
1797
|
+
'serveWeb',
|
|
1799
1798
|
'--configFilePath',
|
|
1800
1799
|
configFilePath,
|
|
1801
1800
|
]);
|
|
1802
1801
|
|
|
1803
|
-
const callArg =
|
|
1802
|
+
const callArg = mockStartWebServer.mock.calls[0][0];
|
|
1804
1803
|
expect(callArg.issueRepository).not.toBeNull();
|
|
1805
1804
|
expect(callArg.issueTitleStateCache).not.toBeNull();
|
|
1806
1805
|
|
|
@@ -1833,7 +1832,7 @@ mysteryKey: 'value'
|
|
|
1833
1832
|
program.parseAsync([
|
|
1834
1833
|
'node',
|
|
1835
1834
|
'test',
|
|
1836
|
-
'
|
|
1835
|
+
'serveWeb',
|
|
1837
1836
|
'--configFilePath',
|
|
1838
1837
|
configFilePath,
|
|
1839
1838
|
]),
|
|
@@ -1865,7 +1864,7 @@ mysteryKey: 'value'
|
|
|
1865
1864
|
program.parseAsync([
|
|
1866
1865
|
'node',
|
|
1867
1866
|
'test',
|
|
1868
|
-
'
|
|
1867
|
+
'serveWeb',
|
|
1869
1868
|
'--configFilePath',
|
|
1870
1869
|
configFilePath,
|
|
1871
1870
|
]),
|
|
@@ -1879,4 +1878,58 @@ mysteryKey: 'value'
|
|
|
1879
1878
|
processExitSpy.mockRestore();
|
|
1880
1879
|
});
|
|
1881
1880
|
});
|
|
1881
|
+
|
|
1882
|
+
describe('serveConsole (deprecated alias)', () => {
|
|
1883
|
+
it('should appear in the CLI help output', () => {
|
|
1884
|
+
const helpText = program.helpInformation();
|
|
1885
|
+
expect(helpText).toContain('serveConsole');
|
|
1886
|
+
});
|
|
1887
|
+
|
|
1888
|
+
it('should route to the same handler as serveWeb on the default port 9981', async () => {
|
|
1889
|
+
writeConfig({ ...defaultConfig, consoleAccessToken: 'config-token' });
|
|
1890
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
1891
|
+
|
|
1892
|
+
await program.parseAsync([
|
|
1893
|
+
'node',
|
|
1894
|
+
'test',
|
|
1895
|
+
'serveConsole',
|
|
1896
|
+
'--configFilePath',
|
|
1897
|
+
configFilePath,
|
|
1898
|
+
]);
|
|
1899
|
+
|
|
1900
|
+
expect(mockStartWebServer).toHaveBeenCalledTimes(1);
|
|
1901
|
+
const callArg = mockStartWebServer.mock.calls[0][0];
|
|
1902
|
+
expect(callArg.port).toBe(9981);
|
|
1903
|
+
expect(callArg.accessToken).toBe('config-token');
|
|
1904
|
+
expect(callArg.consoleDataOutputDir).toBeNull();
|
|
1905
|
+
expect(callArg.uiDistDir).toBe(
|
|
1906
|
+
path.join(__dirname, '..', 'console', 'ui-dist'),
|
|
1907
|
+
);
|
|
1908
|
+
|
|
1909
|
+
logSpy.mockRestore();
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
it('should use the provided --port and --consoleDataOutputDir', async () => {
|
|
1913
|
+
writeConfig({ ...defaultConfig, consoleAccessToken: 'config-token' });
|
|
1914
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
1915
|
+
|
|
1916
|
+
await program.parseAsync([
|
|
1917
|
+
'node',
|
|
1918
|
+
'test',
|
|
1919
|
+
'serveConsole',
|
|
1920
|
+
'--configFilePath',
|
|
1921
|
+
configFilePath,
|
|
1922
|
+
'--port',
|
|
1923
|
+
'12345',
|
|
1924
|
+
'--consoleDataOutputDir',
|
|
1925
|
+
'/tmp/console-data',
|
|
1926
|
+
]);
|
|
1927
|
+
|
|
1928
|
+
const callArg = mockStartWebServer.mock.calls[0][0];
|
|
1929
|
+
expect(callArg.port).toBe(12345);
|
|
1930
|
+
expect(callArg.consoleDataOutputDir).toBe('/tmp/console-data');
|
|
1931
|
+
|
|
1932
|
+
logSpy.mockRestore();
|
|
1933
|
+
});
|
|
1934
|
+
});
|
|
1882
1935
|
});
|