@@ -5,6 +5,7 @@ import { primaryAIProviders } from '../../constants.ai';
55import type { AIGenerateDraftEventData , Source , TelemetryEvents } from '../../constants.telemetry' ;
66import type { Container } from '../../container' ;
77import { CancellationError } from '../../errors' ;
8+ import type { AdvancedFeatures , PlusFeatures } from '../../features' ;
89import type { GitCommit } from '../../git/models/commit' ;
910import { isCommit } from '../../git/models/commit' ;
1011import type { GitRevisionReference } from '../../git/models/reference' ;
@@ -13,6 +14,7 @@ import { uncommitted, uncommittedStaged } from '../../git/models/revision';
1314import { assertsCommitHasFullDetails } from '../../git/utils/commit.utils' ;
1415import { showAIModelPicker } from '../../quickpicks/aiModelPicker' ;
1516import { configuration } from '../../system/-webview/configuration' ;
17+ import { getContext } from '../../system/-webview/context' ;
1618import type { Storage } from '../../system/-webview/storage' ;
1719import { supportedInVSCodeVersion } from '../../system/-webview/vscode' ;
1820import { debounce } from '../../system/function/debounce' ;
@@ -22,6 +24,7 @@ import { lazy } from '../../system/lazy';
2224import type { Deferred } from '../../system/promise' ;
2325import { getSettledValue } from '../../system/promise' ;
2426import type { ServerConnection } from '../gk/serverConnection' ;
27+ import { ensureFeatureAccess } from '../gk/utils/-webview/acount.utils' ;
2528import type { AIActionType , AIModel , AIModelDescriptor } from './models/model' ;
2629import type { PromptTemplateContext } from './models/promptTemplates' ;
2730import type { AIProvider , AIRequestResult } from './models/provider' ;
@@ -284,11 +287,56 @@ export class AIProviderService implements Disposable {
284287 return model ;
285288 }
286289
290+ private async ensureOrgAccess ( ) : Promise < boolean > {
291+ const orgEnabled = getContext ( 'gitlens:gk:organization:ai:enabled' ) ;
292+ if ( orgEnabled === false ) {
293+ await window . showErrorMessage ( `AI features have been disabled for your organization.` ) ;
294+ return false ;
295+ }
296+
297+ return true ;
298+ }
299+
300+ private async ensureFeatureAccess (
301+ feature :
302+ | 'generateStashMessage'
303+ | 'explainCommit'
304+ | 'cloudPatchGenerateTitleAndDescription'
305+ | 'generateChangelog' ,
306+ title : string ,
307+ source : Source ,
308+ ) : Promise < boolean > {
309+ if ( ! ( await this . ensureOrgAccess ( ) ) ) return false ;
310+
311+ if (
312+ ! ( await ensureFeatureAccess (
313+ this . container ,
314+ title ,
315+ feature satisfies PlusFeatures | AdvancedFeatures ,
316+ source ,
317+ ) )
318+ ) {
319+ return false ;
320+ }
321+
322+ return true ;
323+ }
324+
287325 async explainCommit (
288326 commitOrRevision : GitRevisionReference | GitCommit ,
289327 sourceContext : Source & { type : TelemetryEvents [ 'ai/explain' ] [ 'changeType' ] } ,
290328 options ?: { cancellation ?: CancellationToken ; progress ?: ProgressOptions } ,
291329 ) : Promise < AISummarizeResult | undefined > {
330+ if (
331+ ! ( await this . ensureFeatureAccess (
332+ 'explainCommit' satisfies PlusFeatures ,
333+ 'Explaining commits requires an account with Pro access.' ,
334+ sourceContext ,
335+ ) )
336+ ) {
337+ return undefined ;
338+ }
339+
292340 const diff = await this . container . git . diff ( commitOrRevision . repoPath ) . getDiff ?.( commitOrRevision . ref ) ;
293341 if ( ! diff ?. contents ) throw new Error ( 'No changes found to explain.' ) ;
294342
@@ -339,6 +387,8 @@ export class AIProviderService implements Disposable {
339387 progress ?: ProgressOptions ;
340388 } ,
341389 ) : Promise < AISummarizeResult | undefined > {
390+ if ( ! ( await this . ensureOrgAccess ( ) ) ) return undefined ;
391+
342392 const changes : string | undefined = await this . getChanges ( changesOrRepo ) ;
343393 if ( changes == null ) return undefined ;
344394
@@ -377,6 +427,18 @@ export class AIProviderService implements Disposable {
377427 codeSuggestion ?: boolean ;
378428 } ,
379429 ) : Promise < AISummarizeResult | undefined > {
430+ if (
431+ ! ( await this . ensureFeatureAccess (
432+ 'cloudPatchGenerateTitleAndDescription' satisfies PlusFeatures ,
433+ `Generating ${
434+ options ?. codeSuggestion ? 'code suggestion' : 'cloud patch'
435+ } descriptions requires an account with Pro access.`,
436+ sourceContext ,
437+ ) )
438+ ) {
439+ return undefined ;
440+ }
441+
380442 const changes : string | undefined = await this . getChanges ( changesOrRepo ) ;
381443 if ( changes == null ) return undefined ;
382444
@@ -423,6 +485,16 @@ export class AIProviderService implements Disposable {
423485 progress ?: ProgressOptions ;
424486 } ,
425487 ) : Promise < AISummarizeResult | undefined > {
488+ if (
489+ ! ( await this . ensureFeatureAccess (
490+ 'generateStashMessage' satisfies PlusFeatures ,
491+ 'Generating stash messages requires an account with Pro access.' ,
492+ source ,
493+ ) )
494+ ) {
495+ return undefined ;
496+ }
497+
426498 const changes : string | undefined = await this . getChanges ( changesOrRepo ) ;
427499 if ( changes == null ) {
428500 options ?. generating ?. cancel ( ) ;
@@ -458,6 +530,16 @@ export class AIProviderService implements Disposable {
458530 source : Source ,
459531 options ?: { cancellation ?: CancellationToken ; progress ?: ProgressOptions } ,
460532 ) : Promise < AIResult | undefined > {
533+ if (
534+ ! ( await this . ensureFeatureAccess (
535+ 'generateChangelog' satisfies AdvancedFeatures ,
536+ 'Generating changelogs requires an account with Pro access.' ,
537+ source ,
538+ ) )
539+ ) {
540+ return undefined ;
541+ }
542+
461543 const result = await this . sendRequest (
462544 'generate-changelog' ,
463545 async ( ) => ( {
0 commit comments