github-issue-tower-defence-management 2.6.0 → 2.6.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 (23) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js +2 -1
  3. package/bin/adapter/entry-points/handlers/tokenExhaustionHandover.js.map +1 -1
  4. package/bin/adapter/repositories/GitHubIssueCheckpointRepository.js +37 -0
  5. package/bin/adapter/repositories/GitHubIssueCheckpointRepository.js.map +1 -0
  6. package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js +10 -2
  7. package/bin/domain/usecases/TokenExhaustionHandoverUseCase.js.map +1 -1
  8. package/bin/domain/usecases/adapter-interfaces/IssueCheckpointRepository.js +3 -0
  9. package/bin/domain/usecases/adapter-interfaces/IssueCheckpointRepository.js.map +1 -0
  10. package/package.json +1 -1
  11. package/src/adapter/entry-points/handlers/tokenExhaustionHandover.ts +2 -0
  12. package/src/adapter/repositories/GitHubIssueCheckpointRepository.test.ts +51 -0
  13. package/src/adapter/repositories/GitHubIssueCheckpointRepository.ts +47 -0
  14. package/src/domain/usecases/TokenExhaustionHandoverUseCase.test.ts +87 -3
  15. package/src/domain/usecases/TokenExhaustionHandoverUseCase.ts +14 -1
  16. package/src/domain/usecases/adapter-interfaces/IssueCheckpointRepository.ts +3 -0
  17. package/types/adapter/entry-points/handlers/tokenExhaustionHandover.d.ts.map +1 -1
  18. package/types/adapter/repositories/GitHubIssueCheckpointRepository.d.ts +8 -0
  19. package/types/adapter/repositories/GitHubIssueCheckpointRepository.d.ts.map +1 -0
  20. package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts +3 -1
  21. package/types/domain/usecases/TokenExhaustionHandoverUseCase.d.ts.map +1 -1
  22. package/types/domain/usecases/adapter-interfaces/IssueCheckpointRepository.d.ts +4 -0
  23. package/types/domain/usecases/adapter-interfaces/IssueCheckpointRepository.d.ts.map +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.6.1](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v2.6.0...v2.6.1) (2026-08-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **token-exhaustion:** post checkpoint comment on task issue before SIGTERMing impl subagent ([#1858](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1858)) ([9e6d05a](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/commit/9e6d05abaf3e55060d6dc56a3fdd778b198c4f17)), closes [#1823](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/1823)
7
+
1
8
  # [2.6.0](https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/compare/v2.5.1...v2.6.0) (2026-08-29)
2
9
 
3
10
 
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleTokenExhaustionHandover = void 0;
4
4
  const TokenExhaustionHandoverUseCase_1 = require("../../../domain/usecases/TokenExhaustionHandoverUseCase");
5
+ const GitHubIssueCheckpointRepository_1 = require("../../repositories/GitHubIssueCheckpointRepository");
5
6
  const NodeTmuxSessionRepository_1 = require("../../repositories/NodeTmuxSessionRepository");
6
7
  const RateLimitSnapshotRepository_1 = require("../../repositories/RateLimitSnapshotRepository");
7
8
  const ProcClaudeHandoverSessionRepository_1 = require("../../repositories/ProcClaudeHandoverSessionRepository");
@@ -15,7 +16,7 @@ const handleTokenExhaustionHandover = async (params) => {
15
16
  }
16
17
  const snapshotRepository = new RateLimitSnapshotRepository_1.RateLimitSnapshotRepository(tokenListJsonPath, tokenRateLimitSnapshotBaseDir ?? undefined);
17
18
  const stateRepository = new FileHandoverStateRepository_1.FileHandoverStateRepository(stateFilePath ?? (0, FileHandoverStateRepository_1.defaultHandoverStateFilePath)());
18
- const useCase = new TokenExhaustionHandoverUseCase_1.TokenExhaustionHandoverUseCase(new ProcClaudeHandoverSessionRepository_1.ProcClaudeHandoverSessionRepository(), snapshotRepository, new NodeTmuxSessionRepository_1.NodeTmuxSessionRepository(localCommandRunner), new NodeProcessSignalRepository_1.NodeProcessSignalRepository());
19
+ const useCase = new TokenExhaustionHandoverUseCase_1.TokenExhaustionHandoverUseCase(new ProcClaudeHandoverSessionRepository_1.ProcClaudeHandoverSessionRepository(), snapshotRepository, new NodeTmuxSessionRepository_1.NodeTmuxSessionRepository(localCommandRunner), new NodeProcessSignalRepository_1.NodeProcessSignalRepository(), new GitHubIssueCheckpointRepository_1.GitHubIssueCheckpointRepository(process.env.GH_TOKEN ?? ''));
19
20
  const result = await useCase.run({
20
21
  enabled,
21
22
  issueUrlLeaderMessage: handoverMessage ?? TokenExhaustionHandoverUseCase_1.DEFAULT_TOKEN_EXHAUSTION_HANDOVER_MESSAGE,
@@ -1 +1 @@
1
- {"version":3,"file":"tokenExhaustionHandover.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenExhaustionHandover.ts"],"names":[],"mappings":";;;AACA,4GAKiE;AACjE,4FAAyF;AACzF,gGAA6F;AAC7F,gHAA6G;AAC7G,gGAA6F;AAC7F,gGAGwD;AAcjD,MAAM,6BAA6B,GAAG,KAAK,EAChD,MAAqC,EACtB,EAAE;IACjB,MAAM,EACJ,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,6BAA6B,EAC7B,6BAA6B,EAC7B,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,GAAG,GACJ,GAAG,MAAM,CAAC;IAEX,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CACT,sFAAsF,CACvF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,kBAAkB,GAAG,IAAI,yDAA2B,CACxD,iBAAiB,EACjB,6BAA6B,IAAI,SAAS,CAC3C,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,yDAA2B,CACrD,aAAa,IAAI,IAAA,0DAA4B,GAAE,CAChD,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,+DAA8B,CAChD,IAAI,yEAAmC,EAAE,EACzC,kBAAkB,EAClB,IAAI,qDAAyB,CAAC,kBAAkB,CAAC,EACjD,IAAI,yDAA2B,EAAE,CAClC,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC/B,OAAO;QACP,qBAAqB,EACnB,eAAe,IAAI,0EAAyC;QAC9D,qBAAqB,EACnB,6BAA6B;YAC7B,2FAA0D;QAC5D,kBAAkB,EAChB,kBAAkB,IAAI,8EAA6C;QACrE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE;QAC7B,GAAG;KACJ,CAAC,CAAC;IAEH,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC,CAAC;AAlDW,QAAA,6BAA6B,iCAkDxC"}
1
+ {"version":3,"file":"tokenExhaustionHandover.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenExhaustionHandover.ts"],"names":[],"mappings":";;;AACA,4GAKiE;AACjE,wGAAqG;AACrG,4FAAyF;AACzF,gGAA6F;AAC7F,gHAA6G;AAC7G,gGAA6F;AAC7F,gGAGwD;AAcjD,MAAM,6BAA6B,GAAG,KAAK,EAChD,MAAqC,EACtB,EAAE;IACjB,MAAM,EACJ,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,6BAA6B,EAC7B,6BAA6B,EAC7B,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,GAAG,GACJ,GAAG,MAAM,CAAC;IAEX,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CACT,sFAAsF,CACvF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,kBAAkB,GAAG,IAAI,yDAA2B,CACxD,iBAAiB,EACjB,6BAA6B,IAAI,SAAS,CAC3C,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,yDAA2B,CACrD,aAAa,IAAI,IAAA,0DAA4B,GAAE,CAChD,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,+DAA8B,CAChD,IAAI,yEAAmC,EAAE,EACzC,kBAAkB,EAClB,IAAI,qDAAyB,CAAC,kBAAkB,CAAC,EACjD,IAAI,yDAA2B,EAAE,EACjC,IAAI,iEAA+B,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAChE,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC/B,OAAO;QACP,qBAAqB,EACnB,eAAe,IAAI,0EAAyC;QAC9D,qBAAqB,EACnB,6BAA6B;YAC7B,2FAA0D;QAC5D,kBAAkB,EAChB,kBAAkB,IAAI,8EAA6C;QACrE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE;QAC7B,GAAG;KACJ,CAAC,CAAC;IAEH,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC,CAAC;AAnDW,QAAA,6BAA6B,iCAmDxC"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubIssueCheckpointRepository = void 0;
4
+ const CHECKPOINT_COMMENT_BODY = 'From: :robot: preparation-daemon (-)\n\n```json\n{"pullRequestRequired": false}\n```\n\nThis implementation session was interrupted by the preparation daemon due to token near exhaustion. The task will be re-dispatched.';
5
+ class GitHubIssueCheckpointRepository {
6
+ constructor(ghToken) {
7
+ this.ghToken = ghToken;
8
+ this.postCheckpoint = async (issueUrl) => {
9
+ const { owner, repo, issueNumber } = this.parseIssueUrl(issueUrl);
10
+ const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}/comments`, {
11
+ method: 'POST',
12
+ headers: {
13
+ Authorization: `Bearer ${this.ghToken}`,
14
+ Accept: 'application/vnd.github+json',
15
+ 'Content-Type': 'application/json',
16
+ },
17
+ body: JSON.stringify({ body: CHECKPOINT_COMMENT_BODY }),
18
+ });
19
+ if (!response.ok) {
20
+ throw new Error(`Failed to post checkpoint comment to ${issueUrl}: ${response.status} ${response.statusText}`);
21
+ }
22
+ };
23
+ this.parseIssueUrl = (issueUrl) => {
24
+ const match = issueUrl.match(/github\.com\/([^/]+)\/([^/]+)\/(issues|pull)\/(\d+)/);
25
+ if (!match) {
26
+ throw new Error(`Invalid GitHub issue URL: ${issueUrl}`);
27
+ }
28
+ return {
29
+ owner: match[1],
30
+ repo: match[2],
31
+ issueNumber: parseInt(match[4], 10),
32
+ };
33
+ };
34
+ }
35
+ }
36
+ exports.GitHubIssueCheckpointRepository = GitHubIssueCheckpointRepository;
37
+ //# sourceMappingURL=GitHubIssueCheckpointRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubIssueCheckpointRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/GitHubIssueCheckpointRepository.ts"],"names":[],"mappings":";;;AAEA,MAAM,uBAAuB,GAC3B,6NAA6N,CAAC;AAEhO,MAAa,+BAA+B;IAC1C,YAA6B,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;QAE5C,mBAAc,GAAG,KAAK,EAAE,QAAgB,EAAiB,EAAE;YACzD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAElE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,gCAAgC,KAAK,IAAI,IAAI,WAAW,WAAW,WAAW,EAC9E;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE;oBACvC,MAAM,EAAE,6BAA6B;oBACrC,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;aACxD,CACF,CAAC;YAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CACb,wCAAwC,QAAQ,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAC9F,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;QAEM,kBAAa,GAAG,CACtB,QAAgB,EACsC,EAAE;YACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAC1B,qDAAqD,CACtD,CAAC;YACF,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;YAC3D,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;gBACf,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;gBACd,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;aACpC,CAAC;QACJ,CAAC,CAAC;IAvC6C,CAAC;CAwCjD;AAzCD,0EAyCC"}
@@ -11,11 +11,12 @@ exports.TOKEN_EXHAUSTION_SEVEN_DAY_FREE_THRESHOLD = 0.05;
11
11
  exports.TOKEN_EXHAUSTION_FIVE_HOUR_WARNING_FREE_THRESHOLD = 0.25;
12
12
  exports.TOKEN_EXHAUSTION_SEVEN_DAY_WARNING_FREE_THRESHOLD = 0.15;
13
13
  class TokenExhaustionHandoverUseCase {
14
- constructor(handoverSessionRepository, snapshotRepository, tmuxSessionRepository, processSignalRepository) {
14
+ constructor(handoverSessionRepository, snapshotRepository, tmuxSessionRepository, processSignalRepository, issueCheckpointRepository) {
15
15
  this.handoverSessionRepository = handoverSessionRepository;
16
16
  this.snapshotRepository = snapshotRepository;
17
17
  this.tmuxSessionRepository = tmuxSessionRepository;
18
18
  this.processSignalRepository = processSignalRepository;
19
+ this.issueCheckpointRepository = issueCheckpointRepository;
19
20
  this.run = async (input) => {
20
21
  const nowEpochSeconds = Math.floor(input.now.getTime() / 1000);
21
22
  const sessions = this.handoverSessionRepository.listHandoverSessions();
@@ -130,7 +131,13 @@ class TokenExhaustionHandoverUseCase {
130
131
  };
131
132
  this.sendHandover = async (session, input) => {
132
133
  if (session.kind === 'implSubagent') {
133
- this.processSignalRepository.terminateProcess(session.pid);
134
+ if (session.issueUrl !== null) {
135
+ await this.issueCheckpointRepository.postCheckpoint(session.issueUrl);
136
+ }
137
+ else {
138
+ console.log(`Token exhaustion handover: sending SIGTERM to impl subagent pid=${session.pid} (no issue URL, cannot post checkpoint)`);
139
+ this.processSignalRepository.terminateProcess(session.pid);
140
+ }
134
141
  return;
135
142
  }
136
143
  if (session.sessionName === null) {
@@ -143,6 +150,7 @@ class TokenExhaustionHandoverUseCase {
143
150
  };
144
151
  this.forceKill = async (session, entry) => {
145
152
  if (session.kind === 'implSubagent') {
153
+ this.processSignalRepository.terminateProcess(entry.pid);
146
154
  this.processSignalRepository.killProcess(entry.pid);
147
155
  return;
148
156
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TokenExhaustionHandoverUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/TokenExhaustionHandoverUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TokenExhaustionHandoverUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/TokenExhaustionHandoverUseCase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IssueCheckpointRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IssueCheckpointRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/IssueCheckpointRepository.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -5,6 +5,7 @@ import {
5
5
  DEFAULT_TOKEN_EXHAUSTION_HANDOVER_MESSAGE_BARE_NAME_LEADER,
6
6
  DEFAULT_TOKEN_EXHAUSTION_GRACE_PERIOD_SECONDS,
7
7
  } from '../../../domain/usecases/TokenExhaustionHandoverUseCase';
8
+ import { GitHubIssueCheckpointRepository } from '../../repositories/GitHubIssueCheckpointRepository';
8
9
  import { NodeTmuxSessionRepository } from '../../repositories/NodeTmuxSessionRepository';
9
10
  import { RateLimitSnapshotRepository } from '../../repositories/RateLimitSnapshotRepository';
10
11
  import { ProcClaudeHandoverSessionRepository } from '../../repositories/ProcClaudeHandoverSessionRepository';
@@ -60,6 +61,7 @@ export const handleTokenExhaustionHandover = async (
60
61
  snapshotRepository,
61
62
  new NodeTmuxSessionRepository(localCommandRunner),
62
63
  new NodeProcessSignalRepository(),
64
+ new GitHubIssueCheckpointRepository(process.env.GH_TOKEN ?? ''),
63
65
  );
64
66
 
65
67
  const result = await useCase.run({
@@ -0,0 +1,51 @@
1
+ import { GitHubIssueCheckpointRepository } from './GitHubIssueCheckpointRepository';
2
+
3
+ const VALID_URL = 'https://github.com/owner/repo/issues/42';
4
+ const EXPECTED_API_URL =
5
+ 'https://api.github.com/repos/owner/repo/issues/42/comments';
6
+ const EXPECTED_BODY = JSON.stringify({
7
+ body: 'From: :robot: preparation-daemon (-)\n\n```json\n{"pullRequestRequired": false}\n```\n\nThis implementation session was interrupted by the preparation daemon due to token near exhaustion. The task will be re-dispatched.',
8
+ });
9
+
10
+ describe('GitHubIssueCheckpointRepository', () => {
11
+ let repository: GitHubIssueCheckpointRepository;
12
+
13
+ beforeEach(() => {
14
+ jest.restoreAllMocks();
15
+ repository = new GitHubIssueCheckpointRepository('test-token');
16
+ });
17
+
18
+ it('posts to the correct GitHub API URL with correct headers and body', async () => {
19
+ const fetchSpy = jest
20
+ .spyOn(global, 'fetch')
21
+ .mockResolvedValue(new Response('{}', { status: 201 }));
22
+
23
+ await repository.postCheckpoint(VALID_URL);
24
+
25
+ expect(fetchSpy).toHaveBeenCalledWith(EXPECTED_API_URL, {
26
+ method: 'POST',
27
+ headers: {
28
+ Authorization: 'Bearer test-token',
29
+ Accept: 'application/vnd.github+json',
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ body: EXPECTED_BODY,
33
+ });
34
+ });
35
+
36
+ it('throws when the response is not 2xx', async () => {
37
+ jest
38
+ .spyOn(global, 'fetch')
39
+ .mockResolvedValue(
40
+ new Response('Forbidden', { status: 403, statusText: 'Forbidden' }),
41
+ );
42
+
43
+ await expect(repository.postCheckpoint(VALID_URL)).rejects.toThrow('403');
44
+ });
45
+
46
+ it('throws when the URL does not match the expected GitHub issue pattern', async () => {
47
+ await expect(
48
+ repository.postCheckpoint('https://example.com/not-an-issue'),
49
+ ).rejects.toThrow('Invalid GitHub issue URL');
50
+ });
51
+ });
@@ -0,0 +1,47 @@
1
+ import { IssueCheckpointRepository } from '../../domain/usecases/adapter-interfaces/IssueCheckpointRepository';
2
+
3
+ const CHECKPOINT_COMMENT_BODY =
4
+ 'From: :robot: preparation-daemon (-)\n\n```json\n{"pullRequestRequired": false}\n```\n\nThis implementation session was interrupted by the preparation daemon due to token near exhaustion. The task will be re-dispatched.';
5
+
6
+ export class GitHubIssueCheckpointRepository implements IssueCheckpointRepository {
7
+ constructor(private readonly ghToken: string) {}
8
+
9
+ postCheckpoint = async (issueUrl: string): Promise<void> => {
10
+ const { owner, repo, issueNumber } = this.parseIssueUrl(issueUrl);
11
+
12
+ const response = await fetch(
13
+ `https://api.github.com/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
14
+ {
15
+ method: 'POST',
16
+ headers: {
17
+ Authorization: `Bearer ${this.ghToken}`,
18
+ Accept: 'application/vnd.github+json',
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ body: JSON.stringify({ body: CHECKPOINT_COMMENT_BODY }),
22
+ },
23
+ );
24
+
25
+ if (!response.ok) {
26
+ throw new Error(
27
+ `Failed to post checkpoint comment to ${issueUrl}: ${response.status} ${response.statusText}`,
28
+ );
29
+ }
30
+ };
31
+
32
+ private parseIssueUrl = (
33
+ issueUrl: string,
34
+ ): { owner: string; repo: string; issueNumber: number } => {
35
+ const match = issueUrl.match(
36
+ /github\.com\/([^/]+)\/([^/]+)\/(issues|pull)\/(\d+)/,
37
+ );
38
+ if (!match) {
39
+ throw new Error(`Invalid GitHub issue URL: ${issueUrl}`);
40
+ }
41
+ return {
42
+ owner: match[1],
43
+ repo: match[2],
44
+ issueNumber: parseInt(match[4], 10),
45
+ };
46
+ };
47
+ }
@@ -9,6 +9,7 @@ import {
9
9
  import { ClaudeHandoverSession } from '../entities/ClaudeHandoverSession';
10
10
  import { TokenExhaustionHandoverState } from '../entities/TokenExhaustionHandoverState';
11
11
  import { ClaudeHandoverSessionRepository } from './adapter-interfaces/ClaudeHandoverSessionRepository';
12
+ import { IssueCheckpointRepository } from './adapter-interfaces/IssueCheckpointRepository';
12
13
  import { ProcessSignalRepository } from './adapter-interfaces/ProcessSignalRepository';
13
14
  import { TmuxSessionRepository } from './adapter-interfaces/TmuxSessionRepository';
14
15
  import {
@@ -121,6 +122,9 @@ describe('TokenExhaustionHandoverUseCase', () => {
121
122
  >
122
123
  >;
123
124
  let processSignalRepository: Mocked<ProcessSignalRepository>;
125
+ let issueCheckpointRepository: Mocked<
126
+ Pick<IssueCheckpointRepository, 'postCheckpoint'>
127
+ >;
124
128
 
125
129
  const exhaustedFiveHour = (): TokenModelWeeklyLimit[] => [];
126
130
 
@@ -146,12 +150,16 @@ describe('TokenExhaustionHandoverUseCase', () => {
146
150
  terminateProcess: jest.fn(),
147
151
  killProcess: jest.fn(),
148
152
  };
153
+ issueCheckpointRepository = {
154
+ postCheckpoint: jest.fn().mockResolvedValue(undefined),
155
+ };
149
156
 
150
157
  useCase = new TokenExhaustionHandoverUseCase(
151
158
  handoverSessionRepository,
152
159
  snapshotRepository,
153
160
  tmuxSessionRepository,
154
161
  processSignalRepository,
162
+ issueCheckpointRepository,
155
163
  );
156
164
  });
157
165
 
@@ -330,7 +338,7 @@ describe('TokenExhaustionHandoverUseCase', () => {
330
338
  );
331
339
  });
332
340
 
333
- it('sends SIGTERM to an impl subagent on first detection', async () => {
341
+ it('posts a checkpoint comment to the task issue on first detection of an impl subagent with a known issue URL', async () => {
334
342
  handoverSessionRepository.listHandoverSessions.mockReturnValue([
335
343
  implSubagentSession(),
336
344
  ]);
@@ -341,10 +349,78 @@ describe('TokenExhaustionHandoverUseCase', () => {
341
349
 
342
350
  const result = await useCase.run(defaultInput());
343
351
 
352
+ expect(issueCheckpointRepository.postCheckpoint).toHaveBeenCalledWith(
353
+ ISSUE_URL,
354
+ );
355
+ expect(processSignalRepository.terminateProcess).not.toHaveBeenCalled();
356
+ expect(tmuxSessionRepository.sendKeys).not.toHaveBeenCalled();
357
+ expect(result.state.entries[`pid:${IMPL_PID}`]).toEqual({
358
+ signaledAtEpoch: nowEpochSeconds,
359
+ pid: IMPL_PID,
360
+ });
361
+ });
362
+
363
+ it('sends SIGTERM immediately when the impl subagent has no issue URL', async () => {
364
+ const noUrlSession: ClaudeHandoverSession = {
365
+ ...implSubagentSession(),
366
+ issueUrl: null,
367
+ };
368
+ handoverSessionRepository.listHandoverSessions.mockReturnValue([
369
+ noUrlSession,
370
+ ]);
371
+ snapshotRepository.listSnapshots.mockReturnValue([
372
+ snapshot(TOKEN_EXHAUSTED, { fiveHourUtilization: 0.95 }),
373
+ snapshot(TOKEN_FRESH),
374
+ ]);
375
+ const logSpy = jest.spyOn(console, 'log');
376
+
377
+ const result = await useCase.run(defaultInput());
378
+
344
379
  expect(processSignalRepository.terminateProcess).toHaveBeenCalledWith(
345
380
  IMPL_PID,
346
381
  );
347
- expect(tmuxSessionRepository.sendKeys).not.toHaveBeenCalled();
382
+ expect(issueCheckpointRepository.postCheckpoint).not.toHaveBeenCalled();
383
+ expect(logSpy).toHaveBeenCalledWith(
384
+ expect.stringContaining('no issue URL'),
385
+ );
386
+ expect(result.state.entries[`pid:${IMPL_PID}`]).toEqual({
387
+ signaledAtEpoch: nowEpochSeconds,
388
+ pid: IMPL_PID,
389
+ });
390
+ });
391
+
392
+ it('does not create a state entry when postCheckpoint throws, so the next cycle retries', async () => {
393
+ handoverSessionRepository.listHandoverSessions.mockReturnValue([
394
+ implSubagentSession(),
395
+ ]);
396
+ snapshotRepository.listSnapshots.mockReturnValue([
397
+ snapshot(TOKEN_EXHAUSTED, { fiveHourUtilization: 0.95 }),
398
+ snapshot(TOKEN_FRESH),
399
+ ]);
400
+ issueCheckpointRepository.postCheckpoint.mockRejectedValue(
401
+ new Error('network error'),
402
+ );
403
+
404
+ const result = await useCase.run(defaultInput());
405
+
406
+ expect(result.state.entries[`pid:${IMPL_PID}`]).toBeUndefined();
407
+ expect(result.newlyHandoverSentSessionNames).toEqual([]);
408
+ });
409
+
410
+ it('creates a state entry after postCheckpoint succeeds', async () => {
411
+ handoverSessionRepository.listHandoverSessions.mockReturnValue([
412
+ implSubagentSession(),
413
+ ]);
414
+ snapshotRepository.listSnapshots.mockReturnValue([
415
+ snapshot(TOKEN_EXHAUSTED, { fiveHourUtilization: 0.95 }),
416
+ snapshot(TOKEN_FRESH),
417
+ ]);
418
+
419
+ const result = await useCase.run(defaultInput());
420
+
421
+ expect(issueCheckpointRepository.postCheckpoint).toHaveBeenCalledWith(
422
+ ISSUE_URL,
423
+ );
348
424
  expect(result.state.entries[`pid:${IMPL_PID}`]).toEqual({
349
425
  signaledAtEpoch: nowEpochSeconds,
350
426
  pid: IMPL_PID,
@@ -521,7 +597,7 @@ describe('TokenExhaustionHandoverUseCase', () => {
521
597
  expect(result.killedSessionNames).toEqual([BARE_NAME]);
522
598
  });
523
599
 
524
- it('SIGKILLs an impl subagent that is still alive after the grace period', async () => {
600
+ it('SIGTERMs then SIGKILLs an impl subagent that is still alive after the grace period', async () => {
525
601
  handoverSessionRepository.listHandoverSessions.mockReturnValue([
526
602
  implSubagentSession(),
527
603
  ]);
@@ -547,6 +623,14 @@ describe('TokenExhaustionHandoverUseCase', () => {
547
623
  }),
548
624
  );
549
625
 
626
+ const terminateOrder =
627
+ processSignalRepository.terminateProcess.mock.invocationCallOrder[0];
628
+ const killOrder =
629
+ processSignalRepository.killProcess.mock.invocationCallOrder[0];
630
+ expect(terminateOrder).toBeLessThan(killOrder);
631
+ expect(processSignalRepository.terminateProcess).toHaveBeenCalledWith(
632
+ IMPL_PID,
633
+ );
550
634
  expect(processSignalRepository.killProcess).toHaveBeenCalledWith(IMPL_PID);
551
635
  expect(result.terminatedPids).toEqual([IMPL_PID]);
552
636
  });
@@ -4,6 +4,7 @@ import {
4
4
  TokenExhaustionHandoverStateEntry,
5
5
  } from '../entities/TokenExhaustionHandoverState';
6
6
  import { ClaudeHandoverSessionRepository } from './adapter-interfaces/ClaudeHandoverSessionRepository';
7
+ import { IssueCheckpointRepository } from './adapter-interfaces/IssueCheckpointRepository';
7
8
  import { ProcessSignalRepository } from './adapter-interfaces/ProcessSignalRepository';
8
9
  import { TmuxSessionRepository } from './adapter-interfaces/TmuxSessionRepository';
9
10
  import {
@@ -73,6 +74,10 @@ export class TokenExhaustionHandoverUseCase {
73
74
  | 'launchBareNameLeaderSession'
74
75
  >,
75
76
  private readonly processSignalRepository: ProcessSignalRepository,
77
+ private readonly issueCheckpointRepository: Pick<
78
+ IssueCheckpointRepository,
79
+ 'postCheckpoint'
80
+ >,
76
81
  ) {}
77
82
 
78
83
  run = async (
@@ -245,7 +250,14 @@ export class TokenExhaustionHandoverUseCase {
245
250
  input: TokenExhaustionHandoverInput,
246
251
  ): Promise<void> => {
247
252
  if (session.kind === 'implSubagent') {
248
- this.processSignalRepository.terminateProcess(session.pid);
253
+ if (session.issueUrl !== null) {
254
+ await this.issueCheckpointRepository.postCheckpoint(session.issueUrl);
255
+ } else {
256
+ console.log(
257
+ `Token exhaustion handover: sending SIGTERM to impl subagent pid=${session.pid} (no issue URL, cannot post checkpoint)`,
258
+ );
259
+ this.processSignalRepository.terminateProcess(session.pid);
260
+ }
249
261
  return;
250
262
  }
251
263
  if (session.sessionName === null) {
@@ -263,6 +275,7 @@ export class TokenExhaustionHandoverUseCase {
263
275
  entry: TokenExhaustionHandoverStateEntry,
264
276
  ): Promise<void> => {
265
277
  if (session.kind === 'implSubagent') {
278
+ this.processSignalRepository.terminateProcess(entry.pid);
266
279
  this.processSignalRepository.killProcess(entry.pid);
267
280
  return;
268
281
  }
@@ -0,0 +1,3 @@
1
+ export interface IssueCheckpointRepository {
2
+ postCheckpoint(issueUrl: string): Promise<void>;
3
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"tokenExhaustionHandover.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenExhaustionHandover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAgBpG,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,QAAQ,6BAA6B,KACpC,OAAO,CAAC,IAAI,CAgDd,CAAC"}
1
+ {"version":3,"file":"tokenExhaustionHandover.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/tokenExhaustionHandover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gEAAgE,CAAC;AAiBpG,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,QAAQ,6BAA6B,KACpC,OAAO,CAAC,IAAI,CAiDd,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { IssueCheckpointRepository } from '../../domain/usecases/adapter-interfaces/IssueCheckpointRepository';
2
+ export declare class GitHubIssueCheckpointRepository implements IssueCheckpointRepository {
3
+ private readonly ghToken;
4
+ constructor(ghToken: string);
5
+ postCheckpoint: (issueUrl: string) => Promise<void>;
6
+ private parseIssueUrl;
7
+ }
8
+ //# sourceMappingURL=GitHubIssueCheckpointRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubIssueCheckpointRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/GitHubIssueCheckpointRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,oEAAoE,CAAC;AAK/G,qBAAa,+BAAgC,YAAW,yBAAyB;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAE5C,cAAc,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAqBtD;IAEF,OAAO,CAAC,aAAa,CAcnB;CACH"}
@@ -1,5 +1,6 @@
1
1
  import { TokenExhaustionHandoverState } from '../entities/TokenExhaustionHandoverState';
2
2
  import { ClaudeHandoverSessionRepository } from './adapter-interfaces/ClaudeHandoverSessionRepository';
3
+ import { IssueCheckpointRepository } from './adapter-interfaces/IssueCheckpointRepository';
3
4
  import { ProcessSignalRepository } from './adapter-interfaces/ProcessSignalRepository';
4
5
  import { TmuxSessionRepository } from './adapter-interfaces/TmuxSessionRepository';
5
6
  import { TokenRateLimitSnapshotRepository } from './adapter-interfaces/TokenRateLimitSnapshotRepository';
@@ -34,7 +35,8 @@ export declare class TokenExhaustionHandoverUseCase {
34
35
  private readonly snapshotRepository;
35
36
  private readonly tmuxSessionRepository;
36
37
  private readonly processSignalRepository;
37
- constructor(handoverSessionRepository: Pick<ClaudeHandoverSessionRepository, 'listHandoverSessions'>, snapshotRepository: Pick<TokenRateLimitSnapshotRepository, 'listSnapshots'>, tmuxSessionRepository: Pick<TmuxSessionRepository, 'sendKeys' | 'killSession' | 'listLiveSessionNames' | 'launchBareNameLeaderSession'>, processSignalRepository: ProcessSignalRepository);
38
+ private readonly issueCheckpointRepository;
39
+ constructor(handoverSessionRepository: Pick<ClaudeHandoverSessionRepository, 'listHandoverSessions'>, snapshotRepository: Pick<TokenRateLimitSnapshotRepository, 'listSnapshots'>, tmuxSessionRepository: Pick<TmuxSessionRepository, 'sendKeys' | 'killSession' | 'listLiveSessionNames' | 'launchBareNameLeaderSession'>, processSignalRepository: ProcessSignalRepository, issueCheckpointRepository: Pick<IssueCheckpointRepository, 'postCheckpoint'>);
38
40
  run: (input: TokenExhaustionHandoverInput) => Promise<TokenExhaustionHandoverResult>;
39
41
  private needsRelaunch;
40
42
  private relaunchBareNameLeader;
@@ -1 +1 @@
1
- {"version":3,"file":"TokenExhaustionHandoverUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/TokenExhaustionHandoverUseCase.ts"],"names":[],"mappings":"AACA,OAAO,EACL,4BAA4B,EAE7B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAGL,gCAAgC,EACjC,MAAM,uDAAuD,CAAC;AAE/D,eAAO,MAAM,yCAAyC,ubACgY,CAAC;AAEvb,eAAO,MAAM,0DAA0D,yjBACif,CAAC;AAEzjB,eAAO,MAAM,6CAA6C,MAAM,CAAC;AACjE,eAAO,MAAM,iDAAiD,MAAM,CAAC;AACrE,eAAO,MAAM,sDAAsD,OAAO,CAAC;AAC3E,eAAO,MAAM,yCAAyC,MAAM,CAAC;AAC7D,eAAO,MAAM,yCAAyC,OAAO,CAAC;AAC9D,eAAO,MAAM,iDAAiD,OAAO,CAAC;AACtE,eAAO,MAAM,iDAAiD,OAAO,CAAC;AAYtE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,4BAA4B,CAAC;IACpC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,6BAA6B,EAAE,MAAM,EAAE,CAAC;IACxC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,uCAAuC,EAAE,MAAM,EAAE,CAAC;IAClD,KAAK,EAAE,4BAA4B,CAAC;CACrC,CAAC;AAEF,qBAAa,8BAA8B;IAEvC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAI1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAInC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAOtC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;gBAfvB,yBAAyB,EAAE,IAAI,CAC9C,+BAA+B,EAC/B,sBAAsB,CACvB,EACgB,kBAAkB,EAAE,IAAI,CACvC,gCAAgC,EAChC,eAAe,CAChB,EACgB,qBAAqB,EAAE,IAAI,CAC1C,qBAAqB,EACnB,UAAU,GACV,aAAa,GACb,sBAAsB,GACtB,6BAA6B,CAChC,EACgB,uBAAuB,EAAE,uBAAuB;IAGnE,GAAG,GACD,OAAO,4BAA4B,KAClC,OAAO,CAAC,6BAA6B,CAAC,CAmJvC;IAEF,OAAO,CAAC,aAAa,CACwC;IAE7D,OAAO,CAAC,sBAAsB,CAS5B;IAEF,OAAO,CAAC,YAAY,CAgBlB;IAEF,OAAO,CAAC,SAAS,CAoBf;IAEF,OAAO,CAAC,WAAW,CAGiC;IAEpD,OAAO,CAAC,WAAW,CAC2B;IAE9C,OAAO,CAAC,uBAAuB,CAe7B;IAEF,OAAO,CAAC,gBAAgB,CAgFtB;IAEF,OAAO,CAAC,SAAS,CASf;IAEF,OAAO,CAAC,OAAO,CAQb;IAEF,OAAO,CAAC,cAAc,CAcpB;CACH"}
1
+ {"version":3,"file":"TokenExhaustionHandoverUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/TokenExhaustionHandoverUseCase.ts"],"names":[],"mappings":"AACA,OAAO,EACL,4BAA4B,EAE7B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AACvG,OAAO,EAAE,yBAAyB,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAGL,gCAAgC,EACjC,MAAM,uDAAuD,CAAC;AAE/D,eAAO,MAAM,yCAAyC,ubACgY,CAAC;AAEvb,eAAO,MAAM,0DAA0D,yjBACif,CAAC;AAEzjB,eAAO,MAAM,6CAA6C,MAAM,CAAC;AACjE,eAAO,MAAM,iDAAiD,MAAM,CAAC;AACrE,eAAO,MAAM,sDAAsD,OAAO,CAAC;AAC3E,eAAO,MAAM,yCAAyC,MAAM,CAAC;AAC7D,eAAO,MAAM,yCAAyC,OAAO,CAAC;AAC9D,eAAO,MAAM,iDAAiD,OAAO,CAAC;AACtE,eAAO,MAAM,iDAAiD,OAAO,CAAC;AAYtE,MAAM,MAAM,4BAA4B,GAAG;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,4BAA4B,CAAC;IACpC,GAAG,EAAE,IAAI,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,6BAA6B,EAAE,MAAM,EAAE,CAAC;IACxC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,uCAAuC,EAAE,MAAM,EAAE,CAAC;IAClD,KAAK,EAAE,4BAA4B,CAAC;CACrC,CAAC;AAEF,qBAAa,8BAA8B;IAEvC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;IAI1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAInC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAOtC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,yBAAyB;gBAhBzB,yBAAyB,EAAE,IAAI,CAC9C,+BAA+B,EAC/B,sBAAsB,CACvB,EACgB,kBAAkB,EAAE,IAAI,CACvC,gCAAgC,EAChC,eAAe,CAChB,EACgB,qBAAqB,EAAE,IAAI,CAC1C,qBAAqB,EACnB,UAAU,GACV,aAAa,GACb,sBAAsB,GACtB,6BAA6B,CAChC,EACgB,uBAAuB,EAAE,uBAAuB,EAChD,yBAAyB,EAAE,IAAI,CAC9C,yBAAyB,EACzB,gBAAgB,CACjB;IAGH,GAAG,GACD,OAAO,4BAA4B,KAClC,OAAO,CAAC,6BAA6B,CAAC,CAmJvC;IAEF,OAAO,CAAC,aAAa,CACwC;IAE7D,OAAO,CAAC,sBAAsB,CAS5B;IAEF,OAAO,CAAC,YAAY,CAuBlB;IAEF,OAAO,CAAC,SAAS,CAqBf;IAEF,OAAO,CAAC,WAAW,CAGiC;IAEpD,OAAO,CAAC,WAAW,CAC2B;IAE9C,OAAO,CAAC,uBAAuB,CAe7B;IAEF,OAAO,CAAC,gBAAgB,CAgFtB;IAEF,OAAO,CAAC,SAAS,CASf;IAEF,OAAO,CAAC,OAAO,CAQb;IAEF,OAAO,CAAC,cAAc,CAcpB;CACH"}
@@ -0,0 +1,4 @@
1
+ export interface IssueCheckpointRepository {
2
+ postCheckpoint(issueUrl: string): Promise<void>;
3
+ }
4
+ //# sourceMappingURL=IssueCheckpointRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IssueCheckpointRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/IssueCheckpointRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD"}