github-issue-tower-defence-management 1.150.0 → 1.151.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +9 -1
  3. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +32 -9
  4. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  5. package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js +13 -1
  6. package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js.map +1 -1
  7. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +2 -10
  8. package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
  9. package/bin/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.js +12 -0
  10. package/bin/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.js.map +1 -0
  11. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js +72 -14
  12. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js.map +1 -1
  13. package/bin/domain/entities/UnansweredOwnerCall.js +3 -0
  14. package/bin/domain/entities/UnansweredOwnerCall.js.map +1 -0
  15. package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js +21 -2
  16. package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js.map +1 -1
  17. package/package.json +1 -1
  18. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +58 -14
  19. package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.test.ts +104 -1
  20. package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.ts +19 -0
  21. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +36 -3
  22. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +3 -22
  23. package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.test.ts +111 -0
  24. package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.ts +33 -0
  25. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.singleScan.test.ts +88 -0
  26. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.test.ts +178 -0
  27. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts +122 -22
  28. package/src/domain/entities/UnansweredOwnerCall.ts +4 -0
  29. package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +99 -0
  30. package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts +47 -1
  31. package/src/domain/usecases/intmux/UnansweredOwnerCallSessionKeyContract.test.ts +141 -0
  32. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  33. package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts +2 -0
  34. package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts.map +1 -1
  35. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +2 -2
  36. package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
  37. package/types/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.d.ts +13 -0
  38. package/types/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.d.ts.map +1 -0
  39. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts +7 -0
  40. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts.map +1 -1
  41. package/types/domain/entities/UnansweredOwnerCall.d.ts +5 -0
  42. package/types/domain/entities/UnansweredOwnerCall.d.ts.map +1 -0
  43. package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts +19 -0
  44. package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"GenerateInTmuxByHumanDataUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GenerateInTmuxByHumanDataUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.150.0",
3
+ "version": "1.151.1",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -19,6 +19,14 @@ import {
19
19
  DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS,
20
20
  } from './notifySilentTmuxSessions';
21
21
  import { ownerReplyMarkerDirectoryResolve } from './ownerReplyMarkerDirectoryResolve';
22
+ import { resolveUnansweredOwnerCallsByTmuxSessionName } from './resolveUnansweredOwnerCalls';
23
+ import { LocalProcessLiveSessionProcessSnapshotProvider } from '../../repositories/LocalProcessLiveSessionProcessSnapshotProvider';
24
+ import { ProcFsProcessEnvironReader } from '../../repositories/ProcFsProcessEnvironReader';
25
+ import { FileSystemInteractiveLiveSessionTranscriptResolver } from '../../repositories/FileSystemInteractiveLiveSessionTranscriptResolver';
26
+ import { TranscriptOwnerCallStatusProvider } from '../../repositories/TranscriptOwnerCallStatusProvider';
27
+ import { NoUnansweredOwnerCallStatusProvider } from '../../repositories/NoUnansweredOwnerCallStatusProvider';
28
+ import { OwnerCallStatusProvider } from '../../../domain/usecases/adapter-interfaces/OwnerCallStatusProvider';
29
+ import { UnansweredOwnerCall } from '../../../domain/entities/UnansweredOwnerCall';
22
30
  import {
23
31
  resetDegeneratedTmuxSessions,
24
32
  DEFAULT_RESET_DEGENERATED_TMUX_SESSIONS_PARAMS,
@@ -632,6 +640,54 @@ export class HandleScheduledEventUseCaseHandler {
632
640
 
633
641
  const inTmuxNow = new Date();
634
642
 
643
+ const inTmuxGetuid = process.getuid?.bind(process);
644
+ const ownerCallMarker =
645
+ mergedInput.ownerCallMarker ??
646
+ process.env.TDPM_SILENT_OWNER_CALL_MARKER ??
647
+ null;
648
+ const ownerReplyMarkerDirectory = ownerReplyMarkerDirectoryResolve(
649
+ mergedInput.ownerReplyMarkerDirectory ?? null,
650
+ process.env,
651
+ inTmuxGetuid === undefined ? null : inTmuxGetuid(),
652
+ );
653
+ const transcriptOwnerCallStatusProvider =
654
+ ownerCallMarker !== null && ownerCallMarker.length > 0
655
+ ? new TranscriptOwnerCallStatusProvider(
656
+ ownerCallMarker,
657
+ ownerReplyMarkerDirectory,
658
+ )
659
+ : null;
660
+ const ownerCallStatusProvider: OwnerCallStatusProvider =
661
+ transcriptOwnerCallStatusProvider ??
662
+ new NoUnansweredOwnerCallStatusProvider();
663
+
664
+ let unansweredCallsByTmuxSessionName = new Map<
665
+ string,
666
+ UnansweredOwnerCall[]
667
+ >();
668
+ try {
669
+ if (transcriptOwnerCallStatusProvider !== null) {
670
+ unansweredCallsByTmuxSessionName =
671
+ await resolveUnansweredOwnerCallsByTmuxSessionName({
672
+ liveSessionProcessSnapshotProvider:
673
+ new LocalProcessLiveSessionProcessSnapshotProvider(
674
+ nodeLocalCommandRunner,
675
+ new ProcFsProcessEnvironReader(),
676
+ ),
677
+ interactiveLiveSessionTranscriptResolver:
678
+ new FileSystemInteractiveLiveSessionTranscriptResolver(),
679
+ unansweredOwnerCallListProvider:
680
+ transcriptOwnerCallStatusProvider,
681
+ });
682
+ }
683
+ } catch (error) {
684
+ console.error(
685
+ `Failed to resolve unanswered owner calls: ${
686
+ error instanceof Error ? error.message : String(error)
687
+ }`,
688
+ );
689
+ }
690
+
635
691
  try {
636
692
  writeInTmuxByHumanData({
637
693
  inTmuxDataOutputDir: mergedInput.inTmuxDataOutputDir ?? null,
@@ -648,6 +704,7 @@ export class HandleScheduledEventUseCaseHandler {
648
704
  newIssueRepo: mergedInput.newIssueRepo ?? undefined,
649
705
  project: result.project,
650
706
  issues: result.issues,
707
+ unansweredCallsByTmuxSessionName,
651
708
  now: inTmuxNow,
652
709
  });
653
710
  } catch (error) {
@@ -727,23 +784,11 @@ export class HandleScheduledEventUseCaseHandler {
727
784
  mergedInput.subAgentProcessMatchPattern ??
728
785
  process.env.TDPM_SUBAGENT_PROCESS_MATCH_PATTERN ??
729
786
  null;
730
- const ownerCallMarker =
731
- mergedInput.ownerCallMarker ??
732
- process.env.TDPM_SILENT_OWNER_CALL_MARKER ??
733
- null;
734
787
  const subAgentTranscriptRootDirectory =
735
788
  mergedInput.subAgentTranscriptRootDirectory ??
736
789
  process.env.TDPM_SUBAGENT_TRANSCRIPT_ROOT_DIRECTORY ??
737
790
  null;
738
791
  const getuid = process.getuid?.bind(process);
739
- // The status line writes the reply time it renders here, and the owner sees only that
740
- // status line, so reading the same file keeps the reminder decision and the owner's view
741
- // of it from disagreeing.
742
- const ownerReplyMarkerDirectory = ownerReplyMarkerDirectoryResolve(
743
- mergedInput.ownerReplyMarkerDirectory ?? null,
744
- process.env,
745
- getuid === undefined ? null : getuid(),
746
- );
747
792
  const subAgentRuntimeRootDirectory =
748
793
  mergedInput.subAgentRuntimeRootDirectory ??
749
794
  process.env.TDPM_SUBAGENT_RUNTIME_ROOT_DIRECTORY ??
@@ -753,8 +798,7 @@ export class HandleScheduledEventUseCaseHandler {
753
798
  await notifySilentTmuxSessions({
754
799
  enabled: silentNotificationEnabled,
755
800
  localCommandRunner: nodeLocalCommandRunner,
756
- ownerCallMarker,
757
- ownerReplyMarkerDirectory,
801
+ ownerCallStatusProvider,
758
802
  subAgentOutputRootDirectory,
759
803
  subAgentProcessMatchPattern,
760
804
  subAgentTranscriptRootDirectory,
@@ -4,6 +4,7 @@ import path from 'path';
4
4
  import { Issue } from '../../../domain/entities/Issue';
5
5
  import { FieldOption, Project } from '../../../domain/entities/Project';
6
6
  import { writeInTmuxByHumanData } from './inTmuxByHumanDataWriter';
7
+ import { toTmuxSessionName } from '../../../domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase';
7
8
 
8
9
  const ASSIGNEE = 'owner-login';
9
10
  const CONSOLE_BASE_URL = 'https://console.example.test';
@@ -98,22 +99,124 @@ describe('writeInTmuxByHumanData', () => {
98
99
 
99
100
  const file = (name: string): string => path.join(outDir, name);
100
101
 
101
- it('writes the four per-project files and the four index files', () => {
102
+ it('writes the five per-project files and the five index files', () => {
102
103
  writeInTmuxByHumanData(baseParams(outDir));
103
104
  for (const name of [
104
105
  'demo.json',
105
106
  'demo.v2.json',
106
107
  'demo.v3.json',
107
108
  'demo.v4.json',
109
+ 'demo.v5.json',
108
110
  'index.json',
109
111
  'index.v2.json',
110
112
  'index.v3.json',
111
113
  'index.v4.json',
114
+ 'index.v5.json',
112
115
  ]) {
113
116
  expect(fs.existsSync(file(name))).toBe(true);
114
117
  }
115
118
  });
116
119
 
120
+ it('writes the v5 shape carrying the unanswered calls of the session', () => {
121
+ writeInTmuxByHumanData({
122
+ ...baseParams(outDir),
123
+ unansweredCallsByTmuxSessionName: new Map([
124
+ [
125
+ toTmuxSessionName('https://github.com/demo/repo/issues/1'),
126
+ [
127
+ {
128
+ calledAt: '2026-08-13T10:14:00.000Z',
129
+ body: 'Please decide whether to merge the release branch',
130
+ },
131
+ ],
132
+ ],
133
+ ]),
134
+ });
135
+
136
+ expect(readJson(file('demo.v5.json'))).toEqual({
137
+ version: 5,
138
+ overviewUrl: 'https://github.com/orgs/demo/projects/1',
139
+ tdpmConsoleUrl: `${CONSOLE_BASE_URL}/projects/demo?k=${CONSOLE_TOKEN}`,
140
+ newIssueUrl: `https://github.com/demo-org/demo-repo/issues/new?assignees=${ASSIGNEE}`,
141
+ groups: [
142
+ {
143
+ story: 'Story Alpha',
144
+ sessions: [
145
+ {
146
+ name: 'https://github.com/demo/repo/issues/1',
147
+ description: 'Issue 1',
148
+ unansweredCalls: [
149
+ {
150
+ calledAt: '2026-08-13T10:14:00.000Z',
151
+ body: 'Please decide whether to merge the release branch',
152
+ },
153
+ ],
154
+ },
155
+ ],
156
+ },
157
+ ],
158
+ });
159
+ });
160
+
161
+ it('writes an empty unansweredCalls array when no call is supplied', () => {
162
+ writeInTmuxByHumanData(baseParams(outDir));
163
+ expect(readJson(file('demo.v5.json'))).toMatchObject({
164
+ groups: [
165
+ {
166
+ sessions: [
167
+ {
168
+ name: 'https://github.com/demo/repo/issues/1',
169
+ unansweredCalls: [],
170
+ },
171
+ ],
172
+ },
173
+ ],
174
+ });
175
+ });
176
+
177
+ it('points the v5 index entry at the v5 document of each project', () => {
178
+ writeInTmuxByHumanData(baseParams(outDir));
179
+ expect(readJson(file('index.v5.json'))).toEqual({
180
+ version: 5,
181
+ projects: [
182
+ {
183
+ name: 'demo',
184
+ path: `/${path.basename(outDir)}/demo.v5.json?k=${CONSOLE_TOKEN}`,
185
+ },
186
+ ],
187
+ });
188
+ });
189
+
190
+ it('keeps the v4 document free of unanswered call data when calls are supplied', () => {
191
+ writeInTmuxByHumanData({
192
+ ...baseParams(outDir),
193
+ unansweredCallsByTmuxSessionName: new Map([
194
+ [
195
+ toTmuxSessionName('https://github.com/demo/repo/issues/1'),
196
+ [{ calledAt: '2026-08-13T10:14:00.000Z', body: 'first call body' }],
197
+ ],
198
+ ]),
199
+ });
200
+
201
+ expect(readJson(file('demo.v4.json'))).toEqual({
202
+ version: 4,
203
+ overviewUrl: 'https://github.com/orgs/demo/projects/1',
204
+ tdpmConsoleUrl: `${CONSOLE_BASE_URL}/projects/demo?k=${CONSOLE_TOKEN}`,
205
+ newIssueUrl: `https://github.com/demo-org/demo-repo/issues/new?assignees=${ASSIGNEE}`,
206
+ groups: [
207
+ {
208
+ story: 'Story Alpha',
209
+ sessions: [
210
+ {
211
+ name: 'https://github.com/demo/repo/issues/1',
212
+ description: 'Issue 1',
213
+ },
214
+ ],
215
+ },
216
+ ],
217
+ });
218
+ });
219
+
117
220
  it('writes pretty-printed JSON ending with a trailing newline', () => {
118
221
  writeInTmuxByHumanData(baseParams(outDir));
119
222
  const raw = fs.readFileSync(file('demo.json'), 'utf8');
@@ -2,6 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import type { Issue } from '../../../domain/entities/Issue';
4
4
  import type { Project } from '../../../domain/entities/Project';
5
+ import type { UnansweredOwnerCall } from '../../../domain/entities/UnansweredOwnerCall';
5
6
  import {
6
7
  GenerateInTmuxByHumanDataUseCase,
7
8
  InTmuxByHumanData,
@@ -19,6 +20,7 @@ export type InTmuxByHumanDataWriterParams = {
19
20
  newIssueRepo?: string | null | undefined;
20
21
  project: Project;
21
22
  issues: Issue[];
23
+ unansweredCallsByTmuxSessionName?: Map<string, UnansweredOwnerCall[]>;
22
24
  now: Date;
23
25
  };
24
26
 
@@ -45,6 +47,7 @@ export const writeInTmuxByHumanData = (
45
47
  newIssueRepo,
46
48
  project,
47
49
  issues,
50
+ unansweredCallsByTmuxSessionName,
48
51
  now,
49
52
  } = params;
50
53
  if (!inTmuxDataOutputDir || !pjcode || !assigneeLogin) {
@@ -61,6 +64,9 @@ export const writeInTmuxByHumanData = (
61
64
  newIssueRepo: newIssueRepo ?? undefined,
62
65
  consoleBaseUrl: inTmuxConsoleBaseUrl ?? null,
63
66
  consoleToken: inTmuxConsoleToken ?? null,
67
+ unansweredCallsByTmuxSessionName:
68
+ unansweredCallsByTmuxSessionName ??
69
+ new Map<string, UnansweredOwnerCall[]>(),
64
70
  now,
65
71
  });
66
72
 
@@ -78,6 +84,12 @@ export const writeInTmuxByHumanData = (
78
84
  data.v4,
79
85
  );
80
86
  }
87
+ if (data.v5) {
88
+ writeJsonAtomic(
89
+ path.join(inTmuxDataOutputDir, `${pjcode}.v5.json`),
90
+ data.v5,
91
+ );
92
+ }
81
93
 
82
94
  if (!inTmuxProjectOrder || inTmuxProjectOrder.length === 0) {
83
95
  return;
@@ -105,5 +117,12 @@ export const writeInTmuxByHumanData = (
105
117
  path: `/${outputDirBasename}/${name}.v4.json?k=${inTmuxConsoleToken}`,
106
118
  })),
107
119
  });
120
+ writeJsonAtomic(path.join(inTmuxDataOutputDir, 'index.v5.json'), {
121
+ version: 5,
122
+ projects: presentProjects.map((name) => ({
123
+ name,
124
+ path: `/${outputDirBasename}/${name}.v5.json?k=${inTmuxConsoleToken}`,
125
+ })),
126
+ });
108
127
  }
109
128
  };
@@ -10,6 +10,9 @@ import {
10
10
  notifySilentTmuxSessions,
11
11
  DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS,
12
12
  } from './notifySilentTmuxSessions';
13
+ import { OwnerCallStatusProvider } from '../../../domain/usecases/adapter-interfaces/OwnerCallStatusProvider';
14
+ import { NoUnansweredOwnerCallStatusProvider } from '../../repositories/NoUnansweredOwnerCallStatusProvider';
15
+ import { TranscriptOwnerCallStatusProvider } from '../../repositories/TranscriptOwnerCallStatusProvider';
13
16
 
14
17
  const NOW = new Date('2026-06-26T00:00:00.000Z');
15
18
  const NOW_EPOCH_SECONDS = Math.floor(NOW.getTime() / 1000);
@@ -135,7 +138,7 @@ describe('notifySilentTmuxSessions', () => {
135
138
  enabled: true,
136
139
  localCommandRunner: runner,
137
140
  processEnvironReader: makeEnvironReader(),
138
- ownerCallMarker: null,
141
+ ownerCallStatusProvider: new NoUnansweredOwnerCallStatusProvider(),
139
142
  subAgentOutputRootDirectory: null,
140
143
  subAgentProcessMatchPattern: null,
141
144
  subAgentTranscriptRootDirectory: null,
@@ -189,6 +192,32 @@ describe('notifySilentTmuxSessions', () => {
189
192
  expect(secondSendCall?.[1][4]).toContain('No output has been observed for');
190
193
  });
191
194
 
195
+ it('decides from the owner call status provider it was given', async () => {
196
+ silentAssistantTranscript();
197
+ seedPreviousCandidates([SESSION_NAME]);
198
+ const runner = liveSessionRunner();
199
+ const consultedSessionNames: string[] = [];
200
+ const injectedProvider: OwnerCallStatusProvider = {
201
+ listUnansweredOwnerCallEpochSecondsBySessionName: (
202
+ transcriptPathBySessionName: Map<string, string>,
203
+ ): Promise<Map<string, number>> => {
204
+ consultedSessionNames.push(...transcriptPathBySessionName.keys());
205
+ return Promise.resolve(new Map([[SESSION_NAME, NOW_EPOCH_SECONDS]]));
206
+ },
207
+ };
208
+
209
+ await notifySilentTmuxSessions({
210
+ ...baseParams(runner),
211
+ ownerCallStatusProvider: injectedProvider,
212
+ });
213
+
214
+ expect(consultedSessionNames).toContain(SESSION_NAME);
215
+ const sendCall = runner.runCommand.mock.calls.find(
216
+ (call) => call[0] === 'tmux' && call[1][0] === 'send-keys',
217
+ );
218
+ expect(sendCall).toBeUndefined();
219
+ });
220
+
192
221
  it('does not notify a silent github-named live session on its first candidate cycle', async () => {
193
222
  silentAssistantTranscript();
194
223
  const runner = liveSessionRunner();
@@ -323,7 +352,9 @@ describe('notifySilentTmuxSessions', () => {
323
352
 
324
353
  await notifySilentTmuxSessions({
325
354
  ...baseParams(runner),
326
- ownerCallMarker: '<<OWNER_CALL>>',
355
+ ownerCallStatusProvider: new TranscriptOwnerCallStatusProvider(
356
+ '<<OWNER_CALL>>',
357
+ ),
327
358
  });
328
359
 
329
360
  const sendCall = runner.runCommand.mock.calls.find(
@@ -359,7 +390,9 @@ describe('notifySilentTmuxSessions', () => {
359
390
 
360
391
  await notifySilentTmuxSessions({
361
392
  ...baseParams(runner),
362
- ownerCallMarker: '<<OWNER_CALL>>',
393
+ ownerCallStatusProvider: new TranscriptOwnerCallStatusProvider(
394
+ '<<OWNER_CALL>>',
395
+ ),
363
396
  });
364
397
 
365
398
  const sendCall = runner.runCommand.mock.calls.find(
@@ -23,8 +23,6 @@ import {
23
23
  DEFAULT_SUBMIT_PUSH_OUT_WAIT_MILLISECONDS,
24
24
  TmuxSilentSessionNotificationRepository,
25
25
  } from '../../repositories/TmuxSilentSessionNotificationRepository';
26
- import { NoUnansweredOwnerCallStatusProvider } from '../../repositories/NoUnansweredOwnerCallStatusProvider';
27
- import { TranscriptOwnerCallStatusProvider } from '../../repositories/TranscriptOwnerCallStatusProvider';
28
26
  import { TranscriptRefusalTailStatusProvider } from '../../repositories/TranscriptRefusalTailStatusProvider';
29
27
  import { ProcessListSessionSubAgentActivityRepository } from '../../repositories/ProcessListSessionSubAgentActivityRepository';
30
28
  import { TranscriptSessionSubAgentActivityRepository } from '../../repositories/TranscriptSessionSubAgentActivityRepository';
@@ -44,8 +42,7 @@ export type NotifySilentTmuxSessionsParams = {
44
42
  enabled: boolean;
45
43
  localCommandRunner: LocalCommandRunner;
46
44
  processEnvironReader?: ProcessEnvironReader;
47
- ownerCallMarker: string | null;
48
- ownerReplyMarkerDirectory?: string | null;
45
+ ownerCallStatusProvider: OwnerCallStatusProvider;
49
46
  subAgentOutputRootDirectory: string | null;
50
47
  subAgentProcessMatchPattern: string | null;
51
48
  subAgentTranscriptRootDirectory: string | null;
@@ -66,19 +63,6 @@ export type NotifySilentTmuxSessionsParams = {
66
63
  now: Date;
67
64
  };
68
65
 
69
- const createOwnerCallStatusProvider = (
70
- ownerCallMarker: string | null,
71
- ownerReplyMarkerDirectory: string | null,
72
- ): OwnerCallStatusProvider => {
73
- if (ownerCallMarker !== null && ownerCallMarker.length > 0) {
74
- return new TranscriptOwnerCallStatusProvider(
75
- ownerCallMarker,
76
- ownerReplyMarkerDirectory,
77
- );
78
- }
79
- return new NoUnansweredOwnerCallStatusProvider();
80
- };
81
-
82
66
  const createSubAgentActivityRepository = (
83
67
  subAgentTranscriptRootDirectory: string | null,
84
68
  subAgentRuntimeRootDirectory: string | null,
@@ -114,7 +98,7 @@ export const notifySilentTmuxSessions = async (
114
98
  enabled,
115
99
  localCommandRunner,
116
100
  processEnvironReader,
117
- ownerCallMarker,
101
+ ownerCallStatusProvider,
118
102
  subAgentOutputRootDirectory,
119
103
  subAgentProcessMatchPattern,
120
104
  subAgentTranscriptRootDirectory,
@@ -159,10 +143,7 @@ export const notifySilentTmuxSessions = async (
159
143
  localCommandRunner,
160
144
  now,
161
145
  ),
162
- createOwnerCallStatusProvider(
163
- ownerCallMarker,
164
- params.ownerReplyMarkerDirectory ?? null,
165
- ),
146
+ ownerCallStatusProvider,
166
147
  new TmuxSilentSessionNotificationRepository(
167
148
  localCommandRunner,
168
149
  new RealSleeper(),
@@ -0,0 +1,111 @@
1
+ import { resolveUnansweredOwnerCallsByTmuxSessionName } from './resolveUnansweredOwnerCalls';
2
+ import { UnansweredOwnerCall } from '../../../domain/entities/UnansweredOwnerCall';
3
+ import { InteractiveLiveSession } from '../../../domain/entities/InteractiveLiveSession';
4
+ import { LiveSessionProcessSnapshot } from '../../../domain/entities/LiveSessionProcessSnapshot';
5
+ import { toTmuxSessionName } from '../../../domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase';
6
+
7
+ const ISSUE_URL = 'https://github.com/demo/repo/issues/1';
8
+ const TMUX_SESSION_NAME = toTmuxSessionName(ISSUE_URL);
9
+ const CONFIG_DIR = '/home/agent/.claude';
10
+ const SESSION_ID = 'session-id-1';
11
+
12
+ const snapshotWithSession = (): LiveSessionProcessSnapshot => ({
13
+ sessions: [{ sessionName: TMUX_SESSION_NAME, panePids: [100] }],
14
+ processes: [
15
+ {
16
+ pid: 100,
17
+ ppid: 1,
18
+ commandLine: `claude ${ISSUE_URL}`,
19
+ sessionId: SESSION_ID,
20
+ currentSessionId: SESSION_ID,
21
+ configDir: CONFIG_DIR,
22
+ },
23
+ ],
24
+ });
25
+
26
+ describe('resolveUnansweredOwnerCallsByTmuxSessionName', () => {
27
+ it('asks the call provider for the transcripts of the live interactive sessions and returns what it reports', async () => {
28
+ const call: UnansweredOwnerCall = {
29
+ calledAt: '2026-08-13T10:14:00.000Z',
30
+ body: 'Please decide whether to merge the release branch',
31
+ };
32
+ const requestedTranscriptPaths: Map<string, string>[] = [];
33
+ const resolvedSessions: InteractiveLiveSession[][] = [];
34
+
35
+ const result = await resolveUnansweredOwnerCallsByTmuxSessionName({
36
+ liveSessionProcessSnapshotProvider: {
37
+ getSnapshot: async () => snapshotWithSession(),
38
+ },
39
+ interactiveLiveSessionTranscriptResolver: {
40
+ resolveTranscriptPaths: (sessions) => {
41
+ resolvedSessions.push(sessions);
42
+ return new Map(
43
+ sessions.map((session) => [
44
+ session.sessionName,
45
+ `/transcripts/${session.sessionId}.jsonl`,
46
+ ]),
47
+ );
48
+ },
49
+ },
50
+ unansweredOwnerCallListProvider: {
51
+ listUnansweredOwnerCallsBySessionName: async (
52
+ transcriptPathBySessionName,
53
+ ) => {
54
+ requestedTranscriptPaths.push(transcriptPathBySessionName);
55
+ return new Map([[TMUX_SESSION_NAME, [call]]]);
56
+ },
57
+ },
58
+ });
59
+
60
+ expect(resolvedSessions[0]?.map((session) => session.sessionName)).toEqual([
61
+ TMUX_SESSION_NAME,
62
+ ]);
63
+ expect(requestedTranscriptPaths[0]?.get(TMUX_SESSION_NAME)).toBe(
64
+ `/transcripts/${SESSION_ID}.jsonl`,
65
+ );
66
+ expect(result.get(TMUX_SESSION_NAME)).toEqual([call]);
67
+ });
68
+
69
+ it('keys the returned calls by the tmux session name the reconciler derives from the issue url', async () => {
70
+ const result = await resolveUnansweredOwnerCallsByTmuxSessionName({
71
+ liveSessionProcessSnapshotProvider: {
72
+ getSnapshot: async () => snapshotWithSession(),
73
+ },
74
+ interactiveLiveSessionTranscriptResolver: {
75
+ resolveTranscriptPaths: (sessions) =>
76
+ new Map(
77
+ sessions.map((session) => [session.sessionName, '/transcript']),
78
+ ),
79
+ },
80
+ unansweredOwnerCallListProvider: {
81
+ listUnansweredOwnerCallsBySessionName: async (
82
+ transcriptPathBySessionName,
83
+ ) =>
84
+ new Map(
85
+ [...transcriptPathBySessionName.keys()].map((sessionName) => [
86
+ sessionName,
87
+ [{ calledAt: '2026-08-13T10:14:00.000Z', body: 'body' }],
88
+ ]),
89
+ ),
90
+ },
91
+ });
92
+
93
+ expect([...result.keys()]).toEqual([toTmuxSessionName(ISSUE_URL)]);
94
+ });
95
+
96
+ it('returns nothing when no live session exposes a transcript', async () => {
97
+ const result = await resolveUnansweredOwnerCallsByTmuxSessionName({
98
+ liveSessionProcessSnapshotProvider: {
99
+ getSnapshot: async () => ({ sessions: [], processes: [] }),
100
+ },
101
+ interactiveLiveSessionTranscriptResolver: {
102
+ resolveTranscriptPaths: () => new Map(),
103
+ },
104
+ unansweredOwnerCallListProvider: {
105
+ listUnansweredOwnerCallsBySessionName: async () => new Map(),
106
+ },
107
+ });
108
+
109
+ expect(result.size).toBe(0);
110
+ });
111
+ });
@@ -0,0 +1,33 @@
1
+ import { UnansweredOwnerCall } from '../../../domain/entities/UnansweredOwnerCall';
2
+ import { InteractiveLiveSession } from '../../../domain/entities/InteractiveLiveSession';
3
+ import { ResolveInteractiveLiveSessionsUseCase } from '../../../domain/usecases/ResolveInteractiveLiveSessionsUseCase';
4
+ import { LiveSessionProcessSnapshotProvider } from '../../../domain/usecases/adapter-interfaces/LiveSessionProcessSnapshotProvider';
5
+ import { InteractiveLiveSessionTranscriptResolver } from '../../../domain/usecases/adapter-interfaces/InteractiveLiveSessionTranscriptResolver';
6
+
7
+ export type UnansweredOwnerCallListProvider = {
8
+ listUnansweredOwnerCallsBySessionName: (
9
+ transcriptPathBySessionName: Map<string, string>,
10
+ ) => Promise<Map<string, UnansweredOwnerCall[]>>;
11
+ };
12
+
13
+ export type ResolveUnansweredOwnerCallsParams = {
14
+ liveSessionProcessSnapshotProvider: LiveSessionProcessSnapshotProvider;
15
+ interactiveLiveSessionTranscriptResolver: InteractiveLiveSessionTranscriptResolver;
16
+ unansweredOwnerCallListProvider: UnansweredOwnerCallListProvider;
17
+ };
18
+
19
+ export const resolveUnansweredOwnerCallsByTmuxSessionName = async (
20
+ params: ResolveUnansweredOwnerCallsParams,
21
+ ): Promise<Map<string, UnansweredOwnerCall[]>> => {
22
+ const snapshot =
23
+ await params.liveSessionProcessSnapshotProvider.getSnapshot();
24
+ const interactiveSessions: InteractiveLiveSession[] =
25
+ new ResolveInteractiveLiveSessionsUseCase().resolve(snapshot);
26
+ const transcriptPathBySessionName =
27
+ params.interactiveLiveSessionTranscriptResolver.resolveTranscriptPaths(
28
+ interactiveSessions,
29
+ );
30
+ return params.unansweredOwnerCallListProvider.listUnansweredOwnerCallsBySessionName(
31
+ transcriptPathBySessionName,
32
+ );
33
+ };