@achieveai/azuredevops-mcp 1.3.15 → 1.3.17

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 (100) hide show
  1. package/dist/Services/AzureDevOpsService.js +4 -3
  2. package/dist/Services/AzureDevOpsService.js.map +1 -1
  3. package/dist/Services/BuildService.project.test.js +91 -0
  4. package/dist/Services/BuildService.project.test.js.map +1 -0
  5. package/dist/Services/GitService.js +101 -75
  6. package/dist/Services/GitService.js.map +1 -1
  7. package/dist/Services/GitService.project.test.js +407 -0
  8. package/dist/Services/GitService.project.test.js.map +1 -0
  9. package/dist/Services/WorkItemService.js +105 -25
  10. package/dist/Services/WorkItemService.js.map +1 -1
  11. package/dist/Tools/WorkItemTools.js +1 -1
  12. package/dist/Tools/WorkItemTools.js.map +1 -1
  13. package/dist/index.js +40 -18
  14. package/dist/index.js.map +1 -1
  15. package/dist/package.json +59 -0
  16. package/dist/src/Interfaces/AIAssisted.js +3 -0
  17. package/dist/src/Interfaces/AIAssisted.js.map +1 -0
  18. package/dist/src/Interfaces/ArtifactManagement.js +3 -0
  19. package/dist/src/Interfaces/ArtifactManagement.js.map +1 -0
  20. package/dist/src/Interfaces/AzureDevOps.js +3 -0
  21. package/dist/src/Interfaces/AzureDevOps.js.map +1 -0
  22. package/dist/src/Interfaces/BoardsAndSprints.js +3 -0
  23. package/dist/src/Interfaces/BoardsAndSprints.js.map +1 -0
  24. package/dist/src/Interfaces/CodeAndRepositories.js +3 -0
  25. package/dist/src/Interfaces/CodeAndRepositories.js.map +1 -0
  26. package/dist/src/Interfaces/Common.js +134 -0
  27. package/dist/src/Interfaces/Common.js.map +1 -0
  28. package/dist/src/Interfaces/CostResourceManagement.js +3 -0
  29. package/dist/src/Interfaces/CostResourceManagement.js.map +1 -0
  30. package/dist/src/Interfaces/DevSecOps.js +3 -0
  31. package/dist/src/Interfaces/DevSecOps.js.map +1 -0
  32. package/dist/src/Interfaces/ExternalIntegrations.js +3 -0
  33. package/dist/src/Interfaces/ExternalIntegrations.js.map +1 -0
  34. package/dist/src/Interfaces/HybridCrossPlatform.js +3 -0
  35. package/dist/src/Interfaces/HybridCrossPlatform.js.map +1 -0
  36. package/dist/src/Interfaces/Pipelines.js +3 -0
  37. package/dist/src/Interfaces/Pipelines.js.map +1 -0
  38. package/dist/src/Interfaces/ProjectManagement.js +3 -0
  39. package/dist/src/Interfaces/ProjectManagement.js.map +1 -0
  40. package/dist/src/Interfaces/TestingCapabilities.js +3 -0
  41. package/dist/src/Interfaces/TestingCapabilities.js.map +1 -0
  42. package/dist/src/Interfaces/Wiki.js +3 -0
  43. package/dist/src/Interfaces/Wiki.js.map +1 -0
  44. package/dist/src/Interfaces/WorkItems.js +3 -0
  45. package/dist/src/Interfaces/WorkItems.js.map +1 -0
  46. package/dist/src/Services/AIAssistedDevelopmentService.js +195 -0
  47. package/dist/src/Services/AIAssistedDevelopmentService.js.map +1 -0
  48. package/dist/src/Services/ArtifactManagementService.js +346 -0
  49. package/dist/src/Services/ArtifactManagementService.js.map +1 -0
  50. package/dist/src/Services/AzureDevOpsService.js +385 -0
  51. package/dist/src/Services/AzureDevOpsService.js.map +1 -0
  52. package/dist/src/Services/BoardsSprintsService.js +339 -0
  53. package/dist/src/Services/BoardsSprintsService.js.map +1 -0
  54. package/dist/src/Services/BuildService.js +405 -0
  55. package/dist/src/Services/BuildService.js.map +1 -0
  56. package/dist/src/Services/DevSecOpsService.js +307 -0
  57. package/dist/src/Services/DevSecOpsService.js.map +1 -0
  58. package/dist/src/Services/EntraAuthHandler.js +337 -0
  59. package/dist/src/Services/EntraAuthHandler.js.map +1 -0
  60. package/dist/src/Services/GitService.js +1595 -0
  61. package/dist/src/Services/GitService.js.map +1 -0
  62. package/dist/src/Services/ProjectService.js +257 -0
  63. package/dist/src/Services/ProjectService.js.map +1 -0
  64. package/dist/src/Services/TestingCapabilitiesService.js +149 -0
  65. package/dist/src/Services/TestingCapabilitiesService.js.map +1 -0
  66. package/dist/src/Services/WikiService.js +90 -0
  67. package/dist/src/Services/WikiService.js.map +1 -0
  68. package/dist/src/Services/WorkItemService.js +885 -0
  69. package/dist/src/Services/WorkItemService.js.map +1 -0
  70. package/dist/src/Tools/AIAssistedDevelopmentTools.js +137 -0
  71. package/dist/src/Tools/AIAssistedDevelopmentTools.js.map +1 -0
  72. package/dist/src/Tools/ArtifactManagementTools.js +140 -0
  73. package/dist/src/Tools/ArtifactManagementTools.js.map +1 -0
  74. package/dist/src/Tools/BoardsSprintsTools.js +338 -0
  75. package/dist/src/Tools/BoardsSprintsTools.js.map +1 -0
  76. package/dist/src/Tools/BuildTools.js +468 -0
  77. package/dist/src/Tools/BuildTools.js.map +1 -0
  78. package/dist/src/Tools/DevSecOpsTools.js +147 -0
  79. package/dist/src/Tools/DevSecOpsTools.js.map +1 -0
  80. package/dist/src/Tools/GitTools.js +1475 -0
  81. package/dist/src/Tools/GitTools.js.map +1 -0
  82. package/dist/src/Tools/ProjectTools.js +360 -0
  83. package/dist/src/Tools/ProjectTools.js.map +1 -0
  84. package/dist/src/Tools/TestingCapabilitiesTools.js +157 -0
  85. package/dist/src/Tools/TestingCapabilitiesTools.js.map +1 -0
  86. package/dist/src/Tools/WikiTools.js +137 -0
  87. package/dist/src/Tools/WikiTools.js.map +1 -0
  88. package/dist/src/Tools/WorkItemTools.js +862 -0
  89. package/dist/src/Tools/WorkItemTools.js.map +1 -0
  90. package/dist/src/config.js +176 -0
  91. package/dist/src/config.js.map +1 -0
  92. package/dist/src/index.js +1716 -0
  93. package/dist/src/index.js.map +1 -0
  94. package/dist/src/utils/formatHelpers.js +257 -0
  95. package/dist/src/utils/formatHelpers.js.map +1 -0
  96. package/dist/src/utils/getClassMethods.js +8 -0
  97. package/dist/src/utils/getClassMethods.js.map +1 -0
  98. package/dist/src/utils/repositoryResolver.js +40 -0
  99. package/dist/src/utils/repositoryResolver.js.map +1 -0
  100. package/package.json +5 -3
@@ -20,10 +20,11 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
20
20
  /**
21
21
  * Get work item references linked to a pull request
22
22
  */
23
- async getPullRequestWorkItemRefs(repository, pullRequestId) {
23
+ async getPullRequestWorkItemRefs(repository, pullRequestId, project) {
24
24
  const gitApi = await this.getGitApi();
25
- const repositoryId = await this.resolveRepositoryId(repository);
26
- const refs = await gitApi.getPullRequestWorkItemRefs(repositoryId, pullRequestId, this.config.project);
25
+ const effectiveProject = project || this.config.project;
26
+ const repositoryId = await this.resolveRepositoryId(repository, effectiveProject);
27
+ const refs = await gitApi.getPullRequestWorkItemRefs(repositoryId, pullRequestId, effectiveProject);
27
28
  if (!refs || refs.length === 0)
28
29
  return [];
29
30
  return refs.map(ref => {
@@ -127,8 +128,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
127
128
  async listBranches(params) {
128
129
  try {
129
130
  const gitApi = await this.getGitApi();
131
+ const project = params.project || this.config.project;
130
132
  // Resolve repository name/ID to actual repository ID
131
- const repositoryId = await this.resolveRepositoryId(params.repository);
133
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
132
134
  const branches = await gitApi.getBranches(repositoryId, params.filter);
133
135
  if (params.top && branches.length > params.top) {
134
136
  return branches.slice(0, params.top);
@@ -147,8 +149,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
147
149
  async searchCode(params) {
148
150
  try {
149
151
  const gitApi = await this.getGitApi();
152
+ const project = params.projectId || this.config.project;
150
153
  // Resolve repository name/ID to actual repository ID if provided
151
- const repositoryId = params.repository ? await this.resolveRepositoryId(params.repository) : "";
154
+ const repositoryId = params.repository ? await this.resolveRepositoryId(params.repository, project) : "";
152
155
  // This is a simplified implementation using item search
153
156
  // For more comprehensive code search, you'd use the Search API
154
157
  const items = await gitApi.getItems(repositoryId || "", undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined);
@@ -177,8 +180,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
177
180
  async browseRepository(params) {
178
181
  try {
179
182
  const gitApi = await this.getGitApi();
183
+ const project = params.project || this.config.project;
180
184
  // Resolve repository name/ID to actual repository ID
181
- const repositoryId = await this.resolveRepositoryId(params.repository);
185
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
182
186
  const items = await gitApi.getItems(repositoryId, undefined, params.path, undefined, true, undefined, undefined, undefined, undefined, undefined);
183
187
  return items;
184
188
  }
@@ -193,8 +197,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
193
197
  async getFileContent(params) {
194
198
  try {
195
199
  const gitApi = await this.getGitApi();
200
+ const project = params.project || this.config.project;
196
201
  // Resolve repository name/ID to actual repository ID
197
- const repositoryId = await this.resolveRepositoryId(params.repository);
202
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
198
203
  // Get the file content as a stream
199
204
  const content = await gitApi.getItemContent(repositoryId, params.path, undefined, undefined);
200
205
  let fileContent = '';
@@ -266,11 +271,11 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
266
271
  /**
267
272
  * Get file content by object ID
268
273
  */
269
- async getFileContentByObjectId(repositoryId, objectId) {
274
+ async getFileContentByObjectId(repositoryId, objectId, project) {
270
275
  try {
271
276
  const gitApi = await this.getGitApi();
272
277
  // Get content by blob ID (object ID)
273
- const content = await gitApi.getBlobContent(repositoryId, objectId, this.config.project);
278
+ const content = await gitApi.getBlobContent(repositoryId, objectId, project || this.config.project);
274
279
  if (Buffer.isBuffer(content)) {
275
280
  return content.toString('utf8');
276
281
  }
@@ -311,11 +316,11 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
311
316
  * Get the latest iteration number for a pull request
312
317
  * Returns the most recent iteration that contains the latest changes
313
318
  */
314
- async getLatestPullRequestIteration(repositoryId, pullRequestId) {
319
+ async getLatestPullRequestIteration(repositoryId, pullRequestId, project) {
315
320
  try {
316
321
  const gitApi = await this.getGitApi();
317
322
  // Get all iterations for the pull request
318
- const iterations = await gitApi.getPullRequestIterations(repositoryId, pullRequestId, this.config.project);
323
+ const iterations = await gitApi.getPullRequestIterations(repositoryId, pullRequestId, project || this.config.project);
319
324
  if (!iterations || iterations.length === 0) {
320
325
  // Fallback to iteration 1 if no iterations found
321
326
  return 1;
@@ -538,8 +543,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
538
543
  };
539
544
  // Get commits with proper search criteria for richer data
540
545
  // Resolve repository name/ID to actual repository ID
541
- const repositoryId = await this.resolveRepositoryId(params.repository);
542
- const commits = await gitApi.getCommits(repositoryId, searchCriteria, params.projectId || this.config.project);
546
+ const project = params.projectId || this.config.project;
547
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
548
+ const commits = await gitApi.getCommits(repositoryId, searchCriteria, project);
543
549
  // The commits are already filtered and paginated by the API
544
550
  return commits || [];
545
551
  }
@@ -577,8 +583,9 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
577
583
  async getPullRequests(params) {
578
584
  try {
579
585
  const gitApi = await this.getGitApi();
586
+ const project = params.project || params.projectId || this.config.project;
580
587
  // Resolve repository name/ID to actual repository ID
581
- const repositoryId = await this.resolveRepositoryId(params.repository);
588
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
582
589
  // Create search criteria with proper types
583
590
  const searchCriteria = {
584
591
  repositoryId: repositoryId,
@@ -599,7 +606,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
599
606
  searchCriteria.status = 0;
600
607
  // 'all' doesn't need to be set
601
608
  }
602
- const pullRequests = await this.withAuthRetry(() => gitApi.getPullRequests(repositoryId, searchCriteria, this.config.project, undefined, // maxCommentLength
609
+ const pullRequests = await this.withAuthRetry(() => gitApi.getPullRequests(repositoryId, searchCriteria, project, undefined, // maxCommentLength
603
610
  params.skip || 0, params.top || 50));
604
611
  // Note: Work item integration could be added here in the future
605
612
  // For now, we return the basic pull request data with rich reviewer information
@@ -616,6 +623,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
616
623
  async createPullRequest(params) {
617
624
  try {
618
625
  const gitApi = await this.getGitApi();
626
+ const project = params.project || this.config.project;
619
627
  const pullRequest = {
620
628
  sourceRefName: params.sourceRefName,
621
629
  targetRefName: params.targetRefName,
@@ -624,8 +632,8 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
624
632
  reviewers: params.reviewers ? params.reviewers.map(id => ({ id })) : undefined
625
633
  };
626
634
  // Resolve repository name/ID to actual repository ID
627
- const repositoryId = await this.resolveRepositoryId(params.repository);
628
- const createdPullRequest = await gitApi.createPullRequest(pullRequest, repositoryId, this.config.project);
635
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
636
+ const createdPullRequest = await gitApi.createPullRequest(pullRequest, repositoryId, project);
629
637
  return createdPullRequest;
630
638
  }
631
639
  catch (error) {
@@ -639,16 +647,17 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
639
647
  /**
640
648
  * Get policy evaluations for a pull request
641
649
  */
642
- async getPolicyEvaluations(repository, pullRequestId) {
650
+ async getPolicyEvaluations(repository, pullRequestId, projectOverride) {
643
651
  try {
644
652
  const policyApi = await this.connection.getPolicyApi();
653
+ const effectiveProject = projectOverride || this.config.project;
645
654
  // Need project GUID for artifact ID
646
655
  const coreApi = await this.connection.getCoreApi();
647
- const project = await coreApi.getProject(this.config.project);
656
+ const project = await coreApi.getProject(effectiveProject);
648
657
  const projectId = project.id;
649
658
  // Artifact ID format uses %2F between segments (per MEMORY.md)
650
659
  const artifactId = `vstfs:///CodeReview/CodeReviewId/${projectId}%2F${pullRequestId}`;
651
- const evaluations = await policyApi.getPolicyEvaluations(this.config.project, artifactId);
660
+ const evaluations = await policyApi.getPolicyEvaluations(effectiveProject, artifactId);
652
661
  return evaluations || [];
653
662
  }
654
663
  catch (error) {
@@ -659,14 +668,15 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
659
668
  async getPullRequest(params) {
660
669
  try {
661
670
  const gitApi = await this.getGitApi();
671
+ const project = params.project || this.config.project;
662
672
  // Resolve repository name/ID to actual repository ID
663
- const repositoryId = await this.resolveRepositoryId(params.repository);
664
- const pullRequest = await this.withAuthRetry(() => gitApi.getPullRequest(repositoryId, params.pullRequestId, this.config.project));
673
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
674
+ const pullRequest = await this.withAuthRetry(() => gitApi.getPullRequest(repositoryId, params.pullRequestId, project));
665
675
  // Create enhanced response with work items
666
676
  const enhancedPullRequest = { ...pullRequest };
667
677
  // Fetch associated work items
668
678
  try {
669
- const workItemRefs = await gitApi.getPullRequestWorkItemRefs(repositoryId, params.pullRequestId, this.config.project);
679
+ const workItemRefs = await gitApi.getPullRequestWorkItemRefs(repositoryId, params.pullRequestId, project);
670
680
  if (workItemRefs && workItemRefs.length > 0) {
671
681
  // Get work item IDs from references
672
682
  const workItemIds = workItemRefs
@@ -679,7 +689,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
679
689
  if (workItemIds.length > 0) {
680
690
  // Fetch work item details
681
691
  const witApi = await this.connection.getWorkItemTrackingApi();
682
- const workItems = await witApi.getWorkItems(workItemIds, undefined, undefined, undefined, undefined, this.config.project);
692
+ const workItems = await witApi.getWorkItems(workItemIds, undefined, undefined, undefined, undefined, project);
683
693
  // Add work items to pull request object
684
694
  enhancedPullRequest.workItems = workItems.map(wi => ({
685
695
  id: wi.id,
@@ -701,7 +711,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
701
711
  const include = params.include;
702
712
  if (!include || include.length === 0 || include.includes('policies')) {
703
713
  try {
704
- const evaluations = await this.getPolicyEvaluations(params.repository, params.pullRequestId);
714
+ const evaluations = await this.getPolicyEvaluations(params.repository, params.pullRequestId, project);
705
715
  enhancedPullRequest.policyEvaluations = evaluations;
706
716
  }
707
717
  catch {
@@ -723,14 +733,15 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
723
733
  async getPullRequestComments(params) {
724
734
  try {
725
735
  const gitApi = await this.getGitApi();
736
+ const project = params.project || this.config.project;
726
737
  // Resolve repository name/ID to actual repository ID
727
- const repositoryId = await this.resolveRepositoryId(params.repository);
738
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
728
739
  if (params.threadId) {
729
- const thread = await gitApi.getPullRequestThread(repositoryId, params.pullRequestId, params.threadId, this.config.project);
740
+ const thread = await gitApi.getPullRequestThread(repositoryId, params.pullRequestId, params.threadId, project);
730
741
  return thread;
731
742
  }
732
743
  else {
733
- let threads = await gitApi.getThreads(repositoryId, params.pullRequestId, this.config.project);
744
+ let threads = await gitApi.getThreads(repositoryId, params.pullRequestId, project);
734
745
  // Apply status filter
735
746
  if (params.status && threads) {
736
747
  const statusMap = {
@@ -761,14 +772,15 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
761
772
  async approvePullRequest(params) {
762
773
  try {
763
774
  const gitApi = await this.getGitApi();
775
+ const project = params.project || this.config.project;
764
776
  // Resolve repository name/ID to actual repository ID
765
- const repositoryId = await this.resolveRepositoryId(params.repository);
777
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
766
778
  // Resolve current user's identity (the "me" shorthand isn't supported by all ADO configurations)
767
779
  const reviewerId = await this.getAuthenticatedUserId();
768
780
  const vote = {
769
781
  vote: 10
770
782
  };
771
- const result = await gitApi.createPullRequestReviewer(vote, repositoryId, params.pullRequestId, reviewerId, this.config.project);
783
+ const result = await gitApi.createPullRequestReviewer(vote, repositoryId, params.pullRequestId, reviewerId, project);
772
784
  return result;
773
785
  }
774
786
  catch (error) {
@@ -782,6 +794,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
782
794
  async mergePullRequest(params) {
783
795
  try {
784
796
  const gitApi = await this.getGitApi();
797
+ const project = params.project || this.config.project;
785
798
  // Convert string merge strategy to number
786
799
  let mergeStrategy = 1; // Default to noFastForward
787
800
  if (params.mergeStrategy === 'rebase')
@@ -790,13 +803,13 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
790
803
  mergeStrategy = 3;
791
804
  else if (params.mergeStrategy === 'squash')
792
805
  mergeStrategy = 4;
793
- let repositoryId = await this.resolveRepositoryId(params.repository);
806
+ let repositoryId = await this.resolveRepositoryId(params.repository, project);
794
807
  const result = await gitApi.updatePullRequest({
795
808
  status: 3, // 3 = completed in PullRequestStatus enum
796
809
  completionOptions: {
797
810
  mergeStrategy: mergeStrategy
798
811
  }
799
- }, repositoryId, params.pullRequestId, this.config.project);
812
+ }, repositoryId, params.pullRequestId, project);
800
813
  return result;
801
814
  }
802
815
  catch (error) {
@@ -810,6 +823,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
810
823
  async completePullRequest(params) {
811
824
  try {
812
825
  const gitApi = await this.getGitApi();
826
+ const project = params.project || params.projectId || this.config.project;
813
827
  // Get the current pull request
814
828
  const pullRequest = await gitApi.getPullRequestById(params.pullRequestId);
815
829
  // Convert string merge strategy to number
@@ -820,7 +834,7 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
820
834
  mergeStrategy = 3;
821
835
  else if (params.mergeStrategy === 'squash')
822
836
  mergeStrategy = 4;
823
- let repositoryId = await this.resolveRepositoryId(params.repository);
837
+ let repositoryId = await this.resolveRepositoryId(params.repository, project);
824
838
  // Update the pull request to completed status
825
839
  const updatedPullRequest = await gitApi.updatePullRequest({
826
840
  status: 3, // 3 = completed in PullRequestStatus enum
@@ -842,11 +856,12 @@ class GitService extends AzureDevOpsService_1.AzureDevOpsService {
842
856
  async addPullRequestInlineComment(params) {
843
857
  try {
844
858
  const gitApi = await this.getGitApi();
845
- let repositoryId = await this.resolveRepositoryId(params.repository);
859
+ const project = params.project || this.config.project;
860
+ let repositoryId = await this.resolveRepositoryId(params.repository, project);
846
861
  // Get the latest iteration number
847
- const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId);
862
+ const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId, project);
848
863
  // Get the changes for the file to get the change tracking ID
849
- const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, this.config.project);
864
+ const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, project);
850
865
  // Helper function to normalize paths by removing leading slash
851
866
  const normalizePath = (path) => {
852
867
  return path.startsWith('/') ? path.substring(1) : path;
@@ -948,7 +963,7 @@ Note: You can only add inline comments to files that have been modified in the P
948
963
  }
949
964
  };
950
965
  // Create the thread (which includes the comment)
951
- const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, this.config.project);
966
+ const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, project);
952
967
  return result;
953
968
  }
954
969
  catch (error) {
@@ -992,6 +1007,7 @@ Original error: ${errorMessage}`);
992
1007
  async addPullRequestFileComment(params) {
993
1008
  try {
994
1009
  const gitApi = await this.getGitApi();
1010
+ const project = params.project || this.config.project;
995
1011
  // Create a thread with proper context for a file-level comment
996
1012
  // PR comments are markdown-native — normalise literal \n escapes from LLM tool calls.
997
1013
  const content = params.format === 'html'
@@ -1010,9 +1026,9 @@ Original error: ${errorMessage}`);
1010
1026
  }
1011
1027
  };
1012
1028
  // Resolve repository name/ID to actual repository ID
1013
- const repositoryId = await this.resolveRepositoryId(params.repository);
1029
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1014
1030
  // Create the thread (which includes the comment)
1015
- const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, this.config.project);
1031
+ const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, project);
1016
1032
  return result;
1017
1033
  }
1018
1034
  catch (error) {
@@ -1026,6 +1042,7 @@ Original error: ${errorMessage}`);
1026
1042
  async addPullRequestComment(params) {
1027
1043
  try {
1028
1044
  const gitApi = await this.getGitApi();
1045
+ const project = params.project || this.config.project;
1029
1046
  // Create a thread for a general PR comment (no file context)
1030
1047
  // PR comments are markdown-native — normalise literal \n escapes from LLM tool calls.
1031
1048
  const content = params.format === 'html'
@@ -1041,9 +1058,9 @@ Original error: ${errorMessage}`);
1041
1058
  // No threadContext for general PR comments
1042
1059
  };
1043
1060
  // Resolve repository name/ID to actual repository ID
1044
- const repositoryId = await this.resolveRepositoryId(params.repository);
1061
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1045
1062
  // Create the thread (which includes the comment)
1046
- const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, this.config.project);
1063
+ const result = await gitApi.createThread(thread, repositoryId, params.pullRequestId, project);
1047
1064
  return result;
1048
1065
  }
1049
1066
  catch (error) {
@@ -1057,16 +1074,17 @@ Original error: ${errorMessage}`);
1057
1074
  async getPullRequestFileChanges(params) {
1058
1075
  try {
1059
1076
  const gitApi = await this.getGitApi();
1077
+ const project = params.project || this.config.project;
1060
1078
  // Resolve repository name/ID to actual repository ID
1061
- const repositoryId = await this.resolveRepositoryId(params.repository);
1079
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1062
1080
  // If path is provided, we need to get the changes for that specific file
1063
1081
  if (params.path) {
1064
1082
  // Get the latest iteration number
1065
- const iterationNumber = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId);
1083
+ const iterationNumber = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId, project);
1066
1084
  let changes = null;
1067
1085
  try {
1068
1086
  // Get the changes from the latest iteration
1069
- changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, iterationNumber, this.config.project);
1087
+ changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, iterationNumber, project);
1070
1088
  }
1071
1089
  catch (error) {
1072
1090
  console.error('Error getting PR changes:', error);
@@ -1097,8 +1115,8 @@ Original error: ${errorMessage}`);
1097
1115
  // Modified file - get both versions and calculate diff
1098
1116
  try {
1099
1117
  const [originalContent, currentContent] = await Promise.all([
1100
- this.getFileContentByObjectId(repositoryId, change.item.originalObjectId),
1101
- this.getFileContentByObjectId(repositoryId, change.item.objectId)
1118
+ this.getFileContentByObjectId(repositoryId, change.item.originalObjectId, project),
1119
+ this.getFileContentByObjectId(repositoryId, change.item.objectId, project)
1102
1120
  ]);
1103
1121
  diffContent = this.calculateUnifiedDiff(originalContent, currentContent, change.item.path);
1104
1122
  diffContent = this.addInlineCommentGuidance(diffContent, change.changeType);
@@ -1111,7 +1129,7 @@ Original error: ${errorMessage}`);
1111
1129
  else if (change.changeType === 1 && change.item?.objectId) {
1112
1130
  // Added file - get new content and format as all additions
1113
1131
  try {
1114
- const newContent = await this.getFileContentByObjectId(repositoryId, change.item.objectId);
1132
+ const newContent = await this.getFileContentByObjectId(repositoryId, change.item.objectId, project);
1115
1133
  diffContent = this.calculateAddedFileDiff(newContent, change.item.path);
1116
1134
  }
1117
1135
  catch (error) {
@@ -1122,7 +1140,7 @@ Original error: ${errorMessage}`);
1122
1140
  else if (change.changeType === 3 && change.item?.originalObjectId) {
1123
1141
  // Deleted file - get original content and format as all deletions
1124
1142
  try {
1125
- const originalContent = await this.getFileContentByObjectId(repositoryId, change.item.originalObjectId);
1143
+ const originalContent = await this.getFileContentByObjectId(repositoryId, change.item.originalObjectId, project);
1126
1144
  diffContent = this.calculateDeletedFileDiff(originalContent, change.item.path);
1127
1145
  }
1128
1146
  catch (error) {
@@ -1142,8 +1160,8 @@ Original error: ${errorMessage}`);
1142
1160
  }
1143
1161
  // If no path is provided, get all changes with diffs
1144
1162
  // Get the latest iteration number
1145
- const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId);
1146
- const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, this.config.project);
1163
+ const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId, project);
1164
+ const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, project);
1147
1165
  // Enhance with diff content for each change (smart selection to show variety)
1148
1166
  const allChanges = changes.changeEntries || [];
1149
1167
  // Smart selection: try to get examples of different change types
@@ -1168,8 +1186,8 @@ Original error: ${errorMessage}`);
1168
1186
  // Modified file - get both versions and calculate diff
1169
1187
  try {
1170
1188
  const [originalContent, currentContent] = await Promise.all([
1171
- this.getFileContentByObjectId(repositoryId, change.item.originalObjectId),
1172
- this.getFileContentByObjectId(repositoryId, change.item.objectId)
1189
+ this.getFileContentByObjectId(repositoryId, change.item.originalObjectId, project),
1190
+ this.getFileContentByObjectId(repositoryId, change.item.objectId, project)
1173
1191
  ]);
1174
1192
  diffContent = this.calculateUnifiedDiff(originalContent, currentContent, change.item.path);
1175
1193
  diffContent = this.addInlineCommentGuidance(diffContent, change.changeType);
@@ -1182,7 +1200,7 @@ Original error: ${errorMessage}`);
1182
1200
  else if (change.changeType === 1 && change.item?.objectId) {
1183
1201
  // Added file - get new content and format as all additions
1184
1202
  try {
1185
- const newContent = await this.getFileContentByObjectId(repositoryId, change.item.objectId);
1203
+ const newContent = await this.getFileContentByObjectId(repositoryId, change.item.objectId, project);
1186
1204
  diffContent = this.calculateAddedFileDiff(newContent, change.item.path);
1187
1205
  }
1188
1206
  catch (error) {
@@ -1193,7 +1211,7 @@ Original error: ${errorMessage}`);
1193
1211
  else if (change.changeType === 3 && change.item?.originalObjectId) {
1194
1212
  // Deleted file - get original content and format as all deletions
1195
1213
  try {
1196
- const originalContent = await this.getFileContentByObjectId(repositoryId, change.item.originalObjectId);
1214
+ const originalContent = await this.getFileContentByObjectId(repositoryId, change.item.originalObjectId, project);
1197
1215
  diffContent = this.calculateDeletedFileDiff(originalContent, change.item.path);
1198
1216
  }
1199
1217
  catch (error) {
@@ -1224,11 +1242,12 @@ Original error: ${errorMessage}`);
1224
1242
  async getPullRequestChangesCount(params) {
1225
1243
  try {
1226
1244
  const gitApi = await this.getGitApi();
1245
+ const project = params.project || this.config.project;
1227
1246
  // Resolve repository name/ID to actual repository ID
1228
- const repositoryId = await this.resolveRepositoryId(params.repository);
1247
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1229
1248
  // Get the latest iteration number
1230
- const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId);
1231
- const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, this.config.project);
1249
+ const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId, project);
1250
+ const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, project);
1232
1251
  return {
1233
1252
  totalChanges: changes.changeEntries?.length || 0,
1234
1253
  addedFiles: changes.changeEntries?.filter(entry => entry.changeType === GitInterfaces_1.VersionControlChangeType.Add).length || 0,
@@ -1247,11 +1266,12 @@ Original error: ${errorMessage}`);
1247
1266
  async getAllPullRequestChanges(params) {
1248
1267
  try {
1249
1268
  const gitApi = await this.getGitApi();
1269
+ const project = params.project || this.config.project;
1250
1270
  // Resolve repository name/ID to actual repository ID
1251
- const repositoryId = await this.resolveRepositoryId(params.repository);
1271
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1252
1272
  // Get the latest iteration number
1253
- const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId);
1254
- const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, this.config.project);
1273
+ const latestIteration = await this.getLatestPullRequestIteration(repositoryId, params.pullRequestId, project);
1274
+ const changes = await gitApi.getPullRequestIterationChanges(repositoryId, params.pullRequestId, latestIteration, project);
1255
1275
  let changeEntries = changes.changeEntries || [];
1256
1276
  // Apply pagination if specified
1257
1277
  if (params.skip && params.skip > 0) {
@@ -1273,12 +1293,13 @@ Original error: ${errorMessage}`);
1273
1293
  /**
1274
1294
  * Get list of changed files in a pull request (useful for knowing which files can have inline comments)
1275
1295
  */
1276
- async getPullRequestChangedFilesList(repositoryId, pullRequestId) {
1296
+ async getPullRequestChangedFilesList(repositoryId, pullRequestId, project) {
1277
1297
  try {
1278
1298
  const gitApi = await this.getGitApi();
1299
+ const effectiveProject = project || this.config.project;
1279
1300
  // Get the latest iteration number
1280
- const latestIteration = await this.getLatestPullRequestIteration(repositoryId, pullRequestId);
1281
- const changes = await gitApi.getPullRequestIterationChanges(repositoryId, pullRequestId, latestIteration, this.config.project);
1301
+ const latestIteration = await this.getLatestPullRequestIteration(repositoryId, pullRequestId, effectiveProject);
1302
+ const changes = await gitApi.getPullRequestIterationChanges(repositoryId, pullRequestId, latestIteration, effectiveProject);
1282
1303
  return changes.changeEntries?.map(entry => entry.item?.path).filter((path) => Boolean(path)) || [];
1283
1304
  }
1284
1305
  catch (error) {
@@ -1414,7 +1435,8 @@ Original error: ${errorMessage}`);
1414
1435
  */
1415
1436
  async updatePullRequest(params) {
1416
1437
  const gitApi = await this.getGitApi();
1417
- const repositoryId = await this.resolveRepositoryId(params.repository);
1438
+ const project = params.project || this.config.project;
1439
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1418
1440
  const updatePayload = {};
1419
1441
  if (params.title !== undefined)
1420
1442
  updatePayload.title = params.title;
@@ -1448,14 +1470,15 @@ Original error: ${errorMessage}`);
1448
1470
  updatePayload.completionOptions = completionOptions;
1449
1471
  }
1450
1472
  }
1451
- return await gitApi.updatePullRequest(updatePayload, repositoryId, params.pullRequestId, this.config.project);
1473
+ return await gitApi.updatePullRequest(updatePayload, repositoryId, params.pullRequestId, project);
1452
1474
  }
1453
1475
  /**
1454
1476
  * Add or remove reviewers on a pull request.
1455
1477
  */
1456
1478
  async updatePullRequestReviewers(params) {
1457
1479
  const gitApi = await this.getGitApi();
1458
- const repositoryId = await this.resolveRepositoryId(params.repository);
1480
+ const project = params.project || this.config.project;
1481
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1459
1482
  const results = { added: [], removed: [] };
1460
1483
  if (params.reviewersToAdd && params.reviewersToAdd.length > 0) {
1461
1484
  for (const reviewer of params.reviewersToAdd) {
@@ -1463,13 +1486,13 @@ Original error: ${errorMessage}`);
1463
1486
  id: reviewer,
1464
1487
  isRequired: params.makeRequired || false,
1465
1488
  };
1466
- const result = await gitApi.createPullRequestReviewer(reviewerObj, repositoryId, params.pullRequestId, reviewer, this.config.project);
1489
+ const result = await gitApi.createPullRequestReviewer(reviewerObj, repositoryId, params.pullRequestId, reviewer, project);
1467
1490
  results.added.push(result);
1468
1491
  }
1469
1492
  }
1470
1493
  if (params.reviewersToRemove && params.reviewersToRemove.length > 0) {
1471
1494
  for (const reviewer of params.reviewersToRemove) {
1472
- await gitApi.deletePullRequestReviewer(repositoryId, params.pullRequestId, reviewer, this.config.project);
1495
+ await gitApi.deletePullRequestReviewer(repositoryId, params.pullRequestId, reviewer, project);
1473
1496
  results.removed.push(reviewer);
1474
1497
  }
1475
1498
  }
@@ -1480,7 +1503,8 @@ Original error: ${errorMessage}`);
1480
1503
  */
1481
1504
  async replyToComment(params) {
1482
1505
  const gitApi = await this.getGitApi();
1483
- const repositoryId = await this.resolveRepositoryId(params.repository);
1506
+ const project = params.project || this.config.project;
1507
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1484
1508
  // PR comments are markdown-native — normalise literal \n escapes from LLM tool calls.
1485
1509
  const commentContent = params.format === 'html'
1486
1510
  ? params.comment
@@ -1490,14 +1514,15 @@ Original error: ${errorMessage}`);
1490
1514
  parentCommentId: 0, // 0 = reply to thread
1491
1515
  commentType: 1, // text comment
1492
1516
  };
1493
- return await gitApi.createComment(comment, repositoryId, params.pullRequestId, params.threadId, this.config.project);
1517
+ return await gitApi.createComment(comment, repositoryId, params.pullRequestId, params.threadId, project);
1494
1518
  }
1495
1519
  /**
1496
1520
  * Update a comment thread's status (resolve/reactivate).
1497
1521
  */
1498
1522
  async updatePullRequestThread(params) {
1499
1523
  const gitApi = await this.getGitApi();
1500
- const repositoryId = await this.resolveRepositoryId(params.repository);
1524
+ const project = params.project || this.config.project;
1525
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1501
1526
  const statusMap = {
1502
1527
  'active': 1,
1503
1528
  'fixed': 2,
@@ -1510,20 +1535,21 @@ Original error: ${errorMessage}`);
1510
1535
  const threadUpdate = {
1511
1536
  status: statusMap[params.status] ?? 1,
1512
1537
  };
1513
- return await gitApi.updateThread(threadUpdate, repositoryId, params.pullRequestId, params.threadId, this.config.project);
1538
+ return await gitApi.updateThread(threadUpdate, repositoryId, params.pullRequestId, params.threadId, project);
1514
1539
  }
1515
1540
  /**
1516
1541
  * Create a new branch from a source ref.
1517
1542
  */
1518
1543
  async createBranch(params) {
1519
1544
  const gitApi = await this.getGitApi();
1520
- const repositoryId = await this.resolveRepositoryId(params.repository);
1545
+ const project = params.project || this.config.project;
1546
+ const repositoryId = await this.resolveRepositoryId(params.repository, project);
1521
1547
  // Resolve source ref to a commit ID
1522
1548
  let sourceObjectId = params.sourceRef;
1523
1549
  // If sourceRef looks like a branch name, resolve it to commit ID
1524
1550
  if (!sourceObjectId.match(/^[0-9a-f]{40}$/i)) {
1525
1551
  const branchName = sourceObjectId.replace(/^refs\/heads\//, '');
1526
- const branches = await gitApi.getBranches(repositoryId, this.config.project);
1552
+ const branches = await gitApi.getBranches(repositoryId, project);
1527
1553
  const branch = branches?.find((b) => b.name === branchName || b.name === `refs/heads/${branchName}`);
1528
1554
  if (!branch || !branch.commit?.commitId) {
1529
1555
  throw new Error(`Source branch '${branchName}' not found or has no commits.`);
@@ -1538,7 +1564,7 @@ Original error: ${errorMessage}`);
1538
1564
  oldObjectId: '0000000000000000000000000000000000000000',
1539
1565
  newObjectId: sourceObjectId,
1540
1566
  }];
1541
- const result = await gitApi.updateRefs(refUpdate, repositoryId, this.config.project);
1567
+ const result = await gitApi.updateRefs(refUpdate, repositoryId, project);
1542
1568
  return result?.[0];
1543
1569
  }
1544
1570
  }