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.
- package/CHANGELOG.md +19 -0
- package/README.md +9 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +32 -9
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js +13 -1
- package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js.map +1 -1
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js +2 -10
- package/bin/adapter/entry-points/handlers/notifySilentTmuxSessions.js.map +1 -1
- package/bin/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.js +12 -0
- package/bin/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.js.map +1 -0
- package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js +72 -14
- package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js.map +1 -1
- package/bin/domain/entities/UnansweredOwnerCall.js +3 -0
- package/bin/domain/entities/UnansweredOwnerCall.js.map +1 -0
- package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js +21 -2
- package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +58 -14
- package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.test.ts +104 -1
- package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.ts +19 -0
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +36 -3
- package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.ts +3 -22
- package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.test.ts +111 -0
- package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.ts +33 -0
- package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.singleScan.test.ts +88 -0
- package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.test.ts +178 -0
- package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts +122 -22
- package/src/domain/entities/UnansweredOwnerCall.ts +4 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +99 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts +47 -1
- package/src/domain/usecases/intmux/UnansweredOwnerCallSessionKeyContract.test.ts +141 -0
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts +2 -0
- package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts +2 -2
- package/types/adapter/entry-points/handlers/notifySilentTmuxSessions.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.d.ts +13 -0
- package/types/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.d.ts.map +1 -0
- package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts +7 -0
- package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts.map +1 -1
- package/types/domain/entities/UnansweredOwnerCall.d.ts +5 -0
- package/types/domain/entities/UnansweredOwnerCall.d.ts.map +1 -0
- package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts +19 -0
- 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":";;;
|
|
1
|
+
{"version":3,"file":"GenerateInTmuxByHumanDataUseCase.js","sourceRoot":"","sources":["../../../../src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
};
|