Skip to content

Commit e5fd795

Browse files
Merge pull request #8 from AndreaGriffiths11/claude/improve-accessibility-01JtPScbdhnk4e3PQ7X2fUUa
Improve codebase accessibility
2 parents c5bc8bf + 1d66f29 commit e5fd795

12 files changed

Lines changed: 693 additions & 212 deletions

package-lock.json

Lines changed: 1 addition & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@
140140
"webpack-cli": "^6.0.1"
141141
},
142142
"dependencies": {
143-
"@types/axios": "^0.9.36",
144-
"axios": "^1.12.0",
143+
"axios": "^1.7.0",
145144
"dotenv": "^16.5.0"
146145
}
147146
}

src/core/copilot-mcp-service.ts

Lines changed: 47 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import * as vscode from 'vscode';
22
import * as path from 'path';
3-
import axios from 'axios';
4-
import { TokenManager } from './token-manager';
53
import { ExpertiseAnalyzer, ExpertiseAnalysis } from './expertise-analyzer';
64
import { Expert } from '../types/expert';
5+
import { GitService } from './git-service';
76

87
export interface GitHubRepository {
98
owner: string;
@@ -30,11 +29,9 @@ export interface MCPServerStatus {
3029

3130
export class CopilotMCPService {
3231
private outputChannel: vscode.OutputChannel;
33-
private tokenManager: TokenManager;
3432

35-
constructor(outputChannel: vscode.OutputChannel, tokenManager: TokenManager) {
33+
constructor(outputChannel: vscode.OutputChannel) {
3634
this.outputChannel = outputChannel;
37-
this.tokenManager = tokenManager;
3835
}
3936

4037
//Check the status of GitHub MCP Server containers
@@ -125,26 +122,25 @@ export class CopilotMCPService {
125122
}
126123
}
127124

128-
129-
//Detect GitHub repository information from the current workspace
130-
125+
126+
//Detect GitHub repository information from the current workspace (using secure GitService)
127+
131128
async detectRepository(): Promise<GitHubRepository | null> {
132129
try {
133130
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
134131
if (!workspaceFolder) {
135132
throw new Error('No workspace folder open');
136133
}
137134

138-
// Try to parse git remote to get owner/repo
139-
const { exec } = require('child_process');
140-
const util = require('util');
141-
const execAsync = util.promisify(exec);
135+
// Use secure GitService to get remote URL
136+
const gitService = new GitService(workspaceFolder.uri.fsPath, this.outputChannel);
137+
const remoteUrl = await gitService.getRemoteUrl();
142138

143-
const { stdout } = await execAsync('git config --get remote.origin.url', {
144-
cwd: workspaceFolder.uri.fsPath
145-
});
139+
if (!remoteUrl) {
140+
this.outputChannel.appendLine('No git remote URL found');
141+
return null;
142+
}
146143

147-
const remoteUrl = stdout.trim();
148144
this.outputChannel.appendLine(`Git remote URL: ${remoteUrl}`);
149145

150146
// Parse GitHub URL (supports both HTTPS and SSH)
@@ -341,29 +337,6 @@ Just call the tool and format the response. Don't explain anything else.`;
341337
}
342338
}
343339

344-
/**
345-
* Create an enhanced prompt specifically designed for MCP usage
346-
*/
347-
private createEnhancedMCPPrompt(basePrompt: string): string {
348-
// Extract repository info from the base prompt
349-
const repoMatch = basePrompt.match(/(\w+\/\w+)/);
350-
const repoPath = repoMatch ? repoMatch[1] : 'owner/repo';
351-
const [owner, repo] = repoPath.split('/');
352-
353-
return `Call mcp_github_list_commits with owner: "${owner}", repo: "${repo}", perPage: 5
354-
355-
Then respond with JSON format:
356-
{
357-
"commits": [{"sha": "...", "author": {"name": "...", "email": "...", "date": "..."}, "message": "..."}],
358-
"contributors": [{"name": "...", "email": "...", "totalCommits": 0}],
359-
"issues": [],
360-
"pullRequests": [],
361-
"collaborationInsights": ["Analysis complete"]
362-
}
363-
364-
Execute now.`;
365-
}
366-
367340
/**
368341
* Parse repository response from Copilot Chat
369342
*/
@@ -437,29 +410,19 @@ Execute now.`;
437410
}
438411

439412
/**
440-
* Get commits from local git repository
413+
* Get commits from local git repository (using secure GitService)
441414
*/
442415
private async getLocalCommits(repoPath: string): Promise<any[]> {
443-
const { exec } = require('child_process');
444-
const util = require('util');
445-
const execAsync = util.promisify(exec);
446-
447416
try {
448-
const { stdout } = await execAsync('git log --pretty=format:"%H|%an|%ae|%ad|%s" --date=iso -n 50', {
449-
cwd: repoPath
450-
});
451-
452-
return stdout.split('\n')
453-
.filter((line: string) => line.trim())
454-
.map((line: string) => {
455-
const [sha, author, email, date, message] = line.split('|');
456-
return {
457-
sha,
458-
author: { name: author, email, date },
459-
message,
460-
files: [] // Would need additional git commands to get files per commit
461-
};
462-
});
417+
const gitService = new GitService(repoPath, this.outputChannel);
418+
const commits = await gitService.getCommits(50);
419+
420+
return commits.map(commit => ({
421+
sha: commit.sha,
422+
author: commit.author,
423+
message: commit.message,
424+
files: [] // Would need additional git commands to get files per commit
425+
}));
463426
} catch (error) {
464427
this.outputChannel.appendLine(`Error getting local commits: ${error}`);
465428
return [];
@@ -475,7 +438,7 @@ Execute now.`;
475438
commits.forEach(commit => {
476439
const email = commit.author.email;
477440
const name = commit.author.name;
478-
const commitDate = new Date(commit.author.date);
441+
const commitDate = new Date(commit.date);
479442

480443
if (contributorMap.has(email)) {
481444
const contributor = contributorMap.get(email)!;
@@ -502,7 +465,7 @@ Execute now.`;
502465
/**
503466
* Get workspace files for analysis
504467
*/
505-
private async getWorkspaceFiles(repoPath: string): Promise<string[]> {
468+
private async getWorkspaceFiles(_repoPath: string): Promise<string[]> {
506469
try {
507470
const files = await vscode.workspace.findFiles('**/*', '**/node_modules/**');
508471
return files.map(file => vscode.workspace.asRelativePath(file));
@@ -727,17 +690,6 @@ Execute now.`;
727690
// vscode.window.showInformationMessage('suggestExpertForIssueDetails called. See logs.');
728691
}
729692

730-
731-
private extractIssueDataFromResponse(responseData: any): any {
732-
return {
733-
title: responseData.title,
734-
body: responseData.body,
735-
labels: responseData.labels?.map((label: any) => label.name) || [],
736-
number: responseData.number,
737-
url: responseData.html_url
738-
};
739-
}
740-
741693
private findBestExpertForIssue(issueData: any, experts: Expert[], extractKeywords: (text: string) => string[]): Expert | null {
742694
if (!experts || experts.length === 0) return null;
743695
const issueKeywords = extractKeywords(`${issueData.title} ${issueData.body}`);
@@ -790,32 +742,28 @@ Execute now.`;
790742
vscode.window.showInformationMessage(message, { modal: true }, 'Notify Expert')
791743
.then(async (selection) => {
792744
if (selection === 'Notify Expert') {
793-
await this.notifyExpert(expert, issueData, issueNumber);
745+
await this._notifyExpert(expert, issueData, issueNumber);
794746
}
795747
});
796748
}
797749

798750
/**
799751
* Notify the expert about the issue (e.g., via GitHub comment, email, etc.)
752+
* @private - Placeholder for future email integration
800753
*/
801-
private async notifyExpert(expert: Expert, issueData: any, issueNumber?: number): Promise<void> {
754+
private async _notifyExpert(expert: Expert, _issueData: any, issueNumber?: number): Promise<void> {
802755
if (!expert.email) {
803756
vscode.window.showErrorMessage('No email available for the expert. Cannot send notification.');
804757
return;
805758
}
806759

807-
// Simple email notification (placeholder, integrate with actual email service)
808-
const subject = `Expertise Requested for Issue #${issueNumber}: ${issueData.title}`;
809-
const body = `Hello ${expert.name},\n\n` +
810-
`You have been suggested as an expert for GitHub Issue #${issueNumber} - ${issueData.title}.\n` +
811-
`Issue URL: ${issueData.url}\n\n` +
812-
`Please check the issue for details and consider contributing your expertise.\n\n` +
813-
`Thank you!`;
760+
// TODO: Integrate with actual email service
761+
// Email subject: `Expertise Requested for Issue #${issueNumber}: ${issueData.title}`
762+
// Email body: Expert details and issue URL
814763

815-
this.outputChannel.appendLine(`Sending email to ${expert.email}...`);
816-
// Integrate with email service here
764+
this.outputChannel.appendLine(`Would send email to ${expert.email} for issue #${issueNumber}`);
817765

818-
vscode.window.showInformationMessage(`Notification sent to ${expert.name} <${expert.email}>`, { modal: true });
766+
vscode.window.showInformationMessage(`Notification would be sent to ${expert.name} <${expert.email}>`, { modal: true });
819767
}
820768

821769
// Add getExpertRecentActivity and showExpertActivity methods back to CopilotMCPService
@@ -827,28 +775,21 @@ Execute now.`;
827775
if (!workspaceFolder) {
828776
return { success: false, error: 'No workspace folder found' };
829777
}
830-
const { exec } = require('child_process');
831-
const { promisify } = require('util');
832-
const execAsync = promisify(exec);
778+
833779
try {
834-
const commitCommand = `git log --author="${expertEmail}" --pretty=format:"%H|%s|%ad" --date=short -n 10`;
835-
const { stdout: commitOutput } = await execAsync(commitCommand, { cwd: workspaceFolder.uri.fsPath });
836-
const recentCommits = commitOutput.split('\n')
837-
.filter((line: string) => line.trim())
838-
.map((line: string) => {
839-
const [sha, message, date] = line.split('|');
840-
return {
841-
repo: "Current Repository",
842-
message: message || "No message",
843-
date: date || new Date().toISOString().split('T')[0],
844-
url: `#${sha?.substring(0, 7) || 'unknown'}`
845-
};
846-
});
847-
const fileCommand = `git log --author=\"${expertEmail}\" --name-only --pretty=format: -n 20 | sort | uniq | head -10`;
848-
const { stdout: fileOutput } = await execAsync(fileCommand, { cwd: workspaceFolder.uri.fsPath });
849-
const recentFiles = fileOutput.split('\n')
850-
.filter((file: string) => file.trim())
851-
.slice(0, 5);
780+
// Use secure GitService instead of direct git commands
781+
const gitService = new GitService(workspaceFolder.uri.fsPath, this.outputChannel);
782+
783+
const commits = await gitService.getCommitsByAuthor(expertEmail, 10);
784+
const recentCommits = commits.map(commit => ({
785+
repo: "Current Repository",
786+
message: commit.message || "No message",
787+
date: commit.date.split(' ')[0] || new Date().toISOString().split('T')[0],
788+
url: `#${commit.sha.substring(0, 7)}`
789+
}));
790+
791+
const recentFiles = await gitService.getFilesByAuthor(expertEmail, 10);
792+
852793
const activity = {
853794
expertName,
854795
expertEmail,
@@ -863,7 +804,7 @@ Execute now.`;
863804
recentFiles.length > 0 ? `Recently worked on: ${recentFiles.slice(0, 3).join(', ')}` : "No recent file activity found",
864805
`Last commit: ${recentCommits[0]?.date || 'Unknown'}`
865806
],
866-
currentFocus: recentCommits.length > 0 ?
807+
currentFocus: recentCommits.length > 0 ?
867808
`Recent work: ${recentCommits[0]?.message?.substring(0, 100) || 'No recent activity'}` :
868809
"No recent activity in this repository"
869810
};

0 commit comments

Comments
 (0)