@@ -8,7 +8,33 @@ interface ToolRequirement {
88 notes ?: string ;
99}
1010
11+ /**
12+ * Action-level tier requirement
13+ */
14+ interface ActionRequirement {
15+ tier : "free" | "premium" | "ultimate" ;
16+ minVersion : number ;
17+ notes ?: string ;
18+ }
19+
20+ /**
21+ * Tool with action-level requirements (for consolidated tools)
22+ */
23+ interface ToolActionRequirements {
24+ /** Default requirement when action is not specified */
25+ default : ActionRequirement ;
26+ /** Action-specific requirements (override default) */
27+ actions ?: Record < string , ActionRequirement > ;
28+ }
29+
1130export class ToolAvailability {
31+ /** Tier hierarchy for comparison: free < premium < ultimate */
32+ private static readonly TIER_ORDER : Record < string , number > = {
33+ free : 0 ,
34+ premium : 1 ,
35+ ultimate : 2 ,
36+ } ;
37+
1238 // Comprehensive tool requirements based on GitLab documentation
1339 private static toolRequirements : Record < string , ToolRequirement > = {
1440 // Core Tools - Available in Free Tier
@@ -413,7 +439,233 @@ export class ToolAvailability {
413439 unprotect_repository_tag : { minVersion : 11.3 , requiredTier : "free" } ,
414440 } ;
415441
416- public static isToolAvailable ( toolName : string ) : boolean {
442+ // ============================================================================
443+ // Consolidated Tools with Action-Level Requirements
444+ // ============================================================================
445+
446+ private static actionRequirements : Record < string , ToolActionRequirements > = {
447+ // Core tools
448+ browse_projects : {
449+ default : { tier : "free" , minVersion : 8.0 } ,
450+ } ,
451+ browse_namespaces : {
452+ default : { tier : "free" , minVersion : 9.0 } ,
453+ } ,
454+ browse_commits : {
455+ default : { tier : "free" , minVersion : 8.0 } ,
456+ } ,
457+ browse_events : {
458+ default : { tier : "free" , minVersion : 9.0 } ,
459+ } ,
460+ create_branch : {
461+ default : { tier : "free" , minVersion : 8.0 } ,
462+ } ,
463+ create_group : {
464+ default : { tier : "free" , minVersion : 8.0 } ,
465+ } ,
466+ manage_repository : {
467+ default : { tier : "free" , minVersion : 8.0 } ,
468+ } ,
469+ get_users : {
470+ default : { tier : "free" , minVersion : 8.0 } ,
471+ } ,
472+
473+ // Merge Requests
474+ browse_merge_requests : {
475+ default : { tier : "free" , minVersion : 8.0 } ,
476+ actions : {
477+ approvals : { tier : "premium" , minVersion : 10.6 , notes : "MR approvals" } ,
478+ } ,
479+ } ,
480+ browse_mr_discussions : {
481+ default : { tier : "free" , minVersion : 8.0 } ,
482+ } ,
483+ manage_merge_request : {
484+ default : { tier : "free" , minVersion : 8.0 } ,
485+ } ,
486+ manage_mr_discussion : {
487+ default : { tier : "free" , minVersion : 8.0 } ,
488+ actions : {
489+ comment : { tier : "free" , minVersion : 8.0 } ,
490+ thread : { tier : "free" , minVersion : 11.0 } ,
491+ reply : { tier : "free" , minVersion : 11.0 } ,
492+ update : { tier : "free" , minVersion : 8.0 } ,
493+ apply_suggestion : { tier : "free" , minVersion : 13.0 } ,
494+ apply_suggestions : { tier : "free" , minVersion : 13.0 } ,
495+ } ,
496+ } ,
497+ manage_draft_notes : {
498+ default : { tier : "free" , minVersion : 13.2 } ,
499+ } ,
500+
501+ // Work Items
502+ browse_work_items : {
503+ default : { tier : "free" , minVersion : 15.0 } ,
504+ } ,
505+ manage_work_item : {
506+ default : { tier : "free" , minVersion : 15.0 } ,
507+ } ,
508+
509+ // Labels
510+ browse_labels : {
511+ default : { tier : "free" , minVersion : 8.0 } ,
512+ } ,
513+ manage_label : {
514+ default : { tier : "free" , minVersion : 8.0 } ,
515+ } ,
516+
517+ // Wiki
518+ browse_wiki : {
519+ default : { tier : "free" , minVersion : 9.0 } ,
520+ } ,
521+ manage_wiki : {
522+ default : { tier : "free" , minVersion : 9.0 } ,
523+ } ,
524+
525+ // Pipelines
526+ browse_pipelines : {
527+ default : { tier : "free" , minVersion : 9.0 } ,
528+ } ,
529+ manage_pipeline : {
530+ default : { tier : "free" , minVersion : 9.0 } ,
531+ } ,
532+ manage_pipeline_job : {
533+ default : { tier : "free" , minVersion : 9.0 } ,
534+ } ,
535+
536+ // Variables
537+ browse_variables : {
538+ default : { tier : "free" , minVersion : 9.0 } ,
539+ } ,
540+ manage_variable : {
541+ default : { tier : "free" , minVersion : 9.0 } ,
542+ } ,
543+
544+ // Milestones
545+ browse_milestones : {
546+ default : { tier : "free" , minVersion : 8.0 } ,
547+ actions : {
548+ burndown : { tier : "premium" , minVersion : 12.0 , notes : "Burndown charts" } ,
549+ } ,
550+ } ,
551+ manage_milestone : {
552+ default : { tier : "free" , minVersion : 8.0 } ,
553+ } ,
554+
555+ // Files
556+ browse_files : {
557+ default : { tier : "free" , minVersion : 8.0 } ,
558+ } ,
559+ manage_files : {
560+ default : { tier : "free" , minVersion : 8.0 } ,
561+ } ,
562+
563+ // Snippets
564+ browse_snippets : {
565+ default : { tier : "free" , minVersion : 8.15 } ,
566+ } ,
567+ manage_snippet : {
568+ default : { tier : "free" , minVersion : 8.15 } ,
569+ } ,
570+
571+ // Webhooks
572+ list_webhooks : {
573+ default : { tier : "free" , minVersion : 8.0 , notes : "Project webhooks" } ,
574+ } ,
575+ manage_webhook : {
576+ default : { tier : "free" , minVersion : 8.0 , notes : "Project webhooks" } ,
577+ actions : {
578+ create_group : { tier : "premium" , minVersion : 10.4 , notes : "Group webhooks" } ,
579+ update_group : { tier : "premium" , minVersion : 10.4 , notes : "Group webhooks" } ,
580+ delete_group : { tier : "premium" , minVersion : 10.4 , notes : "Group webhooks" } ,
581+ } ,
582+ } ,
583+
584+ // Integrations
585+ list_integrations : {
586+ default : { tier : "free" , minVersion : 8.0 } ,
587+ } ,
588+ manage_integration : {
589+ default : { tier : "free" , minVersion : 8.0 } ,
590+ } ,
591+
592+ // Todos
593+ list_todos : {
594+ default : { tier : "free" , minVersion : 8.0 } ,
595+ } ,
596+ manage_todos : {
597+ default : { tier : "free" , minVersion : 8.0 } ,
598+ } ,
599+
600+ // Additional tools
601+ list_project_members : {
602+ default : { tier : "free" , minVersion : 8.0 } ,
603+ } ,
604+ list_group_iterations : {
605+ default : { tier : "premium" , minVersion : 13.1 , notes : "Iterations/Sprints" } ,
606+ } ,
607+ download_attachment : {
608+ default : { tier : "free" , minVersion : 10.0 } ,
609+ } ,
610+ } ;
611+
612+ /**
613+ * Get requirement for a tool, optionally with action
614+ */
615+ public static getActionRequirement (
616+ toolName : string ,
617+ action ?: string
618+ ) : ActionRequirement | undefined {
619+ const toolReq = this . actionRequirements [ toolName ] ;
620+ if ( ! toolReq ) return undefined ;
621+
622+ // If action specified, check action-specific requirement first
623+ if ( action && toolReq . actions ?. [ action ] ) {
624+ return toolReq . actions [ action ] ;
625+ }
626+
627+ return toolReq . default ;
628+ }
629+
630+ /**
631+ * Get the highest tier required by any action of a tool
632+ */
633+ public static getHighestTier ( toolName : string ) : "free" | "premium" | "ultimate" {
634+ const toolReq = this . actionRequirements [ toolName ] ;
635+ if ( ! toolReq ) {
636+ // Fallback to legacy requirements
637+ const legacy = this . toolRequirements [ toolName ] ;
638+ return legacy ?. requiredTier ?? "free" ;
639+ }
640+
641+ let highest = toolReq . default . tier ;
642+
643+ if ( toolReq . actions ) {
644+ for ( const actionReq of Object . values ( toolReq . actions ) ) {
645+ if ( this . TIER_ORDER [ actionReq . tier ] > this . TIER_ORDER [ highest ] ) {
646+ highest = actionReq . tier ;
647+ }
648+ }
649+ }
650+
651+ return highest ;
652+ }
653+
654+ /**
655+ * Get all actions that require a specific tier or higher
656+ */
657+ public static getTierRestrictedActions ( toolName : string , tier : "premium" | "ultimate" ) : string [ ] {
658+ const toolReq = this . actionRequirements [ toolName ] ;
659+ if ( ! toolReq ?. actions ) return [ ] ;
660+
661+ const minLevel = this . TIER_ORDER [ tier ] ;
662+
663+ return Object . entries ( toolReq . actions )
664+ . filter ( ( [ , req ] ) => this . TIER_ORDER [ req . tier ] >= minLevel )
665+ . map ( ( [ action ] ) => action ) ;
666+ }
667+
668+ public static isToolAvailable ( toolName : string , action ?: string ) : boolean {
417669 const connectionManager = ConnectionManager . getInstance ( ) ;
418670
419671 // Add null check as extra safety
@@ -424,6 +676,18 @@ export class ToolAvailability {
424676
425677 try {
426678 const instanceInfo = connectionManager . getInstanceInfo ( ) ;
679+
680+ // Check action requirements first (consolidated tools)
681+ const actionReq = this . getActionRequirement ( toolName , action ) ;
682+ if ( actionReq ) {
683+ const version = this . parseVersion ( instanceInfo . version ) ;
684+ if ( version < actionReq . minVersion ) {
685+ return false ;
686+ }
687+ return this . isTierSufficient ( instanceInfo . tier , actionReq . tier ) ;
688+ }
689+
690+ // Fallback to legacy requirements
427691 const requirement = this . toolRequirements [ toolName ] ;
428692
429693 if ( ! requirement ) {
@@ -459,10 +723,26 @@ export class ToolAvailability {
459723 }
460724
461725 public static getAvailableTools ( ) : string [ ] {
462- return Object . keys ( this . toolRequirements ) . filter ( tool => this . isToolAvailable ( tool ) ) ;
726+ // Combine tools from both legacy toolRequirements and new actionRequirements
727+ const allTools = new Set ( [
728+ ...Object . keys ( this . toolRequirements ) ,
729+ ...Object . keys ( this . actionRequirements ) ,
730+ ] ) ;
731+ return Array . from ( allTools ) . filter ( tool => this . isToolAvailable ( tool ) ) ;
463732 }
464733
465- public static getToolRequirement ( toolName : string ) : ToolRequirement | undefined {
734+ public static getToolRequirement ( toolName : string , action ?: string ) : ToolRequirement | undefined {
735+ // Check action requirements first (consolidated tools)
736+ const actionReq = this . getActionRequirement ( toolName , action ) ;
737+ if ( actionReq ) {
738+ return {
739+ minVersion : actionReq . minVersion ,
740+ requiredTier : actionReq . tier ,
741+ notes : actionReq . notes ,
742+ } ;
743+ }
744+
745+ // Fallback to legacy requirements
466746 return this . toolRequirements [ toolName ] ;
467747 }
468748
0 commit comments