github-issue-tower-defence-management 1.59.0 → 1.60.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 (46) hide show
  1. package/.github/workflows/create-pr.yml +1 -1
  2. package/.github/workflows/test.yml +4 -0
  3. package/.github/workflows/umino-project.yml +3 -3
  4. package/CHANGELOG.md +14 -0
  5. package/bin/adapter/proxy/ClaudeMessageResponseParser.js +123 -0
  6. package/bin/adapter/proxy/ClaudeMessageResponseParser.js.map +1 -0
  7. package/bin/adapter/proxy/proxyEntry.js +16 -3
  8. package/bin/adapter/proxy/proxyEntry.js.map +1 -1
  9. package/bin/adapter/repositories/SqliteClaudeMessageResponseRepository.js +186 -0
  10. package/bin/adapter/repositories/SqliteClaudeMessageResponseRepository.js.map +1 -0
  11. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +14 -0
  12. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  13. package/bin/domain/entities/ClaudeMessageResponse.js +3 -0
  14. package/bin/domain/entities/ClaudeMessageResponse.js.map +1 -0
  15. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +18 -11
  16. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
  17. package/bin/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.js +3 -0
  18. package/bin/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.js.map +1 -0
  19. package/package.json +3 -1
  20. package/src/adapter/proxy/ClaudeMessageResponseParser.test.ts +211 -0
  21. package/src/adapter/proxy/ClaudeMessageResponseParser.ts +180 -0
  22. package/src/adapter/proxy/proxyEntry.ts +28 -3
  23. package/src/adapter/repositories/SqliteClaudeMessageResponseRepository.test.ts +313 -0
  24. package/src/adapter/repositories/SqliteClaudeMessageResponseRepository.ts +164 -0
  25. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +27 -0
  26. package/src/domain/entities/ClaudeMessageResponse.ts +31 -0
  27. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +187 -39
  28. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +37 -20
  29. package/src/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.ts +5 -0
  30. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +5 -0
  31. package/types/adapter/proxy/ClaudeMessageResponseParser.d.ts +4 -0
  32. package/types/adapter/proxy/ClaudeMessageResponseParser.d.ts.map +1 -0
  33. package/types/adapter/proxy/proxyEntry.d.ts +2 -1
  34. package/types/adapter/proxy/proxyEntry.d.ts.map +1 -1
  35. package/types/adapter/repositories/SqliteClaudeMessageResponseRepository.d.ts +10 -0
  36. package/types/adapter/repositories/SqliteClaudeMessageResponseRepository.d.ts.map +1 -0
  37. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +1 -0
  38. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  39. package/types/domain/entities/ClaudeMessageResponse.d.ts +32 -0
  40. package/types/domain/entities/ClaudeMessageResponse.d.ts.map +1 -0
  41. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +3 -2
  42. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
  43. package/types/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.d.ts +5 -0
  44. package/types/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.d.ts.map +1 -0
  45. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +1 -0
  46. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
@@ -77,7 +77,7 @@ class NotifyFinishedIssuePreparationUseCase {
77
77
  return;
78
78
  }
79
79
  const comments = await this.issueCommentRepository.getCommentsFromIssue(issue);
80
- const { rejections, approvedPrUrl } = await this.collectRejections(issue, comments);
80
+ const { rejections } = await this.collectRejections(issue, comments);
81
81
  const rejectionStatusMessage = rejections.length > 0
82
82
  ? `Auto Status Check: REJECTED\n${rejections.map((r) => `- ${r.detail}`).join('\n')}`
83
83
  : 'Auto Status Check: APPROVED';
@@ -92,9 +92,7 @@ class NotifyFinishedIssuePreparationUseCase {
92
92
  const escalationStatusLine = rejections.length > 0
93
93
  ? rejectionStatusMessage
94
94
  : 'Auto Status Check: APPROVED (escalated due to prior failures)';
95
- if (rejections.length === 0 && approvedPrUrl !== null) {
96
- await this.setPrNextActionDate(approvedPrUrl, project);
97
- }
95
+ await this.setDependedIssueUrlForAllOpenPRs(issue, params.issueUrl, project);
98
96
  await this.issueCommentRepository.createComment(issue, `${escalationStatusLine}\n\nFailed to pass the check automatically for ${params.thresholdForAutoReject} times`);
99
97
  await this.sendWorkflowBlockerNotification(params.issueUrl, params.workflowBlockerResolvedWebhookUrl, project);
100
98
  return;
@@ -103,15 +101,14 @@ class NotifyFinishedIssuePreparationUseCase {
103
101
  issue.status = WorkflowStatus_1.AWAITING_QUALITY_CHECK_STATUS_NAME;
104
102
  await this.issueRepository.update(issue, project);
105
103
  await this.issueRepository.updateStatus(project, issue, awaitingQualityCheckStatusOption.id);
106
- if (approvedPrUrl !== null) {
107
- await this.setPrNextActionDate(approvedPrUrl, project);
108
- }
104
+ await this.setDependedIssueUrlForAllOpenPRs(issue, params.issueUrl, project);
109
105
  await this.sendWorkflowBlockerNotification(params.issueUrl, params.workflowBlockerResolvedWebhookUrl, project);
110
106
  return;
111
107
  }
112
108
  issue.status = WorkflowStatus_1.AWAITING_WORKSPACE_STATUS_NAME;
113
109
  await this.issueRepository.update(issue, project);
114
110
  await this.issueRepository.updateStatus(project, issue, awaitingWorkspaceStatusOption.id);
111
+ await this.setDependedIssueUrlForAllOpenPRs(issue, params.issueUrl, project);
115
112
  await this.issueCommentRepository.createComment(issue, rejectionStatusMessage);
116
113
  };
117
114
  this.collectRejections = async (issue, comments) => {
@@ -154,10 +151,20 @@ class NotifyFinishedIssuePreparationUseCase {
154
151
  const nextStepValue = Reflect.get(reportJson, 'nextStep');
155
152
  return nextStepValue !== null && nextStepValue !== undefined;
156
153
  };
157
- this.setPrNextActionDate = async (prUrl, project) => {
158
- const nextActionDate = new Date();
159
- nextActionDate.setMonth(nextActionDate.getMonth() + 1);
160
- await this.issueRepository.updateNextActionDate(prUrl, project, nextActionDate);
154
+ this.setDependedIssueUrlForAllOpenPRs = async (issue, issueUrl, project) => {
155
+ const openPRs = issue.isPr
156
+ ? await this.resolveOpenPrsForPrItem(issue.url)
157
+ : await this.issueRepository.findRelatedOpenPRs(issue.url);
158
+ for (const pr of openPRs) {
159
+ await this.issueRepository.setDependedIssueUrl(pr.url, project, issueUrl);
160
+ }
161
+ };
162
+ this.resolveOpenPrsForPrItem = async (prUrl) => {
163
+ const pr = await this.issueRepository.getOpenPullRequest(prUrl);
164
+ if (pr === null) {
165
+ return [];
166
+ }
167
+ return [pr];
161
168
  };
162
169
  this.sendWorkflowBlockerNotification = async (issueUrl, webhookUrlTemplate, project) => {
163
170
  if (webhookUrlTemplate === null) {
@@ -1 +1 @@
1
- {"version":3,"file":"NotifyFinishedIssuePreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NotifyFinishedIssuePreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ClaudeMessageResponseRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeMessageResponseRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.59.0",
3
+ "version": "1.60.1",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -50,6 +50,7 @@
50
50
  "devDependencies": {
51
51
  "@semantic-release/changelog": "^6.0.3",
52
52
  "@semantic-release/commit-analyzer": "^13.0.0",
53
+ "@types/better-sqlite3": "7.6.13",
53
54
  "@types/cookie": "^1.0.0",
54
55
  "@types/jest": "^29.5.12",
55
56
  "@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -72,6 +73,7 @@
72
73
  "typescript": "^6.0.0"
73
74
  },
74
75
  "dependencies": {
76
+ "better-sqlite3": "12.10.0",
75
77
  "cheerio": "^1.0.0",
76
78
  "commander": "^14.0.0",
77
79
  "cookie": "^1.0.1",
@@ -0,0 +1,211 @@
1
+ import { parseClaudeMessageResponse } from './ClaudeMessageResponseParser';
2
+
3
+ const SUCCESS_BODY = JSON.stringify({
4
+ id: 'msg_01XFDUDYJgAACTvykiHMn8xy',
5
+ type: 'message',
6
+ role: 'assistant',
7
+ model: 'claude-sonnet-4-5',
8
+ stop_reason: 'end_turn',
9
+ stop_sequence: null,
10
+ usage: {
11
+ input_tokens: 100,
12
+ output_tokens: 50,
13
+ cache_creation_input_tokens: null,
14
+ cache_read_input_tokens: null,
15
+ },
16
+ });
17
+
18
+ const ERROR_BODY = JSON.stringify({
19
+ type: 'error',
20
+ error: {
21
+ type: 'rate_limit_error',
22
+ message: 'Too many requests',
23
+ },
24
+ });
25
+
26
+ const SUCCESS_HEADERS = {
27
+ 'x-request-id': 'req_01234',
28
+ 'anthropic-ratelimit-unified-status': 'active',
29
+ 'anthropic-ratelimit-unified-5h-status': 'active',
30
+ 'anthropic-ratelimit-unified-5h-utilization': '42.5',
31
+ 'anthropic-ratelimit-unified-5h-reset': '1705316200',
32
+ 'anthropic-ratelimit-unified-7d-status': 'active',
33
+ 'anthropic-ratelimit-unified-7d-utilization': '10.0',
34
+ 'anthropic-ratelimit-unified-7d-reset': '1705920000',
35
+ 'anthropic-organization-id': 'org-abc123',
36
+ 'anthropic-service-tier': 'standard',
37
+ };
38
+
39
+ describe('parseClaudeMessageResponse', () => {
40
+ it('parses a successful 200 response with all fields', () => {
41
+ const result = parseClaudeMessageResponse(
42
+ 'hashed-token',
43
+ 200,
44
+ SUCCESS_HEADERS,
45
+ SUCCESS_BODY,
46
+ );
47
+
48
+ expect(result.tokenName).toBe('hashed-token');
49
+ expect(result.httpStatus).toBe(200);
50
+ expect(result.externalClaudeMessageId).toBe('msg_01XFDUDYJgAACTvykiHMn8xy');
51
+ expect(result.externalClaudeRequestId).toBe('req_01234');
52
+ expect(result.model).toBe('claude-sonnet-4-5');
53
+ expect(result.role).toBe('assistant');
54
+ expect(result.stopReason).toBe('end_turn');
55
+ expect(result.stopSequence).toBeNull();
56
+ expect(result.inputTokens).toBe(100);
57
+ expect(result.outputTokens).toBe(50);
58
+ expect(result.cacheCreationInputTokens).toBeNull();
59
+ expect(result.cacheReadInputTokens).toBeNull();
60
+ expect(result.serviceTier).toBe('standard');
61
+ expect(result.errorType).toBeNull();
62
+ expect(result.errorMessage).toBeNull();
63
+ expect(result.anthropicRatelimitUnifiedStatus).toBe('active');
64
+ expect(result.anthropicRatelimitUnified5hStatus).toBe('active');
65
+ expect(result.anthropicRatelimitUnified5hUtilization).toBe(42.5);
66
+ expect(result.anthropicRatelimitUnified5hReset).toBe(1705316200);
67
+ expect(result.anthropicRatelimitUnified7dStatus).toBe('active');
68
+ expect(result.anthropicRatelimitUnified7dUtilization).toBe(10.0);
69
+ expect(result.anthropicRatelimitUnified7dReset).toBe(1705920000);
70
+ expect(result.retryAfter).toBeNull();
71
+ expect(result.anthropicOrganizationId).toBe('org-abc123');
72
+ });
73
+
74
+ it('assigns a non-empty ULID as id', () => {
75
+ const result = parseClaudeMessageResponse('tok', 200, {}, '{}');
76
+ expect(result.id).toHaveLength(26);
77
+ expect(/^[0-9A-HJKMNP-TV-Z]{26}$/.test(result.id)).toBe(true);
78
+ });
79
+
80
+ it('sets observedAt to a recent Date', () => {
81
+ const before = Date.now();
82
+ const result = parseClaudeMessageResponse('tok', 200, {}, '{}');
83
+ const after = Date.now();
84
+ expect(result.observedAt.getTime()).toBeGreaterThanOrEqual(before);
85
+ expect(result.observedAt.getTime()).toBeLessThanOrEqual(after);
86
+ });
87
+
88
+ it('parses an error response body', () => {
89
+ const result = parseClaudeMessageResponse(
90
+ 'hashed-token',
91
+ 429,
92
+ { 'retry-after': '30' },
93
+ ERROR_BODY,
94
+ );
95
+
96
+ expect(result.httpStatus).toBe(429);
97
+ expect(result.errorType).toBe('rate_limit_error');
98
+ expect(result.errorMessage).toBe('Too many requests');
99
+ expect(result.retryAfter).toBe(30);
100
+ expect(result.model).toBeNull();
101
+ expect(result.role).toBeNull();
102
+ expect(result.stopReason).toBeNull();
103
+ expect(result.inputTokens).toBeNull();
104
+ expect(result.outputTokens).toBeNull();
105
+ });
106
+
107
+ it('returns null for missing body fields when body is empty object', () => {
108
+ const result = parseClaudeMessageResponse('tok', 200, {}, '{}');
109
+
110
+ expect(result.externalClaudeMessageId).toBeNull();
111
+ expect(result.model).toBeNull();
112
+ expect(result.role).toBeNull();
113
+ expect(result.stopReason).toBeNull();
114
+ expect(result.stopSequence).toBeNull();
115
+ expect(result.inputTokens).toBeNull();
116
+ expect(result.outputTokens).toBeNull();
117
+ });
118
+
119
+ it('returns null for rate limit headers when they are absent', () => {
120
+ const result = parseClaudeMessageResponse('tok', 200, {}, '{}');
121
+
122
+ expect(result.anthropicRatelimitUnifiedStatus).toBeNull();
123
+ expect(result.anthropicRatelimitUnified5hStatus).toBeNull();
124
+ expect(result.anthropicRatelimitUnified5hUtilization).toBeNull();
125
+ expect(result.anthropicRatelimitUnified5hReset).toBeNull();
126
+ expect(result.anthropicOrganizationId).toBeNull();
127
+ expect(result.retryAfter).toBeNull();
128
+ });
129
+
130
+ it('handles non-JSON body gracefully by leaving body fields null', () => {
131
+ const result = parseClaudeMessageResponse(
132
+ 'tok',
133
+ 200,
134
+ {},
135
+ 'this is not json',
136
+ );
137
+
138
+ expect(result.externalClaudeMessageId).toBeNull();
139
+ expect(result.model).toBeNull();
140
+ expect(result.inputTokens).toBeNull();
141
+ });
142
+
143
+ it('handles empty body string gracefully', () => {
144
+ const result = parseClaudeMessageResponse('tok', 200, {}, '');
145
+
146
+ expect(result.externalClaudeMessageId).toBeNull();
147
+ expect(result.model).toBeNull();
148
+ });
149
+
150
+ it('picks the first value when a header is an array', () => {
151
+ const result = parseClaudeMessageResponse(
152
+ 'tok',
153
+ 200,
154
+ { 'x-request-id': ['req-first', 'req-second'] },
155
+ '{}',
156
+ );
157
+
158
+ expect(result.externalClaudeRequestId).toBe('req-first');
159
+ });
160
+
161
+ it('parses cache token fields from usage', () => {
162
+ const body = JSON.stringify({
163
+ id: 'msg_cache',
164
+ role: 'assistant',
165
+ model: 'claude-sonnet-4-5',
166
+ stop_reason: 'end_turn',
167
+ usage: {
168
+ input_tokens: 200,
169
+ output_tokens: 80,
170
+ cache_creation_input_tokens: 150,
171
+ cache_read_input_tokens: 50,
172
+ },
173
+ });
174
+
175
+ const result = parseClaudeMessageResponse('tok', 200, {}, body);
176
+
177
+ expect(result.cacheCreationInputTokens).toBe(150);
178
+ expect(result.cacheReadInputTokens).toBe(50);
179
+ });
180
+
181
+ it('parses ephemeral token fields from usage', () => {
182
+ const body = JSON.stringify({
183
+ id: 'msg_ephemeral',
184
+ role: 'assistant',
185
+ model: 'claude-sonnet-4-5',
186
+ stop_reason: 'end_turn',
187
+ usage: {
188
+ input_tokens: 300,
189
+ output_tokens: 120,
190
+ ephemeral_5m_input_tokens: 100,
191
+ ephemeral_1h_input_tokens: 200,
192
+ },
193
+ });
194
+
195
+ const result = parseClaudeMessageResponse('tok', 200, {}, body);
196
+
197
+ expect(result.ephemeral5mInputTokens).toBe(100);
198
+ expect(result.ephemeral1hInputTokens).toBe(200);
199
+ });
200
+
201
+ it('parses a non-finite utilization header as null', () => {
202
+ const result = parseClaudeMessageResponse(
203
+ 'tok',
204
+ 200,
205
+ { 'anthropic-ratelimit-unified-5h-utilization': 'not-a-number' },
206
+ '{}',
207
+ );
208
+
209
+ expect(result.anthropicRatelimitUnified5hUtilization).toBeNull();
210
+ });
211
+ });
@@ -0,0 +1,180 @@
1
+ import * as http from 'http';
2
+ import { ClaudeMessageResponse } from '../../domain/entities/ClaudeMessageResponse';
3
+ import { generateUlid } from '../repositories/SqliteClaudeMessageResponseRepository';
4
+
5
+ const pickHeader = (
6
+ headers: http.IncomingHttpHeaders,
7
+ key: string,
8
+ ): string | null => {
9
+ const value = headers[key];
10
+ if (Array.isArray(value)) return value[0] ?? null;
11
+ return value ?? null;
12
+ };
13
+
14
+ const parseNullableFloat = (value: string | null): number | null => {
15
+ if (value === null) return null;
16
+ const parsed = parseFloat(value);
17
+ return Number.isFinite(parsed) ? parsed : null;
18
+ };
19
+
20
+ const parseNullableInt = (value: unknown): number | null => {
21
+ if (value === null || value === undefined) return null;
22
+ const parsed =
23
+ typeof value === 'number' ? value : parseInt(String(value), 10);
24
+ return Number.isFinite(parsed) ? parsed : null;
25
+ };
26
+
27
+ const isRecord = (value: unknown): value is Record<string, unknown> =>
28
+ value !== null && typeof value === 'object' && !Array.isArray(value);
29
+
30
+ const extractUsage = (
31
+ body: Record<string, unknown>,
32
+ ): {
33
+ inputTokens: number | null;
34
+ outputTokens: number | null;
35
+ cacheCreationInputTokens: number | null;
36
+ cacheReadInputTokens: number | null;
37
+ ephemeral5mInputTokens: number | null;
38
+ ephemeral1hInputTokens: number | null;
39
+ } => {
40
+ const usage = body['usage'];
41
+ if (!isRecord(usage)) {
42
+ return {
43
+ inputTokens: null,
44
+ outputTokens: null,
45
+ cacheCreationInputTokens: null,
46
+ cacheReadInputTokens: null,
47
+ ephemeral5mInputTokens: null,
48
+ ephemeral1hInputTokens: null,
49
+ };
50
+ }
51
+ return {
52
+ inputTokens: parseNullableInt(usage['input_tokens']),
53
+ outputTokens: parseNullableInt(usage['output_tokens']),
54
+ cacheCreationInputTokens: parseNullableInt(
55
+ usage['cache_creation_input_tokens'],
56
+ ),
57
+ cacheReadInputTokens: parseNullableInt(usage['cache_read_input_tokens']),
58
+ ephemeral5mInputTokens: parseNullableInt(
59
+ usage['ephemeral_5m_input_tokens'],
60
+ ),
61
+ ephemeral1hInputTokens: parseNullableInt(
62
+ usage['ephemeral_1h_input_tokens'],
63
+ ),
64
+ };
65
+ };
66
+
67
+ const extractRole = (body: Record<string, unknown>): string | null => {
68
+ const role = body['role'];
69
+ return typeof role === 'string' ? role : null;
70
+ };
71
+
72
+ const extractFirstContentRole = (
73
+ body: Record<string, unknown>,
74
+ ): string | null => {
75
+ const content = body['content'];
76
+ if (!Array.isArray(content)) return null;
77
+ const first: unknown = content[0];
78
+ if (!isRecord(first)) return null;
79
+ const role = first['role'];
80
+ return typeof role === 'string' ? role : null;
81
+ };
82
+
83
+ export const parseClaudeMessageResponse = (
84
+ tokenName: string,
85
+ httpStatus: number,
86
+ headers: http.IncomingHttpHeaders,
87
+ body: string,
88
+ ): ClaudeMessageResponse => {
89
+ let parsedBody: Record<string, unknown> = {};
90
+ try {
91
+ const parsed: unknown = JSON.parse(body);
92
+ if (isRecord(parsed)) {
93
+ parsedBody = parsed;
94
+ }
95
+ } catch {
96
+ parsedBody = {};
97
+ }
98
+
99
+ const errorObj = parsedBody['error'];
100
+ const errorRecord = isRecord(errorObj) ? errorObj : null;
101
+ const errorType =
102
+ errorRecord !== null && typeof errorRecord['type'] === 'string'
103
+ ? errorRecord['type']
104
+ : null;
105
+ const errorMessage =
106
+ errorRecord !== null && typeof errorRecord['message'] === 'string'
107
+ ? errorRecord['message']
108
+ : null;
109
+
110
+ const externalClaudeMessageId =
111
+ typeof parsedBody['id'] === 'string' ? parsedBody['id'] : null;
112
+
113
+ const model =
114
+ typeof parsedBody['model'] === 'string' ? parsedBody['model'] : null;
115
+
116
+ const role = extractRole(parsedBody) ?? extractFirstContentRole(parsedBody);
117
+
118
+ const stopReason =
119
+ typeof parsedBody['stop_reason'] === 'string'
120
+ ? parsedBody['stop_reason']
121
+ : null;
122
+ const stopSequence =
123
+ typeof parsedBody['stop_sequence'] === 'string'
124
+ ? parsedBody['stop_sequence']
125
+ : null;
126
+
127
+ const usage = extractUsage(parsedBody);
128
+
129
+ const retryAfterRaw = pickHeader(headers, 'retry-after');
130
+ const retryAfter = parseNullableFloat(retryAfterRaw);
131
+
132
+ return {
133
+ id: generateUlid(),
134
+ observedAt: new Date(),
135
+ tokenName,
136
+ externalClaudeMessageId,
137
+ externalClaudeRequestId: pickHeader(headers, 'x-request-id'),
138
+ httpStatus,
139
+ model,
140
+ role,
141
+ stopReason,
142
+ stopSequence,
143
+ inputTokens: usage.inputTokens,
144
+ outputTokens: usage.outputTokens,
145
+ cacheCreationInputTokens: usage.cacheCreationInputTokens,
146
+ cacheReadInputTokens: usage.cacheReadInputTokens,
147
+ ephemeral5mInputTokens: usage.ephemeral5mInputTokens,
148
+ ephemeral1hInputTokens: usage.ephemeral1hInputTokens,
149
+ serviceTier: pickHeader(headers, 'anthropic-service-tier'),
150
+ inferenceGeo: pickHeader(headers, 'anthropic-inference-geo'),
151
+ errorType,
152
+ errorMessage,
153
+ anthropicRatelimitUnifiedStatus: pickHeader(
154
+ headers,
155
+ 'anthropic-ratelimit-unified-status',
156
+ ),
157
+ anthropicRatelimitUnified5hStatus: pickHeader(
158
+ headers,
159
+ 'anthropic-ratelimit-unified-5h-status',
160
+ ),
161
+ anthropicRatelimitUnified5hUtilization: parseNullableFloat(
162
+ pickHeader(headers, 'anthropic-ratelimit-unified-5h-utilization'),
163
+ ),
164
+ anthropicRatelimitUnified5hReset: parseNullableFloat(
165
+ pickHeader(headers, 'anthropic-ratelimit-unified-5h-reset'),
166
+ ),
167
+ anthropicRatelimitUnified7dStatus: pickHeader(
168
+ headers,
169
+ 'anthropic-ratelimit-unified-7d-status',
170
+ ),
171
+ anthropicRatelimitUnified7dUtilization: parseNullableFloat(
172
+ pickHeader(headers, 'anthropic-ratelimit-unified-7d-utilization'),
173
+ ),
174
+ anthropicRatelimitUnified7dReset: parseNullableFloat(
175
+ pickHeader(headers, 'anthropic-ratelimit-unified-7d-reset'),
176
+ ),
177
+ retryAfter,
178
+ anthropicOrganizationId: pickHeader(headers, 'anthropic-organization-id'),
179
+ };
180
+ };
@@ -2,10 +2,14 @@ import * as http from 'http';
2
2
  import * as https from 'https';
3
3
  import {
4
4
  PROXY_PORT,
5
+ hashToken,
5
6
  parseModelRateLimitsFromBody,
6
7
  writeModelRateLimit,
7
8
  writeRateLimit,
8
9
  } from './RateLimitCache';
10
+ import { ClaudeMessageResponseRepository } from '../../domain/usecases/adapter-interfaces/ClaudeMessageResponseRepository';
11
+ import { parseClaudeMessageResponse } from './ClaudeMessageResponseParser';
12
+ import { SqliteClaudeMessageResponseRepository } from '../repositories/SqliteClaudeMessageResponseRepository';
9
13
 
10
14
  const UPSTREAM_HOST = 'api.anthropic.com';
11
15
 
@@ -25,7 +29,10 @@ const extractToken = (
25
29
  return token.length > 0 ? token : null;
26
30
  };
27
31
 
28
- const startProxy = (port: number): void => {
32
+ const startProxy = (
33
+ port: number,
34
+ claudeMessageResponseRepository: ClaudeMessageResponseRepository | null = null,
35
+ ): void => {
29
36
  const server = http.createServer((clientRequest, clientResponse) => {
30
37
  const token = extractToken(clientRequest.headers['authorization']);
31
38
  const upstreamHeaders: Record<string, string | string[] | undefined> = {
@@ -55,13 +62,29 @@ const startProxy = (port: number): void => {
55
62
  inspectedBytes += chunk.length;
56
63
  });
57
64
  upstreamResponse.on('end', () => {
65
+ const body = Buffer.concat(inspectedChunks).toString('utf8');
58
66
  try {
59
- const body = Buffer.concat(inspectedChunks).toString('utf8');
60
67
  const limits = parseModelRateLimitsFromBody(body);
61
68
  writeModelRateLimit(token, limits);
62
69
  } catch (error) {
63
70
  console.error('Failed to write model rate limit cache:', error);
64
71
  }
72
+ if (claudeMessageResponseRepository !== null) {
73
+ try {
74
+ const response = parseClaudeMessageResponse(
75
+ hashToken(token),
76
+ upstreamResponse.statusCode ?? 0,
77
+ upstreamResponse.headers,
78
+ body,
79
+ );
80
+ claudeMessageResponseRepository.append(response);
81
+ } catch (error) {
82
+ console.error(
83
+ 'Failed to record Claude message response:',
84
+ error,
85
+ );
86
+ }
87
+ }
65
88
  });
66
89
  }
67
90
  clientResponse.writeHead(
@@ -86,7 +109,9 @@ const startProxy = (port: number): void => {
86
109
  };
87
110
 
88
111
  if (require.main === module) {
89
- startProxy(PROXY_PORT);
112
+ const dbPath = './db/claude_message_response.db';
113
+ const repository = new SqliteClaudeMessageResponseRepository(dbPath);
114
+ startProxy(PROXY_PORT, repository);
90
115
  }
91
116
 
92
117
  export { startProxy, extractToken };