github-issue-tower-defence-management 1.95.0 → 1.97.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/.github/workflows/console-ui.yml +17 -0
- package/CHANGELOG.md +14 -0
- package/README.md +20 -0
- package/bin/adapter/entry-points/cli/index.js +21 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-BeJzGnfH.js → index-B3F4E8LD.js} +33 -33
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +18 -2
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js +77 -0
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js.map +1 -0
- package/bin/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.js +19 -0
- package/bin/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.js.map +1 -0
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js +44 -0
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -0
- package/bin/adapter/repositories/ProcClaudeLiveSessionRepository.js +139 -0
- package/bin/adapter/repositories/ProcClaudeLiveSessionRepository.js.map +1 -0
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js +59 -0
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.js.map +1 -0
- package/bin/domain/usecases/adapter-interfaces/TmuxSessionRepository.js +3 -0
- package/bin/domain/usecases/adapter-interfaces/TmuxSessionRepository.js.map +1 -0
- package/bin/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.js +41 -0
- package/bin/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.js.map +1 -0
- package/package.json +4 -1
- package/src/adapter/entry-points/cli/index.ts +38 -0
- package/src/adapter/entry-points/console/ui/biome.json +7 -1
- package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +93 -0
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +380 -0
- package/src/adapter/entry-points/console/ui/e2e/playwright.config.ts +30 -0
- package/src/adapter/entry-points/console/ui/e2e/tsconfig.json +18 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +2 -4
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +5 -6
- package/src/adapter/entry-points/console/ui-dist/assets/{index-BeJzGnfH.js → index-B3F4E8LD.js} +33 -33
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +17 -0
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.test.ts +268 -0
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts +116 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.test.ts +123 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.ts +29 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +100 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.ts +53 -0
- package/src/adapter/repositories/ProcClaudeLiveSessionRepository.test.ts +146 -0
- package/src/adapter/repositories/ProcClaudeLiveSessionRepository.ts +119 -0
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.test.ts +147 -0
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts +100 -0
- package/src/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.ts +8 -0
- package/src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts +9 -0
- package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.test.ts +186 -0
- package/src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.ts +75 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts +20 -0
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts.map +1 -0
- package/types/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.d.ts +10 -0
- package/types/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.d.ts.map +1 -0
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +10 -0
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -0
- package/types/adapter/repositories/ProcClaudeLiveSessionRepository.d.ts +11 -0
- package/types/adapter/repositories/ProcClaudeLiveSessionRepository.d.ts.map +1 -0
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts +23 -0
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.d.ts +8 -0
- package/types/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.d.ts.map +1 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts +6 -0
- package/types/domain/usecases/adapter-interfaces/TmuxSessionRepository.d.ts.map +1 -0
- package/types/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.d.ts +19 -0
- package/types/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.d.ts.map +1 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { Issue } from '../../entities/Issue';
|
|
2
|
+
import { IN_TMUX_STATUS_NAME } from '../../entities/WorkflowStatus';
|
|
3
|
+
import { TmuxSessionRepository } from '../adapter-interfaces/TmuxSessionRepository';
|
|
4
|
+
import {
|
|
5
|
+
InTmuxByHumanSessionReconcileUseCase,
|
|
6
|
+
toTmuxSessionName,
|
|
7
|
+
} from './InTmuxByHumanSessionReconcileUseCase';
|
|
8
|
+
|
|
9
|
+
const ASSIGNEE = 'owner-login';
|
|
10
|
+
const LAUNCHER = 'cl';
|
|
11
|
+
|
|
12
|
+
let issueCounter = 0;
|
|
13
|
+
const makeIssue = (overrides: Partial<Issue> = {}): Issue => {
|
|
14
|
+
issueCounter += 1;
|
|
15
|
+
return {
|
|
16
|
+
nameWithOwner: 'demo/repo',
|
|
17
|
+
number: issueCounter,
|
|
18
|
+
title: `Issue ${issueCounter}`,
|
|
19
|
+
state: 'OPEN',
|
|
20
|
+
status: IN_TMUX_STATUS_NAME,
|
|
21
|
+
story: null,
|
|
22
|
+
nextActionDate: null,
|
|
23
|
+
nextActionHour: null,
|
|
24
|
+
estimationMinutes: null,
|
|
25
|
+
dependedIssueUrls: [],
|
|
26
|
+
completionDate50PercentConfidence: null,
|
|
27
|
+
url: `https://github.com/demo/repo/issues/${issueCounter}`,
|
|
28
|
+
assignees: [ASSIGNEE],
|
|
29
|
+
labels: [],
|
|
30
|
+
org: 'demo',
|
|
31
|
+
repo: 'repo',
|
|
32
|
+
body: '',
|
|
33
|
+
itemId: `item-${issueCounter}`,
|
|
34
|
+
isPr: false,
|
|
35
|
+
isInProgress: false,
|
|
36
|
+
isClosed: false,
|
|
37
|
+
createdAt: new Date(),
|
|
38
|
+
author: '',
|
|
39
|
+
...overrides,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const createFakeTmuxSessionRepository = (state: {
|
|
44
|
+
liveSessionNames: string[];
|
|
45
|
+
processCommandLines: string[];
|
|
46
|
+
}): TmuxSessionRepository & {
|
|
47
|
+
launches: {
|
|
48
|
+
sessionName: string;
|
|
49
|
+
launcherCommand: string;
|
|
50
|
+
issueUrl: string;
|
|
51
|
+
}[];
|
|
52
|
+
} => {
|
|
53
|
+
const launches: {
|
|
54
|
+
sessionName: string;
|
|
55
|
+
launcherCommand: string;
|
|
56
|
+
issueUrl: string;
|
|
57
|
+
}[] = [];
|
|
58
|
+
return {
|
|
59
|
+
launches,
|
|
60
|
+
listLiveSessionNames: async () => state.liveSessionNames,
|
|
61
|
+
listInteractiveProcessCommandLines: async () => state.processCommandLines,
|
|
62
|
+
launchDetachedSession: async (sessionName, launcherCommand, issueUrl) => {
|
|
63
|
+
launches.push({ sessionName, launcherCommand, issueUrl });
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
describe('InTmuxByHumanSessionReconcileUseCase', () => {
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
issueCounter = 0;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('launches a detached session for an In Tmux by human issue with no live session', async () => {
|
|
74
|
+
const issue = makeIssue();
|
|
75
|
+
const repository = createFakeTmuxSessionRepository({
|
|
76
|
+
liveSessionNames: [],
|
|
77
|
+
processCommandLines: [],
|
|
78
|
+
});
|
|
79
|
+
const useCase = new InTmuxByHumanSessionReconcileUseCase(repository);
|
|
80
|
+
|
|
81
|
+
const result = await useCase.run({
|
|
82
|
+
issues: [issue],
|
|
83
|
+
assigneeLogin: ASSIGNEE,
|
|
84
|
+
launcherCommand: LAUNCHER,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(repository.launches).toEqual([
|
|
88
|
+
{
|
|
89
|
+
sessionName: toTmuxSessionName(issue.url),
|
|
90
|
+
launcherCommand: LAUNCHER,
|
|
91
|
+
issueUrl: issue.url,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
expect(result.launchedIssueUrls).toEqual([issue.url]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('does not launch when a live session already exists for the issue', async () => {
|
|
98
|
+
const issue = makeIssue();
|
|
99
|
+
const repository = createFakeTmuxSessionRepository({
|
|
100
|
+
liveSessionNames: [toTmuxSessionName(issue.url)],
|
|
101
|
+
processCommandLines: [
|
|
102
|
+
`claude --model opus --agent leader --name ${issue.url}`,
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
const useCase = new InTmuxByHumanSessionReconcileUseCase(repository);
|
|
106
|
+
|
|
107
|
+
const result = await useCase.run({
|
|
108
|
+
issues: [issue],
|
|
109
|
+
assigneeLogin: ASSIGNEE,
|
|
110
|
+
launcherCommand: LAUNCHER,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(repository.launches).toEqual([]);
|
|
114
|
+
expect(result.launchedIssueUrls).toEqual([]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('treats a session as missing when the tmux session exists but no process advertises the issue url', async () => {
|
|
118
|
+
const issue = makeIssue();
|
|
119
|
+
const repository = createFakeTmuxSessionRepository({
|
|
120
|
+
liveSessionNames: [toTmuxSessionName(issue.url)],
|
|
121
|
+
processCommandLines: ['claude --model opus --name some-other-task'],
|
|
122
|
+
});
|
|
123
|
+
const useCase = new InTmuxByHumanSessionReconcileUseCase(repository);
|
|
124
|
+
|
|
125
|
+
const result = await useCase.run({
|
|
126
|
+
issues: [issue],
|
|
127
|
+
assigneeLogin: ASSIGNEE,
|
|
128
|
+
launcherCommand: LAUNCHER,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(repository.launches).toHaveLength(1);
|
|
132
|
+
expect(result.launchedIssueUrls).toEqual([issue.url]);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('launches only the missing sessions across multiple In Tmux by human issues', async () => {
|
|
136
|
+
const liveIssue = makeIssue();
|
|
137
|
+
const missingIssueOne = makeIssue();
|
|
138
|
+
const missingIssueTwo = makeIssue();
|
|
139
|
+
const repository = createFakeTmuxSessionRepository({
|
|
140
|
+
liveSessionNames: [toTmuxSessionName(liveIssue.url)],
|
|
141
|
+
processCommandLines: [`claude --model opus --name ${liveIssue.url}`],
|
|
142
|
+
});
|
|
143
|
+
const useCase = new InTmuxByHumanSessionReconcileUseCase(repository);
|
|
144
|
+
|
|
145
|
+
const result = await useCase.run({
|
|
146
|
+
issues: [liveIssue, missingIssueOne, missingIssueTwo],
|
|
147
|
+
assigneeLogin: ASSIGNEE,
|
|
148
|
+
launcherCommand: LAUNCHER,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(result.launchedIssueUrls).toEqual([
|
|
152
|
+
missingIssueOne.url,
|
|
153
|
+
missingIssueTwo.url,
|
|
154
|
+
]);
|
|
155
|
+
expect(repository.launches.map((launch) => launch.issueUrl)).toEqual([
|
|
156
|
+
missingIssueOne.url,
|
|
157
|
+
missingIssueTwo.url,
|
|
158
|
+
]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('ignores issues that are not In Tmux by human, closed, or assigned to another login', async () => {
|
|
162
|
+
const otherStatusIssue = makeIssue({ status: 'Done' });
|
|
163
|
+
const closedIssue = makeIssue({ isClosed: true });
|
|
164
|
+
const otherAssigneeIssue = makeIssue({ assignees: ['someone-else'] });
|
|
165
|
+
const repository = createFakeTmuxSessionRepository({
|
|
166
|
+
liveSessionNames: [],
|
|
167
|
+
processCommandLines: [],
|
|
168
|
+
});
|
|
169
|
+
const useCase = new InTmuxByHumanSessionReconcileUseCase(repository);
|
|
170
|
+
|
|
171
|
+
const result = await useCase.run({
|
|
172
|
+
issues: [otherStatusIssue, closedIssue, otherAssigneeIssue],
|
|
173
|
+
assigneeLogin: ASSIGNEE,
|
|
174
|
+
launcherCommand: LAUNCHER,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(repository.launches).toEqual([]);
|
|
178
|
+
expect(result.launchedIssueUrls).toEqual([]);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('transforms an issue url into a tmux session name by replacing non-alphanumeric characters', () => {
|
|
182
|
+
expect(toTmuxSessionName('https://github.com/demo/repo/issues/42')).toBe(
|
|
183
|
+
'https___github_com_demo_repo_issues_42',
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Issue } from '../../entities/Issue';
|
|
2
|
+
import { IN_TMUX_STATUS_NAME } from '../../entities/WorkflowStatus';
|
|
3
|
+
import { TmuxSessionRepository } from '../adapter-interfaces/TmuxSessionRepository';
|
|
4
|
+
|
|
5
|
+
export type InTmuxByHumanSessionReconcileInput = {
|
|
6
|
+
issues: Issue[];
|
|
7
|
+
assigneeLogin: string;
|
|
8
|
+
launcherCommand: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type InTmuxByHumanSessionReconcileResult = {
|
|
12
|
+
launchedIssueUrls: string[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const toTmuxSessionName = (issueUrl: string): string =>
|
|
16
|
+
issueUrl.replace(/[^a-zA-Z0-9]/g, '_');
|
|
17
|
+
|
|
18
|
+
export class InTmuxByHumanSessionReconcileUseCase {
|
|
19
|
+
constructor(private readonly tmuxSessionRepository: TmuxSessionRepository) {}
|
|
20
|
+
|
|
21
|
+
run = async (
|
|
22
|
+
input: InTmuxByHumanSessionReconcileInput,
|
|
23
|
+
): Promise<InTmuxByHumanSessionReconcileResult> => {
|
|
24
|
+
const { issues, assigneeLogin, launcherCommand } = input;
|
|
25
|
+
|
|
26
|
+
const targetIssues = issues.filter((issue) =>
|
|
27
|
+
this.isInTmuxByHuman(issue, assigneeLogin),
|
|
28
|
+
);
|
|
29
|
+
if (targetIssues.length === 0) {
|
|
30
|
+
return { launchedIssueUrls: [] };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const liveSessionNames = new Set(
|
|
34
|
+
await this.tmuxSessionRepository.listLiveSessionNames(),
|
|
35
|
+
);
|
|
36
|
+
const processCommandLines =
|
|
37
|
+
await this.tmuxSessionRepository.listInteractiveProcessCommandLines();
|
|
38
|
+
|
|
39
|
+
const launchedIssueUrls: string[] = [];
|
|
40
|
+
for (const issue of targetIssues) {
|
|
41
|
+
if (
|
|
42
|
+
this.hasLiveSession(issue.url, liveSessionNames, processCommandLines)
|
|
43
|
+
) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
await this.tmuxSessionRepository.launchDetachedSession(
|
|
47
|
+
toTmuxSessionName(issue.url),
|
|
48
|
+
launcherCommand,
|
|
49
|
+
issue.url,
|
|
50
|
+
);
|
|
51
|
+
launchedIssueUrls.push(issue.url);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { launchedIssueUrls };
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
private isInTmuxByHuman = (issue: Issue, assigneeLogin: string): boolean =>
|
|
58
|
+
issue.status === IN_TMUX_STATUS_NAME &&
|
|
59
|
+
issue.isClosed === false &&
|
|
60
|
+
issue.assignees.includes(assigneeLogin);
|
|
61
|
+
|
|
62
|
+
private hasLiveSession = (
|
|
63
|
+
issueUrl: string,
|
|
64
|
+
liveSessionNames: Set<string>,
|
|
65
|
+
processCommandLines: string[],
|
|
66
|
+
): boolean => {
|
|
67
|
+
const sessionName = toTmuxSessionName(issueUrl);
|
|
68
|
+
if (!liveSessionNames.has(sessionName)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return processCommandLines.some((commandLine) =>
|
|
72
|
+
commandLine.includes(issueUrl),
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAwGzB,eAAO,MAAM,OAAO,SAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HandleScheduledEventUseCaseHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts"],"names":[],"mappings":"AA0BA,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,CA4WP;CACH"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ClaudeLiveSessionRepository } from '../../../domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
+
import { LiveSessionOauthTokenSelectUseCase } from '../../../domain/usecases/LiveSessionOauthTokenSelectUseCase';
|
|
3
|
+
export type LiveSessionOauthTokenSelectHandlerInput = {
|
|
4
|
+
tokenListJsonPath: string | null;
|
|
5
|
+
cacheDirectory: string | null;
|
|
6
|
+
nowEpochSeconds: number;
|
|
7
|
+
};
|
|
8
|
+
export type LiveSessionOauthTokenSelectHandlerOutput = {
|
|
9
|
+
selectedToken: string | null;
|
|
10
|
+
selectedName: string | null;
|
|
11
|
+
diagnostics: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare class LiveSessionOauthTokenSelectHandler {
|
|
14
|
+
private readonly useCase;
|
|
15
|
+
private readonly liveSessionRepository;
|
|
16
|
+
constructor(useCase?: LiveSessionOauthTokenSelectUseCase, liveSessionRepository?: ClaudeLiveSessionRepository);
|
|
17
|
+
handle: (input: LiveSessionOauthTokenSelectHandlerInput) => LiveSessionOauthTokenSelectHandlerOutput;
|
|
18
|
+
private formatDiagnostics;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=LiveSessionOauthTokenSelectHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAEL,kCAAkC,EACnC,MAAM,6DAA6D,CAAC;AAUrE,MAAM,MAAM,uCAAuC,GAAG;IACpD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,wCAAwC,GAAG;IACrD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBADrB,OAAO,GAAE,kCAA6E,EACtF,qBAAqB,GAAE,2BAAmE;IAG7G,MAAM,GACJ,OAAO,uCAAuC,KAC7C,wCAAwC,CAuDzC;IAEF,OAAO,CAAC,iBAAiB,CAuBvB;CACH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Issue } from '../../../domain/entities/Issue';
|
|
2
|
+
import { LocalCommandRunner } from '../../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
3
|
+
export type ReconcileInTmuxByHumanSessionsParams = {
|
|
4
|
+
inTmuxLauncherCommand: string | null;
|
|
5
|
+
assigneeLogin: string;
|
|
6
|
+
issues: Issue[];
|
|
7
|
+
localCommandRunner: LocalCommandRunner;
|
|
8
|
+
};
|
|
9
|
+
export declare const reconcileInTmuxByHumanSessions: (params: ReconcileInTmuxByHumanSessionsParams) => Promise<void>;
|
|
10
|
+
//# sourceMappingURL=inTmuxByHumanSessionReconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inTmuxByHumanSessionReconciler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/inTmuxByHumanSessionReconciler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAIpG,MAAM,MAAM,oCAAoC,GAAG;IACjD,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,QAAQ,oCAAoC,KAC3C,OAAO,CAAC,IAAI,CAcd,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { LocalCommandRunner } from '../../domain/usecases/adapter-interfaces/LocalCommandRunner';
|
|
2
|
+
import { TmuxSessionRepository } from '../../domain/usecases/adapter-interfaces/TmuxSessionRepository';
|
|
3
|
+
export declare class NodeTmuxSessionRepository implements TmuxSessionRepository {
|
|
4
|
+
private readonly localCommandRunner;
|
|
5
|
+
constructor(localCommandRunner: LocalCommandRunner);
|
|
6
|
+
listLiveSessionNames: () => Promise<string[]>;
|
|
7
|
+
listInteractiveProcessCommandLines: () => Promise<string[]>;
|
|
8
|
+
launchDetachedSession: (sessionName: string, launcherCommand: string, issueUrl: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=NodeTmuxSessionRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeTmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeTmuxSessionRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AAEvG,qBAAa,yBAA0B,YAAW,qBAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,kBAAkB;IAEnE,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAYhD;IAEF,kCAAkC,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAY9D;IAEF,qBAAqB,GACnB,aAAa,MAAM,EACnB,iBAAiB,MAAM,EACvB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAad;CACH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ClaudeLiveSession, ClaudeLiveSessionRepository } from '../../domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
+
export declare class ProcClaudeLiveSessionRepository implements ClaudeLiveSessionRepository {
|
|
3
|
+
private readonly procDirectory;
|
|
4
|
+
constructor(procDirectory?: string);
|
|
5
|
+
listLiveSessions: () => ClaudeLiveSession[];
|
|
6
|
+
private listProcessIdDirectories;
|
|
7
|
+
private readLiveSession;
|
|
8
|
+
private isClaudeProcess;
|
|
9
|
+
private readEnviron;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=ProcClaudeLiveSessionRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcClaudeLiveSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/ProcClaudeLiveSessionRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,sEAAsE,CAAC;AAiB9E,qBAAa,+BAAgC,YAAW,2BAA2B;IAE/E,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,GAAE,MAA+B;IAGjE,gBAAgB,QAAO,iBAAiB,EAAE,CASxC;IAEF,OAAO,CAAC,wBAAwB,CAQ9B;IAEF,OAAO,CAAC,eAAe,CAqBrB;IAEF,OAAO,CAAC,eAAe,CAgBrB;IAEF,OAAO,CAAC,WAAW,CA4BjB;CACH"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ClaudeLiveSession } from './adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
+
import { OauthTokenCandidate, OauthTokenSelectUseCase } from './OauthTokenSelectUseCase';
|
|
3
|
+
export type LiveSessionOauthTokenCandidateMetrics = {
|
|
4
|
+
name: string;
|
|
5
|
+
fiveHourFreeRatio: number;
|
|
6
|
+
sevenDayFreeRatio: number;
|
|
7
|
+
sevenDayEndEpoch: number;
|
|
8
|
+
liveSessionCount: number;
|
|
9
|
+
eligible: boolean;
|
|
10
|
+
exclusionReason: string | null;
|
|
11
|
+
};
|
|
12
|
+
export type LiveSessionOauthTokenSelectResult = {
|
|
13
|
+
selected: OauthTokenCandidate | null;
|
|
14
|
+
metrics: LiveSessionOauthTokenCandidateMetrics[];
|
|
15
|
+
};
|
|
16
|
+
export declare class LiveSessionOauthTokenSelectUseCase {
|
|
17
|
+
private readonly rateLimitSelectUseCase;
|
|
18
|
+
constructor(rateLimitSelectUseCase?: OauthTokenSelectUseCase);
|
|
19
|
+
run: (candidates: OauthTokenCandidate[], liveSessions: ClaudeLiveSession[], nowEpochSeconds: number) => LiveSessionOauthTokenSelectResult;
|
|
20
|
+
private preferred;
|
|
21
|
+
private liveSessionCountByToken;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=LiveSessionOauthTokenSelectUseCase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACrF,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,qCAAqC,EAAE,CAAC;CAClD,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBAAtB,sBAAsB,GAAE,uBAAuD;IAGlG,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,cAAc,iBAAiB,EAAE,EACjC,iBAAiB,MAAM,KACtB,iCAAiC,CAuClC;IAEF,OAAO,CAAC,SAAS,CAUf;IAEF,OAAO,CAAC,uBAAuB,CAe7B;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaudeLiveSessionRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/ClaudeLiveSessionRepository.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,2BAA2B;IAC1C,gBAAgB,EAAE,MAAM,iBAAiB,EAAE,CAAC;CAC7C"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface TmuxSessionRepository {
|
|
2
|
+
listLiveSessionNames: () => Promise<string[]>;
|
|
3
|
+
listInteractiveProcessCommandLines: () => Promise<string[]>;
|
|
4
|
+
launchDetachedSession: (sessionName: string, launcherCommand: string, issueUrl: string) => Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=TmuxSessionRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/TmuxSessionRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,kCAAkC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D,qBAAqB,EAAE,CACrB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Issue } from '../../entities/Issue';
|
|
2
|
+
import { TmuxSessionRepository } from '../adapter-interfaces/TmuxSessionRepository';
|
|
3
|
+
export type InTmuxByHumanSessionReconcileInput = {
|
|
4
|
+
issues: Issue[];
|
|
5
|
+
assigneeLogin: string;
|
|
6
|
+
launcherCommand: string;
|
|
7
|
+
};
|
|
8
|
+
export type InTmuxByHumanSessionReconcileResult = {
|
|
9
|
+
launchedIssueUrls: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare const toTmuxSessionName: (issueUrl: string) => string;
|
|
12
|
+
export declare class InTmuxByHumanSessionReconcileUseCase {
|
|
13
|
+
private readonly tmuxSessionRepository;
|
|
14
|
+
constructor(tmuxSessionRepository: TmuxSessionRepository);
|
|
15
|
+
run: (input: InTmuxByHumanSessionReconcileInput) => Promise<InTmuxByHumanSessionReconcileResult>;
|
|
16
|
+
private isInTmuxByHuman;
|
|
17
|
+
private hasLiveSession;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=InTmuxByHumanSessionReconcileUseCase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InTmuxByHumanSessionReconcileUseCase.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/intmux/InTmuxByHumanSessionReconcileUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AAEpF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mCAAmC,GAAG;IAChD,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,MACb,CAAC;AAEzC,qBAAa,oCAAoC;IACnC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBAArB,qBAAqB,EAAE,qBAAqB;IAEzE,GAAG,GACD,OAAO,kCAAkC,KACxC,OAAO,CAAC,mCAAmC,CAAC,CAgC7C;IAEF,OAAO,CAAC,eAAe,CAGmB;IAE1C,OAAO,CAAC,cAAc,CAYpB;CACH"}
|