@diff-review-system/drs 2.2.1 → 3.0.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.
Files changed (240) hide show
  1. package/README.md +228 -92
  2. package/dist/ci/runner.d.ts.map +1 -1
  3. package/dist/ci/runner.js +19 -22
  4. package/dist/ci/runner.js.map +1 -1
  5. package/dist/cli/describe-mr.d.ts.map +1 -1
  6. package/dist/cli/describe-mr.js +39 -20
  7. package/dist/cli/describe-mr.js.map +1 -1
  8. package/dist/cli/describe-pr.d.ts.map +1 -1
  9. package/dist/cli/describe-pr.js +39 -20
  10. package/dist/cli/describe-pr.js.map +1 -1
  11. package/dist/cli/index.js +11 -7
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/init.d.ts.map +1 -1
  14. package/dist/cli/init.js +30 -2
  15. package/dist/cli/init.js.map +1 -1
  16. package/dist/cli/post-comments.d.ts.map +1 -1
  17. package/dist/cli/post-comments.js +5 -5
  18. package/dist/cli/post-comments.js.map +1 -1
  19. package/dist/cli/review-local.d.ts.map +1 -1
  20. package/dist/cli/review-local.integration.test.d.ts +2 -0
  21. package/dist/cli/review-local.integration.test.d.ts.map +1 -0
  22. package/dist/cli/review-local.integration.test.js +343 -0
  23. package/dist/cli/review-local.integration.test.js.map +1 -0
  24. package/dist/cli/review-local.js +5 -4
  25. package/dist/cli/review-local.js.map +1 -1
  26. package/dist/cli/review-local.live.e2e.test.d.ts +2 -0
  27. package/dist/cli/review-local.live.e2e.test.d.ts.map +1 -0
  28. package/dist/cli/review-local.live.e2e.test.js +154 -0
  29. package/dist/cli/review-local.live.e2e.test.js.map +1 -0
  30. package/dist/cli/review-local.test.d.ts +2 -0
  31. package/dist/cli/review-local.test.d.ts.map +1 -0
  32. package/dist/cli/review-local.test.js +164 -0
  33. package/dist/cli/review-local.test.js.map +1 -0
  34. package/dist/cli/review-mr.d.ts +1 -1
  35. package/dist/cli/review-mr.d.ts.map +1 -1
  36. package/dist/cli/review-mr.js +92 -17
  37. package/dist/cli/review-mr.js.map +1 -1
  38. package/dist/cli/review-mr.test.d.ts +2 -0
  39. package/dist/cli/review-mr.test.d.ts.map +1 -0
  40. package/dist/cli/review-mr.test.js +142 -0
  41. package/dist/cli/review-mr.test.js.map +1 -0
  42. package/dist/cli/review-pr.d.ts +1 -1
  43. package/dist/cli/review-pr.d.ts.map +1 -1
  44. package/dist/cli/review-pr.js +96 -13
  45. package/dist/cli/review-pr.js.map +1 -1
  46. package/dist/cli/review-pr.test.d.ts +2 -0
  47. package/dist/cli/review-pr.test.d.ts.map +1 -0
  48. package/dist/cli/review-pr.test.js +137 -0
  49. package/dist/cli/review-pr.test.js.map +1 -0
  50. package/dist/cli/show-changes.js +4 -4
  51. package/dist/github/platform-adapter.js +2 -2
  52. package/dist/gitlab/client.js +1 -1
  53. package/dist/lib/code-quality-report.js +1 -1
  54. package/dist/lib/comment-formatter.d.ts +2 -1
  55. package/dist/lib/comment-formatter.d.ts.map +1 -1
  56. package/dist/lib/comment-formatter.js +33 -1
  57. package/dist/lib/comment-formatter.js.map +1 -1
  58. package/dist/lib/comment-formatter.test.js +43 -0
  59. package/dist/lib/comment-formatter.test.js.map +1 -1
  60. package/dist/lib/comment-manager.d.ts.map +1 -1
  61. package/dist/lib/comment-manager.js +4 -3
  62. package/dist/lib/comment-manager.js.map +1 -1
  63. package/dist/lib/comment-poster.d.ts +2 -1
  64. package/dist/lib/comment-poster.d.ts.map +1 -1
  65. package/dist/lib/comment-poster.js +2 -2
  66. package/dist/lib/comment-poster.js.map +1 -1
  67. package/dist/lib/comment-poster.test.js +27 -11
  68. package/dist/lib/comment-poster.test.js.map +1 -1
  69. package/dist/lib/config-model-overrides.test.d.ts +1 -1
  70. package/dist/lib/config-model-overrides.test.js +2 -2
  71. package/dist/lib/config-model-overrides.test.js.map +1 -1
  72. package/dist/lib/config.d.ts +34 -7
  73. package/dist/lib/config.d.ts.map +1 -1
  74. package/dist/lib/config.js +35 -13
  75. package/dist/lib/config.js.map +1 -1
  76. package/dist/lib/config.test.js +16 -0
  77. package/dist/lib/config.test.js.map +1 -1
  78. package/dist/lib/context-compression.d.ts +27 -1
  79. package/dist/lib/context-compression.d.ts.map +1 -1
  80. package/dist/lib/context-compression.js +106 -4
  81. package/dist/lib/context-compression.js.map +1 -1
  82. package/dist/lib/context-compression.test.js +305 -1
  83. package/dist/lib/context-compression.test.js.map +1 -1
  84. package/dist/lib/context-loader.d.ts +3 -2
  85. package/dist/lib/context-loader.d.ts.map +1 -1
  86. package/dist/lib/context-loader.js +11 -11
  87. package/dist/lib/context-loader.js.map +1 -1
  88. package/dist/lib/description-executor.d.ts +19 -2
  89. package/dist/lib/description-executor.d.ts.map +1 -1
  90. package/dist/lib/description-executor.js +52 -21
  91. package/dist/lib/description-executor.js.map +1 -1
  92. package/dist/lib/description-executor.test.d.ts +2 -0
  93. package/dist/lib/description-executor.test.d.ts.map +1 -0
  94. package/dist/lib/description-executor.test.js +120 -0
  95. package/dist/lib/description-executor.test.js.map +1 -0
  96. package/dist/lib/description-formatter.d.ts +8 -3
  97. package/dist/lib/description-formatter.d.ts.map +1 -1
  98. package/dist/lib/description-formatter.js +88 -13
  99. package/dist/lib/description-formatter.js.map +1 -1
  100. package/dist/lib/description-formatter.test.d.ts +2 -0
  101. package/dist/lib/description-formatter.test.d.ts.map +1 -0
  102. package/dist/lib/description-formatter.test.js +57 -0
  103. package/dist/lib/description-formatter.test.js.map +1 -0
  104. package/dist/lib/diff-parser.test.d.ts +2 -0
  105. package/dist/lib/diff-parser.test.d.ts.map +1 -0
  106. package/dist/lib/diff-parser.test.js +335 -0
  107. package/dist/lib/diff-parser.test.js.map +1 -0
  108. package/dist/lib/exit.d.ts +35 -0
  109. package/dist/lib/exit.d.ts.map +1 -0
  110. package/dist/lib/exit.js +53 -0
  111. package/dist/lib/exit.js.map +1 -0
  112. package/dist/lib/exit.test.d.ts +2 -0
  113. package/dist/lib/exit.test.d.ts.map +1 -0
  114. package/dist/lib/exit.test.js +120 -0
  115. package/dist/lib/exit.test.js.map +1 -0
  116. package/dist/lib/format-utils.d.ts +3 -0
  117. package/dist/lib/format-utils.d.ts.map +1 -0
  118. package/dist/lib/format-utils.js +7 -0
  119. package/dist/lib/format-utils.js.map +1 -0
  120. package/dist/lib/json-output.d.ts +4 -1
  121. package/dist/lib/json-output.d.ts.map +1 -1
  122. package/dist/lib/json-output.js +2 -1
  123. package/dist/lib/json-output.js.map +1 -1
  124. package/dist/lib/json-output.test.d.ts +2 -0
  125. package/dist/lib/json-output.test.d.ts.map +1 -0
  126. package/dist/lib/json-output.test.js +135 -0
  127. package/dist/lib/json-output.test.js.map +1 -0
  128. package/dist/lib/logger.d.ts +10 -2
  129. package/dist/lib/logger.d.ts.map +1 -1
  130. package/dist/lib/logger.js +22 -4
  131. package/dist/lib/logger.js.map +1 -1
  132. package/dist/lib/logger.test.d.ts +2 -0
  133. package/dist/lib/logger.test.d.ts.map +1 -0
  134. package/dist/lib/logger.test.js +324 -0
  135. package/dist/lib/logger.test.js.map +1 -0
  136. package/dist/lib/position-validator.test.d.ts +2 -0
  137. package/dist/lib/position-validator.test.d.ts.map +1 -0
  138. package/dist/lib/position-validator.test.js +128 -0
  139. package/dist/lib/position-validator.test.js.map +1 -0
  140. package/dist/lib/repository-validator.js +1 -1
  141. package/dist/lib/review-core.d.ts +9 -4
  142. package/dist/lib/review-core.d.ts.map +1 -1
  143. package/dist/lib/review-core.js +207 -112
  144. package/dist/lib/review-core.js.map +1 -1
  145. package/dist/lib/review-core.test.js +76 -30
  146. package/dist/lib/review-core.test.js.map +1 -1
  147. package/dist/lib/review-orchestrator.d.ts +12 -7
  148. package/dist/lib/review-orchestrator.d.ts.map +1 -1
  149. package/dist/lib/review-orchestrator.js +78 -22
  150. package/dist/lib/review-orchestrator.js.map +1 -1
  151. package/dist/lib/review-orchestrator.test.js +160 -42
  152. package/dist/lib/review-orchestrator.test.js.map +1 -1
  153. package/dist/lib/review-parser.test.d.ts +2 -0
  154. package/dist/lib/review-parser.test.d.ts.map +1 -0
  155. package/dist/lib/review-parser.test.js +130 -0
  156. package/dist/lib/review-parser.test.js.map +1 -0
  157. package/dist/lib/review-usage.d.ts +32 -0
  158. package/dist/lib/review-usage.d.ts.map +1 -0
  159. package/dist/lib/review-usage.js +72 -0
  160. package/dist/lib/review-usage.js.map +1 -0
  161. package/dist/lib/review-usage.test.d.ts +2 -0
  162. package/dist/lib/review-usage.test.d.ts.map +1 -0
  163. package/dist/lib/review-usage.test.js +83 -0
  164. package/dist/lib/review-usage.test.js.map +1 -0
  165. package/dist/lib/unified-review-executor.d.ts +6 -2
  166. package/dist/lib/unified-review-executor.d.ts.map +1 -1
  167. package/dist/lib/unified-review-executor.js +54 -28
  168. package/dist/lib/unified-review-executor.js.map +1 -1
  169. package/dist/lib/unified-review-executor.test.js +138 -16
  170. package/dist/lib/unified-review-executor.test.js.map +1 -1
  171. package/dist/lib/write-json-output.test.d.ts +2 -0
  172. package/dist/lib/write-json-output.test.d.ts.map +1 -0
  173. package/dist/lib/write-json-output.test.js +259 -0
  174. package/dist/lib/write-json-output.test.js.map +1 -0
  175. package/dist/pi/sdk.d.ts +94 -0
  176. package/dist/pi/sdk.d.ts.map +1 -0
  177. package/dist/pi/sdk.js +486 -0
  178. package/dist/pi/sdk.js.map +1 -0
  179. package/dist/pi/sdk.test.d.ts +2 -0
  180. package/dist/pi/sdk.test.d.ts.map +1 -0
  181. package/dist/pi/sdk.test.js +331 -0
  182. package/dist/pi/sdk.test.js.map +1 -0
  183. package/dist/{opencode → runtime}/agent-loader.d.ts +7 -5
  184. package/dist/runtime/agent-loader.d.ts.map +1 -0
  185. package/dist/{opencode → runtime}/agent-loader.js +24 -19
  186. package/dist/runtime/agent-loader.js.map +1 -0
  187. package/dist/runtime/agent-loader.test.d.ts +2 -0
  188. package/dist/runtime/agent-loader.test.d.ts.map +1 -0
  189. package/dist/runtime/agent-loader.test.js +280 -0
  190. package/dist/runtime/agent-loader.test.js.map +1 -0
  191. package/dist/runtime/built-in-paths.d.ts +2 -0
  192. package/dist/runtime/built-in-paths.d.ts.map +1 -0
  193. package/dist/runtime/built-in-paths.js +14 -0
  194. package/dist/runtime/built-in-paths.js.map +1 -0
  195. package/dist/{opencode → runtime}/client.d.ts +35 -18
  196. package/dist/runtime/client.d.ts.map +1 -0
  197. package/dist/runtime/client.js +486 -0
  198. package/dist/runtime/client.js.map +1 -0
  199. package/dist/{opencode → runtime}/client.test.d.ts.map +1 -1
  200. package/dist/runtime/client.test.js +392 -0
  201. package/dist/runtime/client.test.js.map +1 -0
  202. package/dist/runtime/path-config.d.ts +8 -0
  203. package/dist/runtime/path-config.d.ts.map +1 -0
  204. package/dist/runtime/path-config.js +68 -0
  205. package/dist/runtime/path-config.js.map +1 -0
  206. package/dist/runtime/path-config.test.d.ts +2 -0
  207. package/dist/runtime/path-config.test.d.ts.map +1 -0
  208. package/dist/runtime/path-config.test.js +103 -0
  209. package/dist/runtime/path-config.test.js.map +1 -0
  210. package/package.json +5 -5
  211. package/.opencode/opencode.jsonc +0 -15
  212. package/.opencode/tool/write_json_output.ts +0 -24
  213. package/.opencode/tools/drs_skill.ts +0 -67
  214. package/dist/lib/skills-prompt.d.ts +0 -3
  215. package/dist/lib/skills-prompt.d.ts.map +0 -1
  216. package/dist/lib/skills-prompt.js +0 -70
  217. package/dist/lib/skills-prompt.js.map +0 -1
  218. package/dist/opencode/agent-loader.d.ts.map +0 -1
  219. package/dist/opencode/agent-loader.js.map +0 -1
  220. package/dist/opencode/client.d.ts.map +0 -1
  221. package/dist/opencode/client.js +0 -456
  222. package/dist/opencode/client.js.map +0 -1
  223. package/dist/opencode/client.test.js +0 -317
  224. package/dist/opencode/client.test.js.map +0 -1
  225. package/dist/opencode/opencode-paths.d.ts +0 -2
  226. package/dist/opencode/opencode-paths.d.ts.map +0 -1
  227. package/dist/opencode/opencode-paths.js +0 -7
  228. package/dist/opencode/opencode-paths.js.map +0 -1
  229. package/dist/opencode/skill-loader.d.ts +0 -15
  230. package/dist/opencode/skill-loader.d.ts.map +0 -1
  231. package/dist/opencode/skill-loader.js +0 -88
  232. package/dist/opencode/skill-loader.js.map +0 -1
  233. /package/{.opencode/agent → .pi/agents}/describe/pr-describer.md +0 -0
  234. /package/{.opencode/agent → .pi/agents}/review/documentation.md +0 -0
  235. /package/{.opencode/agent → .pi/agents}/review/performance.md +0 -0
  236. /package/{.opencode/agent → .pi/agents}/review/quality.md +0 -0
  237. /package/{.opencode/agent → .pi/agents}/review/security.md +0 -0
  238. /package/{.opencode/agent → .pi/agents}/review/style.md +0 -0
  239. /package/{.opencode/agent → .pi/agents}/review/unified-reviewer.md +0 -0
  240. /package/dist/{opencode → runtime}/client.test.d.ts +0 -0
@@ -2,8 +2,8 @@ import { createGitHubClient } from '../github/client.js';
2
2
  import { GitHubPlatformAdapter } from '../github/platform-adapter.js';
3
3
  import { executeUnifiedReview } from '../lib/unified-review-executor.js';
4
4
  /**
5
- * Parse a GitHub diff patch to extract valid line numbers for review comments
6
- * GitHub only allows comments on lines that are in the diff (added, removed, or context)
5
+ * Parse a GitHub diff patch to extract valid line numbers for review comments.
6
+ * GitHub only allows comments on lines that are in the diff (added, removed, or context).
7
7
  */
8
8
  function parseValidLinesFromPatch(patch) {
9
9
  const validLines = new Set();
@@ -37,20 +37,102 @@ function parseValidLinesFromPatch(patch) {
37
37
  }
38
38
  return validLines;
39
39
  }
40
+ function parseStatusCodeFromMessage(message) {
41
+ const match = message.match(/\b(401|403|404|422|429)\b/);
42
+ return match ? parseInt(match[1], 10) : undefined;
43
+ }
44
+ function extractStatusCode(error) {
45
+ if (!error || typeof error !== 'object') {
46
+ return undefined;
47
+ }
48
+ const candidate = error;
49
+ if (typeof candidate.statusCode === 'number') {
50
+ return candidate.statusCode;
51
+ }
52
+ if (typeof candidate.status === 'number') {
53
+ return candidate.status;
54
+ }
55
+ if (candidate.response && typeof candidate.response === 'object') {
56
+ if (typeof candidate.response.statusCode === 'number') {
57
+ return candidate.response.statusCode;
58
+ }
59
+ if (typeof candidate.response.status === 'number') {
60
+ return candidate.response.status;
61
+ }
62
+ }
63
+ if (candidate.cause && candidate.cause !== error) {
64
+ return extractStatusCode(candidate.cause);
65
+ }
66
+ return undefined;
67
+ }
68
+ function mapGitHubContextError(error, options) {
69
+ const rawMessage = error instanceof Error ? error.message : String(error);
70
+ const normalized = rawMessage.toLowerCase();
71
+ const statusCode = extractStatusCode(error) ?? parseStatusCodeFromMessage(rawMessage);
72
+ const pullRequestRef = `${options.owner}/${options.repo}#${options.prNumber}`;
73
+ if (normalized.includes('github_token environment variable is required')) {
74
+ return new Error('GitHub authentication is required. Set GITHUB_TOKEN with a token that can access the target pull request.');
75
+ }
76
+ if (statusCode === 401 ||
77
+ normalized.includes('unauthorized') ||
78
+ normalized.includes('bad credentials')) {
79
+ return new Error(`GitHub authentication failed for ${pullRequestRef}. Verify GITHUB_TOKEN and ensure it has permission to read the repository.`);
80
+ }
81
+ if (statusCode === 429 || normalized.includes('rate limit')) {
82
+ return new Error(`GitHub API rate limit reached while loading ${pullRequestRef}. Retry after cooldown or use a token with higher API limits.`);
83
+ }
84
+ if (statusCode === 403 || normalized.includes('forbidden')) {
85
+ return new Error(`GitHub authorization failed for ${pullRequestRef}. Ensure the token can access the repository and pull request.`);
86
+ }
87
+ if (statusCode === 404 || normalized.includes('not found')) {
88
+ return new Error(`GitHub pull request not found: ${pullRequestRef}. Verify --owner/--repo/--pr values and token access.`);
89
+ }
90
+ if (statusCode === 422 ||
91
+ normalized.includes('unprocessable entity') ||
92
+ normalized.includes('validation failed')) {
93
+ return new Error(`GitHub rejected pull request lookup for ${pullRequestRef}. Confirm the PR number and repository details are valid.`);
94
+ }
95
+ const connectivityError = normalized.includes('fetch failed') ||
96
+ normalized.includes('econnrefused') ||
97
+ normalized.includes('enotfound') ||
98
+ normalized.includes('etimedout') ||
99
+ normalized.includes('econnreset');
100
+ if (connectivityError) {
101
+ return new Error(`Unable to reach GitHub API while loading ${pullRequestRef}. Check network connectivity and retry.`);
102
+ }
103
+ return new Error(`Failed to load GitHub pull request context for ${pullRequestRef}: ${rawMessage}`);
104
+ }
105
+ async function loadPullRequestContext(platformClient, options) {
106
+ const projectId = `${options.owner}/${options.repo}`;
107
+ try {
108
+ const pullRequest = await platformClient.getPullRequest(projectId, options.prNumber);
109
+ const changedFiles = await platformClient.getChangedFiles(projectId, options.prNumber);
110
+ return {
111
+ pullRequest,
112
+ changedFiles,
113
+ };
114
+ }
115
+ catch (error) {
116
+ throw mapGitHubContextError(error, options);
117
+ }
118
+ }
40
119
  /**
41
- * Review a GitHub pull request
120
+ * Review a GitHub pull request.
42
121
  */
43
122
  export async function reviewPR(config, options) {
44
- // Create GitHub client and adapter
45
- const githubClient = createGitHubClient();
46
- const platformClient = new GitHubPlatformAdapter(githubClient);
47
- // Project ID in format "owner/repo"
123
+ let platformClient;
124
+ try {
125
+ const githubClient = createGitHubClient();
126
+ platformClient = new GitHubPlatformAdapter(githubClient);
127
+ }
128
+ catch (error) {
129
+ throw mapGitHubContextError(error, options);
130
+ }
48
131
  const projectId = `${options.owner}/${options.repo}`;
49
- // Fetch files to build line validator
50
- const files = await githubClient.getPRFiles(options.owner, options.repo, options.prNumber);
132
+ const { pullRequest, changedFiles } = await loadPullRequestContext(platformClient, options);
51
133
  // Build a map of file -> valid line numbers (lines that are in the diff)
52
134
  const validLinesMap = new Map();
53
- for (const file of files) {
135
+ for (const file of changedFiles) {
54
136
  if (file.patch && file.status !== 'removed') {
55
137
  const validLines = parseValidLinesFromPatch(file.patch);
56
138
  validLinesMap.set(file.filename, validLines);
@@ -64,12 +146,11 @@ export async function reviewPR(config, options) {
64
146
  },
65
147
  };
66
148
  // Create inline position builder
67
- const createInlinePosition = (issue, platformData) => {
68
- const data = platformData;
149
+ const createInlinePosition = (issue, _platformData) => {
69
150
  return {
70
151
  path: issue.file,
71
152
  line: issue.line,
72
- commitSha: data.head.sha,
153
+ commitSha: pullRequest.headSha,
73
154
  };
74
155
  };
75
156
  // Execute unified review
@@ -77,6 +158,8 @@ export async function reviewPR(config, options) {
77
158
  platformClient,
78
159
  projectId,
79
160
  prNumber: options.prNumber,
161
+ pullRequest,
162
+ changedFiles,
80
163
  postComments: options.postComments,
81
164
  postErrorComment: options.postErrorComment,
82
165
  outputPath: options.outputPath,
@@ -1 +1 @@
1
- {"version":3,"file":"review-pr.js","sourceRoot":"","sources":["../../src/cli/review-pr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-pr.js","sourceRoot":"","sources":["../../src/cli/review-pr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=review-pr.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-pr.test.d.ts","sourceRoot":"","sources":["../../src/cli/review-pr.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,137 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { reviewPR } from './review-pr.js';
3
+ const { mockGitHubClient, createGitHubClient, executeUnifiedReview } = vi.hoisted(() => ({
4
+ mockGitHubClient: {
5
+ getPullRequest: vi.fn(),
6
+ getPRFiles: vi.fn(),
7
+ },
8
+ createGitHubClient: vi.fn(),
9
+ executeUnifiedReview: vi.fn(),
10
+ }));
11
+ vi.mock('../github/client.js', () => ({
12
+ createGitHubClient,
13
+ }));
14
+ vi.mock('../lib/unified-review-executor.js', () => ({
15
+ executeUnifiedReview,
16
+ }));
17
+ const baseConfig = {
18
+ pi: {},
19
+ gitlab: { url: 'https://gitlab.com', token: 'token' },
20
+ github: { token: 'token' },
21
+ review: {
22
+ agents: ['security', 'quality'],
23
+ ignorePatterns: [],
24
+ },
25
+ };
26
+ const baseOptions = {
27
+ owner: 'octocat',
28
+ repo: 'hello-world',
29
+ prNumber: 17,
30
+ postComments: true,
31
+ postErrorComment: true,
32
+ describe: false,
33
+ postDescription: false,
34
+ };
35
+ describe('review-pr', () => {
36
+ beforeEach(() => {
37
+ vi.clearAllMocks();
38
+ createGitHubClient.mockReturnValue(mockGitHubClient);
39
+ executeUnifiedReview.mockResolvedValue(undefined);
40
+ mockGitHubClient.getPullRequest.mockResolvedValue({
41
+ number: 17,
42
+ title: 'Test PR',
43
+ body: 'Test description',
44
+ user: { login: 'octocat' },
45
+ head: {
46
+ ref: 'feature/pi-migration',
47
+ sha: 'head-sha',
48
+ },
49
+ base: {
50
+ ref: 'main',
51
+ },
52
+ });
53
+ mockGitHubClient.getPRFiles.mockResolvedValue([
54
+ {
55
+ filename: 'src/app.ts',
56
+ status: 'modified',
57
+ additions: 2,
58
+ deletions: 1,
59
+ changes: 3,
60
+ patch: '@@ -8,2 +8,3 @@\n context line\n+new line\n-removed line',
61
+ },
62
+ {
63
+ filename: 'src/old.ts',
64
+ status: 'removed',
65
+ additions: 0,
66
+ deletions: 5,
67
+ changes: 5,
68
+ patch: '@@ -1 +0,0 @@\n-old line',
69
+ },
70
+ ]);
71
+ });
72
+ it('loads PR context once and forwards diff-aware validators to unified review', async () => {
73
+ await reviewPR(baseConfig, baseOptions);
74
+ expect(createGitHubClient).toHaveBeenCalledTimes(1);
75
+ expect(mockGitHubClient.getPullRequest).toHaveBeenCalledWith('octocat', 'hello-world', 17);
76
+ expect(mockGitHubClient.getPRFiles).toHaveBeenCalledWith('octocat', 'hello-world', 17);
77
+ const unifiedOptions = vi.mocked(executeUnifiedReview).mock.calls[0][1];
78
+ expect(unifiedOptions.pullRequest).toEqual(expect.objectContaining({
79
+ number: 17,
80
+ title: 'Test PR',
81
+ headSha: 'head-sha',
82
+ }));
83
+ expect(unifiedOptions.changedFiles).toEqual(expect.arrayContaining([
84
+ expect.objectContaining({ filename: 'src/app.ts', status: 'modified' }),
85
+ expect.objectContaining({ filename: 'src/old.ts', status: 'removed' }),
86
+ ]));
87
+ expect(unifiedOptions.lineValidator?.isValidLine('src/app.ts', 8)).toBe(true);
88
+ expect(unifiedOptions.lineValidator?.isValidLine('src/app.ts', 9)).toBe(true);
89
+ expect(unifiedOptions.lineValidator?.isValidLine('src/app.ts', 10)).toBe(false);
90
+ expect(unifiedOptions.lineValidator?.isValidLine('src/old.ts', 1)).toBe(false);
91
+ const inlinePosition = unifiedOptions.createInlinePosition?.({
92
+ category: 'QUALITY',
93
+ severity: 'HIGH',
94
+ title: 'Example issue',
95
+ file: 'src/app.ts',
96
+ line: 9,
97
+ problem: 'Problem',
98
+ solution: 'Solution',
99
+ agent: 'quality',
100
+ }, {
101
+ head: {
102
+ sha: 'ignored-sha',
103
+ },
104
+ });
105
+ expect(inlinePosition).toEqual({
106
+ path: 'src/app.ts',
107
+ line: 9,
108
+ commitSha: 'head-sha',
109
+ });
110
+ });
111
+ it('rejects with actionable guidance when GITHUB_TOKEN is missing', async () => {
112
+ createGitHubClient.mockImplementationOnce(() => {
113
+ throw new Error('GITHUB_TOKEN environment variable is required');
114
+ });
115
+ await expect(reviewPR(baseConfig, baseOptions)).rejects.toThrow('Set GITHUB_TOKEN');
116
+ expect(executeUnifiedReview).not.toHaveBeenCalled();
117
+ });
118
+ it('maps GitHub authentication failures to actionable errors', async () => {
119
+ const authError = Object.assign(new Error('Bad credentials'), { status: 401 });
120
+ mockGitHubClient.getPullRequest.mockRejectedValueOnce(authError);
121
+ await expect(reviewPR(baseConfig, baseOptions)).rejects.toThrow('GitHub authentication failed for octocat/hello-world#17');
122
+ expect(executeUnifiedReview).not.toHaveBeenCalled();
123
+ });
124
+ it('maps GitHub not found failures with repository/pr remediation', async () => {
125
+ const notFoundError = Object.assign(new Error('Not Found'), { status: 404 });
126
+ mockGitHubClient.getPullRequest.mockRejectedValueOnce(notFoundError);
127
+ await expect(reviewPR(baseConfig, baseOptions)).rejects.toThrow('GitHub pull request not found: octocat/hello-world#17');
128
+ expect(executeUnifiedReview).not.toHaveBeenCalled();
129
+ });
130
+ it('maps GitHub rate limit failures with retry guidance', async () => {
131
+ const rateLimitError = Object.assign(new Error('API rate limit exceeded'), { status: 403 });
132
+ mockGitHubClient.getPRFiles.mockRejectedValueOnce(rateLimitError);
133
+ await expect(reviewPR(baseConfig, baseOptions)).rejects.toThrow('GitHub API rate limit reached while loading octocat/hello-world#17');
134
+ expect(executeUnifiedReview).not.toHaveBeenCalled();
135
+ });
136
+ });
137
+ //# sourceMappingURL=review-pr.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-pr.test.js","sourceRoot":"","sources":["../../src/cli/review-pr.test.ts"],"names":[],"mappings":"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"}
@@ -82,9 +82,9 @@ function resolveBaseBranch(cliBaseBranch, targetBranch) {
82
82
  };
83
83
  }
84
84
  export async function showChanges(config, options) {
85
- const workingDir = options.workingDir || process.cwd();
86
- const isGitHub = Boolean(options.owner || options.repo || options.prNumber);
87
- const isGitLab = Boolean(options.projectId || options.mrIid);
85
+ const workingDir = options.workingDir ?? process.cwd();
86
+ const isGitHub = Boolean(options.owner ?? options.repo ?? options.prNumber);
87
+ const isGitLab = Boolean(options.projectId ?? options.mrIid);
88
88
  if (isGitHub && isGitLab) {
89
89
  throw new Error('Specify either GitHub options (--owner/--repo/--pr) or GitLab options (--project/--mr), not both.');
90
90
  }
@@ -177,7 +177,7 @@ async function writeOutput(payload, outputPath, jsonOutput, workingDir = process
177
177
  await writeFile(fullPath, output, 'utf-8');
178
178
  console.log(chalk.green(`✓ Output written to ${outputPath}\n`));
179
179
  }
180
- if (jsonOutput || !outputPath) {
180
+ if (jsonOutput ?? !outputPath) {
181
181
  console.log(output);
182
182
  }
183
183
  }
@@ -18,7 +18,7 @@ export class GitHubPlatformAdapter {
18
18
  return {
19
19
  number: pr.number,
20
20
  title: pr.title,
21
- description: pr.body || undefined,
21
+ description: pr.body ?? undefined,
22
22
  author: pr.user?.login || 'Unknown',
23
23
  sourceBranch: pr.head.ref,
24
24
  targetBranch: pr.base.ref,
@@ -43,7 +43,7 @@ export class GitHubPlatformAdapter {
43
43
  const comments = await this.client.listPRComments(owner, repo, prNumber);
44
44
  return comments.map((c) => ({
45
45
  id: c.id,
46
- body: c.body || '',
46
+ body: c.body ?? '',
47
47
  }));
48
48
  }
49
49
  async getInlineComments(projectId, prNumber) {
@@ -100,7 +100,7 @@ export class GitLabClient {
100
100
  * Create a GitLab client from environment variables
101
101
  */
102
102
  export function createGitLabClient() {
103
- const url = process.env.GITLAB_URL || 'https://gitlab.com';
103
+ const url = process.env.GITLAB_URL ?? 'https://gitlab.com';
104
104
  const token = process.env.GITLAB_TOKEN;
105
105
  if (!token) {
106
106
  throw new Error('GITLAB_TOKEN environment variable is required');
@@ -42,7 +42,7 @@ export function convertToCodeQualityIssue(issue) {
42
42
  location: {
43
43
  path: issue.file,
44
44
  lines: {
45
- begin: issue.line || 1,
45
+ begin: issue.line ?? 1,
46
46
  },
47
47
  },
48
48
  };
@@ -12,6 +12,7 @@ export interface ReviewIssue {
12
12
  agent: string;
13
13
  }
14
14
  import type { ChangeSummary } from './change-summary.js';
15
+ import type { ReviewUsageSummary } from './review-usage.js';
15
16
  export interface ReviewSummary {
16
17
  filesReviewed: number;
17
18
  issuesFound: number;
@@ -27,7 +28,7 @@ export declare function formatIssueComment(issue: ReviewIssue, fingerprint?: str
27
28
  * Format a review summary as a GitLab comment
28
29
  * @param commentId Optional comment ID to embed for update identification
29
30
  */
30
- export declare function formatSummaryComment(summary: ReviewSummary, issues: ReviewIssue[], commentId?: string, changeSummary?: ChangeSummary): string;
31
+ export declare function formatSummaryComment(summary: ReviewSummary, issues: ReviewIssue[], commentId?: string, changeSummary?: ChangeSummary, reviewUsage?: ReviewUsageSummary): string;
31
32
  /**
32
33
  * Format issue for terminal output with colors
33
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"comment-formatter.d.ts","sourceRoot":"","sources":["../../src/lib/comment-formatter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACnE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;AAE/F,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;CAC3C;AAiBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CA0BnF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,WAAW,EAAE,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,aAAa,GAC5B,MAAM,CA2FR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAY9D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAc7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,CAyB5F"}
1
+ {"version":3,"file":"comment-formatter.d.ts","sourceRoot":"","sources":["../../src/lib/comment-formatter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACnE,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;AAE/F,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;CAC3C;AAoDD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CA0BnF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,WAAW,EAAE,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,aAAa,EAC7B,WAAW,CAAC,EAAE,kBAAkB,GAC/B,MAAM,CA+FR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAY9D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAc7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,CAyB5F"}
@@ -1,3 +1,4 @@
1
+ import { formatCost, formatCount } from './format-utils.js';
1
2
  const SEVERITY_EMOJI = {
2
3
  CRITICAL: '🔴',
3
4
  HIGH: '🟡',
@@ -11,6 +12,34 @@ const CATEGORY_EMOJI = {
11
12
  PERFORMANCE: '⚡',
12
13
  DOCUMENTATION: '📝',
13
14
  };
15
+ function formatReviewUsageSection(usage) {
16
+ const total = usage.total;
17
+ let markdown = `## 💰 Model Usage\n\n`;
18
+ markdown += `<details>\n<summary>View token and cost breakdown</summary>\n\n`;
19
+ markdown += `### Run Totals\n\n`;
20
+ markdown += `- **Input Tokens**: ${formatCount(total.input)}\n`;
21
+ markdown += `- **Output Tokens**: ${formatCount(total.output)}\n`;
22
+ markdown += `- **Cache Read Tokens**: ${formatCount(total.cacheRead)}\n`;
23
+ markdown += `- **Cache Write Tokens**: ${formatCount(total.cacheWrite)}\n`;
24
+ markdown += `- **Total Tokens**: ${formatCount(total.totalTokens)}\n`;
25
+ markdown += `- **Estimated Cost**: ${formatCost(total.cost)}\n`;
26
+ if (total.totalTokens > 0 && total.cost === 0) {
27
+ markdown +=
28
+ '- _Cost is $0.0000 because model pricing is unknown or configured as free. Add `pricing.models` in `.drs/drs.config.yaml` to override._\n';
29
+ }
30
+ markdown += `\n`;
31
+ if (usage.agents.length > 0) {
32
+ markdown += `### By Agent\n\n`;
33
+ markdown += `| Agent | Model | Turns | Input | Output | Cache Read | Cache Write | Total Tokens | Cost | Status |\n`;
34
+ markdown += `| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |\n`;
35
+ for (const agent of usage.agents) {
36
+ markdown += `| ${agent.agentType} | ${agent.model ?? 'n/a'} | ${formatCount(agent.turns)} | ${formatCount(agent.usage.input)} | ${formatCount(agent.usage.output)} | ${formatCount(agent.usage.cacheRead)} | ${formatCount(agent.usage.cacheWrite)} | ${formatCount(agent.usage.totalTokens)} | ${formatCost(agent.usage.cost)} | ${agent.success === false ? 'failed' : 'ok'} |\n`;
37
+ }
38
+ markdown += `\n`;
39
+ }
40
+ markdown += `</details>\n\n`;
41
+ return markdown;
42
+ }
14
43
  /**
15
44
  * Format a single review issue as a GitLab comment
16
45
  * @param fingerprint Optional fingerprint to embed in comment for deduplication
@@ -41,7 +70,7 @@ export function formatIssueComment(issue, fingerprint) {
41
70
  * Format a review summary as a GitLab comment
42
71
  * @param commentId Optional comment ID to embed for update identification
43
72
  */
44
- export function formatSummaryComment(summary, issues, commentId, changeSummary) {
73
+ export function formatSummaryComment(summary, issues, commentId, changeSummary, reviewUsage) {
45
74
  // Add hidden identifier for update-or-create logic
46
75
  let comment = '';
47
76
  if (commentId) {
@@ -62,6 +91,9 @@ export function formatSummaryComment(summary, issues, commentId, changeSummary)
62
91
  comment += `## 📊 Statistics\n\n`;
63
92
  comment += `- **Files Reviewed**: ${summary.filesReviewed}\n`;
64
93
  comment += `- **Total Issues**: ${summary.issuesFound}\n\n`;
94
+ if (reviewUsage) {
95
+ comment += formatReviewUsageSection(reviewUsage);
96
+ }
65
97
  if (summary.issuesFound > 0) {
66
98
  comment += `### By Severity\n`;
67
99
  comment += `- ${SEVERITY_EMOJI.CRITICAL} **Critical**: ${summary.bySeverity.CRITICAL}\n`;
@@ -1 +1 @@
1
- {"version":3,"file":"comment-formatter.js","sourceRoot":"","sources":["../../src/lib/comment-formatter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"comment-formatter.js","sourceRoot":"","sources":["../../src/lib/comment-formatter.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAU5D,MAAM,cAAc,GAAkC;IACpD,QAAQ,EAAE,IAAI;IACd,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,MAAM,cAAc,GAAkC;IACpD,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,GAAG;IACV,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,IAAI;CACpB,CAAC;AAEF,SAAS,wBAAwB,CAAC,KAAyB;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAE1B,IAAI,QAAQ,GAAG,uBAAuB,CAAC;IACvC,QAAQ,IAAI,iEAAiE,CAAC;IAC9E,QAAQ,IAAI,oBAAoB,CAAC;IACjC,QAAQ,IAAI,uBAAuB,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;IAChE,QAAQ,IAAI,wBAAwB,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;IAClE,QAAQ,IAAI,4BAA4B,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC;IACzE,QAAQ,IAAI,6BAA6B,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;IAC3E,QAAQ,IAAI,uBAAuB,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC;IACtE,QAAQ,IAAI,yBAAyB,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IAChE,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAC9C,QAAQ;YACN,2IAA2I,CAAC;IAChJ,CAAC;IACD,QAAQ,IAAI,IAAI,CAAC;IAEjB,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,QAAQ,IAAI,kBAAkB,CAAC;QAC/B,QAAQ,IAAI,wGAAwG,CAAC;QACrH,QAAQ,IAAI,wEAAwE,CAAC;QAErF,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,QAAQ,IAAI,KAAK,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,KAAK,IAAI,KAAK,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;QACtX,CAAC;QAED,QAAQ,IAAI,IAAI,CAAC;IACnB,CAAC;IAED,QAAQ,IAAI,gBAAgB,CAAC;IAE7B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAkB,EAAE,WAAoB;IACzE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAErD,2CAA2C;IAC3C,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,IAAI,kBAAkB,WAAW,QAAQ,CAAC;IACnD,CAAC;IAED,OAAO,IAAI,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,KAAK,MAAM,CAAC;IAChE,OAAO,IAAI,eAAe,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAChF,OAAO,IAAI,iBAAiB,aAAa,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC;IAChE,OAAO,IAAI,oBAAoB,KAAK,CAAC,KAAK,MAAM,CAAC;IAEjD,OAAO,IAAI,gBAAgB,KAAK,CAAC,OAAO,MAAM,CAAC;IAC/C,OAAO,IAAI,iBAAiB,KAAK,CAAC,QAAQ,IAAI,CAAC;IAE/C,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,IAAI,oBAAoB,CAAC;QAChC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACnC,OAAO,IAAI,KAAK,GAAG,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAsB,EACtB,MAAqB,EACrB,SAAkB,EAClB,aAA6B,EAC7B,WAAgC;IAEhC,mDAAmD;IACnD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,IAAI,wBAAwB,SAAS,QAAQ,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,+BAA+B,CAAC;IAE3C,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,0BAA0B,CAAC;QACtC,OAAO,IAAI,GAAG,aAAa,CAAC,WAAW,MAAM,CAAC;QAC9C,OAAO,IAAI,eAAe,aAAa,CAAC,IAAI,IAAI,CAAC;QACjD,OAAO,IAAI,qBAAqB,aAAa,CAAC,UAAU,IAAI,CAAC;QAC7D,OAAO,IAAI,qBAAqB,aAAa,CAAC,SAAS,IAAI,CAAC;QAC5D,IAAI,aAAa,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxC,OAAO,IAAI,8BAA8B,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACnF,CAAC;QACD,OAAO,IAAI,IAAI,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,sBAAsB,CAAC;IAClC,OAAO,IAAI,yBAAyB,OAAO,CAAC,aAAa,IAAI,CAAC;IAC9D,OAAO,IAAI,uBAAuB,OAAO,CAAC,WAAW,MAAM,CAAC;IAE5D,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,IAAI,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,mBAAmB,CAAC;QAC/B,OAAO,IAAI,KAAK,cAAc,CAAC,QAAQ,kBAAkB,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC;QACzF,OAAO,IAAI,KAAK,cAAc,CAAC,IAAI,cAAc,OAAO,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;QAC7E,OAAO,IAAI,KAAK,cAAc,CAAC,MAAM,gBAAgB,OAAO,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC;QACnF,OAAO,IAAI,KAAK,cAAc,CAAC,GAAG,aAAa,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC;QAE5E,OAAO,IAAI,mBAAmB,CAAC;QAC/B,OAAO,IAAI,KAAK,cAAc,CAAC,QAAQ,kBAAkB,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC;QACzF,OAAO,IAAI,KAAK,cAAc,CAAC,OAAO,iBAAiB,OAAO,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC;QACtF,OAAO,IAAI,KAAK,cAAc,CAAC,KAAK,eAAe,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;QAChF,OAAO,IAAI,KAAK,cAAc,CAAC,WAAW,qBAAqB,OAAO,CAAC,UAAU,CAAC,WAAW,IAAI,CAAC;QAClG,OAAO,IAAI,KAAK,cAAc,CAAC,aAAa,uBAAuB,OAAO,CAAC,UAAU,CAAC,aAAa,MAAM,CAAC;QAE1G,2BAA2B;QAC3B,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;QACvE,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;QAE7D,0CAA0C;QAC1C,MAAM,kBAAkB,GAAG,CAAC,KAAkB,EAAE,EAAE;YAChD,IAAI,OAAO,GAAG,OAAO,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,KAAK,MAAM,CAAC;YACzE,OAAO,IAAI,eAAe,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,sBAAsB,KAAK,CAAC,QAAQ,MAAM,CAAC;YACpH,OAAO,IAAI,gBAAgB,KAAK,CAAC,OAAO,MAAM,CAAC;YAC/C,OAAO,IAAI,iBAAiB,KAAK,CAAC,QAAQ,IAAI,CAAC;YAC/C,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpD,OAAO,IAAI,qBAAqB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAClE,CAAC;YACD,OAAO,OAAO,GAAG,IAAI,CAAC;QACxB,CAAC,CAAC;QAEF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,2BAA2B,CAAC;YACvC,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;gBACnC,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,gCAAgC,CAAC;YAC5C,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;gBAC/B,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,kCAAkC,CAAC;YAC9C,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBACjC,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,8BAA8B,CAAC;YAC1C,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;gBAC9B,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,+CAA+C,CAAC;IAC7D,CAAC;IAED,OAAO,IAAI,uDAAuD,CAAC;IAEnE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAErD,IAAI,MAAM,GAAG,2CAA2C,CAAC;IACzD,MAAM,IAAI,GAAG,aAAa,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,KAAK,IAAI,CAAC;IAC9F,MAAM,IAAI,yCAAyC,CAAC;IACpD,MAAM,IAAI,MAAM,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACtE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,MAAM,CAAC;IACjC,MAAM,IAAI,UAAU,KAAK,CAAC,QAAQ,IAAI,CAAC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAkB;IACnD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,IAAI,wBAAwB,SAAS,QAAQ,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,mCAAmC,CAAC;IAC/C,OAAO,IAAI,4EAA4E,CAAC;IACxF,OAAO,IAAI,oDAAoD,CAAC;IAChE,OAAO,IAAI,SAAS,CAAC;IACrB,OAAO,IAAI,0EAA0E,CAAC;IACtF,OAAO,IAAI,8CAA8C,CAAC;IAE1D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,aAAqB,EAAE,MAAqB;IAC3E,MAAM,OAAO,GAAkB;QAC7B,aAAa;QACb,WAAW,EAAE,MAAM,CAAC,MAAM;QAC1B,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,CAAC;YACT,GAAG,EAAE,CAAC;SACP;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,CAAC;YACR,WAAW,EAAE,CAAC;YACd,aAAa,EAAE,CAAC;SACjB;KACF,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;IACvC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -289,6 +289,49 @@ describe('comment-formatter', () => {
289
289
  expect(formatted).toContain('Minor fix');
290
290
  expect(formatted).not.toContain('Affected Subsystems');
291
291
  });
292
+ it('should include expandable usage block when usage data is provided', () => {
293
+ const summary = {
294
+ filesReviewed: 3,
295
+ issuesFound: 0,
296
+ bySeverity: { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 },
297
+ byCategory: { SECURITY: 0, QUALITY: 0, STYLE: 0, PERFORMANCE: 0, DOCUMENTATION: 0 },
298
+ };
299
+ const usage = {
300
+ total: {
301
+ input: 1234,
302
+ output: 234,
303
+ cacheRead: 500,
304
+ cacheWrite: 0,
305
+ totalTokens: 1968,
306
+ cost: 0.0423,
307
+ },
308
+ agents: [
309
+ {
310
+ agentType: 'unified-reviewer',
311
+ model: 'opencode/glm-5-free',
312
+ turns: 4,
313
+ success: true,
314
+ usage: {
315
+ input: 1234,
316
+ output: 234,
317
+ cacheRead: 500,
318
+ cacheWrite: 0,
319
+ totalTokens: 1968,
320
+ cost: 0.0423,
321
+ },
322
+ },
323
+ ],
324
+ };
325
+ const formatted = formatSummaryComment(summary, [], undefined, undefined, usage);
326
+ expect(formatted).toContain('💰 Model Usage');
327
+ expect(formatted).toContain('<details>');
328
+ expect(formatted).toContain('View token and cost breakdown');
329
+ expect(formatted).toContain('| Agent | Model | Turns | Input | Output | Cache Read |');
330
+ expect(formatted).toContain('unified-reviewer');
331
+ expect(formatted).toContain('opencode/glm-5-free');
332
+ expect(formatted).toContain('$0.0423');
333
+ expect(formatted).toContain('</details>');
334
+ });
292
335
  });
293
336
  describe('formatTerminalIssue', () => {
294
337
  it('should format issue for terminal output', () => {