github-issue-tower-defence-management 1.151.0 → 1.151.2

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 (39) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/bin/adapter/entry-points/console/consoleDoneStore.js +19 -1
  3. package/bin/adapter/entry-points/console/consoleDoneStore.js.map +1 -1
  4. package/bin/adapter/entry-points/console/consoleOperationApi.js +17 -5
  5. package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
  6. package/bin/adapter/entry-points/console/ui-dist/assets/index-CY96HROQ.js +83 -0
  7. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  8. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +14 -15
  9. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  10. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +2 -10
  11. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
  12. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js +16 -5
  13. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js.map +1 -1
  14. package/package.json +1 -1
  15. package/src/adapter/entry-points/console/consoleDoneStore.test.ts +21 -0
  16. package/src/adapter/entry-points/console/consoleDoneStore.ts +25 -0
  17. package/src/adapter/entry-points/console/consoleOperationApi.test.ts +58 -7
  18. package/src/adapter/entry-points/console/consoleOperationApi.ts +43 -6
  19. package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.test.ts +79 -1
  20. package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.ts +20 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +42 -0
  22. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +6 -2
  23. package/src/adapter/entry-points/console/ui-dist/assets/index-CY96HROQ.js +83 -0
  24. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  25. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +26 -28
  26. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +36 -3
  27. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +3 -22
  28. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.singleScan.test.ts +88 -0
  29. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts +22 -11
  30. package/types/adapter/entry-points/console/consoleDoneStore.d.ts +3 -0
  31. package/types/adapter/entry-points/console/consoleDoneStore.d.ts.map +1 -1
  32. package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
  33. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  34. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +2 -2
  35. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
  36. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts +2 -0
  37. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts.map +1 -1
  38. package/bin/adapter/entry-points/console/ui-dist/assets/index-UQt5L756.js +0 -83
  39. package/src/adapter/entry-points/console/ui-dist/assets/index-UQt5L756.js +0 -83
@@ -4,10 +4,15 @@ import {
4
4
  isOverlayEntryActed,
5
5
  overlayEntriesActedSinceSnapshot,
6
6
  overlayKeyForItem,
7
+ overlayStatusSinceSnapshot,
7
8
  overlayStorageKey,
8
9
  writeOverlayEntry,
9
10
  } from './overlay';
10
- import type { ConsoleListItem, ConsoleOverlay } from './types';
11
+ import type {
12
+ ConsoleListItem,
13
+ ConsoleOverlay,
14
+ ConsoleOverlayStatus,
15
+ } from './types';
11
16
 
12
17
  const item = (number: number): ConsoleListItem => ({
13
18
  number,
@@ -230,3 +235,76 @@ describe('writeOverlayEntry', () => {
230
235
  });
231
236
  });
232
237
  });
238
+
239
+ describe('overlayStatusSinceSnapshot', () => {
240
+ const snapshotGeneratedAt = '2026-08-13T21:52:01.000Z';
241
+ const snapshotEpochMs = Date.parse(snapshotGeneratedAt);
242
+ const inTmuxByHuman: ConsoleOverlayStatus = {
243
+ name: 'In Tmux by human',
244
+ color: 'RED',
245
+ };
246
+
247
+ const overlayWithStatusAt = (epochMs: number): ConsoleOverlay => ({
248
+ [overlayKeyForItem(item(1))]: {
249
+ status: inTmuxByHuman,
250
+ ts: epochMs,
251
+ mode: 'todo-by-human',
252
+ },
253
+ });
254
+
255
+ it('shows a status the owner set after the snapshot was generated', () => {
256
+ expect(
257
+ overlayStatusSinceSnapshot(
258
+ overlayWithStatusAt(snapshotEpochMs + 1000),
259
+ item(1),
260
+ snapshotGeneratedAt,
261
+ ),
262
+ ).toEqual(inTmuxByHuman);
263
+ });
264
+
265
+ it('drops a status the snapshot already superseded', () => {
266
+ expect(
267
+ overlayStatusSinceSnapshot(
268
+ overlayWithStatusAt(snapshotEpochMs - 1000),
269
+ item(1),
270
+ snapshotGeneratedAt,
271
+ ),
272
+ ).toBeNull();
273
+ });
274
+
275
+ it('drops every status when the snapshot time is unusable', () => {
276
+ expect(
277
+ overlayStatusSinceSnapshot(
278
+ overlayWithStatusAt(snapshotEpochMs + 1000),
279
+ item(1),
280
+ null,
281
+ ),
282
+ ).toBeNull();
283
+ });
284
+
285
+ it('shows a status set at the exact moment the snapshot was generated', () => {
286
+ expect(
287
+ overlayStatusSinceSnapshot(
288
+ overlayWithStatusAt(snapshotEpochMs),
289
+ item(1),
290
+ snapshotGeneratedAt,
291
+ ),
292
+ ).toEqual(inTmuxByHuman);
293
+ });
294
+
295
+ it('drops every status when the snapshot time cannot be parsed', () => {
296
+ expect(
297
+ overlayStatusSinceSnapshot(
298
+ overlayWithStatusAt(snapshotEpochMs + 1000),
299
+ item(1),
300
+ 'not a timestamp',
301
+ ),
302
+ ).toBeNull();
303
+ });
304
+
305
+ it('returns null when the item has no overlay entry', () => {
306
+ expect(
307
+ overlayStatusSinceSnapshot({}, item(1), snapshotGeneratedAt),
308
+ ).toBeNull();
309
+ });
310
+ });
@@ -2,6 +2,7 @@ import type {
2
2
  ConsoleListItem,
3
3
  ConsoleOverlay,
4
4
  ConsoleOverlayEntry,
5
+ ConsoleOverlayStatus,
5
6
  ConsoleTabName,
6
7
  } from './types';
7
8
 
@@ -47,6 +48,25 @@ export const overlayEntriesActedSinceSnapshot = (
47
48
  return acted;
48
49
  };
49
50
 
51
+ export const overlayStatusSinceSnapshot = (
52
+ overlay: ConsoleOverlay,
53
+ item: ConsoleListItem,
54
+ snapshotGeneratedAt: string | null,
55
+ ): ConsoleOverlayStatus | null => {
56
+ if (snapshotGeneratedAt === null) {
57
+ return null;
58
+ }
59
+ const snapshotGeneratedAtMs = Date.parse(snapshotGeneratedAt);
60
+ if (Number.isNaN(snapshotGeneratedAtMs)) {
61
+ return null;
62
+ }
63
+ const entry = overlay[overlayKeyForItem(item)];
64
+ if (entry === undefined || entry.ts < snapshotGeneratedAtMs) {
65
+ return null;
66
+ }
67
+ return entry.status ?? null;
68
+ };
69
+
50
70
  export const writeOverlayEntry = (
51
71
  overlay: ConsoleOverlay,
52
72
  key: string,
@@ -106,6 +106,48 @@ describe('ConsolePage', () => {
106
106
  ).toContain('TDPM Console port');
107
107
  });
108
108
 
109
+ it('keeps a status the snapshot already superseded out of the detail header', async () => {
110
+ localStorage.setItem(
111
+ 'pv_overlay_acme',
112
+ JSON.stringify({
113
+ PVTI_1: {
114
+ status: { name: 'In Tmux by human', color: 'RED' },
115
+ ts: Date.parse('2026-06-18T00:00:00.000Z'),
116
+ mode: 'prs',
117
+ },
118
+ }),
119
+ );
120
+ const { getByText, findByText, container } = render(<ConsolePage />);
121
+ await waitFor(() => {
122
+ expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
123
+ });
124
+ fireEvent.click(getByText('Add serveConsole subcommand'));
125
+ expect(await findByText('Approve')).toBeInTheDocument();
126
+ expect(container.querySelector('.console-detail-status-chip')).toBeNull();
127
+ });
128
+
129
+ it('shows a status the owner set after the snapshot was generated in the detail header', async () => {
130
+ localStorage.setItem(
131
+ 'pv_overlay_acme',
132
+ JSON.stringify({
133
+ PVTI_1: {
134
+ status: { name: 'In Tmux by human', color: 'RED' },
135
+ ts: Date.parse('2026-06-19T00:10:00.000Z'),
136
+ mode: 'prs',
137
+ },
138
+ }),
139
+ );
140
+ const { getByText, findByText, container } = render(<ConsolePage />);
141
+ await waitFor(() => {
142
+ expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
143
+ });
144
+ fireEvent.click(getByText('Add serveConsole subcommand'));
145
+ expect(await findByText('Approve')).toBeInTheDocument();
146
+ expect(
147
+ container.querySelector('.console-detail-status-chip')?.textContent,
148
+ ).toBe('In Tmux by human');
149
+ });
150
+
109
151
  it('opens the detail view when an item is selected', async () => {
110
152
  const { getByText, findByText } = render(<ConsolePage />);
111
153
  await waitFor(() => {
@@ -30,6 +30,7 @@ import {
30
30
  filterPendingItems,
31
31
  overlayEntriesActedSinceSnapshot,
32
32
  overlayKeyForItem,
33
+ overlayStatusSinceSnapshot,
33
34
  } from '../logic/overlay';
34
35
  import type { ConsoleSwipeDirection } from '../logic/swipe';
35
36
  import { findNextNonEmptyTabToRight } from '../logic/tabAdvance';
@@ -164,8 +165,11 @@ export const ConsolePage = () => {
164
165
  if (selectedItem === null) {
165
166
  return null;
166
167
  }
167
- const entry = overlayState.overlay[overlayKeyForItem(selectedItem)];
168
- return entry?.status ?? null;
168
+ return overlayStatusSinceSnapshot(
169
+ overlayState.overlay,
170
+ selectedItem,
171
+ snapshots[activeTab]?.generatedAt ?? null,
172
+ );
169
173
  })();
170
174
 
171
175
  const storyNameForSelected =