codeant-cli 0.3.1 → 0.3.3

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 (69) hide show
  1. package/dist/178.index.js +1 -1
  2. package/dist/239.index.js +1 -1
  3. package/dist/701.index.js +1 -1
  4. package/dist/880.index.js +1 -1
  5. package/dist/935.index.js +1 -1
  6. package/dist/966.index.js +1 -1
  7. package/dist/index.js +5 -5
  8. package/dist/review/239.index.js +1 -0
  9. package/dist/review/index.js +8 -0
  10. package/dist/review/package.json +3 -0
  11. package/package.json +5 -6
  12. package/src/commands/getBaseUrl.js +0 -21
  13. package/src/commands/login.js +0 -125
  14. package/src/commands/logout.js +0 -30
  15. package/src/commands/review.js +0 -294
  16. package/src/commands/secrets.js +0 -148
  17. package/src/commands/setBaseUrl.js +0 -37
  18. package/src/components/ReviewUI.js +0 -410
  19. package/src/components/SecretsUI.js +0 -366
  20. package/src/components/Welcome.js +0 -144
  21. package/src/index.js +0 -349
  22. package/src/reviewHeadless.js +0 -198
  23. package/src/scm/azure/client.js +0 -21
  24. package/src/scm/azure/getCodeReview.js +0 -20
  25. package/src/scm/azure/getPullRequest.js +0 -30
  26. package/src/scm/azure/index.js +0 -6
  27. package/src/scm/azure/listCodeReviews.js +0 -17
  28. package/src/scm/azure/listPullRequestComments.js +0 -41
  29. package/src/scm/azure/listPullRequests.js +0 -26
  30. package/src/scm/azure/searchComments.js +0 -35
  31. package/src/scm/bitbucket/client.js +0 -18
  32. package/src/scm/bitbucket/getCodeReview.js +0 -3
  33. package/src/scm/bitbucket/getPullRequest.js +0 -26
  34. package/src/scm/bitbucket/index.js +0 -6
  35. package/src/scm/bitbucket/listCodeReviews.js +0 -17
  36. package/src/scm/bitbucket/listPullRequestComments.js +0 -33
  37. package/src/scm/bitbucket/listPullRequests.js +0 -33
  38. package/src/scm/bitbucket/searchComments.js +0 -29
  39. package/src/scm/github/client.js +0 -17
  40. package/src/scm/github/getCodeReview.js +0 -26
  41. package/src/scm/github/getPullRequest.js +0 -27
  42. package/src/scm/github/index.js +0 -6
  43. package/src/scm/github/listCodeReviews.js +0 -17
  44. package/src/scm/github/listPullRequestComments.js +0 -51
  45. package/src/scm/github/listPullRequests.js +0 -32
  46. package/src/scm/github/searchComments.js +0 -30
  47. package/src/scm/gitlab/client.js +0 -16
  48. package/src/scm/gitlab/getCodeReview.js +0 -18
  49. package/src/scm/gitlab/getPullRequest.js +0 -24
  50. package/src/scm/gitlab/index.js +0 -6
  51. package/src/scm/gitlab/listCodeReviews.js +0 -21
  52. package/src/scm/gitlab/listPullRequestComments.js +0 -44
  53. package/src/scm/gitlab/listPullRequests.js +0 -26
  54. package/src/scm/gitlab/searchComments.js +0 -28
  55. package/src/scm/index.js +0 -96
  56. package/src/tools/executeTool.js +0 -31
  57. package/src/tools/globTool.js +0 -9
  58. package/src/tools/grepTool.js +0 -18
  59. package/src/tools/lsTool.js +0 -7
  60. package/src/tools/readTool.js +0 -12
  61. package/src/utils/analytics.js +0 -45
  62. package/src/utils/baseUrl.js +0 -11
  63. package/src/utils/commonApiHelper.js +0 -143
  64. package/src/utils/config.js +0 -42
  65. package/src/utils/fetchApi.js +0 -39
  66. package/src/utils/gitDiffHelper.js +0 -1203
  67. package/src/utils/reviewApiHelper.js +0 -275
  68. package/src/utils/scmAuth.js +0 -136
  69. package/src/utils/secretsApiHelper.js +0 -242
@@ -1,41 +0,0 @@
1
- import { getConnection, splitRepo } from './client.js';
2
-
3
- export async function listPullRequestComments({ name, prNumber, codeantGenerated, createdAfter, createdBefore }) {
4
- const connection = getConnection();
5
- const gitApi = await connection.getGitApi();
6
- const { project, repo } = splitRepo(name);
7
-
8
- const threads = await gitApi.getThreads(repo, prNumber, project);
9
-
10
- let comments = [];
11
- for (const thread of (threads || [])) {
12
- for (const comment of (thread.comments || [])) {
13
- if (comment.commentType === 'system') continue;
14
- comments.push({
15
- id: comment.id,
16
- threadId: thread.id,
17
- type: thread.threadContext?.filePath ? 'review' : 'issue',
18
- author: comment.author?.displayName || comment.author?.uniqueName,
19
- body: comment.content,
20
- path: thread.threadContext?.filePath || null,
21
- line: thread.threadContext?.rightFileStart?.line || null,
22
- createdAt: comment.publishedDate,
23
- updatedAt: comment.lastUpdatedDate,
24
- isCodeantComment: (comment.author?.displayName || '').toLowerCase().includes('codeant') || comment.content?.includes('Suggestion'),
25
- resolved: thread.status === 2, // Fixed
26
- });
27
- }
28
- }
29
-
30
- if (codeantGenerated !== undefined) {
31
- comments = comments.filter(c => c.isCodeantComment === codeantGenerated);
32
- }
33
- if (createdAfter) {
34
- comments = comments.filter(c => new Date(c.createdAt) >= new Date(createdAfter));
35
- }
36
- if (createdBefore) {
37
- comments = comments.filter(c => new Date(c.createdAt) <= new Date(createdBefore));
38
- }
39
-
40
- return comments;
41
- }
@@ -1,26 +0,0 @@
1
- import { getConnection, splitRepo } from './client.js';
2
-
3
- export async function listPullRequests({ name, sourceBranch, authorLogin, state = 'open', limit = 20 }) {
4
- const connection = getConnection();
5
- const gitApi = await connection.getGitApi();
6
- const { project, repo } = splitRepo(name);
7
-
8
- const statusMap = { open: 1 /* Active */, closed: 3 /* Completed */ };
9
- const searchCriteria = { status: statusMap[state] || 1 };
10
- if (sourceBranch) searchCriteria.sourceRefName = `refs/heads/${sourceBranch}`;
11
- if (authorLogin) searchCriteria.creatorId = authorLogin;
12
-
13
- const prs = await gitApi.getPullRequests(repo, searchCriteria, project, undefined, undefined, limit);
14
-
15
- return (prs || []).map(pr => ({
16
- number: pr.pullRequestId,
17
- title: pr.title,
18
- state: pr.status === 1 ? 'open' : pr.status === 3 ? 'closed' : 'unknown',
19
- merged: pr.status === 3 && pr.closedBy != null,
20
- author: pr.createdBy?.displayName || pr.createdBy?.uniqueName,
21
- sourceBranch: pr.sourceRefName?.replace('refs/heads/', ''),
22
- targetBranch: pr.targetRefName?.replace('refs/heads/', ''),
23
- createdAt: pr.creationDate,
24
- url: pr.url,
25
- }));
26
- }
@@ -1,35 +0,0 @@
1
- import { getConnection, splitRepo } from './client.js';
2
-
3
- export async function searchComments({ name, query, limit = 10 }) {
4
- const connection = getConnection();
5
- const gitApi = await connection.getGitApi();
6
- const { project, repo } = splitRepo(name);
7
-
8
- const prs = await gitApi.getPullRequests(repo, { status: 1 }, project, undefined, undefined, 10);
9
-
10
- let allComments = [];
11
- for (const pr of (prs || [])) {
12
- const threads = await gitApi.getThreads(repo, pr.pullRequestId, project);
13
- for (const thread of (threads || [])) {
14
- for (const comment of (thread.comments || [])) {
15
- if (comment.commentType === 'system') continue;
16
- allComments.push({
17
- prNumber: pr.pullRequestId,
18
- prTitle: pr.title,
19
- id: comment.id,
20
- author: comment.author?.displayName,
21
- body: comment.content,
22
- path: thread.threadContext?.filePath || null,
23
- line: thread.threadContext?.rightFileStart?.line || null,
24
- createdAt: comment.publishedDate,
25
- isCodeantComment: (comment.author?.displayName || '').toLowerCase().includes('codeant'),
26
- });
27
- }
28
- }
29
- }
30
-
31
- const q = query.toLowerCase();
32
- allComments = allComments.filter(c => c.body?.toLowerCase().includes(q));
33
-
34
- return allComments.slice(0, limit);
35
- }
@@ -1,18 +0,0 @@
1
- import pkg from 'bitbucket';
2
- const { Bitbucket } = pkg;
3
- import { getBitbucketToken, getBitbucketBaseUrl } from '../../utils/scmAuth.js';
4
-
5
- export function getClient() {
6
- const token = getBitbucketToken();
7
- if (!token) throw new Error('Bitbucket token not found. Set BITBUCKET_TOKEN env var or run `codeant set-token bitbucket <token>`.');
8
- const opts = { auth: { token } };
9
- const baseUrl = getBitbucketBaseUrl();
10
- if (baseUrl) opts.baseUrl = baseUrl.replace(/\/+$/, '');
11
- return new Bitbucket(opts);
12
- }
13
-
14
- export function splitRepo(name) {
15
- const [workspace, repo_slug] = name.split('/');
16
- if (!workspace || !repo_slug) throw new Error(`Invalid repo name "${name}". Use workspace/repo format.`);
17
- return { workspace, repo_slug };
18
- }
@@ -1,3 +0,0 @@
1
- export async function getCodeReview() {
2
- throw new Error('Bitbucket does not support individual code review retrieval. Use `pr comments` instead.');
3
- }
@@ -1,26 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function getPullRequest({ name, prNumber }) {
4
- const client = getClient();
5
- const { workspace, repo_slug } = splitRepo(name);
6
-
7
- const { data: pr } = await client.repositories.getPullRequest({ workspace, repo_slug, pull_request_id: prNumber });
8
-
9
- return {
10
- number: pr.id,
11
- title: pr.title,
12
- state: pr.state?.toLowerCase(),
13
- merged: pr.state === 'MERGED',
14
- author: pr.author?.display_name || pr.author?.nickname,
15
- sourceBranch: pr.source?.branch?.name,
16
- targetBranch: pr.destination?.branch?.name,
17
- body: pr.description,
18
- createdAt: pr.created_on,
19
- updatedAt: pr.updated_on,
20
- url: pr.links?.html?.href,
21
- reviewSummary: pr.participants?.filter(p => p.role === 'REVIEWER').map(p => ({
22
- user: p.user?.display_name || p.user?.nickname,
23
- state: p.approved ? 'APPROVED' : 'PENDING',
24
- })) || [],
25
- };
26
- }
@@ -1,6 +0,0 @@
1
- export { listPullRequests } from './listPullRequests.js';
2
- export { getPullRequest } from './getPullRequest.js';
3
- export { listPullRequestComments } from './listPullRequestComments.js';
4
- export { listCodeReviews } from './listCodeReviews.js';
5
- export { getCodeReview } from './getCodeReview.js';
6
- export { searchComments } from './searchComments.js';
@@ -1,17 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listCodeReviews({ name, prNumber, limit = 20 }) {
4
- // Bitbucket doesn't have discrete "reviews" — participants with reviewer role are the equivalent
5
- const client = getClient();
6
- const { workspace, repo_slug } = splitRepo(name);
7
-
8
- const { data: pr } = await client.repositories.getPullRequest({ workspace, repo_slug, pull_request_id: prNumber });
9
-
10
- return (pr.participants || []).filter(p => p.role === 'REVIEWER').slice(0, limit).map(p => ({
11
- id: null,
12
- user: p.user?.display_name || p.user?.nickname,
13
- state: p.approved ? 'APPROVED' : 'PENDING',
14
- body: null,
15
- submittedAt: null,
16
- }));
17
- }
@@ -1,33 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listPullRequestComments({ name, prNumber, codeantGenerated, createdAfter, createdBefore }) {
4
- const client = getClient();
5
- const { workspace, repo_slug } = splitRepo(name);
6
-
7
- const { data } = await client.repositories.listPullRequestComments({ workspace, repo_slug, pull_request_id: prNumber, pagelen: 100 });
8
-
9
- let comments = (data.values || []).map(c => ({
10
- id: c.id,
11
- type: c.inline ? 'review' : 'issue',
12
- author: c.user?.display_name || c.user?.nickname,
13
- body: c.content?.raw || c.content?.markup || '',
14
- path: c.inline?.path || null,
15
- line: c.inline?.to || null,
16
- createdAt: c.created_on,
17
- updatedAt: c.updated_on,
18
- isCodeantComment: (c.user?.display_name || c.user?.nickname || '').toLowerCase().includes('codeant') || (c.content?.raw || c.content?.markup || '').includes('Suggestion'),
19
- resolved: c.resolved || false,
20
- }));
21
-
22
- if (codeantGenerated !== undefined) {
23
- comments = comments.filter(c => c.isCodeantComment === codeantGenerated);
24
- }
25
- if (createdAfter) {
26
- comments = comments.filter(c => new Date(c.createdAt) >= new Date(createdAfter));
27
- }
28
- if (createdBefore) {
29
- comments = comments.filter(c => new Date(c.createdAt) <= new Date(createdBefore));
30
- }
31
-
32
- return comments;
33
- }
@@ -1,33 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listPullRequests({ name, sourceBranch, authorLogin, state = 'open', limit = 20 }) {
4
- const client = getClient();
5
- const { workspace, repo_slug } = splitRepo(name);
6
-
7
- const stateMap = { open: 'OPEN', closed: 'MERGED,DECLINED,SUPERSEDED' };
8
- const { data } = await client.repositories.listPullRequests({ workspace, repo_slug, state: stateMap[state] || 'OPEN', pagelen: limit });
9
-
10
- let prs = (data.values || []).map(pr => ({
11
- number: pr.id,
12
- title: pr.title,
13
- state: pr.state?.toLowerCase(),
14
- merged: pr.state === 'MERGED',
15
- author: pr.author?.display_name || pr.author?.nickname,
16
- sourceBranch: pr.source?.branch?.name,
17
- targetBranch: pr.destination?.branch?.name,
18
- createdAt: pr.created_on,
19
- updatedAt: pr.updated_on,
20
- url: pr.links?.html?.href,
21
- }));
22
-
23
- if (sourceBranch) {
24
- const sb = sourceBranch.toLowerCase();
25
- prs = prs.filter(pr => pr.sourceBranch?.toLowerCase().includes(sb));
26
- }
27
- if (authorLogin) {
28
- const author = authorLogin.toLowerCase();
29
- prs = prs.filter(pr => pr.author?.toLowerCase().includes(author));
30
- }
31
-
32
- return prs;
33
- }
@@ -1,29 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function searchComments({ name, query, limit = 10 }) {
4
- const client = getClient();
5
- const { workspace, repo_slug } = splitRepo(name);
6
-
7
- const { data: prsData } = await client.repositories.listPullRequests({ workspace, repo_slug, state: 'OPEN', pagelen: 10 });
8
-
9
- let allComments = [];
10
- for (const pr of (prsData.values || [])) {
11
- const { data: commentsData } = await client.repositories.listPullRequestComments({ workspace, repo_slug, pull_request_id: pr.id, pagelen: 50 });
12
- allComments.push(...(commentsData.values || []).map(c => ({
13
- prNumber: pr.id,
14
- prTitle: pr.title,
15
- id: c.id,
16
- author: c.user?.display_name || c.user?.nickname,
17
- body: c.content?.raw || '',
18
- path: c.inline?.path || null,
19
- line: c.inline?.to || null,
20
- createdAt: c.created_on,
21
- isCodeantComment: (c.user?.display_name || '').toLowerCase().includes('codeant'),
22
- })));
23
- }
24
-
25
- const q = query.toLowerCase();
26
- allComments = allComments.filter(c => c.body?.toLowerCase().includes(q));
27
-
28
- return allComments.slice(0, limit);
29
- }
@@ -1,17 +0,0 @@
1
- import { Octokit } from '@octokit/rest';
2
- import { getGitHubToken, getGitHubBaseUrl } from '../../utils/scmAuth.js';
3
-
4
- export function getClient() {
5
- const token = getGitHubToken();
6
- if (!token) throw new Error('GitHub token not found. Set GITHUB_TOKEN env var, login via `gh auth login`, or run `codeant set-token github <token>`.');
7
- const opts = { auth: token };
8
- const baseUrl = getGitHubBaseUrl();
9
- if (baseUrl) opts.baseUrl = baseUrl.replace(/\/+$/, '') + '/api/v3';
10
- return new Octokit(opts);
11
- }
12
-
13
- export function splitRepo(name) {
14
- const [owner, repo] = name.split('/');
15
- if (!owner || !repo) throw new Error(`Invalid repo name "${name}". Use owner/repo format.`);
16
- return { owner, repo };
17
- }
@@ -1,26 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function getCodeReview({ name, prNumber, reviewId }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- const [{ data: review }, { data: reviewComments }] = await Promise.all([
8
- octokit.pulls.getReview({ owner, repo, pull_number: prNumber, review_id: reviewId }),
9
- octokit.pulls.listCommentsForReview({ owner, repo, pull_number: prNumber, review_id: reviewId, per_page: 100 }),
10
- ]);
11
-
12
- return {
13
- id: review.id,
14
- user: review.user?.login,
15
- state: review.state,
16
- body: review.body,
17
- submittedAt: review.submitted_at,
18
- comments: reviewComments.map(c => ({
19
- id: c.id,
20
- path: c.path,
21
- line: c.line || c.original_line,
22
- body: c.body,
23
- createdAt: c.created_at,
24
- })),
25
- };
26
- }
@@ -1,27 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function getPullRequest({ name, prNumber }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- const { data: pr } = await octokit.pulls.get({ owner, repo, pull_number: prNumber });
8
- const { data: reviews } = await octokit.pulls.listReviews({ owner, repo, pull_number: prNumber });
9
-
10
- return {
11
- number: pr.number,
12
- title: pr.title,
13
- state: pr.state,
14
- merged: pr.merged_at !== null,
15
- author: pr.user?.login,
16
- sourceBranch: pr.head?.ref,
17
- targetBranch: pr.base?.ref,
18
- body: pr.body,
19
- createdAt: pr.created_at,
20
- updatedAt: pr.updated_at,
21
- url: pr.html_url,
22
- additions: pr.additions,
23
- deletions: pr.deletions,
24
- changedFiles: pr.changed_files,
25
- reviewSummary: reviews.map(r => ({ user: r.user?.login, state: r.state, submittedAt: r.submitted_at })),
26
- };
27
- }
@@ -1,6 +0,0 @@
1
- export { listPullRequests } from './listPullRequests.js';
2
- export { getPullRequest } from './getPullRequest.js';
3
- export { listPullRequestComments } from './listPullRequestComments.js';
4
- export { listCodeReviews } from './listCodeReviews.js';
5
- export { getCodeReview } from './getCodeReview.js';
6
- export { searchComments } from './searchComments.js';
@@ -1,17 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listCodeReviews({ name, prNumber, limit = 20, offset = 0 }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- const { data } = await octokit.pulls.listReviews({ owner, repo, pull_number: prNumber, per_page: limit, page: Math.floor(offset / limit) + 1 });
8
-
9
- return data.map(r => ({
10
- id: r.id,
11
- user: r.user?.login,
12
- state: r.state,
13
- body: r.body,
14
- submittedAt: r.submitted_at,
15
- url: r.html_url,
16
- }));
17
- }
@@ -1,51 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listPullRequestComments({ name, prNumber, codeantGenerated, addressed, createdAfter, createdBefore }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- // Get both review comments (inline) and issue comments (general)
8
- const [{ data: reviewComments }, { data: issueComments }] = await Promise.all([
9
- octokit.pulls.listReviewComments({ owner, repo, pull_number: prNumber, per_page: 100 }),
10
- octokit.issues.listComments({ owner, repo, issue_number: prNumber, per_page: 100 }),
11
- ]);
12
-
13
- let comments = [
14
- ...reviewComments.map(c => ({
15
- id: c.id,
16
- type: 'review',
17
- author: c.user?.login,
18
- body: c.body,
19
- path: c.path,
20
- line: c.line || c.original_line,
21
- createdAt: c.created_at,
22
- updatedAt: c.updated_at,
23
- isCodeantComment: c.user?.login?.includes('codeant') || c.body?.includes('Suggestion'),
24
- inReplyToId: c.in_reply_to_id || null,
25
- })),
26
- ...issueComments.map(c => ({
27
- id: c.id,
28
- type: 'issue',
29
- author: c.user?.login,
30
- body: c.body,
31
- path: null,
32
- line: null,
33
- createdAt: c.created_at,
34
- updatedAt: c.updated_at,
35
- isCodeantComment: c.user?.login?.includes('codeant') || c.body?.includes('Suggestion'),
36
- inReplyToId: null,
37
- })),
38
- ];
39
-
40
- if (codeantGenerated !== undefined) {
41
- comments = comments.filter(c => c.isCodeantComment === codeantGenerated);
42
- }
43
- if (createdAfter) {
44
- comments = comments.filter(c => new Date(c.createdAt) >= new Date(createdAfter));
45
- }
46
- if (createdBefore) {
47
- comments = comments.filter(c => new Date(c.createdAt) <= new Date(createdBefore));
48
- }
49
-
50
- return comments;
51
- }
@@ -1,32 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function listPullRequests({ name, sourceBranch, authorLogin, state = 'open', limit = 20, offset = 0 }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- const perPage = Math.max(limit, 1);
8
- const params = { owner, repo, state: state === 'closed' ? 'closed' : 'open', per_page: perPage, page: Math.floor(offset / perPage) + 1, sort: 'updated', direction: 'desc' };
9
- if (sourceBranch) params.head = sourceBranch.includes(':') ? sourceBranch : `${owner}:${sourceBranch}`;
10
-
11
- const { data } = await octokit.pulls.list(params);
12
-
13
- let prs = data.map(pr => ({
14
- number: pr.number,
15
- title: pr.title,
16
- state: pr.state,
17
- merged: pr.merged_at !== null,
18
- author: pr.user?.login,
19
- sourceBranch: pr.head?.ref,
20
- targetBranch: pr.base?.ref,
21
- createdAt: pr.created_at,
22
- updatedAt: pr.updated_at,
23
- url: pr.html_url,
24
- }));
25
-
26
- if (authorLogin) {
27
- const author = authorLogin.toLowerCase();
28
- prs = prs.filter(pr => pr.author?.toLowerCase().includes(author));
29
- }
30
-
31
- return prs;
32
- }
@@ -1,30 +0,0 @@
1
- import { getClient, splitRepo } from './client.js';
2
-
3
- export async function searchComments({ name, query, limit = 10, includeAddressed = false }) {
4
- const octokit = getClient();
5
- const { owner, repo } = splitRepo(name);
6
-
7
- // GitHub doesn't have a native comment search API, so we fetch recent PR comments and filter
8
- const { data: prs } = await octokit.pulls.list({ owner, repo, state: 'all', per_page: 10, sort: 'updated' });
9
-
10
- let allComments = [];
11
- for (const pr of prs) {
12
- const { data: comments } = await octokit.pulls.listReviewComments({ owner, repo, pull_number: pr.number, per_page: 50 });
13
- allComments.push(...comments.map(c => ({
14
- prNumber: pr.number,
15
- prTitle: pr.title,
16
- id: c.id,
17
- author: c.user?.login,
18
- body: c.body,
19
- path: c.path,
20
- line: c.line || c.original_line,
21
- createdAt: c.created_at,
22
- isCodeantComment: c.user?.login?.includes('codeant'),
23
- })));
24
- }
25
-
26
- const q = query.toLowerCase();
27
- allComments = allComments.filter(c => c.body?.toLowerCase().includes(q));
28
-
29
- return allComments.slice(0, limit);
30
- }
@@ -1,16 +0,0 @@
1
- import { Gitlab } from '@gitbeaker/rest';
2
- import { getGitLabToken, getGitLabBaseUrl } from '../../utils/scmAuth.js';
3
-
4
- export function getClient() {
5
- const token = getGitLabToken();
6
- if (!token) throw new Error('GitLab token not found. Set GITLAB_TOKEN env var, login via `glab auth login`, or run `codeant set-token gitlab <token>`.');
7
- const opts = { token };
8
- const host = getGitLabBaseUrl();
9
- if (host) opts.host = host.replace(/\/+$/, '');
10
- return new Gitlab(opts);
11
- }
12
-
13
- // GitLab uses project ID or "owner/repo" encoded as "owner%2Frepo"
14
- export function projectId(name) {
15
- return encodeURIComponent(name);
16
- }
@@ -1,18 +0,0 @@
1
- import { getClient, projectId } from './client.js';
2
-
3
- export async function getCodeReview({ name, prNumber, reviewId }) {
4
- const api = getClient();
5
-
6
- const note = await api.MergeRequestNotes.show(projectId(name), prNumber, reviewId);
7
-
8
- return {
9
- id: note.id,
10
- user: note.author?.username,
11
- state: note.resolved ? 'APPROVED' : 'COMMENTED',
12
- body: note.body,
13
- submittedAt: note.created_at,
14
- path: note.position?.new_path || null,
15
- line: note.position?.new_line || null,
16
- comments: [],
17
- };
18
- }
@@ -1,24 +0,0 @@
1
- import { getClient, projectId } from './client.js';
2
-
3
- export async function getPullRequest({ name, prNumber }) {
4
- const api = getClient();
5
-
6
- const mr = await api.MergeRequests.show(projectId(name), prNumber);
7
- const approvals = await api.MergeRequestApprovals.configuration(projectId(name), { mergerequestIid: prNumber }).catch(() => null);
8
-
9
- return {
10
- number: mr.iid,
11
- title: mr.title,
12
- state: mr.state === 'opened' ? 'open' : mr.state,
13
- merged: mr.state === 'merged',
14
- author: mr.author?.username,
15
- sourceBranch: mr.source_branch,
16
- targetBranch: mr.target_branch,
17
- body: mr.description,
18
- createdAt: mr.created_at,
19
- updatedAt: mr.updated_at,
20
- url: mr.web_url,
21
- additions: mr.changes_count,
22
- reviewSummary: approvals?.approved_by?.map(a => ({ user: a.user?.username, state: 'APPROVED' })) || [],
23
- };
24
- }
@@ -1,6 +0,0 @@
1
- export { listPullRequests } from './listPullRequests.js';
2
- export { getPullRequest } from './getPullRequest.js';
3
- export { listPullRequestComments } from './listPullRequestComments.js';
4
- export { listCodeReviews } from './listCodeReviews.js';
5
- export { getCodeReview } from './getCodeReview.js';
6
- export { searchComments } from './searchComments.js';
@@ -1,21 +0,0 @@
1
- import { getClient, projectId } from './client.js';
2
-
3
- export async function listCodeReviews({ name, prNumber, limit = 20, offset = 0 }) {
4
- const api = getClient();
5
-
6
- // GitLab doesn't have "reviews" like GitHub — use notes + approvals
7
- const notes = await api.MergeRequestNotes.all(projectId(name), prNumber, {
8
- perPage: limit,
9
- page: Math.floor(offset / Math.max(limit, 1)) + 1,
10
- });
11
-
12
- const reviewNotes = notes.filter(n => !n.system);
13
-
14
- return reviewNotes.map(n => ({
15
- id: n.id,
16
- user: n.author?.username,
17
- state: n.resolved ? 'APPROVED' : 'COMMENTED',
18
- body: n.body,
19
- submittedAt: n.created_at,
20
- }));
21
- }
@@ -1,44 +0,0 @@
1
- import { getClient, projectId } from './client.js';
2
-
3
- export async function listPullRequestComments({ name, prNumber, codeantGenerated, createdAfter, createdBefore }) {
4
- const api = getClient();
5
-
6
- const [notes, discussions] = await Promise.all([
7
- api.MergeRequestNotes.all(projectId(name), prNumber, { perPage: 100 }),
8
- api.MergeRequestDiscussions.all(projectId(name), prNumber, { perPage: 100 }),
9
- ]);
10
-
11
- let comments = notes.map(n => ({
12
- id: n.id,
13
- type: n.type === 'DiffNote' ? 'review' : 'issue',
14
- author: n.author?.username,
15
- body: n.body,
16
- path: n.position?.new_path || null,
17
- line: n.position?.new_line || null,
18
- createdAt: n.created_at,
19
- updatedAt: n.updated_at,
20
- isCodeantComment: n.author?.username?.includes('codeant') || n.body?.includes('Suggestion'),
21
- resolved: n.resolved || false,
22
- discussionId: null,
23
- }));
24
-
25
- // Enrich with discussion context
26
- for (const disc of discussions) {
27
- for (const note of disc.notes || []) {
28
- const match = comments.find(c => c.id === note.id);
29
- if (match) match.discussionId = disc.id;
30
- }
31
- }
32
-
33
- if (codeantGenerated !== undefined) {
34
- comments = comments.filter(c => c.isCodeantComment === codeantGenerated);
35
- }
36
- if (createdAfter) {
37
- comments = comments.filter(c => new Date(c.createdAt) >= new Date(createdAfter));
38
- }
39
- if (createdBefore) {
40
- comments = comments.filter(c => new Date(c.createdAt) <= new Date(createdBefore));
41
- }
42
-
43
- return comments;
44
- }
@@ -1,26 +0,0 @@
1
- import { getClient, projectId } from './client.js';
2
-
3
- export async function listPullRequests({ name, sourceBranch, authorLogin, state = 'open', limit = 20, offset = 0 }) {
4
- const api = getClient();
5
-
6
- const params = { perPage: limit, page: Math.floor(offset / limit) + 1, orderBy: 'updated_at', sort: 'desc' };
7
- if (state === 'open') params.state = 'opened';
8
- else if (state === 'closed') params.state = 'closed';
9
- if (sourceBranch) params.sourceBranch = sourceBranch;
10
- if (authorLogin) params.authorUsername = authorLogin;
11
-
12
- const mrs = await api.MergeRequests.all({ projectId: projectId(name), ...params });
13
-
14
- return mrs.map(mr => ({
15
- number: mr.iid,
16
- title: mr.title,
17
- state: mr.state === 'opened' ? 'open' : mr.state,
18
- merged: mr.state === 'merged',
19
- author: mr.author?.username,
20
- sourceBranch: mr.source_branch,
21
- targetBranch: mr.target_branch,
22
- createdAt: mr.created_at,
23
- updatedAt: mr.updated_at,
24
- url: mr.web_url,
25
- }));
26
- }