github-issue-tower-defence-management 1.83.0 → 1.84.1
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 +67 -4
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +19 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/consoleListsWriter.js +43 -0
- package/bin/adapter/entry-points/handlers/consoleListsWriter.js.map +1 -0
- package/bin/adapter/proxy/RateLimitCache.js +27 -2
- package/bin/adapter/proxy/RateLimitCache.js.map +1 -1
- package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +5 -1
- package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +6 -6
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js +101 -0
- package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js.map +1 -0
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +18 -0
- package/src/adapter/entry-points/handlers/consoleListsWriter.test.ts +167 -0
- package/src/adapter/entry-points/handlers/consoleListsWriter.ts +60 -0
- package/src/adapter/proxy/RateLimitCache.test.ts +95 -0
- package/src/adapter/proxy/RateLimitCache.ts +32 -1
- package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +43 -0
- package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +6 -1
- package/src/domain/entities/ClaudeTokenUsage.ts +1 -0
- package/src/domain/usecases/StartPreparationUseCase.test.ts +343 -0
- package/src/domain/usecases/StartPreparationUseCase.ts +6 -6
- package/src/domain/usecases/console/GenerateConsoleListsUseCase.test.ts +372 -0
- package/src/domain/usecases/console/GenerateConsoleListsUseCase.ts +206 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/consoleListsWriter.d.ts +13 -0
- package/types/adapter/entry-points/handlers/consoleListsWriter.d.ts.map +1 -0
- package/types/adapter/proxy/RateLimitCache.d.ts +1 -0
- package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -1
- package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -1
- package/types/domain/entities/ClaudeTokenUsage.d.ts +1 -0
- package/types/domain/entities/ClaudeTokenUsage.d.ts.map +1 -1
- package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts +63 -0
- package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts.map +1 -0
|
@@ -168,7 +168,7 @@ export class StartPreparationUseCase {
|
|
|
168
168
|
const nowEpochSeconds = Date.now() / 1000;
|
|
169
169
|
const eligibleTokens = tokenUsages
|
|
170
170
|
.filter((usage) => !usage.blocked)
|
|
171
|
-
.filter((usage) => !usage.
|
|
171
|
+
.filter((usage) => !usage.fiveHourRejected)
|
|
172
172
|
.filter((usage) => !this.isWithinCooldown(usage, nowEpochSeconds))
|
|
173
173
|
.filter(
|
|
174
174
|
(usage) =>
|
|
@@ -236,7 +236,7 @@ export class StartPreparationUseCase {
|
|
|
236
236
|
const nowEpochSeconds = Date.now() / 1000;
|
|
237
237
|
const selectedTokens = tokenUsages
|
|
238
238
|
.filter((usage) => !usage.blocked)
|
|
239
|
-
.filter((usage) => !usage.
|
|
239
|
+
.filter((usage) => !usage.fiveHourRejected)
|
|
240
240
|
.filter((usage) => !this.isWithinCooldown(usage, nowEpochSeconds))
|
|
241
241
|
.filter(
|
|
242
242
|
(usage) => !this.isModelWeeklyLimitRejected(usage, weeklyLimitType),
|
|
@@ -261,16 +261,16 @@ export class StartPreparationUseCase {
|
|
|
261
261
|
name: usage.name ?? '',
|
|
262
262
|
fiveHourUtilization: usage.fiveHourUtilization,
|
|
263
263
|
blocked: usage.blocked,
|
|
264
|
-
rejected: usage.
|
|
264
|
+
rejected: usage.fiveHourRejected,
|
|
265
265
|
thresholdExcluded:
|
|
266
266
|
!usage.blocked &&
|
|
267
|
-
!usage.
|
|
267
|
+
!usage.fiveHourRejected &&
|
|
268
268
|
!this.isWithinCooldown(usage, nowEpochSeconds) &&
|
|
269
269
|
!this.isModelWeeklyLimitRejected(usage, weeklyLimitType) &&
|
|
270
270
|
usage.fiveHourUtilization * 100 >= utilizationPercentageThreshold,
|
|
271
271
|
cooldownExcluded:
|
|
272
272
|
!usage.blocked &&
|
|
273
|
-
!usage.
|
|
273
|
+
!usage.fiveHourRejected &&
|
|
274
274
|
this.isWithinCooldown(usage, nowEpochSeconds),
|
|
275
275
|
}));
|
|
276
276
|
const selectedEntries: RotationOrderEntry[] = selectedTokens.map(
|
|
@@ -338,7 +338,7 @@ export class StartPreparationUseCase {
|
|
|
338
338
|
);
|
|
339
339
|
if (selectedTokens.length === 0) {
|
|
340
340
|
console.warn(
|
|
341
|
-
`All ${tokenUsages.length} configured Claude OAuth token(s) are unavailable (blocked, rejected, weekly limits for
|
|
341
|
+
`All ${tokenUsages.length} configured Claude OAuth token(s) are unavailable (blocked, 5h-window rejected, within cooldown, weekly limits for every candidate model exhausted, or 5h utilization >= ${params.utilizationPercentageThreshold}%). Skipping starting preparation.`,
|
|
342
342
|
);
|
|
343
343
|
return { rotationOrder };
|
|
344
344
|
}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { Issue } from '../../entities/Issue';
|
|
2
|
+
import { FieldOption, Project } from '../../entities/Project';
|
|
3
|
+
import { GenerateConsoleListsUseCase } from './GenerateConsoleListsUseCase';
|
|
4
|
+
|
|
5
|
+
const ASSIGNEE = 'owner-login';
|
|
6
|
+
|
|
7
|
+
const storyOption = (
|
|
8
|
+
id: string,
|
|
9
|
+
name: string,
|
|
10
|
+
color: FieldOption['color'],
|
|
11
|
+
): FieldOption => ({ id, name, color, description: '' });
|
|
12
|
+
|
|
13
|
+
const STORY_OPTIONS: FieldOption[] = [
|
|
14
|
+
storyOption('s1', 'regular / NO STORY; SET STORY FIELD', 'RED'),
|
|
15
|
+
storyOption('s2', 'Story Alpha', 'BLUE'),
|
|
16
|
+
storyOption('s3', 'Story Beta', 'GREEN'),
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const STATUS_OPTIONS: FieldOption[] = [
|
|
20
|
+
storyOption('st-unread', 'Unread', 'ORANGE'),
|
|
21
|
+
storyOption('st-aw', 'Awaiting Workspace', 'BLUE'),
|
|
22
|
+
storyOption('st-prep', 'Preparation', 'YELLOW'),
|
|
23
|
+
storyOption('st-failed', 'Failed Preparation', 'RED'),
|
|
24
|
+
storyOption('st-aqc', 'Awaiting Quality Check', 'GREEN'),
|
|
25
|
+
storyOption('st-todo', 'Todo by human', 'PINK'),
|
|
26
|
+
storyOption('st-tmux', 'In Tmux by human', 'RED'),
|
|
27
|
+
storyOption('st-done', 'Done', 'PURPLE'),
|
|
28
|
+
storyOption('st-icebox', 'Icebox', 'GRAY'),
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const baseProject = (story: Project['story']): Project => ({
|
|
32
|
+
id: 'project-node-id',
|
|
33
|
+
url: 'https://github.com/orgs/demo/projects/1',
|
|
34
|
+
databaseId: 1,
|
|
35
|
+
name: 'demo',
|
|
36
|
+
status: {
|
|
37
|
+
name: 'Status',
|
|
38
|
+
fieldId: 'status-field',
|
|
39
|
+
statuses: STATUS_OPTIONS,
|
|
40
|
+
},
|
|
41
|
+
nextActionDate: null,
|
|
42
|
+
nextActionHour: null,
|
|
43
|
+
story,
|
|
44
|
+
remainingEstimationMinutes: null,
|
|
45
|
+
dependedIssueUrlSeparatedByComma: null,
|
|
46
|
+
completionDate50PercentConfidence: null,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const projectWithStory: Project = baseProject({
|
|
50
|
+
name: 'story',
|
|
51
|
+
fieldId: 'story-field',
|
|
52
|
+
databaseId: 2,
|
|
53
|
+
stories: STORY_OPTIONS,
|
|
54
|
+
workflowManagementStory: { id: 'wm', name: 'workflow management' },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let issueCounter = 0;
|
|
58
|
+
const makeIssue = (overrides: Partial<Issue>): Issue => {
|
|
59
|
+
issueCounter += 1;
|
|
60
|
+
return {
|
|
61
|
+
nameWithOwner: 'demo/repo',
|
|
62
|
+
number: issueCounter,
|
|
63
|
+
title: `Issue ${issueCounter}`,
|
|
64
|
+
state: 'OPEN',
|
|
65
|
+
status: null,
|
|
66
|
+
story: null,
|
|
67
|
+
nextActionDate: null,
|
|
68
|
+
nextActionHour: null,
|
|
69
|
+
estimationMinutes: null,
|
|
70
|
+
dependedIssueUrls: [],
|
|
71
|
+
completionDate50PercentConfidence: null,
|
|
72
|
+
url: `https://github.com/demo/repo/issues/${issueCounter}`,
|
|
73
|
+
assignees: [ASSIGNEE],
|
|
74
|
+
labels: [],
|
|
75
|
+
org: 'demo',
|
|
76
|
+
repo: 'repo',
|
|
77
|
+
body: 'should never be projected',
|
|
78
|
+
itemId: `item-${issueCounter}`,
|
|
79
|
+
isPr: false,
|
|
80
|
+
isInProgress: false,
|
|
81
|
+
isClosed: false,
|
|
82
|
+
createdAt: new Date('2026-06-13T08:18:45.000Z'),
|
|
83
|
+
author: 'someone',
|
|
84
|
+
...overrides,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
describe('GenerateConsoleListsUseCase', () => {
|
|
89
|
+
const usecase = new GenerateConsoleListsUseCase();
|
|
90
|
+
const generatedAt = '2026-06-14T07:22:33Z';
|
|
91
|
+
|
|
92
|
+
beforeEach(() => {
|
|
93
|
+
issueCounter = 0;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const run = (issues: Issue[], project: Project = projectWithStory) =>
|
|
97
|
+
usecase.run({
|
|
98
|
+
project,
|
|
99
|
+
issues,
|
|
100
|
+
pjcode: 'demo',
|
|
101
|
+
assigneeLogin: ASSIGNEE,
|
|
102
|
+
generatedAt,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('common actionable filter', () => {
|
|
106
|
+
it('rejects closed issues', () => {
|
|
107
|
+
const result = run([makeIssue({ status: 'Unread', isClosed: true })]);
|
|
108
|
+
expect(result.unread.items).toHaveLength(0);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('rejects issues not assigned to the assignee login', () => {
|
|
112
|
+
const result = run([
|
|
113
|
+
makeIssue({ status: 'Unread', assignees: ['other-person'] }),
|
|
114
|
+
]);
|
|
115
|
+
expect(result.unread.items).toHaveLength(0);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('rejects issues with a depended issue url', () => {
|
|
119
|
+
const result = run([
|
|
120
|
+
makeIssue({
|
|
121
|
+
status: 'Unread',
|
|
122
|
+
dependedIssueUrls: ['https://github.com/demo/repo/issues/99'],
|
|
123
|
+
}),
|
|
124
|
+
]);
|
|
125
|
+
expect(result.unread.items).toHaveLength(0);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('rejects issues with a next action date', () => {
|
|
129
|
+
const result = run([
|
|
130
|
+
makeIssue({
|
|
131
|
+
status: 'Unread',
|
|
132
|
+
nextActionDate: new Date('2026-07-01T00:00:00.000Z'),
|
|
133
|
+
}),
|
|
134
|
+
]);
|
|
135
|
+
expect(result.unread.items).toHaveLength(0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('rejects issues with a next action hour', () => {
|
|
139
|
+
const result = run([makeIssue({ status: 'Unread', nextActionHour: 9 })]);
|
|
140
|
+
expect(result.unread.items).toHaveLength(0);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('accepts an issue that passes every actionable condition', () => {
|
|
144
|
+
const result = run([makeIssue({ status: 'Unread' })]);
|
|
145
|
+
expect(result.unread.items).toHaveLength(1);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('per-tab selectors', () => {
|
|
150
|
+
it('selects awaiting quality check items case-insensitively for prs', () => {
|
|
151
|
+
const result = run([
|
|
152
|
+
makeIssue({ status: 'awaiting quality check' }),
|
|
153
|
+
makeIssue({ status: 'Awaiting Quality Check' }),
|
|
154
|
+
makeIssue({ status: 'Unread' }),
|
|
155
|
+
]);
|
|
156
|
+
expect(result.prs.items).toHaveLength(2);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('selects unread items case-insensitively', () => {
|
|
160
|
+
const result = run([
|
|
161
|
+
makeIssue({ status: 'UNREAD' }),
|
|
162
|
+
makeIssue({ status: 'Awaiting Quality Check' }),
|
|
163
|
+
]);
|
|
164
|
+
expect(result.unread.items).toHaveLength(1);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('selects failed preparation items only with exact case', () => {
|
|
168
|
+
const result = run([
|
|
169
|
+
makeIssue({ status: 'Failed Preparation' }),
|
|
170
|
+
makeIssue({ status: 'failed preparation' }),
|
|
171
|
+
makeIssue({ status: 'FAILED PREPARATION' }),
|
|
172
|
+
]);
|
|
173
|
+
expect(result['failed-preparation'].items).toHaveLength(1);
|
|
174
|
+
expect(result['failed-preparation'].items[0].number).toBe(1);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('selects no-story items case-insensitively for triage', () => {
|
|
178
|
+
const result = run([
|
|
179
|
+
makeIssue({ story: 'regular / NO STORY; SET STORY FIELD' }),
|
|
180
|
+
makeIssue({ story: 'no story please' }),
|
|
181
|
+
makeIssue({ story: 'Story Alpha' }),
|
|
182
|
+
makeIssue({ story: null }),
|
|
183
|
+
]);
|
|
184
|
+
expect(result.triage.items).toHaveLength(2);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('common item projection', () => {
|
|
189
|
+
it('projects the expected keys and never includes a body field', () => {
|
|
190
|
+
const result = run([
|
|
191
|
+
makeIssue({
|
|
192
|
+
status: 'Unread',
|
|
193
|
+
story: 'Story Alpha',
|
|
194
|
+
labels: ['bug', 'p1'],
|
|
195
|
+
isPr: true,
|
|
196
|
+
}),
|
|
197
|
+
]);
|
|
198
|
+
const item = result.unread.items[0];
|
|
199
|
+
expect(Object.keys(item).sort()).toEqual(
|
|
200
|
+
[
|
|
201
|
+
'createdAt',
|
|
202
|
+
'isPr',
|
|
203
|
+
'itemId',
|
|
204
|
+
'labels',
|
|
205
|
+
'nameWithOwner',
|
|
206
|
+
'number',
|
|
207
|
+
'projectItemId',
|
|
208
|
+
'repo',
|
|
209
|
+
'story',
|
|
210
|
+
'title',
|
|
211
|
+
'url',
|
|
212
|
+
].sort(),
|
|
213
|
+
);
|
|
214
|
+
expect(item).not.toHaveProperty('body');
|
|
215
|
+
expect(item.repo).toBe('demo/repo');
|
|
216
|
+
expect(item.nameWithOwner).toBe('demo/repo');
|
|
217
|
+
expect(item.projectItemId).toBe(item.itemId);
|
|
218
|
+
expect(item.isPr).toBe(true);
|
|
219
|
+
expect(item.story).toBe('Story Alpha');
|
|
220
|
+
expect(item.labels).toEqual(['bug', 'p1']);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('maps a null story to an empty string', () => {
|
|
224
|
+
const result = run([makeIssue({ status: 'Unread', story: null })]);
|
|
225
|
+
expect(result.unread.items[0].story).toBe('');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('serializes createdAt as an ISO string keeping milliseconds', () => {
|
|
229
|
+
const result = run([
|
|
230
|
+
makeIssue({
|
|
231
|
+
status: 'Unread',
|
|
232
|
+
createdAt: new Date('2026-06-13T08:18:45.000Z'),
|
|
233
|
+
}),
|
|
234
|
+
]);
|
|
235
|
+
expect(result.unread.items[0].createdAt).toBe('2026-06-13T08:18:45.000Z');
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('story order stable sort', () => {
|
|
240
|
+
it('sorts by story field order and places unknown stories last', () => {
|
|
241
|
+
const result = run([
|
|
242
|
+
makeIssue({ status: 'Unread', story: 'Story Beta' }),
|
|
243
|
+
makeIssue({ status: 'Unread', story: 'Unmapped Story' }),
|
|
244
|
+
makeIssue({ status: 'Unread', story: 'Story Alpha' }),
|
|
245
|
+
makeIssue({ status: 'Unread', story: 'Story Beta' }),
|
|
246
|
+
]);
|
|
247
|
+
expect(result.unread.items.map((i) => i.story)).toEqual([
|
|
248
|
+
'Story Alpha',
|
|
249
|
+
'Story Beta',
|
|
250
|
+
'Story Beta',
|
|
251
|
+
'Unmapped Story',
|
|
252
|
+
]);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('keeps original order between items sharing the same story (stable)', () => {
|
|
256
|
+
const result = run([
|
|
257
|
+
makeIssue({ status: 'Unread', story: 'Story Alpha', title: 'first' }),
|
|
258
|
+
makeIssue({ status: 'Unread', story: 'Story Alpha', title: 'second' }),
|
|
259
|
+
]);
|
|
260
|
+
expect(result.unread.items.map((i) => i.title)).toEqual([
|
|
261
|
+
'first',
|
|
262
|
+
'second',
|
|
263
|
+
]);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('options construction', () => {
|
|
268
|
+
it('excludes awaiting quality check and done from prs status options', () => {
|
|
269
|
+
const names = run([]).prs.statusOptions.map((o) => o.name);
|
|
270
|
+
expect(names).not.toContain('Awaiting Quality Check');
|
|
271
|
+
expect(names).not.toContain('Done');
|
|
272
|
+
expect(names).toContain('Unread');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('excludes unread and done from unread status options', () => {
|
|
276
|
+
const names = run([]).unread.statusOptions.map((o) => o.name);
|
|
277
|
+
expect(names).not.toContain('Unread');
|
|
278
|
+
expect(names).not.toContain('Done');
|
|
279
|
+
expect(names).toContain('Awaiting Workspace');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('excludes the failed-preparation routing-excluded set', () => {
|
|
283
|
+
const names = run([])['failed-preparation'].statusOptions.map(
|
|
284
|
+
(o) => o.name,
|
|
285
|
+
);
|
|
286
|
+
for (const excluded of [
|
|
287
|
+
'Failed Preparation',
|
|
288
|
+
'Done',
|
|
289
|
+
'Preparation',
|
|
290
|
+
'Icebox',
|
|
291
|
+
'Unread',
|
|
292
|
+
'In Tmux by human',
|
|
293
|
+
]) {
|
|
294
|
+
expect(names).not.toContain(excluded);
|
|
295
|
+
}
|
|
296
|
+
expect(names).toContain('Awaiting Workspace');
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('emits all story options for triage and no statusOptions key', () => {
|
|
300
|
+
const triage = run([]).triage;
|
|
301
|
+
expect(triage.storyOptions.map((o) => o.name)).toEqual([
|
|
302
|
+
'regular / NO STORY; SET STORY FIELD',
|
|
303
|
+
'Story Alpha',
|
|
304
|
+
'Story Beta',
|
|
305
|
+
]);
|
|
306
|
+
expect(triage).not.toHaveProperty('statusOptions');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('builds storyOrder from story field option order', () => {
|
|
310
|
+
expect(run([]).prs.storyOrder).toEqual([
|
|
311
|
+
'regular / NO STORY; SET STORY FIELD',
|
|
312
|
+
'Story Alpha',
|
|
313
|
+
'Story Beta',
|
|
314
|
+
]);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
describe('storyColors shape per tab', () => {
|
|
319
|
+
it('uses object color values for prs, unread and failed-preparation', () => {
|
|
320
|
+
const result = run([]);
|
|
321
|
+
expect(result.prs.storyColors['Story Alpha']).toEqual({ color: 'BLUE' });
|
|
322
|
+
expect(result.unread.storyColors['Story Beta']).toEqual({
|
|
323
|
+
color: 'GREEN',
|
|
324
|
+
});
|
|
325
|
+
expect(result['failed-preparation'].storyColors['Story Alpha']).toEqual({
|
|
326
|
+
color: 'BLUE',
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('uses plain string color values for triage', () => {
|
|
331
|
+
const result = run([]);
|
|
332
|
+
expect(result.triage.storyColors['Story Alpha']).toBe('BLUE');
|
|
333
|
+
expect(result.triage.storyColors['Story Beta']).toBe('GREEN');
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
describe('generatedAt and pjcode passthrough', () => {
|
|
338
|
+
it('writes the provided generatedAt without milliseconds on every tab', () => {
|
|
339
|
+
const result = run([]);
|
|
340
|
+
expect(result.prs.generatedAt).toBe(generatedAt);
|
|
341
|
+
expect(result.triage.generatedAt).toBe(generatedAt);
|
|
342
|
+
expect(result.unread.generatedAt).toBe(generatedAt);
|
|
343
|
+
expect(result['failed-preparation'].generatedAt).toBe(generatedAt);
|
|
344
|
+
expect(generatedAt).not.toMatch(/\.\d{3}Z$/);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('writes the configured pjcode on every tab', () => {
|
|
348
|
+
const result = run([]);
|
|
349
|
+
expect(result.prs.pjcode).toBe('demo');
|
|
350
|
+
expect(result.triage.pjcode).toBe('demo');
|
|
351
|
+
expect(result.unread.pjcode).toBe('demo');
|
|
352
|
+
expect(result['failed-preparation'].pjcode).toBe('demo');
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe('project without a story field', () => {
|
|
357
|
+
const projectNoStory = baseProject(null);
|
|
358
|
+
|
|
359
|
+
it('degrades story order, colors and triage options gracefully', () => {
|
|
360
|
+
const result = run(
|
|
361
|
+
[makeIssue({ status: 'Unread', story: 'no story' })],
|
|
362
|
+
projectNoStory,
|
|
363
|
+
);
|
|
364
|
+
expect(result.prs.storyOrder).toEqual([]);
|
|
365
|
+
expect(result.prs.storyColors).toEqual({});
|
|
366
|
+
expect(result.triage.storyOptions).toEqual([]);
|
|
367
|
+
expect(result.triage.storyColors).toEqual({});
|
|
368
|
+
expect(result.unread.items).toHaveLength(1);
|
|
369
|
+
expect(result.triage.items).toHaveLength(1);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Issue } from '../../entities/Issue';
|
|
2
|
+
import { FieldOption, Project } from '../../entities/Project';
|
|
3
|
+
|
|
4
|
+
export type ConsoleColor = FieldOption['color'];
|
|
5
|
+
|
|
6
|
+
export type ConsoleListItem = {
|
|
7
|
+
number: number;
|
|
8
|
+
title: string;
|
|
9
|
+
url: string;
|
|
10
|
+
repo: string;
|
|
11
|
+
nameWithOwner: string;
|
|
12
|
+
projectItemId: string;
|
|
13
|
+
itemId: string;
|
|
14
|
+
isPr: boolean;
|
|
15
|
+
story: string;
|
|
16
|
+
labels: string[];
|
|
17
|
+
createdAt: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ConsoleFieldOption = {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
color: ConsoleColor;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ConsoleStatusTab = {
|
|
27
|
+
pjcode: string;
|
|
28
|
+
generatedAt: string;
|
|
29
|
+
statusOptions: ConsoleFieldOption[];
|
|
30
|
+
storyOrder: string[];
|
|
31
|
+
storyColors: Record<string, { color: ConsoleColor }>;
|
|
32
|
+
items: ConsoleListItem[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type ConsoleTriageTab = {
|
|
36
|
+
pjcode: string;
|
|
37
|
+
generatedAt: string;
|
|
38
|
+
storyOptions: ConsoleFieldOption[];
|
|
39
|
+
storyOrder: string[];
|
|
40
|
+
storyColors: Record<string, ConsoleColor>;
|
|
41
|
+
items: ConsoleListItem[];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type ConsoleTabName = 'prs' | 'triage' | 'unread' | 'failed-preparation';
|
|
45
|
+
|
|
46
|
+
export type ConsoleLists = {
|
|
47
|
+
prs: ConsoleStatusTab;
|
|
48
|
+
triage: ConsoleTriageTab;
|
|
49
|
+
unread: ConsoleStatusTab;
|
|
50
|
+
'failed-preparation': ConsoleStatusTab;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type GenerateConsoleListsInput = {
|
|
54
|
+
project: Project;
|
|
55
|
+
issues: Issue[];
|
|
56
|
+
pjcode: string;
|
|
57
|
+
assigneeLogin: string;
|
|
58
|
+
generatedAt: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const UNKNOWN_STORY_SORT_INDEX = 999999;
|
|
62
|
+
|
|
63
|
+
export class GenerateConsoleListsUseCase {
|
|
64
|
+
run = (input: GenerateConsoleListsInput): ConsoleLists => {
|
|
65
|
+
const { project, issues, pjcode, assigneeLogin, generatedAt } = input;
|
|
66
|
+
|
|
67
|
+
const storyOptions = project.story ? project.story.stories : [];
|
|
68
|
+
const storyOrder = storyOptions.map((option) => option.name);
|
|
69
|
+
const statusOptions = project.status.statuses;
|
|
70
|
+
|
|
71
|
+
const actionableIssues = issues.filter((issue) =>
|
|
72
|
+
this.isActionable(issue, assigneeLogin),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const buildStatusTab = (
|
|
76
|
+
selector: (issue: Issue) => boolean,
|
|
77
|
+
excludedStatusNames: string[],
|
|
78
|
+
): ConsoleStatusTab => ({
|
|
79
|
+
pjcode,
|
|
80
|
+
generatedAt,
|
|
81
|
+
statusOptions: this.buildFieldOptions(statusOptions, excludedStatusNames),
|
|
82
|
+
storyOrder,
|
|
83
|
+
storyColors: this.buildStoryColorsObject(storyOptions),
|
|
84
|
+
items: this.sortByStoryOrder(
|
|
85
|
+
actionableIssues
|
|
86
|
+
.filter(selector)
|
|
87
|
+
.map((issue) => this.projectItem(issue)),
|
|
88
|
+
storyOrder,
|
|
89
|
+
),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
prs: buildStatusTab(
|
|
94
|
+
(issue) =>
|
|
95
|
+
issue.status !== null &&
|
|
96
|
+
issue.status.toLowerCase() === 'awaiting quality check',
|
|
97
|
+
['awaiting quality check', 'done'],
|
|
98
|
+
),
|
|
99
|
+
unread: buildStatusTab(
|
|
100
|
+
(issue) =>
|
|
101
|
+
issue.status !== null && issue.status.toLowerCase() === 'unread',
|
|
102
|
+
['unread', 'done'],
|
|
103
|
+
),
|
|
104
|
+
'failed-preparation': buildStatusTab(
|
|
105
|
+
(issue) => issue.status === 'Failed Preparation',
|
|
106
|
+
[
|
|
107
|
+
'failed preparation',
|
|
108
|
+
'done',
|
|
109
|
+
'preparation',
|
|
110
|
+
'icebox',
|
|
111
|
+
'unread',
|
|
112
|
+
'in tmux by human',
|
|
113
|
+
],
|
|
114
|
+
),
|
|
115
|
+
triage: {
|
|
116
|
+
pjcode,
|
|
117
|
+
generatedAt,
|
|
118
|
+
storyOptions: this.buildFieldOptions(storyOptions, []),
|
|
119
|
+
storyOrder,
|
|
120
|
+
storyColors: this.buildStoryColorsString(storyOptions),
|
|
121
|
+
items: this.sortByStoryOrder(
|
|
122
|
+
actionableIssues
|
|
123
|
+
.filter(
|
|
124
|
+
(issue) =>
|
|
125
|
+
issue.story !== null &&
|
|
126
|
+
issue.story.toLowerCase().includes('no story'),
|
|
127
|
+
)
|
|
128
|
+
.map((issue) => this.projectItem(issue)),
|
|
129
|
+
storyOrder,
|
|
130
|
+
),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
private isActionable = (issue: Issue, assigneeLogin: string): boolean =>
|
|
136
|
+
issue.isClosed === false &&
|
|
137
|
+
issue.assignees.includes(assigneeLogin) &&
|
|
138
|
+
issue.dependedIssueUrls.length === 0 &&
|
|
139
|
+
issue.nextActionDate === null &&
|
|
140
|
+
issue.nextActionHour === null;
|
|
141
|
+
|
|
142
|
+
private projectItem = (issue: Issue): ConsoleListItem => ({
|
|
143
|
+
number: issue.number,
|
|
144
|
+
title: issue.title,
|
|
145
|
+
url: issue.url,
|
|
146
|
+
repo: issue.nameWithOwner,
|
|
147
|
+
nameWithOwner: issue.nameWithOwner,
|
|
148
|
+
projectItemId: issue.itemId,
|
|
149
|
+
itemId: issue.itemId,
|
|
150
|
+
isPr: issue.isPr,
|
|
151
|
+
story: issue.story ?? '',
|
|
152
|
+
labels: issue.labels,
|
|
153
|
+
createdAt: issue.createdAt.toISOString(),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
private buildFieldOptions = (
|
|
157
|
+
options: FieldOption[],
|
|
158
|
+
excludedLowerCaseNames: string[],
|
|
159
|
+
): ConsoleFieldOption[] =>
|
|
160
|
+
options
|
|
161
|
+
.filter(
|
|
162
|
+
(option) => !excludedLowerCaseNames.includes(option.name.toLowerCase()),
|
|
163
|
+
)
|
|
164
|
+
.map((option) => ({
|
|
165
|
+
id: option.id,
|
|
166
|
+
name: option.name,
|
|
167
|
+
color: option.color,
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
private buildStoryColorsObject = (
|
|
171
|
+
options: FieldOption[],
|
|
172
|
+
): Record<string, { color: ConsoleColor }> => {
|
|
173
|
+
const result: Record<string, { color: ConsoleColor }> = {};
|
|
174
|
+
for (const option of options) {
|
|
175
|
+
result[option.name] = { color: option.color };
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
private buildStoryColorsString = (
|
|
181
|
+
options: FieldOption[],
|
|
182
|
+
): Record<string, ConsoleColor> => {
|
|
183
|
+
const result: Record<string, ConsoleColor> = {};
|
|
184
|
+
for (const option of options) {
|
|
185
|
+
result[option.name] = option.color;
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
private sortByStoryOrder = (
|
|
191
|
+
items: ConsoleListItem[],
|
|
192
|
+
storyOrder: string[],
|
|
193
|
+
): ConsoleListItem[] => {
|
|
194
|
+
const indexByStory = new Map(
|
|
195
|
+
storyOrder.map((name, index) => [name, index]),
|
|
196
|
+
);
|
|
197
|
+
return items
|
|
198
|
+
.map((item, position) => ({
|
|
199
|
+
item,
|
|
200
|
+
position,
|
|
201
|
+
sortKey: indexByStory.get(item.story) ?? UNKNOWN_STORY_SORT_INDEX,
|
|
202
|
+
}))
|
|
203
|
+
.sort((a, b) => a.sortKey - b.sortKey || a.position - b.position)
|
|
204
|
+
.map((entry) => entry.item);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AA8B3D,qBAAa,kCAAkC;IAC7C,MAAM,GACJ,gBAAgB,MAAM,EACtB,UAAU,OAAO,KAChB,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,CAmUP;CACH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Issue } from '../../../domain/entities/Issue';
|
|
2
|
+
import type { Project } from '../../../domain/entities/Project';
|
|
3
|
+
export type ConsoleListsWriterParams = {
|
|
4
|
+
consoleDataOutputDir: string | null | undefined;
|
|
5
|
+
pjcode: string | null | undefined;
|
|
6
|
+
assigneeLogin: string | null | undefined;
|
|
7
|
+
project: Project;
|
|
8
|
+
issues: Issue[];
|
|
9
|
+
generatedAt?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const formatConsoleGeneratedAt: (date: Date) => string;
|
|
12
|
+
export declare const writeConsoleLists: (params: ConsoleListsWriterParams) => void;
|
|
13
|
+
//# sourceMappingURL=consoleListsWriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleListsWriter.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/consoleListsWriter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAOhE,MAAM,MAAM,wBAAwB,GAAG;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChD,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AASF,eAAO,MAAM,wBAAwB,GAAI,MAAM,IAAI,KAAG,MACR,CAAC;AAU/C,eAAO,MAAM,iBAAiB,GAAI,QAAQ,wBAAwB,KAAG,IAsBpE,CAAC"}
|
|
@@ -25,5 +25,6 @@ export declare const cachePathForToken: (token: string) => string;
|
|
|
25
25
|
export declare const writeRateLimit: (token: string, headers: Record<string, string | string[] | undefined>, statusCode?: number | null) => void;
|
|
26
26
|
export declare const writeModelRateLimit: (token: string, limits: Record<string, ModelWeeklyLimit>) => void;
|
|
27
27
|
export declare const parseModelRateLimitsFromBody: (body: string) => Record<string, ModelWeeklyLimit>;
|
|
28
|
+
export declare const parseModelRateLimitsFromHeaders: (headers: Record<string, string>) => Record<string, ModelWeeklyLimit>;
|
|
28
29
|
export declare const readRateLimit: (token: string) => RateLimitSnapshot | null;
|
|
29
30
|
//# sourceMappingURL=RateLimitCache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimitCache.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/RateLimitCache.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACpD,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,UAAU,OAAO,CAAC;AAI/B,eAAO,MAAM,uCAAuC,KAAK,CAAC;AAE1D,eAAO,MAAM,mCAAmC,MAAM,CAAC;AAEvD,eAAO,MAAM,QAAQ,QAAO,MAG3B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MACqB,CAAC;AAEhE,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MACC,CAAC;AA4CpD,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,aAAY,MAAM,GAAG,IAAW,KAC/B,IAmDF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,QAAQ,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KACvC,IAkBF,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,MAAM,MAAM,KACX,MAAM,CAAC,MAAM,EAAE,gBAAgB,CA0BjC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,iBAAiB,GAAG,
|
|
1
|
+
{"version":3,"file":"RateLimitCache.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/RateLimitCache.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACpD,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,UAAU,OAAO,CAAC;AAI/B,eAAO,MAAM,uCAAuC,KAAK,CAAC;AAE1D,eAAO,MAAM,mCAAmC,MAAM,CAAC;AAEvD,eAAO,MAAM,QAAQ,QAAO,MAG3B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,MACqB,CAAC;AAEhE,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MACC,CAAC;AA4CpD,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,aAAY,MAAM,GAAG,IAAW,KAC/B,IAmDF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,QAAQ,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,KACvC,IAkBF,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,MAAM,MAAM,KACX,MAAM,CAAC,MAAM,EAAE,gBAAgB,CA0BjC,CAAC;AAOF,eAAO,MAAM,+BAA+B,GAC1C,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC9B,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAmBjC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,iBAAiB,GAAG,IAwDjE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProxyClaudeTokenUsageRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qEAAqE,CAAC;AAKjH,qBAAa,+BAAgC,YAAW,0BAA0B;IAE9E,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,IAAI,GAAE,MAAmB;IAG5C,gBAAgB,QAAa,OAAO,CAAC,IAAI,CAAC,CAExC;IAEF,uBAAuB,QAAa,OAAO,CAAC,gBAAgB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"ProxyClaudeTokenUsageRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qEAAqE,CAAC;AAKjH,qBAAa,+BAAgC,YAAW,0BAA0B;IAE9E,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,IAAI,GAAE,MAAmB;IAG5C,gBAAgB,QAAa,OAAO,CAAC,IAAI,CAAC,CAExC;IAEF,uBAAuB,QAAa,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAqF7D;IAEF,sBAAsB,QAAa,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiChE;IAEF,OAAO,CAAC,aAAa,CAYnB;IAEF,YAAY,QAAO,MAAM,CAAoC;CAC9D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeTokenUsage.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/ClaudeTokenUsage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC"}
|
|
1
|
+
{"version":3,"file":"ClaudeTokenUsage.d.ts","sourceRoot":"","sources":["../../../src/domain/entities/ClaudeTokenUsage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC"}
|