github-issue-tower-defence-management 1.192.0 → 1.194.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +4 -0
  3. package/bin/adapter/entry-points/cli/index.js +19 -0
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/console/consoleOperationApi.js +9 -2
  6. package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
  7. package/bin/adapter/entry-points/console/ui-dist/assets/{index-RaFqjB7u.js → index-CYwLv9pf.js} +2 -2
  8. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  9. package/bin/adapter/entry-points/handlers/tokenStatusWriter.js +1 -0
  10. package/bin/adapter/entry-points/handlers/tokenStatusWriter.js.map +1 -1
  11. package/bin/adapter/repositories/NodeLocalCommandRunner.js +5 -0
  12. package/bin/adapter/repositories/NodeLocalCommandRunner.js.map +1 -1
  13. package/bin/adapter/repositories/NodeTmuxSessionRepository.js +29 -0
  14. package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -1
  15. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +4 -2
  16. package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -1
  17. package/bin/domain/usecases/StartPreparationUseCase.js +70 -22
  18. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  19. package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js +1 -3
  20. package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js.map +1 -1
  21. package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js +12 -4
  22. package/bin/domain/usecases/dashboard/GenerateTokenStatusUseCase.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/adapter/entry-points/cli/index.test.ts +102 -0
  25. package/src/adapter/entry-points/cli/index.ts +43 -0
  26. package/src/adapter/entry-points/console/consoleOperationApi.test.ts +19 -5
  27. package/src/adapter/entry-points/console/consoleOperationApi.ts +18 -1
  28. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +45 -0
  29. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +7 -0
  30. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryList.stories.tsx +31 -0
  31. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryList.test.tsx +96 -0
  32. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryList.tsx +20 -2
  33. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +159 -0
  34. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +17 -1
  35. package/src/adapter/entry-points/console/ui-dist/assets/{index-RaFqjB7u.js → index-CYwLv9pf.js} +2 -2
  36. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  37. package/src/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.test.ts +1 -0
  38. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +1 -0
  39. package/src/adapter/entry-points/handlers/resetDegeneratedTmuxSessions.test.ts +4 -1
  40. package/src/adapter/entry-points/handlers/situationFileWriter.test.ts +2 -0
  41. package/src/adapter/entry-points/handlers/staleTmuxSessionCleaner.test.ts +1 -0
  42. package/src/adapter/entry-points/handlers/tokenStatusWriter.ts +1 -0
  43. package/src/adapter/repositories/LocalCommandIssueAttachmentRepository.test.ts +4 -0
  44. package/src/adapter/repositories/LocalProcessLiveSessionProcessSnapshotProvider.test.ts +1 -0
  45. package/src/adapter/repositories/NodeLocalCommandRunner.test.ts +16 -0
  46. package/src/adapter/repositories/NodeLocalCommandRunner.ts +5 -1
  47. package/src/adapter/repositories/NodeSubAgentProcessLister.test.ts +1 -0
  48. package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +132 -0
  49. package/src/adapter/repositories/NodeTmuxSessionRepository.ts +37 -0
  50. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +38 -0
  51. package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +6 -2
  52. package/src/adapter/repositories/TmuxSilentSessionNotificationRepository.test.ts +2 -0
  53. package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +1 -0
  54. package/src/domain/usecases/StartPreparationUseCase.test.ts +213 -2
  55. package/src/domain/usecases/StartPreparationUseCase.ts +155 -48
  56. package/src/domain/usecases/adapter-interfaces/LocalCommandRunner.ts +1 -0
  57. package/src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts +4 -0
  58. package/src/domain/usecases/console/GenerateConsoleListsUseCase.test.ts +5 -4
  59. package/src/domain/usecases/console/GenerateConsoleListsUseCase.ts +9 -11
  60. package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.test.ts +63 -0
  61. package/src/domain/usecases/dashboard/GenerateTokenStatusUseCase.ts +13 -4
  62. package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +1 -0
  63. package/src/domain/usecases/issueReactivationTriggerIsPending.test.ts +1 -0
  64. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  65. package/types/adapter/entry-points/console/consoleOperationApi.d.ts +1 -0
  66. package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
  67. package/types/adapter/entry-points/handlers/tokenStatusWriter.d.ts.map +1 -1
  68. package/types/adapter/repositories/NodeLocalCommandRunner.d.ts +1 -0
  69. package/types/adapter/repositories/NodeLocalCommandRunner.d.ts.map +1 -1
  70. package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +1 -0
  71. package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -1
  72. package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -1
  73. package/types/domain/usecases/StartPreparationUseCase.d.ts +10 -1
  74. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
  75. package/types/domain/usecases/adapter-interfaces/LocalCommandRunner.d.ts +1 -0
  76. package/types/domain/usecases/adapter-interfaces/LocalCommandRunner.d.ts.map +1 -1
  77. package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts +1 -0
  78. package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts.map +1 -1
  79. package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts.map +1 -1
  80. package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts +1 -0
  81. package/types/domain/usecases/dashboard/GenerateTokenStatusUseCase.d.ts.map +1 -1
@@ -994,6 +994,165 @@ describe('ConsolePage auto-advance tab', () => {
994
994
  });
995
995
  });
996
996
 
997
+ it('shows the stories tab badge count as the number of non-GRAY stories', async () => {
998
+ global.fetch = jest.fn(async (url: string) => {
999
+ const listMatch = url.match(/\/projects\/[^/]+\/([^/]+)\/list\.json/);
1000
+ if (listMatch !== null) {
1001
+ const tab = listMatch[1];
1002
+ if (tab === 'stories') {
1003
+ return {
1004
+ ok: true,
1005
+ status: 200,
1006
+ json: async () => ({
1007
+ generatedAt: '2026-06-19T00:00:00.000Z',
1008
+ stories: [
1009
+ {
1010
+ storyName: 'TDPM Console port',
1011
+ storyOptionId: 'st1',
1012
+ color: 'BLUE',
1013
+ openItemCount: 3,
1014
+ storyViewUrl: null,
1015
+ },
1016
+ {
1017
+ storyName: 'regular / workflow improvement',
1018
+ storyOptionId: 'st2',
1019
+ color: 'GRAY',
1020
+ openItemCount: 2,
1021
+ storyViewUrl: null,
1022
+ },
1023
+ ],
1024
+ defaultNameWithOwner: null,
1025
+ storyOrder: [],
1026
+ }),
1027
+ };
1028
+ }
1029
+ return { ok: true, status: 200, json: async () => listPayload(tab) };
1030
+ }
1031
+ if (url === '/api/projects') {
1032
+ return {
1033
+ ok: true,
1034
+ status: 200,
1035
+ json: async () => ({ pjcodes: ['acme'] }),
1036
+ };
1037
+ }
1038
+ return { ok: true, status: 200, json: async () => ({ body: '# body' }) };
1039
+ }) as unknown as typeof fetch;
1040
+
1041
+ const { container } = render(<ConsolePage />);
1042
+
1043
+ await waitFor(() => {
1044
+ const tabs = [...container.querySelectorAll('.console-tab')];
1045
+ const storiesTab = tabs.find((el) => el.textContent?.includes('Stories'));
1046
+ expect(storiesTab).toBeTruthy();
1047
+ expect(storiesTab?.querySelector('.console-tab-badge')?.textContent).toBe(
1048
+ '1',
1049
+ );
1050
+ });
1051
+ });
1052
+
1053
+ it('reads console-story-show-gray from localStorage and shows gray stories when true', async () => {
1054
+ localStorage.setItem('console-story-show-gray', 'true');
1055
+ window.history.replaceState({}, '', '/projects/acme/stories?k=token');
1056
+ global.fetch = jest.fn(async (url: string) => {
1057
+ const listMatch = url.match(/\/projects\/[^/]+\/([^/]+)\/list\.json/);
1058
+ if (listMatch !== null) {
1059
+ const tab = listMatch[1];
1060
+ if (tab === 'stories') {
1061
+ return {
1062
+ ok: true,
1063
+ status: 200,
1064
+ json: async () => ({
1065
+ generatedAt: '2026-06-19T00:00:00.000Z',
1066
+ stories: [
1067
+ {
1068
+ storyName: 'TDPM Console port',
1069
+ storyOptionId: 'st1',
1070
+ color: 'BLUE',
1071
+ openItemCount: 3,
1072
+ storyViewUrl: null,
1073
+ },
1074
+ {
1075
+ storyName: 'regular / workflow improvement',
1076
+ storyOptionId: 'st2',
1077
+ color: 'GRAY',
1078
+ openItemCount: 2,
1079
+ storyViewUrl: null,
1080
+ },
1081
+ ],
1082
+ defaultNameWithOwner: null,
1083
+ storyOrder: [],
1084
+ }),
1085
+ };
1086
+ }
1087
+ return { ok: true, status: 200, json: async () => listPayload(tab) };
1088
+ }
1089
+ if (url === '/api/projects') {
1090
+ return {
1091
+ ok: true,
1092
+ status: 200,
1093
+ json: async () => ({ pjcodes: ['acme'] }),
1094
+ };
1095
+ }
1096
+ return { ok: true, status: 200, json: async () => ({ body: '# body' }) };
1097
+ }) as unknown as typeof fetch;
1098
+
1099
+ const { findByText } = render(<ConsolePage />);
1100
+ expect(
1101
+ await findByText('regular / workflow improvement'),
1102
+ ).toBeInTheDocument();
1103
+ });
1104
+
1105
+ it('writes true to console-story-show-gray in localStorage when the toggle button is clicked', async () => {
1106
+ window.history.replaceState({}, '', '/projects/acme/stories?k=token');
1107
+ global.fetch = jest.fn(async (url: string) => {
1108
+ const listMatch = url.match(/\/projects\/[^/]+\/([^/]+)\/list\.json/);
1109
+ if (listMatch !== null) {
1110
+ const tab = listMatch[1];
1111
+ if (tab === 'stories') {
1112
+ return {
1113
+ ok: true,
1114
+ status: 200,
1115
+ json: async () => ({
1116
+ generatedAt: '2026-06-19T00:00:00.000Z',
1117
+ stories: [
1118
+ {
1119
+ storyName: 'TDPM Console port',
1120
+ storyOptionId: 'st1',
1121
+ color: 'BLUE',
1122
+ openItemCount: 3,
1123
+ storyViewUrl: null,
1124
+ },
1125
+ {
1126
+ storyName: 'regular / workflow improvement',
1127
+ storyOptionId: 'st2',
1128
+ color: 'GRAY',
1129
+ openItemCount: 2,
1130
+ storyViewUrl: null,
1131
+ },
1132
+ ],
1133
+ defaultNameWithOwner: null,
1134
+ storyOrder: [],
1135
+ }),
1136
+ };
1137
+ }
1138
+ return { ok: true, status: 200, json: async () => listPayload(tab) };
1139
+ }
1140
+ if (url === '/api/projects') {
1141
+ return {
1142
+ ok: true,
1143
+ status: 200,
1144
+ json: async () => ({ pjcodes: ['acme'] }),
1145
+ };
1146
+ }
1147
+ return { ok: true, status: 200, json: async () => ({ body: '# body' }) };
1148
+ }) as unknown as typeof fetch;
1149
+
1150
+ const { findByRole } = render(<ConsolePage />);
1151
+ const toggleBtn = await findByRole('button', { name: 'Show archived' });
1152
+ fireEvent.click(toggleBtn);
1153
+ expect(localStorage.getItem('console-story-show-gray')).toBe('true');
1154
+ });
1155
+
997
1156
  it('navigates to the next project when a completing action fires after the project timer elapses', async () => {
998
1157
  localStorage.setItem(
999
1158
  'tdpm-timer-settings',
@@ -97,7 +97,9 @@ export const ConsolePage = () => {
97
97
  continue;
98
98
  }
99
99
  if (tab.name === 'stories') {
100
- result[tab.name] = snapshot.stories.length;
100
+ result[tab.name] = snapshot.stories.filter(
101
+ (s) => s.color !== 'GRAY',
102
+ ).length;
101
103
  } else {
102
104
  result[tab.name] = countPendingItems(
103
105
  snapshot.items,
@@ -330,6 +332,18 @@ export const ConsolePage = () => {
330
332
 
331
333
  const detailScreenRef = useConsoleSwipeNavigation(handleSwipe);
332
334
 
335
+ const [showGray, setShowGray] = useState(
336
+ () => localStorage.getItem('console-story-show-gray') === 'true',
337
+ );
338
+
339
+ const handleToggleGray = useCallback((): void => {
340
+ setShowGray((prev) => {
341
+ const next = !prev;
342
+ localStorage.setItem('console-story-show-gray', String(next));
343
+ return next;
344
+ });
345
+ }, []);
346
+
333
347
  const storiesSnapshot = snapshots.stories;
334
348
  const storyEntries = storiesSnapshot?.stories ?? [];
335
349
  const defaultNameWithOwner = storiesSnapshot?.defaultNameWithOwner ?? null;
@@ -502,9 +516,11 @@ export const ConsolePage = () => {
502
516
  stories={storyEntries}
503
517
  isLoading={isLoading}
504
518
  error={error}
519
+ showGray={showGray}
505
520
  onCreateIssue={handleCreateIssue}
506
521
  onAddStory={handleStoryAdd}
507
522
  onSelectColor={handleSelectColor}
523
+ onToggleGray={handleToggleGray}
508
524
  optimisticColors={storyOptimisticColors}
509
525
  colorChangeInFlight={storyColorChangeInFlight}
510
526
  colorErrors={storyColorErrors}