@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.
- package/README.md +228 -92
- package/dist/ci/runner.d.ts.map +1 -1
- package/dist/ci/runner.js +19 -22
- package/dist/ci/runner.js.map +1 -1
- package/dist/cli/describe-mr.d.ts.map +1 -1
- package/dist/cli/describe-mr.js +39 -20
- package/dist/cli/describe-mr.js.map +1 -1
- package/dist/cli/describe-pr.d.ts.map +1 -1
- package/dist/cli/describe-pr.js +39 -20
- package/dist/cli/describe-pr.js.map +1 -1
- package/dist/cli/index.js +11 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +30 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/post-comments.d.ts.map +1 -1
- package/dist/cli/post-comments.js +5 -5
- package/dist/cli/post-comments.js.map +1 -1
- package/dist/cli/review-local.d.ts.map +1 -1
- package/dist/cli/review-local.integration.test.d.ts +2 -0
- package/dist/cli/review-local.integration.test.d.ts.map +1 -0
- package/dist/cli/review-local.integration.test.js +343 -0
- package/dist/cli/review-local.integration.test.js.map +1 -0
- package/dist/cli/review-local.js +5 -4
- package/dist/cli/review-local.js.map +1 -1
- package/dist/cli/review-local.live.e2e.test.d.ts +2 -0
- package/dist/cli/review-local.live.e2e.test.d.ts.map +1 -0
- package/dist/cli/review-local.live.e2e.test.js +154 -0
- package/dist/cli/review-local.live.e2e.test.js.map +1 -0
- package/dist/cli/review-local.test.d.ts +2 -0
- package/dist/cli/review-local.test.d.ts.map +1 -0
- package/dist/cli/review-local.test.js +164 -0
- package/dist/cli/review-local.test.js.map +1 -0
- package/dist/cli/review-mr.d.ts +1 -1
- package/dist/cli/review-mr.d.ts.map +1 -1
- package/dist/cli/review-mr.js +92 -17
- package/dist/cli/review-mr.js.map +1 -1
- package/dist/cli/review-mr.test.d.ts +2 -0
- package/dist/cli/review-mr.test.d.ts.map +1 -0
- package/dist/cli/review-mr.test.js +142 -0
- package/dist/cli/review-mr.test.js.map +1 -0
- package/dist/cli/review-pr.d.ts +1 -1
- package/dist/cli/review-pr.d.ts.map +1 -1
- package/dist/cli/review-pr.js +96 -13
- package/dist/cli/review-pr.js.map +1 -1
- package/dist/cli/review-pr.test.d.ts +2 -0
- package/dist/cli/review-pr.test.d.ts.map +1 -0
- package/dist/cli/review-pr.test.js +137 -0
- package/dist/cli/review-pr.test.js.map +1 -0
- package/dist/cli/show-changes.js +4 -4
- package/dist/github/platform-adapter.js +2 -2
- package/dist/gitlab/client.js +1 -1
- package/dist/lib/code-quality-report.js +1 -1
- package/dist/lib/comment-formatter.d.ts +2 -1
- package/dist/lib/comment-formatter.d.ts.map +1 -1
- package/dist/lib/comment-formatter.js +33 -1
- package/dist/lib/comment-formatter.js.map +1 -1
- package/dist/lib/comment-formatter.test.js +43 -0
- package/dist/lib/comment-formatter.test.js.map +1 -1
- package/dist/lib/comment-manager.d.ts.map +1 -1
- package/dist/lib/comment-manager.js +4 -3
- package/dist/lib/comment-manager.js.map +1 -1
- package/dist/lib/comment-poster.d.ts +2 -1
- package/dist/lib/comment-poster.d.ts.map +1 -1
- package/dist/lib/comment-poster.js +2 -2
- package/dist/lib/comment-poster.js.map +1 -1
- package/dist/lib/comment-poster.test.js +27 -11
- package/dist/lib/comment-poster.test.js.map +1 -1
- package/dist/lib/config-model-overrides.test.d.ts +1 -1
- package/dist/lib/config-model-overrides.test.js +2 -2
- package/dist/lib/config-model-overrides.test.js.map +1 -1
- package/dist/lib/config.d.ts +34 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +35 -13
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.js +16 -0
- package/dist/lib/config.test.js.map +1 -1
- package/dist/lib/context-compression.d.ts +27 -1
- package/dist/lib/context-compression.d.ts.map +1 -1
- package/dist/lib/context-compression.js +106 -4
- package/dist/lib/context-compression.js.map +1 -1
- package/dist/lib/context-compression.test.js +305 -1
- package/dist/lib/context-compression.test.js.map +1 -1
- package/dist/lib/context-loader.d.ts +3 -2
- package/dist/lib/context-loader.d.ts.map +1 -1
- package/dist/lib/context-loader.js +11 -11
- package/dist/lib/context-loader.js.map +1 -1
- package/dist/lib/description-executor.d.ts +19 -2
- package/dist/lib/description-executor.d.ts.map +1 -1
- package/dist/lib/description-executor.js +52 -21
- package/dist/lib/description-executor.js.map +1 -1
- package/dist/lib/description-executor.test.d.ts +2 -0
- package/dist/lib/description-executor.test.d.ts.map +1 -0
- package/dist/lib/description-executor.test.js +120 -0
- package/dist/lib/description-executor.test.js.map +1 -0
- package/dist/lib/description-formatter.d.ts +8 -3
- package/dist/lib/description-formatter.d.ts.map +1 -1
- package/dist/lib/description-formatter.js +88 -13
- package/dist/lib/description-formatter.js.map +1 -1
- package/dist/lib/description-formatter.test.d.ts +2 -0
- package/dist/lib/description-formatter.test.d.ts.map +1 -0
- package/dist/lib/description-formatter.test.js +57 -0
- package/dist/lib/description-formatter.test.js.map +1 -0
- package/dist/lib/diff-parser.test.d.ts +2 -0
- package/dist/lib/diff-parser.test.d.ts.map +1 -0
- package/dist/lib/diff-parser.test.js +335 -0
- package/dist/lib/diff-parser.test.js.map +1 -0
- package/dist/lib/exit.d.ts +35 -0
- package/dist/lib/exit.d.ts.map +1 -0
- package/dist/lib/exit.js +53 -0
- package/dist/lib/exit.js.map +1 -0
- package/dist/lib/exit.test.d.ts +2 -0
- package/dist/lib/exit.test.d.ts.map +1 -0
- package/dist/lib/exit.test.js +120 -0
- package/dist/lib/exit.test.js.map +1 -0
- package/dist/lib/format-utils.d.ts +3 -0
- package/dist/lib/format-utils.d.ts.map +1 -0
- package/dist/lib/format-utils.js +7 -0
- package/dist/lib/format-utils.js.map +1 -0
- package/dist/lib/json-output.d.ts +4 -1
- package/dist/lib/json-output.d.ts.map +1 -1
- package/dist/lib/json-output.js +2 -1
- package/dist/lib/json-output.js.map +1 -1
- package/dist/lib/json-output.test.d.ts +2 -0
- package/dist/lib/json-output.test.d.ts.map +1 -0
- package/dist/lib/json-output.test.js +135 -0
- package/dist/lib/json-output.test.js.map +1 -0
- package/dist/lib/logger.d.ts +10 -2
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +22 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/logger.test.d.ts +2 -0
- package/dist/lib/logger.test.d.ts.map +1 -0
- package/dist/lib/logger.test.js +324 -0
- package/dist/lib/logger.test.js.map +1 -0
- package/dist/lib/position-validator.test.d.ts +2 -0
- package/dist/lib/position-validator.test.d.ts.map +1 -0
- package/dist/lib/position-validator.test.js +128 -0
- package/dist/lib/position-validator.test.js.map +1 -0
- package/dist/lib/repository-validator.js +1 -1
- package/dist/lib/review-core.d.ts +9 -4
- package/dist/lib/review-core.d.ts.map +1 -1
- package/dist/lib/review-core.js +207 -112
- package/dist/lib/review-core.js.map +1 -1
- package/dist/lib/review-core.test.js +76 -30
- package/dist/lib/review-core.test.js.map +1 -1
- package/dist/lib/review-orchestrator.d.ts +12 -7
- package/dist/lib/review-orchestrator.d.ts.map +1 -1
- package/dist/lib/review-orchestrator.js +78 -22
- package/dist/lib/review-orchestrator.js.map +1 -1
- package/dist/lib/review-orchestrator.test.js +160 -42
- package/dist/lib/review-orchestrator.test.js.map +1 -1
- package/dist/lib/review-parser.test.d.ts +2 -0
- package/dist/lib/review-parser.test.d.ts.map +1 -0
- package/dist/lib/review-parser.test.js +130 -0
- package/dist/lib/review-parser.test.js.map +1 -0
- package/dist/lib/review-usage.d.ts +32 -0
- package/dist/lib/review-usage.d.ts.map +1 -0
- package/dist/lib/review-usage.js +72 -0
- package/dist/lib/review-usage.js.map +1 -0
- package/dist/lib/review-usage.test.d.ts +2 -0
- package/dist/lib/review-usage.test.d.ts.map +1 -0
- package/dist/lib/review-usage.test.js +83 -0
- package/dist/lib/review-usage.test.js.map +1 -0
- package/dist/lib/unified-review-executor.d.ts +6 -2
- package/dist/lib/unified-review-executor.d.ts.map +1 -1
- package/dist/lib/unified-review-executor.js +54 -28
- package/dist/lib/unified-review-executor.js.map +1 -1
- package/dist/lib/unified-review-executor.test.js +138 -16
- package/dist/lib/unified-review-executor.test.js.map +1 -1
- package/dist/lib/write-json-output.test.d.ts +2 -0
- package/dist/lib/write-json-output.test.d.ts.map +1 -0
- package/dist/lib/write-json-output.test.js +259 -0
- package/dist/lib/write-json-output.test.js.map +1 -0
- package/dist/pi/sdk.d.ts +94 -0
- package/dist/pi/sdk.d.ts.map +1 -0
- package/dist/pi/sdk.js +486 -0
- package/dist/pi/sdk.js.map +1 -0
- package/dist/pi/sdk.test.d.ts +2 -0
- package/dist/pi/sdk.test.d.ts.map +1 -0
- package/dist/pi/sdk.test.js +331 -0
- package/dist/pi/sdk.test.js.map +1 -0
- package/dist/{opencode → runtime}/agent-loader.d.ts +7 -5
- package/dist/runtime/agent-loader.d.ts.map +1 -0
- package/dist/{opencode → runtime}/agent-loader.js +24 -19
- package/dist/runtime/agent-loader.js.map +1 -0
- package/dist/runtime/agent-loader.test.d.ts +2 -0
- package/dist/runtime/agent-loader.test.d.ts.map +1 -0
- package/dist/runtime/agent-loader.test.js +280 -0
- package/dist/runtime/agent-loader.test.js.map +1 -0
- package/dist/runtime/built-in-paths.d.ts +2 -0
- package/dist/runtime/built-in-paths.d.ts.map +1 -0
- package/dist/runtime/built-in-paths.js +14 -0
- package/dist/runtime/built-in-paths.js.map +1 -0
- package/dist/{opencode → runtime}/client.d.ts +35 -18
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +486 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/{opencode → runtime}/client.test.d.ts.map +1 -1
- package/dist/runtime/client.test.js +392 -0
- package/dist/runtime/client.test.js.map +1 -0
- package/dist/runtime/path-config.d.ts +8 -0
- package/dist/runtime/path-config.d.ts.map +1 -0
- package/dist/runtime/path-config.js +68 -0
- package/dist/runtime/path-config.js.map +1 -0
- package/dist/runtime/path-config.test.d.ts +2 -0
- package/dist/runtime/path-config.test.d.ts.map +1 -0
- package/dist/runtime/path-config.test.js +103 -0
- package/dist/runtime/path-config.test.js.map +1 -0
- package/package.json +5 -5
- package/.opencode/opencode.jsonc +0 -15
- package/.opencode/tool/write_json_output.ts +0 -24
- package/.opencode/tools/drs_skill.ts +0 -67
- package/dist/lib/skills-prompt.d.ts +0 -3
- package/dist/lib/skills-prompt.d.ts.map +0 -1
- package/dist/lib/skills-prompt.js +0 -70
- package/dist/lib/skills-prompt.js.map +0 -1
- package/dist/opencode/agent-loader.d.ts.map +0 -1
- package/dist/opencode/agent-loader.js.map +0 -1
- package/dist/opencode/client.d.ts.map +0 -1
- package/dist/opencode/client.js +0 -456
- package/dist/opencode/client.js.map +0 -1
- package/dist/opencode/client.test.js +0 -317
- package/dist/opencode/client.test.js.map +0 -1
- package/dist/opencode/opencode-paths.d.ts +0 -2
- package/dist/opencode/opencode-paths.d.ts.map +0 -1
- package/dist/opencode/opencode-paths.js +0 -7
- package/dist/opencode/opencode-paths.js.map +0 -1
- package/dist/opencode/skill-loader.d.ts +0 -15
- package/dist/opencode/skill-loader.d.ts.map +0 -1
- package/dist/opencode/skill-loader.js +0 -88
- package/dist/opencode/skill-loader.js.map +0 -1
- /package/{.opencode/agent → .pi/agents}/describe/pr-describer.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/documentation.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/performance.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/quality.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/security.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/style.md +0 -0
- /package/{.opencode/agent → .pi/agents}/review/unified-reviewer.md +0 -0
- /package/dist/{opencode → runtime}/client.test.d.ts +0 -0
package/dist/cli/review-pr.js
CHANGED
|
@@ -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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
68
|
-
const data = platformData;
|
|
149
|
+
const createInlinePosition = (issue, _platformData) => {
|
|
69
150
|
return {
|
|
70
151
|
path: issue.file,
|
|
71
152
|
line: issue.line,
|
|
72
|
-
commitSha:
|
|
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":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"review-pr.js","sourceRoot":"","sources":["../../src/cli/review-pr.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|
package/dist/cli/show-changes.js
CHANGED
|
@@ -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
|
|
86
|
-
const isGitHub = Boolean(options.owner
|
|
87
|
-
const isGitLab = Boolean(options.projectId
|
|
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
|
|
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
|
|
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) {
|
package/dist/gitlab/client.js
CHANGED
|
@@ -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
|
|
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');
|
|
@@ -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;
|
|
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":"
|
|
1
|
+
{"version":3,"file":"comment-formatter.js","sourceRoot":"","sources":["../../src/lib/comment-formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -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', () => {
|