github-issue-tower-defence-management 1.88.0 → 1.88.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 +7 -0
- package/README.md +9 -1
- package/bin/adapter/entry-points/cli/index.js +35 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/console/consoleDataDelivery.js +155 -0
- package/bin/adapter/entry-points/console/consoleDataDelivery.js.map +1 -0
- package/bin/adapter/entry-points/console/consoleDoneStore.js +100 -0
- package/bin/adapter/entry-points/console/consoleDoneStore.js.map +1 -0
- package/bin/adapter/entry-points/console/consoleOperationApi.js +178 -0
- package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -0
- package/bin/adapter/entry-points/console/consoleReadApi.js +119 -0
- package/bin/adapter/entry-points/console/consoleReadApi.js.map +1 -0
- package/bin/adapter/entry-points/console/consoleServer.js +147 -3
- package/bin/adapter/entry-points/console/consoleServer.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +3 -0
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.test.ts +94 -0
- package/src/adapter/entry-points/cli/index.ts +61 -0
- package/src/adapter/entry-points/console/consoleDataDelivery.test.ts +184 -0
- package/src/adapter/entry-points/console/consoleDataDelivery.ts +169 -0
- package/src/adapter/entry-points/console/consoleDoneStore.test.ts +98 -0
- package/src/adapter/entry-points/console/consoleDoneStore.ts +91 -0
- package/src/adapter/entry-points/console/consoleOperationApi.test.ts +444 -0
- package/src/adapter/entry-points/console/consoleOperationApi.ts +280 -0
- package/src/adapter/entry-points/console/consoleReadApi.test.ts +297 -0
- package/src/adapter/entry-points/console/consoleReadApi.ts +192 -0
- package/src/adapter/entry-points/console/consoleServer.test.ts +269 -0
- package/src/adapter/entry-points/console/consoleServer.ts +228 -4
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +34 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +3 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/console/consoleDataDelivery.d.ts +23 -0
- package/types/adapter/entry-points/console/consoleDataDelivery.d.ts.map +1 -0
- package/types/adapter/entry-points/console/consoleDoneStore.d.ts +10 -0
- package/types/adapter/entry-points/console/consoleDoneStore.d.ts.map +1 -0
- package/types/adapter/entry-points/console/consoleOperationApi.d.ts +18 -0
- package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -0
- package/types/adapter/entry-points/console/consoleReadApi.d.ts +44 -0
- package/types/adapter/entry-points/console/consoleReadApi.d.ts.map +1 -0
- package/types/adapter/entry-points/console/consoleServer.d.ts +8 -1
- package/types/adapter/entry-points/console/consoleServer.d.ts.map +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
+
import { IssueRepository } from '../../../domain/usecases/adapter-interfaces/IssueRepository';
|
|
5
|
+
import { Project } from '../../../domain/entities/Project';
|
|
6
|
+
import {
|
|
7
|
+
buildConsoleDataResponse,
|
|
8
|
+
parseConsoleDataRoute,
|
|
9
|
+
} from './consoleDataDelivery';
|
|
10
|
+
import {
|
|
11
|
+
IssueTitleStateCache,
|
|
12
|
+
handleComments,
|
|
13
|
+
handleIssueTitle,
|
|
14
|
+
handleItemBody,
|
|
15
|
+
handlePrCommits,
|
|
16
|
+
handlePrFiles,
|
|
17
|
+
handleRelatedPrs,
|
|
18
|
+
} from './consoleReadApi';
|
|
19
|
+
import {
|
|
20
|
+
ConsoleOperationContext,
|
|
21
|
+
handleIntmux,
|
|
22
|
+
handleReview,
|
|
23
|
+
handleTriage,
|
|
24
|
+
} from './consoleOperationApi';
|
|
4
25
|
|
|
5
26
|
export const DEFAULT_CONSOLE_PORT = 9981;
|
|
6
27
|
|
|
@@ -108,6 +129,10 @@ export type ConsoleServerOptions = {
|
|
|
108
129
|
accessToken: string;
|
|
109
130
|
uiDistDir: string;
|
|
110
131
|
consoleDataOutputDir: string | null;
|
|
132
|
+
pjcode?: string | null;
|
|
133
|
+
issueRepository?: IssueRepository | null;
|
|
134
|
+
project?: Project | null;
|
|
135
|
+
issueTitleStateCache?: IssueTitleStateCache | null;
|
|
111
136
|
};
|
|
112
137
|
|
|
113
138
|
const sendNotFound = (response: http.ServerResponse): void => {
|
|
@@ -134,11 +159,189 @@ const serveBootstrapIndex = (response: http.ServerResponse): void => {
|
|
|
134
159
|
response.end(PLACEHOLDER_INDEX_HTML);
|
|
135
160
|
};
|
|
136
161
|
|
|
137
|
-
|
|
162
|
+
const sendJson = (
|
|
163
|
+
response: http.ServerResponse,
|
|
164
|
+
statusCode: number,
|
|
165
|
+
body: unknown,
|
|
166
|
+
): void => {
|
|
167
|
+
response.writeHead(statusCode, {
|
|
168
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
169
|
+
'Cache-Control': 'no-store',
|
|
170
|
+
});
|
|
171
|
+
response.end(JSON.stringify(body));
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const sendDataResponse = (
|
|
175
|
+
response: http.ServerResponse,
|
|
176
|
+
statusCode: number,
|
|
177
|
+
contentType: string,
|
|
178
|
+
body: string,
|
|
179
|
+
): void => {
|
|
180
|
+
response.writeHead(statusCode, {
|
|
181
|
+
'Content-Type': contentType,
|
|
182
|
+
'Cache-Control': 'no-store',
|
|
183
|
+
});
|
|
184
|
+
response.end(body);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const readRequestBody = (request: http.IncomingMessage): Promise<string> =>
|
|
188
|
+
new Promise((resolve, reject) => {
|
|
189
|
+
const chunks: Uint8Array[] = [];
|
|
190
|
+
request.on('data', (chunk: Uint8Array) => chunks.push(chunk));
|
|
191
|
+
request.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
192
|
+
request.on('error', reject);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
196
|
+
value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
197
|
+
|
|
198
|
+
const parseRequestBody = (raw: string): Record<string, unknown> | null => {
|
|
199
|
+
if (raw.length === 0) {
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
let parsed: unknown;
|
|
203
|
+
try {
|
|
204
|
+
parsed = JSON.parse(raw);
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
if (!isRecord(parsed)) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return parsed;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const handleReadApi = async (
|
|
215
|
+
options: ConsoleServerOptions,
|
|
216
|
+
requestPath: string,
|
|
217
|
+
searchParams: URLSearchParams,
|
|
218
|
+
): Promise<{ statusCode: number; body: unknown } | null> => {
|
|
219
|
+
const issueRepository = options.issueRepository ?? null;
|
|
220
|
+
if (issueRepository === null) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const cache = options.issueTitleStateCache ?? null;
|
|
224
|
+
const url = searchParams.get('url');
|
|
225
|
+
switch (requestPath) {
|
|
226
|
+
case '/api/itembody':
|
|
227
|
+
return handleItemBody(issueRepository, url);
|
|
228
|
+
case '/api/comments':
|
|
229
|
+
return handleComments(issueRepository, url);
|
|
230
|
+
case '/api/prfiles':
|
|
231
|
+
return handlePrFiles(issueRepository, url);
|
|
232
|
+
case '/api/prcommits':
|
|
233
|
+
return handlePrCommits(issueRepository, url);
|
|
234
|
+
case '/api/relatedprs':
|
|
235
|
+
return handleRelatedPrs(issueRepository, url);
|
|
236
|
+
case '/api/issuetitle':
|
|
237
|
+
if (cache === null) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
return handleIssueTitle(issueRepository, cache, url);
|
|
241
|
+
default:
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const handleOperationApi = async (
|
|
247
|
+
options: ConsoleServerOptions,
|
|
248
|
+
requestPath: string,
|
|
249
|
+
body: Record<string, unknown>,
|
|
250
|
+
): Promise<{ statusCode: number; body: unknown } | null> => {
|
|
251
|
+
const issueRepository = options.issueRepository ?? null;
|
|
252
|
+
const project = options.project ?? null;
|
|
253
|
+
if (issueRepository === null || project === null) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const context: ConsoleOperationContext = {
|
|
257
|
+
issueRepository,
|
|
258
|
+
project,
|
|
259
|
+
consoleDataOutputDir: options.consoleDataOutputDir,
|
|
260
|
+
pjcode: options.pjcode ?? null,
|
|
261
|
+
};
|
|
262
|
+
switch (requestPath) {
|
|
263
|
+
case '/api/review':
|
|
264
|
+
return handleReview(context, body);
|
|
265
|
+
case '/api/triage':
|
|
266
|
+
return handleTriage(context, body);
|
|
267
|
+
case '/api/intmux':
|
|
268
|
+
return handleIntmux(context, body);
|
|
269
|
+
default:
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const handleTokenedRequest = async (
|
|
138
275
|
options: ConsoleServerOptions,
|
|
139
276
|
request: http.IncomingMessage,
|
|
140
277
|
response: http.ServerResponse,
|
|
141
|
-
|
|
278
|
+
requestPath: string,
|
|
279
|
+
searchParams: URLSearchParams,
|
|
280
|
+
): Promise<void> => {
|
|
281
|
+
const method = (request.method ?? 'GET').toUpperCase();
|
|
282
|
+
|
|
283
|
+
if (requestPath.startsWith('/api/')) {
|
|
284
|
+
if (method === 'GET') {
|
|
285
|
+
const readResult = await handleReadApi(
|
|
286
|
+
options,
|
|
287
|
+
requestPath,
|
|
288
|
+
searchParams,
|
|
289
|
+
);
|
|
290
|
+
if (readResult === null) {
|
|
291
|
+
sendNotFound(response);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
sendJson(response, readResult.statusCode, readResult.body);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (method === 'POST') {
|
|
298
|
+
const raw = await readRequestBody(request);
|
|
299
|
+
const parsedBody = parseRequestBody(raw);
|
|
300
|
+
if (parsedBody === null) {
|
|
301
|
+
sendJson(response, 400, { error: 'invalid JSON body' });
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const operationResult = await handleOperationApi(
|
|
305
|
+
options,
|
|
306
|
+
requestPath,
|
|
307
|
+
parsedBody,
|
|
308
|
+
);
|
|
309
|
+
if (operationResult === null) {
|
|
310
|
+
sendNotFound(response);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
sendJson(response, operationResult.statusCode, operationResult.body);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
sendNotFound(response);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (method === 'GET') {
|
|
321
|
+
const dataRoute = parseConsoleDataRoute(requestPath);
|
|
322
|
+
if (dataRoute !== null && options.consoleDataOutputDir !== null) {
|
|
323
|
+
const dataResponse = buildConsoleDataResponse(
|
|
324
|
+
options.consoleDataOutputDir,
|
|
325
|
+
dataRoute,
|
|
326
|
+
);
|
|
327
|
+
sendDataResponse(
|
|
328
|
+
response,
|
|
329
|
+
dataResponse.statusCode,
|
|
330
|
+
dataResponse.contentType,
|
|
331
|
+
dataResponse.body,
|
|
332
|
+
);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
sendNotFound(response);
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
export const handleConsoleRequest = async (
|
|
341
|
+
options: ConsoleServerOptions,
|
|
342
|
+
request: http.IncomingMessage,
|
|
343
|
+
response: http.ServerResponse,
|
|
344
|
+
): Promise<void> => {
|
|
142
345
|
const requestUrl = new URL(request.url ?? '/', 'http://localhost');
|
|
143
346
|
const requestPath = requestUrl.pathname;
|
|
144
347
|
|
|
@@ -156,7 +359,13 @@ export const handleConsoleRequest = (
|
|
|
156
359
|
sendUnauthorized(response);
|
|
157
360
|
return;
|
|
158
361
|
}
|
|
159
|
-
|
|
362
|
+
await handleTokenedRequest(
|
|
363
|
+
options,
|
|
364
|
+
request,
|
|
365
|
+
response,
|
|
366
|
+
requestPath,
|
|
367
|
+
requestUrl.searchParams,
|
|
368
|
+
);
|
|
160
369
|
return;
|
|
161
370
|
}
|
|
162
371
|
|
|
@@ -196,11 +405,26 @@ export const handleConsoleRequest = (
|
|
|
196
405
|
response.end(staticContent);
|
|
197
406
|
};
|
|
198
407
|
|
|
408
|
+
const sendInternalServerError = (response: http.ServerResponse): void => {
|
|
409
|
+
if (response.headersSent) {
|
|
410
|
+
response.end();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
response.writeHead(500, {
|
|
414
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
415
|
+
'Cache-Control': 'no-store',
|
|
416
|
+
});
|
|
417
|
+
response.end('Internal Server Error');
|
|
418
|
+
};
|
|
419
|
+
|
|
199
420
|
export const createConsoleServer = (
|
|
200
421
|
options: ConsoleServerOptions,
|
|
201
422
|
): http.Server =>
|
|
202
423
|
http.createServer((request, response) => {
|
|
203
|
-
handleConsoleRequest(options, request, response)
|
|
424
|
+
handleConsoleRequest(options, request, response).catch((error) => {
|
|
425
|
+
console.error('console request failed', error);
|
|
426
|
+
sendInternalServerError(response);
|
|
427
|
+
});
|
|
204
428
|
});
|
|
205
429
|
|
|
206
430
|
export type StartConsoleServerOptions = ConsoleServerOptions & {
|
|
@@ -1876,6 +1876,40 @@ describe('NotifyFinishedIssuePreparationUseCase', () => {
|
|
|
1876
1876
|
);
|
|
1877
1877
|
});
|
|
1878
1878
|
|
|
1879
|
+
it('should not call setDependedIssueUrl when issue is a PR and the resolved PR URL matches the issue URL (self-reference prevention)', async () => {
|
|
1880
|
+
const prUrl = 'https://github.com/user/repo/pull/77';
|
|
1881
|
+
const prIssue = createMockIssue({
|
|
1882
|
+
url: prUrl,
|
|
1883
|
+
status: 'Preparation',
|
|
1884
|
+
isPr: true,
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
|
|
1888
|
+
mockIssueRepository.get.mockResolvedValue(prIssue);
|
|
1889
|
+
mockIssueCommentRepository.getCommentsFromIssue.mockResolvedValue([
|
|
1890
|
+
createMockComment({ content: 'From: :robot: Agent report' }),
|
|
1891
|
+
]);
|
|
1892
|
+
mockIssueRepository.getOpenPullRequest.mockResolvedValue({
|
|
1893
|
+
url: prUrl,
|
|
1894
|
+
isConflicted: false,
|
|
1895
|
+
isPassedAllCiJob: true,
|
|
1896
|
+
isCiStateSuccess: true,
|
|
1897
|
+
isResolvedAllReviewComments: true,
|
|
1898
|
+
isBranchOutOfDate: false,
|
|
1899
|
+
missingRequiredCheckNames: [],
|
|
1900
|
+
});
|
|
1901
|
+
|
|
1902
|
+
await useCase.run({
|
|
1903
|
+
projectUrl: 'https://github.com/users/user/projects/1',
|
|
1904
|
+
issueUrl: prUrl,
|
|
1905
|
+
thresholdForAutoReject: 3,
|
|
1906
|
+
workflowBlockerResolvedWebhookUrl: null,
|
|
1907
|
+
allowedIssueAuthors: null,
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
expect(mockIssueRepository.setDependedIssueUrl).not.toHaveBeenCalled();
|
|
1911
|
+
});
|
|
1912
|
+
|
|
1879
1913
|
it('should log a warning and skip setDependedIssueUrl when dependedIssueUrlSeparatedByComma is not configured in project', async () => {
|
|
1880
1914
|
const projectWithoutDependedField = createMockProject({
|
|
1881
1915
|
dependedIssueUrlSeparatedByComma: null,
|
|
@@ -360,6 +360,9 @@ export class NotifyFinishedIssuePreparationUseCase {
|
|
|
360
360
|
? await this.resolveOpenPrsForPrItem(issue.url)
|
|
361
361
|
: await this.issueRepository.findRelatedOpenPRs(issue.url);
|
|
362
362
|
for (const pr of openPRs) {
|
|
363
|
+
if (pr.url === issueUrl) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
363
366
|
await this.issueRepository.setDependedIssueUrl(pr.url, project, issueUrl);
|
|
364
367
|
}
|
|
365
368
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,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":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAiFzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const CONSOLE_LIST_TAB_NAMES: string[];
|
|
2
|
+
export type ConsoleDataRoute = {
|
|
3
|
+
kind: 'list';
|
|
4
|
+
pjcode: string;
|
|
5
|
+
tab: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'detail';
|
|
8
|
+
pjcode: string;
|
|
9
|
+
tab: string;
|
|
10
|
+
key: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'in-tmux';
|
|
13
|
+
pjcode: string;
|
|
14
|
+
relativePath: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const parseConsoleDataRoute: (requestPath: string) => ConsoleDataRoute | null;
|
|
17
|
+
export type ConsoleDataResponse = {
|
|
18
|
+
statusCode: number;
|
|
19
|
+
contentType: string;
|
|
20
|
+
body: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const buildConsoleDataResponse: (consoleDataOutputDir: string, route: ConsoleDataRoute) => ConsoleDataResponse;
|
|
23
|
+
//# sourceMappingURL=consoleDataDelivery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleDataDelivery.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleDataDelivery.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,EAAE,MAAM,EAM1C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAO9D,eAAO,MAAM,qBAAqB,GAChC,aAAa,MAAM,KAClB,gBAAgB,GAAG,IAoCrB,CAAC;AA0CF,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,sBAAsB,MAAM,EAC5B,OAAO,gBAAgB,KACtB,mBA6CF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CONSOLE_DONE_FILE_NAME = ".done.json";
|
|
2
|
+
export type ConsoleDoneRecord = {
|
|
3
|
+
projectItemIds: string[];
|
|
4
|
+
};
|
|
5
|
+
export declare const doneFilePathForTab: (consoleDataOutputDir: string, pjcode: string, tab: string) => string;
|
|
6
|
+
export declare const readDoneProjectItemIds: (consoleDataOutputDir: string, pjcode: string, tab: string) => string[];
|
|
7
|
+
export declare const recordDoneProjectItemId: (consoleDataOutputDir: string, pjcode: string, tab: string, projectItemId: string) => void;
|
|
8
|
+
export declare const CONSOLE_DONE_TAB_NAMES: string[];
|
|
9
|
+
export declare const recordDoneProjectItemIdAcrossTabs: (consoleDataOutputDir: string, pjcode: string, projectItemId: string) => void;
|
|
10
|
+
//# sourceMappingURL=consoleDoneStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleDoneStore.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleDoneStore.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAqBF,eAAO,MAAM,kBAAkB,GAC7B,sBAAsB,MAAM,EAC5B,QAAQ,MAAM,EACd,KAAK,MAAM,KACV,MACmE,CAAC;AAEvE,eAAO,MAAM,sBAAsB,GACjC,sBAAsB,MAAM,EAC5B,QAAQ,MAAM,EACd,KAAK,MAAM,KACV,MAAM,EASR,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,sBAAsB,MAAM,EAC5B,QAAQ,MAAM,EACd,KAAK,MAAM,EACX,eAAe,MAAM,KACpB,IAgBF,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,MAAM,EAO1C,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAC5C,sBAAsB,MAAM,EAC5B,QAAQ,MAAM,EACd,eAAe,MAAM,KACpB,IAIF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IssueRepository } from '../../../domain/usecases/adapter-interfaces/IssueRepository';
|
|
2
|
+
import { Project } from '../../../domain/entities/Project';
|
|
3
|
+
export declare const AWAITING_WORKSPACE_STATUS_NAME = "awaiting workspace";
|
|
4
|
+
export declare const IN_TMUX_BY_HUMAN_STATUS_NAME = "in tmux by human";
|
|
5
|
+
export type ConsoleOperationContext = {
|
|
6
|
+
issueRepository: IssueRepository;
|
|
7
|
+
project: Project;
|
|
8
|
+
consoleDataOutputDir: string | null;
|
|
9
|
+
pjcode: string | null;
|
|
10
|
+
};
|
|
11
|
+
export type ConsoleOperationResponse = {
|
|
12
|
+
statusCode: number;
|
|
13
|
+
body: unknown;
|
|
14
|
+
};
|
|
15
|
+
export declare const handleReview: (context: ConsoleOperationContext, body: Record<string, unknown>) => Promise<ConsoleOperationResponse>;
|
|
16
|
+
export declare const handleTriage: (context: ConsoleOperationContext, body: Record<string, unknown>) => Promise<ConsoleOperationResponse>;
|
|
17
|
+
export declare const handleIntmux: (context: ConsoleOperationContext, body: Record<string, unknown>) => Promise<ConsoleOperationResponse>;
|
|
18
|
+
//# sourceMappingURL=consoleOperationApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleOperationApi.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleOperationApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6DAA6D,CAAC;AAC9F,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAI3D,eAAO,MAAM,8BAA8B,uBAAuB,CAAC;AACnE,eAAO,MAAM,4BAA4B,qBAAqB,CAAC;AAE/D,MAAM,MAAM,uBAAuB,GAAG;IACpC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AA0EF,eAAO,MAAM,YAAY,GACvB,SAAS,uBAAuB,EAChC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,wBAAwB,CAiElC,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,SAAS,uBAAuB,EAChC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,wBAAwB,CAkFlC,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,SAAS,uBAAuB,EAChC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,wBAAwB,CA2BlC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { IssueRepository } from '../../../domain/usecases/adapter-interfaces/IssueRepository';
|
|
2
|
+
export declare const ISSUE_TITLE_CACHE_TTL_MS: number;
|
|
3
|
+
export type IssueOrPullRequestState = {
|
|
4
|
+
state: string;
|
|
5
|
+
merged: boolean;
|
|
6
|
+
isPullRequest: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare class IssueTitleStateCache {
|
|
9
|
+
private readonly nowMs;
|
|
10
|
+
private readonly entries;
|
|
11
|
+
constructor(nowMs?: () => number);
|
|
12
|
+
get: (url: string) => IssueOrPullRequestState | null;
|
|
13
|
+
set: (url: string, state: IssueOrPullRequestState) => void;
|
|
14
|
+
}
|
|
15
|
+
export type ConsoleReadApiResponse = {
|
|
16
|
+
statusCode: number;
|
|
17
|
+
body: unknown;
|
|
18
|
+
};
|
|
19
|
+
export type RelatedPullRequestWithSummary = {
|
|
20
|
+
url: string;
|
|
21
|
+
branchName: string | null;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
isDraft: boolean;
|
|
24
|
+
isConflicted: boolean;
|
|
25
|
+
isPassedAllCiJob: boolean;
|
|
26
|
+
isCiStateSuccess: boolean;
|
|
27
|
+
isResolvedAllReviewComments: boolean;
|
|
28
|
+
isBranchOutOfDate: boolean;
|
|
29
|
+
missingRequiredCheckNames: string[];
|
|
30
|
+
summary: {
|
|
31
|
+
title: string;
|
|
32
|
+
body: string;
|
|
33
|
+
additions: number;
|
|
34
|
+
deletions: number;
|
|
35
|
+
changedFiles: number;
|
|
36
|
+
} | null;
|
|
37
|
+
};
|
|
38
|
+
export declare const handleItemBody: (issueRepository: IssueRepository, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
39
|
+
export declare const handleComments: (issueRepository: IssueRepository, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
40
|
+
export declare const handlePrFiles: (issueRepository: IssueRepository, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
41
|
+
export declare const handlePrCommits: (issueRepository: IssueRepository, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
42
|
+
export declare const handleRelatedPrs: (issueRepository: IssueRepository, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
43
|
+
export declare const handleIssueTitle: (issueRepository: IssueRepository, cache: IssueTitleStateCache, url: string | null) => Promise<ConsoleReadApiResponse>;
|
|
44
|
+
//# sourceMappingURL=consoleReadApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleReadApi.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleReadApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAGhB,MAAM,6DAA6D,CAAC;AAErE,eAAO,MAAM,wBAAwB,QAAa,CAAC;AAEnD,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC;AAOF,qBAAa,oBAAoB;IAGnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;gBAEtC,KAAK,GAAE,MAAM,MAAyB;IAEnE,GAAG,GAAI,KAAK,MAAM,KAAG,uBAAuB,GAAG,IAAI,CAYjD;IAEF,GAAG,GAAI,KAAK,MAAM,EAAE,OAAO,uBAAuB,KAAG,IAAI,CAEvD;CACH;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAYF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,2BAA2B,EAAE,OAAO,CAAC;IACrC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,GAAG,IAAI,CAAC;CACV,CAAC;AAqBF,eAAO,MAAM,cAAc,GACzB,iBAAiB,eAAe,EAChC,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CAMhC,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,iBAAiB,eAAe,EAChC,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CAMhC,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,iBAAiB,eAAe,EAChC,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CAShC,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,iBAAiB,eAAe,EAChC,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CAMhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,eAAe,EAChC,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CA2BhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,eAAe,EAChC,OAAO,oBAAoB,EAC3B,KAAK,MAAM,GAAG,IAAI,KACjB,OAAO,CAAC,sBAAsB,CAWhC,CAAC"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as http from 'http';
|
|
2
|
+
import { IssueRepository } from '../../../domain/usecases/adapter-interfaces/IssueRepository';
|
|
3
|
+
import { Project } from '../../../domain/entities/Project';
|
|
4
|
+
import { IssueTitleStateCache } from './consoleReadApi';
|
|
2
5
|
export declare const DEFAULT_CONSOLE_PORT = 9981;
|
|
3
6
|
export declare const CONSOLE_TOKEN_HEADER = "x-pv-token";
|
|
4
7
|
export declare const hasDotSegment: (requestPath: string) => boolean;
|
|
@@ -9,8 +12,12 @@ export type ConsoleServerOptions = {
|
|
|
9
12
|
accessToken: string;
|
|
10
13
|
uiDistDir: string;
|
|
11
14
|
consoleDataOutputDir: string | null;
|
|
15
|
+
pjcode?: string | null;
|
|
16
|
+
issueRepository?: IssueRepository | null;
|
|
17
|
+
project?: Project | null;
|
|
18
|
+
issueTitleStateCache?: IssueTitleStateCache | null;
|
|
12
19
|
};
|
|
13
|
-
export declare const handleConsoleRequest: (options: ConsoleServerOptions, request: http.IncomingMessage, response: http.ServerResponse) => void
|
|
20
|
+
export declare const handleConsoleRequest: (options: ConsoleServerOptions, request: http.IncomingMessage, response: http.ServerResponse) => Promise<void>;
|
|
14
21
|
export declare const createConsoleServer: (options: ConsoleServerOptions) => http.Server;
|
|
15
22
|
export type StartConsoleServerOptions = ConsoleServerOptions & {
|
|
16
23
|
port: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consoleServer.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"consoleServer.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/console/consoleServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,6DAA6D,CAAC;AAC9F,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAK3D,OAAO,EACL,oBAAoB,EAOrB,MAAM,kBAAkB,CAAC;AAQ1B,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAmCjD,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGiB,CAAC;AAEtE,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,KAAG,OAGrB,CAAC;AAEhC,eAAO,MAAM,YAAY,GACvB,eAAe,MAAM,EACrB,eAAe,MAAM,GAAG,IAAI,KAC3B,OAAoE,CAAC;AAExE,eAAO,MAAM,oBAAoB,GAC/B,YAAY,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,EACpC,aAAa,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KACzC,MAAM,GAAG,IAQX,CAAC;AAuCF,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,oBAAoB,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACpD,CAAC;AA4MF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,oBAAoB,EAC7B,SAAS,IAAI,CAAC,eAAe,EAC7B,UAAU,IAAI,CAAC,cAAc,KAC5B,OAAO,CAAC,IAAI,CA8Dd,CAAC;AAcF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,KAC5B,IAAI,CAAC,MAMJ,CAAC;AAEL,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,yBAAyB,KACjC,OAAO,CAAC,IAAI,CAAC,MAAM,CAQlB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotifyFinishedIssuePreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAa3E,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,QAAQ,EAAE,MAAM;CAI7B;AACD,qBAAa,uBAAwB,SAAQ,KAAK;gBAE9C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,cAAc,EAAE,MAAM,GAAG,IAAI;CAOhC;AAMD,qBAAa,qCAAqC;IAK9C,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAahC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IAIvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAtBpC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAA0B;IAClE,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAkC;gBAG/D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,KAAK,GACL,QAAQ,GACR,cAAc,GACd,oBAAoB,GACpB,mBAAmB,GACnB,oBAAoB,GACpB,gCAAgC,GAChC,oBAAoB,GACpB,iCAAiC,GACjC,qBAAqB,CACxB,EACgB,sBAAsB,EAAE,IAAI,CAC3C,sBAAsB,EACtB,sBAAsB,GAAG,eAAe,CACzC,EACgB,iBAAiB,EAAE,IAAI,CACtC,iBAAiB,EACjB,gBAAgB,CACjB;IAQH,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,iCAAiC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjD,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACtC,oBAAoB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACvC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;KACzD,KAAG,OAAO,CAAC,IAAI,CAAC,CAwMf;IAEF,OAAO,CAAC,eAAe,CAIgD;IAEvE,OAAO,CAAC,iBAAiB,CA+BvB;IAEF,OAAO,CAAC,qBAAqB,CAuB3B;IAEF,OAAO,CAAC,gCAAgC,
|
|
1
|
+
{"version":3,"file":"NotifyFinishedIssuePreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAa3E,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,QAAQ,EAAE,MAAM;CAI7B;AACD,qBAAa,uBAAwB,SAAQ,KAAK;gBAE9C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,cAAc,EAAE,MAAM,GAAG,IAAI;CAOhC;AAMD,qBAAa,qCAAqC;IAK9C,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAahC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IAIvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAtBpC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAA0B;IAClE,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CAAkC;gBAG/D,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,EACtD,eAAe,EAAE,IAAI,CACpC,eAAe,EACb,KAAK,GACL,QAAQ,GACR,cAAc,GACd,oBAAoB,GACpB,mBAAmB,GACnB,oBAAoB,GACpB,gCAAgC,GAChC,oBAAoB,GACpB,iCAAiC,GACjC,qBAAqB,CACxB,EACgB,sBAAsB,EAAE,IAAI,CAC3C,sBAAsB,EACtB,sBAAsB,GAAG,eAAe,CACzC,EACgB,iBAAiB,EAAE,IAAI,CACtC,iBAAiB,EACjB,gBAAgB,CACjB;IAQH,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,iCAAiC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjD,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACtC,oBAAoB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QACvC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;KACzD,KAAG,OAAO,CAAC,IAAI,CAAC,CAwMf;IAEF,OAAO,CAAC,eAAe,CAIgD;IAEvE,OAAO,CAAC,iBAAiB,CA+BvB;IAEF,OAAO,CAAC,qBAAqB,CAuB3B;IAEF,OAAO,CAAC,gCAAgC,CAoBtC;IAEF,OAAO,CAAC,uBAAuB,CAQ7B;IAEF,OAAO,CAAC,+BAA+B,CAkCrC;CACH"}
|