github-issue-tower-defence-management 1.83.0 → 1.84.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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.84.0](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.83.0...v1.84.0) (2026-06-14)
2
+
3
+
4
+ ### Features
5
+
6
+ * **console:** generate per-tab Console list.json files in scheduled cycle ([#831](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/831)) ([0368fb7](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/0368fb74d572a5d9b73966440da2c62669d1d4f4))
7
+
1
8
  # [1.83.0](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v1.82.1...v1.83.0) (2026-06-14)
2
9
 
3
10
 
package/README.md CHANGED
@@ -199,6 +199,7 @@ claudeCodeOauthTokenListJsonPath?: string # Optional: Path to a JSON file listin
199
199
  awLogDirectoryPath?: string # Optional: Directory path where aw log files named {org}_{repo}_{number}_* are written. Used with awLogStaleThresholdMinutes to detect zombie-wrapper orphans
200
200
  awLogStaleThresholdMinutes?: number # Optional: Minutes since last aw log mtime after which a Preparation issue is considered orphaned even when pgrep still returns 0. Requires awLogDirectoryPath
201
201
  labelsAsLlmAgentName?: string[] # Optional: List of issue labels that are themselves agent names. When an issue carries any label that is included in this list, that label name is used as the agent name. Selection precedence is: (1) explicit `llm-agent:` label, (2) labelsAsLlmAgentName entry match, (3) `category:` label, (4) defaultLlmAgentName, (5) defaultAgentName
202
+ consoleDataOutputDir?: string # Optional: Base output directory for the per-project Console list.json files written each schedule cycle. When unset, Console list generation is skipped
202
203
  changeTargetPathAliases?: # Optional: Map of short alias keys to full repository-root-relative directory paths. Allows `change-target:<alias>` labels to reference deeply nested paths that exceed GitHub's 50-character label limit. When a `change-target:` label's value matches a key in this map, it is expanded to the corresponding full path before confinement checking. Values with leading or trailing slashes are normalized automatically. Example below
203
204
  adapter-interfaces: src/domain/usecases/adapter-interfaces
204
205
  ```
@@ -331,6 +332,68 @@ This file is written atomically (written to a `.tmp` file then renamed) so exter
331
332
 
332
333
  System metrics are read from `/proc/meminfo` at snapshot write time.
333
334
 
335
+ ## Per-Project Console Lists
336
+
337
+ When `consoleDataOutputDir` is configured, each schedule cycle also writes four per-tab Console list files, generated from the same in-memory project and issue data already loaded for the cycle (no additional GitHub API calls):
338
+
339
+ ```
340
+ {consoleDataOutputDir}/{projectName}/{tab}/list.json
341
+ ```
342
+
343
+ for `tab` in `prs`, `triage`, `unread`, and `failed-preparation`. Each file is written atomically (written to a `.tmp` file then renamed) so external readers never see a partial write. When `consoleDataOutputDir` is unset the generation is skipped, and any error during generation is logged and swallowed so the schedule cycle is never affected.
344
+
345
+ ### Item Selection
346
+
347
+ Every tab applies a common actionable filter to the project's issues: the issue is open, is assigned to the project manager, has no depended issue URLs, and has neither a next action date nor a next action hour set. Each tab then applies its own selector:
348
+
349
+ - `prs`: status equals `Awaiting Quality Check` (case-insensitive)
350
+ - `unread`: status equals `Unread` (case-insensitive)
351
+ - `failed-preparation`: status equals `Failed Preparation` (exact case)
352
+ - `triage`: story name contains `no story` (case-insensitive)
353
+
354
+ ### JSON Shape
355
+
356
+ The `prs`, `unread`, and `failed-preparation` tabs share this shape:
357
+
358
+ ```json
359
+ {
360
+ "pjcode": "my-project",
361
+ "generatedAt": "2026-06-14T07:22:33Z",
362
+ "statusOptions": [
363
+ { "id": "...", "name": "Awaiting Workspace", "color": "BLUE" }
364
+ ],
365
+ "storyOrder": ["Story Alpha", "Story Beta"],
366
+ "storyColors": { "Story Alpha": { "color": "BLUE" } },
367
+ "items": [
368
+ {
369
+ "number": 1,
370
+ "title": "Example",
371
+ "url": "https://github.com/owner/repo/issues/1",
372
+ "repo": "owner/repo",
373
+ "nameWithOwner": "owner/repo",
374
+ "projectItemId": "...",
375
+ "itemId": "...",
376
+ "isPr": false,
377
+ "story": "Story Alpha",
378
+ "labels": ["bug"],
379
+ "createdAt": "2026-06-13T08:18:45.000Z"
380
+ }
381
+ ]
382
+ }
383
+ ```
384
+
385
+ The `triage` tab omits `statusOptions`, adds `storyOptions` (all story field options), and uses plain color string values in `storyColors` (for example `"Story Alpha": "BLUE"`).
386
+
387
+ ### Field Descriptions
388
+
389
+ - `pjcode`: The configured project name.
390
+ - `generatedAt`: UTC timestamp (no milliseconds) when the lists were generated. Item `createdAt` values keep milliseconds.
391
+ - `statusOptions`: Project status field options offered as routing buttons. The current-status option and `Done` are excluded; `failed-preparation` additionally excludes `Preparation`, `Icebox`, `Unread`, and `In Tmux by human`.
392
+ - `storyOptions` (triage tab only): All story field options.
393
+ - `storyOrder`: Story field option names in field order (empty array when the project has no story field).
394
+ - `storyColors`: Map from story name to its color. Object value (`{ "color": ... }`) for `prs`/`unread`/`failed-preparation`; plain string value for `triage`.
395
+ - `items`: Selected issues, stable-sorted by their story's position in `storyOrder` (unknown stories sorted last). No item carries a `body` field.
396
+
334
397
  ## Token Rotation Order File
335
398
 
336
399
  After each schedule cycle where Claude OAuth token rotation is active, TDPM writes the computed rotation order to:
@@ -43,6 +43,7 @@ const yaml_1 = __importDefault(require("yaml"));
43
43
  const typia_1 = __importDefault(require("typia"));
44
44
  const fs_1 = __importDefault(require("fs"));
45
45
  const situationFileWriter_1 = require("./situationFileWriter");
46
+ const consoleListsWriter_1 = require("./consoleListsWriter");
46
47
  const rotationOrderFileWriter_1 = require("./rotationOrderFileWriter");
47
48
  const projectConfig_1 = require("../cli/projectConfig");
48
49
  const SystemDateRepository_1 = require("../../repositories/SystemDateRepository");
@@ -86,13 +87,13 @@ class HandleScheduledEventUseCaseHandler {
86
87
  this.handle = async (configFilePath, _verbose) => {
87
88
  const configFileContent = fs_1.default.readFileSync(configFilePath, 'utf8');
88
89
  const input = yaml_1.default.parse(configFileContent);
89
- if (!(() => { const _io0 = input => "string" === typeof input.projectName && "string" === typeof input.org && "string" === typeof input.projectUrl && "string" === typeof input.manager && ("object" === typeof input.workingReport && null !== input.workingReport && _io1(input.workingReport)) && "string" === typeof input.urlOfStoryView && "boolean" === typeof input.disabled && "number" === typeof input.allowIssueCacheMinutes && (null === input.labelsAsLlmAgentName || undefined === input.labelsAsLlmAgentName || Array.isArray(input.labelsAsLlmAgentName) && input.labelsAsLlmAgentName.every(elem => "string" === typeof elem)) && (null === input.changeTargetPathAliases || undefined === input.changeTargetPathAliases || "object" === typeof input.changeTargetPathAliases && null !== input.changeTargetPathAliases && false === Array.isArray(input.changeTargetPathAliases) && _io2(input.changeTargetPathAliases)) && (null === input.startPreparation || undefined === input.startPreparation || "object" === typeof input.startPreparation && null !== input.startPreparation && _io3(input.startPreparation)) && (undefined === input.thresholdForAutoReject || "number" === typeof input.thresholdForAutoReject) && (null === input.dailySecurityScan || undefined === input.dailySecurityScan || "object" === typeof input.dailySecurityScan && null !== input.dailySecurityScan && _io4(input.dailySecurityScan)) && (undefined === input.claudeCodeOauthTokenListJsonPath || "string" === typeof input.claudeCodeOauthTokenListJsonPath) && ("object" === typeof input.credentials && null !== input.credentials && _io5(input.credentials)); const _io1 = input => "string" === typeof input.repo && (Array.isArray(input.members) && input.members.every(elem => "string" === typeof elem)) && "string" === typeof input.spreadsheetUrl; const _io2 = input => Object.keys(input).every(key => {
90
+ if (!(() => { const _io0 = input => "string" === typeof input.projectName && "string" === typeof input.org && "string" === typeof input.projectUrl && "string" === typeof input.manager && ("object" === typeof input.workingReport && null !== input.workingReport && _io1(input.workingReport)) && "string" === typeof input.urlOfStoryView && "boolean" === typeof input.disabled && "number" === typeof input.allowIssueCacheMinutes && (null === input.labelsAsLlmAgentName || undefined === input.labelsAsLlmAgentName || Array.isArray(input.labelsAsLlmAgentName) && input.labelsAsLlmAgentName.every(elem => "string" === typeof elem)) && (null === input.changeTargetPathAliases || undefined === input.changeTargetPathAliases || "object" === typeof input.changeTargetPathAliases && null !== input.changeTargetPathAliases && false === Array.isArray(input.changeTargetPathAliases) && _io2(input.changeTargetPathAliases)) && (null === input.startPreparation || undefined === input.startPreparation || "object" === typeof input.startPreparation && null !== input.startPreparation && _io3(input.startPreparation)) && (undefined === input.thresholdForAutoReject || "number" === typeof input.thresholdForAutoReject) && (null === input.dailySecurityScan || undefined === input.dailySecurityScan || "object" === typeof input.dailySecurityScan && null !== input.dailySecurityScan && _io4(input.dailySecurityScan)) && (undefined === input.claudeCodeOauthTokenListJsonPath || "string" === typeof input.claudeCodeOauthTokenListJsonPath) && (undefined === input.consoleDataOutputDir || "string" === typeof input.consoleDataOutputDir) && ("object" === typeof input.credentials && null !== input.credentials && _io5(input.credentials)); const _io1 = input => "string" === typeof input.repo && (Array.isArray(input.members) && input.members.every(elem => "string" === typeof elem)) && "string" === typeof input.spreadsheetUrl; const _io2 = input => Object.keys(input).every(key => {
90
91
  const value = input[key];
91
92
  if (undefined === value)
92
93
  return true;
93
94
  return "string" === typeof value;
94
95
  }); const _io3 = input => "string" === typeof input.defaultAgentName && (null === input.defaultLlmModelName || undefined === input.defaultLlmModelName || "string" === typeof input.defaultLlmModelName) && (null === input.fallbackLlmModelName || undefined === input.fallbackLlmModelName || "string" === typeof input.fallbackLlmModelName) && (null === input.defaultLlmAgentName || undefined === input.defaultLlmAgentName || "string" === typeof input.defaultLlmAgentName) && "string" === typeof input.configFilePath && (null === input.maximumPreparingIssuesCount || "number" === typeof input.maximumPreparingIssuesCount) && (undefined === input.utilizationPercentageThreshold || "number" === typeof input.utilizationPercentageThreshold) && (null === input.allowedIssueAuthors || undefined === input.allowedIssueAuthors || Array.isArray(input.allowedIssueAuthors) && input.allowedIssueAuthors.every(elem => "string" === typeof elem)) && (undefined === input.preparationProcessCheckCommand || "string" === typeof input.preparationProcessCheckCommand) && (null === input.codexHomeCandidates || undefined === input.codexHomeCandidates || Array.isArray(input.codexHomeCandidates) && input.codexHomeCandidates.every(elem => "string" === typeof elem)) && (undefined === input.awLogDirectoryPath || "string" === typeof input.awLogDirectoryPath) && (undefined === input.awLogStaleThresholdMinutes || "number" === typeof input.awLogStaleThresholdMinutes) && (null === input.awaitingQualityCheckStatus || undefined === input.awaitingQualityCheckStatus || "string" === typeof input.awaitingQualityCheckStatus) && (null === input.labelsAsLlmAgentName || undefined === input.labelsAsLlmAgentName || Array.isArray(input.labelsAsLlmAgentName) && input.labelsAsLlmAgentName.every(elem => "string" === typeof elem)); const _io4 = input => "string" === typeof input.scanBaseDirectory && "number" === typeof input.targetHourUtc && (undefined === input.enableKevNvdReport || "boolean" === typeof input.enableKevNvdReport) && (undefined === input.kevReportRepo || "string" === typeof input.kevReportRepo); const _io5 = input => "object" === typeof input.manager && null !== input.manager && _io6(input.manager) && ("object" === typeof input.bot && null !== input.bot && _io10(input.bot)); const _io6 = input => "object" === typeof input.github && null !== input.github && _io7(input.github) && ("object" === typeof input.slack && null !== input.slack && _io8(input.slack)) && ("object" === typeof input.googleServiceAccount && null !== input.googleServiceAccount && _io9(input.googleServiceAccount)); const _io7 = input => "string" === typeof input.token; const _io8 = input => "string" === typeof input.userToken; const _io9 = input => "string" === typeof input.serviceAccountKey; const _io10 = input => "object" === typeof input.github && null !== input.github && _io11(input.github); const _io11 = input => "string" === typeof input.token; return input => "object" === typeof input && null !== input && _io0(input); })()(input)) {
95
- throw new Error(`Invalid input: ${JSON.stringify(input)}\n\n${JSON.stringify((() => { const _io0 = input => "string" === typeof input.projectName && "string" === typeof input.org && "string" === typeof input.projectUrl && "string" === typeof input.manager && ("object" === typeof input.workingReport && null !== input.workingReport && _io1(input.workingReport)) && "string" === typeof input.urlOfStoryView && "boolean" === typeof input.disabled && "number" === typeof input.allowIssueCacheMinutes && (null === input.labelsAsLlmAgentName || undefined === input.labelsAsLlmAgentName || Array.isArray(input.labelsAsLlmAgentName) && input.labelsAsLlmAgentName.every(elem => "string" === typeof elem)) && (null === input.changeTargetPathAliases || undefined === input.changeTargetPathAliases || "object" === typeof input.changeTargetPathAliases && null !== input.changeTargetPathAliases && false === Array.isArray(input.changeTargetPathAliases) && _io2(input.changeTargetPathAliases)) && (null === input.startPreparation || undefined === input.startPreparation || "object" === typeof input.startPreparation && null !== input.startPreparation && _io3(input.startPreparation)) && (undefined === input.thresholdForAutoReject || "number" === typeof input.thresholdForAutoReject) && (null === input.dailySecurityScan || undefined === input.dailySecurityScan || "object" === typeof input.dailySecurityScan && null !== input.dailySecurityScan && _io4(input.dailySecurityScan)) && (undefined === input.claudeCodeOauthTokenListJsonPath || "string" === typeof input.claudeCodeOauthTokenListJsonPath) && ("object" === typeof input.credentials && null !== input.credentials && _io5(input.credentials)); const _io1 = input => "string" === typeof input.repo && (Array.isArray(input.members) && input.members.every(elem => "string" === typeof elem)) && "string" === typeof input.spreadsheetUrl; const _io2 = input => Object.keys(input).every(key => {
96
+ throw new Error(`Invalid input: ${JSON.stringify(input)}\n\n${JSON.stringify((() => { const _io0 = input => "string" === typeof input.projectName && "string" === typeof input.org && "string" === typeof input.projectUrl && "string" === typeof input.manager && ("object" === typeof input.workingReport && null !== input.workingReport && _io1(input.workingReport)) && "string" === typeof input.urlOfStoryView && "boolean" === typeof input.disabled && "number" === typeof input.allowIssueCacheMinutes && (null === input.labelsAsLlmAgentName || undefined === input.labelsAsLlmAgentName || Array.isArray(input.labelsAsLlmAgentName) && input.labelsAsLlmAgentName.every(elem => "string" === typeof elem)) && (null === input.changeTargetPathAliases || undefined === input.changeTargetPathAliases || "object" === typeof input.changeTargetPathAliases && null !== input.changeTargetPathAliases && false === Array.isArray(input.changeTargetPathAliases) && _io2(input.changeTargetPathAliases)) && (null === input.startPreparation || undefined === input.startPreparation || "object" === typeof input.startPreparation && null !== input.startPreparation && _io3(input.startPreparation)) && (undefined === input.thresholdForAutoReject || "number" === typeof input.thresholdForAutoReject) && (null === input.dailySecurityScan || undefined === input.dailySecurityScan || "object" === typeof input.dailySecurityScan && null !== input.dailySecurityScan && _io4(input.dailySecurityScan)) && (undefined === input.claudeCodeOauthTokenListJsonPath || "string" === typeof input.claudeCodeOauthTokenListJsonPath) && (undefined === input.consoleDataOutputDir || "string" === typeof input.consoleDataOutputDir) && ("object" === typeof input.credentials && null !== input.credentials && _io5(input.credentials)); const _io1 = input => "string" === typeof input.repo && (Array.isArray(input.members) && input.members.every(elem => "string" === typeof elem)) && "string" === typeof input.spreadsheetUrl; const _io2 = input => Object.keys(input).every(key => {
96
97
  const value = input[key];
97
98
  if (undefined === value)
98
99
  return true;
@@ -177,6 +178,10 @@ class HandleScheduledEventUseCaseHandler {
177
178
  path: _path + ".claudeCodeOauthTokenListJsonPath",
178
179
  expected: "(string | undefined)",
179
180
  value: input.claudeCodeOauthTokenListJsonPath
181
+ }), undefined === input.consoleDataOutputDir || "string" === typeof input.consoleDataOutputDir || _report(_exceptionable, {
182
+ path: _path + ".consoleDataOutputDir",
183
+ expected: "(string | undefined)",
184
+ value: input.consoleDataOutputDir
180
185
  }), ("object" === typeof input.credentials && null !== input.credentials || _report(_exceptionable, {
181
186
  path: _path + ".credentials",
182
187
  expected: "__type.o2",
@@ -522,6 +527,18 @@ class HandleScheduledEventUseCaseHandler {
522
527
  preparationProcessCheckCommand: mergedInput.startPreparation?.preparationProcessCheckCommand ?? null,
523
528
  localCommandRunner: nodeLocalCommandRunner,
524
529
  });
530
+ try {
531
+ (0, consoleListsWriter_1.writeConsoleLists)({
532
+ consoleDataOutputDir: mergedInput.consoleDataOutputDir ?? null,
533
+ pjcode: input.projectName,
534
+ assigneeLogin: input.manager,
535
+ project: result.project,
536
+ issues: result.issues,
537
+ });
538
+ }
539
+ catch (error) {
540
+ console.error(`Failed to write console lists: ${error instanceof Error ? error.message : String(error)}`);
541
+ }
525
542
  }
526
543
  return result;
527
544
  };
@@ -1 +1 @@
1
- {"version":3,"file":"HandleScheduledEventUseCaseHandler.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HandleScheduledEventUseCaseHandler.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.writeConsoleLists = exports.formatConsoleGeneratedAt = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const GenerateConsoleListsUseCase_1 = require("../../../domain/usecases/console/GenerateConsoleListsUseCase");
10
+ const CONSOLE_TAB_NAMES = [
11
+ 'prs',
12
+ 'triage',
13
+ 'unread',
14
+ 'failed-preparation',
15
+ ];
16
+ const formatConsoleGeneratedAt = (date) => date.toISOString().replace(/\.\d{3}Z$/, 'Z');
17
+ exports.formatConsoleGeneratedAt = formatConsoleGeneratedAt;
18
+ const writeJsonAtomic = (filePath, data) => {
19
+ const dir = path_1.default.dirname(filePath);
20
+ fs_1.default.mkdirSync(dir, { recursive: true });
21
+ const tmpPath = `${filePath}.tmp`;
22
+ fs_1.default.writeFileSync(tmpPath, JSON.stringify(data));
23
+ fs_1.default.renameSync(tmpPath, filePath);
24
+ };
25
+ const writeConsoleLists = (params) => {
26
+ const { consoleDataOutputDir, pjcode, assigneeLogin } = params;
27
+ if (!consoleDataOutputDir || !pjcode || !assigneeLogin) {
28
+ return;
29
+ }
30
+ const generatedAt = params.generatedAt ?? (0, exports.formatConsoleGeneratedAt)(new Date());
31
+ const lists = new GenerateConsoleListsUseCase_1.GenerateConsoleListsUseCase().run({
32
+ project: params.project,
33
+ issues: params.issues,
34
+ pjcode,
35
+ assigneeLogin,
36
+ generatedAt,
37
+ });
38
+ for (const tab of CONSOLE_TAB_NAMES) {
39
+ writeJsonAtomic(path_1.default.join(consoleDataOutputDir, pjcode, tab, 'list.json'), lists[tab]);
40
+ }
41
+ };
42
+ exports.writeConsoleLists = writeConsoleLists;
43
+ //# sourceMappingURL=consoleListsWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleListsWriter.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/consoleListsWriter.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AAGxB,8GAIsE;AAWtE,MAAM,iBAAiB,GAAqB;IAC1C,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,oBAAoB;CACrB,CAAC;AAEK,MAAM,wBAAwB,GAAG,CAAC,IAAU,EAAU,EAAE,CAC7D,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AADlC,QAAA,wBAAwB,4BACU;AAE/C,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,IAAa,EAAQ,EAAE;IAChE,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAClC,YAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAChD,YAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC,CAAC;AAEK,MAAM,iBAAiB,GAAG,CAAC,MAAgC,EAAQ,EAAE;IAC1E,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IAC/D,IAAI,CAAC,oBAAoB,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACvD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GACf,MAAM,CAAC,WAAW,IAAI,IAAA,gCAAwB,EAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAiB,IAAI,yDAA2B,EAAE,CAAC,GAAG,CAAC;QAChE,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM;QACN,aAAa;QACb,WAAW;KACZ,CAAC,CAAC;IAEH,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,eAAe,CACb,cAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,EACzD,KAAK,CAAC,GAAG,CAAC,CACX,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAtBW,QAAA,iBAAiB,qBAsB5B"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GenerateConsoleListsUseCase = void 0;
4
+ const UNKNOWN_STORY_SORT_INDEX = 999999;
5
+ class GenerateConsoleListsUseCase {
6
+ constructor() {
7
+ this.run = (input) => {
8
+ const { project, issues, pjcode, assigneeLogin, generatedAt } = input;
9
+ const storyOptions = project.story ? project.story.stories : [];
10
+ const storyOrder = storyOptions.map((option) => option.name);
11
+ const statusOptions = project.status.statuses;
12
+ const actionableIssues = issues.filter((issue) => this.isActionable(issue, assigneeLogin));
13
+ const buildStatusTab = (selector, excludedStatusNames) => ({
14
+ pjcode,
15
+ generatedAt,
16
+ statusOptions: this.buildFieldOptions(statusOptions, excludedStatusNames),
17
+ storyOrder,
18
+ storyColors: this.buildStoryColorsObject(storyOptions),
19
+ items: this.sortByStoryOrder(actionableIssues
20
+ .filter(selector)
21
+ .map((issue) => this.projectItem(issue)), storyOrder),
22
+ });
23
+ return {
24
+ prs: buildStatusTab((issue) => issue.status !== null &&
25
+ issue.status.toLowerCase() === 'awaiting quality check', ['awaiting quality check', 'done']),
26
+ unread: buildStatusTab((issue) => issue.status !== null && issue.status.toLowerCase() === 'unread', ['unread', 'done']),
27
+ 'failed-preparation': buildStatusTab((issue) => issue.status === 'Failed Preparation', [
28
+ 'failed preparation',
29
+ 'done',
30
+ 'preparation',
31
+ 'icebox',
32
+ 'unread',
33
+ 'in tmux by human',
34
+ ]),
35
+ triage: {
36
+ pjcode,
37
+ generatedAt,
38
+ storyOptions: this.buildFieldOptions(storyOptions, []),
39
+ storyOrder,
40
+ storyColors: this.buildStoryColorsString(storyOptions),
41
+ items: this.sortByStoryOrder(actionableIssues
42
+ .filter((issue) => issue.story !== null &&
43
+ issue.story.toLowerCase().includes('no story'))
44
+ .map((issue) => this.projectItem(issue)), storyOrder),
45
+ },
46
+ };
47
+ };
48
+ this.isActionable = (issue, assigneeLogin) => issue.isClosed === false &&
49
+ issue.assignees.includes(assigneeLogin) &&
50
+ issue.dependedIssueUrls.length === 0 &&
51
+ issue.nextActionDate === null &&
52
+ issue.nextActionHour === null;
53
+ this.projectItem = (issue) => ({
54
+ number: issue.number,
55
+ title: issue.title,
56
+ url: issue.url,
57
+ repo: issue.nameWithOwner,
58
+ nameWithOwner: issue.nameWithOwner,
59
+ projectItemId: issue.itemId,
60
+ itemId: issue.itemId,
61
+ isPr: issue.isPr,
62
+ story: issue.story ?? '',
63
+ labels: issue.labels,
64
+ createdAt: issue.createdAt.toISOString(),
65
+ });
66
+ this.buildFieldOptions = (options, excludedLowerCaseNames) => options
67
+ .filter((option) => !excludedLowerCaseNames.includes(option.name.toLowerCase()))
68
+ .map((option) => ({
69
+ id: option.id,
70
+ name: option.name,
71
+ color: option.color,
72
+ }));
73
+ this.buildStoryColorsObject = (options) => {
74
+ const result = {};
75
+ for (const option of options) {
76
+ result[option.name] = { color: option.color };
77
+ }
78
+ return result;
79
+ };
80
+ this.buildStoryColorsString = (options) => {
81
+ const result = {};
82
+ for (const option of options) {
83
+ result[option.name] = option.color;
84
+ }
85
+ return result;
86
+ };
87
+ this.sortByStoryOrder = (items, storyOrder) => {
88
+ const indexByStory = new Map(storyOrder.map((name, index) => [name, index]));
89
+ return items
90
+ .map((item, position) => ({
91
+ item,
92
+ position,
93
+ sortKey: indexByStory.get(item.story) ?? UNKNOWN_STORY_SORT_INDEX,
94
+ }))
95
+ .sort((a, b) => a.sortKey - b.sortKey || a.position - b.position)
96
+ .map((entry) => entry.item);
97
+ };
98
+ }
99
+ }
100
+ exports.GenerateConsoleListsUseCase = GenerateConsoleListsUseCase;
101
+ //# sourceMappingURL=GenerateConsoleListsUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateConsoleListsUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/console/GenerateConsoleListsUseCase.ts"],"names":[],"mappings":";;;AA4DA,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAExC,MAAa,2BAA2B;IAAxC;QACE,QAAG,GAAG,CAAC,KAAgC,EAAgB,EAAE;YACvD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;YAEtE,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;YAE9C,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/C,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,aAAa,CAAC,CACxC,CAAC;YAEF,MAAM,cAAc,GAAG,CACrB,QAAmC,EACnC,mBAA6B,EACX,EAAE,CAAC,CAAC;gBACtB,MAAM;gBACN,WAAW;gBACX,aAAa,EAAE,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,mBAAmB,CAAC;gBACzE,UAAU;gBACV,WAAW,EAAE,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC;gBACtD,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAC1B,gBAAgB;qBACb,MAAM,CAAC,QAAQ,CAAC;qBAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAC1C,UAAU,CACX;aACF,CAAC,CAAC;YAEH,OAAO;gBACL,GAAG,EAAE,cAAc,CACjB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,MAAM,KAAK,IAAI;oBACrB,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,wBAAwB,EACzD,CAAC,wBAAwB,EAAE,MAAM,CAAC,CACnC;gBACD,MAAM,EAAE,cAAc,CACpB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,QAAQ,EAClE,CAAC,QAAQ,EAAE,MAAM,CAAC,CACnB;gBACD,oBAAoB,EAAE,cAAc,CAClC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,oBAAoB,EAChD;oBACE,oBAAoB;oBACpB,MAAM;oBACN,aAAa;oBACb,QAAQ;oBACR,QAAQ;oBACR,kBAAkB;iBACnB,CACF;gBACD,MAAM,EAAE;oBACN,MAAM;oBACN,WAAW;oBACX,YAAY,EAAE,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,EAAE,CAAC;oBACtD,UAAU;oBACV,WAAW,EAAE,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC;oBACtD,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAC1B,gBAAgB;yBACb,MAAM,CACL,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,KAAK,KAAK,IAAI;wBACpB,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CACjD;yBACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAC1C,UAAU,CACX;iBACF;aACF,CAAC;QACJ,CAAC,CAAC;QAEM,iBAAY,GAAG,CAAC,KAAY,EAAE,aAAqB,EAAW,EAAE,CACtE,KAAK,CAAC,QAAQ,KAAK,KAAK;YACxB,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC;YACvC,KAAK,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC;YACpC,KAAK,CAAC,cAAc,KAAK,IAAI;YAC7B,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC;QAExB,gBAAW,GAAG,CAAC,KAAY,EAAmB,EAAE,CAAC,CAAC;YACxD,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,aAAa;YACzB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,aAAa,EAAE,KAAK,CAAC,MAAM;YAC3B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE;SACzC,CAAC,CAAC;QAEK,sBAAiB,GAAG,CAC1B,OAAsB,EACtB,sBAAgC,EACV,EAAE,CACxB,OAAO;aACJ,MAAM,CACL,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CACxE;aACA,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC,CAAC;QAEA,2BAAsB,GAAG,CAC/B,OAAsB,EACmB,EAAE;YAC3C,MAAM,MAAM,GAA4C,EAAE,CAAC;YAC3D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAChD,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEM,2BAAsB,GAAG,CAC/B,OAAsB,EACQ,EAAE;YAChC,MAAM,MAAM,GAAiC,EAAE,CAAC;YAChD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;YACrC,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEM,qBAAgB,GAAG,CACzB,KAAwB,EACxB,UAAoB,EACD,EAAE;YACrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAC/C,CAAC;YACF,OAAO,KAAK;iBACT,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACxB,IAAI;gBACJ,QAAQ;gBACR,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,wBAAwB;aAClE,CAAC,CAAC;iBACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;iBAChE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC,CAAC;IACJ,CAAC;CAAA;AA/ID,kEA+IC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.83.0",
3
+ "version": "1.84.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -2,6 +2,7 @@ import YAML from 'yaml';
2
2
  import TYPIA from 'typia';
3
3
  import fs from 'fs';
4
4
  import { writeSituationFile } from './situationFileWriter';
5
+ import { writeConsoleLists } from './consoleListsWriter';
5
6
  import { writeRotationOrderFile } from './rotationOrderFileWriter';
6
7
  import {
7
8
  fetchProjectReadme,
@@ -66,6 +67,7 @@ export class HandleScheduledEventUseCaseHandler {
66
67
  const input: unknown = YAML.parse(configFileContent);
67
68
  type inputType = Parameters<HandleScheduledEventUseCase['run']>[0] & {
68
69
  claudeCodeOauthTokenListJsonPath?: string;
70
+ consoleDataOutputDir?: string;
69
71
  credentials: {
70
72
  manager: {
71
73
  github: {
@@ -365,6 +367,22 @@ export class HandleScheduledEventUseCaseHandler {
365
367
  mergedInput.startPreparation?.preparationProcessCheckCommand ?? null,
366
368
  localCommandRunner: nodeLocalCommandRunner,
367
369
  });
370
+
371
+ try {
372
+ writeConsoleLists({
373
+ consoleDataOutputDir: mergedInput.consoleDataOutputDir ?? null,
374
+ pjcode: input.projectName,
375
+ assigneeLogin: input.manager,
376
+ project: result.project,
377
+ issues: result.issues,
378
+ });
379
+ } catch (error) {
380
+ console.error(
381
+ `Failed to write console lists: ${
382
+ error instanceof Error ? error.message : String(error)
383
+ }`,
384
+ );
385
+ }
368
386
  }
369
387
  return result;
370
388
  };
@@ -0,0 +1,167 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { mock } from 'jest-mock-extended';
5
+ import { Issue } from '../../../domain/entities/Issue';
6
+ import { FieldOption, Project } from '../../../domain/entities/Project';
7
+ import {
8
+ formatConsoleGeneratedAt,
9
+ writeConsoleLists,
10
+ } from './consoleListsWriter';
11
+
12
+ const isRecord = (value: unknown): value is Record<string, unknown> =>
13
+ value !== null && typeof value === 'object' && !Array.isArray(value);
14
+
15
+ const isUnknownArray = (value: unknown): value is unknown[] =>
16
+ Array.isArray(value);
17
+
18
+ const ASSIGNEE = 'owner-login';
19
+
20
+ const option = (
21
+ id: string,
22
+ name: string,
23
+ color: FieldOption['color'],
24
+ ): FieldOption => ({ id, name, color, description: '' });
25
+
26
+ const project: Project = {
27
+ ...mock<Project>(),
28
+ status: {
29
+ name: 'Status',
30
+ fieldId: 'status-field',
31
+ statuses: [
32
+ option('st-unread', 'Unread', 'ORANGE'),
33
+ option('st-aw', 'Awaiting Workspace', 'BLUE'),
34
+ option('st-aqc', 'Awaiting Quality Check', 'GREEN'),
35
+ ],
36
+ },
37
+ story: {
38
+ name: 'story',
39
+ fieldId: 'story-field',
40
+ databaseId: 2,
41
+ stories: [option('s1', 'Story Alpha', 'BLUE')],
42
+ workflowManagementStory: { id: 'wm', name: 'workflow management' },
43
+ },
44
+ };
45
+
46
+ const makeIssue = (overrides: Partial<Issue>): Issue => ({
47
+ ...mock<Issue>(),
48
+ number: 1,
49
+ title: 'Issue 1',
50
+ nameWithOwner: 'demo/repo',
51
+ url: 'https://github.com/demo/repo/issues/1',
52
+ status: null,
53
+ story: null,
54
+ nextActionDate: null,
55
+ nextActionHour: null,
56
+ dependedIssueUrls: [],
57
+ assignees: [ASSIGNEE],
58
+ labels: [],
59
+ body: 'should never be written',
60
+ itemId: 'item-1',
61
+ isPr: false,
62
+ isClosed: false,
63
+ createdAt: new Date('2026-06-13T08:18:45.000Z'),
64
+ ...overrides,
65
+ });
66
+
67
+ describe('writeConsoleLists', () => {
68
+ let outDir: string;
69
+
70
+ beforeEach(() => {
71
+ outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'console-out-'));
72
+ });
73
+
74
+ afterEach(() => {
75
+ fs.rmSync(outDir, { recursive: true, force: true });
76
+ });
77
+
78
+ const tabFile = (tab: string): string =>
79
+ path.join(outDir, 'demo', tab, 'list.json');
80
+
81
+ it('writes all four tab list.json files', () => {
82
+ writeConsoleLists({
83
+ consoleDataOutputDir: outDir,
84
+ pjcode: 'demo',
85
+ assigneeLogin: ASSIGNEE,
86
+ project,
87
+ issues: [makeIssue({ status: 'Unread' })],
88
+ generatedAt: '2026-06-14T07:22:33Z',
89
+ });
90
+
91
+ for (const tab of ['prs', 'triage', 'unread', 'failed-preparation']) {
92
+ expect(fs.existsSync(tabFile(tab))).toBe(true);
93
+ }
94
+ });
95
+
96
+ it('writes items with no body field', () => {
97
+ writeConsoleLists({
98
+ consoleDataOutputDir: outDir,
99
+ pjcode: 'demo',
100
+ assigneeLogin: ASSIGNEE,
101
+ project,
102
+ issues: [makeIssue({ status: 'Unread' })],
103
+ generatedAt: '2026-06-14T07:22:33Z',
104
+ });
105
+
106
+ const raw: unknown = JSON.parse(fs.readFileSync(tabFile('unread'), 'utf8'));
107
+ expect(isRecord(raw)).toBe(true);
108
+ const items: unknown = isRecord(raw) ? raw.items : undefined;
109
+ expect(isUnknownArray(items)).toBe(true);
110
+ const firstItem: unknown = isUnknownArray(items) ? items[0] : undefined;
111
+ expect(isRecord(firstItem)).toBe(true);
112
+ expect(firstItem).not.toHaveProperty('body');
113
+ });
114
+
115
+ it('does not leave a temp file behind after writing', () => {
116
+ writeConsoleLists({
117
+ consoleDataOutputDir: outDir,
118
+ pjcode: 'demo',
119
+ assigneeLogin: ASSIGNEE,
120
+ project,
121
+ issues: [],
122
+ generatedAt: '2026-06-14T07:22:33Z',
123
+ });
124
+ expect(fs.existsSync(`${tabFile('prs')}.tmp`)).toBe(false);
125
+ });
126
+
127
+ it('is a no-op when consoleDataOutputDir is unset', () => {
128
+ writeConsoleLists({
129
+ consoleDataOutputDir: undefined,
130
+ pjcode: 'demo',
131
+ assigneeLogin: ASSIGNEE,
132
+ project,
133
+ issues: [makeIssue({ status: 'Unread' })],
134
+ });
135
+ expect(fs.readdirSync(outDir)).toHaveLength(0);
136
+ });
137
+
138
+ it('is a no-op when pjcode is unset', () => {
139
+ writeConsoleLists({
140
+ consoleDataOutputDir: outDir,
141
+ pjcode: '',
142
+ assigneeLogin: ASSIGNEE,
143
+ project,
144
+ issues: [makeIssue({ status: 'Unread' })],
145
+ });
146
+ expect(fs.readdirSync(outDir)).toHaveLength(0);
147
+ });
148
+
149
+ it('is a no-op when assigneeLogin is unset', () => {
150
+ writeConsoleLists({
151
+ consoleDataOutputDir: outDir,
152
+ pjcode: 'demo',
153
+ assigneeLogin: null,
154
+ project,
155
+ issues: [makeIssue({ status: 'Unread' })],
156
+ });
157
+ expect(fs.readdirSync(outDir)).toHaveLength(0);
158
+ });
159
+ });
160
+
161
+ describe('formatConsoleGeneratedAt', () => {
162
+ it('strips milliseconds and keeps the trailing Z', () => {
163
+ expect(formatConsoleGeneratedAt(new Date('2026-06-14T07:22:33.456Z'))).toBe(
164
+ '2026-06-14T07:22:33Z',
165
+ );
166
+ });
167
+ });
@@ -0,0 +1,60 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import type { Issue } from '../../../domain/entities/Issue';
4
+ import type { Project } from '../../../domain/entities/Project';
5
+ import {
6
+ ConsoleLists,
7
+ ConsoleTabName,
8
+ GenerateConsoleListsUseCase,
9
+ } from '../../../domain/usecases/console/GenerateConsoleListsUseCase';
10
+
11
+ export type ConsoleListsWriterParams = {
12
+ consoleDataOutputDir: string | null | undefined;
13
+ pjcode: string | null | undefined;
14
+ assigneeLogin: string | null | undefined;
15
+ project: Project;
16
+ issues: Issue[];
17
+ generatedAt?: string;
18
+ };
19
+
20
+ const CONSOLE_TAB_NAMES: ConsoleTabName[] = [
21
+ 'prs',
22
+ 'triage',
23
+ 'unread',
24
+ 'failed-preparation',
25
+ ];
26
+
27
+ export const formatConsoleGeneratedAt = (date: Date): string =>
28
+ date.toISOString().replace(/\.\d{3}Z$/, 'Z');
29
+
30
+ const writeJsonAtomic = (filePath: string, data: unknown): void => {
31
+ const dir = path.dirname(filePath);
32
+ fs.mkdirSync(dir, { recursive: true });
33
+ const tmpPath = `${filePath}.tmp`;
34
+ fs.writeFileSync(tmpPath, JSON.stringify(data));
35
+ fs.renameSync(tmpPath, filePath);
36
+ };
37
+
38
+ export const writeConsoleLists = (params: ConsoleListsWriterParams): void => {
39
+ const { consoleDataOutputDir, pjcode, assigneeLogin } = params;
40
+ if (!consoleDataOutputDir || !pjcode || !assigneeLogin) {
41
+ return;
42
+ }
43
+
44
+ const generatedAt =
45
+ params.generatedAt ?? formatConsoleGeneratedAt(new Date());
46
+ const lists: ConsoleLists = new GenerateConsoleListsUseCase().run({
47
+ project: params.project,
48
+ issues: params.issues,
49
+ pjcode,
50
+ assigneeLogin,
51
+ generatedAt,
52
+ });
53
+
54
+ for (const tab of CONSOLE_TAB_NAMES) {
55
+ writeJsonAtomic(
56
+ path.join(consoleDataOutputDir, pjcode, tab, 'list.json'),
57
+ lists[tab],
58
+ );
59
+ }
60
+ };
@@ -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":"AAuBA,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,CAkTP;CACH"}
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"}
@@ -0,0 +1,63 @@
1
+ import { Issue } from '../../entities/Issue';
2
+ import { FieldOption, Project } from '../../entities/Project';
3
+ export type ConsoleColor = FieldOption['color'];
4
+ export type ConsoleListItem = {
5
+ number: number;
6
+ title: string;
7
+ url: string;
8
+ repo: string;
9
+ nameWithOwner: string;
10
+ projectItemId: string;
11
+ itemId: string;
12
+ isPr: boolean;
13
+ story: string;
14
+ labels: string[];
15
+ createdAt: string;
16
+ };
17
+ export type ConsoleFieldOption = {
18
+ id: string;
19
+ name: string;
20
+ color: ConsoleColor;
21
+ };
22
+ export type ConsoleStatusTab = {
23
+ pjcode: string;
24
+ generatedAt: string;
25
+ statusOptions: ConsoleFieldOption[];
26
+ storyOrder: string[];
27
+ storyColors: Record<string, {
28
+ color: ConsoleColor;
29
+ }>;
30
+ items: ConsoleListItem[];
31
+ };
32
+ export type ConsoleTriageTab = {
33
+ pjcode: string;
34
+ generatedAt: string;
35
+ storyOptions: ConsoleFieldOption[];
36
+ storyOrder: string[];
37
+ storyColors: Record<string, ConsoleColor>;
38
+ items: ConsoleListItem[];
39
+ };
40
+ export type ConsoleTabName = 'prs' | 'triage' | 'unread' | 'failed-preparation';
41
+ export type ConsoleLists = {
42
+ prs: ConsoleStatusTab;
43
+ triage: ConsoleTriageTab;
44
+ unread: ConsoleStatusTab;
45
+ 'failed-preparation': ConsoleStatusTab;
46
+ };
47
+ export type GenerateConsoleListsInput = {
48
+ project: Project;
49
+ issues: Issue[];
50
+ pjcode: string;
51
+ assigneeLogin: string;
52
+ generatedAt: string;
53
+ };
54
+ export declare class GenerateConsoleListsUseCase {
55
+ run: (input: GenerateConsoleListsInput) => ConsoleLists;
56
+ private isActionable;
57
+ private projectItem;
58
+ private buildFieldOptions;
59
+ private buildStoryColorsObject;
60
+ private buildStoryColorsString;
61
+ private sortByStoryOrder;
62
+ }
63
+ //# sourceMappingURL=GenerateConsoleListsUseCase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerateConsoleListsUseCase.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/console/GenerateConsoleListsUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,YAAY,CAAA;KAAE,CAAC,CAAC;IACrD,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC1C,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,oBAAoB,CAAC;AAEhF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,gBAAgB,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,oBAAoB,EAAE,gBAAgB,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,qBAAa,2BAA2B;IACtC,GAAG,GAAI,OAAO,yBAAyB,KAAG,YAAY,CAqEpD;IAEF,OAAO,CAAC,YAAY,CAKY;IAEhC,OAAO,CAAC,WAAW,CAYhB;IAEH,OAAO,CAAC,iBAAiB,CAYjB;IAER,OAAO,CAAC,sBAAsB,CAQ5B;IAEF,OAAO,CAAC,sBAAsB,CAQ5B;IAEF,OAAO,CAAC,gBAAgB,CAetB;CACH"}