@githits/mcp 0.10.1 → 0.11.0

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.
@@ -1314,4 +1314,4 @@ query ReadPackageDoc($pageId: String!) {
1314
1314
  baseUrl
1315
1315
  }
1316
1316
  }
1317
- }`;class PackageIntelligenceServiceImpl{endpointUrl;tokenProvider;fetchFn;runtime;constructor(endpointUrl,tokenProvider,fetchFn=globalThis.fetch,runtime={}){this.endpointUrl=endpointUrl;this.tokenProvider=tokenProvider;this.fetchFn=fetchFn;this.runtime=runtime}async packageSummary(params){return withTelemetrySpan("pkg-intel.summary.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageSummary(token,params)}))}async executePackageSummary(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_SUMMARY_QUERY,variables:{registry:params.registry,name:params.packageName,includeVerboseFields:params.includeVerboseFields!==false},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=graphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.packageSummary;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalise(data)}createHttpError(response){return createPackageIntelligenceHttpError(response)}createTransportError(error){return createPackageIntelligenceTransportError(error)}createGraphQLError(errors){return createPackageIntelligenceGraphQLError(errors,this.runtime.clientVersion)}normalise(data){const name=data.package?.name??undefined;const latestVersion=data.package?.latestVersion??undefined;if(!name||!latestVersion){throw new MalformedPackageIntelligenceResponseError("Package summary response missing required name/latestVersion.")}const pkg=data.package;const github=pkg?.githubRepository;const identity={name,latestVersion,registry:pkg?.registry??undefined,description:pkg?.description??undefined,latestVersionPublishedAt:pkg?.latestVersionPublishedAt??undefined,homepage:pkg?.homepage??undefined,repositoryUrl:pkg?.repositoryUrl??undefined,license:pkg?.license??undefined,downloadsLastMonth:pkg?.downloadsLastMonth??undefined,downloadsTotal:pkg?.downloadsTotal??undefined,githubRepository:github?{stargazersCount:github.stargazersCount??undefined,forksCount:github.forksCount??undefined,openIssuesCount:github.openIssuesCount??undefined,archived:github.archived??undefined,language:github.language??undefined,topics:github.topics??undefined,pushedAt:github.pushedAt??undefined}:undefined};const security=data.security?{vulnerabilityCount:data.security.vulnerabilityCount??undefined,hasCurrentVulnerabilities:data.security.hasCurrentVulnerabilities??undefined,recentVulnerabilities:data.security.recentVulnerabilities?.map((vuln)=>({osvId:vuln.osvId??undefined,summary:vuln.summary??undefined,severityScore:vuln.severityScore??undefined,publishedAt:vuln.publishedAt??undefined}))??undefined}:undefined;const latestChangelogs=data.latestChangelogs?.map((entry)=>({version:entry.version??undefined,publishedAt:entry.publishedAt??undefined,body:entry.body??undefined}))??undefined;return{package:identity,security,latestChangelogs}}async packageVulnerabilities(params){return withTelemetrySpan("pkg-intel.vulnerabilities.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageVulnerabilities(token,params)}))}async executePackageVulnerabilities(token,params){let after=null;let firstPage;const entries=[];const seenCursors=new Set;do{const page=await this.fetchPackageVulnerabilitiesPage(token,params,after);if(!firstPage)firstPage=page;const advisoryPage=page.security?.advisories;if(!advisoryPage){after=null;break}entries.push(...advisoryPage.entries);if(advisoryPage.pageInfo.hasNextPage){const nextCursor=advisoryPage.pageInfo.endCursor;if(!nextCursor){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination omitted next cursor.")}if(seenCursors.has(nextCursor)){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination repeated a cursor.")}seenCursors.add(nextCursor);after=nextCursor}else{after=null}}while(after!==null);if(!firstPage){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}if(firstPage.security){const expectedCount=firstPage.security.advisories.pageInfo.totalCount;if(entries.length!==expectedCount){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination returned an incomplete advisory set.")}}const data=firstPage.security?{...firstPage,security:{...firstPage.security,advisories:{...firstPage.security.advisories,entries}}}:firstPage;return this.normaliseVulnerabilityReport(data)}async fetchPackageVulnerabilitiesPage(token,params,after){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_VULNERABILITIES_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,minSeverity:params.minSeverity,includeWithdrawn:params.includeWithdrawn,scope:params.advisoryScope,after},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=vulnerabilitiesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageVulnerabilities;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return data}normaliseVulnerabilityReport(data){const name=data.package?.name??undefined;const version=data.package?.version??undefined;if(!name||!version){throw new MalformedPackageIntelligenceResponseError("Vulnerability report response missing required name/version.")}const identity={name,version,registry:data.package?.registry??undefined,publishedAt:data.package?.publishedAt??undefined,deprecated:data.package?.deprecated??undefined,deprecationReason:data.package?.deprecationReason??undefined};const security=data.security?{affectedVulnerabilityCount:data.security.affectedVulnerabilityCount,nonAffectingVulnerabilityCount:data.security.nonAffectingVulnerabilityCount,allVulnerabilityCount:data.security.allVulnerabilityCount,currentVersionAffected:data.security.currentVersionAffected??undefined,vulnerabilities:data.security.advisories.entries.map((vuln)=>({osvId:vuln.osvId??undefined,summary:vuln.summary??undefined,severityScore:vuln.severityScore??undefined,severityType:vuln.severityType??undefined,affectedVersionRanges:vuln.affectedVersionRanges??undefined,affectedVersionRangesCount:vuln.affectedVersionRangesCount,affectedVersionRangesTruncated:vuln.affectedVersionRangesTruncated,fixedInVersions:vuln.fixedInVersions??undefined,publishedAt:vuln.publishedAt??undefined,modifiedAt:vuln.modifiedAt??undefined,withdrawnAt:vuln.withdrawnAt??undefined,aliases:vuln.aliases??undefined,isMalicious:vuln.isMalicious??undefined,affectsInspectedVersion:vuln.affectsInspectedVersion,matchedAffectedVersionRanges:vuln.matchedAffectedVersionRanges,duplicateIds:vuln.duplicateIds})),upgradePaths:data.security.upgradePaths??undefined}:undefined;return{package:identity,security}}async packageDependencies(params){return withTelemetrySpan("pkg-intel.dependencies.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageDependencies(token,params)}))}async packageUpgradeDependencyProbe(params){return withTelemetrySpan("pkg-intel.upgrade-dependency-probe.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageUpgradeDependencyProbe(token,params)}))}async packageUpgradeReview(params){return withTelemetrySpan("pkg-intel.upgrade-review.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageUpgradeReview(token,params)}))}async executePackageUpgradeReview(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_UPGRADE_REVIEW_QUERY,variables:{packages:params.packages,includeTransitiveSecurity:params.includeTransitiveSecurity,includeDependencyIssues:params.includeDependencyIssues,minSeverity:params.minSeverity,changelogLimit:params.changelogLimit},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageUpgradeReviewGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.packageUpgradeReview;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return stripNullProperties(data)}async executePackageUpgradeDependencyProbe(token,params){const includeTransitiveRisk=params.includeTransitiveSecurity===true||params.includeDependencyIssues===true||params.includeDependencyChanges===true;let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_UPGRADE_DEPENDENCY_PROBE_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,includeTransitiveRisk,includeTransitiveSecurity:params.includeTransitiveSecurity===true,includeDependencyIssues:params.includeDependencyIssues===true,includeDependencyChanges:params.includeDependencyChanges===true,includeGroups:params.includeGroups===true,lifecycle:params.includeGroups===true?["peer"]:undefined,minSeverity:params.minSeverity},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=dependenciesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageDependencies;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseDependencyReport(data)}async executePackageDependencies(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_DEPENDENCIES_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,includeTransitive:params.includeTransitive,includeTransitiveDetails:params.includeTransitiveDetails!==false,includeDependencyGraph:params.includeTransitive===true,includeGroups:params.includeGroups!==false,maxDepth:params.maxDepth,lifecycle:params.lifecycle&&params.lifecycle.length>0?params.lifecycle:undefined},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=dependenciesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageDependencies;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseDependencyReport(data)}normaliseDependencyReport(data){const name=data.package?.name??undefined;const version=data.package?.version??undefined;if(!name||!version){throw new MalformedPackageIntelligenceResponseError("Package dependencies response missing required name/version.")}const identity={name,version,registry:data.package?.registry??undefined,publishedAt:data.package?.publishedAt??undefined,deprecated:data.package?.deprecated??undefined,deprecationReason:data.package?.deprecationReason??undefined};const bundle=data.dependencies;const dependencies=bundle?{direct:bundle.direct?.map((entry)=>{if(!entry.name){throw new MalformedPackageIntelligenceResponseError("Dependency entry missing required name.")}return{name:entry.name,versionConstraint:entry.versionConstraint??undefined,type:entry.type??undefined}})??undefined,transitive:bundle.transitive?{totalEdges:bundle.transitive.totalEdges??undefined,uniquePackagesCount:bundle.transitive.uniquePackagesCount??undefined,uniqueDependencies:bundle.transitive.uniqueDependencies??undefined,dependencyConflicts:bundle.transitive.dependencyConflicts?.map((c)=>({packageName:c.packageName,requiredVersions:c.requiredVersions,conflictingEdges:c.conflictingEdges.map((edge)=>({fromIndex:edge.fromIndex??undefined,toIndex:edge.toIndex,versionConstraint:edge.versionConstraint,dependencyType:edge.dependencyType}))}))??undefined,circularDependencyCycles:bundle.transitive.circularDependencyCycles?.map((cycle)=>({cycleStart:cycle.cycleStart,circularPath:cycle.circularPath,displayChain:cycle.displayChain}))??undefined,dependencyGraph:bundle.transitive.dependencyGraph?{formatVersion:bundle.transitive.dependencyGraph.formatVersion,nodes:bundle.transitive.dependencyGraph.nodes.map((n)=>({registry:n.registry,name:n.name,version:n.version??undefined})),edges:bundle.transitive.dependencyGraph.edges.map((e)=>({fromIndex:e.fromIndex??undefined,toIndex:e.toIndex,constraint:e.constraint??undefined,dependencyType:e.dependencyType??undefined}))}:undefined,vulnerabilitySummary:this.normaliseTransitiveVulnerabilitySummary(bundle.transitive.vulnerabilitySummary),dependencyIssues:this.normaliseDependencyIssuesSummary(bundle.transitive.dependencyIssues)}:undefined}:undefined;const dependencyGroups=data.dependencyGroups?{primaryGroup:data.dependencyGroups.primaryGroup??undefined,environmentMarkers:data.dependencyGroups.environmentMarkers?.map((m)=>({type:m.type??undefined,value:m.value??undefined,raw:m.raw??undefined}))??undefined,groups:data.dependencyGroups.groups.map((group)=>({name:group.name,lifecycle:group.lifecycle,conditionType:group.conditionType,conditionValue:group.conditionValue??undefined,selectionMode:group.selectionMode,exclusiveGroup:group.exclusiveGroup??undefined,fallbackPriority:group.fallbackPriority??undefined,compatibleWith:group.compatibleWith??undefined,defaultEnabled:group.defaultEnabled??undefined,dependencies:group.dependencies.map((entry)=>({name:entry.name,constraint:entry.constraint??undefined}))}))}:undefined;return{package:identity,dependencies,dependencyGroups}}normaliseTransitiveVulnerabilitySummary(summary){if(!summary)return;return{affected:summary.affected,nonAffecting:summary.nonAffecting,combined:summary.combined,totalPackagesAnalyzed:summary.totalPackagesAnalyzed,affectedPackageCount:summary.affectedPackageCount,calculatedAt:summary.calculatedAt??undefined,packages:summary.packages.map((pkg)=>({registry:pkg.registry,name:pkg.name,versions:pkg.versions,affectedCount:pkg.affectedCount,nonAffectingCount:pkg.nonAffectingCount,totalCount:pkg.totalCount,maxSeverityScore:pkg.maxSeverityScore??undefined,maxSeverityLabel:pkg.maxSeverityLabel??undefined,advisoryIds:pkg.advisoryIds,mostCritical:pkg.mostCritical?this.normaliseVulnerabilitySummaryDetail(pkg.mostCritical):undefined,advisoryOccurrences:pkg.advisoryOccurrences?.map((occurrence)=>({version:occurrence.version,affectsResolvedVersion:occurrence.affectsResolvedVersion,matchedAffectedVersionRanges:occurrence.matchedAffectedVersionRanges,fixVersionsAboveResolved:occurrence.fixVersionsAboveResolved,nearestFixedVersion:occurrence.nearestFixedVersion??undefined,advisory:this.normaliseVulnerabilitySummaryDetail(occurrence.advisory)}))??undefined}))}}normaliseVulnerabilitySummaryDetail(advisory){return{osvId:advisory.osvId??undefined,registry:advisory.registry??undefined,packageName:advisory.packageName??undefined,summary:advisory.summary??undefined,severityScore:advisory.severityScore??undefined,severityType:advisory.severityType??undefined,affectedVersionRanges:advisory.affectedVersionRanges??undefined,fixedInVersions:advisory.fixedInVersions??undefined,publishedAt:advisory.publishedAt??undefined,modifiedAt:advisory.modifiedAt??undefined,withdrawnAt:advisory.withdrawnAt??undefined,aliases:advisory.aliases??undefined,isMalicious:advisory.isMalicious??undefined}}normaliseDependencyIssuesSummary(issues){if(!issues)return;return{totalCount:issues.totalCount,deprecatedCount:issues.deprecatedCount,outdatedCount:issues.outdatedCount,duplicateCount:issues.duplicateCount,conflictCount:issues.conflictCount,deprecatedPackages:issues.deprecatedPackages.map((pkg)=>({registry:pkg.registry,name:pkg.name,versions:pkg.versions,reasons:pkg.reasons.map((reason)=>({version:reason.version,reason:reason.reason??undefined}))})),outdatedPackages:issues.outdatedPackages.map((pkg)=>({registry:pkg.registry,name:pkg.name,latestVersion:pkg.latestVersion??undefined,severity:pkg.severity,versions:pkg.versions.map((version)=>({version:version.version,severity:version.severity})),repositoryUrl:pkg.repositoryUrl??undefined})),duplicatePackages:issues.duplicatePackages.map((pkg)=>({registry:pkg.registry??undefined,name:pkg.name,versions:pkg.versions})),conflicts:issues.conflicts.map((conflict)=>({registry:conflict.registry??undefined,name:conflict.name,versions:conflict.versions,requiredVersions:conflict.requiredVersions,conflictingEdges:conflict.conflictingEdges.map((edge)=>({fromIndex:edge.fromIndex??undefined,toIndex:edge.toIndex,versionConstraint:edge.versionConstraint,dependencyType:edge.dependencyType}))}))}}async packageChangelog(params){return withTelemetrySpan("pkg-intel.changelog.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageChangelog(token,params)}))}async executePackageChangelog(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_CHANGELOG_QUERY,variables:{registry:params.registry,name:params.packageName,repoUrl:params.repoUrl,gitRef:params.gitRef,fromVersion:params.fromVersion,toVersion:params.toVersion,limit:params.limit,includeBodies:params.includeBodies!==false},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=changelogGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageChangelog;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseChangelogReport(data,params)}normaliseChangelogReport(data,params){const source=data.source?.trim()?data.source:undefined;const rawEntries=data.entries??[];if(!source&&rawEntries.length===0){const target=params.repoUrl??(params.registry&&params.packageName?`${params.registry.toLowerCase()}:${params.packageName}`:"package");throw new PackageIntelligenceChangelogSourceNotFoundError(`No changelog source available for ${target} (tried GitHub Releases, CHANGELOG.md, and HexDocs).`)}const entries=rawEntries.map((entry)=>({version:entry.version??undefined,normalizedVersion:entry.normalizedVersion??undefined,body:entry.body??undefined,htmlUrl:entry.htmlUrl??undefined,publishedAt:entry.publishedAt??undefined}));const packageInfo=data.package?{name:data.package.name??undefined,registry:data.package.registry??undefined,repoUrl:data.package.repoUrl??undefined,fromVersion:data.package.fromVersion??undefined,toVersion:data.package.toVersion??undefined,limit:data.package.limit??undefined}:undefined;return{package:packageInfo,source,entries}}async listPackageDocs(params){return withTelemetrySpan("pkg-intel.docs.list",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executeListPackageDocs(token,params)}))}async executeListPackageDocs(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:LIST_PACKAGE_DOCS_QUERY,variables:{registry:params.registry,packageName:params.packageName,version:params.version,limit:params.limit,after:params.after},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageDocsListGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.listPackageDocs;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalisePackageDocsList(data)}normalisePackageDocsList(data){return{registry:data.registry??undefined,packageName:data.packageName??undefined,version:data.version??undefined,stale:data.stale??undefined,pages:data.pages?.map((page)=>({id:page.id??undefined,title:page.title??undefined,slug:page.slug??undefined,order:page.order??undefined,linkName:page.linkName??undefined,lastUpdatedAt:page.lastUpdatedAt??undefined,sourceKind:page.sourceKind??undefined,sourceUrl:page.sourceUrl??undefined,repoUrl:page.repoUrl??undefined,gitRef:page.gitRef??undefined,requestedRef:page.requestedRef??undefined,filePath:page.filePath??undefined}))??[],pageInfo:data.pageInfo?{hasNextPage:data.pageInfo.hasNextPage,endCursor:data.pageInfo.endCursor??undefined,totalCount:data.pageInfo.totalCount??undefined}:undefined}}async readPackageDoc(params){return withTelemetrySpan("pkg-intel.docs.read",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executeReadPackageDoc(token,params)}))}async executeReadPackageDoc(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:READ_PACKAGE_DOC_QUERY,variables:{pageId:params.pageId},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageDocReadGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.getDocPage;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalisePackageDocResult(data)}normalisePackageDocResult(data){return{registry:data.registry??undefined,packageName:data.packageName??undefined,version:data.version??undefined,sourceKind:data.sourceKind??undefined,page:data.page?{id:data.page.id??undefined,title:data.page.title??undefined,content:data.page.content??undefined,contentFormat:data.page.contentFormat??undefined,breadcrumbs:data.page.breadcrumbs??undefined,linkName:data.page.linkName??undefined,lastUpdatedAt:data.page.lastUpdatedAt??undefined,sourceKind:data.page.sourceKind??undefined,source:data.page.source?{url:data.page.source.url??undefined,label:data.page.source.label??undefined}:undefined,repoUrl:data.page.repoUrl??undefined,gitRef:data.page.gitRef??undefined,requestedRef:data.page.requestedRef??undefined,filePath:data.page.filePath??undefined,baseUrl:data.page.baseUrl??undefined}:undefined}}}function stripNullProperties(value){if(Array.isArray(value))return value.map(stripNullProperties);if(!value||typeof value!=="object")return value;const result={};for(const[key,child]of Object.entries(value)){if(child!==null)result[key]=stripNullProperties(child)}return result}function createPackageIntelligenceHttpError(response){const status=response.status;const detail=parseDetail2(response.responseBody);if(status===401){return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server")}if(status===403){return new PackageIntelligenceAccessError(detail??"Access denied.")}if(status>=500){return new PackageIntelligenceBackendError(detail?`Server error (${status}): ${detail}`:`Server error (${status})`,status)}return new PackageIntelligenceBackendError(detail??`Request failed with status ${status}`,status)}function createPackageIntelligenceTransportError(error){if(isFetchTimeoutError(error.cause)){return new PackageIntelligenceBackendError("Package intelligence request timed out.",undefined,"TIMEOUT",true)}return new PackageIntelligenceNetworkError("Could not reach the package intelligence service. Check your connection or set GITHITS_CODE_NAV_URL.",{cause:error})}function createPackageIntelligenceGraphQLError(errors,clientVersion){const message=errors.map((error)=>error.message).join(", ");const extensions=getPrimaryExtensions2(errors);const code=typeof extensions?.code==="string"?extensions.code:undefined;const retryable=typeof extensions?.retryable==="boolean"?extensions.retryable:undefined;if(isClientUpdateRequiredGraphQLError({message,code})){return new ClientUpdateRequiredError(undefined,undefined,clientVersion)}if(isGraphQLSchemaMismatchError({message,code})){const sanitized="Backend protocol mismatch. Your CLI may be newer than the server, or the server may require a newer CLI. Run `githits update-check` to verify your installed version. Set GITHITS_DEBUG=pkg-graphql to inspect GraphQL details during local development.";debugLog("pkg-graphql",{event:"graphql-schema-mismatch",code:code??"omitted",message});return new PackageIntelligenceBackendError(isDebugAreaEnabled("pkg-graphql")?message:sanitized,undefined,code,retryable)}switch(code){case"NOT_FOUND":case"PACKAGE_NOT_FOUND":return new PackageIntelligenceTargetNotFoundError(message);case"VERSION_NOT_FOUND":return new PackageIntelligenceVersionNotFoundError(message,typeof extensions?.package==="string"?extensions.package:undefined,typeof extensions?.requested_version==="string"?extensions.requested_version:undefined,parseVersionList(extensions?.available_versions??extensions?.availableVersions));case"UNSUPPORTED_REGISTRY":case"VALIDATION_ERROR":return new PackageIntelligenceValidationError(message);case"FEATURE_FLAG_REQUIRED":return new PackageIntelligenceFeatureFlagRequiredError(message);case"UNAUTHORIZED":return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case"FORBIDDEN":return new PackageIntelligenceAccessError("Access denied. This feature may not be enabled for your account.");case"UPSTREAM_ERROR":case"TIMEOUT":case"RATE_LIMITED":case"INTERNAL_ERROR":case"UNKNOWN_ERROR":return new PackageIntelligenceBackendError(message,undefined,code,retryable);default:return new PackageIntelligenceBackendError(message,undefined,code,retryable)}}function parseDetail2(body){if(!body)return;try{const parsed=JSON.parse(body);if(typeof parsed.detail==="string")return parsed.detail;if(typeof parsed.error==="string")return parsed.error}catch{return body}return}function getPrimaryExtensions2(errors){for(const error of errors){if(error.extensions&&Object.keys(error.extensions).length>0){return error.extensions}}return}function parseVersionList(raw){if(!Array.isArray(raw))return;const versions=[];for(const item of raw){if(typeof item==="string"&&item.length>0){versions.push(item)}}return versions.length>0?versions:undefined}class RefreshingGitHitsService{apiUrl;tokenProvider;serviceFactory;runtime;constructor(apiUrl,tokenProvider,serviceFactory=undefined,runtime={}){this.apiUrl=apiUrl;this.tokenProvider=tokenProvider;this.serviceFactory=serviceFactory;this.runtime=runtime}async search(params){return this.withTokenRefresh((service)=>service.search(params))}async getLanguages(){return this.withTokenRefresh((service)=>service.getLanguages())}async searchLanguages(query,limit){return this.withTokenRefresh((service)=>service.searchLanguages(query,limit))}async submitFeedback(params){return this.withTokenRefresh((service)=>service.submitFeedback(params))}async withTokenRefresh(operation){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:async(token)=>{const service=this.serviceFactory?this.serviceFactory(this.apiUrl,token):new GitHitsServiceImpl(this.apiUrl,token,undefined,undefined,this.runtime);return operation(service)}})}}function createStaticTokenProvider(token){return{getToken:async()=>token,forceRefresh:async()=>{return}}}import{createHash,randomUUID}from"node:crypto";var MAX_HEADER_BYTES=256;var SESSION_ENV_VARS=["TERM_SESSION_ID","ITERM_SESSION_ID","WEZTERM_PANE","KITTY_PID","ALACRITTY_SOCKET","WT_SESSION","VSCODE_PID","SUPERSET_PANE_ID","SUPERSET_WORKSPACE_ID","STARSHIP_SESSION_KEY","SSH_CONNECTION"];var cachedSessionId;function resolveRawSessionId(env=process.env,ppid=process.ppid){for(const key of SESSION_ENV_VARS){const value=env[key];if(value&&value.trim().length>0){return value.trim()}}if(typeof ppid==="number"&&!Number.isNaN(ppid)&&ppid>0){return String(ppid)}return randomUUID()}function getSessionId(env,ppid){if(cachedSessionId!==undefined&&env===undefined&&ppid===undefined){return cachedSessionId}const raw=resolveRawSessionId(env,ppid);const hashed=hashValue(raw);if(env===undefined&&ppid===undefined){cachedSessionId=hashed}return hashed}function hashValue(input){return createHash("sha256").update(input).digest("hex").slice(0,16)}var AGENT_PROBES=[{envVar:"OPENCODE",name:"opencode"},{envVar:"CLAUDECODE",name:"claude-code"},{envVar:"CURSOR_TRACE_ID",name:"cursor"},{envVar:"WINDSURF_CONFIG_DIR",name:"windsurf"},{envVar:"ZED_TERM",name:"zed"},{envVar:"VSCODE_PID",name:"vscode"}];function parseAgentString(raw){const trimmed=raw.trim();if(trimmed.length===0)return;const slashIndex=trimmed.indexOf("/");if(slashIndex===-1)return{name:trimmed};const name=trimmed.slice(0,slashIndex);const ver=trimmed.slice(slashIndex+1);if(name.length===0)return;return{name,version:ver||undefined}}function formatAgentInfo(info){return info.version?`${info.name}/${info.version}`:info.name}function resolveAgentInfo(env=process.env){const explicit=env.GITHITS_AGENT;if(explicit&&explicit.trim().length>0){return parseAgentString(explicit)}for(const probe of AGENT_PROBES){const value=env[probe.envVar];if(value&&value.trim().length>0){return{name:probe.name}}}return}var CONTROL_CHARS=/[\x00-\x1f\x7f-\x9f]/g;function sanitizeHeaderValue(value){if(value===undefined||value===null||typeof value!=="string"){return}const cleaned=value.replace(CONTROL_CHARS,"").trim();if(cleaned.length===0)return;if(Buffer.byteLength(cleaned,"utf8")>MAX_HEADER_BYTES)return;return cleaned}function createClientHeaderBuilder(options){return()=>buildClientHeadersWithContext({clientName:options.clientName,clientVersion:options.clientVersion,agentProvider:options.agentProvider,env:options.env,ppid:options.ppid})}function buildClientHeadersWithContext(context){try{const headers={};const name=sanitizeHeaderValue(context.clientName);if(name){headers["x-githits-client-name"]=name}const safeClientVersion=sanitizeHeaderValue(context.clientVersion);if(safeClientVersion){headers["x-githits-client-version"]=safeClientVersion}const agentInfo=context.agentProvider?.()??resolveAgentInfo(context.env);if(agentInfo){const agentValue=sanitizeHeaderValue(formatAgentInfo(agentInfo));if(agentValue){headers["x-githits-agent"]=agentValue}}const sessionId=sanitizeHeaderValue(getSessionId(context.env,context.ppid));if(sessionId){headers["x-githits-session-id"]=sessionId}return headers}catch{return{}}}import{createHash as createHash2,randomBytes}from"node:crypto";import{z as z4}from"zod";var listCandidateSchema=z4.object({kind:z4.string(),canonicalKey:z4.string(),confidence:z4.string(),description:z4.string().nullable().optional(),repositoryUrl:z4.string().nullable().optional(),stars:z4.number().int().nullable().optional(),downloadsLastMonth:z4.number().int().nullable().optional(),downloadsTotal:z4.number().int().nullable().optional(),docsAvailable:z4.boolean(),codeAvailable:z4.boolean()});var targetReferenceSchema=listCandidateSchema.pick({kind:true,canonicalKey:true,confidence:true});var detailedCandidateSchema=listCandidateSchema.extend({displayName:z4.string(),registry:z4.string().nullable().optional(),packageName:z4.string().nullable().optional(),latestVersion:z4.string().nullable().optional(),repositoryOwner:z4.string().nullable().optional(),repositoryName:z4.string().nullable().optional(),documentationUrl:z4.string().nullable().optional(),matchedAliases:z4.array(z4.string()),matchTier:z4.number().int(),score:z4.number(),reason:z4.string().nullable().optional()});var graphQLErrorSchema3=z4.object({message:z4.string(),extensions:z4.record(z4.string(),z4.unknown()).optional()});export{CLIENT_UPDATE_REQUIRED_REASON,ClientUpdateRequiredError,debugLog,FetchTimeoutError,DEFAULT_MCP_URL,DEFAULT_API_URL,DEFAULT_CODE_NAV_URL,getMcpUrl,getApiUrl,getCodeNavigationUrl,getEnvApiToken,TermsAcceptanceRequiredError,PKGSEER_REGISTRY_ARGS,PKGSEER_REGISTRY_LIST,toPkgseerRegistry,toPkgseerRegistryLowercase,isKnownPkgseerRegistryArg,withTelemetrySpan,startTelemetrySpan,endTelemetrySpan,flushTelemetry,AuthenticationError,ApiRateLimitError,GitHitsServiceImpl,CodeNavigationAccessError,CodeNavigationGraphQLError,CodeNavigationIndexingError,CodeNavigationUnresolvableError,MalformedCodeNavigationResponseError,CodeDiffError,CodeNavigationTargetNotFoundError,CodeNavigationFileNotFoundError,CodeNavigationVersionNotFoundError,CodeNavigationRefNotFoundError,CodeNavigationValidationError,CodeNavigationFeatureFlagRequiredError,CodeNavigationNetworkError,CodeNavigationBackendError,CodeNavigationServiceImpl,PackageIntelligenceAccessError,PackageIntelligenceFeatureFlagRequiredError,PackageIntelligenceNetworkError,PackageIntelligenceBackendError,PackageIntelligenceGraphQLError,PackageIntelligenceTargetNotFoundError,PackageIntelligenceValidationError,PackageIntelligenceVersionNotFoundError,MalformedPackageIntelligenceResponseError,PackageIntelligenceChangelogSourceNotFoundError,PackageIntelligenceServiceImpl,RefreshingGitHitsService,createStaticTokenProvider,createClientHeaderBuilder};
1317
+ }`;class PackageIntelligenceServiceImpl{endpointUrl;tokenProvider;fetchFn;runtime;constructor(endpointUrl,tokenProvider,fetchFn=globalThis.fetch,runtime={}){this.endpointUrl=endpointUrl;this.tokenProvider=tokenProvider;this.fetchFn=fetchFn;this.runtime=runtime}async packageSummary(params){return withTelemetrySpan("pkg-intel.summary.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageSummary(token,params)}))}async executePackageSummary(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_SUMMARY_QUERY,variables:{registry:params.registry,name:params.packageName,includeVerboseFields:params.includeVerboseFields!==false},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=graphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.packageSummary;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalise(data)}createHttpError(response){return createPackageIntelligenceHttpError(response)}createTransportError(error){return createPackageIntelligenceTransportError(error)}createGraphQLError(errors){return createPackageIntelligenceGraphQLError(errors,this.runtime.clientVersion)}normalise(data){const name=data.package?.name??undefined;const latestVersion=data.package?.latestVersion??undefined;if(!name||!latestVersion){throw new MalformedPackageIntelligenceResponseError("Package summary response missing required name/latestVersion.")}const pkg=data.package;const github=pkg?.githubRepository;const identity={name,latestVersion,registry:pkg?.registry??undefined,description:pkg?.description??undefined,latestVersionPublishedAt:pkg?.latestVersionPublishedAt??undefined,homepage:pkg?.homepage??undefined,repositoryUrl:pkg?.repositoryUrl??undefined,license:pkg?.license??undefined,downloadsLastMonth:pkg?.downloadsLastMonth??undefined,downloadsTotal:pkg?.downloadsTotal??undefined,githubRepository:github?{stargazersCount:github.stargazersCount??undefined,forksCount:github.forksCount??undefined,openIssuesCount:github.openIssuesCount??undefined,archived:github.archived??undefined,language:github.language??undefined,topics:github.topics??undefined,pushedAt:github.pushedAt??undefined}:undefined};const security=data.security?{vulnerabilityCount:data.security.vulnerabilityCount??undefined,hasCurrentVulnerabilities:data.security.hasCurrentVulnerabilities??undefined,recentVulnerabilities:data.security.recentVulnerabilities?.map((vuln)=>({osvId:vuln.osvId??undefined,summary:vuln.summary??undefined,severityScore:vuln.severityScore??undefined,publishedAt:vuln.publishedAt??undefined}))??undefined}:undefined;const latestChangelogs=data.latestChangelogs?.map((entry)=>({version:entry.version??undefined,publishedAt:entry.publishedAt??undefined,body:entry.body??undefined}))??undefined;return{package:identity,security,latestChangelogs}}async packageVulnerabilities(params){return withTelemetrySpan("pkg-intel.vulnerabilities.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageVulnerabilities(token,params)}))}async executePackageVulnerabilities(token,params){let after=null;let firstPage;const entries=[];const seenCursors=new Set;do{const page=await this.fetchPackageVulnerabilitiesPage(token,params,after);if(!firstPage)firstPage=page;const advisoryPage=page.security?.advisories;if(!advisoryPage){after=null;break}entries.push(...advisoryPage.entries);if(advisoryPage.pageInfo.hasNextPage){const nextCursor=advisoryPage.pageInfo.endCursor;if(!nextCursor){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination omitted next cursor.")}if(seenCursors.has(nextCursor)){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination repeated a cursor.")}seenCursors.add(nextCursor);after=nextCursor}else{after=null}}while(after!==null);if(!firstPage){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}if(firstPage.security){const expectedCount=firstPage.security.advisories.pageInfo.totalCount;if(entries.length!==expectedCount){throw new MalformedPackageIntelligenceResponseError("Vulnerability response pagination returned an incomplete advisory set.")}}const data=firstPage.security?{...firstPage,security:{...firstPage.security,advisories:{...firstPage.security.advisories,entries}}}:firstPage;return this.normaliseVulnerabilityReport(data)}async fetchPackageVulnerabilitiesPage(token,params,after){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_VULNERABILITIES_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,minSeverity:params.minSeverity,includeWithdrawn:params.includeWithdrawn,scope:params.advisoryScope,after},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=vulnerabilitiesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageVulnerabilities;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return data}normaliseVulnerabilityReport(data){const name=data.package?.name??undefined;const version=data.package?.version??undefined;if(!name||!version){throw new MalformedPackageIntelligenceResponseError("Vulnerability report response missing required name/version.")}const identity={name,version,registry:data.package?.registry??undefined,publishedAt:data.package?.publishedAt??undefined,deprecated:data.package?.deprecated??undefined,deprecationReason:data.package?.deprecationReason??undefined};const security=data.security?{affectedVulnerabilityCount:data.security.affectedVulnerabilityCount,nonAffectingVulnerabilityCount:data.security.nonAffectingVulnerabilityCount,allVulnerabilityCount:data.security.allVulnerabilityCount,currentVersionAffected:data.security.currentVersionAffected??undefined,vulnerabilities:data.security.advisories.entries.map((vuln)=>({osvId:vuln.osvId??undefined,summary:vuln.summary??undefined,severityScore:vuln.severityScore??undefined,severityType:vuln.severityType??undefined,affectedVersionRanges:vuln.affectedVersionRanges??undefined,affectedVersionRangesCount:vuln.affectedVersionRangesCount,affectedVersionRangesTruncated:vuln.affectedVersionRangesTruncated,fixedInVersions:vuln.fixedInVersions??undefined,publishedAt:vuln.publishedAt??undefined,modifiedAt:vuln.modifiedAt??undefined,withdrawnAt:vuln.withdrawnAt??undefined,aliases:vuln.aliases??undefined,isMalicious:vuln.isMalicious??undefined,affectsInspectedVersion:vuln.affectsInspectedVersion,matchedAffectedVersionRanges:vuln.matchedAffectedVersionRanges,duplicateIds:vuln.duplicateIds})),upgradePaths:data.security.upgradePaths??undefined}:undefined;return{package:identity,security}}async packageDependencies(params){return withTelemetrySpan("pkg-intel.dependencies.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageDependencies(token,params)}))}async packageUpgradeDependencyProbe(params){return withTelemetrySpan("pkg-intel.upgrade-dependency-probe.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageUpgradeDependencyProbe(token,params)}))}async packageUpgradeReview(params){return withTelemetrySpan("pkg-intel.upgrade-review.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageUpgradeReview(token,params)}))}async executePackageUpgradeReview(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_UPGRADE_REVIEW_QUERY,variables:{packages:params.packages,includeTransitiveSecurity:params.includeTransitiveSecurity,includeDependencyIssues:params.includeDependencyIssues,minSeverity:params.minSeverity,changelogLimit:params.changelogLimit},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageUpgradeReviewGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.packageUpgradeReview;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return stripNullProperties(data)}async executePackageUpgradeDependencyProbe(token,params){const includeTransitiveRisk=params.includeTransitiveSecurity===true||params.includeDependencyIssues===true||params.includeDependencyChanges===true;let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_UPGRADE_DEPENDENCY_PROBE_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,includeTransitiveRisk,includeTransitiveSecurity:params.includeTransitiveSecurity===true,includeDependencyIssues:params.includeDependencyIssues===true,includeDependencyChanges:params.includeDependencyChanges===true,includeGroups:params.includeGroups===true,lifecycle:params.includeGroups===true?["peer"]:undefined,minSeverity:params.minSeverity},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=dependenciesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageDependencies;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseDependencyReport(data)}async executePackageDependencies(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_DEPENDENCIES_QUERY,variables:{registry:params.registry,name:params.packageName,version:params.version,includeTransitive:params.includeTransitive,includeTransitiveDetails:params.includeTransitiveDetails!==false,includeDependencyGraph:params.includeTransitive===true,includeGroups:params.includeGroups!==false,maxDepth:params.maxDepth,lifecycle:params.lifecycle&&params.lifecycle.length>0?params.lifecycle:undefined},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=dependenciesGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageDependencies;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseDependencyReport(data)}normaliseDependencyReport(data){const name=data.package?.name??undefined;const version=data.package?.version??undefined;if(!name||!version){throw new MalformedPackageIntelligenceResponseError("Package dependencies response missing required name/version.")}const identity={name,version,registry:data.package?.registry??undefined,publishedAt:data.package?.publishedAt??undefined,deprecated:data.package?.deprecated??undefined,deprecationReason:data.package?.deprecationReason??undefined};const bundle=data.dependencies;const dependencies=bundle?{direct:bundle.direct?.map((entry)=>{if(!entry.name){throw new MalformedPackageIntelligenceResponseError("Dependency entry missing required name.")}return{name:entry.name,versionConstraint:entry.versionConstraint??undefined,type:entry.type??undefined}})??undefined,transitive:bundle.transitive?{totalEdges:bundle.transitive.totalEdges??undefined,uniquePackagesCount:bundle.transitive.uniquePackagesCount??undefined,uniqueDependencies:bundle.transitive.uniqueDependencies??undefined,dependencyConflicts:bundle.transitive.dependencyConflicts?.map((c)=>({packageName:c.packageName,requiredVersions:c.requiredVersions,conflictingEdges:c.conflictingEdges.map((edge)=>({fromIndex:edge.fromIndex??undefined,toIndex:edge.toIndex,versionConstraint:edge.versionConstraint,dependencyType:edge.dependencyType}))}))??undefined,circularDependencyCycles:bundle.transitive.circularDependencyCycles?.map((cycle)=>({cycleStart:cycle.cycleStart,circularPath:cycle.circularPath,displayChain:cycle.displayChain}))??undefined,dependencyGraph:bundle.transitive.dependencyGraph?{formatVersion:bundle.transitive.dependencyGraph.formatVersion,nodes:bundle.transitive.dependencyGraph.nodes.map((n)=>({registry:n.registry,name:n.name,version:n.version??undefined})),edges:bundle.transitive.dependencyGraph.edges.map((e)=>({fromIndex:e.fromIndex??undefined,toIndex:e.toIndex,constraint:e.constraint??undefined,dependencyType:e.dependencyType??undefined}))}:undefined,vulnerabilitySummary:this.normaliseTransitiveVulnerabilitySummary(bundle.transitive.vulnerabilitySummary),dependencyIssues:this.normaliseDependencyIssuesSummary(bundle.transitive.dependencyIssues)}:undefined}:undefined;const dependencyGroups=data.dependencyGroups?{primaryGroup:data.dependencyGroups.primaryGroup??undefined,environmentMarkers:data.dependencyGroups.environmentMarkers?.map((m)=>({type:m.type??undefined,value:m.value??undefined,raw:m.raw??undefined}))??undefined,groups:data.dependencyGroups.groups.map((group)=>({name:group.name,lifecycle:group.lifecycle,conditionType:group.conditionType,conditionValue:group.conditionValue??undefined,selectionMode:group.selectionMode,exclusiveGroup:group.exclusiveGroup??undefined,fallbackPriority:group.fallbackPriority??undefined,compatibleWith:group.compatibleWith??undefined,defaultEnabled:group.defaultEnabled??undefined,dependencies:group.dependencies.map((entry)=>({name:entry.name,constraint:entry.constraint??undefined}))}))}:undefined;return{package:identity,dependencies,dependencyGroups}}normaliseTransitiveVulnerabilitySummary(summary){if(!summary)return;return{affected:summary.affected,nonAffecting:summary.nonAffecting,combined:summary.combined,totalPackagesAnalyzed:summary.totalPackagesAnalyzed,affectedPackageCount:summary.affectedPackageCount,calculatedAt:summary.calculatedAt??undefined,packages:summary.packages.map((pkg)=>({registry:pkg.registry,name:pkg.name,versions:pkg.versions,affectedCount:pkg.affectedCount,nonAffectingCount:pkg.nonAffectingCount,totalCount:pkg.totalCount,maxSeverityScore:pkg.maxSeverityScore??undefined,maxSeverityLabel:pkg.maxSeverityLabel??undefined,advisoryIds:pkg.advisoryIds,mostCritical:pkg.mostCritical?this.normaliseVulnerabilitySummaryDetail(pkg.mostCritical):undefined,advisoryOccurrences:pkg.advisoryOccurrences?.map((occurrence)=>({version:occurrence.version,affectsResolvedVersion:occurrence.affectsResolvedVersion,matchedAffectedVersionRanges:occurrence.matchedAffectedVersionRanges,fixVersionsAboveResolved:occurrence.fixVersionsAboveResolved,nearestFixedVersion:occurrence.nearestFixedVersion??undefined,advisory:this.normaliseVulnerabilitySummaryDetail(occurrence.advisory)}))??undefined}))}}normaliseVulnerabilitySummaryDetail(advisory){return{osvId:advisory.osvId??undefined,registry:advisory.registry??undefined,packageName:advisory.packageName??undefined,summary:advisory.summary??undefined,severityScore:advisory.severityScore??undefined,severityType:advisory.severityType??undefined,affectedVersionRanges:advisory.affectedVersionRanges??undefined,fixedInVersions:advisory.fixedInVersions??undefined,publishedAt:advisory.publishedAt??undefined,modifiedAt:advisory.modifiedAt??undefined,withdrawnAt:advisory.withdrawnAt??undefined,aliases:advisory.aliases??undefined,isMalicious:advisory.isMalicious??undefined}}normaliseDependencyIssuesSummary(issues){if(!issues)return;return{totalCount:issues.totalCount,deprecatedCount:issues.deprecatedCount,outdatedCount:issues.outdatedCount,duplicateCount:issues.duplicateCount,conflictCount:issues.conflictCount,deprecatedPackages:issues.deprecatedPackages.map((pkg)=>({registry:pkg.registry,name:pkg.name,versions:pkg.versions,reasons:pkg.reasons.map((reason)=>({version:reason.version,reason:reason.reason??undefined}))})),outdatedPackages:issues.outdatedPackages.map((pkg)=>({registry:pkg.registry,name:pkg.name,latestVersion:pkg.latestVersion??undefined,severity:pkg.severity,versions:pkg.versions.map((version)=>({version:version.version,severity:version.severity})),repositoryUrl:pkg.repositoryUrl??undefined})),duplicatePackages:issues.duplicatePackages.map((pkg)=>({registry:pkg.registry??undefined,name:pkg.name,versions:pkg.versions})),conflicts:issues.conflicts.map((conflict)=>({registry:conflict.registry??undefined,name:conflict.name,versions:conflict.versions,requiredVersions:conflict.requiredVersions,conflictingEdges:conflict.conflictingEdges.map((edge)=>({fromIndex:edge.fromIndex??undefined,toIndex:edge.toIndex,versionConstraint:edge.versionConstraint,dependencyType:edge.dependencyType}))}))}}async packageChangelog(params){return withTelemetrySpan("pkg-intel.changelog.request",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executePackageChangelog(token,params)}))}async executePackageChangelog(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:PACKAGE_CHANGELOG_QUERY,variables:{registry:params.registry,name:params.packageName,repoUrl:params.repoUrl,gitRef:params.gitRef,fromVersion:params.fromVersion,toVersion:params.toVersion,limit:params.limit,includeBodies:params.includeBodies!==false},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=changelogGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.packageChangelog;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normaliseChangelogReport(data,params)}normaliseChangelogReport(data,params){const source=data.source?.trim()?data.source:undefined;const rawEntries=data.entries??[];if(!source&&rawEntries.length===0){const target=params.repoUrl??(params.registry&&params.packageName?`${params.registry.toLowerCase()}:${params.packageName}`:"package");throw new PackageIntelligenceChangelogSourceNotFoundError(`No changelog source available for ${target} (tried GitHub Releases, CHANGELOG.md, and HexDocs).`)}const entries=rawEntries.map((entry)=>({version:entry.version??undefined,normalizedVersion:entry.normalizedVersion??undefined,body:entry.body??undefined,htmlUrl:entry.htmlUrl??undefined,publishedAt:entry.publishedAt??undefined}));const packageInfo=data.package?{name:data.package.name??undefined,registry:data.package.registry??undefined,repoUrl:data.package.repoUrl??undefined,fromVersion:data.package.fromVersion??undefined,toVersion:data.package.toVersion??undefined,limit:data.package.limit??undefined}:undefined;return{package:packageInfo,source,entries}}async listPackageDocs(params){return withTelemetrySpan("pkg-intel.docs.list",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executeListPackageDocs(token,params)}))}async executeListPackageDocs(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:LIST_PACKAGE_DOCS_QUERY,variables:{registry:params.registry,packageName:params.packageName,version:params.version,limit:params.limit,after:params.after},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageDocsListGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw promoteGenericVersionNotFound(this.createGraphQLError(parsed.data.errors),params)}const data=parsed.data.data?.listPackageDocs;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalisePackageDocsList(data)}normalisePackageDocsList(data){return{registry:data.registry??undefined,packageName:data.packageName??undefined,version:data.version??undefined,stale:data.stale??undefined,pages:data.pages?.map((page)=>({id:page.id??undefined,title:page.title??undefined,slug:page.slug??undefined,order:page.order??undefined,linkName:page.linkName??undefined,lastUpdatedAt:page.lastUpdatedAt??undefined,sourceKind:page.sourceKind??undefined,sourceUrl:page.sourceUrl??undefined,repoUrl:page.repoUrl??undefined,gitRef:page.gitRef??undefined,requestedRef:page.requestedRef??undefined,filePath:page.filePath??undefined}))??[],pageInfo:data.pageInfo?{hasNextPage:data.pageInfo.hasNextPage,endCursor:data.pageInfo.endCursor??undefined,totalCount:data.pageInfo.totalCount??undefined}:undefined}}async readPackageDoc(params){return withTelemetrySpan("pkg-intel.docs.read",()=>executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:(token)=>this.executeReadPackageDoc(token,params)}))}async executeReadPackageDoc(token,params){let response;try{response=await postPkgseerGraphql({endpointUrl:this.endpointUrl,token,query:READ_PACKAGE_DOC_QUERY,variables:{pageId:params.pageId},fetchFn:this.fetchFn,clientHeaders:this.runtime.clientHeaders,userAgent:this.runtime.userAgent})}catch(cause){if(cause instanceof PkgseerTransportError){throw this.createTransportError(cause)}throw cause}if(response.status<200||response.status>=300){throw this.createHttpError(response)}const parsed=packageDocReadGraphQLResponseSchema.safeParse(response.parsedBody);if(!parsed.success){throw new MalformedPackageIntelligenceResponseError("Malformed response from the package-intelligence service.")}if(parsed.data.errors&&parsed.data.errors.length>0){throw this.createGraphQLError(parsed.data.errors)}const data=parsed.data.data?.getDocPage;if(!data){throw new MalformedPackageIntelligenceResponseError("Empty response from the package-intelligence service.")}return this.normalisePackageDocResult(data)}normalisePackageDocResult(data){return{registry:data.registry??undefined,packageName:data.packageName??undefined,version:data.version??undefined,sourceKind:data.sourceKind??undefined,page:data.page?{id:data.page.id??undefined,title:data.page.title??undefined,content:data.page.content??undefined,contentFormat:data.page.contentFormat??undefined,breadcrumbs:data.page.breadcrumbs??undefined,linkName:data.page.linkName??undefined,lastUpdatedAt:data.page.lastUpdatedAt??undefined,sourceKind:data.page.sourceKind??undefined,source:data.page.source?{url:data.page.source.url??undefined,label:data.page.source.label??undefined}:undefined,repoUrl:data.page.repoUrl??undefined,gitRef:data.page.gitRef??undefined,requestedRef:data.page.requestedRef??undefined,filePath:data.page.filePath??undefined,baseUrl:data.page.baseUrl??undefined}:undefined}}}function stripNullProperties(value){if(Array.isArray(value))return value.map(stripNullProperties);if(!value||typeof value!=="object")return value;const result={};for(const[key,child]of Object.entries(value)){if(child!==null)result[key]=stripNullProperties(child)}return result}function createPackageIntelligenceHttpError(response){const status=response.status;const detail=parseDetail2(response.responseBody);if(status===401){return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server")}if(status===403){return new PackageIntelligenceAccessError(detail??"Access denied.")}if(status>=500){return new PackageIntelligenceBackendError(detail?`Server error (${status}): ${detail}`:`Server error (${status})`,status)}return new PackageIntelligenceBackendError(detail??`Request failed with status ${status}`,status)}function createPackageIntelligenceTransportError(error){if(isFetchTimeoutError(error.cause)){return new PackageIntelligenceBackendError("Package intelligence request timed out.",undefined,"TIMEOUT",true)}return new PackageIntelligenceNetworkError("Could not reach the package intelligence service. Check your connection or set GITHITS_CODE_NAV_URL.",{cause:error})}function createPackageIntelligenceGraphQLError(errors,clientVersion){const message=errors.map((error)=>error.message).join(", ");const extensions=getPrimaryExtensions2(errors);const code=typeof extensions?.code==="string"?extensions.code:undefined;const retryable=typeof extensions?.retryable==="boolean"?extensions.retryable:undefined;if(isClientUpdateRequiredGraphQLError({message,code})){return new ClientUpdateRequiredError(undefined,undefined,clientVersion)}if(isGraphQLSchemaMismatchError({message,code})){const sanitized="Backend protocol mismatch. Your CLI may be newer than the server, or the server may require a newer CLI. Run `githits update-check` to verify your installed version. Set GITHITS_DEBUG=pkg-graphql to inspect GraphQL details during local development.";debugLog("pkg-graphql",{event:"graphql-schema-mismatch",code:code??"omitted",message});return new PackageIntelligenceBackendError(isDebugAreaEnabled("pkg-graphql")?message:sanitized,undefined,code,retryable)}switch(code){case"NOT_FOUND":case"PACKAGE_NOT_FOUND":return new PackageIntelligenceTargetNotFoundError(message);case"VERSION_NOT_FOUND":return new PackageIntelligenceVersionNotFoundError(message,typeof extensions?.package==="string"?extensions.package:undefined,typeof extensions?.requested_version==="string"?extensions.requested_version:undefined,parseVersionList(extensions?.available_versions??extensions?.availableVersions));case"UNSUPPORTED_REGISTRY":case"VALIDATION_ERROR":return new PackageIntelligenceValidationError(message);case"FEATURE_FLAG_REQUIRED":return new PackageIntelligenceFeatureFlagRequiredError(message);case"UNAUTHORIZED":return new AuthenticationError(SERVER_AUTHENTICATION_REJECTED_MESSAGE,"server");case"FORBIDDEN":return new PackageIntelligenceAccessError("Access denied. This feature may not be enabled for your account.");case"UPSTREAM_ERROR":case"TIMEOUT":case"RATE_LIMITED":case"INTERNAL_ERROR":case"UNKNOWN_ERROR":return new PackageIntelligenceBackendError(message,undefined,code,retryable);default:return new PackageIntelligenceBackendError(message,undefined,code,retryable)}}function parseDetail2(body){if(!body)return;try{const parsed=JSON.parse(body);if(typeof parsed.detail==="string")return parsed.detail;if(typeof parsed.error==="string")return parsed.error}catch{return body}return}function getPrimaryExtensions2(errors){for(const error of errors){if(error.extensions&&Object.keys(error.extensions).length>0){return error.extensions}}return}function parseVersionList(raw){if(!Array.isArray(raw))return;const versions=[];for(const item of raw){if(typeof item==="string"&&item.length>0){versions.push(item)}}return versions.length>0?versions:undefined}class RefreshingGitHitsService{apiUrl;tokenProvider;serviceFactory;runtime;constructor(apiUrl,tokenProvider,serviceFactory=undefined,runtime={}){this.apiUrl=apiUrl;this.tokenProvider=tokenProvider;this.serviceFactory=serviceFactory;this.runtime=runtime}async search(params){return this.withTokenRefresh((service)=>service.search(params))}async getLanguages(){return this.withTokenRefresh((service)=>service.getLanguages())}async searchLanguages(query,limit){return this.withTokenRefresh((service)=>service.searchLanguages(query,limit))}async submitFeedback(params){return this.withTokenRefresh((service)=>service.submitFeedback(params))}async withTokenRefresh(operation){return executeWithTokenRefresh({getToken:()=>this.tokenProvider.getToken(),forceRefresh:()=>this.tokenProvider.forceRefresh(),shouldRefresh:isTokenRefreshableError,executeWithToken:async(token)=>{const service=this.serviceFactory?this.serviceFactory(this.apiUrl,token):new GitHitsServiceImpl(this.apiUrl,token,undefined,undefined,this.runtime);return operation(service)}})}}function createStaticTokenProvider(token){return{getToken:async()=>token,forceRefresh:async()=>{return}}}import{createHash,randomUUID}from"node:crypto";var MAX_HEADER_BYTES=256;var SESSION_ENV_VARS=["TERM_SESSION_ID","ITERM_SESSION_ID","WEZTERM_PANE","KITTY_PID","ALACRITTY_SOCKET","WT_SESSION","VSCODE_PID","SUPERSET_PANE_ID","SUPERSET_WORKSPACE_ID","STARSHIP_SESSION_KEY","SSH_CONNECTION"];var cachedSessionId;function resolveRawSessionId(env=process.env,ppid=process.ppid){for(const key of SESSION_ENV_VARS){const value=env[key];if(value&&value.trim().length>0){return value.trim()}}if(typeof ppid==="number"&&!Number.isNaN(ppid)&&ppid>0){return String(ppid)}return randomUUID()}function getSessionId(env,ppid){if(cachedSessionId!==undefined&&env===undefined&&ppid===undefined){return cachedSessionId}const raw=resolveRawSessionId(env,ppid);const hashed=hashValue(raw);if(env===undefined&&ppid===undefined){cachedSessionId=hashed}return hashed}function hashValue(input){return createHash("sha256").update(input).digest("hex").slice(0,16)}var AGENT_PROBES=[{envVar:"OPENCODE",name:"opencode"},{envVar:"CLAUDECODE",name:"claude-code"},{envVar:"CURSOR_TRACE_ID",name:"cursor"},{envVar:"WINDSURF_CONFIG_DIR",name:"windsurf"},{envVar:"ZED_TERM",name:"zed"},{envVar:"VSCODE_PID",name:"vscode"}];function parseAgentString(raw){const trimmed=raw.trim();if(trimmed.length===0)return;const slashIndex=trimmed.indexOf("/");if(slashIndex===-1)return{name:trimmed};const name=trimmed.slice(0,slashIndex);const ver=trimmed.slice(slashIndex+1);if(name.length===0)return;return{name,version:ver||undefined}}function formatAgentInfo(info){return info.version?`${info.name}/${info.version}`:info.name}function resolveAgentInfo(env=process.env){const explicit=env.GITHITS_AGENT;if(explicit&&explicit.trim().length>0){return parseAgentString(explicit)}for(const probe of AGENT_PROBES){const value=env[probe.envVar];if(value&&value.trim().length>0){return{name:probe.name}}}return}var CONTROL_CHARS=/[\x00-\x1f\x7f-\x9f]/g;function sanitizeHeaderValue(value){if(value===undefined||value===null||typeof value!=="string"){return}const cleaned=value.replace(CONTROL_CHARS,"").trim();if(cleaned.length===0)return;if(Buffer.byteLength(cleaned,"utf8")>MAX_HEADER_BYTES)return;return cleaned}function createClientHeaderBuilder(options){return()=>buildClientHeadersWithContext({clientName:options.clientName,clientVersion:options.clientVersion,agentProvider:options.agentProvider,env:options.env,ppid:options.ppid})}function buildClientHeadersWithContext(context){try{const headers={};const name=sanitizeHeaderValue(context.clientName);if(name){headers["x-githits-client-name"]=name}const safeClientVersion=sanitizeHeaderValue(context.clientVersion);if(safeClientVersion){headers["x-githits-client-version"]=safeClientVersion}const agentInfo=context.agentProvider?.()??resolveAgentInfo(context.env);if(agentInfo){const agentValue=sanitizeHeaderValue(formatAgentInfo(agentInfo));if(agentValue){headers["x-githits-agent"]=agentValue}}const sessionId=sanitizeHeaderValue(getSessionId(context.env,context.ppid));if(sessionId){headers["x-githits-session-id"]=sessionId}return headers}catch{return{}}}import{createHash as createHash2,randomBytes}from"node:crypto";import{z as z4}from"zod";var latestVersionMaliciousEvidenceSchema=z4.object({advisories:z4.array(z4.object({osvId:z4.string(),classificationReasons:z4.array(z4.string())})).max(5),totalCount:z4.number().int().nonnegative(),truncated:z4.boolean()}).nullable();var listCandidateSchema=z4.object({kind:z4.string(),canonicalKey:z4.string(),confidence:z4.string(),latestVersionMaliciousStatus:z4.string(),latestVersionMaliciousEvidence:latestVersionMaliciousEvidenceSchema,description:z4.string().nullable().optional(),repositoryUrl:z4.string().nullable().optional(),stars:z4.number().int().nullable().optional(),downloadsLastMonth:z4.number().int().nullable().optional(),downloadsTotal:z4.number().int().nullable().optional(),docsAvailable:z4.boolean(),codeAvailable:z4.boolean()});var targetReferenceSchema=listCandidateSchema.pick({kind:true,canonicalKey:true,confidence:true});var detailedCandidateSchema=listCandidateSchema.extend({displayName:z4.string(),registry:z4.string().nullable().optional(),packageName:z4.string().nullable().optional(),latestVersion:z4.string().nullable().optional(),repositoryOwner:z4.string().nullable().optional(),repositoryName:z4.string().nullable().optional(),documentationUrl:z4.string().nullable().optional(),matchedAliases:z4.array(z4.string()),matchTier:z4.number().int(),score:z4.number(),reason:z4.string().nullable().optional()});var graphQLErrorSchema3=z4.object({message:z4.string(),extensions:z4.record(z4.string(),z4.unknown()).optional()});export{CLIENT_UPDATE_REQUIRED_REASON,ClientUpdateRequiredError,debugLog,FetchTimeoutError,DEFAULT_MCP_URL,DEFAULT_API_URL,DEFAULT_CODE_NAV_URL,getMcpUrl,getApiUrl,getCodeNavigationUrl,getEnvApiToken,TermsAcceptanceRequiredError,PKGSEER_REGISTRY_ARGS,PKGSEER_REGISTRY_LIST,toPkgseerRegistry,toPkgseerRegistryLowercase,isKnownPkgseerRegistryArg,withTelemetrySpan,startTelemetrySpan,endTelemetrySpan,flushTelemetry,AuthenticationError,ApiRateLimitError,GitHitsServiceImpl,CodeNavigationAccessError,CodeNavigationGraphQLError,CodeNavigationIndexingError,CodeNavigationUnresolvableError,MalformedCodeNavigationResponseError,CodeDiffError,CodeNavigationTargetNotFoundError,CodeNavigationFileNotFoundError,CodeNavigationVersionNotFoundError,CodeNavigationRefNotFoundError,CodeNavigationValidationError,CodeNavigationFeatureFlagRequiredError,CodeNavigationNetworkError,CodeNavigationBackendError,CodeNavigationServiceImpl,PackageIntelligenceAccessError,PackageIntelligenceFeatureFlagRequiredError,PackageIntelligenceNetworkError,PackageIntelligenceBackendError,PackageIntelligenceGraphQLError,PackageIntelligenceTargetNotFoundError,PackageIntelligenceValidationError,PackageIntelligenceVersionNotFoundError,MalformedPackageIntelligenceResponseError,PackageIntelligenceChangelogSourceNotFoundError,PackageIntelligenceServiceImpl,RefreshingGitHitsService,createStaticTokenProvider,createClientHeaderBuilder};
@@ -26,7 +26,7 @@ interface HttpChallengeMetadata {
26
26
  get(name: string): string | null;
27
27
  } | Record<string, string | undefined>;
28
28
  }
29
- declare const EXPECTED_MCP_TOOLS: readonly ["get_example", "search_language", "pkg_info", "pkg_deps", "pkg_vulns", "pkg_changelog", "pkg_upgrade_review", "docs_list", "docs_read", "code_files", "code_read", "code_grep", "search", "search_status", "feedback"];
29
+ declare const EXPECTED_MCP_TOOLS: readonly ["quick_start", "get_example", "search_language", "pkg_info", "pkg_deps", "pkg_vulns", "pkg_changelog", "pkg_upgrade_review", "docs_list", "docs_read", "code_files", "code_read", "code_grep", "search", "search_status", "feedback"];
30
30
  declare function resultText(result: McpSmokeToolResult, context: string): string;
31
31
  declare function assertCleanErrorEnvelope(result: McpSmokeToolResult, context: string): ErrorEnvelope;
32
32
  declare function assertHttpUnauthorizedChallenge(metadata: HttpChallengeMetadata, context?: string): void;
@@ -1 +1 @@
1
- var EXPECTED_MCP_TOOLS=["get_example","search_language","pkg_info","pkg_deps","pkg_vulns","pkg_changelog","pkg_upgrade_review","docs_list","docs_read","code_files","code_read","code_grep","search","search_status","feedback"];var DEFAULT_TEXT_LIMIT=12000;var SMOKE_PACKAGE_VERSION="5.2.1";var SMOKE_PACKAGE_TARGET={registry:"npm",package_name:"express",version:SMOKE_PACKAGE_VERSION};function assert(condition,message){if(!condition){throw new Error(message)}}function parseJson(text,context){try{return JSON.parse(text)}catch(error){const message=error instanceof Error?error.message:"unknown error";throw new Error(`${context}: expected parseable JSON (${message})`)}}function assertNotJson(text,context){try{JSON.parse(text)}catch{return}throw new Error(`${context}: default response unexpectedly parsed as JSON`)}function assertRecord(value,context){assert(value!==null&&typeof value==="object"&&!Array.isArray(value),`${context}: expected object`)}function headerValue(headers,name){if(!headers)return null;if("get"in headers&&typeof headers.get==="function"){return headers.get(name)}const lowerName=name.toLowerCase();for(const[key,value]of Object.entries(headers)){if(key.toLowerCase()===lowerName)return value??null}return null}function resultText(result,context){assert(Array.isArray(result.content),`${context}: expected content array`);const first=result.content[0];assert(first?.type==="text",`${context}: expected text content`);assert(typeof first.text==="string",`${context}: expected text string`);return first.text}function assertCleanErrorEnvelope(result,context){assert(result.isError===true,`${context}: expected MCP error result`);const payload=parseJson(resultText(result,context),context);assertRecord(payload,context);assert(typeof payload.error==="string"&&payload.error.length>0,`${context}: missing error`);assert(typeof payload.code==="string"&&payload.code.length>0,`${context}: missing code`);assert(typeof payload.retryable==="boolean",`${context}: missing retryable`);return payload}function assertHttpUnauthorizedChallenge(metadata,context="unauthenticated HTTP challenge"){assert(metadata.status===401,`${context}: expected HTTP 401`);const challenge=headerValue(metadata.headers,"www-authenticate");assert(typeof challenge==="string"&&challenge.length>0,`${context}: missing WWW-Authenticate header`);assert(/^Bearer\b/i.test(challenge),`${context}: expected Bearer challenge, got ${challenge}`)}function assertDefaultText(result,context){assert(result.isError!==true,`${context}: expected success`);const text=resultText(result,context);assert(text.length>0,`${context}: expected non-empty text`);assert(text.length<DEFAULT_TEXT_LIMIT,`${context}: default text too large (${text.length} chars)`);assertNotJson(text,context);assert(!text.includes("--lifecycle"),`${context}: leaked CLI lifecycle flag`);assert(!text.includes("--verbose"),`${context}: leaked CLI verbose flag`);return text}function assertJsonResult(result,context){assert(result.isError!==true,`${context}: expected success`);return parseJson(resultText(result,context),context)}function assertErrorCode(result,context,code){const envelope=assertCleanErrorEnvelope(result,context);assert(envelope.code===code,`${context}: expected ${code}, got ${envelope.code}`)}async function callTool(caller,name,args){return await caller.callTool(name,args)}async function callToolText(caller,name,args){const result=await caller.callTool(name,args);const text=resultText(result,name);if(result.isError===true){throw new Error(text)}return text}async function assertLiveOrAuthRequired(caller,logger){const result=await callTool(caller,"search_language",{query:"python"});if(result.isError===true){const envelope=assertCleanErrorEnvelope(result,"search_language auth probe");assert(envelope.code==="AUTH_REQUIRED",`auth probe returned unexpected code ${envelope.code}`);logger.log("AUTH_REQUIRED: live smoke skipped");return false}const text=assertDefaultText(result,"search_language default");assert(text.includes("python (Python)"),"search_language default missing Python display name");assert(text.includes("aliases:"),"search_language default missing aliases");return true}async function runLiveSmoke(caller){const languageJson=assertJsonResult(await callTool(caller,"search_language",{query:"python",format:"json"}),"search_language json");assert(Array.isArray(languageJson),"search_language json: expected array");const exampleText=assertDefaultText(await callTool(caller,"get_example",{query:"express hello world",language:"javascript"}),"get_example default");assert(exampleText.includes("solution_id:"),"get_example default missing solution_id hint");const exampleJson=assertJsonResult(await callTool(caller,"get_example",{query:"express hello world",language:"javascript",format:"json"}),"get_example json");assertRecord(exampleJson,"get_example json");assert(typeof exampleJson.result==="string","get_example json missing result");const pkgInfoText=assertDefaultText(await callTool(caller,"pkg_info",{registry:"npm",package_name:"express"}),"pkg_info default");assert(pkgInfoText.includes("express"),"pkg_info default missing package name");assert(pkgInfoText.includes("Repository")&&pkgInfoText.includes("stars"),"pkg_info default missing repository popularity");assert(pkgInfoText.includes("Vulnerabilities"),"pkg_info default missing vulnerability status");assert(!pkgInfoText.includes("Install")&&!pkgInfoText.includes("Usage"),"pkg_info default should not include quickstart fields");const pkgInfoJson=assertJsonResult(await callTool(caller,"pkg_info",{registry:"npm",package_name:"express",format:"json"}),"pkg_info json");assertRecord(pkgInfoJson,"pkg_info json");assert(pkgInfoJson.registry==="npm","pkg_info json registry mismatch");assert(pkgInfoJson.name==="express","pkg_info json name mismatch");assert(typeof pkgInfoJson.version==="string","pkg_info json missing version");assert(!("install"in pkgInfoJson)&&!("usage"in pkgInfoJson),"pkg_info json should not include quickstart fields");const depsText=assertDefaultText(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express"}),"pkg_deps default");assert(depsText.includes("Runtime dependencies:"),"pkg_deps default missing runtime heading");assert(depsText.includes('pass lifecycle="all"'),"pkg_deps default missing MCP-native lifecycle hint");const depsAllText=assertDefaultText(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express",lifecycle:"all"}),"pkg_deps lifecycle all");assert(depsAllText.includes("Dependency groups:"),"pkg_deps lifecycle all missing groups heading");assert(!depsAllText.includes("Hidden groups:"),"pkg_deps lifecycle all still hides groups");const depsJson=assertJsonResult(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express",format:"json"}),"pkg_deps json");assertRecord(depsJson,"pkg_deps json");assertRecord(depsJson.runtime,"pkg_deps json runtime");const vulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express"}),"pkg_vulns default");assert(vulnsText.includes("express")||vulnsText.includes("vulnerab"),"pkg_vulns default missing context");assert(!vulnsText.includes("use -v"),"pkg_vulns leaked CLI -v hint");const filteredVulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"lodash",version:"4.17.20",min_severity:"high"}),"pkg_vulns filtered default");assert(filteredVulnsText.includes("Filter severity >= high"),"pkg_vulns filtered default missing filter echo");assert(!filteredVulnsText.includes("use -v"),"pkg_vulns filtered default leaked CLI -v hint");const vulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",format:"json"}),"pkg_vulns json");assertRecord(vulnsJson,"pkg_vulns json");assert("summary"in vulnsJson||"advisories"in vulnsJson,"pkg_vulns json missing vulnerability data");const filteredVulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"lodash",version:"4.17.20",min_severity:"high",format:"json"}),"pkg_vulns filtered json");assertRecord(filteredVulnsJson,"pkg_vulns filtered json");assertRecord(filteredVulnsJson.filter,"pkg_vulns filtered json filter");assert(filteredVulnsJson.filter.minSeverity==="high","pkg_vulns filtered json missing severity filter echo");const scopedVulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",advisory_scope:"non_affecting"}),"pkg_vulns scoped default");assert(scopedVulnsText.includes("Scope historical advisories only"),"pkg_vulns scoped default missing scope echo");assert(scopedVulnsText.includes("No active vulnerabilities affect this version"),"pkg_vulns scoped default missing current-risk statement");assert(!scopedVulnsText.includes("use -v"),"pkg_vulns scoped default leaked CLI -v hint");const scopedVulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",advisory_scope:"non_affecting",format:"json"}),"pkg_vulns scoped json");assertRecord(scopedVulnsJson,"pkg_vulns scoped json");assertRecord(scopedVulnsJson.filter,"pkg_vulns scoped json filter");assert(scopedVulnsJson.filter.advisoryScope==="non_affecting","pkg_vulns scoped json missing advisory scope echo");const changelogText=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:1}),"pkg_changelog default");assert(!changelogText.includes("--verbose"),"pkg_changelog default leaked CLI verbose flag");if(changelogText.includes("truncated")||changelogText.includes("full bodies")){assert(changelogText.includes('pass verbose=true, body_lines=<n>, or format="json"'),"pkg_changelog truncation hint is not MCP-native")}const changelogBodyLinesText=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:2,body_lines:3}),"pkg_changelog body_lines");assert(changelogBodyLinesText.includes('pass verbose=true, body_lines=<n>, or format="json"'),"pkg_changelog body_lines missing MCP-native truncation hint");assert(!changelogBodyLinesText.includes("--verbose"),"pkg_changelog body_lines leaked CLI verbose flag");const changelogJson=assertJsonResult(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:1,format:"json"}),"pkg_changelog json");assertRecord(changelogJson,"pkg_changelog json");assertRecord(changelogJson.entries,"pkg_changelog json entries");const changelogTimeline=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:2,omit_bodies:true}),"pkg_changelog timeline");assert(!changelogTimeline.includes("What's Changed"),"pkg_changelog omit_bodies=true still emitted bodies");const upgradeReviewText=assertDefaultText(await callTool(caller,"pkg_upgrade_review",{registry:"npm",package_name:"express",current_version:"5.0.0",target_version:"5.2.1",skip_transitive_security:true}),"pkg_upgrade_review default");assert(upgradeReviewText.includes("pkg_upgrade_review")&&upgradeReviewText.includes("vulnerabilities")&&upgradeReviewText.includes("changes"),"pkg_upgrade_review default missing evidence sections");assert(!upgradeReviewText.includes("recommendation")&&!upgradeReviewText.includes("risk level"),"pkg_upgrade_review default leaked assessment language");const upgradeReviewJson=assertJsonResult(await callTool(caller,"pkg_upgrade_review",{registry:"npm",package_name:"express",current_version:"5.0.0",target_version:"5.2.1",skip_transitive_security:true,format:"json"}),"pkg_upgrade_review json");assertRecord(upgradeReviewJson,"pkg_upgrade_review json");assertRecord(upgradeReviewJson.summary,"pkg_upgrade_review json summary");assert(Array.isArray(upgradeReviewJson.reviews),"pkg_upgrade_review json missing reviews array");const firstUpgradeReview=upgradeReviewJson.reviews[0];assert(firstUpgradeReview,"pkg_upgrade_review json missing first review");for(const forbidden of["risk","riskLevel","recommendation","findings","verification"]){assert(!(forbidden in firstUpgradeReview),`pkg_upgrade_review json leaked judgment field ${forbidden}`)}const docsText=assertDefaultText(await callTool(caller,"docs_list",{...SMOKE_PACKAGE_TARGET,limit:2}),"docs_list default");assert(docsText.includes("docs_read page_id="),"docs_list default missing docs_read follow-up");const docsJson=assertJsonResult(await callTool(caller,"docs_list",{...SMOKE_PACKAGE_TARGET,limit:2,format:"json"}),"docs_list json");assertRecord(docsJson,"docs_list json");assert(Array.isArray(docsJson.pages),"docs_list json missing pages array");const firstPage=docsJson.pages[0];assert(firstPage&&typeof firstPage.pageId==="string","docs_list json missing readable page id");const docReadText=assertDefaultText(await callTool(caller,"docs_read",{page_id:firstPage.pageId,start_line:1,end_line:5}),"docs_read default");assert(docReadText.length>0,"docs_read default missing content");const docReadJson=assertJsonResult(await callTool(caller,"docs_read",{page_id:firstPage.pageId,start_line:1,end_line:5,format:"json"}),"docs_read json");assertRecord(docReadJson,"docs_read json");assert(typeof docReadJson.content==="string","docs_read json missing content");const codeFilesText=assertDefaultText(await callTool(caller,"code_files",{target:SMOKE_PACKAGE_TARGET,path_prefix:"package.json",limit:1}),"code_files default");assert(codeFilesText.includes("package.json"),"code_files default missing package.json");const codeFilesJson=assertJsonResult(await callTool(caller,"code_files",{target:SMOKE_PACKAGE_TARGET,path_prefix:"package.json",limit:1,format:"json"}),"code_files json");assertRecord(codeFilesJson,"code_files json");assert(Array.isArray(codeFilesJson.files),"code_files json missing files array");const codeReadText=assertDefaultText(await callTool(caller,"code_read",{target:SMOKE_PACKAGE_TARGET,path:"package.json",start_line:1,end_line:5}),"code_read default");assert(/^1\s+/m.test(codeReadText),"code_read default missing line numbers");const codeReadJson=assertJsonResult(await callTool(caller,"code_read",{target:SMOKE_PACKAGE_TARGET,path:"package.json",start_line:1,end_line:5,format:"json"}),"code_read json");assertRecord(codeReadJson,"code_read json");assert(codeReadJson.path==="package.json","code_read json path mismatch");const codeGrepText=assertDefaultText(await callTool(caller,"code_grep",{target:SMOKE_PACKAGE_TARGET,pattern:"express",path:"package.json",max_matches:1}),"code_grep default");assert(codeGrepText.includes("package.json"),"code_grep default missing package.json");const codeGrepJson=assertJsonResult(await callTool(caller,"code_grep",{target:SMOKE_PACKAGE_TARGET,pattern:"express",path:"package.json",max_matches:1,format:"json"}),"code_grep json");assertRecord(codeGrepJson,"code_grep json");assert("matches"in codeGrepJson||"totalMatches"in codeGrepJson,"code_grep json missing matches");const searchText=assertDefaultText(await callTool(caller,"search",{target:SMOKE_PACKAGE_TARGET,query:"router",limit:1}),"search default");assert(searchText.includes("code_read")||searchText.includes("docs_read")||searchText.includes("search_status"),"search default missing ready-to-call follow-up");const searchJson=assertJsonResult(await callTool(caller,"search",{target:SMOKE_PACKAGE_TARGET,query:"router",limit:1,format:"json"}),"search json");assertRecord(searchJson,"search json");const searchRef=typeof searchJson.searchRef==="string"?searchJson.searchRef:undefined;if(searchRef){const statusJson=assertJsonResult(await callTool(caller,"search_status",{search_ref:searchRef,wait_timeout_ms:0,format:"json"}),"search_status json");assertRecord(statusJson,"search_status json");assert("completed"in statusJson||"progress"in statusJson,"search_status json missing status data")}else{assertErrorCode(await callTool(caller,"search_status",{search_ref:"smoke-invalid-search-ref",wait_timeout_ms:0}),"search_status invalid ref","NOT_FOUND")}const feedbackValidation=await callTool(caller,"feedback",{solution_id:"",accepted:true});assert(feedbackValidation.isError===true,"feedback validation should fail before submitting");assert(resultText(feedbackValidation,"feedback validation").includes("MCP error"),"feedback validation missing protocol error text")}async function runMcpSmoke(caller,options={}){const logger=options.logger??console;const includeLiveTools=options.includeLiveTools??true;const toolsResponse=await caller.listTools();const toolNames=new Set(toolsResponse.tools.map((tool)=>tool.name));for(const expected of EXPECTED_MCP_TOOLS){assert(toolNames.has(expected),`listTools missing ${expected}`)}if(!includeLiveTools)return;if(await assertLiveOrAuthRequired(caller,logger)){await runLiveSmoke(caller);logger.log("MCP smoke passed")}}export{EXPECTED_MCP_TOOLS,assertCleanErrorEnvelope,assertDefaultText,assertHttpUnauthorizedChallenge,assertJsonResult,callToolText,resultText,runMcpSmoke};
1
+ var EXPECTED_MCP_TOOLS=["quick_start","get_example","search_language","pkg_info","pkg_deps","pkg_vulns","pkg_changelog","pkg_upgrade_review","docs_list","docs_read","code_files","code_read","code_grep","search","search_status","feedback"];var DEFAULT_TEXT_LIMIT=12000;var SMOKE_PACKAGE_VERSION="5.2.1";var SMOKE_PACKAGE_TARGET={registry:"npm",package_name:"express",version:SMOKE_PACKAGE_VERSION};function assert(condition,message){if(!condition){throw new Error(message)}}function parseJson(text,context){try{return JSON.parse(text)}catch(error){const message=error instanceof Error?error.message:"unknown error";throw new Error(`${context}: expected parseable JSON (${message})`)}}function assertNotJson(text,context){try{JSON.parse(text)}catch{return}throw new Error(`${context}: default response unexpectedly parsed as JSON`)}function assertRecord(value,context){assert(value!==null&&typeof value==="object"&&!Array.isArray(value),`${context}: expected object`)}function headerValue(headers,name){if(!headers)return null;if("get"in headers&&typeof headers.get==="function"){return headers.get(name)}const lowerName=name.toLowerCase();for(const[key,value]of Object.entries(headers)){if(key.toLowerCase()===lowerName)return value??null}return null}function resultText(result,context){assert(Array.isArray(result.content),`${context}: expected content array`);const first=result.content[0];assert(first?.type==="text",`${context}: expected text content`);assert(typeof first.text==="string",`${context}: expected text string`);return first.text}function assertCleanErrorEnvelope(result,context){assert(result.isError===true,`${context}: expected MCP error result`);const payload=parseJson(resultText(result,context),context);assertRecord(payload,context);assert(typeof payload.error==="string"&&payload.error.length>0,`${context}: missing error`);assert(typeof payload.code==="string"&&payload.code.length>0,`${context}: missing code`);assert(typeof payload.retryable==="boolean",`${context}: missing retryable`);return payload}function assertHttpUnauthorizedChallenge(metadata,context="unauthenticated HTTP challenge"){assert(metadata.status===401,`${context}: expected HTTP 401`);const challenge=headerValue(metadata.headers,"www-authenticate");assert(typeof challenge==="string"&&challenge.length>0,`${context}: missing WWW-Authenticate header`);assert(/^Bearer\b/i.test(challenge),`${context}: expected Bearer challenge, got ${challenge}`)}function assertDefaultText(result,context){assert(result.isError!==true,`${context}: expected success`);const text=resultText(result,context);assert(text.length>0,`${context}: expected non-empty text`);assert(text.length<DEFAULT_TEXT_LIMIT,`${context}: default text too large (${text.length} chars)`);assertNotJson(text,context);assert(!text.includes("--lifecycle"),`${context}: leaked CLI lifecycle flag`);assert(!text.includes("--verbose"),`${context}: leaked CLI verbose flag`);return text}function assertJsonResult(result,context){assert(result.isError!==true,`${context}: expected success`);return parseJson(resultText(result,context),context)}function assertErrorCode(result,context,code){const envelope=assertCleanErrorEnvelope(result,context);assert(envelope.code===code,`${context}: expected ${code}, got ${envelope.code}`)}async function callTool(caller,name,args){return await caller.callTool(name,args)}async function callToolText(caller,name,args){const result=await caller.callTool(name,args);const text=resultText(result,name);if(result.isError===true){throw new Error(text)}return text}async function assertLiveOrAuthRequired(caller,logger){const result=await callTool(caller,"search_language",{query:"python"});if(result.isError===true){const envelope=assertCleanErrorEnvelope(result,"search_language auth probe");assert(envelope.code==="AUTH_REQUIRED",`auth probe returned unexpected code ${envelope.code}`);logger.log("AUTH_REQUIRED: live smoke skipped");return false}const text=assertDefaultText(result,"search_language default");assert(text.includes("python (Python)"),"search_language default missing Python display name");assert(text.includes("aliases:"),"search_language default missing aliases");return true}async function runLiveSmoke(caller){const languageJson=assertJsonResult(await callTool(caller,"search_language",{query:"python",format:"json"}),"search_language json");assert(Array.isArray(languageJson),"search_language json: expected array");const exampleText=assertDefaultText(await callTool(caller,"get_example",{query:"express hello world",language:"javascript"}),"get_example default");assert(exampleText.includes("solution_id:"),"get_example default missing solution_id hint");const exampleJson=assertJsonResult(await callTool(caller,"get_example",{query:"express hello world",language:"javascript",format:"json"}),"get_example json");assertRecord(exampleJson,"get_example json");assert(typeof exampleJson.result==="string","get_example json missing result");const pkgInfoText=assertDefaultText(await callTool(caller,"pkg_info",{registry:"npm",package_name:"express"}),"pkg_info default");assert(pkgInfoText.includes("express"),"pkg_info default missing package name");assert(pkgInfoText.includes("Repository")&&pkgInfoText.includes("stars"),"pkg_info default missing repository popularity");assert(pkgInfoText.includes("Vulnerabilities"),"pkg_info default missing vulnerability status");assert(!pkgInfoText.includes("Install")&&!pkgInfoText.includes("Usage"),"pkg_info default should not include quickstart fields");const pkgInfoJson=assertJsonResult(await callTool(caller,"pkg_info",{registry:"npm",package_name:"express",format:"json"}),"pkg_info json");assertRecord(pkgInfoJson,"pkg_info json");assert(pkgInfoJson.registry==="npm","pkg_info json registry mismatch");assert(pkgInfoJson.name==="express","pkg_info json name mismatch");assert(typeof pkgInfoJson.version==="string","pkg_info json missing version");assert(!("install"in pkgInfoJson)&&!("usage"in pkgInfoJson),"pkg_info json should not include quickstart fields");const depsText=assertDefaultText(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express"}),"pkg_deps default");assert(depsText.includes("Runtime dependencies:"),"pkg_deps default missing runtime heading");assert(depsText.includes('pass lifecycle="all"'),"pkg_deps default missing MCP-native lifecycle hint");const depsAllText=assertDefaultText(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express",lifecycle:"all"}),"pkg_deps lifecycle all");assert(depsAllText.includes("Dependency groups:"),"pkg_deps lifecycle all missing groups heading");assert(!depsAllText.includes("Hidden groups:"),"pkg_deps lifecycle all still hides groups");const depsJson=assertJsonResult(await callTool(caller,"pkg_deps",{registry:"npm",package_name:"express",format:"json"}),"pkg_deps json");assertRecord(depsJson,"pkg_deps json");assertRecord(depsJson.runtime,"pkg_deps json runtime");const vulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express"}),"pkg_vulns default");assert(vulnsText.includes("express")||vulnsText.includes("vulnerab"),"pkg_vulns default missing context");assert(!vulnsText.includes("use -v"),"pkg_vulns leaked CLI -v hint");const filteredVulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"lodash",version:"4.17.20",min_severity:"high"}),"pkg_vulns filtered default");assert(filteredVulnsText.includes("Filter severity >= high"),"pkg_vulns filtered default missing filter echo");assert(!filteredVulnsText.includes("use -v"),"pkg_vulns filtered default leaked CLI -v hint");const vulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",format:"json"}),"pkg_vulns json");assertRecord(vulnsJson,"pkg_vulns json");assert("summary"in vulnsJson||"advisories"in vulnsJson,"pkg_vulns json missing vulnerability data");const filteredVulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"lodash",version:"4.17.20",min_severity:"high",format:"json"}),"pkg_vulns filtered json");assertRecord(filteredVulnsJson,"pkg_vulns filtered json");assertRecord(filteredVulnsJson.filter,"pkg_vulns filtered json filter");assert(filteredVulnsJson.filter.minSeverity==="high","pkg_vulns filtered json missing severity filter echo");const scopedVulnsText=assertDefaultText(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",advisory_scope:"non_affecting"}),"pkg_vulns scoped default");assert(scopedVulnsText.includes("Scope historical advisories only"),"pkg_vulns scoped default missing scope echo");assert(scopedVulnsText.includes("No active vulnerabilities affect this version"),"pkg_vulns scoped default missing current-risk statement");assert(!scopedVulnsText.includes("use -v"),"pkg_vulns scoped default leaked CLI -v hint");const scopedVulnsJson=assertJsonResult(await callTool(caller,"pkg_vulns",{registry:"npm",package_name:"express",advisory_scope:"non_affecting",format:"json"}),"pkg_vulns scoped json");assertRecord(scopedVulnsJson,"pkg_vulns scoped json");assertRecord(scopedVulnsJson.filter,"pkg_vulns scoped json filter");assert(scopedVulnsJson.filter.advisoryScope==="non_affecting","pkg_vulns scoped json missing advisory scope echo");const changelogText=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:1}),"pkg_changelog default");assert(!changelogText.includes("--verbose"),"pkg_changelog default leaked CLI verbose flag");if(changelogText.includes("truncated")||changelogText.includes("full bodies")){assert(changelogText.includes('pass verbose=true, body_lines=<n>, or format="json"'),"pkg_changelog truncation hint is not MCP-native")}const changelogBodyLinesText=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:2,body_lines:3}),"pkg_changelog body_lines");assert(changelogBodyLinesText.includes('pass verbose=true, body_lines=<n>, or format="json"'),"pkg_changelog body_lines missing MCP-native truncation hint");assert(!changelogBodyLinesText.includes("--verbose"),"pkg_changelog body_lines leaked CLI verbose flag");const changelogJson=assertJsonResult(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:1,format:"json"}),"pkg_changelog json");assertRecord(changelogJson,"pkg_changelog json");assertRecord(changelogJson.entries,"pkg_changelog json entries");const changelogTimeline=assertDefaultText(await callTool(caller,"pkg_changelog",{registry:"npm",package_name:"express",limit:2,omit_bodies:true}),"pkg_changelog timeline");assert(!changelogTimeline.includes("What's Changed"),"pkg_changelog omit_bodies=true still emitted bodies");const upgradeReviewText=assertDefaultText(await callTool(caller,"pkg_upgrade_review",{registry:"npm",package_name:"express",current_version:"5.0.0",target_version:"5.2.1",skip_transitive_security:true}),"pkg_upgrade_review default");assert(upgradeReviewText.includes("pkg_upgrade_review")&&upgradeReviewText.includes("vulnerabilities")&&upgradeReviewText.includes("changes"),"pkg_upgrade_review default missing evidence sections");assert(!upgradeReviewText.includes("recommendation")&&!upgradeReviewText.includes("risk level"),"pkg_upgrade_review default leaked assessment language");const upgradeReviewJson=assertJsonResult(await callTool(caller,"pkg_upgrade_review",{registry:"npm",package_name:"express",current_version:"5.0.0",target_version:"5.2.1",skip_transitive_security:true,format:"json"}),"pkg_upgrade_review json");assertRecord(upgradeReviewJson,"pkg_upgrade_review json");assertRecord(upgradeReviewJson.summary,"pkg_upgrade_review json summary");assert(Array.isArray(upgradeReviewJson.reviews),"pkg_upgrade_review json missing reviews array");const firstUpgradeReview=upgradeReviewJson.reviews[0];assert(firstUpgradeReview,"pkg_upgrade_review json missing first review");for(const forbidden of["risk","riskLevel","recommendation","findings","verification"]){assert(!(forbidden in firstUpgradeReview),`pkg_upgrade_review json leaked judgment field ${forbidden}`)}const docsText=assertDefaultText(await callTool(caller,"docs_list",{...SMOKE_PACKAGE_TARGET,limit:2}),"docs_list default");assert(docsText.includes("docs_read page_id="),"docs_list default missing docs_read follow-up");const docsJson=assertJsonResult(await callTool(caller,"docs_list",{...SMOKE_PACKAGE_TARGET,limit:2,format:"json"}),"docs_list json");assertRecord(docsJson,"docs_list json");assert(Array.isArray(docsJson.pages),"docs_list json missing pages array");const firstPage=docsJson.pages[0];assert(firstPage&&typeof firstPage.pageId==="string","docs_list json missing readable page id");const docReadText=assertDefaultText(await callTool(caller,"docs_read",{page_id:firstPage.pageId,start_line:1,end_line:5}),"docs_read default");assert(docReadText.length>0,"docs_read default missing content");const docReadJson=assertJsonResult(await callTool(caller,"docs_read",{page_id:firstPage.pageId,start_line:1,end_line:5,format:"json"}),"docs_read json");assertRecord(docReadJson,"docs_read json");assert(typeof docReadJson.content==="string","docs_read json missing content");const codeFilesText=assertDefaultText(await callTool(caller,"code_files",{target:SMOKE_PACKAGE_TARGET,path_prefix:"package.json",limit:1}),"code_files default");assert(codeFilesText.includes("package.json"),"code_files default missing package.json");const codeFilesJson=assertJsonResult(await callTool(caller,"code_files",{target:SMOKE_PACKAGE_TARGET,path_prefix:"package.json",limit:1,format:"json"}),"code_files json");assertRecord(codeFilesJson,"code_files json");assert(Array.isArray(codeFilesJson.files),"code_files json missing files array");const codeReadText=assertDefaultText(await callTool(caller,"code_read",{target:SMOKE_PACKAGE_TARGET,path:"package.json",start_line:1,end_line:5}),"code_read default");assert(/^1\s+/m.test(codeReadText),"code_read default missing line numbers");const codeReadJson=assertJsonResult(await callTool(caller,"code_read",{target:SMOKE_PACKAGE_TARGET,path:"package.json",start_line:1,end_line:5,format:"json"}),"code_read json");assertRecord(codeReadJson,"code_read json");assert(codeReadJson.path==="package.json","code_read json path mismatch");const codeGrepText=assertDefaultText(await callTool(caller,"code_grep",{target:SMOKE_PACKAGE_TARGET,pattern:"express",path:"package.json",max_matches:1}),"code_grep default");assert(codeGrepText.includes("package.json"),"code_grep default missing package.json");const codeGrepJson=assertJsonResult(await callTool(caller,"code_grep",{target:SMOKE_PACKAGE_TARGET,pattern:"express",path:"package.json",max_matches:1,format:"json"}),"code_grep json");assertRecord(codeGrepJson,"code_grep json");assert("matches"in codeGrepJson||"totalMatches"in codeGrepJson,"code_grep json missing matches");const searchText=assertDefaultText(await callTool(caller,"search",{target:SMOKE_PACKAGE_TARGET,query:"router",limit:1}),"search default");assert(searchText.includes("code_read")||searchText.includes("docs_read")||searchText.includes("search_status"),"search default missing ready-to-call follow-up");const searchJson=assertJsonResult(await callTool(caller,"search",{target:SMOKE_PACKAGE_TARGET,query:"router",limit:1,format:"json"}),"search json");assertRecord(searchJson,"search json");const searchRef=typeof searchJson.searchRef==="string"?searchJson.searchRef:undefined;if(searchRef){const statusJson=assertJsonResult(await callTool(caller,"search_status",{search_ref:searchRef,wait_timeout_ms:0,format:"json"}),"search_status json");assertRecord(statusJson,"search_status json");assert("completed"in statusJson||"progress"in statusJson,"search_status json missing status data")}else{assertErrorCode(await callTool(caller,"search_status",{search_ref:"smoke-invalid-search-ref",wait_timeout_ms:0}),"search_status invalid ref","NOT_FOUND")}const feedbackValidation=await callTool(caller,"feedback",{solution_id:"",accepted:true});assert(feedbackValidation.isError===true,"feedback validation should fail before submitting");assert(resultText(feedbackValidation,"feedback validation").includes("MCP error"),"feedback validation missing protocol error text")}async function runMcpSmoke(caller,options={}){const logger=options.logger??console;const includeLiveTools=options.includeLiveTools??true;const toolsResponse=await caller.listTools();const toolNames=new Set(toolsResponse.tools.map((tool)=>tool.name));for(const expected of EXPECTED_MCP_TOOLS){assert(toolNames.has(expected),`listTools missing ${expected}`)}const quickStart=assertDefaultText(await callTool(caller,"quick_start",{}),"quick_start default");for(const expected of["GitHits provides","`search`","`code_grep`"]){assert(quickStart.includes(expected),`quick_start default missing ${expected}`)}if(!includeLiveTools)return;if(await assertLiveOrAuthRequired(caller,logger)){await runLiveSmoke(caller);logger.log("MCP smoke passed")}}export{EXPECTED_MCP_TOOLS,assertCleanErrorEnvelope,assertDefaultText,assertHttpUnauthorizedChallenge,assertJsonResult,callToolText,resultText,runMcpSmoke};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githits/mcp",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "Reusable MCP server APIs and tools for GitHits",
5
5
  "type": "module",
6
6
  "files": [